feature/full-breadcrumb-on-task-show (#675)

* show the full breadcrumb on task show page w/ burnettk

* check read permission of process model before displaying in breadcrumb on task show page

* in the breadcrumb if the api returns 401 then just ignore the breadcrumb

* pyl

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2023-11-16 10:05:08 -05:00 committed by GitHub
parent 32f8ca5154
commit 1eed6e2444
6 changed files with 110 additions and 71 deletions

View File

@ -17,6 +17,8 @@ groups:
users: [jason@sartography.com, kevin@sartography.com]
group2:
users: [dan@sartography.com]
group3:
users: [jon@sartography.com]
permissions:
admin:
@ -25,7 +27,7 @@ permissions:
uri: /*
basic:
groups: [group2]
groups: [group2, group3]
actions: [all]
uri: BASIC

View File

@ -158,7 +158,8 @@ def process_model_show(modified_process_model_identifier: str, include_file_refe
process_model.bpmn_version_control_identifier = current_git_revision
available_actions = {}
# if the user got here then they can read the process model
available_actions = {"read": {"path": f"/process-models/{modified_process_model_identifier}", "method": "GET"}}
if GitService.check_for_publish_configs(raise_on_missing=False):
available_actions = {
"publish": {"path": f"/process-model-publish/{modified_process_model_identifier}", "method": "POST"}

View File

@ -4,6 +4,8 @@ import { useEffect, useState } from 'react';
import { modifyProcessIdentifierForPathParam } from '../helpers';
import {
HotCrumbItem,
HotCrumbItemArray,
HotCrumbItemObject,
ProcessGroup,
ProcessGroupLite,
ProcessModel,
@ -29,6 +31,7 @@ export default function ProcessBreadcrumb({ hotCrumbs }: OwnProps) {
entityToExplode as string
)}`,
successCallback: setProcessEntity,
onUnauthorized: () => {},
});
} else if (entityType === 'process-group-id') {
HttpService.makeCallToBackend({
@ -36,6 +39,7 @@ export default function ProcessBreadcrumb({ hotCrumbs }: OwnProps) {
entityToExplode as string
)}`,
successCallback: setProcessEntity,
onUnauthorized: () => {},
});
} else {
setProcessEntity(entityToExplode as any);
@ -47,74 +51,91 @@ export default function ProcessBreadcrumb({ hotCrumbs }: OwnProps) {
}
}, [setProcessEntity, hotCrumbs]);
const checkPermissions = (crumb: HotCrumbItemObject) => {
if (!crumb.checkPermission) {
return true;
}
return (
processEntity &&
'actions' in processEntity &&
processEntity.actions &&
'read' in processEntity.actions
);
};
// eslint-disable-next-line sonarjs/cognitive-complexity
const hotCrumbElement = () => {
if (hotCrumbs) {
const leadingCrumbLinks = hotCrumbs.map((crumb: any) => {
if (
'entityToExplode' in crumb &&
processEntity &&
processEntity.parent_groups
) {
const breadcrumbs = processEntity.parent_groups.map(
(parentGroup: ProcessGroupLite) => {
const fullUrl = `/process-groups/${modifyProcessIdentifierForPathParam(
parentGroup.id
const leadingCrumbLinks = hotCrumbs.map(
(crumb: HotCrumbItemArray | HotCrumbItemObject) => {
if (
'entityToExplode' in crumb &&
processEntity &&
processEntity.parent_groups &&
checkPermissions(crumb)
) {
const breadcrumbs = processEntity.parent_groups.map(
(parentGroup: ProcessGroupLite) => {
const fullUrl = `/process-groups/${modifyProcessIdentifierForPathParam(
parentGroup.id
)}`;
return (
<BreadcrumbItem key={parentGroup.id} href={fullUrl}>
{parentGroup.display_name}
</BreadcrumbItem>
);
}
);
if (crumb.linkLastItem) {
let apiBase = '/process-groups';
let dataQaTag = '';
if (crumb.entityType.startsWith('process-model')) {
apiBase = '/process-models';
dataQaTag = 'process-model-breadcrumb-link';
}
const fullUrl = `${apiBase}/${modifyProcessIdentifierForPathParam(
processEntity.id
)}`;
return (
<BreadcrumbItem key={parentGroup.id} href={fullUrl}>
{parentGroup.display_name}
breadcrumbs.push(
<BreadcrumbItem
key={processEntity.id}
href={fullUrl}
data-qa={dataQaTag}
>
{processEntity.display_name}
</BreadcrumbItem>
);
} else {
breadcrumbs.push(
<BreadcrumbItem key={processEntity.id} isCurrentPage>
{processEntity.display_name}
</BreadcrumbItem>
);
}
);
if (crumb.linkLastItem) {
let apiBase = '/process-groups';
let dataQaTag = '';
if (crumb.entityType.startsWith('process-model')) {
apiBase = '/process-models';
dataQaTag = 'process-model-breadcrumb-link';
}
const fullUrl = `${apiBase}/${modifyProcessIdentifierForPathParam(
processEntity.id
)}`;
breadcrumbs.push(
<BreadcrumbItem
key={processEntity.id}
href={fullUrl}
data-qa={dataQaTag}
>
{processEntity.display_name}
</BreadcrumbItem>
);
} else {
breadcrumbs.push(
<BreadcrumbItem key={processEntity.id} isCurrentPage>
{processEntity.display_name}
</BreadcrumbItem>
);
return breadcrumbs;
}
return breadcrumbs;
if (Array.isArray(crumb)) {
const valueLabel = crumb[0];
const url = crumb[1];
if (!url && valueLabel) {
return (
<BreadcrumbItem isCurrentPage key={valueLabel}>
{valueLabel}
</BreadcrumbItem>
);
}
if (url && valueLabel) {
return (
<BreadcrumbItem key={valueLabel} href={url}>
{valueLabel}
</BreadcrumbItem>
);
}
}
return null;
}
const valueLabel = crumb[0];
const url = crumb[1];
if (!url && valueLabel) {
return (
<BreadcrumbItem isCurrentPage key={valueLabel}>
{valueLabel}
</BreadcrumbItem>
);
}
if (url && valueLabel) {
return (
<BreadcrumbItem key={valueLabel} href={url}>
{valueLabel}
</BreadcrumbItem>
);
}
return null;
});
);
return <Breadcrumb noTrailingSlash>{leadingCrumbLinks}</Breadcrumb>;
}
return null;

View File

@ -6,6 +6,20 @@ import { AbilityContext } from '../contexts/Can';
import { PermissionCheckResponseBody, PermissionsToCheck } from '../interfaces';
import HttpService from '../services/HttpService';
export const checkPermissions = (
permissionsToCheck: PermissionsToCheck,
successCallback: Function
) => {
if (Object.keys(permissionsToCheck).length !== 0) {
HttpService.makeCallToBackend({
path: `/permissions-check`,
httpMethod: 'POST',
successCallback,
postBody: { requests_to_check: permissionsToCheck },
});
}
};
export const usePermissionFetcher = (
permissionsToCheck: PermissionsToCheck
) => {
@ -37,14 +51,7 @@ export const usePermissionFetcher = (
ability.update(rules);
setPermissionsLoaded(true);
};
if (Object.keys(permissionsToCheck).length !== 0) {
HttpService.makeCallToBackend({
path: `/permissions-check`,
httpMethod: 'POST',
successCallback: processPermissionResult,
postBody: { requests_to_check: permissionsToCheck },
});
}
checkPermissions(permissionsToCheck, processPermissionResult);
});
return { ability, permissionsLoaded };

View File

@ -299,6 +299,7 @@ export interface HotCrumbItemObject {
entityToExplode: ProcessModel | ProcessGroup | string;
entityType: string;
linkLastItem?: boolean;
checkPermission?: boolean;
}
export type HotCrumbItemArray = [displayValue: string, url?: string];

View File

@ -411,11 +411,18 @@ export default function TaskShow() {
pageElements.push(
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/process-groups'],
{
entityToExplode: basicTask.process_model_identifier,
entityType: 'process-model-id',
linkLastItem: true,
checkPermission: true,
},
[
`Process Instance Id: ${params.process_instance_id}`,
`Process Instance Id: ${basicTask.process_instance_id}`,
`/process-instances/for-me/${modifyProcessIdentifierForPathParam(
basicTask.process_model_identifier
)}/${params.process_instance_id}`,
)}/${basicTask.process_instance_id}`,
],
[`Task: ${basicTask.name_for_display || basicTask.id}`],
]}