@gadmin2n/schematics 0.0.149 → 0.0.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +125 -36
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +42 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +2 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/.seed-timestamp +0 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +3 -1
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/check-dev-env.js +218 -0
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/page-manage.ts +78 -12
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +37 -67
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +0 -17
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.controller.ts +46 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.ts +60 -1
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.ts +3 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +9 -1
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +55 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.module.ts +2 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/page-transfer.service.ts +491 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.dto.ts +213 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.module.ts +28 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/resource-transfer.service.ts +137 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/role-transfer.service.ts +248 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/transfer-token.service.ts +65 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/user-transfer.service.ts +146 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +55 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.module.ts +2 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +55 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts +2 -0
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.spec.ts +46 -0
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.ts +3 -2
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +55 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts +2 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +1 -0
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +96 -14
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +41 -41
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.spec.ts +36 -0
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.ts +90 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +4 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-trigger.pg.spec.ts +1 -0
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +115 -63
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.spec.ts +166 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.ts +217 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.spec.ts +33 -0
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.ts +57 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.spec.ts +196 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.ts +125 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.controller.ts +9 -3
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +148 -4
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +12 -1
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +14 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +75 -45
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +25 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferExportModal.tsx +115 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferImportModal.tsx +257 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -2
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +40 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +15 -13
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +40 -0
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +15 -13
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +2 -1
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +89 -65
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +51 -127
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permissionReadme/index.tsx +53 -109
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +45 -41
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +51 -72
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +49 -40
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +16 -5
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +28 -10
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +60 -1
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +94 -12
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +13 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +3 -3
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +8 -1
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +167 -94
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +95 -95
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.test.tsx +81 -0
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.tsx +126 -0
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +48 -52
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +2 -2
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +1 -3
  79. package/package.json +1 -1
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/ac.config.ts +0 -24
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/SqlModal.tsx +0 -495
@@ -0,0 +1,126 @@
1
+ import {
2
+ Card,
3
+ Form,
4
+ Input,
5
+ Select,
6
+ Space,
7
+ Switch,
8
+ Typography,
9
+ message,
10
+ } from 'antd';
11
+ import { useEffect, useState } from 'react';
12
+ import { useTranslation } from 'react-i18next';
13
+ import type { IntegrationConnection } from '../../connections/connection.types';
14
+ import { fetchConnections } from '../../connections/connectionsApi';
15
+ import type { WidgetProps } from '../schema-form/widget-registry';
16
+ import { EventTriggerConfigEditor } from './EventTriggerConfigEditor';
17
+
18
+ type EventTriggerLifecycleConfig = Record<string, unknown> & {
19
+ failureCallback?: {
20
+ connectionRef?: string;
21
+ path?: string;
22
+ };
23
+ };
24
+
25
+ export function EventTriggerLifecycleConfigEditor({
26
+ value,
27
+ onChange,
28
+ ...props
29
+ }: WidgetProps<EventTriggerLifecycleConfig | undefined>) {
30
+ const { t } = useTranslation('workflow');
31
+ const config = value ?? {};
32
+ const callback = config.failureCallback;
33
+ const [connections, setConnections] = useState<IntegrationConnection[]>([]);
34
+ const [loading, setLoading] = useState(false);
35
+
36
+ useEffect(() => {
37
+ setLoading(true);
38
+ fetchConnections('')
39
+ .then(setConnections)
40
+ .catch((error) =>
41
+ message.error(
42
+ error?.message ?? t('nodeEditors.event.failureCallbackLoadFailed'),
43
+ ),
44
+ )
45
+ .finally(() => setLoading(false));
46
+ }, []);
47
+
48
+ function updateCallback(
49
+ next: EventTriggerLifecycleConfig['failureCallback'] | undefined,
50
+ ) {
51
+ const updated = { ...config };
52
+ if (next) updated.failureCallback = next;
53
+ else delete updated.failureCallback;
54
+ onChange(updated);
55
+ }
56
+
57
+ return (
58
+ <Space direction="vertical" size={12} style={{ width: '100%' }}>
59
+ <EventTriggerConfigEditor
60
+ {...(props as any)}
61
+ value={config as any}
62
+ onChange={(next) =>
63
+ onChange({
64
+ ...(next as unknown as Record<string, unknown>),
65
+ ...(callback && { failureCallback: callback }),
66
+ })
67
+ }
68
+ />
69
+ <Card size="small" title={t('nodeEditors.event.failureCallbackTitle')}>
70
+ <Typography.Paragraph type="secondary">
71
+ {t('nodeEditors.event.failureCallbackDescription')}
72
+ </Typography.Paragraph>
73
+ <Form.Item label={t('nodeEditors.event.failureCallbackEnabled')}>
74
+ <Switch
75
+ checked={Boolean(callback)}
76
+ disabled={props.disabled}
77
+ onChange={(enabled) =>
78
+ updateCallback(
79
+ enabled ? { connectionRef: '', path: '' } : undefined,
80
+ )
81
+ }
82
+ />
83
+ </Form.Item>
84
+ {callback && (
85
+ <>
86
+ <Form.Item
87
+ label={t('nodeEditors.event.failureCallbackConnection')}
88
+ required
89
+ >
90
+ <Select
91
+ value={callback.connectionRef || undefined}
92
+ loading={loading}
93
+ disabled={props.disabled}
94
+ showSearch
95
+ optionFilterProp="label"
96
+ options={connections
97
+ .filter((connection) => connection.isEnabled)
98
+ .map((connection) => ({
99
+ value: connection.code,
100
+ label: `${connection.name} (${connection.code})`,
101
+ }))}
102
+ onChange={(connectionRef) =>
103
+ updateCallback({ ...callback, connectionRef })
104
+ }
105
+ />
106
+ </Form.Item>
107
+ <Form.Item
108
+ label={t('nodeEditors.event.failureCallbackPath')}
109
+ required
110
+ style={{ marginBottom: 0 }}
111
+ >
112
+ <Input
113
+ value={callback.path}
114
+ disabled={props.disabled}
115
+ placeholder="/api/hardware-disposal/workflow-failed"
116
+ onChange={(event) =>
117
+ updateCallback({ ...callback, path: event.target.value })
118
+ }
119
+ />
120
+ </Form.Item>
121
+ </>
122
+ )}
123
+ </Card>
124
+ </Space>
125
+ );
126
+ }
@@ -2,13 +2,16 @@ import { fireEvent, render, screen } from '@testing-library/react';
2
2
  import { describe, expect, it, vi } from 'vitest';
