Skip to content

Commit

Permalink
Resume Signal Form (#622)
Browse files Browse the repository at this point in the history
* Resume Form

* feat: launch form for gate node

Signed-off-by: James <[email protected]>

* fix: launch form for gate nodes

Signed-off-by: James <[email protected]>

* fix: node details for gate node

Signed-off-by: James <[email protected]>

* fix: add resumeformstate

Signed-off-by: James <[email protected]>

* fix: setsignal added

Signed-off-by: James <[email protected]>

* fix: string node input label fixed

Signed-off-by: James <[email protected]>

* fix: add resume form for 4 places

Signed-off-by: James <[email protected]>

* fix: refactor codes to reduce duplication

Signed-off-by: James <[email protected]>

* fix: base launch event

Signed-off-by: James <[email protected]>

* fix: build fix

Signed-off-by: James <[email protected]>

* fix: move constant strings to i18n

Signed-off-by: James <[email protected]>

* fix: flyteidl for build fix temporarily

Signed-off-by: James <[email protected]>

* fix: launch form dialog

Signed-off-by: James <[email protected]>

* fix: node execution actions resume button

Signed-off-by: James <[email protected]>

* fix: tests for node execution actions and paused tasks component

Signed-off-by: James <[email protected]>

* fix: test for launch worflow form

Signed-off-by: James <[email protected]>

* fix: pr wrap up fix

Signed-off-by: James <[email protected]>

Signed-off-by: James <[email protected]>
  • Loading branch information
james-union authored Oct 25, 2022
1 parent 1542da0 commit be9f643
Show file tree
Hide file tree
Showing 40 changed files with 699 additions and 238 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
]
},
"dependencies": {
"@flyteorg/flyteidl": "1.1.16"
"@flyteorg/flyteidl": "https://github.com/flyteorg/flyteidl.git#feature/gate-nodes"
},
"devDependencies": {
"@storybook/addon-actions": "^6.4.19",
Expand Down
2 changes: 1 addition & 1 deletion packages/zapp/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@date-io/moment": "1.3.9",
"@flyteorg/flyteidl": "1.1.4",
"@flyteorg/flyteidl": "https://github.com/flyteorg/flyteidl.git#feature/gate-nodes",
"@material-ui/core": "^4.0.0",
"@material-ui/icons": "^4.0.0",
"@material-ui/pickers": "^3.2.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useEffect, useState } from 'react';
import { NodeExecutionDetails } from '../types';
import t from './strings';
import { ExecutionNodeDeck } from './ExecutionNodeDeck';
import { useNodeExecutionContext } from '../contextProvider/NodeExecutionDetails';

const useStyles = makeStyles((theme: Theme) => {
return {
Expand Down Expand Up @@ -71,13 +72,19 @@ export const ExecutionDetailsActions = ({
const styles = useStyles();

const [showLaunchForm, setShowLaunchForm] = useState<boolean>(false);
const [showResumeForm, setShowResumeForm] = useState<boolean>(false);

const [initialParameters, setInitialParameters] = useState<
TaskInitialLaunchParameters | undefined
>(undefined);

const executionData = useNodeExecutionData(nodeExecutionId);
const execution = useNodeExecution(nodeExecutionId);
const { compiledWorkflowClosure } = useNodeExecutionContext();
const id = details?.taskTemplate?.id;
const compiledNode = (compiledWorkflowClosure?.primary.template.nodes ?? []).find(
(node) => node.id === nodeExecutionId.nodeId,
);

useEffect(() => {
if (!id) {
Expand Down Expand Up @@ -107,8 +114,9 @@ export const ExecutionDetailsActions = ({
setShowLaunchForm(true);
};

const resumeAction = () => {
// TODO https://github.com/flyteorg/flyteconsole/issues/587 Launch form for node id
const onResumeClick = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
setShowResumeForm(true);
};

return (
Expand All @@ -130,7 +138,7 @@ export const ExecutionDetailsActions = ({
</Button>
)}
{phase === NodeExecutionPhase.PAUSED && (
<Button variant="outlined" color="primary" onClick={resumeAction}>
<Button variant="outlined" color="primary" onClick={onResumeClick}>
{t('resume')}
</Button>
)}
Expand All @@ -143,6 +151,15 @@ export const ExecutionDetailsActions = ({
setShowLaunchForm={setShowLaunchForm}
/>
)}
{compiledNode && (
<LaunchFormDialog
compiledNode={compiledNode}
initialParameters={initialParameters}
nodeId={nodeExecutionId.nodeId}
showLaunchForm={showResumeForm}
setShowLaunchForm={setShowResumeForm}
/>
)}
{execution?.value?.closure?.deckUri && (
<Dialog PaperProps={{ className: styles.dialog }} maxWidth={false} open={showDeck}>
<div className={styles.dialogTitle}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ export const TaskNames = React.forwardRef<HTMLDivElement, TaskNamesProps>(
</div>
{onAction && (
<Tooltip title={t('resume')}>
<IconButton onClick={() => onAction(node.id)}>
<IconButton
onClick={() => onAction(node.id)}
data-testid={`resume-gate-node-${node.id}`}
>
<PlayCircleOutlineIcon />
</IconButton>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const NodeExecutionActions = ({ execution }: NodeExecutionActionsProps):
const { setSelectedExecution } = useContext(DetailsPanelContext);

const [showLaunchForm, setShowLaunchForm] = useState<boolean>(false);
const [showResumeForm, setShowResumeForm] = useState<boolean>(false);
const [nodeExecutionDetails, setNodeExecutionDetails] = useState<
NodeExecutionDetails | undefined
>(undefined);
Expand All @@ -42,6 +43,9 @@ export const NodeExecutionActions = ({ execution }: NodeExecutionActionsProps):
execution.id,
);
const phase = getNodeFrontendPhase(execution.closure.phase, isGateNode);
const compiledNode = (compiledWorkflowClosure?.primary.template.nodes ?? []).find(
(node) => node.id === execution.id.nodeId,
);

useEffect(() => {
getNodeExecutionDetails(execution).then((res) => {
Expand Down Expand Up @@ -82,37 +86,16 @@ export const NodeExecutionActions = ({ execution }: NodeExecutionActionsProps):
setShowLaunchForm(true);
};

const resumeAction = () => {
// TODO https://github.com/flyteorg/flyteconsole/issues/587 Launch form for node id
};

const renderRerunAction = () => {
if (!id || !initialParameters) {
return <></>;
}

return (
<>
<Tooltip title={t('rerunTooltip')}>
<IconButton onClick={rerunIconOnClick}>
<RerunIcon />
</IconButton>
</Tooltip>
<LaunchFormDialog
id={id as ResourceIdentifier}
initialParameters={initialParameters}
showLaunchForm={showLaunchForm}
setShowLaunchForm={setShowLaunchForm}
/>
</>
);
const onResumeClick = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
setShowResumeForm(true);
};

return (
<div>
{phase === NodeExecutionPhase.PAUSED && (
<Tooltip title={t('resumeTooltip')}>
<IconButton onClick={resumeAction}>
<IconButton onClick={onResumeClick}>
<PlayCircleOutlineIcon />
</IconButton>
</Tooltip>
Expand All @@ -122,7 +105,30 @@ export const NodeExecutionActions = ({ execution }: NodeExecutionActionsProps):
<InputsAndOutputsIcon />
</IconButton>
</Tooltip>
{renderRerunAction()}
{id && initialParameters ? (
<>
<Tooltip title={t('rerunTooltip')}>
<IconButton onClick={rerunIconOnClick}>
<RerunIcon />
</IconButton>
</Tooltip>
<LaunchFormDialog
id={id as ResourceIdentifier}
initialParameters={initialParameters}
showLaunchForm={showLaunchForm}
setShowLaunchForm={setShowLaunchForm}
/>
</>
) : null}
{compiledNode && (
<LaunchFormDialog
compiledNode={compiledNode}
initialParameters={initialParameters}
nodeId={execution.id.nodeId}
showLaunchForm={showResumeForm}
setShowLaunchForm={setShowResumeForm}
/>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { render, waitFor } from '@testing-library/react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { NodeExecutionDetailsContextProvider } from 'components/Executions/contextProvider/NodeExecutionDetails';
import { mockWorkflowId } from 'mocks/data/fixtures/types';
import { QueryClient, QueryClientProvider } from 'react-query';
Expand All @@ -11,6 +11,10 @@ import { NodeExecution } from 'models/Execution/types';
import { NodeExecutionActions } from '../NodeExecutionActions';

jest.mock('components/Workflow/workflowQueries');
jest.mock('components/Launch/LaunchForm/ResumeForm', () => ({
ResumeForm: jest.fn(({ children }) => <div data-testid="resume-form">{children}</div>),
}));

const { fetchWorkflow } = require('components/Workflow/workflowQueries');

const state = { selectedExecution: null, setSelectedExeccution: jest.fn() };
Expand Down Expand Up @@ -55,4 +59,20 @@ describe('Executions > Tables > NodeExecutionActions', () => {
expect(queryByTitle('Rerun')).toBeInTheDocument();
expect(queryByTitle('Resume')).toBeInTheDocument();
});

it('should render ResumeForm on resume button click', async () => {
const mockExecution = { ...execution, closure: { phase: 100 } };
const { queryByTitle, getByTitle, queryByTestId } = renderComponent({
execution: mockExecution,
state,
});
await waitFor(() => queryByTitle('Resume'));

expect(queryByTitle('Resume')).toBeInTheDocument();

const resumeButton = getByTitle('Resume');
await fireEvent.click(resumeButton);

expect(queryByTestId('resume-form')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ const getNodeDetails = (node: dNode, tasks: CompiledTask[]): NodeExecutionInfo =
};
}

if (node.value.gateNode) {
const templateName = node.name;
const task = tasks.find((t) => t.template.id.name === templateName);
const taskType = getTaskDisplayType(task?.template.type);
return {
scopedId: node.scopedId,
displayId: node.value.id ?? node.id,
displayName: 'gateNode',
displayType: taskType,
taskTemplate: task?.template,
};
}

return UNKNOWN_DETAILS;
};

Expand Down
1 change: 1 addition & 0 deletions packages/zapp/console/src/components/Executions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum NodeExecutionDisplayType {
MapTask = 'Map Task',
BatchHiveTask = 'Hive Batch Task',
BranchNode = 'Branch Node',
GateNode = 'Gate Node',
DynamicTask = 'Dynamic Task',
HiveTask = 'Hive Task',
PythonTask = 'Python Task',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { makeStyles, Theme } from '@material-ui/core/styles';
import { BlobDimensionality } from 'models/Common/types';
import * as React from 'react';
import { blobFormatHelperText, blobUriHelperText } from './constants';
import t from './strings';
import { InputProps } from './types';
import { getLaunchInputId, isBlobValue } from './utils';

Expand Down Expand Up @@ -84,7 +84,7 @@ export const BlobInput: React.FC<InputProps> = (props) => {
<div className={styles.inputContainer}>
<TextField
id={getLaunchInputId(`${name}-uri`)}
helperText={blobUriHelperText}
helperText={t('blobUriHelperText')}
fullWidth={true}
label="uri"
onChange={handleUriChange}
Expand All @@ -95,7 +95,7 @@ export const BlobInput: React.FC<InputProps> = (props) => {
<TextField
className={styles.formatInput}
id={getLaunchInputId(`${name}-format`)}
helperText={blobFormatHelperText}
helperText={t('blobFormatHelperText')}
label="format"
onChange={handleFormatChange}
value={blobValue.format}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Button, DialogActions, FormHelperText } from '@material-ui/core';
import { ButtonCircularProgress } from 'components/common/ButtonCircularProgress';
import * as React from 'react';
import { useEffect } from 'react';
import { history } from 'routes/history';
import { Routes } from 'routes/routes';
import { formStrings } from './constants';
import t from './strings';
import { LaunchState } from './launchMachine';
import { useStyles } from './styles';
import { BaseInterpretedLaunchState, BaseLaunchService } from './types';
Expand All @@ -13,13 +14,15 @@ export interface LaunchFormActionsProps {
service: BaseLaunchService;
onClose(): void;
isError: boolean;
submitTitle: string;
}
/** Renders the Submit/Cancel buttons for a LaunchForm */
export const LaunchFormActions: React.FC<LaunchFormActionsProps> = ({
state,
service,
onClose,
isError,
submitTitle,
}) => {
const styles = useStyles();
const submissionInFlight = state.matches(LaunchState.SUBMITTING);
Expand All @@ -40,7 +43,7 @@ export const LaunchFormActions: React.FC<LaunchFormActionsProps> = ({
onClose();
};

React.useEffect(() => {
useEffect(() => {
const subscription = service.subscribe((newState) => {
// On transition to final success state, read the resulting execution
// id and navigate to the Execution Details page.
Expand All @@ -66,7 +69,7 @@ export const LaunchFormActions: React.FC<LaunchFormActionsProps> = ({
onClick={onCancel}
variant="outlined"
>
{formStrings.cancel}
{t('cancel')}
</Button>
<Button
color="primary"
Expand All @@ -76,7 +79,7 @@ export const LaunchFormActions: React.FC<LaunchFormActionsProps> = ({
type="submit"
variant="contained"
>
{formStrings.submit}
{submitTitle}
{submissionInFlight && <ButtonCircularProgress />}
</Button>
</DialogActions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import {
TaskInitialLaunchParameters,
WorkflowInitialLaunchParameters,
} from 'components/Launch/LaunchForm/types';
import { CompiledNode } from 'models/Node/types';
import { ResumeForm } from './ResumeForm';

interface LaunchFormDialogProps {
id: ResourceIdentifier;
initialParameters: TaskInitialLaunchParameters | WorkflowInitialLaunchParameters;
id?: ResourceIdentifier;
initialParameters?: TaskInitialLaunchParameters | WorkflowInitialLaunchParameters;
showLaunchForm: boolean;
setShowLaunchForm: React.Dispatch<React.SetStateAction<boolean>>;
compiledNode?: CompiledNode;
nodeId?: string;
}

function getLaunchProps(id: ResourceIdentifier) {
Expand All @@ -23,9 +27,14 @@ function getLaunchProps(id: ResourceIdentifier) {
throw new Error('Unknown Resource Type');
}

export const LaunchFormDialog = (props: LaunchFormDialogProps): JSX.Element => {
const { id, initialParameters, showLaunchForm, setShowLaunchForm } = props;

export const LaunchFormDialog = ({
id,
initialParameters,
showLaunchForm,
setShowLaunchForm,
compiledNode,
nodeId,
}: LaunchFormDialogProps): JSX.Element => {
const onCancelLaunch = () => setShowLaunchForm(false);

// prevent child onclick event in the dialog triggers parent onclick event
Expand All @@ -41,11 +50,20 @@ export const LaunchFormDialog = (props: LaunchFormDialogProps): JSX.Element => {
open={showLaunchForm}
onClick={dialogOnClick}
>
<LaunchForm
initialParameters={initialParameters}
onClose={onCancelLaunch}
{...getLaunchProps(id)}
/>
{id ? (
<LaunchForm
initialParameters={initialParameters}
onClose={onCancelLaunch}
{...getLaunchProps(id)}
/>
) : compiledNode && nodeId ? (
<ResumeForm
initialParameters={initialParameters}
nodeId={nodeId}
onClose={onCancelLaunch}
compiledNode={compiledNode}
/>
) : null}
</Dialog>
);
};
Loading

0 comments on commit be9f643

Please sign in to comment.