chore(litmus-portal): Added validation in probes modal and minor fix (#2842)
* Added validation in probes modal and minor fix * Minor change in directory structure and fixed template graph not rendering issue * Minor regex change for validating ssh links Signed-off-by: Amit Kumar Das <amit@chaosnative.com>
This commit is contained in:
parent
cd72a7a40a
commit
c638304960
|
@ -855,6 +855,7 @@ createWorkflow:
|
||||||
addProbe:
|
addProbe:
|
||||||
heading: Add
|
heading: Add
|
||||||
headingStrong: Probe
|
headingStrong: Probe
|
||||||
|
validate: Probe name already exists
|
||||||
labels:
|
labels:
|
||||||
probeName: Probe Name
|
probeName: Probe Name
|
||||||
probeType: Probe Type
|
probeType: Probe Type
|
||||||
|
|
|
@ -84,6 +84,7 @@ export interface ListManifestTemplateArray {
|
||||||
project_name: string;
|
project_name: string;
|
||||||
template_description: string;
|
template_description: string;
|
||||||
template_name: string;
|
template_name: string;
|
||||||
|
isCustomWorkflow: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListManifestTemplate {
|
export interface ListManifestTemplate {
|
||||||
|
|
|
@ -41,6 +41,18 @@ export const validateWorkflowName = (value: string) => {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const validateProbeName = (allProbe: any, probeName: string) => {
|
||||||
|
if (allProbe.length) {
|
||||||
|
const filteredProbes = allProbe.filter(
|
||||||
|
(probe: any) => probe.name.toLowerCase() === probeName
|
||||||
|
);
|
||||||
|
if (filteredProbes.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export const validatePassword = (value: string) => {
|
export const validatePassword = (value: string) => {
|
||||||
const passValid = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/;
|
const passValid = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/;
|
||||||
if (value.length > 0) {
|
if (value.length > 0) {
|
||||||
|
@ -77,7 +89,7 @@ export const isValidWebUrl = (value: string) => {
|
||||||
const regExLocal = /^http:\/\/localhost:([0-9]){1,4}$/g;
|
const regExLocal = /^http:\/\/localhost:([0-9]){1,4}$/g;
|
||||||
const regExIpv4 = /^http:\/\/(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]):([0-9]){1,4}$/g;
|
const regExIpv4 = /^http:\/\/(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]):([0-9]){1,4}$/g;
|
||||||
const regExIpv6 = /^http:\/\/((([0-9a-fA-F]){1,4})\\:){7}([0-9a-fA-F]){1,4}:([0-9]){1,4}$/g;
|
const regExIpv6 = /^http:\/\/((([0-9a-fA-F]){1,4})\\:){7}([0-9a-fA-F]){1,4}:([0-9]){1,4}$/g;
|
||||||
const sshRegEx = /^([A-Za-z0-9]+@|http(|s)\:\/\/)([A-Za-z0-9.]+(:\d+)?)(?::|\/)([\d\/\w.-]+?)(\.git)?$/i;
|
const sshRegEx = /^([A-Za-z0-9]+@|http(|s)\:\/\/)([-a-zA-Z0-9@:%._\+~#=]+(:\d+)?)(?::|\/)([\d\/\w.-]+?)(\.git)?$/i;
|
||||||
if (
|
if (
|
||||||
value.match(regEx) ||
|
value.match(regEx) ||
|
||||||
value.match(regExLocal) ||
|
value.match(regExLocal) ||
|
||||||
|
|
|
@ -19,7 +19,9 @@ import {
|
||||||
ListManifestTemplateArray,
|
ListManifestTemplateArray,
|
||||||
} from '../../../models/graphql/workflowListData';
|
} from '../../../models/graphql/workflowListData';
|
||||||
import { getProjectID } from '../../../utils/getSearchParams';
|
import { getProjectID } from '../../../utils/getSearchParams';
|
||||||
|
import * as WorkflowActions from '../../../redux/actions/workflow';
|
||||||
import useStyles from './styles';
|
import useStyles from './styles';
|
||||||
|
import useActions from '../../../redux/actions';
|
||||||
|
|
||||||
interface ChooseWorkflowRadio {
|
interface ChooseWorkflowRadio {
|
||||||
selected: string;
|
selected: string;
|
||||||
|
@ -33,7 +35,7 @@ const ChooseWorkflowFromExisting = () => {
|
||||||
// Local States
|
// Local States
|
||||||
const [search, setSearch] = useState<string | null>(null);
|
const [search, setSearch] = useState<string | null>(null);
|
||||||
const [selected, setSelected] = useState<string>('');
|
const [selected, setSelected] = useState<string>('');
|
||||||
|
const workflowAction = useActions(WorkflowActions);
|
||||||
const { data: templateData } = useQuery<ListManifestTemplate>(
|
const { data: templateData } = useQuery<ListManifestTemplate>(
|
||||||
LIST_MANIFEST_TEMPLATE,
|
LIST_MANIFEST_TEMPLATE,
|
||||||
{
|
{
|
||||||
|
@ -74,7 +76,9 @@ const ChooseWorkflowFromExisting = () => {
|
||||||
const templateData = filteredExistingWorkflows.filter((workflow) => {
|
const templateData = filteredExistingWorkflows.filter((workflow) => {
|
||||||
return workflow.template_id === event.target.value;
|
return workflow.template_id === event.target.value;
|
||||||
})[0];
|
})[0];
|
||||||
|
workflowAction.setWorkflowManifest({
|
||||||
|
isCustomWorkflow: templateData.isCustomWorkflow,
|
||||||
|
});
|
||||||
localforage.setItem('selectedScheduleOption', selection);
|
localforage.setItem('selectedScheduleOption', selection);
|
||||||
localforage.setItem('workflow', {
|
localforage.setItem('workflow', {
|
||||||
name: templateData.template_name.toLowerCase(),
|
name: templateData.template_name.toLowerCase(),
|
||||||
|
|
|
@ -37,7 +37,7 @@ const ProbeDetails: React.FC<ProbeDetailsProps> = ({
|
||||||
| { name?: string | undefined; value: unknown }
|
| { name?: string | undefined; value: unknown }
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
if (e.target.name === 'url' || e.target.name === 'responseTimeout') {
|
if (e.target.name === 'url') {
|
||||||
setProbeData({
|
setProbeData({
|
||||||
...probeData,
|
...probeData,
|
||||||
'httpProbe/inputs': {
|
'httpProbe/inputs': {
|
||||||
|
@ -46,6 +46,15 @@ const ProbeDetails: React.FC<ProbeDetailsProps> = ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (e.target.name === 'responseTimeout') {
|
||||||
|
setProbeData({
|
||||||
|
...probeData,
|
||||||
|
'httpProbe/inputs': {
|
||||||
|
...probeData['httpProbe/inputs'],
|
||||||
|
[e.target.name]: parseInt(e.target.value as string, 10),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
if (e.target.name === 'insecureSkipVerify') {
|
if (e.target.name === 'insecureSkipVerify') {
|
||||||
setProbeData({
|
setProbeData({
|
||||||
...probeData,
|
...probeData,
|
||||||
|
@ -185,7 +194,7 @@ const ProbeDetails: React.FC<ProbeDetailsProps> = ({
|
||||||
width="50%"
|
width="50%"
|
||||||
id="responseTimeout"
|
id="responseTimeout"
|
||||||
name="responseTimeout"
|
name="responseTimeout"
|
||||||
type="text"
|
type="number"
|
||||||
value={probeData['httpProbe/inputs']?.responseTimeout}
|
value={probeData['httpProbe/inputs']?.responseTimeout}
|
||||||
onChange={handleHttp}
|
onChange={handleHttp}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useStyles from './styles';
|
import useStyles from './styles';
|
||||||
import ProbeDetails from './ProbeDetails';
|
import ProbeDetails from './ProbeDetails';
|
||||||
|
import { validateProbeName } from '../../../../utils/validate';
|
||||||
|
|
||||||
interface AddProbeProps {
|
interface AddProbeProps {
|
||||||
probesValue: any;
|
probesValue: any;
|
||||||
|
@ -153,12 +154,21 @@ const AddProbe: React.FC<AddProbeProps> = ({
|
||||||
{t('createWorkflow.tuneWorkflow.addProbe.labels.probeName')}
|
{t('createWorkflow.tuneWorkflow.addProbe.labels.probeName')}
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
<InputField
|
<InputField
|
||||||
variant="primary"
|
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
value={probeData.name}
|
value={probeData.name}
|
||||||
|
helperText={
|
||||||
|
validateProbeName(allProbes, probeData.name)
|
||||||
|
? t('createWorkflow.tuneWorkflow.addProbe.validate')
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
variant={
|
||||||
|
validateProbeName(allProbes, probeData.name)
|
||||||
|
? 'error'
|
||||||
|
: 'primary'
|
||||||
|
}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setProbeData({ ...probeData, name: e.target.value })
|
setProbeData({ ...probeData, name: e.target.value })
|
||||||
}
|
}
|
||||||
|
@ -328,7 +338,13 @@ const AddProbe: React.FC<AddProbeProps> = ({
|
||||||
>
|
>
|
||||||
{t('createWorkflow.tuneWorkflow.addProbe.button.cancel')}
|
{t('createWorkflow.tuneWorkflow.addProbe.button.cancel')}
|
||||||
</ButtonOutlined>
|
</ButtonOutlined>
|
||||||
<ButtonFilled type="submit">
|
<ButtonFilled
|
||||||
|
type="submit"
|
||||||
|
disabled={
|
||||||
|
validateProbeName(allProbes, probeData.name) ||
|
||||||
|
probeData.name.trim().length === 0
|
||||||
|
}
|
||||||
|
>
|
||||||
{t('createWorkflow.tuneWorkflow.addProbe.button.addProbe')}
|
{t('createWorkflow.tuneWorkflow.addProbe.button.addProbe')}
|
||||||
</ButtonFilled>
|
</ButtonFilled>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,6 +30,7 @@ import useStyles from './styles';
|
||||||
|
|
||||||
interface WorkflowTableProps {
|
interface WorkflowTableProps {
|
||||||
isCustom: boolean | undefined;
|
isCustom: boolean | undefined;
|
||||||
|
namespace: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChaosCRDTable {
|
interface ChaosCRDTable {
|
||||||
|
@ -41,311 +42,322 @@ interface ChaosCRDTable {
|
||||||
ChaosEngine: string;
|
ChaosEngine: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
const WorkflowTable = forwardRef(
|
||||||
const classes = useStyles();
|
({ isCustom, namespace }: WorkflowTableProps, ref) => {
|
||||||
const { t } = useTranslation();
|
const classes = useStyles();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const workflow = useActions(WorkflowActions);
|
const workflow = useActions(WorkflowActions);
|
||||||
const [experiments, setExperiments] = useState<ChaosCRDTable[]>([]);
|
const [experiments, setExperiments] = useState<ChaosCRDTable[]>([]);
|
||||||
const [revertChaos, setRevertChaos] = useState<boolean>(true);
|
const [revertChaos, setRevertChaos] = useState<boolean>(true);
|
||||||
const [displayStepper, setDisplayStepper] = useState<boolean>(false);
|
const [displayStepper, setDisplayStepper] = useState<boolean>(false);
|
||||||
const [engineIndex, setEngineIndex] = useState<number>(0);
|
const [engineIndex, setEngineIndex] = useState<number>(0);
|
||||||
const [selected, setSelected] = useState<string>('');
|
const [selected, setSelected] = useState<string>('');
|
||||||
const manifest = useSelector(
|
const manifest = useSelector(
|
||||||
(state: RootState) => state.workflowManifest.manifest
|
(state: RootState) => state.workflowManifest.manifest
|
||||||
);
|
);
|
||||||
const imageRegistryData = useSelector(
|
const imageRegistryData = useSelector(
|
||||||
(state: RootState) => state.selectedImageRegistry
|
(state: RootState) => state.selectedImageRegistry
|
||||||
);
|
);
|
||||||
const addWeights = (manifest: string) => {
|
const addWeights = (manifest: string) => {
|
||||||
const arr: experimentMap[] = [];
|
const arr: experimentMap[] = [];
|
||||||
const hashMap = new Map();
|
const hashMap = new Map();
|
||||||
const tests = parsed(manifest);
|
const tests = parsed(manifest);
|
||||||
tests.forEach((test) => {
|
tests.forEach((test) => {
|
||||||
let value = 10;
|
let value = 10;
|
||||||
if (hashMap.has(test)) {
|
if (hashMap.has(test)) {
|
||||||
value = hashMap.get(test);
|
value = hashMap.get(test);
|
||||||
}
|
}
|
||||||
arr.push({ experimentName: test, weight: value });
|
arr.push({ experimentName: test, weight: value });
|
||||||
});
|
});
|
||||||
localforage.setItem('weights', arr);
|
localforage.setItem('weights', arr);
|
||||||
};
|
|
||||||
|
|
||||||
const parsing = (yamlText: string) => {
|
|
||||||
const parsedYaml = YAML.parse(yamlText);
|
|
||||||
const expData: ChaosCRDTable[] = [];
|
|
||||||
addWeights(manifest);
|
|
||||||
|
|
||||||
const extractInfo = (template: any, index: number) => {
|
|
||||||
if (template.inputs && template.inputs.artifacts) {
|
|
||||||
template.inputs.artifacts.forEach((artifact: any) => {
|
|
||||||
const chaosEngine = YAML.parse(artifact.raw.data);
|
|
||||||
if (chaosEngine.kind === 'ChaosEngine') {
|
|
||||||
expData.push({
|
|
||||||
StepIndex: index,
|
|
||||||
Name: chaosEngine.metadata.generateName,
|
|
||||||
Namespace: chaosEngine.spec.appinfo?.appns ?? '',
|
|
||||||
Application: chaosEngine.spec.appinfo?.applabel ?? '',
|
|
||||||
Probes: chaosEngine.spec.experiments[0].spec.probe?.length ?? 0,
|
|
||||||
ChaosEngine: artifact.raw.data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (parsedYaml.kind === 'Workflow') {
|
const parsing = (yamlText: string) => {
|
||||||
parsedYaml.spec.templates.forEach((template: any, index: number) => {
|
const parsedYaml = YAML.parse(yamlText);
|
||||||
extractInfo(template, index);
|
const expData: ChaosCRDTable[] = [];
|
||||||
});
|
addWeights(manifest);
|
||||||
} else if (parsedYaml.kind === 'CronWorkflow') {
|
|
||||||
parsedYaml.spec.workflowSpec.templates.forEach(
|
const extractInfo = (template: any, index: number) => {
|
||||||
(template: any, index: number) => {
|
if (template.inputs && template.inputs.artifacts) {
|
||||||
extractInfo(template, index);
|
template.inputs.artifacts.forEach((artifact: any) => {
|
||||||
|
const chaosEngine = YAML.parse(artifact.raw.data);
|
||||||
|
if (chaosEngine.kind === 'ChaosEngine') {
|
||||||
|
expData.push({
|
||||||
|
StepIndex: index,
|
||||||
|
Name: chaosEngine.metadata.generateName,
|
||||||
|
Namespace:
|
||||||
|
chaosEngine.spec.appinfo?.appns ===
|
||||||
|
'{{workflow.parameters.adminModeNamespace}}'
|
||||||
|
? namespace
|
||||||
|
: chaosEngine.spec.appinfo?.appns ?? '',
|
||||||
|
Application: chaosEngine.spec.appinfo?.applabel ?? '',
|
||||||
|
Probes: chaosEngine.spec.experiments[0].spec.probe?.length ?? 0,
|
||||||
|
ChaosEngine: artifact.raw.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (parsedYaml.kind === 'Workflow') {
|
||||||
|
parsedYaml.spec.templates.forEach((template: any, index: number) => {
|
||||||
|
extractInfo(template, index);
|
||||||
|
});
|
||||||
|
} else if (parsedYaml.kind === 'CronWorkflow') {
|
||||||
|
parsedYaml.spec.workflowSpec.templates.forEach(
|
||||||
|
(template: any, index: number) => {
|
||||||
|
extractInfo(template, index);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setExperiments(expData);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Revert Chaos
|
||||||
|
const toggleRevertChaos = (manifest: string) => {
|
||||||
|
const parsedYAML = YAML.parse(manifest);
|
||||||
|
let deleteEngines: string = '';
|
||||||
|
|
||||||
|
// Else if Revert Chaos is set to true and it is not already set in the manifest
|
||||||
|
// For Workflows
|
||||||
|
if (revertChaos && parsedYAML.kind === 'Workflow') {
|
||||||
|
parsedYAML.spec.templates[0].steps.push([
|
||||||
|
{
|
||||||
|
name: 'revert-chaos',
|
||||||
|
template: 'revert-chaos',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
parsed(manifest).forEach((_, i) => {
|
||||||
|
deleteEngines += `${
|
||||||
|
YAML.parse(
|
||||||
|
parsedYAML.spec.templates[2 + i].inputs.artifacts[0].raw.data
|
||||||
|
).metadata.labels['instance_id']
|
||||||
|
}, `;
|
||||||
|
});
|
||||||
|
|
||||||
|
parsedYAML.spec.templates[parsedYAML.spec.templates.length] = {
|
||||||
|
name: 'revert-chaos',
|
||||||
|
container: {
|
||||||
|
image: 'litmuschaos/k8s:latest',
|
||||||
|
command: ['sh', '-c'],
|
||||||
|
args: [
|
||||||
|
`kubectl delete chaosengine -l 'instance_id in (${deleteEngines})' -n {{workflow.parameters.adminModeNamespace}} `,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else if Revert Chaos is set to True and it is not already set in the manifest
|
||||||
|
// For Cron Workflow
|
||||||
|
else if (revertChaos && parsedYAML.kind === 'CronWorkflow') {
|
||||||
|
parsedYAML.spec.workflowSpec.templates[0].steps.push([
|
||||||
|
{
|
||||||
|
name: 'revert-chaos',
|
||||||
|
template: 'revert-chaos',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
parsed(manifest).forEach((_, i) => {
|
||||||
|
deleteEngines = `${
|
||||||
|
deleteEngines +
|
||||||
|
YAML.parse(
|
||||||
|
parsedYAML.spec.workflowSpec.templates[2 + i].inputs.artifacts[0]
|
||||||
|
.raw.data
|
||||||
|
).metadata.name
|
||||||
|
} `;
|
||||||
|
});
|
||||||
|
|
||||||
|
deleteEngines += '-n {{workflow.parameters.adminModeNamespace}}';
|
||||||
|
|
||||||
|
parsedYAML.spec.workflowSpec.templates[
|
||||||
|
parsedYAML.spec.workflowSpec.templates.length
|
||||||
|
] = {
|
||||||
|
name: 'revert-chaos',
|
||||||
|
container: {
|
||||||
|
image: 'litmuschaos/k8s:latest',
|
||||||
|
command: ['sh', '-c'],
|
||||||
|
args: [deleteEngines],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedManifest = updateManifestImage(
|
||||||
|
parsedYAML,
|
||||||
|
imageRegistryData
|
||||||
);
|
);
|
||||||
}
|
workflow.setWorkflowManifest({
|
||||||
setExperiments(expData);
|
manifest: updatedManifest,
|
||||||
};
|
|
||||||
|
|
||||||
// Revert Chaos
|
|
||||||
const toggleRevertChaos = (manifest: string) => {
|
|
||||||
const parsedYAML = YAML.parse(manifest);
|
|
||||||
let deleteEngines: string = '';
|
|
||||||
|
|
||||||
// Else if Revert Chaos is set to true and it is not already set in the manifest
|
|
||||||
// For Workflows
|
|
||||||
if (revertChaos && parsedYAML.kind === 'Workflow') {
|
|
||||||
parsedYAML.spec.templates[0].steps.push([
|
|
||||||
{
|
|
||||||
name: 'revert-chaos',
|
|
||||||
template: 'revert-chaos',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
parsed(manifest).forEach((_, i) => {
|
|
||||||
deleteEngines += `${
|
|
||||||
YAML.parse(
|
|
||||||
parsedYAML.spec.templates[2 + i].inputs.artifacts[0].raw.data
|
|
||||||
).metadata.labels['instance_id']
|
|
||||||
}, `;
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
parsedYAML.spec.templates[parsedYAML.spec.templates.length] = {
|
const closeConfigurationStepper = () => {
|
||||||
name: 'revert-chaos',
|
workflow.setWorkflowManifest({
|
||||||
container: {
|
engineYAML: '',
|
||||||
image: 'litmuschaos/k8s:latest',
|
|
||||||
command: ['sh', '-c'],
|
|
||||||
args: [
|
|
||||||
`kubectl delete chaosengine -l 'instance_id in (${deleteEngines})' -n {{workflow.parameters.adminModeNamespace}} `,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else if Revert Chaos is set to True and it is not already set in the manifest
|
|
||||||
// For Cron Workflow
|
|
||||||
else if (revertChaos && parsedYAML.kind === 'CronWorkflow') {
|
|
||||||
parsedYAML.spec.workflowSpec.templates[0].steps.push([
|
|
||||||
{
|
|
||||||
name: 'revert-chaos',
|
|
||||||
template: 'revert-chaos',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
parsed(manifest).forEach((_, i) => {
|
|
||||||
deleteEngines = `${
|
|
||||||
deleteEngines +
|
|
||||||
YAML.parse(
|
|
||||||
parsedYAML.spec.workflowSpec.templates[2 + i].inputs.artifacts[0]
|
|
||||||
.raw.data
|
|
||||||
).metadata.name
|
|
||||||
} `;
|
|
||||||
});
|
});
|
||||||
|
setDisplayStepper(false);
|
||||||
|
};
|
||||||
|
|
||||||
deleteEngines += '-n {{workflow.parameters.adminModeNamespace}}';
|
const handleChange = (
|
||||||
|
event: React.MouseEvent<HTMLElement>,
|
||||||
|
newValue: boolean
|
||||||
|
) => {
|
||||||
|
setRevertChaos(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
parsedYAML.spec.workflowSpec.templates[
|
useEffect(() => {
|
||||||
parsedYAML.spec.workflowSpec.templates.length
|
if (manifest.length) {
|
||||||
] = {
|
parsing(manifest);
|
||||||
name: 'revert-chaos',
|
}
|
||||||
container: {
|
localforage.getItem('selectedScheduleOption').then((value) => {
|
||||||
image: 'litmuschaos/k8s:latest',
|
if (value) {
|
||||||
command: ['sh', '-c'],
|
setSelected((value as ChooseWorkflowRadio).selected);
|
||||||
args: [deleteEngines],
|
} else setSelected('');
|
||||||
},
|
});
|
||||||
};
|
}, [manifest]);
|
||||||
|
|
||||||
|
function onNext() {
|
||||||
|
if (experiments.length === 0) {
|
||||||
|
return false; // Should show alert
|
||||||
|
}
|
||||||
|
if (!isCustom) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (selected === 'C') {
|
||||||
|
toggleRevertChaos(manifest);
|
||||||
|
}
|
||||||
|
return true; // Should not show any alert
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedManifest = updateManifestImage(parsedYAML, imageRegistryData);
|
useImperativeHandle(ref, () => ({
|
||||||
workflow.setWorkflowManifest({
|
onNext,
|
||||||
manifest: updatedManifest,
|
}));
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeConfigurationStepper = () => {
|
return (
|
||||||
workflow.setWorkflowManifest({
|
<div>
|
||||||
engineYAML: '',
|
{!displayStepper ? (
|
||||||
});
|
<>
|
||||||
setDisplayStepper(false);
|
<TableContainer className={classes.table} component={Paper}>
|
||||||
};
|
<Table aria-label="simple table">
|
||||||
|
<TableHead>
|
||||||
const handleChange = (
|
|
||||||
event: React.MouseEvent<HTMLElement>,
|
|
||||||
newValue: boolean
|
|
||||||
) => {
|
|
||||||
setRevertChaos(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (manifest.length) {
|
|
||||||
parsing(manifest);
|
|
||||||
}
|
|
||||||
localforage.getItem('selectedScheduleOption').then((value) => {
|
|
||||||
if (value) {
|
|
||||||
setSelected((value as ChooseWorkflowRadio).selected);
|
|
||||||
} else setSelected('');
|
|
||||||
});
|
|
||||||
}, [manifest]);
|
|
||||||
|
|
||||||
function onNext() {
|
|
||||||
if (experiments.length === 0) {
|
|
||||||
return false; // Should show alert
|
|
||||||
}
|
|
||||||
if (!isCustom) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (selected === 'C') {
|
|
||||||
toggleRevertChaos(manifest);
|
|
||||||
}
|
|
||||||
return true; // Should not show any alert
|
|
||||||
}
|
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
|
||||||
onNext,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{!displayStepper ? (
|
|
||||||
<>
|
|
||||||
<TableContainer className={classes.table} component={Paper}>
|
|
||||||
<Table aria-label="simple table">
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>
|
|
||||||
{t('createWorkflow.chooseWorkflow.table.head1')}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">
|
|
||||||
{t('createWorkflow.chooseWorkflow.table.head2')}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">
|
|
||||||
{t('createWorkflow.chooseWorkflow.table.head3')}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">
|
|
||||||
{t('createWorkflow.chooseWorkflow.table.head4')}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">
|
|
||||||
{t('createWorkflow.chooseWorkflow.table.head5')}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{experiments.length > 0 ? (
|
|
||||||
experiments.map((experiment: ChaosCRDTable, index) => (
|
|
||||||
<TableRow
|
|
||||||
key={experiment.Name}
|
|
||||||
onClick={() => {
|
|
||||||
setDisplayStepper(true);
|
|
||||||
setEngineIndex(experiment.StepIndex);
|
|
||||||
workflow.setWorkflowManifest({
|
|
||||||
engineYAML: experiment.ChaosEngine,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
className={classes.selection}
|
|
||||||
>
|
|
||||||
<TableCell component="th" scope="row">
|
|
||||||
{index + 1}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">{experiment.Name}</TableCell>
|
|
||||||
<TableCell align="left">{experiment.Namespace}</TableCell>
|
|
||||||
<TableCell align="left">
|
|
||||||
{experiment.Application}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="left">{experiment.Probes}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={5}>
|
<TableCell>
|
||||||
<Typography align="center">
|
{t('createWorkflow.chooseWorkflow.table.head1')}
|
||||||
{t('createWorkflow.chooseWorkflow.pleaseAddExp')}
|
</TableCell>
|
||||||
</Typography>
|
<TableCell align="left">
|
||||||
|
{t('createWorkflow.chooseWorkflow.table.head2')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="left">
|
||||||
|
{t('createWorkflow.chooseWorkflow.table.head3')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="left">
|
||||||
|
{t('createWorkflow.chooseWorkflow.table.head4')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="left">
|
||||||
|
{t('createWorkflow.chooseWorkflow.table.head5')}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
</TableHead>
|
||||||
</TableBody>
|
<TableBody>
|
||||||
</Table>
|
{experiments.length > 0 ? (
|
||||||
</TableContainer>
|
experiments.map((experiment: ChaosCRDTable, index) => (
|
||||||
{selected === 'C' && (
|
<TableRow
|
||||||
<TableContainer className={classes.revertChaos} component={Paper}>
|
key={experiment.Name}
|
||||||
<Row className={classes.wrapper}>
|
onClick={() => {
|
||||||
<div className={classes.key}>
|
setDisplayStepper(true);
|
||||||
<Typography>
|
setEngineIndex(experiment.StepIndex);
|
||||||
{t('createWorkflow.chooseWorkflow.revertSchedule')}
|
workflow.setWorkflowManifest({
|
||||||
</Typography>
|
engineYAML: experiment.ChaosEngine,
|
||||||
</div>
|
});
|
||||||
<div>
|
}}
|
||||||
<ToggleButtonGroup
|
className={classes.selection}
|
||||||
value={revertChaos}
|
>
|
||||||
exclusive
|
<TableCell component="th" scope="row">
|
||||||
onChange={handleChange}
|
{index + 1}
|
||||||
aria-label="text alignment"
|
</TableCell>
|
||||||
>
|
<TableCell align="left">{experiment.Name}</TableCell>
|
||||||
<ToggleButton
|
<TableCell align="left">
|
||||||
value
|
{experiment.Namespace}
|
||||||
style={{
|
</TableCell>
|
||||||
backgroundColor: revertChaos
|
<TableCell align="left">
|
||||||
? theme.palette.success.main
|
{experiment.Application}
|
||||||
: theme.palette.disabledBackground,
|
</TableCell>
|
||||||
color: revertChaos
|
<TableCell align="left">{experiment.Probes}</TableCell>
|
||||||
? theme.palette.common.white
|
</TableRow>
|
||||||
: theme.palette.text.disabled,
|
))
|
||||||
}}
|
) : (
|
||||||
aria-label="centered"
|
<TableRow>
|
||||||
>
|
<TableCell colSpan={5}>
|
||||||
{t('createWorkflow.chooseWorkflow.trueValue')}
|
<Typography align="center">
|
||||||
</ToggleButton>
|
{t('createWorkflow.chooseWorkflow.pleaseAddExp')}
|
||||||
<ToggleButton
|
</Typography>
|
||||||
value={false}
|
</TableCell>
|
||||||
style={{
|
</TableRow>
|
||||||
backgroundColor: !revertChaos
|
)}
|
||||||
? theme.palette.error.main
|
</TableBody>
|
||||||
: theme.palette.disabledBackground,
|
</Table>
|
||||||
color: !revertChaos
|
|
||||||
? theme.palette.common.white
|
|
||||||
: theme.palette.text.disabled,
|
|
||||||
}}
|
|
||||||
aria-label="centered"
|
|
||||||
>
|
|
||||||
{t('createWorkflow.chooseWorkflow.falseValue')}
|
|
||||||
</ToggleButton>
|
|
||||||
</ToggleButtonGroup>
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
)}
|
{selected === 'C' && (
|
||||||
</>
|
<TableContainer className={classes.revertChaos} component={Paper}>
|
||||||
) : (
|
<Row className={classes.wrapper}>
|
||||||
<ConfigurationStepper
|
<div className={classes.key}>
|
||||||
experimentIndex={engineIndex}
|
<Typography>
|
||||||
closeStepper={closeConfigurationStepper}
|
{t('createWorkflow.chooseWorkflow.revertSchedule')}
|
||||||
isCustom={isCustom}
|
</Typography>
|
||||||
/>
|
</div>
|
||||||
)}
|
<div>
|
||||||
</div>
|
<ToggleButtonGroup
|
||||||
);
|
value={revertChaos}
|
||||||
});
|
exclusive
|
||||||
|
onChange={handleChange}
|
||||||
|
aria-label="text alignment"
|
||||||
|
>
|
||||||
|
<ToggleButton
|
||||||
|
value
|
||||||
|
style={{
|
||||||
|
backgroundColor: revertChaos
|
||||||
|
? theme.palette.success.main
|
||||||
|
: theme.palette.disabledBackground,
|
||||||
|
color: revertChaos
|
||||||
|
? theme.palette.common.white
|
||||||
|
: theme.palette.text.disabled,
|
||||||
|
}}
|
||||||
|
aria-label="centered"
|
||||||
|
>
|
||||||
|
{t('createWorkflow.chooseWorkflow.trueValue')}
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton
|
||||||
|
value={false}
|
||||||
|
style={{
|
||||||
|
backgroundColor: !revertChaos
|
||||||
|
? theme.palette.error.main
|
||||||
|
: theme.palette.disabledBackground,
|
||||||
|
color: !revertChaos
|
||||||
|
? theme.palette.common.white
|
||||||
|
: theme.palette.text.disabled,
|
||||||
|
}}
|
||||||
|
aria-label="centered"
|
||||||
|
>
|
||||||
|
{t('createWorkflow.chooseWorkflow.falseValue')}
|
||||||
|
</ToggleButton>
|
||||||
|
</ToggleButtonGroup>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</TableContainer>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<ConfigurationStepper
|
||||||
|
experimentIndex={engineIndex}
|
||||||
|
closeStepper={closeConfigurationStepper}
|
||||||
|
isCustom={isCustom}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default WorkflowTable;
|
export default WorkflowTable;
|
||||||
|
|
|
@ -788,7 +788,11 @@ const TuneWorkflow = forwardRef((_, ref) => {
|
||||||
</Width>
|
</Width>
|
||||||
{/* Workflow Table */}
|
{/* Workflow Table */}
|
||||||
<Width width="70%">
|
<Width width="70%">
|
||||||
<WorkflowTable ref={childRef} isCustom={isCustomWorkflow} />
|
<WorkflowTable
|
||||||
|
ref={childRef}
|
||||||
|
isCustom={isCustomWorkflow}
|
||||||
|
namespace={namespace}
|
||||||
|
/>
|
||||||
</Width>
|
</Width>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import DeveloperGuide from '../../../components/DeveloperGuide';
|
import DeveloperGuide from '../../../components/DeveloperGuide';
|
||||||
import ExperimentHeader from '../../../components/ExperimentHeader';
|
import ExperimentHeader from '../ExperimentHeader';
|
||||||
import ExperimentInfo from '../../../components/ExperimentInfo';
|
import ExperimentInfo from '../../../components/ExperimentInfo';
|
||||||
import InstallChaos from '../../../components/InstallChaos';
|
import InstallChaos from '../../../components/InstallChaos';
|
||||||
import Loader from '../../../components/Loader';
|
import Loader from '../../../components/Loader';
|
||||||
|
|
Loading…
Reference in New Issue