Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Expose cluster information for Workflow Executions #78

Merged
merged 8 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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