Feature/pi table ux tweaks (#1133)

* make only the pi id an link on the pi instance table and set up for a refresh button on the table title on the pi list page w/ burnettk

* added refresh pi table button w/ burnettk

* show the process model link in the pi table as well w/ burnettk

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-02-29 10:42:23 -05:00 committed by GitHub
parent 4cf70a8e9b
commit 87fd3ddf65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 114 additions and 68 deletions

View File

@ -1,16 +1,17 @@
import { ArrowRight } from '@carbon/icons-react'; import { ArrowRight, Renew } from '@carbon/icons-react';
import { import {
Grid, Grid,
Column, Column,
TableRow, TableRow,
Table, Table,
TableHeader,
TableHead, TableHead,
Button, Button,
TableHeader,
Stack,
} from '@carbon/react'; } from '@carbon/react';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import 'react-datepicker/dist/react-datepicker.css'; import 'react-datepicker/dist/react-datepicker.css';
import { useNavigate, useSearchParams } from 'react-router-dom'; import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { import {
getLastMilestoneFromProcessInstance, getLastMilestoneFromProcessInstance,
@ -43,6 +44,7 @@ type OwnProps = {
additionalReportFilters?: ReportFilter[]; additionalReportFilters?: ReportFilter[];
autoReload?: boolean; autoReload?: boolean;
canCompleteAllTasks?: boolean; canCompleteAllTasks?: boolean;
filterComponent?: Function;
header?: SpiffTableHeader; header?: SpiffTableHeader;
onProcessInstanceTableListUpdate?: Function; onProcessInstanceTableListUpdate?: Function;
paginationClassName?: string; paginationClassName?: string;
@ -61,6 +63,7 @@ export default function ProcessInstanceListTable({
additionalReportFilters, additionalReportFilters,
autoReload = false, autoReload = false,
canCompleteAllTasks = false, canCompleteAllTasks = false,
filterComponent,
header, header,
onProcessInstanceTableListUpdate, onProcessInstanceTableListUpdate,
paginationClassName, paginationClassName,
@ -225,6 +228,20 @@ export default function ProcessInstanceListTable({
return []; return [];
}; };
const getProcessModelSpanTag = (
processInstance: ProcessInstance,
identifier: string
) => {
const modifiedModelId = modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
);
return (
<span>
<Link to={`/process-models/${modifiedModelId}`}>{identifier}</Link>
</span>
);
};
const getWaitingForTableCellComponent = (processInstanceTask: any) => { const getWaitingForTableCellComponent = (processInstanceTask: any) => {
let fullUsernameString = ''; let fullUsernameString = '';
let shortUsernameString = ''; let shortUsernameString = '';
@ -244,20 +261,31 @@ export default function ProcessInstanceListTable({
} }
return <span title={fullUsernameString}>{shortUsernameString}</span>; return <span title={fullUsernameString}>{shortUsernameString}</span>;
}; };
const formatProcessInstanceId = (_row: ProcessInstance, id: number) => { const formatProcessInstanceId = (
return <span data-qa="paginated-entity-id">{id}</span>; processInstance: ProcessInstance,
id: number
) => {
const modifiedModelId = modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
);
const piLink = `${processInstanceShowPathPrefix}/${modifiedModelId}/${processInstance.id}`;
return (
<span data-qa="paginated-entity-id">
<Link to={piLink}>{id}</Link>
</span>
);
}; };
const formatProcessModelIdentifier = ( const formatProcessModelIdentifier = (
_row: ProcessInstance, processInstance: ProcessInstance,
identifier: any identifier: any
) => { ) => {
return <span>{identifier}</span>; return getProcessModelSpanTag(processInstance, identifier);
}; };
const formatProcessModelDisplayName = ( const formatProcessModelDisplayName = (
_row: ProcessInstance, processInstance: ProcessInstance,
identifier: any identifier: any
) => { ) => {
return <span>{identifier}</span>; return getProcessModelSpanTag(processInstance, identifier);
}; };
const formatLastMilestone = ( const formatLastMilestone = (
processInstance: ProcessInstance, processInstance: ProcessInstance,
@ -337,6 +365,48 @@ export default function ProcessInstanceListTable({
); );
}; };
const tableTitle = () => {
let headerTextElement = null;
if (header) {
headerTextElement = header.text;
// poor man's markdown, just so we can allow bolded words in headers
if (header.text.includes('**')) {
const parts = header.text.split('**');
if (parts.length === 3) {
headerTextElement = (
<>
{parts[0]}
<strong>{parts[1]}</strong>
{parts[2]}
</>
);
}
}
}
if (header) {
return (
<Stack orientation="horizontal" gap={1}>
<h2
title={header.tooltip_text}
className="process-instance-table-header with-icons"
>
{headerTextElement}
</h2>
<Button
kind="ghost"
data-qa="refresh-process-instance-table"
renderIcon={Renew}
iconDescription="Refresh data in the table"
hasIconOnly
onClick={() => getProcessInstances()}
/>
</Stack>
);
}
return null;
};
const tableTitleLine = () => { const tableTitleLine = () => {
if (!showLinkToReport && !header) { if (!showLinkToReport && !header) {
return null; return null;
@ -367,23 +437,6 @@ export default function ProcessInstanceListTable({
if (!header && !filterButtonLink) { if (!header && !filterButtonLink) {
return null; return null;
} }
let headerTextElement = null;
if (header) {
headerTextElement = header.text;
// poor man's markdown, just so we can allow bolded words in headers
if (header.text.includes('**')) {
const parts = header.text.split('**');
if (parts.length === 3) {
headerTextElement = (
<>
{parts[0]}
<strong>{parts[1]}</strong>
{parts[2]}
</>
);
}
}
}
return ( return (
<> <>
<Column <Column
@ -392,14 +445,7 @@ export default function ProcessInstanceListTable({
lg={{ span: 15 }} lg={{ span: 15 }}
style={{ height: '48px' }} style={{ height: '48px' }}
> >
{header ? ( {tableTitle()}
<h2
title={header.tooltip_text}
className="process-instance-table-header"
>
{headerTextElement}
</h2>
) : null}
</Column> </Column>
{filterButtonLink} {filterButtonLink}
</> </>
@ -455,15 +501,6 @@ export default function ProcessInstanceListTable({
} }
} }
const rowStyle = { cursor: 'pointer' };
const modifiedModelId = modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
);
const navigateToProcessInstance = () => {
navigate(
`${processInstanceShowPathPrefix}/${modifiedModelId}/${processInstance.id}`
);
};
let variantFromMetadata = 'all'; let variantFromMetadata = 'all';
if (reportMetadataFromProcessInstances) { if (reportMetadataFromProcessInstances) {
reportMetadataFromProcessInstances.filter_by.forEach((filter: any) => { reportMetadataFromProcessInstances.filter_by.forEach((filter: any) => {
@ -479,10 +516,7 @@ export default function ProcessInstanceListTable({
return ( return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
<tr <tr
style={rowStyle}
key={processInstance.id} key={processInstance.id}
onClick={navigateToProcessInstance}
onKeyDown={navigateToProcessInstance}
className={`process-instance-list-row-variant-${variantFromMetadata}`} className={`process-instance-list-row-variant-${variantFromMetadata}`}
> >
{currentRow} {currentRow}
@ -573,11 +607,16 @@ export default function ProcessInstanceListTable({
); );
} }
return ( return (
<>
<Grid fullWidth condensed className="megacondensed"> <Grid fullWidth condensed className="megacondensed">
{tableTitleLine()} {tableTitleLine()}
</Grid>
{filterComponent ? filterComponent() : null}
<Grid fullWidth condensed className="megacondensed">
<Column sm={{ span: 4 }} md={{ span: 8 }} lg={{ span: 16 }}> <Column sm={{ span: 4 }} md={{ span: 8 }} lg={{ span: 16 }}>
{tableElement} {tableElement}
</Column> </Column>
</Grid> </Grid>
</>
); );
} }

View File

@ -1539,6 +1539,23 @@ export default function ProcessInstanceListTableWithFilters({
] ]
); );
const filterComponent = () => {
return (
<Grid fullWidth condensed className="megacondensed">
<Column sm={{ span: 4 }} md={{ span: 8 }} lg={{ span: 16 }}>
<Filters
filterOptions={filterOptions}
showFilterOptions={showFilterOptions}
setShowFilterOptions={setShowFilterOptions}
reportSearchComponent={reportSearchComponent}
filtersEnabled={filtersEnabled}
reportHash={reportHash}
/>
</Column>
</Grid>
);
};
let resultsTable = null; let resultsTable = null;
if (reportMetadata) { if (reportMetadata) {
const refilterTextComponent = null; const refilterTextComponent = null;
@ -1559,6 +1576,7 @@ export default function ProcessInstanceListTableWithFilters({
tableHtmlId={tableHtmlId} tableHtmlId={tableHtmlId}
textToShowIfEmpty={textToShowIfEmpty} textToShowIfEmpty={textToShowIfEmpty}
variant={variant} variant={variant}
filterComponent={filterComponent}
/> />
</> </>
); );
@ -1569,18 +1587,6 @@ export default function ProcessInstanceListTableWithFilters({
{reportColumnForm()} {reportColumnForm()}
{advancedOptionsModal()} {advancedOptionsModal()}
{processInstanceReportSaveTag()} {processInstanceReportSaveTag()}
<Grid fullWidth condensed className="megacondensed">
<Column sm={{ span: 4 }} md={{ span: 8 }} lg={{ span: 16 }}>
<Filters
filterOptions={filterOptions}
showFilterOptions={showFilterOptions}
setShowFilterOptions={setShowFilterOptions}
reportSearchComponent={reportSearchComponent}
filtersEnabled={filtersEnabled}
reportHash={reportHash}
/>
</Column>
</Grid>
{resultsTable} {resultsTable}
</div> </div>
); );

View File

@ -493,6 +493,6 @@ export interface SpiffTab {
} }
export interface SpiffTableHeader { export interface SpiffTableHeader {
tooltip_text: string; tooltip_text?: string;
text: string; text: string;
} }

View File

@ -41,10 +41,11 @@ export default function ProcessInstanceList({ variant }: OwnProps) {
}; };
const processInstanceTitleElement = () => { const processInstanceTitleElement = () => {
let headerText = 'My Process Instances';
if (variant === 'all') { if (variant === 'all') {
return <h1>All Process Instances</h1>; headerText = 'All Process Instances';
} }
return <h1>My Process Instances</h1>; return { text: headerText };
}; };
return ( return (
@ -52,10 +53,10 @@ export default function ProcessInstanceList({ variant }: OwnProps) {
<ProcessInstanceListTabs variant={variant} /> <ProcessInstanceListTabs variant={variant} />
<br /> <br />
{processInstanceBreadcrumbElement()} {processInstanceBreadcrumbElement()}
{processInstanceTitleElement()}
<ProcessInstanceListTableWithFilters <ProcessInstanceListTableWithFilters
variant={variant} variant={variant}
showActionsColumn showActionsColumn
header={processInstanceTitleElement()}
/> />
</> </>
); );