added some permissions to the process model show page w/ burnettk
This commit is contained in:
parent
b5d2109b89
commit
c57ae77721
|
@ -36,6 +36,7 @@ module.exports = {
|
|||
],
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'react/require-default-props': 'off',
|
||||
'import/prefer-default-export': 'off',
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ export default function App() {
|
|||
[errorMessage]
|
||||
);
|
||||
|
||||
const ability = defineAbility((can: any) => {});
|
||||
const ability = defineAbility(() => {});
|
||||
|
||||
let errorTag = null;
|
||||
if (errorMessage) {
|
||||
|
|
|
@ -74,10 +74,7 @@ export default function ProcessModelForm({
|
|||
if (hasErrors) {
|
||||
return;
|
||||
}
|
||||
let path = `/process-models`;
|
||||
if (mode === 'edit') {
|
||||
path = `/process-models/${modifiedProcessModelPath}`;
|
||||
}
|
||||
const path = `/process-models/${modifiedProcessModelPath}`;
|
||||
let httpMethod = 'POST';
|
||||
if (mode === 'edit') {
|
||||
httpMethod = 'PUT';
|
||||
|
|
|
@ -52,10 +52,14 @@ import TouchModule from 'diagram-js/lib/navigation/touch';
|
|||
// @ts-expect-error TS(7016) FIXME
|
||||
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
|
||||
|
||||
import { Can } from '@casl/react';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
||||
import ButtonWithConfirmation from './ButtonWithConfirmation';
|
||||
import { makeid } from '../helpers';
|
||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||
import { PermissionsToCheck } from '../interfaces';
|
||||
import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||
|
||||
type OwnProps = {
|
||||
processModelId: string;
|
||||
|
@ -107,6 +111,13 @@ export default function ReactDiagramEditor({
|
|||
|
||||
const alreadyImportedXmlRef = useRef(false);
|
||||
|
||||
const { targetUris } = useUriListForPermissions();
|
||||
const permissionRequestData: PermissionsToCheck = {
|
||||
[targetUris.processModelShowPath]: ['PUT'],
|
||||
[targetUris.processModelFileShowPath]: ['POST', 'GET', 'PUT', 'DELETE'],
|
||||
};
|
||||
const { ability } = usePermissionFetcher(permissionRequestData);
|
||||
|
||||
useEffect(() => {
|
||||
if (diagramModelerState) {
|
||||
return;
|
||||
|
@ -517,20 +528,40 @@ export default function ReactDiagramEditor({
|
|||
if (diagramType !== 'readonly') {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={handleSave} variant="danger">
|
||||
Save
|
||||
</Button>
|
||||
{fileName && (
|
||||
<ButtonWithConfirmation
|
||||
description={`Delete file ${fileName}?`}
|
||||
onConfirmation={handleDelete}
|
||||
buttonLabel="Delete"
|
||||
/>
|
||||
)}
|
||||
{onSetPrimaryFile && (
|
||||
<Button onClick={handleSetPrimaryFile}>Set as primary file</Button>
|
||||
)}
|
||||
<Button onClick={downloadXmlFile}>Download xml</Button>
|
||||
<Can
|
||||
I="PUT"
|
||||
a={targetUris.processModelFileShowPath}
|
||||
ability={ability}
|
||||
>
|
||||
<Button onClick={handleSave}>Save</Button>
|
||||
</Can>
|
||||
<Can
|
||||
I="DELETE"
|
||||
a={targetUris.processModelFileShowPath}
|
||||
ability={ability}
|
||||
>
|
||||
{fileName && (
|
||||
<ButtonWithConfirmation
|
||||
description={`Delete file ${fileName}?`}
|
||||
onConfirmation={handleDelete}
|
||||
buttonLabel="Delete"
|
||||
/>
|
||||
)}
|
||||
</Can>
|
||||
<Can I="PUT" a={targetUris.processModelShowPath} ability={ability}>
|
||||
{onSetPrimaryFile && (
|
||||
<Button onClick={handleSetPrimaryFile}>
|
||||
Set as primary file
|
||||
</Button>
|
||||
)}
|
||||
</Can>
|
||||
<Can
|
||||
I="GET"
|
||||
a={targetUris.processModelFileShowPath}
|
||||
ability={ability}
|
||||
>
|
||||
<Button onClick={downloadXmlFile}>Download xml</Button>
|
||||
</Can>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createContext } from 'react';
|
||||
import { AbilityBuilder, Ability } from '@casl/ability';
|
||||
import { Ability } from '@casl/ability';
|
||||
import { createContextualCan } from '@casl/react';
|
||||
|
||||
export const AbilityContext = createContext(new Ability());
|
||||
|
|
|
@ -12,19 +12,17 @@ export const usePermissionFetcher = (
|
|||
useEffect(() => {
|
||||
const processPermissionResult = (result: PermissionCheckResponseBody) => {
|
||||
const { can, cannot, rules } = new AbilityBuilder(Ability);
|
||||
for (const [url, permissionVerbResults] of Object.entries(
|
||||
result.results
|
||||
)) {
|
||||
for (const [permissionVerb, hasPermission] of Object.entries(
|
||||
permissionVerbResults
|
||||
)) {
|
||||
Object.keys(result.results).forEach((url: string) => {
|
||||
const permissionVerbResults = result.results[url];
|
||||
Object.keys(permissionVerbResults).forEach((permissionVerb: string) => {
|
||||
const hasPermission = permissionVerbResults[permissionVerb];
|
||||
if (hasPermission) {
|
||||
can(permissionVerb, url);
|
||||
} else {
|
||||
cannot(permissionVerb, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ability.update(rules);
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
|
|
|
@ -5,8 +5,10 @@ export const useUriListForPermissions = () => {
|
|||
const targetUris = {
|
||||
processGroupListPath: `/v1.0/process-groups`,
|
||||
processGroupShowPath: `/v1.0/process-groups/${params.process_group_id}`,
|
||||
processModelListPath: `/v1.0/process-models`,
|
||||
processModelCreatePath: `/v1.0/process-models/${params.process_group_id}`,
|
||||
processModelShowPath: `/v1.0/process-models/${params.process_model_id}`,
|
||||
processModelFileCreatePath: `/v1.0/process-models/${params.process_model_id}/files`,
|
||||
processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`,
|
||||
processInstanceListPath: `/v1.0/process-instances`,
|
||||
processInstanceActionPath: `/v1.0/process-models/${params.process_model_id}/process-instances`,
|
||||
};
|
||||
|
|
|
@ -35,6 +35,8 @@ export default function ProcessGroupShow() {
|
|||
const { targetUris } = useUriListForPermissions();
|
||||
const permissionRequestData: PermissionsToCheck = {
|
||||
[targetUris.processGroupListPath]: ['POST'],
|
||||
[targetUris.processGroupShowPath]: ['PUT'],
|
||||
[targetUris.processModelCreatePath]: ['POST'],
|
||||
};
|
||||
const { ability } = usePermissionFetcher(permissionRequestData);
|
||||
|
||||
|
@ -159,23 +161,29 @@ export default function ProcessGroupShow() {
|
|||
<Stack orientation="horizontal" gap={3}>
|
||||
<Can I="POST" a={targetUris.processGroupListPath} ability={ability}>
|
||||
<Button
|
||||
kind="secondary"
|
||||
href={`/admin/process-groups/new?parentGroupId=${processGroup.id}`}
|
||||
>
|
||||
Add a process group
|
||||
</Button>
|
||||
</Can>
|
||||
<Button
|
||||
href={`/admin/process-models/${modifiedProcessGroupId}/new`}
|
||||
<Can
|
||||
I="POST"
|
||||
a={targetUris.processModelCreatePath}
|
||||
ability={ability}
|
||||
>
|
||||
Add a process model
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-groups/${modifiedProcessGroupId}/edit`}
|
||||
variant="secondary"
|
||||
>
|
||||
Edit process group
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${modifiedProcessGroupId}/new`}
|
||||
>
|
||||
Add a process model
|
||||
</Button>
|
||||
</Can>
|
||||
<Can I="PUT" a={targetUris.processGroupShowPath} ability={ability}>
|
||||
<Button
|
||||
href={`/admin/process-groups/${modifiedProcessGroupId}/edit`}
|
||||
>
|
||||
Edit process group
|
||||
</Button>
|
||||
</Can>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
|
|
|
@ -106,9 +106,10 @@ export default function ProcessModelShow() {
|
|||
|
||||
const { targetUris } = useUriListForPermissions();
|
||||
const permissionRequestData: PermissionsToCheck = {
|
||||
[targetUris.processModelShowPath]: ['GET', 'PUT'],
|
||||
[targetUris.processModelShowPath]: ['PUT'],
|
||||
[targetUris.processInstanceListPath]: ['GET'],
|
||||
[targetUris.processInstanceActionPath]: ['POST'],
|
||||
[targetUris.processModelFileCreatePath]: ['POST', 'GET', 'DELETE'],
|
||||
};
|
||||
const { ability } = usePermissionFetcher(permissionRequestData);
|
||||
|
||||
|
@ -263,50 +264,62 @@ export default function ProcessModelShow() {
|
|||
) => {
|
||||
const elements = [];
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Edit}
|
||||
iconDescription="Edit File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
data-qa={`edit-file-${processModelFile.name.replace('.', '-')}`}
|
||||
onClick={() => navigateToFileEdit(processModelFile)}
|
||||
/>
|
||||
<Can I="GET" a={targetUris.processModelFileCreatePath} ability={ability}>
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Edit}
|
||||
iconDescription="Edit File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
data-qa={`edit-file-${processModelFile.name.replace('.', '-')}`}
|
||||
onClick={() => navigateToFileEdit(processModelFile)}
|
||||
/>
|
||||
</Can>
|
||||
);
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Download}
|
||||
iconDescription="Download File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => downloadFile(processModelFile.name)}
|
||||
/>
|
||||
<Can I="GET" a={targetUris.processModelFileCreatePath} ability={ability}>
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Download}
|
||||
iconDescription="Download File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => downloadFile(processModelFile.name)}
|
||||
/>
|
||||
</Can>
|
||||
);
|
||||
|
||||
elements.push(
|
||||
<ButtonWithConfirmation
|
||||
kind="ghost"
|
||||
renderIcon={TrashCan}
|
||||
iconDescription="Delete File"
|
||||
hasIconOnly
|
||||
description={`Delete file: ${processModelFile.name}`}
|
||||
onConfirmation={() => {
|
||||
onDeleteFile(processModelFile.name);
|
||||
}}
|
||||
confirmButtonLabel="Delete"
|
||||
/>
|
||||
<Can
|
||||
I="DELETE"
|
||||
a={targetUris.processModelFileCreatePath}
|
||||
ability={ability}
|
||||
>
|
||||
<ButtonWithConfirmation
|
||||
kind="ghost"
|
||||
renderIcon={TrashCan}
|
||||
iconDescription="Delete File"
|
||||
hasIconOnly
|
||||
description={`Delete file: ${processModelFile.name}`}
|
||||
onConfirmation={() => {
|
||||
onDeleteFile(processModelFile.name);
|
||||
}}
|
||||
confirmButtonLabel="Delete"
|
||||
/>
|
||||
</Can>
|
||||
);
|
||||
if (processModelFile.name.match(/\.bpmn$/) && !isPrimaryBpmnFile) {
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Favorite}
|
||||
iconDescription="Set As Primary File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => onSetPrimaryFile(processModelFile.name)}
|
||||
/>
|
||||
<Can I="PUT" a={targetUris.processModelShowPath} ability={ability}>
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Favorite}
|
||||
iconDescription="Set As Primary File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => onSetPrimaryFile(processModelFile.name)}
|
||||
/>
|
||||
</Can>
|
||||
);
|
||||
}
|
||||
return elements;
|
||||
|
@ -337,7 +350,11 @@ export default function ProcessModelShow() {
|
|||
let fileLink = null;
|
||||
const fileUrl = profileModelFileEditUrl(processModelFile);
|
||||
if (fileUrl) {
|
||||
fileLink = <Link to={fileUrl}>{processModelFile.name}</Link>;
|
||||
if (ability.can('GET', targetUris.processModelFileCreatePath)) {
|
||||
fileLink = <Link to={fileUrl}>{processModelFile.name}</Link>;
|
||||
} else {
|
||||
fileLink = <span>{processModelFile.name}</span>;
|
||||
}
|
||||
}
|
||||
constructedTag = (
|
||||
<TableRow key={processModelFile.name}>
|
||||
|
@ -442,47 +459,53 @@ export default function ProcessModelShow() {
|
|||
</Stack>
|
||||
}
|
||||
>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
renderIcon={Upload}
|
||||
data-qa="upload-file-button"
|
||||
onClick={() => setShowFileUploadModal(true)}
|
||||
size="sm"
|
||||
kind=""
|
||||
className="button-white-background"
|
||||
>
|
||||
Upload File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=bpmn`}
|
||||
size="sm"
|
||||
>
|
||||
New BPMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=dmn`}
|
||||
size="sm"
|
||||
>
|
||||
New DMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=json`}
|
||||
size="sm"
|
||||
>
|
||||
New JSON File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=md`}
|
||||
size="sm"
|
||||
>
|
||||
New Markdown File
|
||||
</Button>
|
||||
</ButtonSet>
|
||||
<br />
|
||||
<Can
|
||||
I="POST"
|
||||
a={targetUris.processModelFileCreatePath}
|
||||
ability={ability}
|
||||
>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
renderIcon={Upload}
|
||||
data-qa="upload-file-button"
|
||||
onClick={() => setShowFileUploadModal(true)}
|
||||
size="sm"
|
||||
kind=""
|
||||
className="button-white-background"
|
||||
>
|
||||
Upload File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=bpmn`}
|
||||
size="sm"
|
||||
>
|
||||
New BPMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=dmn`}
|
||||
size="sm"
|
||||
>
|
||||
New DMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=json`}
|
||||
size="sm"
|
||||
>
|
||||
New JSON File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=md`}
|
||||
size="sm"
|
||||
>
|
||||
New Markdown File
|
||||
</Button>
|
||||
</ButtonSet>
|
||||
<br />
|
||||
</Can>
|
||||
{processModelFileList()}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
|
Loading…
Reference in New Issue