Skip to content

Commit

Permalink
fix: Expose cluster information for Workflow Executions (#78)
Browse files Browse the repository at this point in the history
* chore: update flyteidl

* fix: move some of execution content out of page header

* fix: show cluster name if available

* refactor: rearranging metadata display and adding cluster info

* refactor: pr feedback

* fix: also show execution errors when available

* fix: makes execution metadata collapsible

* fix: don't show execution metadata without values
  • Loading branch information
schottra authored Jul 1, 2020
1 parent bdac7ed commit d43a1e3
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 106 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@date-io/moment": "1.3.9",
"@lyft/flyteidl": "^0.17.27",
"@lyft/flyteidl": "^0.17.34",
"@material-ui/core": "^4.0.0",
"@material-ui/icons": "^4.0.0",
"@material-ui/pickers": "^3.2.2",
Expand Down
49 changes: 49 additions & 0 deletions src/components/Executions/ExecutionDetails/ExecutionDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { Collapse, IconButton } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import ExpandMore from '@material-ui/icons/ExpandMore';
import * as classnames from 'classnames';
import { WaitForData, withRouteParams } from 'components/common';
import { RefreshConfig, useDataRefresher } from 'components/hooks';
import { Execution } from 'models';
Expand All @@ -8,8 +12,32 @@ import { useExecutionDataCache } from '../useExecutionDataCache';
import { useWorkflowExecution } from '../useWorkflowExecution';
import { executionIsTerminal } from '../utils';
import { ExecutionDetailsAppBarContent } from './ExecutionDetailsAppBarContent';
import { ExecutionMetadata } from './ExecutionMetadata';
import { ExecutionNodeViews } from './ExecutionNodeViews';

const useStyles = makeStyles((theme: Theme) => ({
expandCollapseButton: {
transition: theme.transitions.create('transform'),
'&.expanded': {
transform: 'rotate(180deg)'
}
},
expandCollapseContainer: {
alignItems: 'center',
bottom: 0,
display: 'flex',
// Matches height of tabs in the NodeViews container
height: theme.spacing(6),
position: 'absolute',
right: theme.spacing(3),
transform: 'translateY(100%)',
zIndex: 1
},
metadataContainer: {
position: 'relative'
}
}));

export interface ExecutionDetailsRouteParams {
domainId: string;
executionId: string;
Expand All @@ -33,6 +61,9 @@ export const ExecutionDetailsContainer: React.FC<ExecutionDetailsRouteParams> =
domain: domainId,
name: executionId
};
const styles = useStyles();
const [metadataExpanded, setMetadataExpanded] = React.useState(true);
const toggleMetadata = () => setMetadataExpanded(!metadataExpanded);
const dataCache = useExecutionDataCache();
const { fetchable, terminateExecution } = useWorkflowExecution(
id,
Expand All @@ -43,10 +74,28 @@ export const ExecutionDetailsContainer: React.FC<ExecutionDetailsRouteParams> =
terminateExecution,
execution: fetchable.value
};

return (
<WaitForData {...fetchable}>
<ExecutionContext.Provider value={contextValue}>
<ExecutionDetailsAppBarContent execution={fetchable.value} />
<div className={styles.metadataContainer}>
<Collapse in={metadataExpanded}>
<ExecutionMetadata execution={fetchable.value} />
</Collapse>
<div className={styles.expandCollapseContainer}>
<IconButton size="small" onClick={toggleMetadata}>
<ExpandMore
className={classnames(
styles.expandCollapseButton,
{
expanded: metadataExpanded
}
)}
/>
</IconButton>
</div>
</div>
<ExecutionDataCacheContext.Provider value={dataCache}>
<ExecutionNodeViews execution={fetchable.value} />
</ExecutionDataCacheContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { Button, Dialog, Link, Typography } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import ArrowBack from '@material-ui/icons/ArrowBack';
import * as classnames from 'classnames';
import { formatDateUTC, protobufDurationToHMS } from 'common/formatters';
import { timestampToDate } from 'common/utils';
import { navbarGridHeight } from 'common/layout';
import { useCommonStyles } from 'components/common/styles';
import { useLocationState } from 'components/hooks/useLocationState';
import { NavBarContent } from 'components/Navigation/NavBarContent';
Expand All @@ -19,9 +18,6 @@ import { executionIsTerminal } from '../utils';
import { RelaunchExecutionForm } from './RelaunchExecutionForm';

const useStyles = makeStyles((theme: Theme) => {
const actionsMinWidth = theme.spacing(34);
const badgeWidth = theme.spacing(11);
const maxDetailsWidth = `calc(100% - ${actionsMinWidth + badgeWidth}px)`;
return {
actions: {
alignItems: 'center',
Expand All @@ -41,25 +37,13 @@ const useStyles = makeStyles((theme: Theme) => {
flex: '1 1 auto',
maxWidth: '100%'
},
detailsContainer: {
titleContainer: {
alignItems: 'center',
display: 'flex',
flex: '0 1 auto',
justifyContent: 'space-between',
maxWidth: maxDetailsWidth
},
detailItem: {
flexShrink: 0,
marginLeft: theme.spacing(2)
},
detailLabel: {
fontSize: smallFontSize,
lineHeight: 1.25
},
detailValue: {
fontSize: '0.875rem',
fontWeight: 'bold',
lineHeight: '1.1875rem'
flexDirection: 'column',
maxHeight: theme.spacing(navbarGridHeight),
overflow: 'hidden'
},
inputsOutputsLink: {
color: interactiveTextDisabledColor
Expand All @@ -69,7 +53,7 @@ const useStyles = makeStyles((theme: Theme) => {
},
title: {
flex: '0 1 auto',
overflow: 'hidden'
marginLeft: theme.spacing(2)
},
version: {
flex: '0 1 auto',
Expand All @@ -78,12 +62,6 @@ const useStyles = makeStyles((theme: Theme) => {
};
});

interface DetailItem {
className?: string;
label: React.ReactNode;
value: React.ReactNode;
}

/** Renders information about a given Execution into the NavBar */
export const ExecutionDetailsAppBarContent: React.FC<{
execution: Execution;
Expand All @@ -94,7 +72,7 @@ export const ExecutionDetailsAppBarContent: React.FC<{
const [showRelaunchForm, setShowRelaunchForm] = React.useState(false);

const { domain, name, project } = execution.id;
const { duration, startedAt, phase, workflowId } = execution.closure;
const { phase, workflowId } = execution.closure;

const {
backLink = Routes.WorkflowDetails.makeUrl(
Expand Down Expand Up @@ -135,28 +113,6 @@ export const ExecutionDetailsAppBarContent: React.FC<{
<TerminateExecutionButton className={styles.actionButton} />
);

const details: DetailItem[] = [
{
className: styles.title,
label: `${project}/${domain}/${workflowId.name}`,
value: name
},
{ label: 'Domain', value: domain },
{
className: styles.version,
label: 'Version',
value: workflowId.version
},
{
label: 'Time',
value: startedAt ? formatDateUTC(timestampToDate(startedAt)) : ''
},
{
label: 'Duration',
value: duration ? protobufDurationToHMS(duration) : ''
}
];

return (
<>
<NavBarContent>
Expand All @@ -165,34 +121,19 @@ export const ExecutionDetailsAppBarContent: React.FC<{
<ArrowBack />
</RouterLink>
<ExecutionStatusBadge phase={phase} type="workflow" />
<div className={styles.detailsContainer}>
{details.map(({ className, label, value }, idx) => (
<div
className={classnames(
styles.detailItem,
className
)}
key={idx}
>
<Typography
className={classnames(
styles.detailLabel,
commonStyles.truncateText
)}
variant="body1"
>
{label}
</Typography>
<div
className={classnames(
styles.detailValue,
commonStyles.truncateText
)}
>
{value}
</div>
</div>
))}
<div className={styles.titleContainer}>
<Typography
variant="body1"
className={classnames(
styles.title,
commonStyles.textWrapped
)}
>
<span>
{`${project}/${domain}/${workflowId.name}/`}
<strong>{`${name}`}</strong>
</span>
</Typography>
</div>
<div className={styles.actions}>
<Link
Expand Down
124 changes: 124 additions & 0 deletions src/components/Executions/ExecutionDetails/ExecutionMetadata.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Typography } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import * as classnames from 'classnames';
import { unknownValueString } from 'common/constants';
import { formatDateUTC, protobufDurationToHMS } from 'common/formatters';
import { timestampToDate } from 'common/utils';
import { useCommonStyles } from 'components/common/styles';
import { secondaryBackgroundColor } from 'components/Theme';
import { Execution } from 'models';
import * as React from 'react';
import { ExpandableExecutionError } from '../Tables/ExpandableExecutionError';
import { ExecutionMetadataLabels } from './constants';

const useStyles = makeStyles((theme: Theme) => {
return {
container: {
background: secondaryBackgroundColor,
display: 'flex',
flexDirection: 'column',
position: 'relative'
},
detailsContainer: {
alignItems: 'center',
display: 'flex',
flex: '0 1 auto',
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(2)
},
detailItem: {
flexShrink: 0,
marginLeft: theme.spacing(4)
},
expandCollapseButton: {
transition: theme.transitions.create('transform'),
'&.expanded': {
transform: 'rotate(180deg)'
}
},
expandCollapseContainer: {
bottom: 0,
position: 'absolute',
right: theme.spacing(2),
transform: 'translateY(100%)',
zIndex: 1
},
version: {
flex: '0 1 auto',
overflow: 'hidden'
}
};
});

interface DetailItem {
className?: string;
label: React.ReactNode;
value: React.ReactNode;
}

/** Renders metadata details about a given Execution */
export const ExecutionMetadata: React.FC<{
execution: Execution;
}> = ({ execution }) => {
const commonStyles = useCommonStyles();
const styles = useStyles();

const { domain } = execution.id;
const { duration, error, startedAt, workflowId } = execution.closure;
const { systemMetadata } = execution.spec.metadata;
const cluster = systemMetadata?.executionCluster ?? unknownValueString;

const details: DetailItem[] = [
{ label: ExecutionMetadataLabels.domain, value: domain },
{
className: styles.version,
label: ExecutionMetadataLabels.version,
value: workflowId.version
},
{
label: ExecutionMetadataLabels.cluster,
value: cluster
}
];
if (startedAt) {
details.push({
label: ExecutionMetadataLabels.time,
value: formatDateUTC(timestampToDate(startedAt))
});
}
if (duration) {
details.push({
label: ExecutionMetadataLabels.duration,
value: protobufDurationToHMS(duration)
});
}

return (
<div className={styles.container}>
<div className={styles.detailsContainer}>
{details.map(({ className, label, value }, idx) => (
<div
className={classnames(styles.detailItem, className)}
key={idx}
>
<Typography
className={commonStyles.truncateText}
variant="subtitle1"
>
{label}
</Typography>
<Typography
className={commonStyles.truncateText}
variant="h6"
data-testid={`metadata-${label}`}
>
{value}
</Typography>
</div>
))}
</div>

{error ? <ExpandableExecutionError error={error} /> : null}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Tab, Tabs } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import { WaitForData } from 'components/common';
import { useTabState } from 'components/hooks/useTabState';
import { secondaryBackgroundColor } from 'components/Theme';
import { Execution } from 'models';
import * as React from 'react';
import { NodeExecutionsRequestConfigContext } from '../contexts';
Expand All @@ -23,6 +24,7 @@ const useStyles = makeStyles((theme: Theme) => ({
minHeight: 0
},
tabs: {
background: secondaryBackgroundColor,
paddingLeft: theme.spacing(3.5)
}
}));
Expand Down
7 changes: 7 additions & 0 deletions src/components/Executions/ExecutionDetails/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export enum ExecutionMetadataLabels {
cluster = 'Cluster',
domain = 'Domain',
duration = 'Duration',
time = 'Time',
version = 'Version'
}
Loading

0 comments on commit d43a1e3

Please sign in to comment.