chore(scheduling): Added Edit Schedule Functionality + Fixed a CronWorkflow Bug 🐛 (#2657)
* Added Edit Schedule Functionality + Fixed a CronWorkflow Bug 🐛
* Reverting Sidebar text color
* Resolved comments/suggestions
* Adding missing translation
Signed-off-by: Sayan Mondal <sayan@chaosnative.com>
			
			
This commit is contained in:
		
							parent
							
								
									43d0e02810
								
							
						
					
					
						commit
						1a8e67e61d
					
				|  | @ -154,6 +154,15 @@ schedule: | |||
|   workflowBtn: Go to Workflow | ||||
|   backBtn: Go Back | ||||
| 
 | ||||
| editSchedule: | ||||
|   title: Edit Schedule | ||||
|   verify: Verify | ||||
|   cancel: Cancel | ||||
|   save: Save Changes | ||||
|   edit: Edit | ||||
|   theSchedule: The Schedule | ||||
|   successfullyCreated: is successfully created | ||||
| 
 | ||||
| community: | ||||
|   title: 'Community' | ||||
|   heading: 'Litmus Insights' | ||||
|  | @ -794,6 +803,8 @@ createWorkflow: | |||
|     errYaml: Error in CRD Yaml. | ||||
|     codeIsFine: Your code is fine. | ||||
|     youCanMoveOn: You can move on ! | ||||
|     test: test | ||||
|     YAML: YAML | ||||
|     button: | ||||
|       edit: Edit | ||||
|       viewYaml: View YAML | ||||
|  |  | |||
|  | @ -1,13 +1,8 @@ | |||
| import { Card, CardActionArea, Typography } from '@material-ui/core'; | ||||
| import React from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import useActions from '../../redux/actions'; | ||||
| import * as TemplateSelectionActions from '../../redux/actions/template'; | ||||
| import * as WorkflowActions from '../../redux/actions/workflow'; | ||||
| import { history } from '../../redux/configureStore'; | ||||
| import { ReactComponent as Arrow } from '../../svg/arrow.svg'; | ||||
| import { ReactComponent as ArrowDisabled } from '../../svg/arrow_disabled.svg'; | ||||
| import { getProjectID, getProjectRole } from '../../utils/getSearchParams'; | ||||
| import useStyles from './styles'; | ||||
| 
 | ||||
| interface CreateWorkflowCardProps { | ||||
|  | @ -19,28 +14,9 @@ const CreateWorkflowCard: React.FC<CreateWorkflowCardProps> = ({ | |||
| }) => { | ||||
|   const { t } = useTranslation(); | ||||
|   const classes = useStyles({ isDisabled }); | ||||
|   const template = useActions(TemplateSelectionActions); | ||||
|   const projectID = getProjectID(); | ||||
|   const userRole = getProjectRole(); | ||||
|   const workflowAction = useActions(WorkflowActions); | ||||
|   const handleCreateWorkflow = () => { | ||||
|     workflowAction.setWorkflowDetails({ | ||||
|       isCustomWorkflow: false, | ||||
|       customWorkflows: [], | ||||
|     }); | ||||
|     template.selectTemplate({ selectedTemplateID: 0, isDisable: true }); | ||||
|     history.push({ | ||||
|       pathname: '/create-workflow', | ||||
|       search: `?projectID=${projectID}&projectRole=${userRole}`, | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Card | ||||
|       onClick={isDisabled ? () => {} : handleCreateWorkflow} | ||||
|       className={classes.createCard} | ||||
|       data-cy="createWorkflow" | ||||
|     > | ||||
|     <Card className={classes.createCard} data-cy="createWorkflow"> | ||||
|       <CardActionArea className={classes.createCardAction}> | ||||
|         <Typography className={classes.createCardHeading}> | ||||
|           {t('home.workflow.heading')} | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| import { QuickActionCard } from 'litmus-ui'; | ||||
| import React from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import { constants } from '../../constants'; | ||||
| import { Role } from '../../models/graphql/user'; | ||||
| import useActions from '../../redux/actions'; | ||||
| import * as TabActions from '../../redux/actions/tabs'; | ||||
|  | @ -97,7 +98,7 @@ const LocalQuickActionCard: React.FC<LocalQuickActionCardProps> = ({ | |||
|       ? { | ||||
|           src: '/icons/survey.svg', | ||||
|           alt: 'survey', | ||||
|           onClick: () => window.open('https://forms.gle/qMuVphRyEWCFqjD56'), | ||||
|           onClick: () => window.open(constants.FeedbackForm), | ||||
|           text: t('quickActionCard.quickSurvey'), | ||||
|         } | ||||
|       : emptyData, | ||||
|  |  | |||
|  | @ -7,9 +7,8 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|   }, | ||||
|   drawerPaper: { | ||||
|     width: '100%', | ||||
|     backgroundColor: theme.palette.background.default, | ||||
|     backgroundColor: theme.palette.sidebarMenu, | ||||
|     position: 'relative', | ||||
|     color: 'inherit', | ||||
|   }, | ||||
|   litmusDiv: { | ||||
|     display: 'flex', | ||||
|  |  | |||
|  | @ -0,0 +1,13 @@ | |||
| export const constants = { | ||||
|   // Litmus HomePage [Component Used in -> LocalQuickActionCard]
 | ||||
|   FeedbackForm: 'https://forms.gle/KQp5qj8MUneMSxLp9', | ||||
| 
 | ||||
|   /** | ||||
|    * Schedule & Edit Schedule [Component Used in -> views/ScheduleWorkflow, | ||||
|    * pages/EditSchedule/Schedule] | ||||
|    * */ | ||||
|   recurringEveryHour: 'everyHr', | ||||
|   recurringEveryDay: 'everyDay', | ||||
|   recurringEveryWeek: 'everyWeek', | ||||
|   recurringEveryMonth: 'everyMonth', | ||||
| }; | ||||
|  | @ -25,6 +25,8 @@ const HomePage = lazy(() => import('../../pages/HomePage')); | |||
| const Community = lazy(() => import('../../pages/Community')); | ||||
| const Settings = lazy(() => import('../../pages/Settings')); | ||||
| const Targets = lazy(() => import('../../pages/Targets')); | ||||
| const EditSchedule = lazy(() => import('../../pages/EditSchedule')); | ||||
| const SetNewSchedule = lazy(() => import('../../pages/EditSchedule/Schedule')); | ||||
| const ConnectTargets = lazy(() => import('../../pages/ConnectTarget')); | ||||
| const AnalyticsPage = lazy(() => import('../../pages/AnalyticsPage')); | ||||
| const AnalyticsDashboard = lazy( | ||||
|  | @ -194,11 +196,16 @@ const Routes: React.FC = () => { | |||
|             path="/workflows/:workflowRunId" | ||||
|             component={WorkflowDetails} | ||||
|           /> | ||||
|           {/* <Route | ||||
|           <Route | ||||
|             exact | ||||
|             path="/workflows/schedule/:scheduleProjectID/:workflowName" // Check
 | ||||
|             component={SchedulePage} | ||||
|           /> */} | ||||
|             path="/workflows/schedule/:scheduleProjectID/:workflowName" | ||||
|             component={EditSchedule} | ||||
|           /> | ||||
|           <Route | ||||
|             exact | ||||
|             path="/workflows/schedule/:scheduleProjectID/:workflowName/set" | ||||
|             component={SetNewSchedule} | ||||
|           /> | ||||
|           <Route | ||||
|             exact | ||||
|             path="/workflows/template/:templateName" | ||||
|  |  | |||
|  | @ -28,9 +28,6 @@ export interface customWorkflow { | |||
| } | ||||
| 
 | ||||
| export interface WorkflowData { | ||||
|   id: string; | ||||
|   isRecurring: boolean; | ||||
|   isDisabled: boolean; | ||||
|   chaosEngineChanged: boolean; | ||||
|   namespace: string; | ||||
|   workflow_id?: string; | ||||
|  |  | |||
|  | @ -0,0 +1,767 @@ | |||
| import { | ||||
|   Divider, | ||||
|   FormControl, | ||||
|   FormControlLabel, | ||||
|   Radio, | ||||
|   RadioGroup, | ||||
|   Select, | ||||
|   Typography, | ||||
| } from '@material-ui/core'; | ||||
| import { ButtonFilled, ButtonOutlined } from 'litmus-ui'; | ||||
| import localforage from 'localforage'; | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import { useSelector } from 'react-redux'; | ||||
| import YAML from 'yaml'; | ||||
| import BackButton from '../../components/Button/BackButton'; | ||||
| import CustomDate from '../../components/DateTime/CustomDate/index'; | ||||
| import CustomTime from '../../components/DateTime/CustomTime/index'; | ||||
| import { constants } from '../../constants'; | ||||
| import Scaffold from '../../containers/layouts/Scaffold'; | ||||
| import { WorkflowData } from '../../models/redux/workflow'; | ||||
| import useActions from '../../redux/actions'; | ||||
| import * as TemplateSelectionActions from '../../redux/actions/template'; | ||||
| import * as WorkflowActions from '../../redux/actions/workflow'; | ||||
| import { history } from '../../redux/configureStore'; | ||||
| import { RootState } from '../../redux/reducers'; | ||||
| import { getProjectID, getProjectRole } from '../../utils/getSearchParams'; | ||||
| import { cronWorkflow, workflowOnce } from '../../utils/workflowTemplate'; | ||||
| import { fetchWorkflowNameFromManifest } from '../../utils/yamlUtils'; | ||||
| import SetTime from '../../views/CreateWorkflow/ScheduleWorkflow/SetTime'; | ||||
| import useStyles from '../../views/CreateWorkflow/ScheduleWorkflow/styles'; | ||||
| 
 | ||||
| interface ScheduleSyntax { | ||||
|   minute: string | undefined; | ||||
|   hour: string | undefined; | ||||
|   day_month: string | undefined; | ||||
|   month: string | undefined; | ||||
|   day_week: string; | ||||
| } | ||||
| 
 | ||||
| const ScheduleWorkflow = () => { | ||||
|   // Initial Cron State
 | ||||
|   const [cronValue, setCronValue] = useState<ScheduleSyntax>({ | ||||
|     minute: '*', | ||||
|     hour: '*', | ||||
|     day_month: '*', | ||||
|     month: '*', | ||||
|     day_week: '*', | ||||
|   }); | ||||
| 
 | ||||
|   const manifest = useSelector( | ||||
|     (state: RootState) => state.workflowManifest.manifest | ||||
|   ); | ||||
| 
 | ||||
|   // Redux States for Schedule
 | ||||
|   const workflowData: WorkflowData = useSelector( | ||||
|     (state: RootState) => state.workflowData | ||||
|   ); | ||||
| 
 | ||||
|   const { cronSyntax, scheduleType } = workflowData; | ||||
| 
 | ||||
|   const workflowAction = useActions(WorkflowActions); | ||||
|   const template = useActions(TemplateSelectionActions); | ||||
|   // Controls Radio Buttons
 | ||||
|   const [value, setValue] = React.useState( | ||||
|     workflowData.scheduleType.scheduleOnce | ||||
|   ); | ||||
|   const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||||
|     setValue(event.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   // Controls inner radio buttons of Recurring Schedule
 | ||||
|   const [valueDef, setValueDef] = React.useState( | ||||
|     workflowData.scheduleType.recurringSchedule | ||||
|   ); | ||||
|   const handleChangeInstance = (event: React.ChangeEvent<HTMLInputElement>) => { | ||||
|     setValueDef(event.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   const scheduleOnce = workflowOnce; | ||||
|   const scheduleMore = cronWorkflow; | ||||
| 
 | ||||
|   function EditYaml() { | ||||
|     const oldParsedYaml = YAML.parse(manifest); | ||||
|     let NewYaml: string; | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'Workflow' && | ||||
|       scheduleType.scheduleOnce !== 'now' | ||||
|     ) { | ||||
|       const oldParsedYaml = YAML.parse(manifest); | ||||
|       const newParsedYaml = YAML.parse(scheduleMore); | ||||
|       delete newParsedYaml.spec.workflowSpec; | ||||
|       newParsedYaml.spec.schedule = cronSyntax; | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.metadata.labels = { | ||||
|         workflow_id: workflowData.workflow_id, | ||||
|       }; | ||||
|       newParsedYaml.spec.workflowSpec = oldParsedYaml.spec; | ||||
|       const tz = { | ||||
|         timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC', | ||||
|       }; | ||||
|       Object.entries(tz).forEach(([key, value]) => { | ||||
|         newParsedYaml.spec[key] = value; | ||||
|       }); | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflowAction.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'CronWorkflow' && | ||||
|       scheduleType.scheduleOnce === 'now' | ||||
|     ) { | ||||
|       const oldParsedYaml = YAML.parse(manifest); | ||||
|       const newParsedYaml = YAML.parse(scheduleOnce); | ||||
|       delete newParsedYaml.spec; | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.spec = oldParsedYaml.spec.workflowSpec; | ||||
|       newParsedYaml.metadata.labels = { | ||||
|         workflow_id: workflowData.workflow_id, | ||||
|       }; | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflowAction.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'CronWorkflow' && | ||||
|       scheduleType.scheduleOnce !== 'now' | ||||
|       //   && !isDisabled
 | ||||
|     ) { | ||||
|       const newParsedYaml = YAML.parse(manifest); | ||||
|       newParsedYaml.spec.schedule = cronSyntax; | ||||
|       //   newParsedYaml.spec.suspend = false;
 | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.metadata.labels = { workflow_id: workflowData.workflow_id }; | ||||
|       const tz = { | ||||
|         timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC', | ||||
|       }; | ||||
|       Object.entries(tz).forEach(([key, value]) => { | ||||
|         newParsedYaml.spec[key] = value; | ||||
|       }); | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflowAction.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|     // if (oldParsedYaml.kind === 'CronWorkflow' && isDisabled === true) {
 | ||||
|     //   const newParsedYaml = YAML.parse(yaml);
 | ||||
|     //   newParsedYaml.spec.suspend = true;
 | ||||
|     //   const tz = {
 | ||||
|     //     timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC',
 | ||||
|     //   };
 | ||||
|     //   Object.entries(tz).forEach(([key, value]) => {
 | ||||
|     //     newParsedYaml.spec[key] = value;
 | ||||
|     //   });
 | ||||
|     //   NewYaml = YAML.stringify(newParsedYaml);
 | ||||
|     //   workflowAction.setWorkflowDetails({
 | ||||
|     //     link: NewLink,
 | ||||
|     //     yaml: NewYaml,
 | ||||
|     //   });
 | ||||
|     // }
 | ||||
|     localforage.setItem('editSchedule', true); | ||||
|   } | ||||
| 
 | ||||
|   // UseEffect to update the cron syntax with changes
 | ||||
|   useEffect(() => { | ||||
|     const cronSyntax = `${cronValue.minute} ${cronValue.hour} ${cronValue.day_month} ${cronValue.month} ${cronValue.day_week}`; | ||||
|     if (value === 'now') | ||||
|       workflowAction.setWorkflowDetails({ | ||||
|         cronSyntax: '', | ||||
|       }); | ||||
|     else | ||||
|       workflowAction.setWorkflowDetails({ | ||||
|         cronSyntax, | ||||
|       }); | ||||
|   }, [cronValue]); | ||||
| 
 | ||||
|   const classes = useStyles(); | ||||
|   const { t } = useTranslation(); | ||||
| 
 | ||||
|   // Sets individual minutes
 | ||||
|   const [minute, setMinute] = React.useState( | ||||
|     workflowData.scheduleInput.hour_interval | ||||
|   ); | ||||
| 
 | ||||
|   // Sets Weekdays
 | ||||
|   const [days, setDays] = React.useState(workflowData.scheduleInput.weekday); | ||||
| 
 | ||||
|   // Sets Day in number
 | ||||
|   const [dates, setDates] = React.useState(workflowData.scheduleInput.day); | ||||
| 
 | ||||
|   // Sets Time
 | ||||
|   const [selectedTime, setSelectedTime] = React.useState<Date | null>( | ||||
|     new Date(workflowData.scheduleInput.time) | ||||
|   ); | ||||
| 
 | ||||
|   // Sets Date
 | ||||
|   const [selectedDate, setSelectedDate] = React.useState<Date | null>( | ||||
|     new Date(workflowData.scheduleInput.date) | ||||
|   ); | ||||
| 
 | ||||
|   // Function to validate the date and time for "Specific Time" radio button
 | ||||
|   const validateTime = (time: Date | null, date: Date | null) => { | ||||
|     if ( | ||||
|       value === 'specificTime' && | ||||
|       (time?.setSeconds(0) as number) <= new Date().setSeconds(0) && | ||||
|       (date?.getTime() as number) <= new Date().getTime() | ||||
|     ) { | ||||
|       const newTime = new Date(); | ||||
|       newTime.setMinutes(newTime.getMinutes() + 5); | ||||
|       setSelectedTime(newTime); | ||||
|       workflowAction.setWorkflowDetails({ | ||||
|         scheduleInput: { | ||||
|           ...workflowData.scheduleInput, | ||||
|           date, | ||||
|           time: newTime, | ||||
|         }, | ||||
|       }); | ||||
|       setCronValue({ | ||||
|         ...cronValue, | ||||
|         minute: newTime.getMinutes().toString(), | ||||
|         hour: newTime.getHours().toString(), | ||||
|         day_month: date?.getDate().toString(), | ||||
|         month: (date && date.getMonth() + 1)?.toString(), | ||||
|       }); | ||||
|     } else { | ||||
|       workflowAction.setWorkflowDetails({ | ||||
|         scheduleInput: { | ||||
|           ...workflowData.scheduleInput, | ||||
|           date, | ||||
|           time, | ||||
|         }, | ||||
|       }); | ||||
|       setCronValue({ | ||||
|         ...cronValue, | ||||
|         minute: time?.getMinutes().toString(), | ||||
|         hour: time?.getHours().toString(), | ||||
|         day_month: date?.getDate().toString(), | ||||
|         month: (date && date.getMonth() + 1)?.toString(), | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleTimeChange = (time: Date | null) => { | ||||
|     setSelectedTime(time); | ||||
|     validateTime(time, selectedDate); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDateChange = (date: Date | null) => { | ||||
|     setSelectedDate(date); | ||||
|     validateTime(selectedTime, date); | ||||
|   }; | ||||
| 
 | ||||
|   // Function for recurring date change
 | ||||
|   const reccuringDateChange = (date: Date | null) => { | ||||
|     setSelectedTime(date); | ||||
|     setCronValue({ | ||||
|       ...cronValue, | ||||
|       minute: date?.getMinutes().toString(), | ||||
|       hour: date?.getHours().toString(), | ||||
|     }); | ||||
|     workflowAction.setWorkflowDetails({ | ||||
|       scheduleInput: { | ||||
|         ...workflowData.scheduleInput, | ||||
|         time: date, | ||||
|       }, | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   // Stores dates in an array
 | ||||
|   const names: number[] = [1]; | ||||
|   for (let i = 1; i <= 30; i += 1) { | ||||
|     names[i] = i + 1; | ||||
|   } | ||||
|   const mins: number[] = [0]; | ||||
|   for (let i = 0; i <= 59; i += 1) { | ||||
|     mins[i] = i; | ||||
|   } | ||||
|   // Day names
 | ||||
|   const weekdays: string[] = [ | ||||
|     'Monday', | ||||
|     'Tuesday', | ||||
|     'Wednesday', | ||||
|     'Thursday', | ||||
|     'Friday', | ||||
|     'Saturday', | ||||
|     'Sunday', | ||||
|   ]; | ||||
| 
 | ||||
|   // UseEffect to update the values of CronSyntax on radio button change
 | ||||
|   useEffect(() => { | ||||
|     if (value === 'now') { | ||||
|       setValueDef(''); | ||||
|       setCronValue({ | ||||
|         minute: '', | ||||
|         hour: '', | ||||
|         day_month: '', | ||||
|         month: '', | ||||
|         day_week: '', | ||||
|       }); | ||||
|     } | ||||
|     if (value === 'specificTime') { | ||||
|       setValueDef(''); | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|         day_month: selectedDate?.getDate().toString(), | ||||
|         month: (selectedDate && selectedDate.getMonth() + 1)?.toString(), | ||||
|         day_week: '*', | ||||
|       }); | ||||
|       if (workflowData.scheduleInput.time <= new Date()) { | ||||
|         const newTime = new Date(); | ||||
|         newTime.setMinutes(newTime.getMinutes() + 5); | ||||
|         setSelectedTime(newTime); | ||||
|         setCronValue({ | ||||
|           minute: newTime.getMinutes().toString(), | ||||
|           hour: newTime.getHours().toString(), | ||||
|           day_month: selectedDate?.getDate().toString(), | ||||
|           month: (selectedDate && selectedDate.getMonth() + 1)?.toString(), | ||||
|           day_week: '*', | ||||
|         }); | ||||
|         workflowAction.setWorkflowDetails({ | ||||
|           scheduleInput: { | ||||
|             ...workflowData.scheduleInput, | ||||
|             time: newTime, | ||||
|           }, | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|     if (valueDef === constants.recurringEveryHour) { | ||||
|       setCronValue({ | ||||
|         minute: minute.toString(), | ||||
|         hour: '0-23', | ||||
|         day_month: '*', | ||||
|         month: '*', | ||||
|         day_week: '*', | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === constants.recurringEveryDay) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|         day_month: '*', | ||||
|         month: '*', | ||||
|         day_week: '0-6', | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === constants.recurringEveryWeek) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|         day_month: '*', | ||||
|         month: '*', | ||||
|         day_week: days.slice(0, 3), | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === constants.recurringEveryMonth) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|         day_month: dates.toString(), | ||||
|         month: '*', | ||||
|         day_week: '*', | ||||
|       }); | ||||
|     } | ||||
|     if (value === 'recurringSchedule' && valueDef === '') { | ||||
|       template.selectTemplate({ isDisable: true }); | ||||
|     } else { | ||||
|       template.selectTemplate({ isDisable: false }); | ||||
|     } | ||||
|     workflowAction.setWorkflowDetails({ | ||||
|       scheduleType: { | ||||
|         scheduleOnce: value, | ||||
|         recurringSchedule: valueDef, | ||||
|       }, | ||||
|     }); | ||||
|   }, [valueDef, value]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     EditYaml(); | ||||
|   }, [cronValue]); | ||||
| 
 | ||||
|   return ( | ||||
|     <Scaffold> | ||||
|       <BackButton /> | ||||
|       <Typography className={classes.title}> | ||||
|         {t('editSchedule.title')} | ||||
|       </Typography> | ||||
|       <div className={classes.root}> | ||||
|         <div className={classes.innerContainer}> | ||||
|           <br /> | ||||
|           {/* Upper segment */} | ||||
|           <div className={classes.scSegments}> | ||||
|             <div> | ||||
|               <Typography className={classes.headerText}> | ||||
|                 <strong>{t('createWorkflow.scheduleWorkflow.header')}</strong> | ||||
|               </Typography> | ||||
| 
 | ||||
|               <div className={classes.schBody}> | ||||
|                 <Typography align="left" className={classes.description}> | ||||
|                   {t('createWorkflow.scheduleWorkflow.info')} | ||||
|                 </Typography> | ||||
|               </div> | ||||
|             </div> | ||||
|             <img | ||||
|               src="/icons/calendarWorkflowIcon.svg" | ||||
|               alt="calendar" | ||||
|               className={classes.calIcon} | ||||
|             /> | ||||
|           </div> | ||||
|           <Divider /> | ||||
| 
 | ||||
|           {/* Lower segment */} | ||||
|           <div className={classes.scFormControl}> | ||||
|             <FormControl component="fieldset" className={classes.formControl}> | ||||
|               <RadioGroup | ||||
|                 data-cy="ScheduleOptions" | ||||
|                 aria-label="schedule" | ||||
|                 name="schedule" | ||||
|                 value={value} | ||||
|                 onChange={handleChange} | ||||
|               > | ||||
|                 {/* options to choose schedule */} | ||||
|                 <FormControlLabel | ||||
|                   value="now" | ||||
|                   control={ | ||||
|                     <Radio | ||||
|                       classes={{ | ||||
|                         root: classes.radio, | ||||
|                         checked: classes.checked, | ||||
|                       }} | ||||
|                     /> | ||||
|                   } | ||||
|                   label={ | ||||
|                     <Typography className={classes.radioText}> | ||||
|                       {t('createWorkflow.scheduleWorkflow.radio.now')} | ||||
|                     </Typography> | ||||
|                   } | ||||
|                 /> | ||||
|                 {value === 'specificTime' && ( | ||||
|                   <div className={classes.schLater}> | ||||
|                     <Typography className={classes.captionText}> | ||||
|                       {t('createWorkflow.scheduleWorkflow.radio.future')} | ||||
|                     </Typography> | ||||
|                     <div className={classes.innerSpecific}> | ||||
|                       <CustomDate | ||||
|                         selectedDate={selectedDate} | ||||
|                         handleDateChange={(event) => { | ||||
|                           handleDateChange(event); | ||||
|                         }} | ||||
|                         disabled={false} | ||||
|                       /> | ||||
|                       <CustomTime | ||||
|                         handleDateChange={(event) => { | ||||
|                           handleTimeChange(event); | ||||
|                         }} | ||||
|                         value={selectedTime} | ||||
|                         ampm | ||||
|                         disabled={false} | ||||
|                       /> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 )} | ||||
|                 <FormControlLabel | ||||
|                   value="recurringSchedule" | ||||
|                   control={ | ||||
|                     <Radio | ||||
|                       classes={{ | ||||
|                         root: classes.radio, | ||||
|                         checked: classes.checked, | ||||
|                       }} | ||||
|                     /> | ||||
|                   } | ||||
|                   label={ | ||||
|                     <Typography className={classes.radioText}> | ||||
|                       {t('createWorkflow.scheduleWorkflow.radio.recurr')} | ||||
|                     </Typography> | ||||
|                   } | ||||
|                 /> | ||||
|                 {value === 'recurringSchedule' && ( | ||||
|                   <div className={classes.schLater}> | ||||
|                     <Typography className={classes.captionText}> | ||||
|                       {t('createWorkflow.scheduleWorkflow.radio.rightRecurr')} | ||||
|                     </Typography> | ||||
| 
 | ||||
|                     {/* options to select time of recurring schedule */} | ||||
|                     <div className={classes.innerRecurring}> | ||||
|                       <FormControl component="fieldset"> | ||||
|                         <RadioGroup | ||||
|                           aria-label="instanceDef" | ||||
|                           name="instanceDef" | ||||
|                           value={valueDef} | ||||
|                           onChange={(event) => { | ||||
|                             handleChangeInstance(event); | ||||
|                           }} | ||||
|                         > | ||||
|                           <FormControlLabel | ||||
|                             value={constants.recurringEveryHour} | ||||
|                             control={ | ||||
|                               <Radio | ||||
|                                 classes={{ | ||||
|                                   root: classes.radio, | ||||
|                                   checked: classes.checked, | ||||
|                                 }} | ||||
|                               /> | ||||
|                             } | ||||
|                             label={t( | ||||
|                               'createWorkflow.scheduleWorkflow.every.hr' | ||||
|                             )} | ||||
|                           /> | ||||
|                           {valueDef === constants.recurringEveryHour && ( | ||||
|                             <div> | ||||
|                               <div className={classes.scRandom}> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.at')} | ||||
|                                 </Typography> | ||||
|                                 <SetTime | ||||
|                                   data={mins} | ||||
|                                   handleChange={(event) => { | ||||
|                                     setMinute(event.target.value as number); | ||||
|                                     setCronValue({ | ||||
|                                       ...cronValue, | ||||
|                                       minute: (event.target | ||||
|                                         .value as number).toString(), | ||||
|                                       hour: '0-23', | ||||
|                                     }); | ||||
|                                     workflowAction.setWorkflowDetails({ | ||||
|                                       scheduleInput: { | ||||
|                                         ...workflowData.scheduleInput, | ||||
|                                         hour_interval: event.target | ||||
|                                           .value as number, | ||||
|                                       }, | ||||
|                                     }); | ||||
|                                   }} | ||||
|                                   value={minute} | ||||
|                                 /> | ||||
|                                 {minute === 0 || minute === 1 ? ( | ||||
|                                   <Typography> | ||||
|                                     {t('createWorkflow.scheduleWorkflow.min')} | ||||
|                                   </Typography> | ||||
|                                 ) : ( | ||||
|                                   <Typography> | ||||
|                                     {t('createWorkflow.scheduleWorkflow.mins')} | ||||
|                                   </Typography> | ||||
|                                 )} | ||||
|                               </div> | ||||
|                             </div> | ||||
|                           )} | ||||
|                           <FormControlLabel | ||||
|                             value={constants.recurringEveryDay} | ||||
|                             control={ | ||||
|                               <Radio | ||||
|                                 classes={{ | ||||
|                                   root: classes.radio, | ||||
|                                   checked: classes.checked, | ||||
|                                 }} | ||||
|                               /> | ||||
|                             } | ||||
|                             label={t( | ||||
|                               'createWorkflow.scheduleWorkflow.every.day' | ||||
|                             )} | ||||
|                           /> | ||||
|                           {valueDef === constants.recurringEveryDay && ( | ||||
|                             <div> | ||||
|                               <div className={classes.scRandom}> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.at')} | ||||
|                                 </Typography> | ||||
|                                 <CustomTime | ||||
|                                   handleDateChange={(date: Date | null) => { | ||||
|                                     setSelectedTime(date); | ||||
|                                     setCronValue({ | ||||
|                                       ...cronValue, | ||||
|                                       minute: date?.getMinutes().toString(), | ||||
|                                       hour: date?.getHours().toString(), | ||||
|                                       day_week: '0-6', | ||||
|                                     }); | ||||
|                                     workflowAction.setWorkflowDetails({ | ||||
|                                       scheduleInput: { | ||||
|                                         ...workflowData.scheduleInput, | ||||
|                                         time: date, | ||||
|                                       }, | ||||
|                                     }); | ||||
|                                   }} | ||||
|                                   value={selectedTime} | ||||
|                                   ampm | ||||
|                                   disabled={false} | ||||
|                                 /> | ||||
|                               </div> | ||||
|                             </div> | ||||
|                           )} | ||||
|                           <FormControlLabel | ||||
|                             value={constants.recurringEveryWeek} | ||||
|                             control={ | ||||
|                               <Radio | ||||
|                                 classes={{ | ||||
|                                   root: classes.radio, | ||||
|                                   checked: classes.checked, | ||||
|                                 }} | ||||
|                               /> | ||||
|                             } | ||||
|                             label={t( | ||||
|                               'createWorkflow.scheduleWorkflow.every.week' | ||||
|                             )} | ||||
|                           /> | ||||
|                           {valueDef === constants.recurringEveryWeek && ( | ||||
|                             <div> | ||||
|                               <div className={classes.scRandom}> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.on')} | ||||
|                                 </Typography> | ||||
|                                 <FormControl className={classes.formControlDT}> | ||||
|                                   <Select | ||||
|                                     className={classes.select} | ||||
|                                     disableUnderline | ||||
|                                     value={days} | ||||
|                                     onChange={(e) => { | ||||
|                                       setCronValue({ | ||||
|                                         ...cronValue, | ||||
|                                         month: '*', | ||||
|                                         day_week: ((e.target | ||||
|                                           .value as unknown) as string).slice( | ||||
|                                           0, | ||||
|                                           3 | ||||
|                                         ), | ||||
|                                       }); | ||||
|                                       setDays( | ||||
|                                         (e.target.value as unknown) as string | ||||
|                                       ); | ||||
|                                       workflowAction.setWorkflowDetails({ | ||||
|                                         scheduleInput: { | ||||
|                                           ...workflowData.scheduleInput, | ||||
|                                           weekday: (e.target | ||||
|                                             .value as unknown) as string, | ||||
|                                         }, | ||||
|                                       }); | ||||
|                                     }} | ||||
|                                     label="days" | ||||
|                                     inputProps={{ | ||||
|                                       name: 'days', | ||||
|                                       style: { | ||||
|                                         fontSize: '0.75rem', | ||||
|                                         height: '0.43rem', | ||||
|                                       }, | ||||
|                                     }} | ||||
|                                   > | ||||
|                                     {weekdays.map((day) => ( | ||||
|                                       <option | ||||
|                                         key={day} | ||||
|                                         className={classes.opt} | ||||
|                                         value={day} | ||||
|                                       > | ||||
|                                         {day} | ||||
|                                       </option> | ||||
|                                     ))} | ||||
|                                   </Select> | ||||
|                                 </FormControl> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.at')} | ||||
|                                 </Typography> | ||||
|                                 <CustomTime | ||||
|                                   handleDateChange={(date: Date | null) => { | ||||
|                                     reccuringDateChange(date); | ||||
|                                   }} | ||||
|                                   value={selectedTime} | ||||
|                                   ampm | ||||
|                                   disabled={false} | ||||
|                                 /> | ||||
|                               </div> | ||||
|                             </div> | ||||
|                           )} | ||||
|                           <FormControlLabel | ||||
|                             value={constants.recurringEveryMonth} | ||||
|                             control={ | ||||
|                               <Radio | ||||
|                                 classes={{ | ||||
|                                   root: classes.radio, | ||||
|                                   checked: classes.checked, | ||||
|                                 }} | ||||
|                               /> | ||||
|                             } | ||||
|                             label={t( | ||||
|                               'createWorkflow.scheduleWorkflow.every.month' | ||||
|                             )} | ||||
|                           /> | ||||
|                           {valueDef === constants.recurringEveryMonth && ( | ||||
|                             <div> | ||||
|                               <div className={classes.scRandom}> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.on')} | ||||
|                                 </Typography> | ||||
|                                 <SetTime | ||||
|                                   data={names} | ||||
|                                   handleChange={(event) => { | ||||
|                                     setCronValue({ | ||||
|                                       ...cronValue, | ||||
|                                       day_month: (event.target | ||||
|                                         .value as number).toString(), | ||||
|                                     }); | ||||
|                                     setDates(event.target.value as number); | ||||
|                                     workflowAction.setWorkflowDetails({ | ||||
|                                       scheduleInput: { | ||||
|                                         ...workflowData.scheduleInput, | ||||
|                                         day: event.target.value as number, | ||||
|                                       }, | ||||
|                                     }); | ||||
|                                   }} | ||||
|                                   value={dates} | ||||
|                                 /> | ||||
|                                 <Typography className={classes.scRandsub1}> | ||||
|                                   {t('createWorkflow.scheduleWorkflow.at')} | ||||
|                                 </Typography> | ||||
|                                 <CustomTime | ||||
|                                   handleDateChange={(date: Date | null) => { | ||||
|                                     reccuringDateChange(date); | ||||
|                                   }} | ||||
|                                   value={selectedTime} | ||||
|                                   ampm | ||||
|                                   disabled={false} | ||||
|                                 /> | ||||
|                               </div> | ||||
|                             </div> | ||||
|                           )} | ||||
|                         </RadioGroup> | ||||
|                       </FormControl> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 )} | ||||
|               </RadioGroup> | ||||
|             </FormControl> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       {/* Cancel and Save Button */} | ||||
|       <div className={classes.buttonDiv} aria-label="buttons"> | ||||
|         <ButtonOutlined | ||||
|           onClick={() => { | ||||
|             history.push({ | ||||
|               pathname: `/workflows/`, | ||||
|               search: `?projectID=${getProjectID()}&projectRole=${getProjectRole()}`, | ||||
|             }); | ||||
|           }} | ||||
|         > | ||||
|           Cancel | ||||
|         </ButtonOutlined> | ||||
|         <ButtonFilled | ||||
|           onClick={() => | ||||
|             history.push({ | ||||
|               pathname: `/workflows/schedule/${getProjectID()}/${fetchWorkflowNameFromManifest( | ||||
|                 manifest | ||||
|               )}`,
 | ||||
|               search: `?projectID=${getProjectID()}&projectRole=${getProjectRole()}`, | ||||
|             }) | ||||
|           } | ||||
|         > | ||||
|           {t('editSchedule.verify')} | ||||
|         </ButtonFilled> | ||||
|       </div> | ||||
|     </Scaffold> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default ScheduleWorkflow; | ||||
|  | @ -0,0 +1,504 @@ | |||
| import { useMutation, useQuery } from '@apollo/client'; | ||||
| import Typography from '@material-ui/core/Typography'; | ||||
| import EditIcon from '@material-ui/icons/Edit'; | ||||
| import cronstrue from 'cronstrue'; | ||||
| import { ButtonFilled, ButtonOutlined, Modal } from 'litmus-ui'; | ||||
| import localforage from 'localforage'; | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import { useSelector } from 'react-redux'; | ||||
| import { useParams } from 'react-router-dom'; | ||||
| import YAML from 'yaml'; | ||||
| import AdjustedWeights from '../../components/AdjustedWeights'; | ||||
| import BackButton from '../../components/Button/BackButton'; | ||||
| import Loader from '../../components/Loader'; | ||||
| import YamlEditor from '../../components/YamlEditor/Editor'; | ||||
| import { parseYamlValidations } from '../../components/YamlEditor/Validations'; | ||||
| import Scaffold from '../../containers/layouts/Scaffold'; | ||||
| import { UPDATE_SCHEDULE } from '../../graphql/mutations'; | ||||
| import { SCHEDULE_DETAILS } from '../../graphql/queries'; | ||||
| import { | ||||
|   CreateWorkFlowInput, | ||||
|   UpdateWorkflowResponse, | ||||
|   WeightMap, | ||||
| } from '../../models/graphql/createWorkflowData'; | ||||
| import { ScheduleDataVars, Schedules } from '../../models/graphql/scheduleData'; | ||||
| import { experimentMap, WorkflowData } from '../../models/redux/workflow'; | ||||
| import useActions from '../../redux/actions'; | ||||
| import * as TabActions from '../../redux/actions/tabs'; | ||||
| import * as TemplateSelectionActions from '../../redux/actions/template'; | ||||
| import * as WorkflowActions from '../../redux/actions/workflow'; | ||||
| import { history } from '../../redux/configureStore'; | ||||
| import { RootState } from '../../redux/reducers'; | ||||
| import { getProjectID, getProjectRole } from '../../utils/getSearchParams'; | ||||
| import { fetchWorkflowNameFromManifest } from '../../utils/yamlUtils'; | ||||
| import useStyles from './styles'; | ||||
| 
 | ||||
| interface URLParams { | ||||
|   workflowName: string; | ||||
|   scheduleProjectID: string; | ||||
| } | ||||
| 
 | ||||
| interface Weights { | ||||
|   experimentName: string; | ||||
|   weight: number; | ||||
| } | ||||
| 
 | ||||
| interface WorkflowProps { | ||||
|   name: string; | ||||
|   description: string; | ||||
| } | ||||
| 
 | ||||
| const EditSchedule: React.FC = () => { | ||||
|   const classes = useStyles(); | ||||
|   const { t } = useTranslation(); | ||||
| 
 | ||||
|   const [workflow, setWorkflow] = useState<WorkflowProps>({ | ||||
|     name: '', | ||||
|     description: '', | ||||
|   }); | ||||
|   const [weights, setWeights] = useState<experimentMap[]>([ | ||||
|     { | ||||
|       experimentName: '', | ||||
|       weight: 0, | ||||
|     }, | ||||
|   ]); | ||||
| 
 | ||||
|   const [open, setOpen] = React.useState(false); | ||||
|   const [finishModalOpen, setFinishModalOpen] = useState(false); | ||||
|   const [errorModal, setErrorModal] = useState(false); | ||||
| 
 | ||||
|   const template = useActions(TemplateSelectionActions); | ||||
|   const workflowData: WorkflowData = useSelector( | ||||
|     (state: RootState) => state.workflowData | ||||
|   ); | ||||
|   const workflowAction = useActions(WorkflowActions); | ||||
|   // Get Parameters from URL
 | ||||
|   const paramData: URLParams = useParams(); | ||||
|   const projectID = getProjectID(); | ||||
|   const userRole = getProjectRole(); | ||||
| 
 | ||||
|   // Apollo query to get the scheduled data
 | ||||
|   const { data, loading } = useQuery<Schedules, ScheduleDataVars>( | ||||
|     SCHEDULE_DETAILS, | ||||
|     { | ||||
|       variables: { projectID: paramData.scheduleProjectID }, | ||||
|       fetchPolicy: 'cache-and-network', | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   const manifest = useSelector( | ||||
|     (state: RootState) => state.workflowManifest.manifest | ||||
|   ); | ||||
| 
 | ||||
|   const wfDetails = | ||||
|     data && | ||||
|     data.getScheduledWorkflows.filter( | ||||
|       (wf) => wf.workflow_name === paramData.workflowName | ||||
|     )[0]; | ||||
|   const doc = new YAML.Document(); | ||||
|   const w: Weights[] = []; | ||||
|   const { cronSyntax, clusterid, clustername } = workflowData; | ||||
| 
 | ||||
|   const [createChaosWorkFlow, { error: workflowError }] = useMutation< | ||||
|     UpdateWorkflowResponse, | ||||
|     CreateWorkFlowInput | ||||
|   >(UPDATE_SCHEDULE, { | ||||
|     onCompleted: () => { | ||||
|       setFinishModalOpen(true); | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|   const handleMutation = () => { | ||||
|     if ( | ||||
|       workflow.name.length !== 0 && | ||||
|       workflow.description.length !== 0 && | ||||
|       weights.length !== 0 | ||||
|     ) { | ||||
|       const weightData: WeightMap[] = []; | ||||
| 
 | ||||
|       weights.forEach((data) => { | ||||
|         weightData.push({ | ||||
|           experiment_name: data.experimentName, | ||||
|           weightage: data.weight, | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       /* JSON.stringify takes 3 parameters [object to be converted, | ||||
|       a function to alter the conversion, spaces to be shown in final result for indentation ] */ | ||||
|       const yml = YAML.parse(manifest); | ||||
|       const yamlJson = JSON.stringify(yml, null, 2); // Converted to Stringified JSON
 | ||||
| 
 | ||||
|       const chaosWorkFlowInputs = { | ||||
|         workflow_id: wfDetails?.workflow_id, | ||||
|         workflow_manifest: yamlJson, | ||||
|         cronSyntax, | ||||
|         workflow_name: fetchWorkflowNameFromManifest(manifest), | ||||
|         workflow_description: workflow.description, | ||||
|         isCustomWorkflow: false, | ||||
|         weightages: weightData, | ||||
|         project_id: projectID, | ||||
|         cluster_id: clusterid, | ||||
|       }; | ||||
| 
 | ||||
|       createChaosWorkFlow({ | ||||
|         variables: { ChaosWorkFlowInput: chaosWorkFlowInputs }, | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     localforage.getItem('editSchedule').then((isCronEdited) => { | ||||
|       if (wfDetails !== undefined) { | ||||
|         for (let i = 0; i < wfDetails?.weightages.length; i++) { | ||||
|           w.push({ | ||||
|             experimentName: wfDetails?.weightages[i].experiment_name, | ||||
|             weight: wfDetails?.weightages[i].weightage, | ||||
|           }); | ||||
|         } | ||||
|         doc.contents = JSON.parse(wfDetails?.workflow_manifest); | ||||
|         workflowAction.setWorkflowManifest({ | ||||
|           manifest: isCronEdited === null ? doc.toString() : manifest, | ||||
|         }); | ||||
|         setWorkflow({ | ||||
|           name: wfDetails?.workflow_name, | ||||
|           description: wfDetails?.workflow_description, | ||||
|         }); | ||||
|         localforage.setItem('weights', w); | ||||
|         workflowAction.setWorkflowDetails({ | ||||
|           workflow_id: wfDetails?.workflow_id, | ||||
|           clusterid: wfDetails?.cluster_id, | ||||
|           cronSyntax: | ||||
|             isCronEdited === null ? wfDetails?.cronSyntax : cronSyntax, | ||||
|           scheduleType: { | ||||
|             scheduleOnce: | ||||
|               wfDetails?.cronSyntax === '' ? 'now' : 'recurringSchedule', | ||||
|             recurringSchedule: '', | ||||
|           }, | ||||
|           scheduleInput: { | ||||
|             hour_interval: 0, | ||||
|             day: 1, | ||||
|             weekday: 'Monday', | ||||
|             time: new Date(), | ||||
|             date: new Date(), | ||||
|           }, | ||||
|         }); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     template.selectTemplate({ selectTemplateID: 0, isDisable: false }); | ||||
|     setWeights(w); | ||||
|   }, [data]); | ||||
| 
 | ||||
|   const tabs = useActions(TabActions); | ||||
| 
 | ||||
|   const [yamlStatus, setYamlStatus] = React.useState( | ||||
|     `${t('createWorkflow.verifyCommit.codeIsFine')}` | ||||
|   ); | ||||
|   const [modified, setModified] = React.useState(false); | ||||
| 
 | ||||
|   const handleEditOpen = () => { | ||||
|     setModified(false); | ||||
|     setOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleEditClose = () => { | ||||
|     setModified(true); | ||||
|     setOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleNext = () => { | ||||
|     handleMutation(); | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const editorValidations = parseYamlValidations(manifest, classes); | ||||
|     const stateObject = { | ||||
|       markers: editorValidations.markers, | ||||
|       annotations: editorValidations.annotations, | ||||
|     }; | ||||
|     if (stateObject.annotations.length > 0) { | ||||
|       setYamlStatus(`${t('createWorkflow.verifyCommit.errYaml')}`); | ||||
|     } else { | ||||
|       setYamlStatus(`${t('createWorkflow.verifyCommit.codeIsFine')}`); | ||||
|     } | ||||
|   }, [modified]); | ||||
| 
 | ||||
|   const handleFinishModal = () => { | ||||
|     history.push({ | ||||
|       pathname: `/workflows`, | ||||
|       search: `?projectID=${projectID}&projectRole=${userRole}`, | ||||
|     }); | ||||
|     setFinishModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleErrorModalClose = () => { | ||||
|     setErrorModal(false); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Scaffold> | ||||
|       {loading ? ( | ||||
|         <Loader /> | ||||
|       ) : ( | ||||
|         <> | ||||
|           <BackButton /> | ||||
|           <Typography className={classes.title}> | ||||
|             {t('editSchedule.title')} | ||||
|           </Typography> | ||||
|           <div className={classes.root}> | ||||
|             <div className={classes.innerContainer}> | ||||
|               <Typography className={classes.sumText}> | ||||
|                 {t('createWorkflow.verifyCommit.summary.header')} | ||||
|               </Typography> | ||||
| 
 | ||||
|               <div className={classes.outerSum}> | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.summary.workflowName')}: | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   <div className={classes.col2} data-cy="WorkflowName"> | ||||
|                     <Typography> | ||||
|                       {fetchWorkflowNameFromManifest(manifest)} | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.summary.clustername')}: | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   <Typography className={classes.schCol2}> | ||||
|                     {clustername} | ||||
|                   </Typography> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.summary.desc')}: | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   <div className={classes.col2}> | ||||
|                     <Typography>{workflow.description}</Typography> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.summary.schedule')}: | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   <div className={classes.schCol2}> | ||||
|                     {cronSyntax === '' ? ( | ||||
|                       <Typography> | ||||
|                         {t('createWorkflow.verifyCommit.summary.schedulingNow')} | ||||
|                       </Typography> | ||||
|                     ) : ( | ||||
|                       <Typography>{cronstrue.toString(cronSyntax)}</Typography> | ||||
|                     )} | ||||
| 
 | ||||
|                     <ButtonOutlined | ||||
|                       className={classes.editButton} | ||||
|                       onClick={() => | ||||
|                         history.push({ | ||||
|                           pathname: `/workflows/schedule/${projectID}/${fetchWorkflowNameFromManifest( | ||||
|                             manifest | ||||
|                           )}/set`,
 | ||||
|                           search: `?projectID=${projectID}&projectRole=${userRole}`, | ||||
|                         }) | ||||
|                       } | ||||
|                     > | ||||
|                       <EditIcon className={classes.editIcon} data-cy="edit" /> | ||||
|                       {t('editSchedule.edit')} | ||||
|                     </ButtonOutlined> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.summary.adjustedWeights')} | ||||
|                       : | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   {weights.length === 0 ? ( | ||||
|                     <div> | ||||
|                       <Typography className={classes.col2}> | ||||
|                         {t('createWorkflow.verifyCommit.error')} | ||||
|                       </Typography> | ||||
|                     </div> | ||||
|                   ) : ( | ||||
|                     <div className={classes.adjWeights}> | ||||
|                       <div className={classes.progress}> | ||||
|                         {weights.map((Test) => ( | ||||
|                           <AdjustedWeights | ||||
|                             key={Test.weight} | ||||
|                             testName={`${Test.experimentName} ${t( | ||||
|                               'createWorkflow.verifyCommit.test' | ||||
|                             )}`}
 | ||||
|                             testValue={Test.weight} | ||||
|                             spacing={false} | ||||
|                             icon={false} | ||||
|                           /> | ||||
|                         ))} | ||||
|                       </div> | ||||
|                     </div> | ||||
|                   )} | ||||
|                 </div> | ||||
|                 <div className={classes.summaryDiv}> | ||||
|                   <div className={classes.innerSumDiv}> | ||||
|                     <Typography className={classes.col1}> | ||||
|                       {t('createWorkflow.verifyCommit.YAML')} | ||||
|                     </Typography> | ||||
|                   </div> | ||||
|                   <div className={classes.yamlFlex}> | ||||
|                     {weights.length === 0 ? ( | ||||
|                       <Typography className={classes.spacingHorizontal}> | ||||
|                         {t('createWorkflow.verifyCommit.errYaml')} | ||||
|                       </Typography> | ||||
|                     ) : ( | ||||
|                       <Typography> | ||||
|                         <b>{yamlStatus}</b> | ||||
|                         <span className={classes.spacingHorizontal}> | ||||
|                           {t('createWorkflow.verifyCommit.youCanMoveOn')} | ||||
|                         </span> | ||||
|                       </Typography> | ||||
|                     )} | ||||
|                     <br /> | ||||
|                     <ButtonFilled | ||||
|                       className={classes.verifyYAMLButton} | ||||
|                       onClick={handleEditOpen} | ||||
|                     > | ||||
|                       {t('createWorkflow.verifyCommit.button.viewYaml')} | ||||
|                     </ButtonFilled> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           {/* Cancel and Save Button */} | ||||
|           <div className={classes.buttonDiv} aria-label="buttons"> | ||||
|             <ButtonOutlined | ||||
|               onClick={() => { | ||||
|                 history.push({ | ||||
|                   pathname: `/workflows/`, | ||||
|                   search: `?projectID=${projectID}&projectRole=${userRole}`, | ||||
|                 }); | ||||
|               }} | ||||
|             > | ||||
|               {t('editSchedule.cancel')} | ||||
|             </ButtonOutlined> | ||||
|             <ButtonFilled onClick={() => handleNext()}> | ||||
|               {t('editSchedule.save')} | ||||
|             </ButtonFilled> | ||||
|           </div> | ||||
| 
 | ||||
|           <Modal | ||||
|             open={open} | ||||
|             onClose={handleEditClose} | ||||
|             width="60%" | ||||
|             modalActions={ | ||||
|               <ButtonOutlined | ||||
|                 onClick={handleEditClose} | ||||
|                 className={classes.closeBtn} | ||||
|               > | ||||
|                 ✕ | ||||
|               </ButtonOutlined> | ||||
|             } | ||||
|           > | ||||
|             <YamlEditor content={manifest} filename={workflow.name} readOnly /> | ||||
|           </Modal> | ||||
| 
 | ||||
|           {/* Finish Modal */} | ||||
|           <div> | ||||
|             <Modal | ||||
|               data-cy="FinishModal" | ||||
|               open={finishModalOpen} | ||||
|               onClose={handleFinishModal} | ||||
|               width="60%" | ||||
|               aria-labelledby="simple-modal-title" | ||||
|               aria-describedby="simple-modal-description" | ||||
|               modalActions={ | ||||
|                 <div data-cy="GoToWorkflowButton"> | ||||
|                   <ButtonOutlined onClick={handleFinishModal}> | ||||
|                     ✕ | ||||
|                   </ButtonOutlined> | ||||
|                 </div> | ||||
|               } | ||||
|             > | ||||
|               <div className={classes.modal}> | ||||
|                 <img src="/icons/finish.svg" alt="mark" /> | ||||
|                 <div className={classes.heading}> | ||||
|                   {t('editSchedule.theSchedule')} | ||||
|                   <br /> | ||||
|                   <span className={classes.successful}>{workflow.name}</span>, | ||||
|                   <br /> | ||||
|                   <span className={classes.bold}> | ||||
|                     {t('editSchedule.successfullyCreated')} | ||||
|                   </span> | ||||
|                 </div> | ||||
|                 <div className={classes.headWorkflow}> | ||||
|                   {t('workflowStepper.congratulationsSub1')} <br />{' '} | ||||
|                   {t('workflowStepper.congratulationsSub2')} | ||||
|                 </div> | ||||
|                 <div className={classes.button}> | ||||
|                   <ButtonFilled | ||||
|                     data-cy="selectFinish" | ||||
|                     onClick={() => { | ||||
|                       handleFinishModal(); | ||||
|                       tabs.changeWorkflowsTabs(0); | ||||
|                       history.push({ | ||||
|                         pathname: '/workflows', | ||||
|                         search: `?projectID=${projectID}&projectRole=${userRole}`, | ||||
|                       }); | ||||
|                     }} | ||||
|                   > | ||||
|                     <div>{t('workflowStepper.workflowBtn')}</div> | ||||
|                   </ButtonFilled> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </Modal> | ||||
|             <Modal | ||||
|               open={errorModal} | ||||
|               onClose={handleErrorModalClose} | ||||
|               width="60%" | ||||
|               modalActions={ | ||||
|                 <ButtonOutlined onClick={handleErrorModalClose}> | ||||
|                   ✕ | ||||
|                 </ButtonOutlined> | ||||
|               } | ||||
|             > | ||||
|               <div className={classes.modal}> | ||||
|                 <img src="/icons/red-cross.svg" alt="mark" /> | ||||
|                 <div className={classes.heading}> | ||||
|                   <strong>{t('workflowStepper.workflowFailed')}</strong> | ||||
|                 </div> | ||||
|                 <div className={classes.headWorkflow}> | ||||
|                   <Typography> | ||||
|                     {t('workflowStepper.error')} : {workflowError?.message} | ||||
|                   </Typography> | ||||
|                 </div> | ||||
|                 <div className={classes.button}> | ||||
|                   <ButtonFilled | ||||
|                     data-cy="selectFinish" | ||||
|                     onClick={() => { | ||||
|                       setErrorModal(false); | ||||
|                     }} | ||||
|                   > | ||||
|                     <div>{t('workflowStepper.back')}</div> | ||||
|                   </ButtonFilled> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </Modal> | ||||
|           </div> | ||||
|         </> | ||||
|       )} | ||||
|     </Scaffold> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default EditSchedule; | ||||
|  | @ -0,0 +1,217 @@ | |||
| import { makeStyles, Theme } from '@material-ui/core/styles'; | ||||
| 
 | ||||
| const useStyles = makeStyles((theme: Theme) => ({ | ||||
|   horizontalLine: { | ||||
|     background: theme.palette.border.main, | ||||
|   }, | ||||
|   title: { | ||||
|     padding: theme.spacing(0, 2), | ||||
|     fontWeight: 700, | ||||
|     fontSize: '2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '2.3rem', | ||||
|     }, | ||||
|   }, | ||||
|   root: { | ||||
|     background: theme.palette.background.paper, | ||||
|     color: theme.palette.text.primary, | ||||
|     padding: theme.spacing(1, 2), | ||||
|     margin: theme.spacing(2, 'auto'), | ||||
|     width: '100%', | ||||
|     flexDirection: 'column', | ||||
|   }, | ||||
| 
 | ||||
|   // Inner Container
 | ||||
|   innerContainer: { | ||||
|     margin: theme.spacing(4, 'auto'), | ||||
|     width: '95%', // Inner width of the container
 | ||||
|   }, | ||||
| 
 | ||||
|   suHeader: { | ||||
|     display: 'flex', | ||||
|     justifyContent: 'space-between', | ||||
|   }, | ||||
|   headerText: { | ||||
|     fontSize: '1.2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '1.4rem', | ||||
|     }, | ||||
|   }, | ||||
|   description: { | ||||
|     margin: theme.spacing(3, 0), | ||||
|     fontSize: '1rem', | ||||
|   }, | ||||
|   bfinIcon: { | ||||
|     width: '7rem', | ||||
|     height: '6.31rem', | ||||
|   }, | ||||
| 
 | ||||
|   // Body
 | ||||
|   outerSum: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'column', | ||||
|   }, | ||||
|   summaryDiv: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     justifyContent: 'flex-start', | ||||
|     alignItems: 'baseline', | ||||
|     margin: theme.spacing(1, 0), | ||||
|   }, | ||||
|   innerSumDiv: { | ||||
|     alignContent: 'center', | ||||
|     display: 'table-cell', | ||||
|     verticalAlign: 'middle', | ||||
|     width: '20%', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       width: '10%', | ||||
|     }, | ||||
|   }, | ||||
|   sumText: { | ||||
|     width: '100%', | ||||
|     margin: theme.spacing(2, 0), | ||||
|     fontWeight: 700, | ||||
|     fontSize: '1.2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '1.4rem', | ||||
|     }, | ||||
|   }, | ||||
|   col1: { | ||||
|     alignContent: 'center', | ||||
|     color: theme.palette.highlight, | ||||
|     fontSize: '1rem', | ||||
|     paddingTop: theme.spacing(0.5), | ||||
|     verticalAlign: 'middle', | ||||
|   }, | ||||
|   schedule: { | ||||
|     fontSize: '0.85rem', | ||||
|     padding: theme.spacing(0.75, 0, 2, 0), | ||||
|   }, | ||||
|   col2: { | ||||
|     color: theme.palette.text.primary, | ||||
|     marginLeft: theme.spacing(5), | ||||
|     fontWeight: 700, | ||||
|     width: '75%', | ||||
|   }, | ||||
|   schCol2: { | ||||
|     width: '75%', | ||||
|     marginLeft: theme.spacing(5), | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     justifyContent: 'space-between', | ||||
|   }, | ||||
|   clusterName: { | ||||
|     fontSize: '0.85rem', | ||||
|     marginLeft: theme.spacing(7), | ||||
|     paddingTop: theme.spacing(0.5), | ||||
|   }, | ||||
|   editButton: { | ||||
|     height: '1rem', | ||||
|   }, | ||||
|   editIcon: { | ||||
|     color: theme.palette.text.primary, | ||||
|     height: '0.8rem', | ||||
|   }, | ||||
|   link: { | ||||
|     fontSize: '0.875rem', | ||||
|     color: theme.palette.secondary.dark, | ||||
|   }, | ||||
|   adjWeights: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     justifyContent: 'space-between', | ||||
| 
 | ||||
|     width: '80%', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       width: '90%', | ||||
|     }, | ||||
|   }, | ||||
|   config: { | ||||
|     height: '3rem', | ||||
|     fontSize: '0.9375rem', | ||||
|     color: theme.palette.text.disabled, | ||||
|     width: '30rem', | ||||
|     margin: theme.spacing(3.75, 0, 30, 0), | ||||
|   }, | ||||
|   typoCol2: { | ||||
|     fontSize: '1rem', | ||||
|   }, | ||||
|   textEdit: { | ||||
|     marginTop: theme.spacing(7.5), | ||||
|   }, | ||||
|   buttonOutlineText: { | ||||
|     padding: theme.spacing(1.5), | ||||
|   }, | ||||
|   errorText: { | ||||
|     color: theme.palette.error.main, | ||||
|     fontSize: '1rem', | ||||
|     marginLeft: theme.spacing(5), | ||||
|   }, | ||||
|   yamlFlex: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'column', | ||||
|     width: '75%', | ||||
|     marginLeft: theme.spacing(5), | ||||
|   }, | ||||
|   progress: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     flexWrap: 'wrap', | ||||
|     flexGrow: 1, | ||||
|     marginLeft: theme.spacing(5), | ||||
|   }, | ||||
|   spacingHorizontal: { | ||||
|     margin: theme.spacing(0, 1), | ||||
|   }, | ||||
|   buttomPad: { | ||||
|     paddingBottom: theme.spacing(3.75), | ||||
|   }, | ||||
|   closeBtn: { | ||||
|     color: theme.palette.secondary.contrastText, | ||||
|   }, | ||||
|   buttonDiv: { | ||||
|     display: 'flex', | ||||
|     justifyContent: 'space-between', | ||||
|     width: '100%', | ||||
|   }, | ||||
|   verifyYAMLButton: { | ||||
|     width: '20%', | ||||
|   }, | ||||
|   bold: { | ||||
|     fontWeight: 700, | ||||
|   }, | ||||
| 
 | ||||
|   // Modal
 | ||||
|   modal: { | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       padding: theme.spacing(10), | ||||
|     }, | ||||
|     padding: theme.spacing(3), | ||||
|   }, | ||||
|   heading: { | ||||
|     fontSize: '2rem', | ||||
|     textalign: 'center', | ||||
|     marginTop: theme.spacing(3), | ||||
|     color: theme.palette.text.primary, | ||||
|   }, | ||||
|   headWorkflow: { | ||||
|     fontsize: '2rem', | ||||
|     textalign: 'center', | ||||
|     color: theme.palette.text.primary, | ||||
|     marginTop: theme.spacing(3), | ||||
|   }, | ||||
|   button: { | ||||
|     color: theme.palette.text.primary, | ||||
|     textAlign: 'center', | ||||
|     marginTop: theme.spacing(5), | ||||
|   }, | ||||
|   closeButton: { | ||||
|     borderColor: theme.palette.border.main, | ||||
|   }, | ||||
|   successful: { | ||||
|     fontSize: '2.2rem', | ||||
|     fontWeight: 'bold', | ||||
|     margin: theme.spacing(2, 0), | ||||
|   }, | ||||
| })); | ||||
| export default useStyles; | ||||
|  | @ -8,9 +8,6 @@ import { | |||
| import createReducer from './createReducer'; | ||||
| 
 | ||||
| const initialState: WorkflowData = { | ||||
|   id: '', | ||||
|   isRecurring: false, | ||||
|   isDisabled: false, | ||||
|   chaosEngineChanged: false, | ||||
|   namespace: 'litmus', | ||||
|   clusterid: '', | ||||
|  |  | |||
|  | @ -70,6 +70,10 @@ const parsed = (yaml: string) => { | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| export const fetchWorkflowNameFromManifest = (manifest: string) => { | ||||
|   return YAML.parse(manifest).metadata.name; | ||||
| }; | ||||
| 
 | ||||
| export const getWorkflowParameter = (parameterString: string) => { | ||||
|   return parameterString | ||||
|     .substring(1, parameterString.length - 1) | ||||
|  |  | |||
|  | @ -24,7 +24,6 @@ import { RERUN_CHAOS_WORKFLOW } from '../../../graphql/mutations'; | |||
| import { ScheduleWorkflow } from '../../../models/graphql/scheduleData'; | ||||
| import useActions from '../../../redux/actions'; | ||||
| import * as TabActions from '../../../redux/actions/tabs'; | ||||
| import * as WorkflowActions from '../../../redux/actions/workflow'; | ||||
| import { history } from '../../../redux/configureStore'; | ||||
| import { ReactComponent as CrossMarkIcon } from '../../../svg/crossmark.svg'; | ||||
| import timeDifferenceForDate from '../../../utils/datesModifier'; | ||||
|  | @ -63,8 +62,6 @@ const TableData: React.FC<TableDataProps> = ({ | |||
|     setPopAnchorEl(null); | ||||
|   }; | ||||
| 
 | ||||
|   const workflow = useActions(WorkflowActions); | ||||
| 
 | ||||
|   const handlePopOverClick = (event: React.MouseEvent<HTMLElement>) => { | ||||
|     setPopAnchorEl(event.currentTarget); | ||||
|   }; | ||||
|  | @ -125,13 +122,6 @@ const TableData: React.FC<TableDataProps> = ({ | |||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   // If regularity is not Once then set recurring schedule state to true
 | ||||
|   if (data.cronSyntax !== '') { | ||||
|     workflow.setWorkflowDetails({ | ||||
|       isRecurring: true, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   const [reRunChaosWorkFlow] = useMutation(RERUN_CHAOS_WORKFLOW, { | ||||
|     onCompleted: () => { | ||||
|       tabs.changeWorkflowsTabs(0); | ||||
|  |  | |||
|  | @ -18,11 +18,14 @@ import { useSelector } from 'react-redux'; | |||
| import YAML from 'yaml'; | ||||
| import CustomDate from '../../../components/DateTime/CustomDate/index'; | ||||
| import CustomTime from '../../../components/DateTime/CustomTime/index'; | ||||
| import { constants } from '../../../constants'; | ||||
| import { WorkflowData } from '../../../models/redux/workflow'; | ||||
| import useActions from '../../../redux/actions'; | ||||
| import * as TemplateSelectionActions from '../../../redux/actions/template'; | ||||
| import * as WorkflowActions from '../../../redux/actions/workflow'; | ||||
| import { RootState } from '../../../redux/reducers'; | ||||
| import { cronWorkflow, workflowOnce } from '../../../utils/workflowTemplate'; | ||||
| import { fetchWorkflowNameFromManifest } from '../../../utils/yamlUtils'; | ||||
| import SetTime from './SetTime/index'; | ||||
| import useStyles from './styles'; | ||||
| 
 | ||||
|  | @ -54,6 +57,10 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|   ); | ||||
|   const workflow = useActions(WorkflowActions); | ||||
|   const template = useActions(TemplateSelectionActions); | ||||
| 
 | ||||
|   const scheduleOnce = workflowOnce; | ||||
|   const scheduleMore = cronWorkflow; | ||||
| 
 | ||||
|   // Controls Radio Buttons
 | ||||
|   const [value, setValue] = React.useState( | ||||
|     workflowData.scheduleType.scheduleOnce | ||||
|  | @ -81,10 +88,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|       workflow.setWorkflowDetails({ | ||||
|         cronSyntax, | ||||
|       }); | ||||
|     if (value === 'disable') | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: true, | ||||
|       }); | ||||
|   }, [cronValue]); | ||||
| 
 | ||||
|   const classes = useStyles(); | ||||
|  | @ -163,6 +166,76 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|     validateTime(selectedTime, date); | ||||
|   }; | ||||
| 
 | ||||
|   function EditYaml() { | ||||
|     const oldParsedYaml = YAML.parse(manifest); | ||||
|     let NewYaml: string; | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'Workflow' && | ||||
|       workflowData.scheduleType.scheduleOnce !== 'now' | ||||
|     ) { | ||||
|       const oldParsedYaml = YAML.parse(manifest); | ||||
|       const newParsedYaml = YAML.parse(scheduleMore); | ||||
|       delete newParsedYaml.spec.workflowSpec; | ||||
|       newParsedYaml.spec.schedule = workflowData.cronSyntax; | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.metadata.labels = { | ||||
|         workflow_id: workflowData.workflow_id, | ||||
|       }; | ||||
|       newParsedYaml.spec.workflowSpec = oldParsedYaml.spec; | ||||
|       const tz = { | ||||
|         timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC', | ||||
|       }; | ||||
|       Object.entries(tz).forEach(([key, value]) => { | ||||
|         newParsedYaml.spec[key] = value; | ||||
|       }); | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflow.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'CronWorkflow' && | ||||
|       workflowData.scheduleType.scheduleOnce === 'now' | ||||
|     ) { | ||||
|       const oldParsedYaml = YAML.parse(manifest); | ||||
|       const newParsedYaml = YAML.parse(scheduleOnce); | ||||
|       delete newParsedYaml.spec; | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.spec = oldParsedYaml.spec.workflowSpec; | ||||
|       newParsedYaml.metadata.labels = { | ||||
|         workflow_id: workflowData.workflow_id, | ||||
|       }; | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflow.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|     if ( | ||||
|       oldParsedYaml.kind === 'CronWorkflow' && | ||||
|       workflowData.scheduleType.scheduleOnce !== 'now' | ||||
|       //   && !isDisabled
 | ||||
|     ) { | ||||
|       const newParsedYaml = YAML.parse(manifest); | ||||
|       newParsedYaml.spec.schedule = workflowData.cronSyntax; | ||||
|       //   newParsedYaml.spec.suspend = false;
 | ||||
|       delete newParsedYaml.metadata.generateName; | ||||
|       newParsedYaml.metadata.name = fetchWorkflowNameFromManifest(manifest); | ||||
|       newParsedYaml.metadata.labels = { workflow_id: workflowData.workflow_id }; | ||||
|       const tz = { | ||||
|         timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC', | ||||
|       }; | ||||
|       Object.entries(tz).forEach(([key, value]) => { | ||||
|         newParsedYaml.spec[key] = value; | ||||
|       }); | ||||
|       NewYaml = YAML.stringify(newParsedYaml); | ||||
|       workflow.setWorkflowManifest({ | ||||
|         manifest: NewYaml, | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Function for recurring date change
 | ||||
|   const reccuringDateChange = (date: Date | null) => { | ||||
|     setSelectedTime(date); | ||||
|  | @ -202,9 +275,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|   // UseEffect to update the values of CronSyntax on radio button change
 | ||||
|   useEffect(() => { | ||||
|     if (value === 'now') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|       setValueDef(''); | ||||
|       setCronValue({ | ||||
|         minute: '', | ||||
|  | @ -214,11 +284,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|         day_week: '', | ||||
|       }); | ||||
|     } | ||||
|     if (value === 'disable') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: true, | ||||
|       }); | ||||
|     } | ||||
|     if (value === 'specificTime') { | ||||
|       setValueDef(''); | ||||
|       setCronValue({ | ||||
|  | @ -247,10 +312,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|         }); | ||||
|       } | ||||
|     } | ||||
|     if (valueDef === 'everyHr') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|     if (valueDef === constants.recurringEveryHour) { | ||||
|       setCronValue({ | ||||
|         minute: minute.toString(), | ||||
|         hour: '0-23', | ||||
|  | @ -259,10 +321,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|         day_week: '*', | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === 'everyDay') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|     if (valueDef === constants.recurringEveryDay) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|  | @ -271,10 +330,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|         day_week: '0-6', | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === 'everyWeek') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|     if (valueDef === constants.recurringEveryWeek) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|  | @ -283,10 +339,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|         day_week: days.slice(0, 3), | ||||
|       }); | ||||
|     } | ||||
|     if (valueDef === 'everyMonth') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|     if (valueDef === constants.recurringEveryMonth) { | ||||
|       setCronValue({ | ||||
|         minute: selectedTime?.getMinutes().toString(), | ||||
|         hour: selectedTime?.getHours().toString(), | ||||
|  | @ -296,9 +349,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|       }); | ||||
|     } | ||||
|     if (value === 'recurringSchedule' && valueDef === '') { | ||||
|       workflow.setWorkflowDetails({ | ||||
|         isDisabled: false, | ||||
|       }); | ||||
|       template.selectTemplate({ isDisable: true }); | ||||
|     } else { | ||||
|       template.selectTemplate({ isDisable: false }); | ||||
|  | @ -312,6 +362,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|   }, [valueDef, value]); | ||||
| 
 | ||||
|   function onNext() { | ||||
|     EditYaml(); | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|  | @ -354,7 +405,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|               onChange={handleChange} | ||||
|             > | ||||
|               {/* options to choose schedule */} | ||||
|               {!workflowData.isRecurring ? ( | ||||
|               <FormControlLabel | ||||
|                 value="now" | ||||
|                 control={ | ||||
|  | @ -371,39 +421,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                   </Typography> | ||||
|                 } | ||||
|               /> | ||||
|               ) : YAML.parse(manifest).spec.suspend === true ? ( | ||||
|                 <></> | ||||
|               ) : workflowData.isRecurring ? ( | ||||
|                 <FormControlLabel | ||||
|                   value="disable" | ||||
|                   control={ | ||||
|                     <Radio | ||||
|                       classes={{ | ||||
|                         root: classes.radio, | ||||
|                         checked: classes.checked, | ||||
|                       }} | ||||
|                     /> | ||||
|                   } | ||||
|                   label={ | ||||
|                     <Typography className={classes.radioText}> | ||||
|                       Disable Schedule | ||||
|                     </Typography> | ||||
|                   } | ||||
|                 /> | ||||
|               ) : ( | ||||
|                 <></> | ||||
|               )} | ||||
|               {/* <FormControlLabel | ||||
|                 value="specificTime" | ||||
|                 disabled | ||||
|                 control={<Radio classes={{ root: classes.radio, checked: classes.checked }}/>} | ||||
|                 label={ | ||||
|                   <Typography className={classes.radioText}> | ||||
|                     {t('createWorkflow.scheduleWorkflow.radio.specific')} | ||||
|                   </Typography> | ||||
|                 } | ||||
|               /> */} | ||||
|               {value === 'specificTime' ? ( | ||||
|               {value === 'specificTime' && ( | ||||
|                 <div className={classes.schLater}> | ||||
|                   <Typography className={classes.captionText}> | ||||
|                     {t('createWorkflow.scheduleWorkflow.radio.future')} | ||||
|  | @ -426,8 +444,6 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                     /> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               ) : ( | ||||
|                 <></> | ||||
|               )} | ||||
|               <FormControlLabel | ||||
|                 value="recurringSchedule" | ||||
|  | @ -442,7 +458,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                   </Typography> | ||||
|                 } | ||||
|               /> | ||||
|               {value === 'recurringSchedule' ? ( | ||||
|               {value === 'recurringSchedule' && ( | ||||
|                 <div className={classes.schLater}> | ||||
|                   <Typography className={classes.captionText}> | ||||
|                     {t('createWorkflow.scheduleWorkflow.radio.rightRecurr')} | ||||
|  | @ -460,7 +476,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                         }} | ||||
|                       > | ||||
|                         <FormControlLabel | ||||
|                           value="everyHr" | ||||
|                           value={constants.recurringEveryHour} | ||||
|                           control={ | ||||
|                             <Radio | ||||
|                               classes={{ | ||||
|  | @ -471,7 +487,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                           } | ||||
|                           label={t('createWorkflow.scheduleWorkflow.every.hr')} | ||||
|                         /> | ||||
|                         {valueDef === 'everyHr' ? ( | ||||
|                         {valueDef === constants.recurringEveryHour && ( | ||||
|                           <div> | ||||
|                             <div className={classes.scRandom}> | ||||
|                               <Typography className={classes.scRandsub1}> | ||||
|  | @ -508,11 +524,9 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                               )} | ||||
|                             </div> | ||||
|                           </div> | ||||
|                         ) : ( | ||||
|                           <></> | ||||
|                         )} | ||||
|                         <FormControlLabel | ||||
|                           value="everyDay" | ||||
|                           value={constants.recurringEveryDay} | ||||
|                           control={ | ||||
|                             <Radio | ||||
|                               classes={{ | ||||
|  | @ -523,7 +537,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                           } | ||||
|                           label={t('createWorkflow.scheduleWorkflow.every.day')} | ||||
|                         /> | ||||
|                         {valueDef === 'everyDay' ? ( | ||||
|                         {valueDef === constants.recurringEveryDay && ( | ||||
|                           <div> | ||||
|                             <div className={classes.scRandom}> | ||||
|                               <Typography className={classes.scRandsub1}> | ||||
|  | @ -551,11 +565,9 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                               /> | ||||
|                             </div> | ||||
|                           </div> | ||||
|                         ) : ( | ||||
|                           <></> | ||||
|                         )} | ||||
|                         <FormControlLabel | ||||
|                           value="everyWeek" | ||||
|                           value={constants.recurringEveryWeek} | ||||
|                           control={ | ||||
|                             <Radio | ||||
|                               classes={{ | ||||
|  | @ -568,7 +580,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                             'createWorkflow.scheduleWorkflow.every.week' | ||||
|                           )} | ||||
|                         /> | ||||
|                         {valueDef === 'everyWeek' ? ( | ||||
|                         {valueDef === constants.recurringEveryWeek && ( | ||||
|                           <div> | ||||
|                             <div className={classes.scRandom}> | ||||
|                               <Typography className={classes.scRandsub1}> | ||||
|  | @ -633,11 +645,9 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                               /> | ||||
|                             </div> | ||||
|                           </div> | ||||
|                         ) : ( | ||||
|                           <></> | ||||
|                         )} | ||||
|                         <FormControlLabel | ||||
|                           value="everyMonth" | ||||
|                           value={constants.recurringEveryMonth} | ||||
|                           control={ | ||||
|                             <Radio | ||||
|                               classes={{ | ||||
|  | @ -650,7 +660,7 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                             'createWorkflow.scheduleWorkflow.every.month' | ||||
|                           )} | ||||
|                         /> | ||||
|                         {valueDef === 'everyMonth' ? ( | ||||
|                         {valueDef === constants.recurringEveryMonth && ( | ||||
|                           <div> | ||||
|                             <div className={classes.scRandom}> | ||||
|                               <Typography className={classes.scRandsub1}> | ||||
|  | @ -687,15 +697,11 @@ const ScheduleWorkflow = forwardRef((_, ref) => { | |||
|                               /> | ||||
|                             </div> | ||||
|                           </div> | ||||
|                         ) : ( | ||||
|                           <></> | ||||
|                         )} | ||||
|                       </RadioGroup> | ||||
|                     </FormControl> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               ) : ( | ||||
|                 <></> | ||||
|               )} | ||||
|             </RadioGroup> | ||||
|           </FormControl> | ||||
|  |  | |||
|  | @ -5,15 +5,23 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     background: theme.palette.background.paper, | ||||
|     color: theme.palette.text.primary, | ||||
|     padding: theme.spacing(0, 2), | ||||
|     margin: '0 auto', | ||||
|     margin: '1rem auto', | ||||
|     width: '98%', | ||||
|     height: '100%', | ||||
|     flexDirection: 'column', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       width: '99%', | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   title: { | ||||
|     padding: theme.spacing(0, 2), | ||||
|     fontWeight: 700, | ||||
|     fontSize: '2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '2.3rem', | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   // Inner Container
 | ||||
|   innerContainer: { | ||||
|     margin: theme.spacing(4, 'auto'), | ||||
|  | @ -28,7 +36,10 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
| 
 | ||||
|   headerText: { | ||||
|     marginTop: theme.spacing(1.25), | ||||
|     fontSize: '1.5625rem', | ||||
|     fontSize: '1.2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '1.4rem', | ||||
|     }, | ||||
|   }, | ||||
|   schBody: { | ||||
|     width: '32.18rem', | ||||
|  | @ -68,6 +79,11 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     }, | ||||
|   }, | ||||
|   checked: {}, | ||||
|   buttonDiv: { | ||||
|     display: 'flex', | ||||
|     justifyContent: 'space-between', | ||||
|     width: '100%', | ||||
|   }, | ||||
| 
 | ||||
|   /* For recurring schedule options */ | ||||
|   scRandom: { | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ import * as WorkflowActions from '../../../redux/actions/workflow'; | |||
| import { history } from '../../../redux/configureStore'; | ||||
| import { RootState } from '../../../redux/reducers'; | ||||
| import { getProjectID, getProjectRole } from '../../../utils/getSearchParams'; | ||||
| import { fetchWorkflowNameFromManifest } from '../../../utils/yamlUtils'; | ||||
| import useStyles from './styles'; | ||||
| 
 | ||||
| interface WorkflowProps { | ||||
|  | @ -67,7 +68,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|     (state: RootState) => state.workflowData | ||||
|   ); | ||||
| 
 | ||||
|   const { clusterid, cronSyntax, isDisabled, clustername } = workflowData; | ||||
|   const { clusterid, cronSyntax, clustername } = workflowData; | ||||
| 
 | ||||
|   const manifest = useSelector( | ||||
|     (state: RootState) => state.workflowManifest.manifest | ||||
|  | @ -85,9 +86,6 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|       }); | ||||
|     } | ||||
|   }; | ||||
|   const fetchWorkflowNameFromManifest = (manifest: string) => { | ||||
|     return YAML.parse(manifest).metadata.name; | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     saveWorkflowGenerateName(manifest); | ||||
|  | @ -111,7 +109,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|   }, []); | ||||
| 
 | ||||
|   const [yamlStatus, setYamlStatus] = React.useState( | ||||
|     'Your code is fine. You can move on!' | ||||
|     `${t('createWorkflow.verifyCommit.codeIsFine')}` | ||||
|   ); | ||||
| 
 | ||||
|   const [modified, setModified] = React.useState(false); | ||||
|  | @ -245,6 +243,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|     localforage.removeItem('hasSetWorkflowData'); | ||||
|     localforage.removeItem('weights'); | ||||
|     localforage.removeItem('selectedHub'); | ||||
|     localforage.removeItem('editSchedule'); | ||||
|     setFinishModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|  | @ -265,7 +264,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|           <div className={classes.suHeader}> | ||||
|             <div> | ||||
|               <Typography className={classes.headerText}> | ||||
|                 <strong> {t('createWorkflow.verifyCommit.header')}</strong> | ||||
|                 {t('createWorkflow.verifyCommit.header')} | ||||
|               </Typography> | ||||
|               <Typography className={classes.description}> | ||||
|                 {t('createWorkflow.verifyCommit.info')} | ||||
|  | @ -280,7 +279,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|           <Divider /> | ||||
| 
 | ||||
|           <Typography className={classes.sumText}> | ||||
|             <strong>{t('createWorkflow.verifyCommit.summary.header')}</strong> | ||||
|             {t('createWorkflow.verifyCommit.summary.header')} | ||||
|           </Typography> | ||||
| 
 | ||||
|           <div className={classes.outerSum}> | ||||
|  | @ -298,7 +297,6 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|                   onChange={(e) => | ||||
|                     handleNameChange({ changedName: e.target.value }) | ||||
|                   } | ||||
|                   disabled={workflowData.isRecurring} | ||||
|                 /> | ||||
|               </div> | ||||
|             </div> | ||||
|  | @ -339,18 +337,7 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|                 </Typography> | ||||
|               </div> | ||||
|               <div className={classes.schCol2}> | ||||
|                 {/* <CustomDate disabled={edit} /> | ||||
|               <CustomTime | ||||
|                 handleDateChange={handleDateChange} | ||||
|                 value={selectedDate} | ||||
|                 ampm | ||||
|                 disabled={edit} | ||||
|               /> */} | ||||
|                 {isDisabled ? ( | ||||
|                   <Typography className={classes.schedule}> | ||||
|                     {t('createWorkflow.verifyCommit.summary.disabled')} | ||||
|                   </Typography> | ||||
|                 ) : cronSyntax === '' ? ( | ||||
|                 {cronSyntax === '' ? ( | ||||
|                   <Typography className={classes.schedule}> | ||||
|                     {t('createWorkflow.verifyCommit.summary.schedulingNow')} | ||||
|                   </Typography> | ||||
|  | @ -360,9 +347,9 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|                   </Typography> | ||||
|                 )} | ||||
| 
 | ||||
|                 <div className={classes.editButton1}> | ||||
|                 <div className={classes.editButton}> | ||||
|                   <IconButton> | ||||
|                     <EditIcon className={classes.editbtn} data-cy="edit" /> | ||||
|                     <EditIcon className={classes.editIcon} data-cy="edit" /> | ||||
|                   </IconButton> | ||||
|                 </div> | ||||
|               </div> | ||||
|  | @ -376,29 +363,25 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|               {weights.length === 0 ? ( | ||||
|                 <div> | ||||
|                   <Typography className={classes.errorText}> | ||||
|                     <strong>{t('createWorkflow.verifyCommit.error')}</strong> | ||||
|                     {t('createWorkflow.verifyCommit.error')} | ||||
|                   </Typography> | ||||
|                 </div> | ||||
|               ) : ( | ||||
|                 <div className={classes.adjWeights}> | ||||
|                   <div | ||||
|                     className={classes.progress} | ||||
|                     style={{ flexWrap: 'wrap' }} | ||||
|                   > | ||||
|                   <div className={classes.progress}> | ||||
|                     {WorkflowTestData.map((Test) => ( | ||||
|                       <AdjustedWeights | ||||
|                         key={Test.weight} | ||||
|                         testName={`${Test.experimentName} test`} | ||||
|                         testName={`${Test.experimentName} ${t( | ||||
|                           'createWorkflow.verifyCommit.test' | ||||
|                         )}`}
 | ||||
|                         testValue={Test.weight} | ||||
|                         spacing={false} | ||||
|                         icon={false} | ||||
|                       /> | ||||
|                     ))} | ||||
|                   </div> | ||||
|                   <ButtonOutlined | ||||
|                     disabled={workflowData.isRecurring} | ||||
|                     data-cy="testRunButton" | ||||
|                   > | ||||
|                   <ButtonOutlined data-cy="testRunButton"> | ||||
|                     {t('createWorkflow.verifyCommit.button.edit')} | ||||
|                   </ButtonOutlined> | ||||
|                 </div> | ||||
|  | @ -406,22 +389,28 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|             </div> | ||||
|             <div className={classes.summaryDiv}> | ||||
|               <div className={classes.innerSumDiv}> | ||||
|                 <Typography className={classes.col1}>YAML:</Typography> | ||||
|                 <Typography className={classes.col1}> | ||||
|                   {t('createWorkflow.verifyCommit.YAML')} | ||||
|                 </Typography> | ||||
|               </div> | ||||
|               <div className={classes.yamlFlex}> | ||||
|                 {weights.length === 0 ? ( | ||||
|                   <Typography> | ||||
|                     {' '} | ||||
|                     {t('createWorkflow.verifyCommit.errYaml')}{' '} | ||||
|                   <Typography className={classes.spacingHorizontal}> | ||||
|                     {t('createWorkflow.verifyCommit.errYaml')} | ||||
|                   </Typography> | ||||
|                 ) : ( | ||||
|                   <Typography> | ||||
|                     <b>{yamlStatus}</b>{' '} | ||||
|                     <b>{yamlStatus}</b> | ||||
|                     <span className={classes.spacingHorizontal}> | ||||
|                       {t('createWorkflow.verifyCommit.youCanMoveOn')} | ||||
|                     </span> | ||||
|                   </Typography> | ||||
|                 )} | ||||
|                 <br /> | ||||
|                 <ButtonFilled style={{ width: '60%' }} onClick={handleOpen}> | ||||
|                 <ButtonFilled | ||||
|                   className={classes.verifyYAMLButton} | ||||
|                   onClick={handleOpen} | ||||
|                 > | ||||
|                   {t('createWorkflow.verifyCommit.button.viewYaml')} | ||||
|                 </ButtonFilled> | ||||
|               </div> | ||||
|  | @ -467,7 +456,9 @@ const VerifyCommit = forwardRef((_, ref) => { | |||
|               <br /> | ||||
|               <span className={classes.successful}>{workflow.name}</span>, | ||||
|               <br /> | ||||
|               <strong>{t('workflowStepper.successful')}</strong> | ||||
|               <span className={classes.bold}> | ||||
|                 {t('workflowStepper.successful')} | ||||
|               </span> | ||||
|             </div> | ||||
|             <div className={classes.headWorkflow}> | ||||
|               {t('workflowStepper.congratulationsSub1')} <br />{' '} | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     justifyContent: 'space-between', | ||||
|   }, | ||||
|   headerText: { | ||||
|     fontWeight: 700, | ||||
|     fontSize: '1.2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '1.4rem', | ||||
|  | @ -64,8 +65,8 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|   }, | ||||
|   sumText: { | ||||
|     width: '100%', | ||||
|     marginTop: theme.spacing(4.5), | ||||
|     marginBottom: theme.spacing(3), | ||||
|     margin: theme.spacing(2, 0), | ||||
|     fontWeight: 700, | ||||
|     fontSize: '1.2rem', | ||||
|     [theme.breakpoints.up('lg')]: { | ||||
|       fontSize: '1.4rem', | ||||
|  | @ -98,11 +99,12 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     marginLeft: theme.spacing(7), | ||||
|     paddingTop: theme.spacing(0.5), | ||||
|   }, | ||||
|   editButton1: { | ||||
|     marginLeft: theme.spacing(1), | ||||
|   editButton: { | ||||
|     height: '1rem', | ||||
|   }, | ||||
|   editbtn: { | ||||
|     color: theme.palette.text.secondary, | ||||
|   editIcon: { | ||||
|     color: theme.palette.text.primary, | ||||
|     height: '0.8rem', | ||||
|   }, | ||||
|   link: { | ||||
|     fontSize: '0.875rem', | ||||
|  | @ -135,8 +137,12 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|   buttonOutlineText: { | ||||
|     padding: theme.spacing(1.5), | ||||
|   }, | ||||
|   spacingHorizontal: { | ||||
|     margin: theme.spacing(0, 1), | ||||
|   }, | ||||
|   errorText: { | ||||
|     color: theme.palette.error.main, | ||||
|     fontWeight: 700, | ||||
|     fontSize: '1rem', | ||||
|     marginLeft: theme.spacing(5), | ||||
|   }, | ||||
|  | @ -148,6 +154,7 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|   progress: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     flexWrap: 'wrap', | ||||
|     flexGrow: 1, | ||||
|     marginLeft: theme.spacing(5), | ||||
|   }, | ||||
|  | @ -159,6 +166,9 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     marginTop: theme.spacing(-6), | ||||
|     marginRight: theme.spacing(-2.5), | ||||
|   }, | ||||
|   verifyYAMLButton: { | ||||
|     width: '60%', | ||||
|   }, | ||||
| 
 | ||||
|   // Modal
 | ||||
|   modal: { | ||||
|  | @ -190,6 +200,10 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|   successful: { | ||||
|     fontSize: '2.2rem', | ||||
|     fontWeight: 'bold', | ||||
|     margin: theme.spacing(2, 0), | ||||
|   }, | ||||
|   bold: { | ||||
|     fontWeight: 700, | ||||
|   }, | ||||
| })); | ||||
| export default useStyles; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue