From eb450709e8e34972386f4e34ee842208e323a3fb Mon Sep 17 00:00:00 2001 From: Jonathan Kilzi Date: Wed, 14 Feb 2024 09:52:43 +0200 Subject: [PATCH] fix(orchestrator): the instance details card content is cropped (#1196) --- .../__fixtures__/fakeWorkflowRunDetails.ts | 12 ++ .../WorkflowInstancePageContent.tsx | 71 ++--------- .../components/WorkflowRunDetails.stories.tsx | 77 ++++++++++++ .../src/components/WorkflowRunDetails.tsx | 110 ++++++++++++++++++ 4 files changed, 208 insertions(+), 62 deletions(-) create mode 100644 plugins/orchestrator/src/__fixtures__/fakeWorkflowRunDetails.ts create mode 100644 plugins/orchestrator/src/components/WorkflowRunDetails.stories.tsx create mode 100644 plugins/orchestrator/src/components/WorkflowRunDetails.tsx diff --git a/plugins/orchestrator/src/__fixtures__/fakeWorkflowRunDetails.ts b/plugins/orchestrator/src/__fixtures__/fakeWorkflowRunDetails.ts new file mode 100644 index 0000000000..1bbd127769 --- /dev/null +++ b/plugins/orchestrator/src/__fixtures__/fakeWorkflowRunDetails.ts @@ -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', +}; diff --git a/plugins/orchestrator/src/components/WorkflowInstancePageContent.tsx b/plugins/orchestrator/src/components/WorkflowInstancePageContent.tsx index cf7eb5ab29..2c0c2f14ec 100644 --- a/plugins/orchestrator/src/components/WorkflowInstancePageContent.tsx +++ b/plugins/orchestrator/src/components/WorkflowInstancePageContent.tsx @@ -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'; @@ -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 = ( @@ -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%', @@ -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: ( - - ), - }, - { 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: ( - - {assessedInstance.assessedBy.processName} - - ), - }); - } - - return labelsAndValues; - }, [ - details.category, - details.description, - details.duration, - details.id, - details.started, - details.status, - workflowInstanceLink, - assessedInstance, - ]); const nextWorkflows = React.useMemo( () => getNextWorkflows(details, executeWorkflowLink), @@ -167,20 +117,17 @@ export const WorkflowInstancePageContent: React.FC<{ return ( - + - - {detailLabelValues.map(item => ( - - - - ))} - + diff --git a/plugins/orchestrator/src/components/WorkflowRunDetails.stories.tsx b/plugins/orchestrator/src/components/WorkflowRunDetails.stories.tsx new file mode 100644 index 0000000000..b986e56047 --- /dev/null +++ b/plugins/orchestrator/src/components/WorkflowRunDetails.stories.tsx @@ -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( + + + + + + + + + +

Nothing fancy here...

+
+
+
+
, + { + mountedRoutes: { + '/orchestrator': orchestratorRootRouteRef, + }, + }, + ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Story1: Story = { + name: 'Very long description', + args: { + assessedBy: fakeCompletedInstance, + details: { + ...fakeWorkflowRunDetail, + description: veryLongString, + }, + }, +}; diff --git a/plugins/orchestrator/src/components/WorkflowRunDetails.tsx b/plugins/orchestrator/src/components/WorkflowRunDetails.tsx new file mode 100644 index 0000000000..fb101d840e --- /dev/null +++ b/plugins/orchestrator/src/components/WorkflowRunDetails.tsx @@ -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 = ({ + assessedBy, + details, +}) => { + const styles = useStyles(); + const workflowInstanceLink = useRouteRef(workflowInstanceRouteRef); + + return ( + + + + + {capitalize(details.category ?? VALUE_UNAVAILABLE)} + + + + + + + + + + + + + + + + {details.duration} + + + + + + + + {details.id} + + + + + + + {details.started} + + + + + {assessedBy ? ( + + + + + + {assessedBy.processName} + + + + + + ) : null} + + + + + {details.description ?? VALUE_UNAVAILABLE} + + + + + ); +}; +WorkflowRunDetails.displayName = 'WorkflowDetails';