From e6536247724c140f8d1cb140cd8e90a94383700e Mon Sep 17 00:00:00 2001 From: Olga Nad Date: Mon, 15 Aug 2022 09:24:16 -0500 Subject: [PATCH 1/3] fix: update timeline view to show dynamic wf internals on first render Signed-off-by: Olga Nad --- .../ExecutionChildrenLoader.tsx | 33 --- .../ExecutionDetails/ExecutionNodeViews.tsx | 177 +++++++++--- .../ExecutionWorkflowGraph.tsx | 79 +----- .../TaskExecutionNode.tsx | 7 +- .../Timeline/ExecutionTimeline.tsx | 46 +-- .../ExecutionDetails/Timeline/index.tsx | 48 +--- .../src/components/Executions/contexts.ts | 3 +- .../Executions/nodeExecutionQueries.ts | 118 ++++---- .../WorkflowGraph/WorkflowGraph.tsx | 37 +-- .../console/src/components/common/utils.ts | 31 ++ .../ReactFlow/ReactFlowGraphComponent.tsx | 5 +- .../console/src/models/Execution/types.ts | 1 + yarn.lock | 268 +++++++++++++++++- 13 files changed, 549 insertions(+), 304 deletions(-) delete mode 100644 packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionChildrenLoader.tsx diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionChildrenLoader.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionChildrenLoader.tsx deleted file mode 100644 index 9da436efe..000000000 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionChildrenLoader.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { WaitForQuery } from 'components/common/WaitForQuery'; -import { DataError } from 'components/Errors/DataError'; -import * as React from 'react'; -import { NodeExecution } from 'models/Execution/types'; -import { useAllChildNodeExecutionGroupsQuery } from '../nodeExecutionQueries'; -import { NodeExecutionsRequestConfigContext } from '../contexts'; -import { ExecutionWorkflowGraph } from './ExecutionWorkflowGraph'; - -export const ExecutionChildrenLoader = ({ nodeExecutions, workflowId }) => { - const requestConfig = React.useContext(NodeExecutionsRequestConfigContext); - const childGroupsQuery = useAllChildNodeExecutionGroupsQuery(nodeExecutions, requestConfig); - - const renderGraphComponent = (childGroups) => { - const output: any[] = []; - for (let i = 0; i < childGroups.length; i++) { - for (let j = 0; j < childGroups[i].length; j++) { - for (let k = 0; k < childGroups[i][j].nodeExecutions.length; k++) { - output.push(childGroups[i][j].nodeExecutions[k] as NodeExecution); - } - } - } - const executions: NodeExecution[] = output.concat(nodeExecutions); - return nodeExecutions.length > 0 ? ( - - ) : null; - }; - - return ( - - {renderGraphComponent} - - ); -}; diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx index 2a8afdd49..8b4099257 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx @@ -5,16 +5,24 @@ import { WaitForQuery } from 'components/common/WaitForQuery'; import { DataError } from 'components/Errors/DataError'; import { useTabState } from 'components/hooks/useTabState'; import { secondaryBackgroundColor } from 'components/Theme/constants'; -import { Execution, NodeExecution } from 'models/Execution/types'; +import { Execution, ExternalResource, LogsByPhase, NodeExecution } from 'models/Execution/types'; +import { useContext, useEffect, useMemo, useState } from 'react'; +import { keyBy } from 'lodash'; +import { isMapTaskV1 } from 'models/Task/utils'; +import { useQueryClient } from 'react-query'; +import { LargeLoadingSpinner } from 'components/common/LoadingSpinner'; import { NodeExecutionDetailsContextProvider } from '../contextProvider/NodeExecutionDetails'; -import { NodeExecutionsRequestConfigContext } from '../contexts'; +import { NodeExecutionsByIdContext, NodeExecutionsRequestConfigContext } from '../contexts'; import { ExecutionFilters } from '../ExecutionFilters'; import { useNodeExecutionFiltersState } from '../filters/useExecutionFiltersState'; import { NodeExecutionsTable } from '../Tables/NodeExecutionsTable'; import { tabs } from './constants'; -import { ExecutionChildrenLoader } from './ExecutionChildrenLoader'; import { useExecutionNodeViewsState } from './useExecutionNodeViewsState'; import { ExecutionNodesTimeline } from './Timeline'; +import { fetchTaskExecutionList } from '../taskExecutionQueries'; +import { getGroupedLogs } from '../TaskExecutionsList/utils'; +import { useAllChildNodeExecutionGroupsQuery } from '../nodeExecutionQueries'; +import { ExecutionWorkflowGraph } from './ExecutionWorkflowGraph'; const useStyles = makeStyles((theme: Theme) => ({ filters: { @@ -31,8 +39,15 @@ const useStyles = makeStyles((theme: Theme) => ({ background: secondaryBackgroundColor, paddingLeft: theme.spacing(3.5), }, + loading: { + margin: 'auto', + }, })); +interface WorkflowNodeExecution extends NodeExecution { + logsByPhase?: LogsByPhase; +} + export interface ExecutionNodeViewsProps { execution: Execution; } @@ -43,11 +58,22 @@ export const ExecutionNodeViews: React.FC = ({ executio const styles = useStyles(); const filterState = useNodeExecutionFiltersState(); const tabState = useTabState(tabs, defaultTab); + const queryClient = useQueryClient(); + const requestConfig = useContext(NodeExecutionsRequestConfigContext); const { - closure: { abortMetadata }, + closure: { abortMetadata, workflowId }, } = execution; + const [nodeExecutions, setNodeExecutions] = useState([]); + const [nodeExecutionsWithResources, setNodeExecutionsWithResources] = useState< + WorkflowNodeExecution[] + >([]); + + const nodeExecutionsById = useMemo(() => { + return keyBy(nodeExecutionsWithResources, 'scopedId'); + }, [nodeExecutionsWithResources]); + /* 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. */ @@ -58,6 +84,75 @@ export const ExecutionNodeViews: React.FC = ({ executio appliedFilters, ); + useEffect(() => { + let isCurrent = true; + async function fetchData(baseNodeExecutions, queryClient) { + const newValue = await Promise.all( + baseNodeExecutions.map(async (baseNodeExecution) => { + const taskExecutions = await fetchTaskExecutionList(queryClient, baseNodeExecution.id); + + const useNewMapTaskView = taskExecutions.every((taskExecution) => { + const { + closure: { taskType, metadata, eventVersion = 0 }, + } = taskExecution; + return isMapTaskV1( + eventVersion, + metadata?.externalResources?.length ?? 0, + taskType ?? undefined, + ); + }); + const externalResources: ExternalResource[] = taskExecutions + .map((taskExecution) => taskExecution.closure.metadata?.externalResources) + .flat() + .filter((resource): resource is ExternalResource => !!resource); + + const logsByPhase: LogsByPhase = getGroupedLogs(externalResources); + + return { + ...baseNodeExecution, + ...(useNewMapTaskView && logsByPhase.size > 0 && { logsByPhase }), + }; + }), + ); + + if (isCurrent) { + setNodeExecutionsWithResources(newValue); + } + } + + if (nodeExecutions.length > 0) { + fetchData(nodeExecutions, queryClient); + } + return () => { + isCurrent = false; + }; + }, [nodeExecutions]); + + // const childGroupsTreeQuery = useAllTreeNodeExecutionGroupsQuery( + // nodeExecutionsQuery.data ?? [], + // requestConfig, + // ); + + const childGroupsAllQuery = useAllChildNodeExecutionGroupsQuery( + nodeExecutionsQuery.data ?? [], + requestConfig, + ); + + useEffect(() => { + if (!childGroupsAllQuery.isLoading) { + const output: any[] = nodeExecutionsQuery.data ?? []; + const childGroups = childGroupsAllQuery.data ?? []; + for (let i = 0; i < childGroups.length; i++) { + for (let j = 0; j < childGroups[i].length; j++) { + for (let k = 0; k < childGroups[i][j].nodeExecutions.length; k++) { + output.push(childGroups[i][j].nodeExecutions[k] as NodeExecution); + } + } + } + setNodeExecutions(output.concat(nodeExecutions)); + } + }, [childGroupsAllQuery.data]); + const renderNodeExecutionsTable = (nodeExecutions: NodeExecution[]) => ( = ({ executio ); - const renderExecutionLoader = (nodeExecutions: NodeExecution[]) => { + const renderExecutionChildrenLoader = () => + nodeExecutions.length > 0 ? : null; + + const renderExecutionLoader = () => { return ( - + + {renderExecutionChildrenLoader} + ); }; - const renderExecutionsTimeline = (nodeExecutions: NodeExecution[]) => ( - + const renderExecutionsTimeline = () => ( + + {() => } + ); + const TimelineLoading = () => { + return ( +
+ +
+ ); + }; + return ( <> @@ -87,29 +198,31 @@ export const ExecutionNodeViews: React.FC = ({ executio - -
- {tabState.value === tabs.nodes.id && ( - <> -
- -
+ + +
+ {tabState.value === tabs.nodes.id && ( + <> +
+ +
+ + {renderNodeExecutionsTable} + + + )} + {tabState.value === tabs.graph.id && ( + + {renderExecutionLoader} + + )} + {tabState.value === tabs.timeline.id && ( - {renderNodeExecutionsTable} + {renderExecutionsTimeline} - - )} - {tabState.value === tabs.graph.id && ( - - {renderExecutionLoader} - - )} - {tabState.value === tabs.timeline.id && ( - - {renderExecutionsTimeline} - - )} -
+ )} +
+
); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionWorkflowGraph.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionWorkflowGraph.tsx index b0181cdec..72165b735 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionWorkflowGraph.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionWorkflowGraph.tsx @@ -3,46 +3,27 @@ import { WaitForQuery } from 'components/common/WaitForQuery'; import { DataError } from 'components/Errors/DataError'; import { makeWorkflowQuery } from 'components/Workflow/workflowQueries'; import { WorkflowGraph } from 'components/WorkflowGraph/WorkflowGraph'; -import { keyBy } from 'lodash'; import { TaskExecutionPhase } from 'models/Execution/enums'; -import { ExternalResource, LogsByPhase, NodeExecution } from 'models/Execution/types'; import { endNodeId, startNodeId } from 'models/Node/constants'; -import { isMapTaskV1 } from 'models/Task/utils'; import { Workflow, WorkflowId } from 'models/Workflow/types'; import * as React from 'react'; -import { useEffect, useMemo, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { useQuery, useQueryClient } from 'react-query'; -import { NodeExecutionsContext } from '../contexts'; -import { fetchTaskExecutionList } from '../taskExecutionQueries'; -import { getGroupedLogs } from '../TaskExecutionsList/utils'; +import { NodeExecutionsByIdContext } from '../contexts'; import { NodeExecutionDetailsPanelContent } from './NodeExecutionDetailsPanelContent'; export interface ExecutionWorkflowGraphProps { - nodeExecutions: NodeExecution[]; workflowId: WorkflowId; } -interface WorkflowNodeExecution extends NodeExecution { - logsByPhase?: LogsByPhase; -} - /** Wraps a WorkflowGraph, customizing it to also show execution statuses */ -export const ExecutionWorkflowGraph: React.FC = ({ - nodeExecutions, - workflowId, -}) => { +export const ExecutionWorkflowGraph: React.FC = ({ workflowId }) => { const queryClient = useQueryClient(); const workflowQuery = useQuery(makeWorkflowQuery(queryClient, workflowId)); - const [nodeExecutionsWithResources, setNodeExecutionsWithResources] = useState< - WorkflowNodeExecution[] - >([]); const [selectedNodes, setSelectedNodes] = useState([]); + const nodeExecutionsById = useContext(NodeExecutionsByIdContext); - const nodeExecutionsById = useMemo( - () => keyBy(nodeExecutionsWithResources, 'scopedId'), - [nodeExecutionsWithResources], - ); // Note: flytegraph allows multiple selection, but we only support showing // a single item in the details panel const selectedExecution = selectedNodes.length @@ -57,49 +38,6 @@ export const ExecutionWorkflowGraph: React.FC = ({ const [selectedPhase, setSelectedPhase] = useState(undefined); const [isDetailsTabClosed, setIsDetailsTabClosed] = useState(!selectedExecution); - useEffect(() => { - let isCurrent = true; - async function fetchData(nodeExecutions, queryClient) { - const newValue = await Promise.all( - nodeExecutions.map(async (nodeExecution) => { - const taskExecutions = await fetchTaskExecutionList(queryClient, nodeExecution.id); - - const useNewMapTaskView = taskExecutions.every((taskExecution) => { - const { - closure: { taskType, metadata, eventVersion = 0 }, - } = taskExecution; - return isMapTaskV1( - eventVersion, - metadata?.externalResources?.length ?? 0, - taskType ?? undefined, - ); - }); - const externalResources: ExternalResource[] = taskExecutions - .map((taskExecution) => taskExecution.closure.metadata?.externalResources) - .flat() - .filter((resource): resource is ExternalResource => !!resource); - - const logsByPhase: LogsByPhase = getGroupedLogs(externalResources); - - return { - ...nodeExecution, - ...(useNewMapTaskView && logsByPhase.size > 0 && { logsByPhase }), - }; - }), - ); - - if (isCurrent) { - setNodeExecutionsWithResources(newValue); - } - } - - fetchData(nodeExecutions, queryClient); - - return () => { - isCurrent = false; - }; - }, [nodeExecutions]); - useEffect(() => { setIsDetailsTabClosed(!selectedExecution); }, [selectedExecution]); @@ -126,18 +64,15 @@ export const ExecutionWorkflowGraph: React.FC = ({ selectedPhase={selectedPhase} onPhaseSelectionChanged={setSelectedPhase} isDetailsTabClosed={isDetailsTabClosed} - nodeExecutionsById={nodeExecutionsById} workflow={workflow} /> ); return ( <> - - - {renderGraph} - - + + {renderGraph} + {selectedExecution && ( > = (props) => { const { node, config, selected } = props; - const nodeExecutions = React.useContext(NodeExecutionsContext); - const nodeExecution = nodeExecutions[node.id]; + const nodeExecutionsById = useContext(NodeExecutionsByIdContext); + const nodeExecution = nodeExecutionsById[node.id]; const phase = nodeExecution ? nodeExecution.closure.phase : NodeExecutionPhase.UNDEFINED; const { badgeColor: color } = getNodeExecutionPhaseConstants(phase); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx index 677cf7e2a..83234ec61 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx @@ -6,8 +6,12 @@ import { transformerWorkflowToDag } from 'components/WorkflowGraph/transformerWo import { isEndNode, isStartNode, isExpanded } from 'components/WorkflowGraph/utils'; import { tableHeaderColor } from 'components/Theme/constants'; import { timestampToDate } from 'common/utils'; -import { NodeExecution } from 'models/Execution/types'; import { dNode } from 'models/Graph/types'; +import { makeNodeExecutionDynamicWorkflowQuery } from 'components/Workflow/workflowQueries'; +import { useQuery } from 'react-query'; +import { useEffect, useState } from 'react'; +import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; +import { checkForDynamicExeuctions } from 'components/common/utils'; import { convertToPlainNodes } from './helpers'; import { ChartHeader } from './chartHeader'; import { useScaleContext } from './scaleContext'; @@ -67,40 +71,50 @@ const useStyles = makeStyles((theme) => ({ const INTERVAL_LENGTH = 110; interface ExProps { - nodeExecutions: NodeExecution[]; chartTimezone: string; } -export const ExecutionTimeline: React.FC = ({ nodeExecutions, chartTimezone }) => { - const [chartWidth, setChartWidth] = React.useState(0); - const [labelInterval, setLabelInterval] = React.useState(INTERVAL_LENGTH); +export const ExecutionTimeline: React.FC = ({ chartTimezone }) => { + const [chartWidth, setChartWidth] = useState(0); + const [labelInterval, setLabelInterval] = useState(INTERVAL_LENGTH); const durationsRef = React.useRef(null); const durationsLabelsRef = React.useRef(null); const taskNamesRef = React.createRef(); - const [originalNodes, setOriginalNodes] = React.useState([]); - const [showNodes, setShowNodes] = React.useState([]); - const [startedAt, setStartedAt] = React.useState(new Date()); + const [originalNodes, setOriginalNodes] = useState([]); + const [showNodes, setShowNodes] = useState([]); + const [startedAt, setStartedAt] = useState(new Date()); const { compiledWorkflowClosure } = useNodeExecutionContext(); const { chartInterval: chartTimeInterval } = useScaleContext(); + const { staticExecutionIdsMap } = compiledWorkflowClosure + ? transformerWorkflowToDag(compiledWorkflowClosure) + : []; - React.useEffect(() => { + const nodeExecutionsById = React.useContext(NodeExecutionsByIdContext); + + const dynamicParents = checkForDynamicExeuctions(nodeExecutionsById, staticExecutionIdsMap); + + const { data: dynamicWorkflows } = useQuery( + makeNodeExecutionDynamicWorkflowQuery(dynamicParents), + ); + + useEffect(() => { const nodes: dNode[] = compiledWorkflowClosure - ? transformerWorkflowToDag(compiledWorkflowClosure).dag.nodes + ? transformerWorkflowToDag(compiledWorkflowClosure, dynamicWorkflows).dag.nodes : []; // we remove start/end node info in the root dNode list during first assignment const initializeNodes = convertToPlainNodes(nodes); setOriginalNodes(initializeNodes); - }, [compiledWorkflowClosure]); + }, [dynamicWorkflows, compiledWorkflowClosure]); - React.useEffect(() => { + useEffect(() => { const initializeNodes = convertToPlainNodes(originalNodes); const updatedShownNodesMap = initializeNodes.map((node) => { - const index = nodeExecutions.findIndex((exe) => exe.scopedId === node.scopedId); + const execution = nodeExecutionsById[node.scopedId]; return { ...node, - execution: index >= 0 ? nodeExecutions[index] : undefined, + execution, }; }); setShowNodes(updatedShownNodesMap); @@ -110,12 +124,12 @@ export const ExecutionTimeline: React.FC = ({ nodeExecutions, chartTime if (firstStartedAt) { setStartedAt(timestampToDate(firstStartedAt)); } - }, [originalNodes, nodeExecutions]); + }, [originalNodes, nodeExecutionsById]); const { items: barItemsData, totalDurationSec } = getChartDurationData(showNodes, startedAt); const styles = useStyles({ chartWidth: chartWidth, itemsShown: showNodes.length }); - React.useEffect(() => { + useEffect(() => { // Sync width of elements and intervals of ChartHeader (time labels) and TimelineChart const calcWidth = Math.ceil(totalDurationSec / chartTimeInterval) * INTERVAL_LENGTH; if (durationsRef.current && calcWidth < durationsRef.current.clientWidth) { diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/index.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/index.tsx index e0349ddab..e0180b7a1 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/index.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/index.tsx @@ -1,12 +1,8 @@ import * as React from 'react'; import { makeStyles } from '@material-ui/core'; -import { NodeExecution, NodeExecutionIdentifier } from 'models/Execution/types'; -import { WaitForQuery } from 'components/common/WaitForQuery'; -import { NodeExecutionsRequestConfigContext } from 'components/Executions/contexts'; -import { useAllTreeNodeExecutionGroupsQuery } from 'components/Executions/nodeExecutionQueries'; -import { DataError } from 'components/Errors/DataError'; +import { NodeExecutionIdentifier } from 'models/Execution/types'; import { DetailsPanel } from 'components/common/DetailsPanel'; -import { LargeLoadingSpinner } from 'components/common/LoadingSpinner'; +import { useMemo, useState } from 'react'; import { NodeExecutionDetailsPanelContent } from '../NodeExecutionDetailsPanelContent'; import { NodeExecutionsTimelineContext } from './context'; import { ExecutionTimelineFooter } from './ExecutionTimelineFooter'; @@ -25,58 +21,28 @@ const useStyles = makeStyles(() => ({ flex: '1 1 0', overflowY: 'auto', }, - loading: { - margin: 'auto', - }, })); -interface TimelineProps { - nodeExecutions: NodeExecution[]; -} - -export const ExecutionNodesTimeline = (props: TimelineProps) => { +export const ExecutionNodesTimeline = () => { const styles = useStyles(); - const [selectedExecution, setSelectedExecution] = React.useState( - null, - ); - const [chartTimezone, setChartTimezone] = React.useState(TimeZone.Local); + const [selectedExecution, setSelectedExecution] = useState(null); + const [chartTimezone, setChartTimezone] = useState(TimeZone.Local); const onCloseDetailsPanel = () => setSelectedExecution(null); const handleTimezoneChange = (tz) => setChartTimezone(tz); - const requestConfig = React.useContext(NodeExecutionsRequestConfigContext); - const childGroupsQuery = useAllTreeNodeExecutionGroupsQuery(props.nodeExecutions, requestConfig); - - const timelineContext = React.useMemo( + const timelineContext = useMemo( () => ({ selectedExecution, setSelectedExecution }), [selectedExecution, setSelectedExecution], ); - const renderExecutionsTimeline = (nodeExecutions: NodeExecution[]) => { - return ; - }; - - const TimelineLoading = () => { - return ( -
- -
- ); - }; - return (
- - {renderExecutionsTimeline} - + ;
diff --git a/packages/zapp/console/src/components/Executions/contexts.ts b/packages/zapp/console/src/components/Executions/contexts.ts index 691d464ee..faeb47b6d 100644 --- a/packages/zapp/console/src/components/Executions/contexts.ts +++ b/packages/zapp/console/src/components/Executions/contexts.ts @@ -9,6 +9,7 @@ export interface ExecutionContextData { export const ExecutionContext = React.createContext( {} as ExecutionContextData, ); -export const NodeExecutionsContext = React.createContext>({}); + +export const NodeExecutionsByIdContext = React.createContext>({}); export const NodeExecutionsRequestConfigContext = React.createContext({}); diff --git a/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts b/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts index f31766060..0afce7962 100644 --- a/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts +++ b/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts @@ -1,4 +1,4 @@ -import { compareTimestampsAscending } from 'common/utils'; +// import { compareTimestampsAscending } from 'common/utils'; import { QueryInput, QueryType } from 'components/data/types'; import { retriesToZero } from 'components/flytegraph/ReactFlow/utils'; import { useConditionalQuery } from 'components/hooks/useConditionalQuery'; @@ -20,7 +20,7 @@ import { } from 'models/Execution/types'; import { endNodeId, startNodeId } from 'models/Node/constants'; import { QueryClient, QueryObserverResult, useQueryClient } from 'react-query'; -import { executionRefreshIntervalMs } from './constants'; +// import { executionRefreshIntervalMs } from './constants'; import { fetchTaskExecutionList } from './taskExecutionQueries'; import { formatRetryAttempt } from './TaskExecutionsList/utils'; import { NodeExecutionGroup } from './types'; @@ -389,42 +389,42 @@ export function useChildNodeExecutionGroupsQuery( /** * Query returns all children (not only direct childs) for a list of `nodeExecutions` */ -async function fetchAllTreeNodeExecutions( - queryClient: QueryClient, - nodeExecutions: NodeExecution[], - config: RequestConfig, -): Promise { - const queue: NodeExecution[] = [...nodeExecutions]; - let left = 0; - let right = queue.length; - - while (left < right) { - const top: NodeExecution = queue[left++]; - const executionGroups: NodeExecutionGroup[] = await fetchChildNodeExecutionGroups( - queryClient, - top, - config, - ); - for (let i = 0; i < executionGroups.length; i++) { - for (let j = 0; j < executionGroups[i].nodeExecutions.length; j++) { - queue.push(executionGroups[i].nodeExecutions[j]); - right++; - } - } - } - - const sorted: NodeExecution[] = queue.sort((na: NodeExecution, nb: NodeExecution) => { - if (!na.closure.startedAt) { - return 1; - } - if (!nb.closure.startedAt) { - return -1; - } - return compareTimestampsAscending(na.closure.startedAt, nb.closure.startedAt); - }); - - return sorted; -} +// async function fetchAllTreeNodeExecutions( +// queryClient: QueryClient, +// nodeExecutions: NodeExecution[], +// config: RequestConfig, +// ): Promise { +// const queue: NodeExecution[] = [...nodeExecutions]; +// let left = 0; +// let right = queue.length; + +// while (left < right) { +// const top: NodeExecution = queue[left++]; +// const executionGroups: NodeExecutionGroup[] = await fetchChildNodeExecutionGroups( +// queryClient, +// top, +// config, +// ); +// for (let i = 0; i < executionGroups.length; i++) { +// for (let j = 0; j < executionGroups[i].nodeExecutions.length; j++) { +// queue.push(executionGroups[i].nodeExecutions[j]); +// right++; +// } +// } +// } + +// const sorted: NodeExecution[] = queue.sort((na: NodeExecution, nb: NodeExecution) => { +// if (!na.closure.startedAt) { +// return 1; +// } +// if (!nb.closure.startedAt) { +// return -1; +// } +// return compareTimestampsAscending(na.closure.startedAt, nb.closure.startedAt); +// }); + +// return sorted; +// } /** * @@ -432,24 +432,24 @@ async function fetchAllTreeNodeExecutions( * @param config * @returns */ -export function useAllTreeNodeExecutionGroupsQuery( - nodeExecutions: NodeExecution[], - config: RequestConfig, -): QueryObserverResult { - const queryClient = useQueryClient(); - const shouldEnableFn = (groups) => { - if (nodeExecutions.some((ne) => !nodeExecutionIsTerminal(ne))) { - return true; - } - return groups.some((group) => !nodeExecutionIsTerminal(group)); - }; - - return useConditionalQuery( - { - queryKey: [QueryType.NodeExecutionTreeList, nodeExecutions[0]?.id, config], - queryFn: () => fetchAllTreeNodeExecutions(queryClient, nodeExecutions, config), - refetchInterval: executionRefreshIntervalMs, - }, - shouldEnableFn, - ); -} +// export function useAllTreeNodeExecutionGroupsQuery( +// nodeExecutions: NodeExecution[], +// config: RequestConfig, +// ): QueryObserverResult { +// const queryClient = useQueryClient(); +// const shouldEnableFn = (groups) => { +// if (nodeExecutions.some((ne) => !nodeExecutionIsTerminal(ne))) { +// return true; +// } +// return groups.some((group) => !nodeExecutionIsTerminal(group)); +// }; + +// return useConditionalQuery( +// { +// queryKey: [QueryType.NodeExecutionTreeList, nodeExecutions[0]?.id, config], +// queryFn: () => fetchAllTreeNodeExecutions(queryClient, nodeExecutions, config), +// refetchInterval: executionRefreshIntervalMs, +// }, +// shouldEnableFn, +// ); +// } diff --git a/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx b/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx index ff0035bb4..9cb179985 100644 --- a/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx +++ b/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx @@ -11,6 +11,9 @@ import { makeNodeExecutionDynamicWorkflowQuery } from 'components/Workflow/workf import { createDebugLogger } from 'common/log'; import { CompiledNode } from 'models/Node/types'; import { TaskExecutionPhase } from 'models/Execution/enums'; +import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; +import { useContext } from 'react'; +import { checkForDynamicExeuctions } from 'components/common/utils'; import { transformerWorkflowToDag } from './transformerWorkflowToDag'; export interface WorkflowGraphProps { @@ -19,7 +22,6 @@ export interface WorkflowGraphProps { selectedPhase?: TaskExecutionPhase; isDetailsTabClosed: boolean; workflow: Workflow; - nodeExecutionsById?: any; } interface PrepareDAGResult { @@ -63,40 +65,10 @@ export const WorkflowGraph: React.FC = (props) => { onPhaseSelectionChanged, selectedPhase, isDetailsTabClosed, - nodeExecutionsById, workflow, } = props; + const nodeExecutionsById = useContext(NodeExecutionsByIdContext); const { dag, staticExecutionIdsMap, error } = workflowToDag(workflow); - /** - * Note: - * Dynamic nodes are deteremined at runtime and thus do not come - * down as part of the workflow closure. We can detect and place - * dynamic nodes by finding orphan execution id's and then mapping - * those executions into the dag by using the executions 'uniqueParentId' - * to render that node as a subworkflow - */ - const checkForDynamicExeuctions = (allExecutions, staticExecutions) => { - const parentsToFetch = {}; - for (const executionId in allExecutions) { - if (!staticExecutions[executionId]) { - const dynamicExecution = allExecutions[executionId]; - const dynamicExecutionId = dynamicExecution.metadata.specNodeId || dynamicExecution.id; - const uniqueParentId = dynamicExecution.fromUniqueParentId; - if (uniqueParentId) { - if (parentsToFetch[uniqueParentId]) { - parentsToFetch[uniqueParentId].push(dynamicExecutionId); - } else { - parentsToFetch[uniqueParentId] = [dynamicExecutionId]; - } - } - } - } - const result = {}; - for (const parentId in parentsToFetch) { - result[parentId] = allExecutions[parentId]; - } - return result; - }; const dynamicParents = checkForDynamicExeuctions(nodeExecutionsById, staticExecutionIdsMap); const dynamicWorkflowQuery = useQuery(makeNodeExecutionDynamicWorkflowQuery(dynamicParents)); @@ -118,7 +90,6 @@ export const WorkflowGraph: React.FC = (props) => { return ( { + const parentsToFetch = {}; + for (const executionId in allExecutions) { + if (!staticExecutions[executionId]) { + const dynamicExecution = allExecutions[executionId]; + const dynamicExecutionId = dynamicExecution.metadata.specNodeId || dynamicExecution.id; + const uniqueParentId = dynamicExecution.fromUniqueParentId; + if (uniqueParentId) { + if (parentsToFetch[uniqueParentId]) { + parentsToFetch[uniqueParentId].push(dynamicExecutionId); + } else { + parentsToFetch[uniqueParentId] = [dynamicExecutionId]; + } + } + } + } + const result = {}; + for (const parentId in parentsToFetch) { + result[parentId] = allExecutions[parentId]; + } + return result; +}; diff --git a/packages/zapp/console/src/components/flytegraph/ReactFlow/ReactFlowGraphComponent.tsx b/packages/zapp/console/src/components/flytegraph/ReactFlow/ReactFlowGraphComponent.tsx index 2fb41b801..b84d2f8bc 100644 --- a/packages/zapp/console/src/components/flytegraph/ReactFlow/ReactFlowGraphComponent.tsx +++ b/packages/zapp/console/src/components/flytegraph/ReactFlow/ReactFlowGraphComponent.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useContext } from 'react'; import { ConvertFlyteDagToReactFlows } from 'components/flytegraph/ReactFlow/transformDAGToReactFlowV2'; +import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; import { RFWrapperProps, RFGraphTypes, ConvertDagProps } from './types'; import { getRFBackground } from './utils'; import { ReactFlowWrapper } from './ReactFlowWrapper'; @@ -50,9 +51,9 @@ const ReactFlowGraphComponent = (props) => { onPhaseSelectionChanged, selectedPhase, isDetailsTabClosed, - nodeExecutionsById, dynamicWorkflows, } = props; + const nodeExecutionsById = useContext(NodeExecutionsByIdContext); const [state, setState] = useState({ data, dynamicWorkflows, diff --git a/packages/zapp/console/src/models/Execution/types.ts b/packages/zapp/console/src/models/Execution/types.ts index 0ac356e58..b2990fc75 100644 --- a/packages/zapp/console/src/models/Execution/types.ts +++ b/packages/zapp/console/src/models/Execution/types.ts @@ -92,6 +92,7 @@ export interface NodeExecution extends Admin.INodeExecution { closure: NodeExecutionClosure; metadata?: NodeExecutionMetadata; scopedId?: string; + fromUniqueParentId?: string; } export interface NodeExecutionsById { diff --git a/yarn.lock b/yarn.lock index 23fe23433..9730cc685 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1647,6 +1647,21 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + "@flyteorg/flyteidl@1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@flyteorg/flyteidl/-/flyteidl-1.1.4.tgz#7a02d80e22c623817b6061f1f5e88ec243041cf1" @@ -1657,6 +1672,15 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@humanwhocodes/config-array@^0.10.4": + version "0.10.4" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" + integrity sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + "@humanwhocodes/config-array@^0.9.2": version "0.9.5" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" @@ -1666,6 +1690,11 @@ debug "^4.1.1" minimatch "^3.0.4" +"@humanwhocodes/gitignore-to-minimatch@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" + integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA== + "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" @@ -4781,6 +4810,11 @@ acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-walk@^7.1.1, acorn-walk@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" @@ -4801,6 +4835,11 @@ acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + address@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -5615,7 +5654,7 @@ base16@^1.0.0: resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= -base64-js@^1.0.2: +base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -5720,6 +5759,15 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + bluebird@^3.3.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -6002,6 +6050,14 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -6355,7 +6411,7 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.1.2: +chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -6363,7 +6419,7 @@ chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.0: +chalk@^5.0.0, chalk@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== @@ -6388,6 +6444,11 @@ character-reference-invalid@^1.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + chart.js@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.6.2.tgz#47342c551f688ffdda2cd53b534cb7e461ecec33" @@ -6590,6 +6651,18 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" + integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== + cli-table3@^0.5.0, cli-table3@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" @@ -6626,6 +6699,11 @@ cli-truncate@^0.2.1: slice-ansi "0.0.4" string-width "^1.0.1" +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -8924,6 +9002,51 @@ eslint@^8.11.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +eslint@^8.15.0: + version "8.21.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.21.0.tgz#1940a68d7e0573cef6f50037addee295ff9be9ef" + integrity sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA== + dependencies: + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.10.4" + "@humanwhocodes/gitignore-to-minimatch" "^1.0.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.3" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.15.0" + globby "^11.1.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + espree@^9.3.1: version "9.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" @@ -8933,6 +9056,15 @@ espree@^9.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^3.3.0" +espree@^9.3.2, espree@^9.3.3: + version "9.3.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.3.tgz#2dd37c4162bb05f433ad3c1a52ddf8a49dc08e9d" + integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -9212,6 +9344,15 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -10125,6 +10266,13 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^13.15.0: + version "13.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== + dependencies: + type-fest "^0.20.2" + globals@^13.6.0, globals@^13.9.0: version "13.13.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" @@ -10151,7 +10299,7 @@ globby@^11.0.0, globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" -globby@^11.0.2, globby@^11.0.4: +globby@^11.0.2, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -10220,6 +10368,11 @@ graceful-fs@^4.2.10, graceful-fs@^4.2.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + graphlib@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" @@ -10832,7 +10985,7 @@ hyphenate-style-name@^1.0.3: resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== -iconv-lite@0.4, iconv-lite@0.4.24: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -10865,7 +11018,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ieee754@^1.1.4: +ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -11042,6 +11195,27 @@ inline-style-parser@0.1.1: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== +inquirer@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4" + integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -11398,6 +11572,11 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" @@ -11606,6 +11785,11 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-weakref@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -12875,7 +13059,7 @@ listr-verbose-renderer@^0.5.0: date-fns "^1.27.2" figures "^2.0.0" -listr@^0.14.1: +listr@^0.14.1, listr@^0.14.3: version "0.14.3" resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== @@ -13130,6 +13314,14 @@ log-symbols@^2.2.0: dependencies: chalk "^2.0.1" +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + log-update@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" @@ -13975,7 +14167,7 @@ multicast-dns@^7.2.4: dns-packet "^5.2.2" thunky "^1.0.2" -mute-stream@~0.0.4: +mute-stream@0.0.8, mute-stream@~0.0.4: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== @@ -14017,6 +14209,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +ncp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA== + negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -14962,6 +15159,21 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -14981,7 +15193,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0: +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -16595,7 +16807,7 @@ read@1, read@^1.0.7, read@~1.0.1, read@~1.0.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -17077,6 +17289,14 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -17136,6 +17356,11 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + run-parallel@^1.1.9: version "1.1.10" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" @@ -17160,6 +17385,13 @@ rxjs@^6.3.3: dependencies: tslib "^1.9.0" +rxjs@^7.5.5: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -18552,7 +18784,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -through@2, "through@>=2.2.7 <3": +through@2, "through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -18589,6 +18821,13 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -18788,6 +19027,11 @@ tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -19496,7 +19740,7 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -wcwidth@^1.0.0: +wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= From 710f1f2bea86ddb2927e6d0d4956d967d35d1fd3 Mon Sep 17 00:00:00 2001 From: Olga Nad Date: Mon, 15 Aug 2022 16:42:54 -0500 Subject: [PATCH 2/3] fix: update tests and clean up code Signed-off-by: Olga Nad --- .../ExecutionDetails/ExecutionNodeViews.tsx | 28 +-- .../Timeline/ExecutionTimeline.tsx | 10 +- .../ExecutionDetails/test/Timeline.test.tsx | 2 +- .../Executions/nodeExecutionQueries.ts | 190 ++++++------------ .../WorkflowGraph/test/WorkflowGraph.test.tsx | 2 - 5 files changed, 75 insertions(+), 157 deletions(-) diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx index 8b4099257..006db91d3 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/ExecutionNodeViews.tsx @@ -21,7 +21,7 @@ import { useExecutionNodeViewsState } from './useExecutionNodeViewsState'; import { ExecutionNodesTimeline } from './Timeline'; import { fetchTaskExecutionList } from '../taskExecutionQueries'; import { getGroupedLogs } from '../TaskExecutionsList/utils'; -import { useAllChildNodeExecutionGroupsQuery } from '../nodeExecutionQueries'; +import { useAllTreeNodeExecutionGroupsQuery } from '../nodeExecutionQueries'; import { ExecutionWorkflowGraph } from './ExecutionWorkflowGraph'; const useStyles = makeStyles((theme: Theme) => ({ @@ -128,30 +128,16 @@ export const ExecutionNodeViews: React.FC = ({ executio }; }, [nodeExecutions]); - // const childGroupsTreeQuery = useAllTreeNodeExecutionGroupsQuery( - // nodeExecutionsQuery.data ?? [], - // requestConfig, - // ); - - const childGroupsAllQuery = useAllChildNodeExecutionGroupsQuery( + const childGroupsQuery = useAllTreeNodeExecutionGroupsQuery( nodeExecutionsQuery.data ?? [], requestConfig, ); useEffect(() => { - if (!childGroupsAllQuery.isLoading) { - const output: any[] = nodeExecutionsQuery.data ?? []; - const childGroups = childGroupsAllQuery.data ?? []; - for (let i = 0; i < childGroups.length; i++) { - for (let j = 0; j < childGroups[i].length; j++) { - for (let k = 0; k < childGroups[i][j].nodeExecutions.length; k++) { - output.push(childGroups[i][j].nodeExecutions[k] as NodeExecution); - } - } - } - setNodeExecutions(output.concat(nodeExecutions)); + if (!childGroupsQuery.isLoading && childGroupsQuery.data) { + setNodeExecutions(childGroupsQuery.data); } - }, [childGroupsAllQuery.data]); + }, [childGroupsQuery.data]); const renderNodeExecutionsTable = (nodeExecutions: NodeExecution[]) => ( @@ -167,7 +153,7 @@ export const ExecutionNodeViews: React.FC = ({ executio const renderExecutionLoader = () => { return ( - + {renderExecutionChildrenLoader} ); @@ -176,7 +162,7 @@ export const ExecutionNodeViews: React.FC = ({ executio const renderExecutionsTimeline = () => ( {() => } diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx index 83234ec61..3dda6ed3c 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx @@ -9,7 +9,7 @@ import { timestampToDate } from 'common/utils'; import { dNode } from 'models/Graph/types'; import { makeNodeExecutionDynamicWorkflowQuery } from 'components/Workflow/workflowQueries'; import { useQuery } from 'react-query'; -import { useEffect, useState } from 'react'; +import { createRef, useContext, useEffect, useRef, useState } from 'react'; import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; import { checkForDynamicExeuctions } from 'components/common/utils'; import { convertToPlainNodes } from './helpers'; @@ -77,9 +77,9 @@ interface ExProps { export const ExecutionTimeline: React.FC = ({ chartTimezone }) => { const [chartWidth, setChartWidth] = useState(0); const [labelInterval, setLabelInterval] = useState(INTERVAL_LENGTH); - const durationsRef = React.useRef(null); - const durationsLabelsRef = React.useRef(null); - const taskNamesRef = React.createRef(); + const durationsRef = useRef(null); + const durationsLabelsRef = useRef(null); + const taskNamesRef = createRef(); const [originalNodes, setOriginalNodes] = useState([]); const [showNodes, setShowNodes] = useState([]); @@ -91,7 +91,7 @@ export const ExecutionTimeline: React.FC = ({ chartTimezone }) => { ? transformerWorkflowToDag(compiledWorkflowClosure) : []; - const nodeExecutionsById = React.useContext(NodeExecutionsByIdContext); + const nodeExecutionsById = useContext(NodeExecutionsByIdContext); const dynamicParents = checkForDynamicExeuctions(nodeExecutionsById, staticExecutionIdsMap); diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx index d1e68dba2..6d10d1ba5 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx @@ -59,7 +59,7 @@ describe('ExecutionDetails > Timeline', () => { render( - + , ); diff --git a/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts b/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts index 0afce7962..556832414 100644 --- a/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts +++ b/packages/zapp/console/src/components/Executions/nodeExecutionQueries.ts @@ -1,4 +1,4 @@ -// import { compareTimestampsAscending } from 'common/utils'; +import { compareTimestampsAscending } from 'common/utils'; import { QueryInput, QueryType } from 'components/data/types'; import { retriesToZero } from 'components/flytegraph/ReactFlow/utils'; import { useConditionalQuery } from 'components/hooks/useConditionalQuery'; @@ -20,7 +20,7 @@ import { } from 'models/Execution/types'; import { endNodeId, startNodeId } from 'models/Node/constants'; import { QueryClient, QueryObserverResult, useQueryClient } from 'react-query'; -// import { executionRefreshIntervalMs } from './constants'; +import { executionRefreshIntervalMs } from './constants'; import { fetchTaskExecutionList } from './taskExecutionQueries'; import { formatRetryAttempt } from './TaskExecutionsList/utils'; import { NodeExecutionGroup } from './types'; @@ -280,43 +280,70 @@ function fetchChildNodeExecutionGroups( return fetchGroupsForTaskExecutionNode(queryClient, nodeExecution, config); } -/** - * Query returns all children for a list of `nodeExecutions` - * Will recursively gather all children for anyone that isParent() +/** Fetches and groups `NodeExecution`s which are direct children of the given + * `NodeExecution`. */ -async function fetchAllChildNodeExecutions( - queryClient: QueryClient, - nodeExecutions: NodeExecution[], +export function useChildNodeExecutionGroupsQuery( + nodeExecution: NodeExecution, config: RequestConfig, -): Promise> { - const executionGroups: Array = await Promise.all( - nodeExecutions.map((exe) => fetchChildNodeExecutionGroups(queryClient, exe, config)), - ); +): QueryObserverResult { + const queryClient = useQueryClient(); + // Use cached data if the parent node execution is terminal and all children + // in all groups are terminal + const shouldEnableFn = (groups: NodeExecutionGroup[]) => { + if (!nodeExecutionIsTerminal(nodeExecution)) { + return true; + } + return groups.some((group) => group.nodeExecutions.some((ne) => !nodeExecutionIsTerminal(ne))); + }; - /** Recursive check for nested/dynamic nodes */ - const childrenFromChildrenNodes: NodeExecution[] = []; - executionGroups.map((group) => - group.map((attempt) => { - attempt.nodeExecutions.map((execution) => { - if (isParentNode(execution)) { - childrenFromChildrenNodes.push(execution); - } - }); - }), + return useConditionalQuery( + { + queryKey: [QueryType.NodeExecutionChildList, nodeExecution.id, config], + queryFn: () => fetchChildNodeExecutionGroups(queryClient, nodeExecution, config), + }, + shouldEnableFn, ); +} - /** Request and concact data from children */ - if (childrenFromChildrenNodes.length > 0) { - const childGroups = await fetchAllChildNodeExecutions( +/** + * Query returns all children (not only direct childs) for a list of `nodeExecutions` + */ +async function fetchAllTreeNodeExecutions( + queryClient: QueryClient, + nodeExecutions: NodeExecution[], + config: RequestConfig, +): Promise { + const queue: NodeExecution[] = [...nodeExecutions]; + let left = 0; + let right = queue.length; + + while (left < right) { + const top: NodeExecution = queue[left++]; + const executionGroups: NodeExecutionGroup[] = await fetchChildNodeExecutionGroups( queryClient, - childrenFromChildrenNodes, + top, config, ); - for (const group in childGroups) { - executionGroups.push(childGroups[group]); + for (let i = 0; i < executionGroups.length; i++) { + for (let j = 0; j < executionGroups[i].nodeExecutions.length; j++) { + queue.push(executionGroups[i].nodeExecutions[j]); + right++; + } } } - return executionGroups; + + const sorted: NodeExecution[] = queue.sort((na: NodeExecution, nb: NodeExecution) => { + if (!na.closure.startedAt) { + return 1; + } + if (!nb.closure.startedAt) { + return -1; + } + return compareTimestampsAscending(na.closure.startedAt, nb.closure.startedAt); + }); + + return sorted; } /** @@ -325,10 +352,10 @@ async function fetchAllChildNodeExecutions( * @param config * @returns */ -export function useAllChildNodeExecutionGroupsQuery( +export function useAllTreeNodeExecutionGroupsQuery( nodeExecutions: NodeExecution[], config: RequestConfig, -): QueryObserverResult, Error> { +): QueryObserverResult { const queryClient = useQueryClient(); const shouldEnableFn = (groups) => { if (groups.length > 0) { @@ -351,105 +378,12 @@ export function useAllChildNodeExecutionGroupsQuery( const key = `${nodeExecutions?.[0]?.scopedId}-${nodeExecutions?.[0]?.closure?.phase}`; - return useConditionalQuery>( + return useConditionalQuery( { - queryKey: [QueryType.NodeExecutionChildList, key, config], - queryFn: () => fetchAllChildNodeExecutions(queryClient, nodeExecutions, config), + queryKey: [QueryType.NodeExecutionTreeList, key, config], + queryFn: () => fetchAllTreeNodeExecutions(queryClient, nodeExecutions, config), + refetchInterval: executionRefreshIntervalMs, }, shouldEnableFn, ); } - -/** Fetches and groups `NodeExecution`s which are direct children of the given - * `NodeExecution`. - */ -export function useChildNodeExecutionGroupsQuery( - nodeExecution: NodeExecution, - config: RequestConfig, -): QueryObserverResult { - const queryClient = useQueryClient(); - // Use cached data if the parent node execution is terminal and all children - // in all groups are terminal - const shouldEnableFn = (groups: NodeExecutionGroup[]) => { - if (!nodeExecutionIsTerminal(nodeExecution)) { - return true; - } - return groups.some((group) => group.nodeExecutions.some((ne) => !nodeExecutionIsTerminal(ne))); - }; - - return useConditionalQuery( - { - queryKey: [QueryType.NodeExecutionChildList, nodeExecution.id, config], - queryFn: () => fetchChildNodeExecutionGroups(queryClient, nodeExecution, config), - }, - shouldEnableFn, - ); -} - -/** - * Query returns all children (not only direct childs) for a list of `nodeExecutions` - */ -// async function fetchAllTreeNodeExecutions( -// queryClient: QueryClient, -// nodeExecutions: NodeExecution[], -// config: RequestConfig, -// ): Promise { -// const queue: NodeExecution[] = [...nodeExecutions]; -// let left = 0; -// let right = queue.length; - -// while (left < right) { -// const top: NodeExecution = queue[left++]; -// const executionGroups: NodeExecutionGroup[] = await fetchChildNodeExecutionGroups( -// queryClient, -// top, -// config, -// ); -// for (let i = 0; i < executionGroups.length; i++) { -// for (let j = 0; j < executionGroups[i].nodeExecutions.length; j++) { -// queue.push(executionGroups[i].nodeExecutions[j]); -// right++; -// } -// } -// } - -// const sorted: NodeExecution[] = queue.sort((na: NodeExecution, nb: NodeExecution) => { -// if (!na.closure.startedAt) { -// return 1; -// } -// if (!nb.closure.startedAt) { -// return -1; -// } -// return compareTimestampsAscending(na.closure.startedAt, nb.closure.startedAt); -// }); - -// return sorted; -// } - -/** - * - * @param nodeExecutions list of parent node executionId's - * @param config - * @returns - */ -// export function useAllTreeNodeExecutionGroupsQuery( -// nodeExecutions: NodeExecution[], -// config: RequestConfig, -// ): QueryObserverResult { -// const queryClient = useQueryClient(); -// const shouldEnableFn = (groups) => { -// if (nodeExecutions.some((ne) => !nodeExecutionIsTerminal(ne))) { -// return true; -// } -// return groups.some((group) => !nodeExecutionIsTerminal(group)); -// }; - -// return useConditionalQuery( -// { -// queryKey: [QueryType.NodeExecutionTreeList, nodeExecutions[0]?.id, config], -// queryFn: () => fetchAllTreeNodeExecutions(queryClient, nodeExecutions, config), -// refetchInterval: executionRefreshIntervalMs, -// }, -// shouldEnableFn, -// ); -// } diff --git a/packages/zapp/console/src/components/WorkflowGraph/test/WorkflowGraph.test.tsx b/packages/zapp/console/src/components/WorkflowGraph/test/WorkflowGraph.test.tsx index bcbb7fb5e..93817bb9d 100644 --- a/packages/zapp/console/src/components/WorkflowGraph/test/WorkflowGraph.test.tsx +++ b/packages/zapp/console/src/components/WorkflowGraph/test/WorkflowGraph.test.tsx @@ -4,7 +4,6 @@ import { createTestQueryClient } from 'test/utils'; import { QueryClient, QueryClientProvider } from 'react-query'; import { WorkflowGraph } from '../WorkflowGraph'; import { workflow } from './workflow.mock'; -import { nodeExecutionsById } from './nodeExecutionsById.mock'; jest.mock('../../flytegraph/ReactFlow/ReactFlowWrapper.tsx', () => ({ ReactFlowWrapper: jest.fn(({ children }) => ( @@ -27,7 +26,6 @@ describe('WorkflowGraph', () => { onNodeSelectionChanged={jest.fn} onPhaseSelectionChanged={jest.fn} workflow={workflow} - nodeExecutionsById={nodeExecutionsById} isDetailsTabClosed={true} /> , From 7561808ca6739181f136b55d29f64082f8e4961b Mon Sep 17 00:00:00 2001 From: Olga Nad Date: Tue, 16 Aug 2022 10:56:39 -0500 Subject: [PATCH 3/3] fix: test Signed-off-by: Olga Nad --- .../ExecutionDetails/Timeline/ExecutionTimeline.tsx | 4 ++-- .../Executions/ExecutionDetails/test/Timeline.test.tsx | 9 ++++++++- .../src/components/WorkflowGraph/WorkflowGraph.tsx | 4 ++-- packages/zapp/console/src/components/common/utils.ts | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx index 3dda6ed3c..e15b6c31f 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx @@ -11,7 +11,7 @@ import { makeNodeExecutionDynamicWorkflowQuery } from 'components/Workflow/workf import { useQuery } from 'react-query'; import { createRef, useContext, useEffect, useRef, useState } from 'react'; import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; -import { checkForDynamicExeuctions } from 'components/common/utils'; +import { checkForDynamicExecutions } from 'components/common/utils'; import { convertToPlainNodes } from './helpers'; import { ChartHeader } from './chartHeader'; import { useScaleContext } from './scaleContext'; @@ -93,7 +93,7 @@ export const ExecutionTimeline: React.FC = ({ chartTimezone }) => { const nodeExecutionsById = useContext(NodeExecutionsByIdContext); - const dynamicParents = checkForDynamicExeuctions(nodeExecutionsById, staticExecutionIdsMap); + const dynamicParents = checkForDynamicExecutions(nodeExecutionsById, staticExecutionIdsMap); const { data: dynamicWorkflows } = useQuery( makeNodeExecutionDynamicWorkflowQuery(dynamicParents), diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx index 6d10d1ba5..f99d01f8d 100644 --- a/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx +++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/test/Timeline.test.tsx @@ -1,5 +1,6 @@ import ThemeProvider from '@material-ui/styles/ThemeProvider'; import { render, waitFor } from '@testing-library/react'; +import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; import { muiTheme } from 'components/Theme/muiTheme'; import { oneFailedTaskWorkflow } from 'mocks/data/fixtures/oneFailedTaskWorkflow'; import { insertFixture } from 'mocks/data/insertFixture'; @@ -16,6 +17,10 @@ jest.mock('../ExecutionWorkflowGraph.tsx', () => ({ ExecutionWorkflowGraph: () => null, })); +jest.mock('../Timeline/ExecutionTimeline.tsx', () => ({ + ExecutionTimeline: () => null, +})); + jest.mock('chart.js', () => ({ Chart: { register: () => null }, Tooltip: { positioners: { cursor: () => null } }, @@ -59,7 +64,9 @@ describe('ExecutionDetails > Timeline', () => { render( - + + + , ); diff --git a/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx b/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx index 9cb179985..fad6e0902 100644 --- a/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx +++ b/packages/zapp/console/src/components/WorkflowGraph/WorkflowGraph.tsx @@ -13,7 +13,7 @@ import { CompiledNode } from 'models/Node/types'; import { TaskExecutionPhase } from 'models/Execution/enums'; import { NodeExecutionsByIdContext } from 'components/Executions/contexts'; import { useContext } from 'react'; -import { checkForDynamicExeuctions } from 'components/common/utils'; +import { checkForDynamicExecutions } from 'components/common/utils'; import { transformerWorkflowToDag } from './transformerWorkflowToDag'; export interface WorkflowGraphProps { @@ -70,7 +70,7 @@ export const WorkflowGraph: React.FC = (props) => { const nodeExecutionsById = useContext(NodeExecutionsByIdContext); const { dag, staticExecutionIdsMap, error } = workflowToDag(workflow); - const dynamicParents = checkForDynamicExeuctions(nodeExecutionsById, staticExecutionIdsMap); + const dynamicParents = checkForDynamicExecutions(nodeExecutionsById, staticExecutionIdsMap); const dynamicWorkflowQuery = useQuery(makeNodeExecutionDynamicWorkflowQuery(dynamicParents)); const renderReactFlowGraph = (dynamicWorkflows) => { debug('DynamicWorkflows:', dynamicWorkflows); diff --git a/packages/zapp/console/src/components/common/utils.ts b/packages/zapp/console/src/components/common/utils.ts index 58bc2eb61..4612bddbe 100644 --- a/packages/zapp/console/src/components/common/utils.ts +++ b/packages/zapp/console/src/components/common/utils.ts @@ -25,7 +25,7 @@ export function measureText(fontDefinition: string, text: string) { * those executions into the dag by using the executions 'uniqueParentId' * to render that node as a subworkflow */ -export const checkForDynamicExeuctions = (allExecutions, staticExecutions) => { +export const checkForDynamicExecutions = (allExecutions, staticExecutions) => { const parentsToFetch = {}; for (const executionId in allExecutions) { if (!staticExecutions[executionId]) {