Skip to content

Commit

Permalink
feat: add advanced options to launch workflow form (#226)
Browse files Browse the repository at this point in the history
Signed-off-by: csirius <[email protected]>
  • Loading branch information
govalt authored Oct 13, 2021
1 parent 7bdb7a4 commit 82a9271
Show file tree
Hide file tree
Showing 9 changed files with 390 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ function useRelaunchWorkflowFormState({
doFetch: async execution => {
const {
closure: { workflowId },
spec: { launchPlan }
spec: {
launchPlan,
disableAll,
maxParallelism,
qualityOfService
}
} = execution;
const workflow = await apiContext.getWorkflow(workflowId);
const inputDefinitions = getWorkflowInputs(workflow);
Expand All @@ -45,7 +50,14 @@ function useRelaunchWorkflowFormState({
},
apiContext
);
return { values, launchPlan, workflowId };
return {
values,
launchPlan,
workflowId,
disableAll,
maxParallelism,
qualityOfService
};
}
},
execution
Expand Down
176 changes: 176 additions & 0 deletions src/components/Launch/LaunchForm/LaunchFormAdvancedInputs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import * as React from 'react';
import { Admin } from 'flyteidl';
import { makeStyles, Theme } from '@material-ui/core/styles';
import Checkbox from '@material-ui/core/Checkbox';
import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import Typography from '@material-ui/core/Typography';

import { qualityOfServiceTier, qualityOfServiceTierLabels } from './constants';
import { LaunchAdvancedOptionsRef } from './types';
import { flyteidl } from '@flyteorg/flyteidl/gen/pb-js/flyteidl';
import IExecutionSpec = flyteidl.admin.IExecutionSpec;
import { Grid, TextField } from '@material-ui/core';

const useStyles = makeStyles((theme: Theme) => ({
sectionTitle: {
marginBottom: theme.spacing(2)
},
sectionContainer: {
display: 'flex',
flexDirection: 'column'
},
qosContainer: {
display: 'flex'
},
autoFlex: {
flex: 1,
display: 'flex'
}
}));

interface LaunchAdvancedOptionsProps {
spec: Admin.IExecutionSpec;
}

export const LaunchFormAdvancedInputs = React.forwardRef<
LaunchAdvancedOptionsRef,
LaunchAdvancedOptionsProps
>(({ spec }, ref) => {
const styles = useStyles();
const [qosTier, setQosTier] = React.useState(
qualityOfServiceTier.UNDEFINED.toString()
);
const [disableAll, setDisableAll] = React.useState(false);
const [maxParallelism, setMaxParallelism] = React.useState('');
const [queueingBudget, setQueueingBudget] = React.useState('');

React.useEffect(() => {
if (spec.disableAll !== undefined && spec.disableAll !== null) {
setDisableAll(spec.disableAll);
}
if (spec.maxParallelism !== undefined && spec.maxParallelism !== null) {
setMaxParallelism(`${spec.maxParallelism}`);
}
if (
spec.qualityOfService?.tier !== undefined &&
spec.qualityOfService?.tier !== null
) {
setQosTier(spec.qualityOfService.tier.toString());
}
}, [spec]);

React.useImperativeHandle(
ref,
() => ({
getValues: () => {
return {
disableAll,
qualityOfService: {
tier: parseInt(qosTier || '0', 10)
},
maxParallelism: parseInt(maxParallelism || '', 10)
} as IExecutionSpec;
},
validate: () => {
return true;
}
}),
[disableAll, qosTier, maxParallelism]
);

const handleQosTierChange = React.useCallback(({ target: { value } }) => {
setQosTier(value);
}, []);

const handleDisableAllChange = React.useCallback(() => {
setDisableAll(prevState => !prevState);
}, []);

const handleMaxParallelismChange = React.useCallback(
({ target: { value } }) => {
setMaxParallelism(value);
},
[]
);

const handleQueueingBudgetChange = React.useCallback(
({ target: { value } }) => {
setQueueingBudget(value);
},
[]
);

return (
<>
<section title="Enable/Disable all notifications">
<FormControlLabel
control={
<Checkbox
checked={disableAll}
onChange={handleDisableAllChange}
/>
}
label="Disable all notifications"
/>
</section>
<section title="Max parallelism">
<TextField
variant="outlined"
label="Max parallelism"
fullWidth
margin="normal"
value={maxParallelism}
onChange={handleMaxParallelismChange}
/>
</section>
<section
title="Quality of Service"
className={styles.sectionContainer}
>
<Typography variant="h6" className={styles.sectionTitle}>
Quality of Service
</Typography>
<Grid container spacing={2}>
<Grid item sm={6}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="quality-of-service-tier-id">
Quality of Service Tier
</InputLabel>
<Select
variant="outlined"
id="quality-of-service-tier-id"
label="Quality of Service Tier"
value={qosTier}
onChange={handleQosTierChange}
>
{Object.keys(qualityOfServiceTierLabels).map(
tier => (
<MenuItem
key={`quality-of-service-${tier}`}
value={tier}
>
{qualityOfServiceTierLabels[tier]}
</MenuItem>
)
)}
</Select>
</FormControl>
</Grid>
<Grid item sm={6}>
<TextField
variant="outlined"
label="Queueing budget"
fullWidth
value={queueingBudget}
onChange={handleQueueingBudgetChange}
/>
</Grid>
</Grid>
</section>
</>
);
});
39 changes: 38 additions & 1 deletion src/components/Launch/LaunchForm/LaunchWorkflowForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { DialogContent } from '@material-ui/core';
import {
Accordion,
AccordionDetails,
AccordionSummary,
DialogContent
} from '@material-ui/core';
import { getCacheKey } from 'components/Cache/utils';
import * as React from 'react';
import { formStrings } from './constants';
Expand All @@ -14,11 +19,16 @@ import {
LaunchWorkflowFormProps
} from './types';
import { useLaunchWorkflowFormState } from './useLaunchWorkflowFormState';
import { isEnterInputsState } from './utils';
import { LaunchRoleInput } from './LaunchRoleInput';
import { LaunchFormAdvancedInputs } from './LaunchFormAdvancedInputs';

/** Renders the form for initiating a Launch request based on a Workflow */
export const LaunchWorkflowForm: React.FC<LaunchWorkflowFormProps> = props => {
const {
formInputsRef,
roleInputRef,
advancedOptionsRef,
state,
service,
workflowSourceSelectorState
Expand Down Expand Up @@ -96,6 +106,33 @@ export const LaunchWorkflowForm: React.FC<LaunchWorkflowFormProps> = props => {
state={baseState}
variant="workflow"
/>
<Accordion className={styles.noBorder}>
<AccordionSummary
classes={{
root: styles.summaryWrapper,
content: styles.advancedOptions
}}
>
Advanced options
</AccordionSummary>
<AccordionDetails classes={{ root: styles.detailsWrapper }}>
{isEnterInputsState(baseState) ? (
<LaunchRoleInput
initialValue={state.context.defaultAuthRole}
ref={roleInputRef}
showErrors={state.context.showErrors}
/>
) : null}
<LaunchFormAdvancedInputs
ref={advancedOptionsRef}
spec={{
disableAll: state.context.disableAll,
maxParallelism: state.context.maxParallelism,
qualityOfService: state.context.qualityOfService
}}
/>
</AccordionDetails>
</Accordion>
</DialogContent>
<LaunchFormActions
state={baseState}
Expand Down
14 changes: 14 additions & 0 deletions src/components/Launch/LaunchForm/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,17 @@ export const blobUriHelperText = '(required) location of the data';
export const blobFormatHelperText = '(optional) csv, parquet, etc...';
export const correctInputErrors =
'Some inputs have errors. Please correct them before submitting.';

export const qualityOfServiceTier = {
UNDEFINED: 0,
HIGH: 1,
MEDIUM: 2,
LOW: 3
};

export const qualityOfServiceTierLabels = {
[qualityOfServiceTier.UNDEFINED]: 'Undefined',
[qualityOfServiceTier.HIGH]: 'High',
[qualityOfServiceTier.MEDIUM]: 'Medium',
[qualityOfServiceTier.LOW]: 'Low'
};
6 changes: 5 additions & 1 deletion src/components/Launch/LaunchForm/launchMachine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Admin } from 'flyteidl';
import { Admin, Core } from 'flyteidl';
import { Identifier, NamedEntityIdentifier } from 'models/Common/types';
import { WorkflowExecutionIdentifier } from 'models/Execution/types';
import { LaunchPlan } from 'models/Launch/types';
Expand Down Expand Up @@ -77,6 +77,10 @@ export interface WorkflowLaunchContext extends BaseLaunchContext {
preferredWorkflowId?: Identifier;
workflowVersion?: WorkflowId;
workflowVersionOptions?: Workflow[];
defaultAuthRole?: Admin.IAuthRole;
disableAll?: boolean | null;
maxParallelism?: number | null;
qualityOfService?: Core.IQualityOfService | null;
}

export interface TaskLaunchContext extends BaseLaunchContext {
Expand Down
28 changes: 26 additions & 2 deletions src/components/Launch/LaunchForm/styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Theme } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import { smallFontSize } from 'components/Theme/constants';
import {
interactiveTextColor,
smallFontSize
} from 'components/Theme/constants';

export const useStyles = makeStyles((theme: Theme) => ({
footer: {
Expand All @@ -14,7 +17,8 @@ export const useStyles = makeStyles((theme: Theme) => ({
width: '100%'
},
inputsSection: {
padding: theme.spacing(2)
padding: theme.spacing(2),
maxHeight: theme.spacing(90)
},
inputLabel: {
color: theme.palette.text.hint,
Expand All @@ -28,5 +32,25 @@ export const useStyles = makeStyles((theme: Theme) => ({
sectionHeader: {
marginBottom: theme.spacing(1),
marginTop: theme.spacing(1)
},
advancedOptions: {
color: interactiveTextColor,
justifyContent: 'flex-end'
},
noBorder: {
'&:before': {
height: 0
}
},
summaryWrapper: {
padding: 0
},
detailsWrapper: {
paddingLeft: 0,
paddingRight: 0,
flexDirection: 'column',
'& section': {
flex: 1
}
}
}));
10 changes: 10 additions & 0 deletions src/components/Launch/LaunchForm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export interface WorkflowInitialLaunchParameters
extends BaseInitialLaunchParameters {
launchPlan?: Identifier;
workflowId?: WorkflowId;
authRole?: Admin.IAuthRole;
disableAll?: boolean | null;
maxParallelism?: number | null;
qualityOfService?: Core.IQualityOfService | null;
}
export interface LaunchWorkflowFormProps extends BaseLaunchFormProps {
workflowId: NamedEntityIdentifier;
Expand Down Expand Up @@ -85,6 +89,10 @@ export interface LaunchRoleInputRef {
getValue(): Admin.IAuthRole;
validate(): boolean;
}
export interface LaunchAdvancedOptionsRef {
getValues(): Admin.IExecutionSpec;
validate(): boolean;
}

export interface WorkflowSourceSelectorState {
launchPlanSelectorOptions: SearchableSelectorOption<LaunchPlan>[];
Expand All @@ -110,7 +118,9 @@ export interface TaskSourceSelectorState {
}

export interface LaunchWorkflowFormState {
advancedOptionsRef: React.RefObject<LaunchAdvancedOptionsRef>;
formInputsRef: React.RefObject<LaunchFormInputsRef>;
roleInputRef: React.RefObject<LaunchRoleInputRef>;
state: State<
WorkflowLaunchContext,
WorkflowLaunchEvent,
Expand Down
Loading

0 comments on commit 82a9271

Please sign in to comment.