Skip to content

Commit 4c3970f

Browse files
authored
Merge pull request #772 from PROCEED-Labs/show-archived-deployments
Show Archived Deployments
2 parents 42d273f + 6fe5767 commit 4c3970f

13 files changed

Lines changed: 268 additions & 119 deletions

File tree

src/management-system-v2/app/(dashboard)/[environmentId]/(automation)/executions/[processId]/instance-helpers.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { StoredDeployment } from '@/lib/data/deployment';
22
import { ExtendedInstanceInfo } from '@/lib/data/instance';
33
import { InstanceInfo } from '@/lib/engines/deployment';
4+
import { Version } from '@prisma/client';
45
import { convertISODurationToMiliseconds } from '@proceed/bpmn-helper/src/getters';
56
import type { ElementLike } from 'diagram-js/lib/core/Types';
67

@@ -179,15 +180,15 @@ export function getVersionInstances(instances: ExtendedInstanceInfo[], version?:
179180
return instances.filter((instance) => instance.processVersion === version);
180181
}
181182

182-
export function getLatestDeployment(deployments: StoredDeployment[]) {
183-
return deployments.reduce(
183+
export function getLatestVersion(versions: Version[]) {
184+
return versions.reduce(
184185
(latest, curr) => {
185-
if (!latest || latest.deployTime.getTime() > curr.deployTime.getTime()) {
186+
if (!latest || latest.createdOn.getTime() < curr.createdOn.getTime()) {
186187
return curr;
187188
}
188189
return latest;
189190
},
190-
undefined as undefined | StoredDeployment,
191+
undefined as undefined | Version,
191192
);
192193
}
193194

src/management-system-v2/app/(dashboard)/[environmentId]/(automation)/executions/[processId]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { isUserErrorResponse } from '@/lib/user-error';
77
import { getProcessDeployments } from '@/lib/data/deployment';
88

99
async function Deployment({ processId, spaceId }: { processId: string; spaceId: string }) {
10-
const deployments = await getProcessDeployments(spaceId, processId);
10+
const deployments = await getProcessDeployments(spaceId, processId, undefined, true, true);
1111

1212
if (isUserErrorResponse(deployments)) {
1313
return (

src/management-system-v2/app/(dashboard)/[environmentId]/(automation)/executions/[processId]/process-deployment-view.tsx

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { ColorOptions, colorOptions } from './instance-coloring';
2626
import { RemoveReadOnly, truthyFilter } from '@/lib/typescript-utils';
2727
import type { ElementLike } from 'diagram-js/lib/core/Types';
2828
import { wrapServerCall } from '@/lib/wrap-server-call';
29-
import { getLatestDeployment, getVersionInstances, getYoungestInstance } from './instance-helpers';
29+
import { getLatestVersion, getVersionInstances, getYoungestInstance } from './instance-helpers';
3030

3131
import useColors from './use-colors';
3232
import useTokens from './use-tokens';
@@ -53,8 +53,8 @@ import { useQuery } from '@tanstack/react-query';
5353
import { getProcessDeployments } from '@/lib/data/deployment';
5454
import { isSuccessResponse, isUserErrorResponse, userError } from '@/lib/user-error';
5555
import { getInstance } from '@/lib/data/instance';
56-
import { asyncMap, pick } from '@/lib/helpers/javascriptHelpers';
57-
import { getProcessBPMN } from '@/lib/data/processes';
56+
import { asyncFilter, asyncMap, pick } from '@/lib/helpers/javascriptHelpers';
57+
import { getVersions } from '@/lib/data/processes';
5858
import { enableInstanceCSVExport } from 'FeatureFlags';
5959
import jsonToCsvExport from 'json-to-csv-export';
6060

@@ -80,10 +80,40 @@ export default function ProcessDeploymentView({ processId }: { processId: string
8080
const canvasRef = useRef<BPMNCanvasRef>(null);
8181
const [infoPanelOpen, setInfoPanelOpen] = useState(false);
8282

83+
const isExecutableVersionMap = useRef<Record<string, boolean>>({});
84+
85+
const { data: versions } = useQuery({
86+
queryFn: async () => {
87+
let versions = await getVersions(spaceId, processId);
88+
if (isUserErrorResponse(versions)) return [];
89+
90+
// filter out all versions that are not executable
91+
versions = await asyncFilter(versions, async (version) => {
92+
if (version.id in isExecutableVersionMap.current) {
93+
return isExecutableVersionMap.current[version.id];
94+
}
95+
96+
const bpmnObj = await toBpmnObject(version.bpmn);
97+
const processes = getElementsByTagName(bpmnObj, 'bpmn:Process');
98+
if (!processes.length) return false;
99+
isExecutableVersionMap.current[version.id] = processes[0].isExecutable;
100+
return processes[0].isExecutable;
101+
});
102+
103+
versions.sort((a, b) => {
104+
return b.createdOn.getTime() - a.createdOn.getTime();
105+
});
106+
107+
return versions;
108+
},
109+
queryKey: ['processVersions', spaceId, processId],
110+
refetchInterval: 1000,
111+
});
112+
83113
// get information where the process is deployed and which instances exist
84114
const { data: deployments, refetch: refetchDeployments } = useQuery({
85115
queryFn: async () => {
86-
const deployments = await getProcessDeployments(spaceId, processId);
116+
const deployments = await getProcessDeployments(spaceId, processId, undefined, true, true);
87117
if (isUserErrorResponse(deployments)) return null;
88118
return deployments;
89119
},
@@ -130,8 +160,8 @@ export default function ProcessDeploymentView({ processId }: { processId: string
130160
const { selectedVersion, versionInstances, currentVersion } = useMemo(() => {
131161
let selectedVersion, versionInstances, currentVersion;
132162

133-
if (deployments?.length) {
134-
selectedVersion = deployments.find((d) => d.versionId === selectedVersionId)?.version;
163+
if (versions?.length) {
164+
selectedVersion = versions.find((v) => v.id === selectedVersionId);
135165

136166
// sort instances newest first
137167
const rawInstances = getVersionInstances(knownInstances, selectedVersionId);
@@ -143,21 +173,21 @@ export default function ProcessDeploymentView({ processId }: { processId: string
143173
? versionInstances.find((i) => i.processInstanceId === selectedInstanceId)
144174
: undefined;
145175

146-
let currentVersionId = getLatestDeployment(deployments)!.versionId;
176+
let currentVersionId = getLatestVersion(versions)!.id;
147177
if (selectedInstance) {
148178
currentVersionId = selectedInstance.processVersion;
149179
} else if (selectedVersionId) {
150180
currentVersionId = selectedVersionId;
151181
}
152-
currentVersion = deployments.find((d) => d.versionId === currentVersionId)!.version;
182+
currentVersion = versions.find((v) => v.id === currentVersionId);
153183
}
154184

155185
return {
156186
selectedVersion,
157187
versionInstances,
158188
currentVersion,
159189
};
160-
}, [deployments, knownInstances, selectedVersionId, selectedInstanceId]);
190+
}, [versions, knownInstances, selectedVersionId, selectedInstanceId]);
161191

162192
const { data: currentInstance, refetch: refetchCurrentInstance } = useQuery({
163193
queryKey: ['processDeployments', spaceId, processId, 'instance', selectedInstanceId],
@@ -179,9 +209,7 @@ export default function ProcessDeploymentView({ processId }: { processId: string
179209

180210
const { data: selectedBpmn } = useQuery({
181211
queryFn: async () => {
182-
const bpmn = await getProcessBPMN(processId, spaceId, currentVersion?.id);
183-
if (isUserErrorResponse(bpmn)) return undefined;
184-
return { bpmn };
212+
return { bpmn: currentVersion?.bpmn || '' };
185213
},
186214
queryKey: ['space', spaceId, 'process', processId, 'version', currentVersion?.id || '', 'bpmn'],
187215
});
@@ -315,11 +343,11 @@ export default function ProcessDeploymentView({ processId }: { processId: string
315343
},
316344
]
317345
: []),
318-
...deployments.map(({ version }) => ({
319-
label: version.name,
320-
key: `${version.id}`,
346+
...(versions?.map((v) => ({
347+
key: v.id,
348+
label: v.name,
321349
disabled: false,
322-
})),
350+
})) || []),
323351
],
324352
selectable: true,
325353
onSelect: ({ key }) => {
@@ -370,14 +398,7 @@ export default function ProcessDeploymentView({ processId }: { processId: string
370398
setStartingInstance(true);
371399
await wrapServerCall({
372400
fn: async () => {
373-
const latestDeployment = getLatestDeployment(deployments);
374-
if (!latestDeployment) {
375-
return userError(
376-
'The current process does not seem to be deployed anymore.',
377-
);
378-
}
379-
380-
const { versionId } = latestDeployment;
401+
const { id: versionId } = currentVersion!;
381402

382403
let startForm = await getProcessStartForm(spaceId, processId, versionId);
383404

@@ -451,7 +472,7 @@ export default function ProcessDeploymentView({ processId }: { processId: string
451472
onClick={async () => {
452473
setTogglingActivation(true);
453474
const nextState = !isProcessActivated;
454-
const versionId = getLatestDeployment(deployments)!.versionId;
475+
const versionId = currentVersion!.id;
455476
await wrapServerCall({
456477
fn: () =>
457478
changeDeploymentActivation(processId, spaceId, versionId, nextState),
@@ -641,10 +662,10 @@ export default function ProcessDeploymentView({ processId }: { processId: string
641662
// start the instance with the initial variable values from the start form
642663
await wrapServerCall({
643664
fn: async () => {
644-
const deployment = getLatestDeployment(deployments);
645-
646-
if (!deployment) {
647-
return userError('The current process does not seem to be deployed.');
665+
if (!currentVersion) {
666+
return userError(
667+
'The current process does not seem to have versions to execute.',
668+
);
648669
}
649670

650671
const mappedVariables: Record<string, { value: any }> = {};
@@ -656,8 +677,8 @@ export default function ProcessDeploymentView({ processId }: { processId: string
656677

657678
return startInstance(
658679
spaceId,
659-
deployment.processId,
660-
deployment.version.id,
680+
currentVersion.processId,
681+
currentVersion.id,
661682
mappedVariables,
662683
);
663684
},

src/management-system-v2/app/(dashboard)/[environmentId]/(automation)/executions/deployments-list.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import processListStyles from '@/components/process-icon-list.module.scss';
1111
type InputItem = {
1212
id: string;
1313
name: string;
14-
versions: { id: string; name: string }[];
14+
versions: { id: string; name: string; deployed: boolean }[];
1515
instances: string[];
1616
};
1717
export type DeployedProcessListProcess = ReplaceKeysWithHighlighted<InputItem, 'name'>;
@@ -95,9 +95,13 @@ const DeploymentsList = ({
9595
dataIndex: 'id',
9696
key: 'Meta Data Button',
9797
title: '',
98-
render: () => {
98+
render: (_, record) => {
9999
return (
100-
<Button style={{ float: 'right' }} type="text">
100+
<Button
101+
style={{ float: 'right' }}
102+
type="text"
103+
disabled={record.versions.every((v) => !v.deployed)}
104+
>
101105
<DeleteOutlined color="red" />
102106
</Button>
103107
);
@@ -138,6 +142,7 @@ const DeploymentsList = ({
138142
style={{ float: 'right' }}
139143
type="text"
140144
onClick={() => removeDeployment(record.id)}
145+
disabled={record.versions.every((v) => !v.deployed)}
141146
>
142147
<DeleteOutlined color="red" />
143148
</Button>

src/management-system-v2/app/(dashboard)/[environmentId]/(automation)/executions/deployments-view.tsx

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use client';
22

3-
import { App, Button } from 'antd';
4-
import { useEffect, useState, useTransition } from 'react';
3+
import { App, Button, Checkbox, Space, Spin, Tooltip, Typography } from 'antd';
4+
import { QuestionCircleOutlined } from '@ant-design/icons';
5+
import { useCallback, useEffect, useState, useTransition } from 'react';
56
import DeploymentsModal from './deployments-modal';
67
import Bar from '@/components/bar';
78
import useFuzySearch from '@/lib/useFuzySearch';
@@ -10,7 +11,7 @@ import { Folder } from '@/lib/data/folder-schema';
1011
import { Process, ProcessMetadata } from '@/lib/data/process-schema';
1112
import { useEnvironment } from '@/components/auth-can';
1213
import { processUnchangedFromBasedOnVersion } from '@/lib/data/processes';
13-
import { useRouter } from 'next/navigation';
14+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
1415
import {
1516
deployProcess as serverDeployProcess,
1617
removeDeployment as serverRemoveDeployment,
@@ -34,12 +35,13 @@ const DeploymentsView = ({
3435
deployedProcesses: {
3536
id: string;
3637
name: string;
37-
versions: { id: string; name: string }[];
38+
versions: { id: string; name: string; deployed: boolean }[];
3839
instances: string[];
3940
}[];
4041
}) => {
4142
const [modalIsOpen, setModalIsOpen] = useState(false);
4243
const app = App.useApp();
44+
const pathname = usePathname();
4345
const space = useEnvironment();
4446
const router = useRouter();
4547
const queryClient = useQueryClient();
@@ -51,6 +53,25 @@ const DeploymentsView = ({
5153
transformData: (matches) => matches.map((match) => match.item),
5254
});
5355

56+
const [togglingShowArchived, startTogglingShowArchived] = useTransition();
57+
const query = useSearchParams();
58+
// Get a new searchParams string by merging the current
59+
// searchParams with a provided key/value pair
60+
// see: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams
61+
const createQueryString = useCallback(
62+
(name: string, value: string) => {
63+
const params = new URLSearchParams(query.toString());
64+
if (!value) {
65+
params.delete(name);
66+
} else {
67+
params.set(name, value);
68+
}
69+
70+
return params.toString();
71+
},
72+
[query],
73+
);
74+
5475
const [checkingProcessVersion, startCheckingProcessVersion] = useTransition();
5576
function deployProcess(
5677
process: Pick<Process, 'id' | 'versions'>,
@@ -125,15 +146,23 @@ const DeploymentsView = ({
125146
setInitialLoading(false);
126147
}, []);
127148

128-
const loading = initialLoading || checkingProcessVersion || removingDeployment;
149+
const loading =
150+
initialLoading || checkingProcessVersion || removingDeployment || togglingShowArchived;
129151

130152
const tableProps: { loading: boolean; pagination?: false } = { loading };
131153

132154
if (initialLoading) tableProps.pagination = false;
133155

134156
return (
135157
<div>
136-
<div style={{ marginBottom: '0.5rem' }}>
158+
<div
159+
style={{
160+
display: 'flex',
161+
justifyContent: 'space-between',
162+
alignItems: 'baseline',
163+
marginBottom: '0.5rem',
164+
}}
165+
>
137166
<Button
138167
type="primary"
139168
onClick={() => {
@@ -143,6 +172,29 @@ const DeploymentsView = ({
143172
>
144173
Deploy Process
145174
</Button>
175+
176+
<Space>
177+
{togglingShowArchived ? (
178+
<Spin size="small" />
179+
) : (
180+
<Checkbox
181+
checked={query.get('archived') == 'true'}
182+
onChange={(el) =>
183+
startTogglingShowArchived(() => {
184+
router.push(
185+
pathname + '?' + createQueryString('archived', el.target.checked ? 'true' : ''),
186+
);
187+
})
188+
}
189+
/>
190+
)}
191+
<Typography.Text>
192+
Show Past Executions{' '}
193+
<Tooltip title="This option displays all processes that have already been executed in the past, even if a process has already been deleted from the Management System.">
194+
<QuestionCircleOutlined />
195+
</Tooltip>
196+
</Typography.Text>
197+
</Space>
146198
</div>
147199

148200
<Bar

0 commit comments

Comments
 (0)