3
3
  import i18n from '../../../../i18n';
4
4
  import { CronTriggerConfigEditor } from './CronTriggerConfigEditor';
5
- import {
6
- DbExecuteConfigEditor,
7
- isDatabaseSqlAllowed,
8
- } from './DbExecuteConfigEditor';
5
+ import { DbExecuteConfigEditor } from './DbExecuteConfigEditor';
9
6
  import { EventTriggerConfigEditor } from './EventTriggerConfigEditor';
10
7
  import { ParallelConfigEditor } from './ParallelConfigEditor';
11
8
 
9
+ const customRequest = vi.fn();
10
+
11
+ vi.mock('helpers/http', () => ({
12
+ customRequest: (...args: unknown[]) => customRequest(...args),
13
+ }));
14
+
12
15
  vi.mock('@monaco-editor/react', () => ({
13
16
  default: ({
14
17
  language,
@@ -353,35 +356,6 @@ describe('simplified workflow node editors', () => {
353
356
  ).not.toBeInTheDocument();
354
357
  });
355
358
 
356
- it('checks SQL against the node write permission', () => {
357
- expect(isDatabaseSqlAllowed(' SELECT * FROM users', false)).toBe(true);
358
- expect(
359
- isDatabaseSqlAllowed(
360
- 'WITH active AS (SELECT 1) SELECT * FROM active',
361
- false,
362
- ),
363
- ).toBe(true);
364
- expect(isDatabaseSqlAllowed('UPDATE users SET active = true', false)).toBe(
365
- false,
366
- );
367
- expect(isDatabaseSqlAllowed('UPDATE users SET active = true', true)).toBe(
368
- true,
369
- );
370
- expect(
371
- isDatabaseSqlAllowed(
372
- 'WITH changed AS (UPDATE requests SET status = $1 RETURNING id) UPDATE assets SET state = $2 WHERE request_id IN (SELECT id FROM changed)',
373
- true,
374
- ),
375
- ).toBe(true);
376
- expect(
377
- isDatabaseSqlAllowed(
378
- 'WITH changed AS (UPDATE requests SET status = $1 RETURNING id) UPDATE assets SET state = $2 WHERE request_id IN (SELECT id FROM changed)',
379
- false,
380
- ),
381
- ).toBe(false);
382
- expect(isDatabaseSqlAllowed('DROP TABLE users', true)).toBe(false);
383
- });
384
-
385
359
  it('explains the zero-based Parallel branch result array', async () => {
386
360
  await i18n.changeLanguage('zh_CN');
387
361
  render(
@@ -522,35 +496,57 @@ describe('simplified workflow node editors', () => {
522
496
  });
523
497
  });
524
498
 
525
- it('uses one SQL editor with a write permission switch', async () => {
499
+ it('selects a workflow_api Function and creates one binding per argument', async () => {
526
500
  await i18n.changeLanguage('zh_CN');
501
+ customRequest.mockResolvedValueOnce([
502
+ {
503
+ schema: 'workflow_api',
504
+ name: 'approve_request',
505
+ identityArguments: 'p_request_id bigint, p_approved boolean',
506
+ returnType: 'jsonb',
507
+ arguments: [
508
+ { position: 1, name: 'p_request_id', type: 'bigint' },
509
+ { position: 2, name: 'p_approved', type: 'boolean' },
510
+ ],
511
+ },
512
+ ]);
527
513
  const onChange = vi.fn();
528
514
  render(
529
515
  <DbExecuteConfigEditor
530
- value={{
531
- allowWrite: false,
532
- sql: 'SELECT * FROM users WHERE id = $1',
533
- parameters: [{ source: 'INPUT', path: 'userId' }],
534
- }}
516
+ value={{ timeoutSeconds: 30 }}
535
517
  onChange={onChange}
536
518
  schema={schema}
537
519
  />,
538
520
  );
539
521
 
540
- const sqlEditor = screen.getByRole('textbox', { name: 'SQL 语句' });
541
- expect(sqlEditor).toHaveValue('SELECT * FROM users WHERE id = $1');
542
- expect(sqlEditor).toHaveAttribute('data-language', 'sql');
543
- expect(screen.getByText('只读 SQL')).toBeInTheDocument();
544
- expect(screen.getByRole('textbox', { name: '参数 $1' })).toBeDisabled();
545
- expect(screen.getByRole('textbox', { name: '参数 $1' })).toHaveValue('$1');
546
- expect(screen.getByText('参数')).toBeInTheDocument();
547
- expect(screen.getByText('值')).toBeInTheDocument();
548
- expect(screen.getByDisplayValue('userId')).toBeInTheDocument();
549
- fireEvent.click(screen.getByRole('switch', { name: '允许写入' }));
522
+ const selector = await screen.findByRole('combobox', {
523
+ name: '数据库 Function',
524
+ });
525
+ expect(
526
+ screen.queryByRole('textbox', { name: 'SQL 语句' }),
527
+ ).not.toBeInTheDocument();
528
+ fireEvent.mouseDown(selector);
529
+ fireEvent.click(
530
+ await screen.findByTitle(
531
+ 'workflow_api.approve_request(p_request_id bigint, p_approved boolean)',
532
+ ),
533
+ );
534
+
550
535
  expect(onChange).toHaveBeenCalledWith({
551
- allowWrite: true,
552
- sql: 'SELECT * FROM users WHERE id = $1',
553
- parameters: [{ source: 'INPUT', path: 'userId' }],
536
+ functionRef: {
537
+ schema: 'workflow_api',
538
+ name: 'approve_request',
539
+ identityArguments: 'p_request_id bigint, p_approved boolean',
540
+ },
541
+ argumentBindings: [
542
+ { source: 'INPUT', path: 'request_id' },
543
+ { source: 'INPUT', path: 'approved' },
544
+ ],
545
+ timeoutSeconds: 30,
554
546
  });
547
+ expect(customRequest).toHaveBeenCalledWith(
548
+ 'workflow/database-functions',
549
+ 'GET',
550
+ );
555
551
  });
556
552
  });
@@ -23,9 +23,9 @@ export function resolveForEachCall(
23
23
  connection.sourceHandle,
24
24
  'start',
25
25
  );
26
- if (!ownerPorts || !firstNode) return null;
26
+ if (!forEachNode || !firstNode || !ownerPorts) return null;
27
27
  return {
28
- forEachNode: forEachNode!,
28
+ forEachNode,
29
29
  firstNode,
30
30
  sourceHandle: ownerPorts.start,
31
31
  targetReturnHandle: ownerPorts.end,
@@ -96,9 +96,7 @@ export function withNewNodeDefaults(
96
96
  }
97
97
  if (nodeType === 'db_execute') {
98
98
  return {
99
- allowWrite: false,
100
- sql: '',
101
- parameters: [],
99
+ argumentBindings: [],
102
100
  timeoutSeconds: 30,
103
101
  };
104
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadmin2n/schematics",
3
- "version": "0.0.149",
3
+ "version": "0.0.151",
4
4
  "description": "Gadmin - modern, fast, powerful node.js web framework (@schematics)",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -1,24 +0,0 @@
1
- import { RolesBuilder } from 'nest-access-control';
2
-
3
- export enum AppRoles {
4
- GUEST = 'GUEST',
5
- PRODUCT = 'PRODUCT',
6
- SYSTEM_ADMIIN = 'SYSTEM_ADMIN',
7
- }
8
-
9
- const ALL_TABLES = ['source', 'tasklog', 'log', 'game', 'role'];
10
-
11
- export const roles: RolesBuilder = new RolesBuilder();
12
- roles
13
- .grant(AppRoles.GUEST)
14
- .readAny(ALL_TABLES, ['*'])
15
- .grant(AppRoles.PRODUCT) // define new or modify existing role. also takes an array.
16
- .extend(AppRoles.GUEST)
17
- .createAny(ALL_TABLES) // equivalent to .createOwn('product', ['*'])
18
- .updateAny(ALL_TABLES)
19
- .deleteAny(ALL_TABLES, ['*'])
20
- .grant(AppRoles.SYSTEM_ADMIIN) // switch to another role without breaking the chain
21
- .extend(AppRoles.PRODUCT)
22
- .createAny(ALL_TABLES)
23
- .updateAny(ALL_TABLES) // explicitly defined attributes
24
- .deleteAny(ALL_TABLES, ['*']);