Skip to content

Commit 5879fe5

Browse files
authored
Merge branch 'main' into mcp
2 parents e890f4d + 5933691 commit 5879fe5

File tree

130 files changed

+21122
-915
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+21122
-915
lines changed

.github/copilot-instructions.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copilot / AI Agent Instructions for PROCEED
2+
3+
Purpose: Give an AI coding agent the minimal, actionable context to be productive in this monorepo.
4+
5+
**Big Picture:**
6+
7+
- **Management System (MS):** Next.js frontend + server code in [src/management-system-v2](src/management-system-v2). Runs at `http://localhost:3000` in dev (first, start a local Postgres instance and then run `yarn dev-ms` from the repo root).
8+
- **Process Engine (PE / Engine):** Node/TS engine code in [src/engine](src/engine). Start the engine in dev from the repo root with `yarn dev`.
9+
- **Helpers:** Reusable helpers live under [src/helper-modules](src/helper-modules).
10+
- **Deprecated/Currrently not in development**: the code under [src/capabilities](src/capabilities) and [src/config-server](src/config-server) is not currently in active development and may be outdated. The focus is on the MS v2 and the engine.
11+
12+
**Monorepo facts & tooling:**
13+
14+
- Workspaces are defined in the root [package.json](package.json). Node >= 20.11 and Yarn v1.22 are expected (see `engines` and `packageManager`).
15+
- Scripts in the root `package.json` orchestrate common workflows (start MS, start engine, db setup, builds).
16+
17+
**Key developer workflows (commands you should use):**
18+
19+
- Install: `yarn install` at the repo root.
20+
- Initialize local Postgres for MS: `yarn dev-ms-db` (this uses [src/management-system-v2/docker-compose-dev.yml](src/management-system-v2/docker-compose-dev.yml) and runs `scripts/db-helper.mts`).
21+
- Run Management System (dev): `yarn dev-ms` (root) or `cd src/management-system-v2 && yarn dev`. (Requires the local Postgres from the previous step).
22+
- Create new DB structure during schema changes: `yarn dev-ms-db-new-structure --name "<desc>"`.
23+
- Build MS for production: `yarn build-ms` (root) or `cd src/management-system-v2 && yarn build`.
24+
- Run Engine in dev: `yarn dev` (root).
25+
- Tests: `yarn test-engine`, `yarn test-e2e`, or `cd src/management-system-v2 && yarn test:unit` for MS unit tests.
26+
27+
**Project-specific conventions & patterns:**
28+
29+
- MS v2 is a Next.js app using `prisma` and server-side code; database access and schema changes rely on `scripts/db-helper.mts` and prisma commands in [src/management-system-v2/package.json](src/management-system-v2/package.json).
30+
- Many repo scripts call `cd` into subfolders; prefer using the root scripts (e.g. `yarn dev-ms`) to ensure the correct environment.
31+
- Build/test scripts may use `ts-node` or `tsx` for short TS scripts (see `predev`, `prebuild`, `postinstall`).
32+
- The engine has a `universal` and `native` part under [src/engine/universal](src/engine/universal) and [src/engine/native](src/engine/native). The `universal` part contains pure Typescript/JavaScript and most business logic. The `native` part contains platform-specific code which is not standardized in JavaScript, e.g. Node.js code for Windows, Linux and Mac under [src/engine/native/node](src/engine/native/node). The universal part uses functionality in the native part via an abstraction layer.
33+
34+
**Integration points & external dependencies:**
35+
36+
- The MS talks to Postgres (local docker compose in dev) and expects environment variables from [src/management-system-v2/.env].
37+
- The MS uses `@proceed/bpmn-helper` and `bpmn-js` for BPMN editing and rendering.
38+
- The engine exposes runtime APIs used by the MS and E2E tests located under [src/engine/e2e_tests](src/engine/e2e_tests).
39+
40+
**Files to inspect for context when changing behavior:**
41+
42+
- Repo-level scripts and workflows: [package.json](package.json)
43+
- MS-specific: [src/management-system-v2/package.json](src/management-system-v2/package.json), [src/management-system-v2/docker-compose-dev.yml](src/management-system-v2/docker-compose-dev.yml), [src/management-system-v2/scripts/db-helper.mts](src/management-system-v2/scripts/db-helper.mts)
44+
- Engine: [src/engine/native](src/engine/native) and [src/engine/universal](src/engine/universal)
45+
46+
**When you change DB schema or Prisma models:**
47+
48+
- Run `yarn dev-ms-db-new-structure --name "<desc>"` to create a new DB instance and run migrations locally.
49+
- Run `yarn dev-ms-db-generate` to regenerate Prisma client if models changed.
50+
51+
If anything here is ambiguous or you want more details (run commands, CI hooks, or where to find specific APIs), tell me what area to expand and I will iterate.

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ services:
1313
- PROCEED_PUBLIC_GANTT_ACTIVE=true
1414
- PROCEED_PUBLIC_CONFIG_SERVER_ACTIVE=false
1515
- PROCEED_PUBLIC_PROCESS_AUTOMATION_ACTIVE=true
16+
- PROCEED_PUBLIC_PROCESS_AUTOMATION_TASK_EDITOR_ACTIVE=true
17+
- PROCEED_PUBLIC_COMPETENCE_MATCHING_ACTIVE=true
1618
ports:
1719
- '3002:33081'
1820
depends_on:

