diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ChartHeader.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ChartHeader.tsx
new file mode 100644
index 000000000..1fafd08c8
--- /dev/null
+++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ChartHeader.tsx
@@ -0,0 +1,68 @@
+import * as React from 'react';
+import * as moment from 'moment-timezone';
+import makeStyles from '@material-ui/core/styles/makeStyles';
+import { COLOR_SPECTRUM } from 'components/Theme/colorSpectrum';
+import { useScaleContext } from './scaleContext';
+import { TimeZone } from './helpers';
+
+interface StyleProps {
+ chartWidth: number;
+ labelInterval: number;
+}
+
+const useStyles = makeStyles((_theme) => ({
+ chartHeader: (props: StyleProps) => ({
+ height: 41,
+ display: 'flex',
+ alignItems: 'center',
+ width: `${props.chartWidth}px`,
+ }),
+ taskDurationsLabelItem: (props: StyleProps) => ({
+ fontSize: 12,
+ fontFamily: 'Open Sans',
+ fontWeight: 'bold',
+ color: COLOR_SPECTRUM.gray40.color,
+ paddingLeft: 10,
+ width: `${props.labelInterval}px`,
+ }),
+}));
+
+interface HeaderProps extends StyleProps {
+ chartTimezone: string;
+ totalDurationSec: number;
+ startedAt: Date;
+}
+
+export const ChartHeader = (props: HeaderProps) => {
+ const styles = useStyles(props);
+
+ const { chartInterval: chartTimeInterval, setMaxValue } = useScaleContext();
+ const { startedAt, chartTimezone, totalDurationSec } = props;
+
+ React.useEffect(() => {
+ setMaxValue(props.totalDurationSec);
+ }, [props.totalDurationSec, setMaxValue]);
+
+ const labels = React.useMemo(() => {
+ const len = Math.ceil(totalDurationSec / chartTimeInterval);
+ const lbs = len > 0 ? new Array(len).fill('') : [];
+ return lbs.map((_, idx) => {
+ const time = moment.utc(new Date(startedAt.getTime() + idx * chartTimeInterval * 1000));
+ return chartTimezone === TimeZone.UTC
+ ? time.format('hh:mm:ss A')
+ : time.local().format('hh:mm:ss A');
+ });
+ }, [chartTimezone, startedAt, chartTimeInterval, totalDurationSec]);
+
+ return (
+
+ {labels.map((label) => {
+ return (
+
+ {label}
+
+ );
+ })}
+
+ );
+};
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 e15b6c31f..14af5b17e 100644
--- a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx
+++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/ExecutionTimeline.tsx
@@ -13,9 +13,9 @@ import { createRef, useContext, useEffect, useRef, useState } from 'react';
import { NodeExecutionsByIdContext } from 'components/Executions/contexts';
import { checkForDynamicExecutions } from 'components/common/utils';
import { convertToPlainNodes } from './helpers';
-import { ChartHeader } from './chartHeader';
+import { ChartHeader } from './ChartHeader';
import { useScaleContext } from './scaleContext';
-import { TaskNames } from './taskNames';
+import { TaskNames } from './TaskNames';
import { getChartDurationData } from './TimelineChart/chartData';
import { TimelineChart } from './TimelineChart';
diff --git a/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TaskNames.tsx b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TaskNames.tsx
new file mode 100644
index 000000000..a2bcd4187
--- /dev/null
+++ b/packages/zapp/console/src/components/Executions/ExecutionDetails/Timeline/TaskNames.tsx
@@ -0,0 +1,99 @@
+import * as React from 'react';
+import { makeStyles, Theme, Typography } from '@material-ui/core';
+
+import { RowExpander } from 'components/Executions/Tables/RowExpander';
+import { getNodeTemplateName } from 'components/WorkflowGraph/utils';
+import { dNode } from 'models/Graph/types';
+import { NodeExecutionName } from './NodeExecutionName';
+import { NodeExecutionsTimelineContext } from './context';
+
+const useStyles = makeStyles((theme: Theme) => ({
+ taskNamesList: {
+ overflowY: 'scroll',
+ flex: 1,
+ },
+ namesContainer: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ justifyContent: 'left',
+ padding: '0 10px',
+ height: 56,
+ width: 256,
+ borderBottom: `1px solid ${theme.palette.divider}`,
+ whiteSpace: 'nowrap',
+ },
+ namesContainerExpander: {
+ display: 'flex',
+ marginTop: 'auto',
+ marginBottom: 'auto',
+ },
+ namesContainerBody: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'flex-start',
+ justifyContent: 'center',
+ whiteSpace: 'nowrap',
+ height: '100%',
+ overflow: 'hidden',
+ },
+ displayName: {
+ marginTop: 4,
+ textOverflow: 'ellipsis',
+ width: '100%',
+ overflow: 'hidden',
+ },
+ leaf: {
+ width: 30,
+ },
+}));
+
+interface TaskNamesProps {
+ nodes: dNode[];
+ onScroll: () => void;
+ onToggle: (id: string, scopeId: string, level: number) => void;
+}
+
+export const TaskNames = React.forwardRef((props, ref) => {
+ const state = React.useContext(NodeExecutionsTimelineContext);
+ const { nodes, onScroll, onToggle } = props;
+ const styles = useStyles();
+
+ return (
+
+ {nodes.map((node) => {
+ const templateName = getNodeTemplateName(node);
+ const nodeLevel = node?.level ?? 0;
+ return (
+
+
+ {node.nodes?.length ? (
+
onToggle(node.id, node.scopedId, nodeLevel)}
+ />
+ ) : (
+
+ )}
+
+
+
+
+
+ {templateName}
+
+
+
+ );
+ })}
+
+ );
+});
diff --git a/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx b/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx
index b2338437f..f674002b9 100644
--- a/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx
+++ b/packages/zapp/console/src/components/Executions/Tables/nodeExecutionColumns.tsx
@@ -3,8 +3,7 @@ import { formatDateLocalTimezone, formatDateUTC, millisecondsToHMS } from 'commo
import { timestampToDate } from 'common/utils';
import { useCommonStyles } from 'components/common/styles';
import { isEqual } from 'lodash';
-import { CatalogCacheStatus, NodeExecutionPhase } from 'models/Execution/enums';
-import { TaskNodeMetadata } from 'models/Execution/types';
+import { NodeExecutionPhase } from 'models/Execution/enums';
import * as React from 'react';
import { useNodeExecutionContext } from '../contextProvider/NodeExecutionDetails';
import { ExecutionStatusBadge } from '../ExecutionStatusBadge';
@@ -107,15 +106,6 @@ const DisplayType: React.FC = ({ execution }) =>
return {type};
};
-const hiddenCacheStatuses = [CatalogCacheStatus.CACHE_MISS, CatalogCacheStatus.CACHE_DISABLED];
-function hasCacheStatus(taskNodeMetadata?: TaskNodeMetadata): taskNodeMetadata is TaskNodeMetadata {
- if (!taskNodeMetadata) {
- return false;
- }
- const { cacheStatus } = taskNodeMetadata;
- return !hiddenCacheStatuses.includes(cacheStatus);
-}
-
export function generateColumns(
styles: ReturnType,
): NodeExecutionColumnDefinition[] {
diff --git a/packages/zapp/console/src/components/WorkflowGraph/utils.ts b/packages/zapp/console/src/components/WorkflowGraph/utils.ts
index 2930f6062..d8e104652 100644
--- a/packages/zapp/console/src/components/WorkflowGraph/utils.ts
+++ b/packages/zapp/console/src/components/WorkflowGraph/utils.ts
@@ -27,22 +27,6 @@ export function isExpanded(node: any) {
return !!node.expanded;
}
-/**
- * Utility funciton assumes (loose) parity between [a]->[b] if matching
- * keys have matching values.
- * @param a object
- * @param b object
- * @returns boolean
- */
-export const checkIfObjectsAreSame = (a, b) => {
- for (const k in a) {
- if (a[k] != b[k]) {
- return false;
- }
- }
- return true;
-};
-
/**
* Returns a display name from either workflows or nodes
* @param context input can be either CompiledWorkflow or CompiledNode
@@ -110,11 +94,12 @@ export const getNodeTypeFromCompiledNode = (node: CompiledNode): dTypes => {
};
export const getSubWorkflowFromId = (id, workflow) => {
+ const _ = require('lodash');
const { subWorkflows } = workflow;
/* Find current matching entitity from subWorkflows */
for (const k in subWorkflows) {
const subWorkflowId = subWorkflows[k].template.id;
- if (checkIfObjectsAreSame(subWorkflowId, id)) {
+ if (_.isEqual(subWorkflowId, id)) {
return subWorkflows[k];
}
}
@@ -122,11 +107,12 @@ export const getSubWorkflowFromId = (id, workflow) => {
};
export const getTaskTypeFromCompiledNode = (taskNode: TaskNode, tasks: CompiledTask[]) => {
+ const _ = require('lodash');
for (let i = 0; i < tasks.length; i++) {
const compiledTask: CompiledTask = tasks[i];
const taskTemplate: TaskTemplate = compiledTask.template;
const templateId: Identifier = taskTemplate.id;
- if (checkIfObjectsAreSame(templateId, taskNode.referenceId)) {
+ if (_.isEqual(templateId, taskNode.referenceId)) {
return compiledTask;
}
}