Skip to content

Commit 27238ce

Browse files
authored
fix: force node executions to pull their status (#737)
* fix: force node executions to pull their status Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: nodes not loading fix Signed-off-by: Carina Ursu <[email protected]> * chore: fix Signed-off-by: Carina Ursu <[email protected]> * chore: fixes Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: some refactoring Signed-off-by: Carina Ursu <[email protected]> * chore: cleanup Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: progress Signed-off-by: Carina Ursu <[email protected]> * chore: fixes Signed-off-by: Carina Ursu <[email protected]> * chore: fix map tasks Signed-off-by: Carina Ursu <[email protected]> * chore: dynamic execution fixes Signed-off-by: Carina Ursu <[email protected]> * chore: fixes Signed-off-by: Carina Ursu <[email protected]> * chore: cleanup Signed-off-by: Carina Ursu <[email protected]> * chore: append task executions Signed-off-by: Carina Ursu <[email protected]> * chore: fix ExecutionTabContent.test.tsx Signed-off-by: Carina Ursu <[email protected]> * chore: fix WorkflowGraph.test.tsx Signed-off-by: Carina Ursu <[email protected]> * chore: test fixes Signed-off-by: Carina Ursu <[email protected]> * chore: more tests Signed-off-by: Carina Ursu <[email protected]> * chore: test fixes Signed-off-by: Carina Ursu <[email protected]> * chore: more tests Signed-off-by: Carina Ursu <[email protected]> * chore: bump version Signed-off-by: Carina Ursu <[email protected]> --------- Signed-off-by: Carina Ursu <[email protected]>
1 parent 33ee52a commit 27238ce

File tree

95 files changed

+3110
-1908
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+3110
-1908
lines changed

packages/console/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@flyteorg/console",
3-
"version": "0.0.20",
3+
"version": "0.0.21",
44
"description": "Flyteconsole main app module",
55
"main": "./dist/index.js",
66
"module": "./lib/index.js",

packages/console/src/components/Executions/CacheStatus.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,15 @@ export interface CacheStatusProps {
8282
variant?: 'normal' | 'iconOnly';
8383
sourceTaskExecutionId?: TaskExecutionIdentifier;
8484
iconStyles?: React.CSSProperties;
85+
className?: string;
8586
}
8687

8788
export const CacheStatus: React.FC<CacheStatusProps> = ({
8889
cacheStatus,
8990
sourceTaskExecutionId,
9091
variant = 'normal',
9192
iconStyles,
93+
className,
9294
}) => {
9395
const commonStyles = useCommonStyles();
9496
const styles = useStyles();
@@ -100,11 +102,12 @@ export const CacheStatus: React.FC<CacheStatusProps> = ({
100102
const message = cacheStatusMessages[cacheStatus] || unknownCacheStatusString;
101103

102104
return variant === 'iconOnly' ? (
103-
<Tooltip title={message}>
105+
<Tooltip title={message} className={className}>
104106
<NodeExecutionCacheStatusIcon
105107
className={classnames(
106108
commonStyles.iconRight,
107109
commonStyles.iconSecondary,
110+
className,
108111
)}
109112
style={iconStyles}
110113
status={cacheStatus}
@@ -113,7 +116,7 @@ export const CacheStatus: React.FC<CacheStatusProps> = ({
113116
) : (
114117
<>
115118
<Typography
116-
className={styles.cacheStatus}
119+
className={classnames(styles.cacheStatus, className)}
117120
variant="subtitle1"
118121
color="textSecondary"
119122
>
@@ -122,6 +125,7 @@ export const CacheStatus: React.FC<CacheStatusProps> = ({
122125
className={classnames(
123126
commonStyles.iconSecondary,
124127
commonStyles.iconLeft,
128+
className,
125129
)}
126130
/>
127131
{message}
@@ -131,6 +135,7 @@ export const CacheStatus: React.FC<CacheStatusProps> = ({
131135
className={classnames(
132136
commonStyles.primaryLink,
133137
styles.sourceExecutionLink,
138+
className,
134139
)}
135140
to={Routes.ExecutionDetails.makeUrl(
136141
sourceTaskExecutionId.nodeExecutionId.executionId,

packages/console/src/components/Executions/ExecutionDetails/DetailsPanelContext.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import React, {
2+
PropsWithChildren,
3+
useContext,
4+
useEffect,
5+
createContext,
6+
useState,
7+
} from 'react';
8+
import { NodeExecutionIdentifier } from 'models/Execution/types';
9+
import { DetailsPanel } from 'components/common/DetailsPanel';
10+
import { TaskExecutionPhase } from 'models';
11+
import { Core } from '@flyteorg/flyteidl-types';
12+
import { isStartOrEndNode } from 'models/Node/utils';
13+
import { NodeExecutionDetailsPanelContent } from './NodeExecutionDetailsPanelContent';
14+
import { useNodeExecutionsById } from '../contextProvider/NodeExecutionDetails';
15+
16+
export interface DetailsPanelContextData {
17+
selectedExecution?: NodeExecutionIdentifier | null;
18+
setSelectedExecution: (
19+
selectedExecutionId: NodeExecutionIdentifier | null,
20+
) => void;
21+
onNodeSelectionChanged: (newSelection: string[]) => void;
22+
selectedPhase: Core.TaskExecution.Phase | undefined;
23+
setSelectedPhase: (
24+
value: React.SetStateAction<Core.TaskExecution.Phase | undefined>,
25+
) => void;
26+
isDetailsTabClosed: boolean;
27+
setIsDetailsTabClosed: (boolean) => void;
28+
}
29+
30+
export const DetailsPanelContext = createContext<DetailsPanelContextData>(
31+
{} as DetailsPanelContextData,
32+
);
33+
34+
export interface DetailsPanelContextProviderProps {
35+
selectedPhase?: TaskExecutionPhase;
36+
}
37+
export const DetailsPanelContextProvider = ({
38+
children,
39+
}: PropsWithChildren<DetailsPanelContextProviderProps>) => {
40+
const [selectedNodes, setSelectedNodes] = useState<string[]>([]);
41+
const { nodeExecutionsById } = useNodeExecutionsById();
42+
43+
const [selectedPhase, setSelectedPhase] = useState<
44+
TaskExecutionPhase | undefined
45+
>(undefined);
46+
47+
// Note: flytegraph allows multiple selection, but we only support showing
48+
// a single item in the details panel
49+
const [selectedExecution, setSelectedExecution] =
50+
useState<NodeExecutionIdentifier | null>(
51+
selectedNodes.length
52+
? nodeExecutionsById[selectedNodes[0]]
53+
? nodeExecutionsById[selectedNodes[0]].id
54+
: {
55+
nodeId: selectedNodes[0],
56+
executionId:
57+
nodeExecutionsById[Object.keys(nodeExecutionsById)[0]].id
58+
.executionId,
59+
}
60+
: null,
61+
);
62+
63+
const [isDetailsTabClosed, setIsDetailsTabClosed] = useState<boolean>(
64+
!selectedExecution,
65+
);
66+
67+
useEffect(() => {
68+
setIsDetailsTabClosed(!selectedExecution);
69+
}, [selectedExecution]);
70+
71+
const onNodeSelectionChanged = (newSelection: string[]) => {
72+
const validSelection = newSelection.filter(nodeId => {
73+
if (isStartOrEndNode(nodeId)) {
74+
return false;
75+
}
76+
return true;
77+
});
78+
setSelectedNodes(validSelection);
79+
const newSelectedExecution = validSelection.length
80+
? nodeExecutionsById[validSelection[0]]
81+
? nodeExecutionsById[validSelection[0]].id
82+
: {
83+
nodeId: validSelection[0],
84+
executionId:
85+
nodeExecutionsById[Object.keys(nodeExecutionsById)[0]].id
86+
.executionId,
87+
}
88+
: null;
89+
setSelectedExecution(newSelectedExecution);
90+
};
91+
92+
const onCloseDetailsPanel = () => {
93+
setSelectedExecution(null);
94+
setSelectedPhase(undefined);
95+
setSelectedNodes([]);
96+
};
97+
98+
return (
99+
<DetailsPanelContext.Provider
100+
value={{
101+
selectedExecution,
102+
setSelectedExecution,
103+
onNodeSelectionChanged,
104+
selectedPhase,
105+
setSelectedPhase,
106+
isDetailsTabClosed,
107+
setIsDetailsTabClosed,
108+
}}
109+
>
110+
{children}
111+
<DetailsPanel open={!isDetailsTabClosed} onClose={onCloseDetailsPanel}>
112+
{!isDetailsTabClosed && selectedExecution && (
113+
<NodeExecutionDetailsPanelContent
114+
onClose={onCloseDetailsPanel}
115+
taskPhase={selectedPhase ?? TaskExecutionPhase.UNDEFINED}
116+
nodeExecutionId={selectedExecution}
117+
/>
118+
)}
119+
</DetailsPanel>
120+
</DetailsPanelContext.Provider>
121+
);
122+
};
123+
124+
export const useDetailsPanel = () => {
125+
return useContext(DetailsPanelContext);
126+
};
Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as React from 'react';
2+
import { useContext } from 'react';
13
import { Collapse, IconButton } from '@material-ui/core';
24
import { makeStyles, Theme } from '@material-ui/core/styles';
35
import ExpandMore from '@material-ui/icons/ExpandMore';
@@ -7,13 +9,16 @@ import { WaitForQuery } from 'components/common/WaitForQuery';
79
import { withRouteParams } from 'components/common/withRouteParams';
810
import { DataError } from 'components/Errors/DataError';
911
import { Execution } from 'models/Execution/types';
10-
import * as React from 'react';
1112
import { RouteComponentProps } from 'react-router-dom';
13+
import { useQuery, useQueryClient } from 'react-query';
14+
import { Workflow } from 'models/Workflow/types';
15+
import { makeWorkflowQuery } from 'components/Workflow/workflowQueries';
1216
import { ExecutionContext } from '../contexts';
1317
import { useWorkflowExecutionQuery } from '../useWorkflowExecution';
1418
import { ExecutionDetailsAppBarContent } from './ExecutionDetailsAppBarContent';
1519
import { ExecutionMetadata } from './ExecutionMetadata';
1620
import { ExecutionNodeViews } from './ExecutionNodeViews';
21+
import { NodeExecutionDetailsContextProvider } from '../contextProvider/NodeExecutionDetails';
1722

1823
const useStyles = makeStyles((theme: Theme) => ({
1924
expandCollapseButton: {
@@ -38,51 +43,60 @@ const useStyles = makeStyles((theme: Theme) => ({
3843
},
3944
}));
4045

41-
export interface ExecutionDetailsRouteParams {
42-
domainId: string;
43-
executionId: string;
44-
projectId: string;
45-
}
46-
export type ExecutionDetailsProps = ExecutionDetailsRouteParams;
47-
48-
interface RenderExecutionDetailsProps {
49-
execution: Execution;
50-
}
51-
52-
const RenderExecutionDetails: React.FC<RenderExecutionDetailsProps> = ({
53-
execution,
54-
}) => {
46+
const RenderExecutionContainer: React.FC<{}> = () => {
5547
const styles = useStyles();
5648
const [metadataExpanded, setMetadataExpanded] = React.useState(true);
5749
const toggleMetadata = () => setMetadataExpanded(!metadataExpanded);
58-
const contextValue = {
59-
execution,
60-
};
6150

51+
const { execution } = useContext(ExecutionContext);
52+
53+
const {
54+
closure: { workflowId },
55+
} = execution;
56+
57+
const workflowQuery = useQuery<Workflow, Error>(
58+
makeWorkflowQuery(useQueryClient(), workflowId),
59+
);
6260
return (
63-
<ExecutionContext.Provider value={contextValue}>
64-
<ExecutionDetailsAppBarContent execution={execution} />
65-
<div className={styles.metadataContainer}>
66-
<Collapse in={metadataExpanded}>
67-
<ExecutionMetadata execution={execution} />
68-
</Collapse>
69-
<div className={styles.expandCollapseContainer}>
70-
<IconButton size="small" onClick={toggleMetadata}>
71-
<ExpandMore
72-
className={classnames(styles.expandCollapseButton, {
73-
expanded: metadataExpanded,
74-
})}
75-
/>
76-
</IconButton>
77-
</div>
78-
</div>
79-
<ExecutionNodeViews execution={execution} />
80-
</ExecutionContext.Provider>
61+
<>
62+
{/* Fetches the current workflow to build the execution tree inside NodeExecutionDetailsContextProvider */}
63+
<WaitForQuery errorComponent={DataError} query={workflowQuery}>
64+
{workflow => (
65+
<>
66+
{/* Provides a node execution tree for the current workflow */}
67+
<NodeExecutionDetailsContextProvider workflowId={workflow.id}>
68+
<ExecutionDetailsAppBarContent />
69+
<div className={styles.metadataContainer}>
70+
<Collapse in={metadataExpanded}>
71+
<ExecutionMetadata />
72+
</Collapse>
73+
<div className={styles.expandCollapseContainer}>
74+
<IconButton size="small" onClick={toggleMetadata}>
75+
<ExpandMore
76+
className={classnames(styles.expandCollapseButton, {
77+
expanded: metadataExpanded,
78+
})}
79+
/>
80+
</IconButton>
81+
</div>
82+
</div>
83+
84+
<ExecutionNodeViews />
85+
</NodeExecutionDetailsContextProvider>
86+
</>
87+
)}
88+
</WaitForQuery>
89+
</>
8190
);
8291
};
8392

93+
export interface ExecutionDetailsRouteParams {
94+
domainId: string;
95+
executionId: string;
96+
projectId: string;
97+
}
8498
/** The view component for the Execution Details page */
85-
export const ExecutionDetailsContainer: React.FC<ExecutionDetailsProps> = ({
99+
export const ExecutionDetailsWrapper: React.FC<ExecutionDetailsRouteParams> = ({
86100
executionId,
87101
domainId,
88102
projectId,
@@ -93,21 +107,28 @@ export const ExecutionDetailsContainer: React.FC<ExecutionDetailsProps> = ({
93107
name: executionId,
94108
};
95109

96-
const renderExecutionDetails = (execution: Execution) => (
97-
<RenderExecutionDetails execution={execution} />
98-
);
110+
const workflowExecutionQuery = useWorkflowExecutionQuery(id);
99111

100112
return (
113+
// get the workflow execution query to get the current workflow id
101114
<WaitForQuery
102115
errorComponent={DataError}
103116
loadingComponent={LargeLoadingSpinner}
104-
query={useWorkflowExecutionQuery(id)}
117+
query={workflowExecutionQuery}
105118
>
106-
{renderExecutionDetails}
119+
{(execution: Execution) => (
120+
<ExecutionContext.Provider
121+
value={{
122+
execution,
123+
}}
124+
>
125+
<RenderExecutionContainer />
126+
</ExecutionContext.Provider>
127+
)}
107128
</WaitForQuery>
108129
);
109130
};
110131

111132
export const ExecutionDetails: React.FunctionComponent<
112133
RouteComponentProps<ExecutionDetailsRouteParams>
113-
> = withRouteParams<ExecutionDetailsRouteParams>(ExecutionDetailsContainer);
134+
> = withRouteParams<ExecutionDetailsRouteParams>(ExecutionDetailsWrapper);

0 commit comments

Comments
 (0)