src/engine/universal/system/src/data.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class Data extends System {
213213
// generate a unique name to prevent file name collisions
214214
let name = v4();
215215
if (fileName.includes('.')) {
216-
const fileType = fileName.split('.').pop();
216+
const fileType = fileName.split('.').slice(1).join('.');
217217
name += '.' + fileType;
218218
}
219219

src/engine/universal/ui/src/__tests__/__snapshots__/module.test.js.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ exports[`UI adds a display item to the SPA (HTTP) 1`] = `
6464
xhr.setRequestHeader('Content-Type', 'application/json');
6565
xhr.send(JSON.stringify(body));
6666
});
67+
},
68+
submit: async (path, body, query) => {
69+
validateEndpointArgs('post', path, body, query);
70+
return new Promise(async (resolve, reject) => {
71+
const xhr = new XMLHttpRequest();
72+
xhr.addEventListener('loadend', (req) => {resolve(JSON.parse(req.target.responseText)); });
73+
const url = query ? path + '?' + Object.entries(query).map(([key, value]) => key + '=' + encodeURIComponent(value)).join('&') : path;
74+
xhr.open('POST', url, true);
75+
xhr.setRequestHeader('Content-Type', 'application/json');
76+
77+
const buffer = await body.arrayBuffer();
78+
79+
xhr.send(JSON.stringify(Array.from(new Uint8Array(buffer))));
80+
});
6781
}
6882
};
6983
</script>

src/engine/universal/ui/src/ui.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@ const ui = {
221221
xhr.setRequestHeader('Content-Type', 'application/json');
222222
xhr.send(JSON.stringify(body));
223223
});
224+
},
225+
submit: async (path, body, query) => {
226+
${validateEndpointArgs.name}('post', path, body, query);
227+
return new Promise(async (resolve, reject) => {
228+
const xhr = new XMLHttpRequest();
229+
xhr.addEventListener('loadend', (req) => {resolve(JSON.parse(req.target.responseText)); });
230+
const url = query ? path + '?' + Object.entries(query).map(([key, value]) => key + '=' + encodeURIComponent(value)).join('&') : path;
231+
xhr.open('POST', url, true);
232+
xhr.setRequestHeader('Content-Type', 'application/json');
233+
234+
const buffer = await body.arrayBuffer();
235+
236+
xhr.send(JSON.stringify(Array.from(new Uint8Array(buffer))));
237+
});
224238
}
225239
};
226240
</script>

src/helper-modules/user-task-helper/index.js

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ const script = `
142142
143143
const variableDefinitions = {%variableDefinitions%};
144144
145+
let submitting = false;
146+
const variableSubmitTimeouts = {};
147+
145148
function getValueFromCheckbox(checkbox) {
146149
if (!checkbox.defaultValue) {
147150
return !!checkbox.checked;
@@ -251,10 +254,9 @@ const script = `
251254
// if the value set for a variable is a file => upload the file and replace the variable
252255
// with a reference to the stored file
253256
if (value instanceof File) {
254-
const buffer = await value.arrayBuffer();
255-
const { path } = await window.PROCEED_DATA.post(
257+
const { path } = await window.PROCEED_DATA.submit(
256258
'/tasklist/api/variable-file',
257-
Array.from(new Uint8Array(buffer)),
259+
value,
258260
{
259261
instanceID,
260262
userTaskID,
@@ -266,14 +268,17 @@ const script = `
266268
}
267269
}
268270
271+
submitting = true;
272+
Object.values(variableSubmitTimeouts).forEach(timeout => clearTimeout(timeout));
269273
window.PROCEED_DATA.put('/tasklist/api/variable', variables, {
270274
instanceID,
271275
userTaskID,
272-
}).then(() => {
273-
window.PROCEED_DATA.post('/tasklist/api/userTask', variables, {
276+
}).then(async () => {
277+
await window.PROCEED_DATA.post('/tasklist/api/userTask', variables, {
274278
instanceID,
275279
userTaskID,
276280
});
281+
submitting = false;
277282
});
278283
}
279284
@@ -312,22 +317,24 @@ const script = `
312317
milestoneInput.nextElementSibling.value = milestoneInput.value + '%'
313318
});
314319
315-
milestoneInput.addEventListener('click', (event) => {
316-
const milestoneName = Array.from(event.target.classList)
317-
.find((className) => className.includes('milestone-'))
318-
.split('milestone-')
319-
.slice(1)
320-
.join('');
321-
322-
window.PROCEED_DATA.put(
323-
'/tasklist/api/milestone',
324-
{ [milestoneName]: parseInt(event.target.value) },
325-
{
326-
instanceID,
327-
userTaskID,
328-
}
329-
);
330-
});
320+
if (!submitting) {
321+
milestoneInput.addEventListener('click', (event) => {
322+
const milestoneName = Array.from(event.target.classList)
323+
.find((className) => className.includes('milestone-'))
324+
.split('milestone-')
325+
.slice(1)
326+
.join('');
327+
328+
window.PROCEED_DATA.put(
329+
'/tasklist/api/milestone',
330+
{ [milestoneName]: parseInt(event.target.value) },
331+
{
332+
instanceID,
333+
userTaskID,
334+
}
335+
);
336+
});
337+
}
331338
});
332339
333340
// get all input(-group)s that can be used to set the value of an input
@@ -358,31 +365,34 @@ const script = `
358365
// cancel pending updates
359366
clearTimeout(variableInputTimer);
360367
361-
if (event.target.type === 'file') {
362-
updateUploadInfo(event.target);
363-
return;
364-
}
365-
366-
// trigger a timeout for an update to commit
367-
variableInputTimer = setTimeout(() => {
368-
try {
369-
const value = getValueFromVariableElement(variableName, variableInput);
370-
371-
validateValue(variableName, value);
372-
updateValidationErrorMessage(variableName);
373-
374-
window.PROCEED_DATA.put(
375-
'/tasklist/api/variable',
376-
{ [variableName]: value },
377-
{
378-
instanceID,
379-
userTaskID,
380-
}
381-
);
382-
} catch (err) {
383-
updateValidationErrorMessage(variableName, err.message);
368+
if (!submitting) {
369+
if (event.target.type === 'file') {
370+
updateUploadInfo(event.target);
371+
return;
384372
}
385-
}, 2000)
373+
374+
// trigger a timeout for an update to commit
375+
variableInputTimer = setTimeout(() => {
376+
try {
377+
const value = getValueFromVariableElement(variableName, variableInput);
378+
379+
validateValue(variableName, value);
380+
updateValidationErrorMessage(variableName);
381+
382+
window.PROCEED_DATA.put(
383+
'/tasklist/api/variable',
384+
{ [variableName]: value },
385+
{
386+
instanceID,
387+
userTaskID,
388+
}
389+
);
390+
} catch (err) {
391+
updateValidationErrorMessage(variableName, err.message);
392+
}
393+
}, 2000)
394+
variableSubmitTimeouts[variableName] = variableInputTimer;
395+
}
386396
});
387397
});
388398
});

0 commit comments

Comments
 (0)