Skip to content

Commit

Permalink
fix(orchestrator): the instance details card content is cropped (#1196)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkilzi authored Feb 14, 2024
1 parent 5b04db9 commit eb45070
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 62 deletions.
12 changes: 12 additions & 0 deletions plugins/orchestrator/src/__fixtures__/fakeWorkflowRunDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { WorkflowRunDetail } from '../components/WorkflowRunDetail';

export const fakeWorkflowRunDetail: WorkflowRunDetail = {
id: '1691fab4-45ce-44d8-840d-5573dfe809b8',
name: 'Assessment Workflow',
workflowId: 'assessment',
started: '2/13/2024, 10:58:26 AM',
duration: 'a few seconds',
category: 'assessment',
status: 'COMPLETED',
description: 'Simple workflow to simulate assessment',
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';

import { Content, InfoCard, Link } from '@backstage/core-components';
import { PathParams, RouteFunc, useRouteRef } from '@backstage/core-plugin-api';
import { AboutField } from '@backstage/plugin-catalog';

import { Grid, makeStyles } from '@material-ui/core';
import moment from 'moment';
Expand All @@ -11,18 +10,16 @@ import {
AssessedProcessInstance,
parseWorkflowVariables,
ProcessInstance,
ProcessInstanceStateValues,
QUERY_PARAM_ASSESSMENT_INSTANCE_ID,
} from '@janus-idp/backstage-plugin-orchestrator-common';

import { VALUE_UNAVAILABLE } from '../constants';
import { executeWorkflowRouteRef, workflowInstanceRouteRef } from '../routes';
import { capitalize } from '../utils/StringUtils';
import { executeWorkflowRouteRef } from '../routes';
import { buildUrl } from '../utils/UrlUtils';
import { EditorViewKind, WorkflowEditor } from './WorkflowEditor';
import { WorkflowInstanceStatusIndicator } from './WorkflowInstanceStatusIndicator';
import { WorkflowProgress } from './WorkflowProgress';
import { WorkflowRunDetail, WorkflowSuggestion } from './WorkflowRunDetail';
import { WorkflowRunDetails } from './WorkflowRunDetails';
import { WorkflowVariablesViewer } from './WorkflowVariablesViewer';

export const mapProcessInstanceToDetails = (
Expand Down Expand Up @@ -87,10 +84,10 @@ const getNextWorkflows = (

const useStyles = makeStyles(_ => ({
topRowCard: {
height: '258px',
height: '20rem',
},
middleRowCard: {
height: 'calc(2 * 258px)',
height: 'calc(2 * 20rem)',
},
bottomRowCard: {
height: '100%',
Expand All @@ -103,57 +100,10 @@ export const WorkflowInstancePageContent: React.FC<{
}> = ({ assessedInstance }) => {
const styles = useStyles();
const executeWorkflowLink = useRouteRef(executeWorkflowRouteRef);
const workflowInstanceLink = useRouteRef(workflowInstanceRouteRef);
const details = React.useMemo(
() => mapProcessInstanceToDetails(assessedInstance.instance),
[assessedInstance.instance],
);
const detailLabelValues = React.useMemo(() => {
const labelsAndValues = [
{
label: 'Category',
value: capitalize(details.category ?? VALUE_UNAVAILABLE),
},
{
label: 'Status',
value: (
<WorkflowInstanceStatusIndicator
status={details.status as ProcessInstanceStateValues}
/>
),
},
{ label: 'Duration', value: details.duration },
{ label: 'ID', value: details.id },
{ label: 'Started', value: details.started },
{ label: 'Description', value: details.description },
];

if (assessedInstance.assessedBy) {
labelsAndValues.push({
label: 'Assessed by',
value: (
<Link
to={workflowInstanceLink({
instanceId: assessedInstance.assessedBy.id,
})}
>
{assessedInstance.assessedBy.processName}
</Link>
),
});
}

return labelsAndValues;
}, [
details.category,
details.description,
details.duration,
details.id,
details.started,
details.status,
workflowInstanceLink,
assessedInstance,
]);

const nextWorkflows = React.useMemo(
() => getNextWorkflows(details, executeWorkflowLink),
Expand All @@ -167,20 +117,17 @@ export const WorkflowInstancePageContent: React.FC<{

return (
<Content noPadding>
<Grid container>
<Grid container spacing={2}>
<Grid item xs={6}>
<InfoCard
title="Details"
divider={false}
className={styles.topRowCard}
>
<Grid container spacing={3}>
{detailLabelValues.map(item => (
<Grid item xs={3} key={item.label}>
<AboutField label={item.label} value={item.value as string} />
</Grid>
))}
</Grid>
<WorkflowRunDetails
details={details}
assessedBy={assessedInstance.assessedBy}
/>
</InfoCard>
</Grid>

Expand Down
77 changes: 77 additions & 0 deletions plugins/orchestrator/src/components/WorkflowRunDetails.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';

import { Content, InfoCard } from '@backstage/core-components';
import { wrapInTestApp } from '@backstage/test-utils';

import { makeStyles } from '@material-ui/core';
import Grid from '@material-ui/core/Grid/Grid';
import { Meta, StoryObj } from '@storybook/react';

import { fakeCompletedInstance } from '../__fixtures__/fakeProcessInstance';
import { fakeWorkflowRunDetail } from '../__fixtures__/fakeWorkflowRunDetails';
import { veryLongString } from '../__fixtures__/veryLongString';
import { orchestratorRootRouteRef } from '../routes';
import { WorkflowRunDetails } from './WorkflowRunDetails';

const useStyles = makeStyles(_ => ({
topRowCard: {
height: '20rem',
},
}));

const meta = {
title: 'Orchestrator/WorkflowDetails',
component: WorkflowRunDetails,
parameters: {
backgrounds: {
default: 'dark',
},
layout: 'padded',
},
decorators: [
Story =>
wrapInTestApp(
<Content noPadding>
<Grid container spacing={2}>
<Grid item xs={6}>
<InfoCard
title="Details"
divider={false}
className={useStyles().topRowCard}
>
<Story />
</InfoCard>
</Grid>
<Grid item xs={6}>
<InfoCard
title="Another card"
divider={false}
className={useStyles().topRowCard}
>
<p>Nothing fancy here...</p>
</InfoCard>
</Grid>
</Grid>
</Content>,
{
mountedRoutes: {
'/orchestrator': orchestratorRootRouteRef,
},
},
),
],
} satisfies Meta<typeof WorkflowRunDetails>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Story1: Story = {
name: 'Very long description',
args: {
assessedBy: fakeCompletedInstance,
details: {
...fakeWorkflowRunDetail,
description: veryLongString,
},
},
};
110 changes: 110 additions & 0 deletions plugins/orchestrator/src/components/WorkflowRunDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';

import { Link } from '@backstage/core-components';
import { useRouteRef } from '@backstage/core-plugin-api';
import { AboutField } from '@backstage/plugin-catalog';

import { Grid, makeStyles, Typography } from '@material-ui/core';

import {
ProcessInstance,
ProcessInstanceStateValues,
} from '@janus-idp/backstage-plugin-orchestrator-common';

import { VALUE_UNAVAILABLE } from '../constants';
import { workflowInstanceRouteRef } from '../routes';
import { capitalize } from '../utils/StringUtils';
import { WorkflowInstanceStatusIndicator } from './WorkflowInstanceStatusIndicator';
import { WorkflowRunDetail } from './WorkflowRunDetail';

type WorkflowDetailsCardProps = {
assessedBy?: ProcessInstance;
details: WorkflowRunDetail;
};

const useStyles = makeStyles({
root: {
overflowY: 'auto',
height: '15rem',
},
});

export const WorkflowRunDetails: React.FC<WorkflowDetailsCardProps> = ({
assessedBy,
details,
}) => {
const styles = useStyles();
const workflowInstanceLink = useRouteRef(workflowInstanceRouteRef);

return (
<Grid container className={styles.root} alignContent="flex-start">
<Grid item md={4} key="Category">
<AboutField label="Category">
<Typography variant="subtitle2" component="div">
<b>{capitalize(details.category ?? VALUE_UNAVAILABLE)}</b>
</Typography>
</AboutField>
</Grid>
<Grid item md={4} key="Status">
<AboutField label="Status">
<Typography variant="subtitle2" component="div">
<b>
<WorkflowInstanceStatusIndicator
status={details.status as ProcessInstanceStateValues}
/>
</b>
</Typography>
</AboutField>
</Grid>
<Grid item md={4} key="Duration">
<AboutField label="Duration">
<Typography variant="subtitle2" component="div">
<b>{details.duration}</b>
</Typography>
</AboutField>
</Grid>

<Grid item md={8} key="ID">
<AboutField label="ID">
<Typography variant="subtitle2" component="div">
<b>{details.id}</b>
</Typography>
</AboutField>
</Grid>
<Grid item md={4} key="Started">
<AboutField label="Started">
<Typography variant="subtitle2" component="div">
<b>{details.started}</b>
</Typography>
</AboutField>
</Grid>

{assessedBy ? (
<Grid item md={12} key="Assessed by">
<AboutField label="Assessed by">
<Typography variant="subtitle2" component="div">
<b>
<Link
to={workflowInstanceLink({
instanceId: assessedBy.id,
})}
>
{assessedBy.processName}
</Link>
</b>
</Typography>
</AboutField>
</Grid>
) : null}

<Grid item md={12} key="Description">
<AboutField label="Description">
<Typography variant="subtitle2" component="div">
<b>{details.description ?? VALUE_UNAVAILABLE}</b>
</Typography>
</AboutField>
</Grid>
</Grid>
);
};
WorkflowRunDetails.displayName = 'WorkflowDetails';

0 comments on commit eb45070

Please sign in to comment.