Skip to content

Commit

Permalink
feat: timeline view (flyteorg#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
govalt authored Feb 15, 2022
1 parent ba2c525 commit f499895
Show file tree
Hide file tree
Showing 25 changed files with 1,699 additions and 886 deletions.
4 changes: 3 additions & 1 deletion .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
singleQuote: true
tabWidth: 4
max-line-length: 120
printWidth: 120
overrides:
- files: "*.json"
- files: ["*.js*", "*.ts*", "*.json"]
options:
tabWidth: 2
- files: ["*.yml", "*.yaml"]
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
"babel-polyfill": "^6.26.0",
"cache": "^2.1.0",
"chalk": "^2.0.1",
"chart.js": "^3.6.2",
"chartjs-plugin-datalabels": "^2.0.0",
"cheerio": "^1.0.0-rc.2",
"cookie-parser": "^1.4.3",
"dagre-d3": "^0.6.4",
Expand All @@ -57,6 +59,7 @@
"lodash": "^4.17.19",
"memory-fs": "^0.4.1",
"morgan": "^1.8.2",
"react-chartjs-2": "^4.0.0",
"react-flow-renderer": "^9.6.3",
"react-ga4": "^1.4.1",
"react-helmet": "^5.1.3",
Expand Down
22 changes: 12 additions & 10 deletions src/basics/FeatureFlags/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
*/

export enum FeatureFlag {
// Test flag is created only for unit-tests
TestFlagUndefined = 'test-flag-undefined',
TestFlagTrue = 'test-flag-true',
// Test flag is created only for unit-tests
TestFlagUndefined = 'test-flag-undefined',
TestFlagTrue = 'test-flag-true',

// Production flags
LaunchPlan = 'launch-plan'
// Production flags
LaunchPlan = 'launch-plan',
TimelineView = 'timeline-view'
}

export type FeatureFlagConfig = { [k: string]: boolean };

export const defaultFlagConfig: FeatureFlagConfig = {
// Test
'test-flag-true': true,
// Test
'test-flag-true': true,

// Production - new code should be turned off by default
// If you need to turn it on locally -> update runtimeConfig in ./index.tsx file
'launch-plan': false
// Production - new code should be turned off by default
// If you need to turn it on locally -> update runtimeConfig in ./index.tsx file
'launch-plan': false,
'timeline-view': false
};
163 changes: 79 additions & 84 deletions src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from 'react';
import { Tab, Tabs } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import { noop } from 'lodash';

import { FeatureFlag, useFeatureFlag } from 'basics/FeatureFlags';
import { WaitForQuery } from 'components/common/WaitForQuery';
import { DataError } from 'components/Errors/DataError';
import { useTabState } from 'components/hooks/useTabState';
Expand All @@ -15,104 +17,97 @@ import { NodeExecutionsTable } from '../Tables/NodeExecutionsTable';
import { tabs } from './constants';
import { ExecutionChildrenLoader } from './ExecutionChildrenLoader';
import { useExecutionNodeViewsState } from './useExecutionNodeViewsState';
import { ExecutionNodesTimeline } from './Timeline';

const useStyles = makeStyles((theme: Theme) => ({
filters: {
paddingLeft: theme.spacing(3)
},
nodesContainer: {
borderTop: `1px solid ${theme.palette.divider}`,
display: 'flex',
flex: '1 1 100%',
flexDirection: 'column',
minHeight: 0
},
tabs: {
background: secondaryBackgroundColor,
paddingLeft: theme.spacing(3.5)
}
filters: {
paddingLeft: theme.spacing(3)
},
nodesContainer: {
borderTop: `1px solid ${theme.palette.divider}`,
display: 'flex',
flex: '1 1 100%',
flexDirection: 'column',
minHeight: 0
},
tabs: {
background: secondaryBackgroundColor,
paddingLeft: theme.spacing(3.5)
}
}));

export interface ExecutionNodeViewsProps {
execution: Execution;
execution: Execution;
}

/** Contains the available ways to visualize the nodes of a WorkflowExecution */
export const ExecutionNodeViews: React.FC<ExecutionNodeViewsProps> = ({
execution
}) => {
const styles = useStyles();
const filterState = useNodeExecutionFiltersState();
const tabState = useTabState(tabs, tabs.nodes.id);
export const ExecutionNodeViews: React.FC<ExecutionNodeViewsProps> = ({ execution }) => {
const defaultTab = tabs.nodes.id;
const styles = useStyles();
const filterState = useNodeExecutionFiltersState();
const tabState = useTabState(tabs, defaultTab);
const isTimelineEnabled = useFeatureFlag(FeatureFlag.TimelineView);

const {
closure: { abortMetadata }
} = execution;
const {
closure: { abortMetadata }
} = execution;

/* We want to maintain the filter selection when switching away from the Nodes
if (!isTimelineEnabled && tabState.value === tabs.timeline.id) {
tabState.onChange(noop, defaultTab);
}

/* We want to maintain the filter selection when switching away from the Nodes
tab and back, but do not want to filter the nodes when viewing the graph. So,
we will only pass filters to the execution state when on the nodes tab. */
const appliedFilters =
tabState.value === tabs.nodes.id ? filterState.appliedFilters : [];
const appliedFilters = tabState.value === tabs.nodes.id ? filterState.appliedFilters : [];

const { nodeExecutionsQuery, nodeExecutionsRequestConfig } = useExecutionNodeViewsState(execution, appliedFilters);

const {
nodeExecutionsQuery,
nodeExecutionsRequestConfig
} = useExecutionNodeViewsState(execution, appliedFilters);
const renderNodeExecutionsTable = (nodeExecutions: NodeExecution[]) => (
<NodeExecutionsRequestConfigContext.Provider value={nodeExecutionsRequestConfig}>
<NodeExecutionsTable abortMetadata={abortMetadata ?? undefined} nodeExecutions={nodeExecutions} />
</NodeExecutionsRequestConfigContext.Provider>
);

const renderNodeExecutionsTable = (nodeExecutions: NodeExecution[]) => (
<NodeExecutionsRequestConfigContext.Provider
value={nodeExecutionsRequestConfig}
>
<NodeExecutionsTable
abortMetadata={abortMetadata ?? undefined}
nodeExecutions={nodeExecutions}
/>
</NodeExecutionsRequestConfigContext.Provider>
);
const renderExecutionLoader = (nodeExecutions: NodeExecution[]) => {
return <ExecutionChildrenLoader nodeExecutions={nodeExecutions} workflowId={execution.closure.workflowId} />;
};

const renderExecutionLoader = (nodeExecutions: NodeExecution[]) => {
return (
<ExecutionChildrenLoader
nodeExecutions={nodeExecutions}
workflowId={execution.closure.workflowId}
/>
);
};
const renderExecutionsTimeline = (nodeExecutions: NodeExecution[]) => (
<ExecutionNodesTimeline nodeExecutions={nodeExecutions} />
);

return (
<>
<Tabs className={styles.tabs} {...tabState}>
<Tab value={tabs.nodes.id} label={tabs.nodes.label} />
<Tab value={tabs.graph.id} label={tabs.graph.label} />
</Tabs>
<NodeExecutionDetailsContextProvider
workflowId={execution.closure.workflowId}
>
<div className={styles.nodesContainer}>
{tabState.value === tabs.nodes.id && (
<>
<div className={styles.filters}>
<ExecutionFilters {...filterState} />
</div>
<WaitForQuery
errorComponent={DataError}
query={nodeExecutionsQuery}
>
{renderNodeExecutionsTable}
</WaitForQuery>
</>
)}
{tabState.value === tabs.graph.id && (
<WaitForQuery
errorComponent={DataError}
query={nodeExecutionsQuery}
>
{renderExecutionLoader}
</WaitForQuery>
)}
</div>
</NodeExecutionDetailsContextProvider>
</>
);
return (
<>
<Tabs className={styles.tabs} {...tabState}>
<Tab value={tabs.nodes.id} label={tabs.nodes.label} />
<Tab value={tabs.graph.id} label={tabs.graph.label} />
{isTimelineEnabled && <Tab value={tabs.timeline.id} label={tabs.timeline.label} />}
</Tabs>
<NodeExecutionDetailsContextProvider workflowId={execution.closure.workflowId}>
<div className={styles.nodesContainer}>
{tabState.value === tabs.nodes.id && (
<>
<div className={styles.filters}>
<ExecutionFilters {...filterState} />
</div>
<WaitForQuery errorComponent={DataError} query={nodeExecutionsQuery}>
{renderNodeExecutionsTable}
</WaitForQuery>
</>
)}
{tabState.value === tabs.graph.id && (
<WaitForQuery errorComponent={DataError} query={nodeExecutionsQuery}>
{renderExecutionLoader}
</WaitForQuery>
)}
{isTimelineEnabled && tabState.value === tabs.timeline.id && (
<WaitForQuery errorComponent={DataError} query={nodeExecutionsQuery}>
{renderExecutionsTimeline}
</WaitForQuery>
)}
</div>
</NodeExecutionDetailsContextProvider>
</>
);
};
Loading

0 comments on commit f499895

Please sign in to comment.