Added Disable Schedule feature + InputField Fixes + Modifications (#2400)
* Fixed InputFields + Dropdowns * Added Disable Schedule feature + Modifications * Fixes DeepScan issue * Fixed Radio Buttons * Added to Translation Signed-off-by: Sayan Mondal <sayan.mondal@mayadata.io>
This commit is contained in:
parent
cdab6d7798
commit
616eea5a73
|
@ -121,7 +121,7 @@ schedule:
|
|||
backBtn: Go Back
|
||||
|
||||
workflowUnderground:
|
||||
heading: 'Click on test to see detailed log of your workflow'
|
||||
heading: 'Click on Info to see details of your workflow'
|
||||
|
||||
community:
|
||||
title: 'Community'
|
||||
|
@ -164,7 +164,7 @@ error:
|
|||
backHome: Go back home
|
||||
|
||||
workflowDetails:
|
||||
detailedLog: Click on test to see detailed log of your workflow
|
||||
detailedLog: Click on Info to see details of your workflow
|
||||
fetchError: An error has occurred while fetching the data
|
||||
######################################
|
||||
############ Views #############
|
||||
|
@ -181,6 +181,9 @@ chaosWorkflows:
|
|||
comparativeResults: Comparative results of selected workflows which ran successfully
|
||||
once: Once
|
||||
seeAnalytics: See analytics
|
||||
browseSchedule:
|
||||
regularityOnce: Once
|
||||
showExperiment: Show Experiment
|
||||
|
||||
settings:
|
||||
accountsTab:
|
||||
|
@ -358,7 +361,7 @@ workflowDetailsView:
|
|||
startTime: Start Time
|
||||
endTime: End Time
|
||||
duration: Duration
|
||||
nodeName: Node Name
|
||||
nodeName: Step Name
|
||||
button:
|
||||
logs: Logs
|
||||
|
||||
|
@ -383,6 +386,7 @@ createWorkflow:
|
|||
saved: Name saved as
|
||||
modalHeading: Create your
|
||||
modalHeadingStrong: workflow name
|
||||
validate: Workflow name can only contain - and alphanumeric characters
|
||||
label:
|
||||
workflowName: Workflow name
|
||||
desc: Description
|
||||
|
@ -447,6 +451,7 @@ createWorkflow:
|
|||
info: Before committing the workflow changes to your, verify and if needed go back to a corresponding section of the wizard to modify.
|
||||
error: Invalid Workflow CRD found ! Please correct the errors.
|
||||
errYaml: Error in CRD Yaml.
|
||||
codeIsFine: Your code is fine. You can move on !
|
||||
button:
|
||||
edit: Edit
|
||||
viewYaml: View YAML
|
||||
|
@ -455,6 +460,7 @@ createWorkflow:
|
|||
workflowName: Workflow name
|
||||
desc: Description
|
||||
schedule: Schedule
|
||||
disabled: Currently Disabled
|
||||
schedulingNow: Scheduling now
|
||||
adjustedWeights: Adjusted Weights
|
||||
clustername: Cluster Name
|
||||
|
|
|
@ -21,7 +21,13 @@ const CustomBreadcrumbs: React.FC<CustomBreadcrumbsProps> = ({ location }) => {
|
|||
// If Template/Workflow Name is clicked [Workflow / Workflow-name / Template]
|
||||
// it would redirect to /workflows
|
||||
if (pathname[2] === 'template' && path === pathname[3]) {
|
||||
return <span>{path}</span>;
|
||||
return <span key="path">{path}</span>;
|
||||
}
|
||||
if (
|
||||
pathname[2] === 'schedule' &&
|
||||
(path === pathname[3] || path === pathname[4])
|
||||
) {
|
||||
return <span key="schedule">{path}</span>;
|
||||
}
|
||||
const link = (
|
||||
<Link
|
||||
|
|
|
@ -8,14 +8,16 @@ import React from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import useActions from '../../redux/actions';
|
||||
import * as TabActions from '../../redux/actions/tabs';
|
||||
import { history } from '../../redux/configureStore';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
import { ReactComponent as CommunityIcon } from '../../svg/community.svg';
|
||||
import { ReactComponent as HomeIcon } from '../../svg/home.svg';
|
||||
import { ReactComponent as MyHubIcon } from '../../svg/myhub.svg';
|
||||
import { ReactComponent as SettingsIcon } from '../../svg/settings.svg';
|
||||
import { ReactComponent as TargetsIcon } from '../../svg/targets.svg';
|
||||
import { ReactComponent as WorkflowsIcon } from '../../svg/workflows.svg';
|
||||
import { ReactComponent as MyHubIcon } from '../../svg/myhub.svg';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface CustomisedListItemProps {
|
||||
|
@ -47,6 +49,7 @@ const CustomisedListItem: React.FC<CustomisedListItemProps> = ({
|
|||
const SideBar: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
const userRole = useSelector((state: RootState) => state.userData.userRole);
|
||||
const tabs = useActions(TabActions);
|
||||
const { t } = useTranslation();
|
||||
const pathName = useLocation().pathname.split('/')[1];
|
||||
|
||||
|
@ -89,6 +92,7 @@ const SideBar: React.FC = () => {
|
|||
key="workflow"
|
||||
handleClick={() => {
|
||||
history.push('/workflows');
|
||||
tabs.changeWorkflowsTabs(0);
|
||||
}}
|
||||
label="Workflows"
|
||||
selected={pathName === 'workflows'}
|
||||
|
|
|
@ -22,6 +22,7 @@ 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 { validateWorkflowName } from '../../utils/validate';
|
||||
import { cronWorkflow, workflowOnce } from '../../utils/workflowTemplate';
|
||||
import parsed from '../../utils/yamlUtils';
|
||||
import ChooseWorkflow from '../../views/CreateWorkflow/ChooseWorkflow/index';
|
||||
|
@ -431,7 +432,11 @@ const CustomStepper = () => {
|
|||
<Typography>Back</Typography>
|
||||
</ButtonOutline>
|
||||
{activeStep === steps.length - 1 ? (
|
||||
<ButtonFilled handleClick={handleOpen} isPrimary>
|
||||
<ButtonFilled
|
||||
isDisabled={validateWorkflowName(name)}
|
||||
handleClick={handleOpen}
|
||||
isPrimary
|
||||
>
|
||||
<div>Finish</div>
|
||||
</ButtonFilled>
|
||||
) : (
|
||||
|
|
|
@ -101,13 +101,12 @@ const Routes: React.FC<RoutesProps> = ({ isOwner, isProjectAvailable }) => {
|
|||
/>
|
||||
{/* Redirects */}
|
||||
<Redirect exact path="/login" to="/" />
|
||||
<Redirect exact path="/workflows/details" to="/workflows" />
|
||||
<Redirect exact path="/workflows/schedule" to="/workflows" />
|
||||
<Redirect exact path="/workflows/template" to="/workflows" />
|
||||
<Redirect exact path="/workflows/analytics" to="/workflows" />
|
||||
<Route
|
||||
exact
|
||||
path="/workflows/details/:workflowRunId"
|
||||
path="/workflows/:workflowRunId"
|
||||
component={WorkflowDetails}
|
||||
/>
|
||||
<Route
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
export interface InfoButtonData {
|
||||
isInfoToggled: boolean;
|
||||
}
|
||||
|
||||
export enum InfoToggledActions {
|
||||
TOGGLE_BUTTON = 'TOGGLE_BUTTON',
|
||||
}
|
||||
|
||||
interface InfoToggledActionType<T, P> {
|
||||
type: T;
|
||||
payload: P;
|
||||
}
|
||||
|
||||
export type InfoToggledAction = InfoToggledActionType<
|
||||
typeof InfoToggledActions.TOGGLE_BUTTON,
|
||||
InfoButtonData
|
||||
>;
|
|
@ -36,6 +36,7 @@ export interface WorkflowData {
|
|||
weights: experimentMap[];
|
||||
isCustomWorkflow: boolean;
|
||||
isRecurring: boolean;
|
||||
isDisabled: boolean;
|
||||
namespace: string;
|
||||
workflow_id?: string;
|
||||
clustername: string;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* eslint-disable react/no-danger */
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { InputField } from 'kubera-ui';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ButtonFilled from '../../components/Button/ButtonFilled';
|
||||
import InputField from '../../components/InputField';
|
||||
import Loader from '../../components/Loader';
|
||||
import config from '../../config';
|
||||
import useActions from '../../redux/actions';
|
||||
|
@ -96,9 +96,13 @@ const LoginPage = () => {
|
|||
? 'Should not start with an empty space'
|
||||
: ''
|
||||
}
|
||||
validationError={validateStartEmptySpacing(authData.username)}
|
||||
variant={
|
||||
validateStartEmptySpacing(authData.username)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
required
|
||||
handleChange={(e) =>
|
||||
onChange={(e) =>
|
||||
setAuthData({
|
||||
username: e.target.value,
|
||||
password: authData.password,
|
||||
|
@ -106,6 +110,7 @@ const LoginPage = () => {
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
<div aria-details="spacer" style={{ margin: '0.4rem 0' }} />
|
||||
<div className={classes.inputValue} data-cy="inputPassword">
|
||||
<InputField
|
||||
label="Password"
|
||||
|
@ -117,8 +122,8 @@ const LoginPage = () => {
|
|||
? 'Wrong Credentials - Try again with correct username or password'
|
||||
: ''
|
||||
}
|
||||
validationError={isError}
|
||||
handleChange={(e) =>
|
||||
variant={isError ? 'error' : 'primary'}
|
||||
onChange={(e) =>
|
||||
setAuthData({
|
||||
username: authData.username,
|
||||
password: e.target.value,
|
||||
|
|
|
@ -63,6 +63,7 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
|
||||
inputValue: {
|
||||
marginLeft: theme.spacing(2),
|
||||
width: '25rem',
|
||||
},
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ 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 { validateWorkflowName } from '../../utils/validate';
|
||||
import parsed from '../../utils/yamlUtils';
|
||||
import ChooseWorkflow from '../../views/CreateWorkflow/ChooseWorkflow/index';
|
||||
import ReliablityScore from '../../views/CreateWorkflow/ReliabilityScore';
|
||||
|
@ -202,6 +203,7 @@ const EditScheduledWorkflow = () => {
|
|||
weights,
|
||||
description,
|
||||
isCustomWorkflow,
|
||||
isDisabled,
|
||||
cronSyntax,
|
||||
name,
|
||||
clusterid,
|
||||
|
@ -274,10 +276,12 @@ const EditScheduledWorkflow = () => {
|
|||
}
|
||||
if (
|
||||
oldParsedYaml.kind === 'CronWorkflow' &&
|
||||
scheduleType.scheduleOnce !== 'now'
|
||||
scheduleType.scheduleOnce !== 'now' &&
|
||||
!isDisabled
|
||||
) {
|
||||
const newParsedYaml = YAML.parse(yaml);
|
||||
newParsedYaml.spec.schedule = cronSyntax;
|
||||
newParsedYaml.spec.suspend = false;
|
||||
delete newParsedYaml.metadata.generateName;
|
||||
newParsedYaml.metadata.name = workflowData.name;
|
||||
newParsedYaml.metadata.labels = { workflow_id: workflowData.workflow_id };
|
||||
|
@ -293,6 +297,21 @@ const EditScheduledWorkflow = () => {
|
|||
yaml: 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);
|
||||
workflow.setWorkflowDetails({
|
||||
link: NewLink,
|
||||
yaml: NewYaml,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
|
@ -375,7 +394,6 @@ const EditScheduledWorkflow = () => {
|
|||
cluster_id: clusterid,
|
||||
};
|
||||
|
||||
// console.log(chaosWorkFlowInputs);
|
||||
createChaosWorkFlow({
|
||||
variables: { ChaosWorkFlowInput: chaosWorkFlowInputs },
|
||||
});
|
||||
|
@ -518,7 +536,11 @@ const EditScheduledWorkflow = () => {
|
|||
</ButtonOutline>
|
||||
) : null}
|
||||
{activeStep === steps.length - 1 ? (
|
||||
<ButtonFilled handleClick={handleOpen} isPrimary>
|
||||
<ButtonFilled
|
||||
isDisabled={validateWorkflowName(name)}
|
||||
handleClick={handleOpen}
|
||||
isPrimary
|
||||
>
|
||||
<div>{t('workflowStepper.finish')}</div>
|
||||
</ButtonFilled>
|
||||
) : (
|
||||
|
|
|
@ -1,93 +1,20 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import BackButton from '../../components/Button/BackButton';
|
||||
import ButtonFilled from '../../components/Button/ButtonFilled';
|
||||
import ButtonOutline from '../../components/Button/ButtonOutline';
|
||||
import useActions from '../../redux/actions';
|
||||
import * as ToggleButtonAction from '../../redux/actions/button';
|
||||
import { RootState } from '../../redux/reducers';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface TopNavButtonsProps {
|
||||
isAnalyticsToggled: boolean;
|
||||
isExportToggled: boolean;
|
||||
isInfoToggled: boolean;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isToggled: TopNavButtonsProps;
|
||||
setIsToggled: React.Dispatch<React.SetStateAction<TopNavButtonsProps>>;
|
||||
}
|
||||
|
||||
const TopNavButtons: React.FC<Props> = ({ isToggled, setIsToggled }) => {
|
||||
const TopNavButtons: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
const setFilledButtonState = (buttonName: string, buttonIcon: string) => {
|
||||
return (
|
||||
<ButtonFilled
|
||||
styles={{ height: '2.2rem' }}
|
||||
isPrimary
|
||||
handleClick={() =>
|
||||
setIsToggled({
|
||||
isAnalyticsToggled: false,
|
||||
isExportToggled: false,
|
||||
isInfoToggled: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={`/icons/${buttonIcon}.svg`}
|
||||
alt={`${buttonName} Icon`}
|
||||
className={classes.icon}
|
||||
/>
|
||||
{buttonName}
|
||||
</ButtonFilled>
|
||||
);
|
||||
};
|
||||
|
||||
const setButtonOutlinedState = (
|
||||
buttonName: string,
|
||||
buttonIcon: string,
|
||||
setIsToggleValues: TopNavButtonsProps
|
||||
) => {
|
||||
return (
|
||||
<ButtonOutline
|
||||
styles={{ height: '2.2rem' }}
|
||||
isDisabled={false}
|
||||
handleClick={() => setIsToggled(setIsToggleValues)}
|
||||
>
|
||||
<img
|
||||
src={`/icons/${buttonIcon}.svg`}
|
||||
alt={`${buttonName} Icon`}
|
||||
className={classes.icon}
|
||||
/>
|
||||
{buttonName}
|
||||
</ButtonOutline>
|
||||
);
|
||||
};
|
||||
/*
|
||||
const AnalyticsButton = () =>
|
||||
isToggled.isAnalyticsToggled
|
||||
? setFilledButtonState('Analytics', 'show-analytics')
|
||||
: setButtonOutlinedState('Analytics', 'show-analytics', {
|
||||
isAnalyticsToggled: true,
|
||||
isExportToggled: false,
|
||||
isInfoToggled: false,
|
||||
});
|
||||
|
||||
const ExportButton = () =>
|
||||
isToggled.isExportToggled
|
||||
? setFilledButtonState('Export', 'export')
|
||||
: setButtonOutlinedState('Export', 'export', {
|
||||
isAnalyticsToggled: false,
|
||||
isExportToggled: true,
|
||||
isInfoToggled: false,
|
||||
});
|
||||
*/
|
||||
const InfoButton = () =>
|
||||
isToggled.isInfoToggled
|
||||
? setFilledButtonState('Info', 'alignment')
|
||||
: setButtonOutlinedState('Info', 'alignment', {
|
||||
isAnalyticsToggled: false,
|
||||
isExportToggled: false,
|
||||
isInfoToggled: true,
|
||||
});
|
||||
const isInfoToggled = useSelector(
|
||||
(state: RootState) => state.toggleInfoButton.isInfoToggled
|
||||
);
|
||||
const toggleButtonAction = useActions(ToggleButtonAction);
|
||||
|
||||
return (
|
||||
<div className={classes.button}>
|
||||
|
@ -95,9 +22,41 @@ const TopNavButtons: React.FC<Props> = ({ isToggled, setIsToggled }) => {
|
|||
<BackButton isDisabled={false} />
|
||||
</div>
|
||||
<div>
|
||||
{/* AnalyticsButton() */}
|
||||
{/* ExportButton() */}
|
||||
{InfoButton()}
|
||||
{isInfoToggled ? (
|
||||
<ButtonFilled
|
||||
styles={{ height: '2.2rem' }}
|
||||
isPrimary
|
||||
handleClick={() =>
|
||||
toggleButtonAction.toggleInfoButton({
|
||||
isInfoToggled: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<img
|
||||
src="./icons/alignment.svg"
|
||||
alt="Info Icon"
|
||||
className={classes.icon}
|
||||
/>
|
||||
Info
|
||||
</ButtonFilled>
|
||||
) : (
|
||||
<ButtonOutline
|
||||
styles={{ height: '2.2rem' }}
|
||||
isDisabled={false}
|
||||
handleClick={() =>
|
||||
toggleButtonAction.toggleInfoButton({
|
||||
isInfoToggled: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<img
|
||||
src="./icons/alignment.svg"
|
||||
alt="Info Icon"
|
||||
className={classes.icon}
|
||||
/>
|
||||
Info
|
||||
</ButtonOutline>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -24,31 +24,22 @@ import WorkflowNodeInfo from '../../views/WorkflowDetails/WorkflowNodeInfo';
|
|||
import useStyles from './styles';
|
||||
import TopNavButtons from './TopNavButtons';
|
||||
|
||||
interface TopNavButtonsProps {
|
||||
isAnalyticsToggled: boolean;
|
||||
isExportToggled: boolean;
|
||||
isInfoToggled: boolean;
|
||||
}
|
||||
|
||||
const WorkflowDetails: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
const [isToggled, setIsToggled] = React.useState<TopNavButtonsProps>({
|
||||
isAnalyticsToggled: false,
|
||||
isExportToggled: false,
|
||||
isInfoToggled: false,
|
||||
});
|
||||
|
||||
const tabs = useActions(TabActions);
|
||||
const { pathname } = useLocation();
|
||||
// Getting the workflow nome from the pathname
|
||||
const workflowRunId = pathname.split('/')[3];
|
||||
const workflowRunId = pathname.split('/')[2];
|
||||
const { t } = useTranslation();
|
||||
|
||||
// get ProjectID
|
||||
const selectedProjectID = useSelector(
|
||||
(state: RootState) => state.userData.selectedProjectID
|
||||
);
|
||||
const isInfoToggled = useSelector(
|
||||
(state: RootState) => state.toggleInfoButton.isInfoToggled
|
||||
);
|
||||
const workflowDetailsTabValue = useSelector(
|
||||
(state: RootState) => state.tabNumber.node
|
||||
);
|
||||
|
@ -111,7 +102,7 @@ const WorkflowDetails: React.FC = () => {
|
|||
|
||||
return (
|
||||
<Scaffold>
|
||||
<TopNavButtons isToggled={isToggled} setIsToggled={setIsToggled} />
|
||||
<TopNavButtons />
|
||||
{/* If workflow data is present then display the workflow details */}
|
||||
{workflow ? (
|
||||
<div className={classes.root}>
|
||||
|
@ -128,7 +119,7 @@ const WorkflowDetails: React.FC = () => {
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
{isToggled.isInfoToggled ? (
|
||||
{isInfoToggled ? (
|
||||
<div className={classes.workflowSideBar}>
|
||||
<AppBar
|
||||
position="static"
|
||||
|
@ -146,7 +137,7 @@ const WorkflowDetails: React.FC = () => {
|
|||
variant="fullWidth"
|
||||
>
|
||||
<StyledTab label="Workflow" />
|
||||
<StyledTab label="Nodes" />
|
||||
<StyledTab label="Steps" />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={workflowDetailsTabValue} index={0}>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import {
|
||||
InfoButtonData,
|
||||
InfoToggledAction,
|
||||
InfoToggledActions,
|
||||
} from '../../models/redux/button';
|
||||
|
||||
export const toggleInfoButton = (data: InfoButtonData): InfoToggledAction => {
|
||||
return {
|
||||
type: InfoToggledActions.TOGGLE_BUTTON,
|
||||
payload: data,
|
||||
};
|
||||
};
|
||||
|
||||
export default toggleInfoButton;
|
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable import/prefer-default-export */
|
||||
import {
|
||||
InfoButtonData,
|
||||
InfoToggledAction,
|
||||
InfoToggledActions,
|
||||
} from '../../models/redux/button';
|
||||
import createReducer from './createReducer';
|
||||
|
||||
const initialState: InfoButtonData = {
|
||||
isInfoToggled: false,
|
||||
};
|
||||
|
||||
export const toggleInfoButton = createReducer<InfoButtonData>(initialState, {
|
||||
[InfoToggledActions.TOGGLE_BUTTON](
|
||||
state: InfoButtonData,
|
||||
action: InfoToggledAction
|
||||
) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default toggleInfoButton;
|
|
@ -1,24 +1,27 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import { AnalyticsData } from '../../models/redux/analytics';
|
||||
import { InfoButtonData } from '../../models/redux/button';
|
||||
import { HubDetails } from '../../models/redux/myhub';
|
||||
import { SelectedNode } from '../../models/redux/nodeSelection';
|
||||
import { TabState } from '../../models/redux/tabs';
|
||||
import { TemplateData } from '../../models/redux/template';
|
||||
import { UserData } from '../../models/redux/user';
|
||||
import { WorkflowData } from '../../models/redux/workflow';
|
||||
import * as analyticsReducer from './analytics';
|
||||
import * as infoButtonReducer from './button';
|
||||
import * as hubDetails from './myhub';
|
||||
import * as nodeSelectionReducer from './nodeSelection';
|
||||
import * as tabsReducer from './tabs';
|
||||
import * as templateReducer from './template';
|
||||
import * as userReducer from './user';
|
||||
import * as workflowReducer from './workflow';
|
||||
import * as hubDetails from './myhub';
|
||||
import { HubDetails } from '../../models/redux/myhub';
|
||||
|
||||
export interface RootState {
|
||||
communityData: AnalyticsData;
|
||||
userData: UserData;
|
||||
workflowData: WorkflowData;
|
||||
selectedNode: SelectedNode;
|
||||
toggleInfoButton: InfoButtonData;
|
||||
tabNumber: TabState;
|
||||
selectTemplate: TemplateData;
|
||||
hubDetails: HubDetails;
|
||||
|
@ -32,5 +35,6 @@ export default () =>
|
|||
...nodeSelectionReducer,
|
||||
...tabsReducer,
|
||||
...templateReducer,
|
||||
...infoButtonReducer,
|
||||
...hubDetails,
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ const initialState: WorkflowData = {
|
|||
weights: [],
|
||||
isCustomWorkflow: false,
|
||||
isRecurring: false,
|
||||
isDisabled: false,
|
||||
namespace: 'litmus',
|
||||
clusterid: '',
|
||||
cronSyntax: '',
|
||||
|
|
|
@ -20,7 +20,7 @@ export const validateEmail = (value: string) => {
|
|||
};
|
||||
|
||||
export const validateWorkflowName = (value: string) => {
|
||||
const workflowValid = /^[a-z0-9._-]+$/g;
|
||||
const workflowValid = /(^[a-z0-9-]{0,55}$)/;
|
||||
if (value.length > 0) {
|
||||
if (value.match(workflowValid)) return false;
|
||||
return true;
|
||||
|
|
|
@ -111,12 +111,28 @@ const TableData: React.FC<TableDataProps> = ({ data, deleteRow }) => {
|
|||
<>
|
||||
<TableCell className={classes.workflowNameData}>
|
||||
<Typography>
|
||||
<strong>{data.workflow_name}</strong>
|
||||
<span
|
||||
className={
|
||||
YAML.parse(data.workflow_manifest).spec.suspend === true
|
||||
? classes.dark
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<strong>{data.workflow_name}</strong>
|
||||
</span>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography className={classes.clusterStartDate}>
|
||||
{formatDate(data.created_at)}
|
||||
<span
|
||||
className={
|
||||
YAML.parse(data.workflow_manifest).spec.suspend === true
|
||||
? classes.dark
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{formatDate(data.created_at)}
|
||||
</span>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
|
@ -124,33 +140,65 @@ const TableData: React.FC<TableDataProps> = ({ data, deleteRow }) => {
|
|||
<div className={classes.expDiv}>
|
||||
<img src="/icons/calender.svg" alt="Calender" />
|
||||
<Typography style={{ paddingLeft: 10 }}>
|
||||
{data.cronSyntax === ''
|
||||
? 'Once'
|
||||
: cronstrue.toString(data.cronSyntax)}
|
||||
<span
|
||||
className={
|
||||
YAML.parse(data.workflow_manifest).spec.suspend === true
|
||||
? classes.dark
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{data.cronSyntax === '' ? (
|
||||
<>{t('chaosWorkflows.browseSchedule.regularityOnce')}</>
|
||||
) : (
|
||||
cronstrue.toString(data.cronSyntax)
|
||||
)}
|
||||
</span>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>{data.cluster_name}</Typography>
|
||||
<Typography>
|
||||
<span
|
||||
className={
|
||||
YAML.parse(data.workflow_manifest).spec.suspend === true
|
||||
? classes.dark
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{data.cluster_name}
|
||||
</span>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button onClick={handlePopOverClick} style={{ textTransform: 'none' }}>
|
||||
{isOpen ? (
|
||||
<div className={classes.expDiv}>
|
||||
<Typography className={classes.expInfoActive}>
|
||||
<strong>Show Experiment</strong>
|
||||
</Typography>
|
||||
<KeyboardArrowDownIcon className={classes.expInfoActiveIcon} />
|
||||
</div>
|
||||
) : (
|
||||
<div className={classes.expDiv}>
|
||||
<Typography className={classes.expInfo}>
|
||||
<strong>Show Experiment</strong>
|
||||
</Typography>
|
||||
<ChevronRightIcon />
|
||||
</div>
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
YAML.parse(data.workflow_manifest).spec.suspend === true
|
||||
? classes.dark
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{isOpen ? (
|
||||
<div className={classes.expDiv}>
|
||||
<Typography className={classes.expInfoActive}>
|
||||
<strong>
|
||||
{t('chaosWorkflows.browseSchedule.showExperiment')}
|
||||
</strong>
|
||||
</Typography>
|
||||
<KeyboardArrowDownIcon className={classes.expInfoActiveIcon} />
|
||||
</div>
|
||||
) : (
|
||||
<div className={classes.expDiv}>
|
||||
<Typography className={classes.expInfo}>
|
||||
<strong>
|
||||
{t('chaosWorkflows.browseSchedule.showExperiment')}
|
||||
</strong>
|
||||
</Typography>
|
||||
<ChevronRightIcon />
|
||||
</div>
|
||||
)}
|
||||
</span>
|
||||
</Button>
|
||||
<Popover
|
||||
id={id}
|
||||
|
|
|
@ -166,6 +166,9 @@ const useStyles = makeStyles((theme) => ({
|
|||
width: '15.1875rem',
|
||||
padding: theme.spacing(3.125, 2.6),
|
||||
},
|
||||
dark: {
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
weightInfo: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
|
|
|
@ -110,7 +110,7 @@ const TableData: React.FC<TableDataProps> = ({ data, exeData }) => {
|
|||
<MenuItem
|
||||
value="Workflow"
|
||||
onClick={() => {
|
||||
history.push(`/workflows/details/${data.workflow_run_id}`);
|
||||
history.push(`/workflows/${data.workflow_run_id}`);
|
||||
}}
|
||||
>
|
||||
<div className={classes.expDiv} data-cy="workflowDetails">
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Typography } from '@material-ui/core';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import { InputField } from 'kubera-ui';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import ButtonFilled from '../../../components/Button/ButtonFilled';
|
||||
import ButtonOutline from '../../../components/Button/ButtonOutline';
|
||||
import InputField from '../../../components/InputField';
|
||||
import PredifinedWorkflows from '../../../components/PredifinedWorkflows';
|
||||
import workflowsList from '../../../components/PredifinedWorkflows/data';
|
||||
import Unimodal from '../../../containers/layouts/Unimodal';
|
||||
|
@ -15,7 +15,7 @@ import * as TemplateSelectionActions from '../../../redux/actions/template';
|
|||
import * as WorkflowActions from '../../../redux/actions/workflow';
|
||||
import { RootState } from '../../../redux/reducers';
|
||||
import { validateWorkflowName } from '../../../utils/validate';
|
||||
import useStyles, { CssTextField } from './styles';
|
||||
import useStyles from './styles';
|
||||
|
||||
// import { getWkfRunCount } from "../../utils";
|
||||
|
||||
|
@ -220,42 +220,36 @@ const ChooseWorkflow: React.FC<ChooseWorkflowProps> = ({ isEditable }) => {
|
|||
<InputField
|
||||
// id="filled-workflowname-input"
|
||||
label={t('createWorkflow.chooseWorkflow.label.workflowName')}
|
||||
disabled={!isEditable}
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
fullWidth
|
||||
helperText={
|
||||
validateWorkflowName(workflowDetails.workflowName)
|
||||
? 'Should not contain spaces or upper case letters'
|
||||
? t('createWorkflow.chooseWorkflow.validate')
|
||||
: ''
|
||||
}
|
||||
success={isSuccess.current}
|
||||
validationError={validateWorkflowName(
|
||||
workflowDetails.workflowName
|
||||
)}
|
||||
// className={classes.textfieldworkflowname}
|
||||
handleChange={WorkflowNameChangeHandler}
|
||||
variant={
|
||||
validateWorkflowName(workflowDetails.workflowName)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
disabled={!isEditable}
|
||||
onChange={WorkflowNameChangeHandler}
|
||||
value={workflowDetails.workflowName}
|
||||
/>
|
||||
<div className={classes.inputAreaDescription}>
|
||||
<CssTextField
|
||||
id="filled-workflowdescription-input"
|
||||
label={t('createWorkflow.chooseWorkflow.label.desc')}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
classes: {
|
||||
input: classes.resize,
|
||||
},
|
||||
}}
|
||||
data-cy="inputWorkflowDescription"
|
||||
className={classes.textfieldworkflowdescription}
|
||||
value={workflowDetails.workflowDesc}
|
||||
onChange={WorkflowDescriptionChangeHandler}
|
||||
multiline
|
||||
rows={12}
|
||||
/>
|
||||
</div>
|
||||
<div aria-details="spacer" style={{ margin: '1rem 0' }} />
|
||||
<InputField
|
||||
id="filled-workflowdescription-input"
|
||||
label={t('createWorkflow.chooseWorkflow.label.desc')}
|
||||
fullWidth
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
data-cy="inputWorkflowDescription"
|
||||
value={workflowDetails.workflowDesc}
|
||||
onChange={WorkflowDescriptionChangeHandler}
|
||||
multiline
|
||||
rows={12}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.buttons}>
|
||||
<div className={classes.cancelButton}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { makeStyles, TextField, withStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
|
@ -50,46 +50,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
marginTop: theme.spacing(5),
|
||||
},
|
||||
|
||||
inputArea: {
|
||||
marginTop: theme.spacing(3),
|
||||
display: 'flex',
|
||||
textDecoration: 'none',
|
||||
flexDirection: 'column',
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2.2),
|
||||
borderRadius: 3,
|
||||
color: 'rgba(0, 0, 0, 0.2)',
|
||||
border: '1px solid rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
|
||||
inputAreaDescription: {
|
||||
marginTop: theme.spacing(3),
|
||||
marginBottom: theme.spacing(3),
|
||||
display: 'flex',
|
||||
textDecoration: 'none',
|
||||
flexDirection: 'column',
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2.2),
|
||||
borderRadius: 3,
|
||||
color: 'rgba(0, 0, 0, 0.2)',
|
||||
border: '1px solid rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
|
||||
textfieldworkflowname: {
|
||||
marginTop: theme.spacing(1),
|
||||
paddingLeft: theme.spacing(2),
|
||||
},
|
||||
|
||||
totalWorkflows: {
|
||||
fontSize: '1rem',
|
||||
fontWeight: 500,
|
||||
},
|
||||
|
||||
textfieldworkflowdescription: {
|
||||
marginTop: theme.spacing(2),
|
||||
paddingLeft: theme.spacing(2),
|
||||
},
|
||||
|
||||
inputDiv: {
|
||||
marginTop: theme.spacing(5),
|
||||
},
|
||||
|
@ -110,10 +75,6 @@ const useStyles = makeStyles((theme) => ({
|
|||
paddingRight: theme.spacing(1.25),
|
||||
},
|
||||
|
||||
resize: {
|
||||
fontSize: '1rem',
|
||||
},
|
||||
|
||||
resizeName: {
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
|
@ -142,13 +103,4 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
}));
|
||||
|
||||
export const CssTextField = withStyles({
|
||||
root: {
|
||||
'& label.MuiInputLabel-root': {
|
||||
color: 'rgba(0, 0, 0, 0.6)',
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
})(TextField);
|
||||
|
||||
export default useStyles;
|
||||
|
|
|
@ -17,12 +17,12 @@ import {
|
|||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
|
||||
import { InputField } from 'kubera-ui';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import YAML from 'yaml';
|
||||
import ButtonFilled from '../../../../components/Button/ButtonFilled';
|
||||
import InputField from '../../../../components/InputField';
|
||||
import Loader from '../../../../components/Loader';
|
||||
import { GET_CHARTS_DATA, GET_HUB_STATUS } from '../../../../graphql';
|
||||
import { GET_EXPERIMENT_YAML } from '../../../../graphql/queries';
|
||||
|
@ -34,8 +34,9 @@ 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 { validateWorkflowName } from '../../../../utils/validate';
|
||||
import BackButton from '../BackButton';
|
||||
import useStyles, { CustomTextField, MenuProps } from './styles';
|
||||
import useStyles, { MenuProps } from './styles';
|
||||
|
||||
interface WorkflowDetails {
|
||||
workflow_name: string;
|
||||
|
@ -238,12 +239,19 @@ const CreateWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
</Typography>
|
||||
<InputField
|
||||
label="Workflow Name"
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
fullWidth
|
||||
data-cy="inputWorkflowName"
|
||||
validationError={false}
|
||||
handleChange={(e) => {
|
||||
variant={
|
||||
validateWorkflowName(workflowData.workflow_name)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
helperText={
|
||||
validateWorkflowName(workflowData.workflow_name)
|
||||
? t('createWorkflow.chooseWorkflow.validate')
|
||||
: ''
|
||||
}
|
||||
onChange={(e) => {
|
||||
setWorkflowData({
|
||||
workflow_name: e.target.value,
|
||||
workflow_desc: workflowData.workflow_desc,
|
||||
|
@ -257,14 +265,11 @@ const CreateWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<Typography variant="h6" className={classes.titleText}>
|
||||
{t('customWorkflow.createWorkflow.workflowDesc')}:
|
||||
</Typography>
|
||||
<CustomTextField
|
||||
<InputField
|
||||
label="Description"
|
||||
data-cy="inputWorkflowDesc"
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
classes: {
|
||||
input: classes.resize,
|
||||
},
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setWorkflowData({
|
||||
|
@ -297,7 +302,14 @@ const CreateWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
>
|
||||
<FormControlLabel
|
||||
value="construct"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
disabled={data?.getHubStatus.length === 0}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
|
@ -374,7 +386,7 @@ const CreateWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
}}
|
||||
edge="end"
|
||||
>
|
||||
<ArrowDropDownIcon />
|
||||
<ArrowDropDownIcon color="secondary" />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
|
@ -463,7 +475,11 @@ const CreateWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
|
||||
<FormControlLabel
|
||||
value="upload"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{ root: classes.radio, checked: classes.checked }}
|
||||
/>
|
||||
}
|
||||
disabled={workflowDetails.customWorkflows.length !== 0}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
|
|
|
@ -44,7 +44,17 @@ const useStyles = makeStyles((theme) => ({
|
|||
height: '2.5rem',
|
||||
fontSize: '0.875rem',
|
||||
padding: theme.spacing(0.5),
|
||||
'& .MuiSelect-icon': {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
radio: {
|
||||
color: theme.palette.primary.dark,
|
||||
'&$checked': {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
},
|
||||
checked: {},
|
||||
nextArrow: {
|
||||
marginLeft: theme.spacing(2.5),
|
||||
},
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { useLazyQuery } from '@apollo/client';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { InputField } from 'kubera-ui';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import YAML from 'yaml';
|
||||
import ButtonFilled from '../../../../components/Button/ButtonFilled';
|
||||
import InputField from '../../../../components/InputField';
|
||||
import Loader from '../../../../components/Loader';
|
||||
import { GET_ENGINE_YAML } from '../../../../graphql/queries';
|
||||
import useActions from '../../../../redux/actions';
|
||||
|
@ -70,14 +70,14 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
|
||||
const changeKey = (
|
||||
index: number,
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
overrideEnvs[index].name = event.target.value;
|
||||
setOverrideEnvs([...overrideEnvs]);
|
||||
};
|
||||
const changeValue = (
|
||||
index: number,
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
overrideEnvs[index].value = event.target.value;
|
||||
setOverrideEnvs([...overrideEnvs]);
|
||||
|
@ -88,7 +88,7 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
|
||||
const changeOriginalEnvValue = (
|
||||
index: number,
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
env[index].value = event.target.value;
|
||||
setEnv([...env]);
|
||||
|
@ -261,12 +261,9 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<div className={classes.inputField}>
|
||||
<InputField
|
||||
label="appns"
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) =>
|
||||
variant="primary"
|
||||
onChange={(event) =>
|
||||
setAppInfo({
|
||||
...appInfo,
|
||||
appns: event.target.value.toLowerCase(),
|
||||
|
@ -277,6 +274,7 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div aria-details="spacer" style={{ margin: '1rem' }} />
|
||||
{YAML.parse(yaml).spec.appinfo?.applabel ? (
|
||||
<div className={classes.appInfoDiv}>
|
||||
<Typography className={classes.appInfoText}>
|
||||
|
@ -285,12 +283,9 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<div className={classes.inputField}>
|
||||
<InputField
|
||||
label="applabel"
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) =>
|
||||
variant="primary"
|
||||
onChange={(event) =>
|
||||
setAppInfo({
|
||||
...appInfo,
|
||||
applabel: event.target.value.toLowerCase(),
|
||||
|
@ -301,6 +296,7 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div aria-details="spacer" style={{ margin: '1rem' }} />
|
||||
{YAML.parse(yaml).spec.appinfo?.appkind ? (
|
||||
<div className={classes.appKind}>
|
||||
<Typography className={classes.appInfoText}>
|
||||
|
@ -309,12 +305,9 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<div className={classes.inputField}>
|
||||
<InputField
|
||||
label="appkind"
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) =>
|
||||
variant="primary"
|
||||
onChange={(event) =>
|
||||
setAppInfo({
|
||||
...appInfo,
|
||||
appkind: event.target.value.toLowerCase(),
|
||||
|
@ -325,6 +318,7 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div aria-details="spacer" style={{ margin: '1rem' }} />
|
||||
{YAML.parse(yaml).spec.annotationCheck ? (
|
||||
<div className={classes.appKind}>
|
||||
<Typography className={classes.appInfoText}>
|
||||
|
@ -333,12 +327,9 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<div className={classes.inputField}>
|
||||
<InputField
|
||||
label="annotationCheck"
|
||||
styles={{
|
||||
width: '100%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) => setAnnotation(event.target.value)}
|
||||
variant="primary"
|
||||
onChange={(event) => setAnnotation(event.target.value)}
|
||||
value={annotation}
|
||||
/>
|
||||
</div>
|
||||
|
@ -353,12 +344,9 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<Typography className={classes.envName}>{data.name}</Typography>
|
||||
<InputField
|
||||
label="Value"
|
||||
styles={{
|
||||
width: '40%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) => changeOriginalEnvValue(index, event)}
|
||||
variant="primary"
|
||||
onChange={(event) => changeOriginalEnvValue(index, event)}
|
||||
value={data.value}
|
||||
/>
|
||||
</div>
|
||||
|
@ -374,22 +362,16 @@ const TuneCustomWorkflow: React.FC<VerifyCommitProps> = ({ gotoStep }) => {
|
|||
<div className={classes.inputDivEnv}>
|
||||
<InputField
|
||||
label="Key"
|
||||
styles={{
|
||||
width: '40%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) => changeKey(index, event)}
|
||||
variant="primary"
|
||||
onChange={(event) => changeKey(index, event)}
|
||||
value={data.name}
|
||||
/>
|
||||
<InputField
|
||||
label="Value"
|
||||
styles={{
|
||||
width: '40%',
|
||||
}}
|
||||
data-cy="inputWorkflow"
|
||||
validationError={false}
|
||||
handleChange={(event) => changeValue(index, event)}
|
||||
variant="primary"
|
||||
onChange={(event) => changeValue(index, event)}
|
||||
value={data.value}
|
||||
/>
|
||||
{overrideEnvs[index + 1] ? null : (
|
||||
|
|
|
@ -91,9 +91,9 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
inputDivEnv: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
marginTop: theme.spacing(1.25),
|
||||
marginLeft: theme.spacing(-2.5),
|
||||
},
|
||||
horizontalLineHeader: {
|
||||
border: `1px solid ${theme.palette.border.main}`,
|
||||
|
|
|
@ -23,7 +23,7 @@ const useStyles = makeStyles((theme) => ({
|
|||
marginLeft: theme.spacing(15),
|
||||
marginBottom: theme.spacing(10),
|
||||
fontSize: '1.6rem',
|
||||
color: 'red',
|
||||
color: theme.palette.error.main,
|
||||
},
|
||||
description: {
|
||||
width: '50rem',
|
||||
|
|
|
@ -307,7 +307,7 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
<div className={classes.scHeader}>
|
||||
{/* Upper segment */}
|
||||
<div className={classes.scSegments}>
|
||||
<div aria-details="content wrapper" style={{ width: '90%' }}>
|
||||
<div>
|
||||
<Typography className={classes.headerText}>
|
||||
<strong>{t('createWorkflow.scheduleWorkflow.header')}</strong>
|
||||
</Typography>
|
||||
|
@ -319,7 +319,7 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="./icons/calendar.svg"
|
||||
src="/icons/calendar.svg"
|
||||
alt="calendar"
|
||||
className={classes.calIcon}
|
||||
/>
|
||||
|
@ -339,17 +339,33 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
{!workflowData.isRecurring ? (
|
||||
<FormControlLabel
|
||||
value="now"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
{t('createWorkflow.scheduleWorkflow.radio.now')}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
) : YAML.parse(workflowData.yaml).spec.suspend === false ? (
|
||||
) : YAML.parse(workflowData.yaml).spec.suspend === true ? (
|
||||
<></>
|
||||
) : !workflowData.isDisabled ? (
|
||||
<FormControlLabel
|
||||
value="disable"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
Disable Schedule
|
||||
|
@ -362,7 +378,7 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
{/* <FormControlLabel
|
||||
value="specificTime"
|
||||
disabled
|
||||
control={<Radio />}
|
||||
control={<Radio classes={{ root: classes.radio, checked: classes.checked }}/>}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
{t('createWorkflow.scheduleWorkflow.radio.specific')}
|
||||
|
@ -397,7 +413,11 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
)}
|
||||
<FormControlLabel
|
||||
value="recurringSchedule"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{ root: classes.radio, checked: classes.checked }}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography className={classes.radioText}>
|
||||
{t('createWorkflow.scheduleWorkflow.radio.recurr')}
|
||||
|
@ -423,7 +443,14 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
>
|
||||
<FormControlLabel
|
||||
value="everyHr"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t('createWorkflow.scheduleWorkflow.every.hr')}
|
||||
/>
|
||||
{valueDef === 'everyHr' ? (
|
||||
|
@ -468,7 +495,14 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
)}
|
||||
<FormControlLabel
|
||||
value="everyDay"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t('createWorkflow.scheduleWorkflow.every.day')}
|
||||
/>
|
||||
{valueDef === 'everyDay' ? (
|
||||
|
@ -504,7 +538,14 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
)}
|
||||
<FormControlLabel
|
||||
value="everyWeek"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t(
|
||||
'createWorkflow.scheduleWorkflow.every.week'
|
||||
)}
|
||||
|
@ -579,7 +620,14 @@ const ScheduleWorkflow: React.FC = () => {
|
|||
)}
|
||||
<FormControlLabel
|
||||
value="everyMonth"
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio
|
||||
classes={{
|
||||
root: classes.radio,
|
||||
checked: classes.checked,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t(
|
||||
'createWorkflow.scheduleWorkflow.every.month'
|
||||
)}
|
||||
|
|
|
@ -60,6 +60,14 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||
marginTop: theme.spacing(5),
|
||||
},
|
||||
|
||||
radio: {
|
||||
color: theme.palette.primary.dark,
|
||||
'&$checked': {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
},
|
||||
checked: {},
|
||||
|
||||
/* For recurring schedule options */
|
||||
scRandom: {
|
||||
display: 'flex',
|
||||
|
|
|
@ -47,6 +47,7 @@ const VerifyCommit: React.FC<VerifyCommitProps> = ({
|
|||
description,
|
||||
weights,
|
||||
cronSyntax,
|
||||
isDisabled,
|
||||
clustername,
|
||||
} = workflowData;
|
||||
|
||||
|
@ -97,9 +98,9 @@ const VerifyCommit: React.FC<VerifyCommitProps> = ({
|
|||
annotations: editorValidations.annotations,
|
||||
};
|
||||
if (stateObject.annotations.length > 0) {
|
||||
setYamlStatus('Error in CRHeloD Yaml.');
|
||||
setYamlStatus(`${t('createWorkflow.verifyCommit.errYaml')}`);
|
||||
} else {
|
||||
setYamlStatus('Your code is fine. You can move on !');
|
||||
setYamlStatus(`${t('createWorkflow.verifyCommit.codeIsFine')}`);
|
||||
}
|
||||
}, [modified]);
|
||||
|
||||
|
@ -192,7 +193,11 @@ const VerifyCommit: React.FC<VerifyCommitProps> = ({
|
|||
ampm
|
||||
disabled={edit}
|
||||
/> */}
|
||||
{cronSyntax === '' ? (
|
||||
{isDisabled ? (
|
||||
<Typography className={classes.schedule}>
|
||||
{t('createWorkflow.verifyCommit.summary.disabled')}
|
||||
</Typography>
|
||||
) : cronSyntax === '' ? (
|
||||
<Typography className={classes.schedule}>
|
||||
{t('createWorkflow.verifyCommit.summary.schedulingNow')}
|
||||
</Typography>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import Slider from '@material-ui/core/Slider';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { Theme, withStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import useStyles from './styles';
|
||||
|
||||
const PrettoSlider = withStyles({
|
||||
const PrettoSlider = withStyles((theme: Theme) => ({
|
||||
root: {
|
||||
backgroundColor: 'null',
|
||||
height: 8,
|
||||
background: 'transparent',
|
||||
height: '0.5rem',
|
||||
},
|
||||
track: {
|
||||
background:
|
||||
'linear-gradient(90deg, #5B44BA 0%, #858CDD 49.48%, #109B67 100%)',
|
||||
height: 38,
|
||||
height: '2.374rem',
|
||||
borderRadius: 4,
|
||||
borderTopRightRadius: 13,
|
||||
borderBottomRightRadius: 13,
|
||||
|
@ -21,29 +21,54 @@ const PrettoSlider = withStyles({
|
|||
borderBottomRightRadius: 4,
|
||||
},
|
||||
},
|
||||
rail: {
|
||||
height: 38,
|
||||
background: '#C9C9CA',
|
||||
borderRadius: 4,
|
||||
thumb: {
|
||||
opacity: 0,
|
||||
},
|
||||
mark: {
|
||||
marginLeft: theme.spacing(-0.85),
|
||||
paddingTop: theme.spacing(0.225),
|
||||
backgroundImage: `url(${'./icons/arrow.svg'})`,
|
||||
backgroundColor: 'transparent',
|
||||
'&[data-index="9"]': {
|
||||
background: 'transparent',
|
||||
},
|
||||
backgroundSize: 'cover',
|
||||
height: 40,
|
||||
width: 10,
|
||||
marginTop: -2,
|
||||
height: '2.4375rem',
|
||||
width: '0.75rem',
|
||||
marginTop: theme.spacing(-0.25),
|
||||
},
|
||||
markActive: {
|
||||
backgroundImage: `url(${'./icons/arrow.svg'})`,
|
||||
background: 'transparent',
|
||||
opacity: 1,
|
||||
},
|
||||
rail: {
|
||||
height: '2.375rem',
|
||||
background: '#C9C9CA',
|
||||
borderRadius: 4,
|
||||
},
|
||||
valueLabel: {
|
||||
top: -22,
|
||||
'& *': {
|
||||
background: 'transparent',
|
||||
color: '#000',
|
||||
color: theme.palette.background.paper,
|
||||
},
|
||||
},
|
||||
})(Slider);
|
||||
|
||||
markLabel: {
|
||||
fontFamily: 'Ubuntu',
|
||||
fontSize: '0.9375rem',
|
||||
marginTop: theme.spacing(-0.625),
|
||||
marginLeft: '-5%',
|
||||
color: 'black',
|
||||
opacity: 0.4,
|
||||
},
|
||||
markLabelActive: {
|
||||
fontFamily: 'Ubuntu',
|
||||
fontSize: '0.9375rem',
|
||||
color: theme.palette.background.paper,
|
||||
opacity: 1,
|
||||
},
|
||||
}))(Slider);
|
||||
const marks = [
|
||||
{
|
||||
value: 1,
|
||||
|
@ -86,14 +111,12 @@ const marks = [
|
|||
label: '10',
|
||||
},
|
||||
];
|
||||
|
||||
interface CustomSliderProps {
|
||||
testName: string;
|
||||
weight: number;
|
||||
index: number;
|
||||
handleChange: (newValue: number, index: number) => void;
|
||||
}
|
||||
|
||||
const WeightSlider: React.FC<CustomSliderProps> = ({
|
||||
testName,
|
||||
weight,
|
||||
|
@ -125,5 +148,4 @@ const WeightSlider: React.FC<CustomSliderProps> = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WeightSlider;
|
||||
|
|
|
@ -22,6 +22,10 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||
selectText: {
|
||||
height: '2.9rem',
|
||||
paddingLeft: theme.spacing(1),
|
||||
|
||||
'& .MuiSelect-icon': {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
},
|
||||
formControl: {
|
||||
marginRight: theme.spacing(2.5),
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import { Typography } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { InputField } from 'kubera-ui';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import BackButton from '../../../components/Button/BackButton';
|
||||
import ButtonFilled from '../../../components/Button/ButtonFilled';
|
||||
import InputField from '../../../components/InputField';
|
||||
import Loader from '../../../components/Loader';
|
||||
import QuickActionCard from '../../../components/QuickActionCard';
|
||||
import VideoCarousel from '../../../components/VideoCarousel';
|
||||
import Scaffold from '../../../containers/layouts/Scaffold';
|
||||
import Unimodal from '../../../containers/layouts/Unimodal';
|
||||
import { ADD_MY_HUB } from '../../../graphql/mutations';
|
||||
import { history } from '../../../redux/configureStore';
|
||||
import { RootState } from '../../../redux/reducers';
|
||||
import {
|
||||
isValidWebUrl,
|
||||
validateStartEmptySpacing,
|
||||
} from '../../../utils/validate';
|
||||
import useStyles from './styles';
|
||||
import { history } from '../../../redux/configureStore';
|
||||
import { ADD_MY_HUB } from '../../../graphql/mutations';
|
||||
import { RootState } from '../../../redux/reducers';
|
||||
import Loader from '../../../components/Loader';
|
||||
|
||||
interface GitHub {
|
||||
HubName: string;
|
||||
|
@ -88,7 +88,7 @@ const MyHub = () => {
|
|||
</Typography>
|
||||
<form id="login-form" autoComplete="on" onSubmit={handleSubmit}>
|
||||
<div className={classes.inputDiv}>
|
||||
<div className={classes.inputField}>
|
||||
<div className={classes.hubNameInput}>
|
||||
<InputField
|
||||
label="Hub Name"
|
||||
value={gitHub.HubName}
|
||||
|
@ -97,9 +97,13 @@ const MyHub = () => {
|
|||
? 'Should not start with an empty space'
|
||||
: ''
|
||||
}
|
||||
validationError={validateStartEmptySpacing(gitHub.HubName)}
|
||||
variant={
|
||||
validateStartEmptySpacing(gitHub.HubName)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
required
|
||||
handleChange={(e) =>
|
||||
onChange={(e) =>
|
||||
setGitHub({
|
||||
HubName: e.target.value,
|
||||
GitURL: gitHub.GitURL,
|
||||
|
@ -115,9 +119,9 @@ const MyHub = () => {
|
|||
helperText={
|
||||
!isValidWebUrl(gitHub.GitURL) ? 'Enter a valid URL' : ''
|
||||
}
|
||||
validationError={!isValidWebUrl(gitHub.GitURL)}
|
||||
variant={isValidWebUrl(gitHub.GitURL) ? 'error' : 'primary'}
|
||||
required
|
||||
handleChange={(e) =>
|
||||
onChange={(e) =>
|
||||
setGitHub({
|
||||
HubName: gitHub.HubName,
|
||||
GitURL: e.target.value,
|
||||
|
@ -135,9 +139,13 @@ const MyHub = () => {
|
|||
? 'Should not start with an empty space'
|
||||
: ''
|
||||
}
|
||||
validationError={validateStartEmptySpacing(gitHub.GitBranch)}
|
||||
variant={
|
||||
validateStartEmptySpacing(gitHub.GitBranch)
|
||||
? 'error'
|
||||
: 'primary'
|
||||
}
|
||||
required
|
||||
handleChange={(e) =>
|
||||
onChange={(e) =>
|
||||
setGitHub({
|
||||
HubName: gitHub.HubName,
|
||||
GitURL: gitHub.GitURL,
|
||||
|
|
|
@ -36,9 +36,14 @@ const useStyles = makeStyles((theme) => ({
|
|||
marginTop: theme.spacing(2.5),
|
||||
marginLeft: theme.spacing(-1.25),
|
||||
},
|
||||
inputField: {
|
||||
hubNameInput: {
|
||||
marginBottom: theme.spacing(2.5),
|
||||
width: '25rem',
|
||||
marginLeft: theme.spacing(2),
|
||||
},
|
||||
inputField: {
|
||||
marginLeft: theme.spacing(2),
|
||||
marginBottom: theme.spacing(2.5),
|
||||
width: '20rem',
|
||||
},
|
||||
modalDiv: {
|
||||
display: 'flex',
|
||||
|
|
|
@ -6,6 +6,7 @@ import ButtonOutline from '../../../components/Button/ButtonOutline';
|
|||
import DagreGraph, { d3Link, d3Node } from '../../../components/DagreGraph';
|
||||
import { Nodes } from '../../../models/graphql/workflowData';
|
||||
import useActions from '../../../redux/actions';
|
||||
import * as ToggleButtonAction from '../../../redux/actions/button';
|
||||
import * as NodeSelectionActions from '../../../redux/actions/nodeSelection';
|
||||
import * as TabActions from '../../../redux/actions/tabs';
|
||||
import { createLabel } from './createLabel';
|
||||
|
@ -29,6 +30,7 @@ const ArgoWorkflow: React.FC<ArgoWorkflowProps> = ({ nodes }) => {
|
|||
// Redux action call for updating selected node
|
||||
const nodeSelection = useActions(NodeSelectionActions);
|
||||
const tabs = useActions(TabActions);
|
||||
const toggleButtonAction = useActions(ToggleButtonAction);
|
||||
|
||||
const [graphData, setGraphData] = useState<GraphData>({
|
||||
nodes: [],
|
||||
|
@ -140,6 +142,9 @@ const ArgoWorkflow: React.FC<ArgoWorkflowProps> = ({ nodes }) => {
|
|||
)[0];
|
||||
setSelectedNodeID(nodeID);
|
||||
tabs.changeWorkflowDetailsTabs(1);
|
||||
toggleButtonAction.toggleInfoButton({
|
||||
isInfoToggled: true,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/* eslint-disable */
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import ButtonOutline from '../../../components/Button/ButtonOutline';
|
||||
import { RootState } from '../../../redux/reducers';
|
||||
import timeDifference from '../../../utils/datesModifier';
|
||||
import NodeLogs from '../NodeLogs';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useStyles from './styles';
|
||||
|
||||
interface WorkflowNodeInfoProps {
|
||||
|
@ -51,16 +51,6 @@ const WorkflowNodeInfo: React.FC<WorkflowNodeInfoProps> = ({
|
|||
<></>
|
||||
)}
|
||||
|
||||
{/* Node Name */}
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography className={classes.nodeSpacing}>
|
||||
<span className={classes.bold}>
|
||||
{t('workflowDetailsView.workflowNodeInfo.name')}:
|
||||
</span>
|
||||
<br />
|
||||
{pod_name}
|
||||
</Typography>
|
||||
</div>
|
||||
{/* Node Type */}
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography className={classes.nodeSpacing}>
|
||||
|
@ -120,12 +110,12 @@ const WorkflowNodeInfo: React.FC<WorkflowNodeInfoProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
{/* Node Name */}
|
||||
{/* Step Name */}
|
||||
<div className={classes.nodeSpacing}>
|
||||
<div className={classes.heightMaintainer}>
|
||||
<Typography>
|
||||
<span className={classes.bold}>
|
||||
{t('workflowDetailsView.workflowNodeInfo.nodeName')}:
|
||||
{t('workflowDetailsView.workflowNodeInfo.stepName')}:
|
||||
</span>{' '}
|
||||
{name}
|
||||
</Typography>
|
||||
|
|
Loading…
Reference in New Issue