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:
|
||||
heading: Add
|
||||
headingStrong: Probe
|
||||
validate: Probe name already exists
|
||||
labels:
|
||||
probeName: Probe Name
|
||||
probeType: Probe Type
|
||||
|
|
|
@ -84,6 +84,7 @@ export interface ListManifestTemplateArray {
|
|||
project_name: string;
|
||||
template_description: string;
|
||||
template_name: string;
|
||||
isCustomWorkflow: boolean;
|
||||
}
|
||||
|
||||
export interface ListManifestTemplate {
|
||||
|
|
|
@ -41,6 +41,18 @@ export const validateWorkflowName = (value: string) => {
|
|||
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) => {
|
||||
const passValid = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/;
|
||||
if (value.length > 0) {
|
||||
|
@ -77,7 +89,7 @@ export const isValidWebUrl = (value: string) => {
|
|||
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 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 (
|
||||
value.match(regEx) ||
|
||||
value.match(regExLocal) ||
|
||||
|
|
|
@ -19,7 +19,9 @@ import {
|
|||
ListManifestTemplateArray,
|
||||
} from '../../../models/graphql/workflowListData';
|
||||
import { getProjectID } from '../../../utils/getSearchParams';
|
||||
import * as WorkflowActions from '../../../redux/actions/workflow';
|
||||
import useStyles from './styles';
|
||||
import useActions from '../../../redux/actions';
|
||||
|
||||
interface ChooseWorkflowRadio {
|
||||
selected: string;
|
||||
|
@ -33,7 +35,7 @@ const ChooseWorkflowFromExisting = () => {
|
|||
// Local States
|
||||
const [search, setSearch] = useState<string | null>(null);
|
||||
const [selected, setSelected] = useState<string>('');
|
||||
|
||||
const workflowAction = useActions(WorkflowActions);
|
||||
const { data: templateData } = useQuery<ListManifestTemplate>(
|
||||
LIST_MANIFEST_TEMPLATE,
|
||||
{
|
||||
|
@ -74,7 +76,9 @@ const ChooseWorkflowFromExisting = () => {
|
|||
const templateData = filteredExistingWorkflows.filter((workflow) => {
|
||||
return workflow.template_id === event.target.value;
|
||||
})[0];
|
||||
|
||||
workflowAction.setWorkflowManifest({
|
||||
isCustomWorkflow: templateData.isCustomWorkflow,
|
||||
});
|
||||
localforage.setItem('selectedScheduleOption', selection);
|
||||
localforage.setItem('workflow', {
|
||||
name: templateData.template_name.toLowerCase(),
|
||||
|
|
|
@ -37,7 +37,7 @@ const ProbeDetails: React.FC<ProbeDetailsProps> = ({
|
|||
| { name?: string | undefined; value: unknown }
|
||||
>
|
||||
) => {
|
||||
if (e.target.name === 'url' || e.target.name === 'responseTimeout') {
|
||||
if (e.target.name === 'url') {
|
||||
setProbeData({
|
||||
...probeData,
|
||||
'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') {
|
||||
setProbeData({
|
||||
...probeData,
|
||||
|
@ -185,7 +194,7 @@ const ProbeDetails: React.FC<ProbeDetailsProps> = ({
|
|||
width="50%"
|
||||
id="responseTimeout"
|
||||
name="responseTimeout"
|
||||
type="text"
|
||||
type="number"
|
||||
value={probeData['httpProbe/inputs']?.responseTimeout}
|
||||
onChange={handleHttp}
|
||||
/>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||
import React from 'react';
|
||||
import useStyles from './styles';
|
||||
import ProbeDetails from './ProbeDetails';
|
||||
import { validateProbeName } from '../../../../utils/validate';
|
||||
|
||||
interface AddProbeProps {
|
||||
probesValue: any;
|
||||
|
@ -153,12 +154,21 @@ const AddProbe: React.FC<AddProbeProps> = ({
|
|||
{t('createWorkflow.tuneWorkflow.addProbe.labels.probeName')}
|
||||
</InputLabel>
|
||||
<InputField
|
||||
variant="primary"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
required
|
||||
value={probeData.name}
|
||||
helperText={
|
||||
validateProbeName(allProbes, probeData.name)
|
||||
? t('createWorkflow.tuneWorkflow.addProbe.validate')
|
||||
: ''
|
||||
}
|
||||
variant={
|
||||
validateProbeName(allProbes, probeData.name)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
onChange={(e) =>
|
||||
setProbeData({ ...probeData, name: e.target.value })
|
||||
}
|
||||
|
@ -328,7 +338,13 @@ const AddProbe: React.FC<AddProbeProps> = ({
|
|||
>
|
||||
{t('createWorkflow.tuneWorkflow.addProbe.button.cancel')}
|
||||
</ButtonOutlined>
|
||||
<ButtonFilled type="submit">
|
||||
<ButtonFilled
|
||||
type="submit"
|
||||
disabled={
|
||||
validateProbeName(allProbes, probeData.name) ||
|
||||
probeData.name.trim().length === 0
|
||||
}
|
||||
>
|
||||
{t('createWorkflow.tuneWorkflow.addProbe.button.addProbe')}
|
||||
</ButtonFilled>
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,7 @@ import useStyles from './styles';
|
|||
|
||||
interface WorkflowTableProps {
|
||||
isCustom: boolean | undefined;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
interface ChaosCRDTable {
|
||||
|
@ -41,311 +42,322 @@ interface ChaosCRDTable {
|
|||
ChaosEngine: string;
|
||||
}
|
||||
|
||||
const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const WorkflowTable = forwardRef(
|
||||
({ isCustom, namespace }: WorkflowTableProps, ref) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const theme = useTheme();
|
||||
const workflow = useActions(WorkflowActions);
|
||||
const [experiments, setExperiments] = useState<ChaosCRDTable[]>([]);
|
||||
const [revertChaos, setRevertChaos] = useState<boolean>(true);
|
||||
const [displayStepper, setDisplayStepper] = useState<boolean>(false);
|
||||
const [engineIndex, setEngineIndex] = useState<number>(0);
|
||||
const [selected, setSelected] = useState<string>('');
|
||||
const manifest = useSelector(
|
||||
(state: RootState) => state.workflowManifest.manifest
|
||||
);
|
||||
const imageRegistryData = useSelector(
|
||||
(state: RootState) => state.selectedImageRegistry
|
||||
);
|
||||
const addWeights = (manifest: string) => {
|
||||
const arr: experimentMap[] = [];
|
||||
const hashMap = new Map();
|
||||
const tests = parsed(manifest);
|
||||
tests.forEach((test) => {
|
||||
let value = 10;
|
||||
if (hashMap.has(test)) {
|
||||
value = hashMap.get(test);
|
||||
}
|
||||
arr.push({ experimentName: test, weight: value });
|
||||
});
|
||||
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,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const theme = useTheme();
|
||||
const workflow = useActions(WorkflowActions);
|
||||
const [experiments, setExperiments] = useState<ChaosCRDTable[]>([]);
|
||||
const [revertChaos, setRevertChaos] = useState<boolean>(true);
|
||||
const [displayStepper, setDisplayStepper] = useState<boolean>(false);
|
||||
const [engineIndex, setEngineIndex] = useState<number>(0);
|
||||
const [selected, setSelected] = useState<string>('');
|
||||
const manifest = useSelector(
|
||||
(state: RootState) => state.workflowManifest.manifest
|
||||
);
|
||||
const imageRegistryData = useSelector(
|
||||
(state: RootState) => state.selectedImageRegistry
|
||||
);
|
||||
const addWeights = (manifest: string) => {
|
||||
const arr: experimentMap[] = [];
|
||||
const hashMap = new Map();
|
||||
const tests = parsed(manifest);
|
||||
tests.forEach((test) => {
|
||||
let value = 10;
|
||||
if (hashMap.has(test)) {
|
||||
value = hashMap.get(test);
|
||||
}
|
||||
arr.push({ experimentName: test, weight: value });
|
||||
});
|
||||
localforage.setItem('weights', arr);
|
||||
};
|
||||
|
||||
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);
|
||||
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 ===
|
||||
'{{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
|
||||
);
|
||||
}
|
||||
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']
|
||||
}, `;
|
||||
workflow.setWorkflowManifest({
|
||||
manifest: updatedManifest,
|
||||
});
|
||||
};
|
||||
|
||||
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
|
||||
} `;
|
||||
const closeConfigurationStepper = () => {
|
||||
workflow.setWorkflowManifest({
|
||||
engineYAML: '',
|
||||
});
|
||||
setDisplayStepper(false);
|
||||
};
|
||||
|
||||
deleteEngines += '-n {{workflow.parameters.adminModeNamespace}}';
|
||||
const handleChange = (
|
||||
event: React.MouseEvent<HTMLElement>,
|
||||
newValue: boolean
|
||||
) => {
|
||||
setRevertChaos(newValue);
|
||||
};
|
||||
|
||||
parsedYAML.spec.workflowSpec.templates[
|
||||
parsedYAML.spec.workflowSpec.templates.length
|
||||
] = {
|
||||
name: 'revert-chaos',
|
||||
container: {
|
||||
image: 'litmuschaos/k8s:latest',
|
||||
command: ['sh', '-c'],
|
||||
args: [deleteEngines],
|
||||
},
|
||||
};
|
||||
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
|
||||
}
|
||||
|
||||
const updatedManifest = updateManifestImage(parsedYAML, imageRegistryData);
|
||||
workflow.setWorkflowManifest({
|
||||
manifest: updatedManifest,
|
||||
});
|
||||
};
|
||||
useImperativeHandle(ref, () => ({
|
||||
onNext,
|
||||
}));
|
||||
|
||||
const closeConfigurationStepper = () => {
|
||||
workflow.setWorkflowManifest({
|
||||
engineYAML: '',
|
||||
});
|
||||
setDisplayStepper(false);
|
||||
};
|
||||
|
||||
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>
|
||||
))
|
||||
) : (
|
||||
return (
|
||||
<div>
|
||||
{!displayStepper ? (
|
||||
<>
|
||||
<TableContainer className={classes.table} component={Paper}>
|
||||
<Table aria-label="simple table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell colSpan={5}>
|
||||
<Typography align="center">
|
||||
{t('createWorkflow.chooseWorkflow.pleaseAddExp')}
|
||||
</Typography>
|
||||
<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>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{selected === 'C' && (
|
||||
<TableContainer className={classes.revertChaos} component={Paper}>
|
||||
<Row className={classes.wrapper}>
|
||||
<div className={classes.key}>
|
||||
<Typography>
|
||||
{t('createWorkflow.chooseWorkflow.revertSchedule')}
|
||||
</Typography>
|
||||
</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>
|
||||
</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>
|
||||
<TableCell colSpan={5}>
|
||||
<Typography align="center">
|
||||
{t('createWorkflow.chooseWorkflow.pleaseAddExp')}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<ConfigurationStepper
|
||||
experimentIndex={engineIndex}
|
||||
closeStepper={closeConfigurationStepper}
|
||||
isCustom={isCustom}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
{selected === 'C' && (
|
||||
<TableContainer className={classes.revertChaos} component={Paper}>
|
||||
<Row className={classes.wrapper}>
|
||||
<div className={classes.key}>
|
||||
<Typography>
|
||||
{t('createWorkflow.chooseWorkflow.revertSchedule')}
|
||||
</Typography>
|
||||
</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;
|
||||
|
|
|
@ -788,7 +788,11 @@ const TuneWorkflow = forwardRef((_, ref) => {
|
|||
</Width>
|
||||
{/* Workflow Table */}
|
||||
<Width width="70%">
|
||||
<WorkflowTable ref={childRef} isCustom={isCustomWorkflow} />
|
||||
<WorkflowTable
|
||||
ref={childRef}
|
||||
isCustom={isCustomWorkflow}
|
||||
namespace={namespace}
|
||||
/>
|
||||
</Width>
|
||||
</Row>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import DeveloperGuide from '../../../components/DeveloperGuide';
|
||||
import ExperimentHeader from '../../../components/ExperimentHeader';
|
||||
import ExperimentHeader from '../ExperimentHeader';
|
||||
import ExperimentInfo from '../../../components/ExperimentInfo';
|
||||
import InstallChaos from '../../../components/InstallChaos';
|
||||
import Loader from '../../../components/Loader';
|
||||
|
|
Loading…
Reference in New Issue