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,7 +42,8 @@ interface ChaosCRDTable {
|
||||||
ChaosEngine: string;
|
ChaosEngine: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
const WorkflowTable = forwardRef(
|
||||||
|
({ isCustom, namespace }: WorkflowTableProps, ref) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -85,7 +87,11 @@ const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
||||||
expData.push({
|
expData.push({
|
||||||
StepIndex: index,
|
StepIndex: index,
|
||||||
Name: chaosEngine.metadata.generateName,
|
Name: chaosEngine.metadata.generateName,
|
||||||
Namespace: chaosEngine.spec.appinfo?.appns ?? '',
|
Namespace:
|
||||||
|
chaosEngine.spec.appinfo?.appns ===
|
||||||
|
'{{workflow.parameters.adminModeNamespace}}'
|
||||||
|
? namespace
|
||||||
|
: chaosEngine.spec.appinfo?.appns ?? '',
|
||||||
Application: chaosEngine.spec.appinfo?.applabel ?? '',
|
Application: chaosEngine.spec.appinfo?.applabel ?? '',
|
||||||
Probes: chaosEngine.spec.experiments[0].spec.probe?.length ?? 0,
|
Probes: chaosEngine.spec.experiments[0].spec.probe?.length ?? 0,
|
||||||
ChaosEngine: artifact.raw.data,
|
ChaosEngine: artifact.raw.data,
|
||||||
|
@ -178,7 +184,10 @@ const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedManifest = updateManifestImage(parsedYAML, imageRegistryData);
|
const updatedManifest = updateManifestImage(
|
||||||
|
parsedYAML,
|
||||||
|
imageRegistryData
|
||||||
|
);
|
||||||
workflow.setWorkflowManifest({
|
workflow.setWorkflowManifest({
|
||||||
manifest: updatedManifest,
|
manifest: updatedManifest,
|
||||||
});
|
});
|
||||||
|
@ -269,7 +278,9 @@ const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="left">{experiment.Name}</TableCell>
|
<TableCell align="left">{experiment.Name}</TableCell>
|
||||||
<TableCell align="left">{experiment.Namespace}</TableCell>
|
<TableCell align="left">
|
||||||
|
{experiment.Namespace}
|
||||||
|
</TableCell>
|
||||||
<TableCell align="left">
|
<TableCell align="left">
|
||||||
{experiment.Application}
|
{experiment.Application}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -346,6 +357,7 @@ const WorkflowTable = forwardRef(({ isCustom }: WorkflowTableProps, ref) => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</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