chore(litmus-portal): Added env tunables, date range for usage stats and fixed logs issue (#2958)

* Added env tunables, date range for usage stats and fixed logs issues
* Minor theme change
* Minor translations fix

Signed-off-by: Amit Kumar Das <amit@chaosnative.com>
This commit is contained in:
Amit Kumar Das 2021-07-02 17:17:54 +05:30 committed by GitHub
parent 5bc3896171
commit 9c38833287
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 498 additions and 103 deletions

View File

@ -25,7 +25,6 @@ getStarted:
sidebar: sidebar:
title: Litmus title: Litmus
version: "Version: 1.13"
header: header:
projectDropdown: projectDropdown:
@ -34,7 +33,7 @@ header:
otherProjects: Other Projects otherProjects: Other Projects
noProjectsOther: You are not part of any projects not owned by you noProjectsOther: You are not part of any projects not owned by you
profileDropdown: profileDropdown:
signedIn: "Signed in as:" signedIn: 'Signed in as:'
emailUnset: Email not set emailUnset: Email not set
emailSet: Set up your email emailSet: Set up your email
switchProject: Please switch to a project you own to access settings switchProject: Please switch to a project you own to access settings
@ -89,7 +88,7 @@ workflowStepper:
back: Back back: Back
editor: editor:
status: "YAML Status:" status: 'YAML Status:'
###################################### ######################################
############ Pages ############# ############ Pages #############
@ -107,14 +106,14 @@ login:
tooltipText: You need to contact your admin to reset your password. tooltipText: You need to contact your admin to reset your password.
schedule: schedule:
heading: "Schedule a workflow" heading: 'Schedule a workflow'
headingDesc: "Click on test to see detailed log of your workflow" headingDesc: 'Click on test to see detailed log of your workflow'
headingText: "Schedule details:" headingText: 'Schedule details:'
description: "Choose the right time to schedule your first workflow. Below you can find some options that may be convenient for you." description: 'Choose the right time to schedule your first workflow. Below you can find some options that may be convenient for you.'
save: "Save Changes" save: 'Save Changes'
scheduleNow: Schedule now scheduleNow: Schedule now
scheduleAfter: Schedule after some time scheduleAfter: Schedule after some time
scheduleAfterSometime: "Choose the minutes, hours, or days when you want to start workflow" scheduleAfterSometime: 'Choose the minutes, hours, or days when you want to start workflow'
scheduleSpecificTime: Schedule at a specific time scheduleSpecificTime: Schedule at a specific time
scheduleFuture: Select date and time to start workflow in future scheduleFuture: Select date and time to start workflow in future
scheduleRecurring: Recurring Schedule scheduleRecurring: Recurring Schedule
@ -122,7 +121,7 @@ schedule:
after: After after: After
at: at at: at
At: At At: At
scheduleOn: "On" scheduleOn: 'On'
missingPerm: Missing sufficient permissions :( missingPerm: Missing sufficient permissions :(
requiredPerm: Looks like you do not have the required permission to create a new workflow on this project. requiredPerm: Looks like you do not have the required permission to create a new workflow on this project.
contact: Contact portal administrator to upgrade your permission. contact: Contact portal administrator to upgrade your permission.
@ -143,11 +142,11 @@ editSchedule:
successfullyCreated: is successfully created successfullyCreated: is successfully created
community: community:
title: "Community" title: 'Community'
heading: "Litmus Insights" heading: 'Litmus Insights'
headingDesc: "Stats for the Litmus community" headingDesc: 'Stats for the Litmus community'
analyticDesc: "Periodic growth of Litmus" analyticDesc: 'Periodic growth of Litmus'
statsHeading: "Litmus users around the world:" statsHeading: 'Litmus users around the world:'
litmusChaos: Litmuschaos litmusChaos: Litmuschaos
follow: Follow follow: Follow
@ -158,8 +157,8 @@ analytics:
comingSoon: Analytics Coming Soon ! comingSoon: Analytics Coming Soon !
waitingMessage: Waiting for workflow to start running ! waitingMessage: Waiting for workflow to start running !
chaosCompleteWaitingMessage: Waiting for chaos experiment to finish ! chaosCompleteWaitingMessage: Waiting for chaos experiment to finish !
highestScore: "Highest Score:" highestScore: 'Highest Score:'
lowestScore: "Lowest Score:" lowestScore: 'Lowest Score:'
exportPDF: Export PDF exportPDF: Export PDF
compareWorkflows: Compare workflows compareWorkflows: Compare workflows
targetCluster: Target cluster targetCluster: Target cluster
@ -443,7 +442,7 @@ analyticsDashboard:
warning: warning:
text: Unexpected bad things will happen if you dont read this! text: Unexpected bad things will happen if you dont read this!
info: The data source seems to be connected to following Application dashboards. Dashboards will be unable to show metrics if the data source is deleted. info: The data source seems to be connected to following Application dashboards. Dashboards will be unable to show metrics if the data source is deleted.
connectedDashboards: "Connected Dashboards :" connectedDashboards: 'Connected Dashboards :'
showLess: Show Less Dashboards showLess: Show Less Dashboards
dashboards: Dashboards dashboards: Dashboards
deletionSuccess: Successfully deleted the data source deletionSuccess: Successfully deleted the data source
@ -547,8 +546,8 @@ homeViews:
recentWorkflowRuns: recentWorkflowRuns:
workflowRunCard: workflowRunCard:
cardTitle: Browse workflow cardTitle: Browse workflow
resilienceRate: "Overall resilience rate:" resilienceRate: 'Overall resilience rate:'
lastRun: "Last Run:" lastRun: 'Last Run:'
showAnalytics: Show the analytics showAnalytics: Show the analytics
downloadManifest: Download manifest downloadManifest: Download manifest
heading: Recent Workflow runs heading: Recent Workflow runs
@ -591,7 +590,7 @@ chaosWorkflows:
disableSchedule: Disable Schedule disableSchedule: Disable Schedule
enableSchedule: Enable Schedule enableSchedule: Enable Schedule
saveTemplate: Save Template saveTemplate: Save Template
updateEngine: "Note: Make sure to update the chaos engine names" updateEngine: 'Note: Make sure to update the chaos engine names'
saveChanges: Save Changes saveChanges: Save Changes
savedSuccessfully: Successfully saved template. savedSuccessfully: Successfully saved template.
cancel: Cancel cancel: Cancel
@ -613,8 +612,8 @@ chaosWorkflows:
sync: Sync Workflow sync: Sync Workflow
terminate: Terminate Workflow terminate: Terminate Workflow
tableData: tableData:
overallRR: "Overall RR : " overallRR: 'Overall RR : '
experimentsPassed: "Experiments Passed : " experimentsPassed: 'Experiments Passed : '
showExperiments: Show Experiments showExperiments: Show Experiments
showTheWorkflow: Show the workflow showTheWorkflow: Show the workflow
showTheAnalytics: Show the analytics showTheAnalytics: Show the analytics
@ -803,7 +802,7 @@ settings:
disconnect: Are you sure you want to disconnect? disconnect: Are you sure you want to disconnect?
save: Save Locally save: Save Locally
repo: Git Repository repo: Git Repository
desc: "* Any existing or active workflows saved locally will not be synced into the git repository" desc: '* Any existing or active workflows saved locally will not be synced into the git repository'
connect: Connect connect: Connect
branch: Branch branch: Branch
URL: Git URL URL: Git URL
@ -818,11 +817,11 @@ settings:
headingDesc: Your image registry for the workflow manifest headingDesc: Your image registry for the workflow manifest
defaultValues: Use the default values defaultValues: Use the default values
defaultText: All YAML files use these default values provided by Litmus. The values cannot be changed. defaultText: All YAML files use these default values provided by Litmus. The values cannot be changed.
registry: "Registry : " registry: 'Registry : '
repo: "Repository : " repo: 'Repository : '
repoType: "Registry Type : " repoType: 'Registry Type : '
dockerio: "docker.io" dockerio: 'docker.io'
litmus: "litmuschaos" litmus: 'litmuschaos'
public: Public public: Public
private: Private private: Private
defaultReg: Use Default Registry defaultReg: Use Default Registry
@ -854,12 +853,12 @@ workflowDetailsView:
Completed: Completed Completed: Completed
runTime: runTime:
runTimeHeader: Run Time runTimeHeader: Run Time
startTime: "Start Time :" startTime: 'Start Time :'
endTime: "End Time :" endTime: 'End Time :'
targets: targets:
targetsHeader: Target targetsHeader: Target
cluster: "Cluster :" cluster: 'Cluster :'
namespace: "Workflow Namespace :" namespace: 'Workflow Namespace :'
workflowNodeInfo: workflowNodeInfo:
name: Name name: Name
type: Type type: Type
@ -914,8 +913,8 @@ createWorkflow:
revertSchedule: Revert Schedule revertSchedule: Revert Schedule
noTemplates: No template available. noTemplates: No template available.
addTemplate: You can add a template from the scheduled workflows table. addTemplate: You can add a template from the scheduled workflows table.
trueValue: "True" trueValue: 'True'
falseValue: "False" falseValue: 'False'
table: table:
head1: Sequence head1: Sequence
head2: Name head2: Name
@ -1010,8 +1009,8 @@ createWorkflow:
myHubInfo: Experiment details myHubInfo: Experiment details
annotationInfo: Provide target application details where you want to induce the chaos. annotationInfo: Provide target application details where you want to induce the chaos.
annotation: Annotation Check annotation: Annotation Check
true: "True" true: 'True'
false: "False" false: 'False'
annotationDesc: The target application does not have an annotation “Chaos=true”. Ideally, you cannot run this experiment unless the annotation is patched to the application. However, this service account has the privileges to disable the enforcement of annotation checks. Mark the annotation as false to proceed. annotationDesc: The target application does not have an annotation “Chaos=true”. Ideally, you cannot run this experiment unless the annotation is patched to the application. However, this service account has the privileges to disable the enforcement of annotation checks. Mark the annotation as false to proceed.
appkind: appKind appkind: appKind
deployment: Deployment deployment: Deployment
@ -1020,7 +1019,7 @@ createWorkflow:
deploymentconfig: Deploymentconfig deploymentconfig: Deploymentconfig
rollout: Rollout rollout: Rollout
nodeselector: NodeSelector nodeselector: NodeSelector
selector: "kubernetes.io/hostname :" selector: 'kubernetes.io/hostname :'
nsError: Namespace not available nsError: Namespace not available
labelError: Label not available in the resource or namespace labelError: Label not available in the resource or namespace
deleteExp: Delete the experiment deleteExp: Delete the experiment
@ -1034,9 +1033,16 @@ createWorkflow:
showDetails: Show Details showDetails: Show Details
showProp: Show Properties showProp: Show Properties
addProbe: Please add probes to see the data addProbe: Please add probes to see the data
addNewProbe: "+ Add a new Probe" addNewProbe: '+ Add a new Probe'
back: Back back: Back
finish: Finish finish: Finish
env:
envHeading: Tune the environment variables of the experiment
showMoreEnv: Show more environment variables
showLessEnv: Show less environment variables
key: Key Tunables
addKey: Add a key-value pair
finish: Finish
addProbe: addProbe:
heading: Add heading: Add
headingStrong: Probe headingStrong: Probe
@ -1216,7 +1222,7 @@ browseTemplate:
######################################### #########################################
internetIssues: internetIssues:
fetchData: "Fetching the data..." fetchData: 'Fetching the data...'
connectionError: It seems you have no internet connection, Please try again When connectivity resumes. connectionError: It seems you have no internet connection, Please try again When connectivity resumes.
###################################### ######################################
@ -1226,14 +1232,14 @@ myhub:
title: MyHubs title: MyHubs
connectTarget: Connect the target connectTarget: Connect the target
viewMyHub: View My Hub viewMyHub: View My Hub
error: "[Error: could not connect]" error: '[Error: could not connect]'
view: View view: View
validationEmptySpace: Should not start with an empty space validationEmptySpace: Should not start with an empty space
validURL: Enter a valid URL validURL: Enter a valid URL
edit: Edit Hub edit: Edit Hub
refresh: Refresh Hub refresh: Refresh Hub
disconnect: Disconnect Hub disconnect: Disconnect Hub
lastSync: "Last synced at:" lastSync: 'Last synced at:'
mainPage: mainPage:
header: ChaosHubs header: ChaosHubs
github: github.com/ github: github.com/
@ -1261,9 +1267,9 @@ myhub:
chaosCharts: Chaos-charts chaosCharts: Chaos-charts
noPredefinedExp: No predefined workflows available with information in this Hub noPredefinedExp: No predefined workflows available with information in this Hub
noExp: No experiments found noExp: No experiments found
lastSynced: "Last synced at: " lastSynced: 'Last synced at: '
repoLink: "Repository Link: " repoLink: 'Repository Link: '
repoBranch: "Repository Branch: " repoBranch: 'Repository Branch: '
connectHubPage: connectHubPage:
connectHub: Connect a new chaos hub connectHub: Connect a new chaos hub
editHub: Edit hub configuration editHub: Edit hub configuration
@ -1281,7 +1287,7 @@ myhub:
accessToken: Access Token accessToken: Access Token
ssh: SSH ssh: SSH
sshText: Please enable read / write access on the above git repository for the following key sshText: Please enable read / write access on the above git repository for the following key
sshAlert: "*Make sure to provide the SSH link of the Git Repository" sshAlert: '*Make sure to provide the SSH link of the Git Repository'
saveLater: Save for later saveLater: Save for later
updateHub: Update the MyHub with correct details from the MyHubs section updateHub: Update the MyHub with correct details from the MyHubs section
cancel: Cancel cancel: Cancel

View File

@ -0,0 +1,90 @@
import React, { useState } from 'react';
import { Button, IconButton, Popover, Typography } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import { DateRangePicker } from 'react-date-range';
import 'react-date-range/dist/styles.css'; // main css file
import 'react-date-range/dist/theme/default.css'; // theme css file
import useStyles from './styles';
interface UsageRangePickerProps {
isOpen: boolean;
popAnchorEl: HTMLElement | null;
displayDate: string;
popOverClick: (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => void;
popOverClose: (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => void;
selectDate: (selectFromDate: string, selectToDate: string) => void;
}
const UsageRangePicker: React.FC<UsageRangePickerProps> = ({
isOpen,
popAnchorEl,
displayDate,
popOverClick,
popOverClose,
selectDate,
}) => {
const classes = useStyles();
const { palette } = useTheme();
const [state, setState] = useState([
{
startDate: new Date(new Date().getFullYear(), new Date().getMonth(), 1),
endDate: new Date(),
key: 'selection',
},
]);
return (
<div className={classes.dateRangeDiv}>
<Button className={classes.selectDate} onClick={popOverClick}>
<Typography className={classes.displayDate}>
{displayDate}
<IconButton className={classes.dateRangeIcon}>
{isOpen ? <KeyboardArrowDownIcon /> : <ChevronRightIcon />}
</IconButton>
</Typography>
</Button>
<Popover
open={isOpen}
anchorEl={popAnchorEl}
onClose={popOverClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
style={{
marginTop: 10,
}}
>
<DateRangePicker
onChange={(item) => {
setState([(item as any).selection]);
selectDate(
`${(item as any).selection.startDate}`,
`${(item as any).selection.endDate}`
);
}}
showSelectionPreview
moveRangeOnFirstSelection={false}
months={1}
ranges={state}
direction="vertical"
editableDateInputs
rangeColors={[palette.primary.dark]}
showMonthAndYearPickers
/>
</Popover>
</div>
);
};
export default UsageRangePicker;

View File

@ -1,28 +1,93 @@
import { Typography } from '@material-ui/core'; import { Typography } from '@material-ui/core';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import moment from 'moment';
import Scaffold from '../../containers/layouts/Scaffold'; import Scaffold from '../../containers/layouts/Scaffold';
import UsageStats from '../../views/UsageStatistics/UsageStats'; import UsageStats from '../../views/UsageStatistics/UsageStats';
import UsageTable from '../../views/UsageStatistics/UsageTable'; import UsageTable from '../../views/UsageStatistics/UsageTable';
import UsageRangePicker from './datePicker';
import useStyles from './styles'; import useStyles from './styles';
interface DateRange {
start_date: string;
end_date: string;
}
const UsageStatistics = () => { const UsageStatistics = () => {
const classes = useStyles(); const classes = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
const [popAnchorEl, setPopAnchorEl] = React.useState<null | HTMLElement>(
null
);
/**
* State variable to set date in UNIX format
*/
const [dates, setDates] = React.useState<DateRange>({
start_date: Math.trunc(
new Date(new Date().getFullYear(), new Date().getMonth(), 1).getTime() /
1000
).toString(),
end_date: Math.trunc(new Date().getTime() / 1000).toString(),
});
/**
* State variable for displaying dates
*/
const [displayDate, setDisplayDate] = React.useState<string>(
`${moment(parseInt(dates.start_date, 10) * 1000).format(
'DD.MM.YY'
)}-${moment(parseInt(dates.end_date, 10) * 1000).format('DD.MM.YY')}`
);
const isOpen = Boolean(popAnchorEl);
const handlePopOverClose = () => {
setPopAnchorEl(null);
};
const handlePopOverClick = (event: React.MouseEvent<HTMLElement>) => {
setPopAnchorEl(event.currentTarget);
};
const dateChange = (selectStartDate: string, selectEndDate: string) => {
// Change the display value of date range
setDisplayDate(
`${moment(selectStartDate).format('DD.MM.YYYY').toString()}-${moment(
selectEndDate
)
.format('DD.MM.YYYY')
.toString()}`
);
setDates({
start_date: moment(selectStartDate).unix().toString(),
end_date: moment(selectEndDate).unix().toString(),
});
};
return ( return (
<Scaffold> <Scaffold>
<Typography variant="h3">{t('usage.usageHeader')}</Typography> <Typography variant="h3">{t('usage.usageHeader')}</Typography>
<Typography className={classes.description}> <div style={{ display: 'flex' }}>
{t('usage.usageSubtitle')} <Typography className={classes.description}>
</Typography> {t('usage.usageSubtitle')}
<UsageStats /> </Typography>
<UsageRangePicker
popOverClick={handlePopOverClick}
popOverClose={handlePopOverClose}
isOpen={isOpen}
popAnchorEl={popAnchorEl}
displayDate={displayDate}
selectDate={dateChange}
/>
</div>
<UsageStats start_time={dates.start_date} end_time={dates.end_date} />
<br /> <br />
<br /> <br />
<Typography variant="h4">{t('usage.projectStatistics')}</Typography> <Typography variant="h4">{t('usage.projectStatistics')}</Typography>
<Typography className={classes.description}> <Typography className={classes.description}>
{t('usage.projectSubtitle')} {t('usage.projectSubtitle')}
</Typography> </Typography>
<UsageTable /> <UsageTable start_time={dates.start_date} end_time={dates.end_date} />
</Scaffold> </Scaffold>
); );
}; };

View File

@ -10,5 +10,26 @@ const useStyles = makeStyles((theme: Theme) => ({
margin: theme.spacing(3, 0), margin: theme.spacing(3, 0),
color: theme.palette.text.hint, color: theme.palette.text.hint,
}, },
selectDate: {
display: 'flex',
flexDirection: 'row',
height: '2.5rem',
minWidth: '9rem',
border: '0.125rem solid',
marginRight: theme.spacing(3.75),
textTransform: 'none',
borderColor: theme.palette.primary.main,
},
displayDate: {
marginLeft: theme.spacing(1),
width: '100%',
},
dateRangeDiv: {
marginLeft: 'auto',
},
dateRangeIcon: {
width: '0.625rem',
height: '0.625rem',
},
})); }));
export default useStyles; export default useStyles;

View File

@ -8,6 +8,7 @@ import { ButtonOutlined } from 'litmus-ui';
import General from '../TuneWorkflowSteps/General'; import General from '../TuneWorkflowSteps/General';
import SteadyState from '../TuneWorkflowSteps/SteadyState'; import SteadyState from '../TuneWorkflowSteps/SteadyState';
import TargetApplication from '../TuneWorkflowSteps/TargetApplication'; import TargetApplication from '../TuneWorkflowSteps/TargetApplication';
import EnvironmentVariables from '../TuneWorkflowSteps/EnvironmentVariables';
import useStyles from './styles'; import useStyles from './styles';
interface ConfigurationStepperProps { interface ConfigurationStepperProps {
@ -29,12 +30,12 @@ function getStepContent(
case 0: case 0:
return <General isCustom={isCustom} gotoStep={gotoStep} />; return <General isCustom={isCustom} gotoStep={gotoStep} />;
case 1: case 1:
return ( return <TargetApplication gotoStep={gotoStep} />;
<TargetApplication engineIndex={engineIndex} gotoStep={gotoStep} />
);
case 2: case 2:
return <SteadyState gotoStep={gotoStep} />;
case 3:
return ( return (
<SteadyState <EnvironmentVariables
engineIndex={engineIndex} engineIndex={engineIndex}
gotoStep={gotoStep} gotoStep={gotoStep}
closeStepper={closeStepper} closeStepper={closeStepper}
@ -60,6 +61,7 @@ const ConfigurationStepper: React.FC<ConfigurationStepperProps> = ({
'General', 'General',
'Target Application', 'Target Application',
'Define the steady state for this application', 'Define the steady state for this application',
'Tune Experiment',
]; ];
const gotoStep = (page: number) => { const gotoStep = (page: number) => {

View File

@ -0,0 +1,210 @@
import { Button, Typography } from '@material-ui/core';
import { ButtonFilled, InputField } from 'litmus-ui';
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import YAML from 'yaml';
import AddIcon from '@material-ui/icons/Add';
import { WorkflowManifest } from '../../../../models/redux/workflow';
import useActions from '../../../../redux/actions';
import * as WorkflowActions from '../../../../redux/actions/workflow';
import { RootState } from '../../../../redux/reducers';
import useStyles from './styles';
interface EnvVariableProps {
engineIndex: number;
gotoStep: (page: number) => void;
closeStepper: () => void;
}
interface EnvValues {
name: string;
value: string;
}
const EnvironmentVariables: React.FC<EnvVariableProps> = ({
gotoStep,
engineIndex,
closeStepper,
}) => {
const { t } = useTranslation();
const classes = useStyles();
const workflow = useActions(WorkflowActions);
const manifest: WorkflowManifest = useSelector(
(state: RootState) => state.workflowManifest
);
/**
* State variable for managing the additional key-value pair
*/
const [addEnv, setAddEnv] = useState<EnvValues>({
name: '',
value: '',
});
/**
* State variable to display Show More / Show Less
*/
const [showMore, setShowMore] = useState(false);
const engine = useSelector(
(state: RootState) => state.workflowManifest.engineYAML
);
const engineYAML = YAML.parse(engine);
/**
* State variable to store all the env varaibles from the engine
*/
const [env, setEnvs] = useState<EnvValues[]>(
engineYAML.spec.experiments[0].spec.components.env
);
/**
* getShowMoreItems functions returns all the envs
* if showMore is true, else this returns maximum of
* 3 envs.
*/
const getShowMoreItems = (env: EnvValues[]) => {
if (showMore) {
return env;
}
return env.slice(0, 3);
};
/**
* handleMainYAMLChange funtion makes the changes
* in the engine YAML and then adds the engine manifest
* to the overall workflow YAML
*/
const handleMainYAMLChange = () => {
engineYAML.spec.experiments[0].spec.components.env = env;
const mainManifest = YAML.parse(manifest.manifest);
mainManifest.spec.templates[engineIndex].inputs.artifacts[0].raw.data =
YAML.stringify(engineYAML);
workflow.setWorkflowManifest({
manifest: YAML.stringify(mainManifest),
engineYAML: YAML.stringify(engineYAML),
});
closeStepper();
};
return (
<div>
<Typography>{t('createWorkflow.tuneWorkflow.env.envHeading')}</Typography>
<br />
<div className={classes.inputDiv}>
{getShowMoreItems(env).map((data, index) => {
return (
<>
<InputField
width="auto"
label={data.name}
value={env[index].value}
onChange={(event) => {
env[index].value = event.target.value;
setEnvs([...env]);
}}
/>
<br />
</>
);
})}
<div>
{env.length > 3 && !showMore ? (
<ButtonFilled
className={classes.showMoreBtn}
onClick={() => {
setShowMore(true);
}}
>
<ArrowDownwardIcon />
<Typography>
{t('createWorkflow.tuneWorkflow.env.showMoreEnv')}
</Typography>
</ButtonFilled>
) : showMore ? (
<ButtonFilled
className={classes.showMoreBtn}
onClick={() => {
setShowMore(false);
}}
>
<ArrowUpwardIcon />
<Typography>
{t('createWorkflow.tuneWorkflow.env.showLessEnv')}
</Typography>
</ButtonFilled>
) : (
<></>
)}
</div>
<div>
<Typography className={classes.keyText}>
{t('createWorkflow.tuneWorkflow.env.key')}
</Typography>
<br />
<div style={{ display: 'flex' }}>
<InputField
label="Add Key"
value={addEnv.name}
onChange={(event) => {
setAddEnv({
...addEnv,
name: event.target.value,
});
}}
width="20"
className={classes.addKeyInput}
/>
<InputField
label="Add Value"
value={addEnv.value}
onChange={(event) => {
setAddEnv({
...addEnv,
value: event.target.value,
});
}}
width="20"
/>
</div>
<ButtonFilled
className={classes.addKeyValue}
onClick={() => {
env[env.length] = {
name: addEnv.name,
value: addEnv.value,
};
setEnvs(env);
setAddEnv({
name: '',
value: '',
});
}}
disabled={addEnv.name.trim() === '' || addEnv.value.trim() === ''}
>
<AddIcon /> {t('createWorkflow.tuneWorkflow.env.addKey')}
</ButtonFilled>
</div>
</div>
<div>
<Button onClick={() => gotoStep(2)} className={classes.button}>
{t('workflowStepper.back')}
</Button>
<Button
variant="contained"
color="primary"
onClick={() => handleMainYAMLChange()}
className={classes.button}
>
{t('createWorkflow.tuneWorkflow.env.finish')}
</Button>
</div>
</div>
);
};
export default EnvironmentVariables;

View File

@ -24,16 +24,10 @@ import AddProbe from '../AddProbe';
import useStyles from './styles'; import useStyles from './styles';
interface SteadyStateProps { interface SteadyStateProps {
engineIndex: number;
gotoStep: (page: number) => void; gotoStep: (page: number) => void;
closeStepper: () => void;
} }
const SteadyState: React.FC<SteadyStateProps> = ({ const SteadyState: React.FC<SteadyStateProps> = ({ gotoStep }) => {
engineIndex,
gotoStep,
closeStepper,
}) => {
const classes = useStyles(); const classes = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
const workflow = useActions(WorkflowActions); const workflow = useActions(WorkflowActions);
@ -55,14 +49,9 @@ const SteadyState: React.FC<SteadyStateProps> = ({
setAddProbe(false); setAddProbe(false);
}; };
// handleManiYAMLChange allows to update the main manifest // handleManiYAMLChange allows to update the changes in individual Chaos Engines
// with the changes in individual Chaos Engines
const handleMainYAMLChange = () => { const handleMainYAMLChange = () => {
const mainManifest = YAML.parse(manifest.manifest);
mainManifest.spec.templates[engineIndex].inputs.artifacts[0].raw.data =
YAML.stringify(chaosEngine);
workflow.setWorkflowManifest({ workflow.setWorkflowManifest({
manifest: YAML.stringify(mainManifest),
engineYAML: YAML.stringify(chaosEngine), engineYAML: YAML.stringify(chaosEngine),
}); });
}; };
@ -103,10 +92,10 @@ const SteadyState: React.FC<SteadyStateProps> = ({
setAddProbe(false); setAddProbe(false);
}; };
const handleStepperClose = () => { const handleNext = () => {
chaosEngine.spec.experiments[0].spec.probe = probesData; chaosEngine.spec.experiments[0].spec.probe = probesData;
handleMainYAMLChange(); handleMainYAMLChange();
return closeStepper(); gotoStep(3);
}; };
return ( return (
@ -269,10 +258,10 @@ const SteadyState: React.FC<SteadyStateProps> = ({
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => handleStepperClose()} onClick={() => handleNext()}
className={classes.button} className={classes.button}
> >
{t('createWorkflow.tuneWorkflow.steadyState.finish')} Next
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -51,14 +51,10 @@ interface TargetApplicationData {
} }
interface TargetApplicationProp { interface TargetApplicationProp {
engineIndex: number;
gotoStep: (page: number) => void; gotoStep: (page: number) => void;
} }
const TargetApplication: React.FC<TargetApplicationProp> = ({ const TargetApplication: React.FC<TargetApplicationProp> = ({ gotoStep }) => {
engineIndex,
gotoStep,
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
/** /**
* State Variables to manage theme changes * State Variables to manage theme changes
@ -152,9 +148,7 @@ const TargetApplication: React.FC<TargetApplicationProp> = ({
]; ];
} }
engineManifest.spec.jobCleanUpPolicy = targetApp.jobCleanUpPolicy; engineManifest.spec.jobCleanUpPolicy = targetApp.jobCleanUpPolicy;
const mainManifest = YAML.parse(manifest.manifest);
mainManifest.spec.templates[engineIndex].inputs.artifacts[0].raw.data =
YAML.stringify(engineManifest);
workflow.setWorkflowManifest({ workflow.setWorkflowManifest({
engineYAML: YAML.stringify(engineManifest), engineYAML: YAML.stringify(engineManifest),
}); });

View File

@ -10,6 +10,13 @@ const useStyles = makeStyles((theme: Theme) => ({
marginTop: theme.spacing(1), marginTop: theme.spacing(1),
marginRight: theme.spacing(1), marginRight: theme.spacing(1),
}, },
showMoreBtn: {
display: 'flex',
color: theme.palette.primary.main,
backgroundColor: 'transparent !important',
cursor: 'pointer',
marginBottom: theme.spacing(2.5),
},
actionsContainer: { actionsContainer: {
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),
}, },
@ -20,7 +27,12 @@ const useStyles = makeStyles((theme: Theme) => ({
border: 'none !important', border: 'none !important',
color: theme.palette.primary.main, color: theme.palette.primary.main,
}, },
keyText: {
fontSize: '1rem',
},
addKeyInput: {
marginRight: theme.spacing(2.25),
},
// General Component // General Component
generalContainer: { generalContainer: {
display: 'flex', display: 'flex',
@ -33,6 +45,14 @@ const useStyles = makeStyles((theme: Theme) => ({
flexDirection: 'column', flexDirection: 'column',
maxWidth: '25rem', maxWidth: '25rem',
}, },
addKeyValue: {
backgroundColor: 'transparent !important',
color: theme.palette.primary.main,
marginTop: theme.spacing(1.25),
marginBottom: theme.spacing(2.25),
},
annotation: { annotation: {
fontSize: '0.875rem', fontSize: '0.875rem',
margin: theme.spacing(0.6, 2, 0, 0), margin: theme.spacing(0.6, 2, 0, 0),

View File

@ -6,7 +6,12 @@ import { GET_GLOBAL_STATS } from '../../../graphql';
import Card from './Cards'; import Card from './Cards';
import useStyles from './styles'; import useStyles from './styles';
const UsageStats = () => { interface TimeRange {
start_time: string;
end_time: string;
}
const UsageStats: React.FC<TimeRange> = ({ start_time, end_time }) => {
const classes = useStyles(); const classes = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
const [usageQuery, { loading, data }] = useLazyQuery(GET_GLOBAL_STATS); const [usageQuery, { loading, data }] = useLazyQuery(GET_GLOBAL_STATS);
@ -16,19 +21,13 @@ const UsageStats = () => {
variables: { variables: {
query: { query: {
DateRange: { DateRange: {
start_date: Math.trunc( start_date: start_time,
new Date( end_date: end_time,
new Date().getFullYear(),
new Date().getMonth(),
1
).getTime() / 1000
).toString(),
end_date: Math.trunc(new Date().getTime() / 1000).toString(),
}, },
}, },
}, },
}); });
}, []); }, [start_time, end_time]);
return ( return (
<div className={classes.cardDiv}> <div className={classes.cardDiv}>

View File

@ -33,7 +33,12 @@ interface SortInput {
Descending?: boolean; Descending?: boolean;
} }
const UsageTable = () => { interface TimeRange {
start_time: string;
end_time: string;
}
const UsageTable: React.FC<TimeRange> = ({ start_time, end_time }) => {
const classes = useStyles(); const classes = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
const [paginationData, setPaginationData] = useState<Pagination>({ const [paginationData, setPaginationData] = useState<Pagination>({
@ -46,21 +51,15 @@ const UsageTable = () => {
}); });
const [search, setSearch] = useState<string>(''); const [search, setSearch] = useState<string>('');
const [usageQuery, { loading, data }] = useLazyQuery(GLOBAL_PROJECT_DATA, {}); const [usageQuery, { loading, data }] = useLazyQuery(GLOBAL_PROJECT_DATA);
useEffect(() => { useEffect(() => {
usageQuery({ usageQuery({
variables: { variables: {
query: { query: {
DateRange: { DateRange: {
start_date: Math.trunc( start_date: start_time,
new Date( end_date: end_time,
new Date().getFullYear(),
new Date().getMonth(),
1
).getTime() / 1000
).toString(),
end_date: Math.trunc(new Date().getTime() / 1000).toString(),
}, },
Pagination: { Pagination: {
page: paginationData.page, page: paginationData.page,
@ -71,7 +70,7 @@ const UsageTable = () => {
}, },
}, },
}); });
}, [paginationData, search, sortData]); }, [paginationData, search, sortData, start_time, end_time]);
return ( return (
<div className={classes.table}> <div className={classes.table}>

View File

@ -87,7 +87,7 @@ const LogsSwitcher: React.FC<LogsSwitcherProps> = ({
chaos_namespace: '', chaos_namespace: '',
}); });
} }
}, [workflow_data]); }, [workflow_data, pod_name]);
const [chaosResult, setChaosResult] = useState(''); const [chaosResult, setChaosResult] = useState('');