@gadmin2n/schematics 0.0.146 → 0.0.148

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 (95) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.local.md +8 -0
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +70 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +1 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +1 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +67 -15
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +17 -4
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +5 -0
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.spec.ts +24 -0
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.ts +15 -0
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.spec.ts +2 -6
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.spec.ts +28 -29
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +16 -34
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +3 -3
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.spec.ts +61 -6
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.spec.ts +2 -2
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/index.ts +2 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.controller.ts +11 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.spec.ts +126 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +136 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.controller.ts +24 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.dto.ts +8 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.service.spec.ts +62 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.service.ts +94 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.types.ts +6 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staffDirectory.module.ts +10 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user.provider.ts +6 -2
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.spec.ts +20 -12
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.ts +21 -19
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +11 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +97 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.ts +150 -2
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.controller.ts +13 -1
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.dto.ts +13 -1
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.errors.ts +1 -0
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.spec.ts +125 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.ts +118 -5
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +20 -3
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +6 -9
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-runtime.facade.ts +2 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.spec.ts +4 -1
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +5 -1
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +44 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +15 -1
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +2 -3
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.spec.ts +33 -22
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +10 -23
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/StaffSelect.test.tsx +69 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/StaffSelect.tsx +145 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/index.ts +2 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/staff-directory.api.ts +16 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/index.ts +1 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.test.ts +10 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +20 -2
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +6 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +49 -11
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +49 -11
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/PeopleGroupModal.tsx +181 -0
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/index.tsx +203 -0
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/people-groups.api.ts +145 -0
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/PersonModal.tsx +112 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/index.tsx +214 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/person-directory.api.ts +79 -0
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/form-modal.tsx +7 -11
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +7 -7
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.test.tsx +20 -0
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +97 -28
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +87 -119
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.test.tsx +22 -1
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.tsx +8 -2
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connections.css +8 -46
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connectionsApi.ts +7 -0
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.test.tsx +32 -3
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +163 -106
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +8 -1
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +26 -0
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +34 -6
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-config.css +13 -16
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +185 -0
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +224 -105
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.test.tsx +1 -1
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +21 -12
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +1 -2
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +160 -8
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +125 -55
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +47 -3
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.test.tsx +33 -1
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.tsx +28 -46
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/human-approval-config.css +16 -0
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/subject-provider.api.ts +0 -6
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.test.tsx +24 -0
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +14 -17
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +1 -0
  93. package/package.json +1 -1
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CreateNodeInstanceDrawer.tsx +0 -162
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupCreateModal.tsx +0 -72
@@ -0,0 +1,69 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { act } from 'react';
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import { searchStaffDirectory } from './staff-directory.api';
5
+ import { StaffSelect } from './StaffSelect';
6
+
7
+ vi.mock('./staff-directory.api', () => ({
8
+ searchStaffDirectory: vi.fn(),
9
+ }));
10
+
11
+ vi.mock('antd', () => ({
12
+ Select: ({ onSearch, onChange, options = [] }: any) => (
13
+ <div>
14
+ <input
15
+ aria-label="staff search"
16
+ onChange={(event) => onSearch(event.target.value)}
17
+ />
18
+ {options.map((option: any) => (
19
+ <button key={option.value} onClick={() => onChange(option.value)}>
20
+ {option.label}
21
+ </button>
22
+ ))}
23
+ </div>
24
+ ),
25
+ Empty: Object.assign(() => <div>empty</div>, {
26
+ PRESENTED_IMAGE_SIMPLE: 'simple',
27
+ }),
28
+ Space: ({ children }: any) => <div>{children}</div>,
29
+ Spin: () => <div>loading</div>,
30
+ Typography: {
31
+ Text: ({ children }: any) => <span>{children}</span>,
32
+ },
33
+ }));
34
+
35
+ describe('StaffSelect', () => {
36
+ beforeEach(() => {
37
+ vi.useFakeTimers();
38
+ vi.clearAllMocks();
39
+ });
40
+
41
+ afterEach(() => vi.useRealTimers());
42
+
43
+ it('searches through the shared backend and returns the selected person', async () => {
44
+ vi.mocked(searchStaffDirectory).mockResolvedValue([
45
+ {
46
+ userId: 'junrujrwang',
47
+ displayName: 'Junru Wang',
48
+ businessGroup: 'OIT',
49
+ },
50
+ ]);
51
+ const onChange = vi.fn();
52
+ const onPersonChange = vi.fn();
53
+ render(<StaffSelect onChange={onChange} onPersonChange={onPersonChange} />);
54
+
55
+ fireEvent.change(screen.getByRole('textbox', { name: 'staff search' }), {
56
+ target: { value: 'junru' },
57
+ });
58
+ await act(() => vi.advanceTimersByTimeAsync(300));
59
+
60
+ expect(searchStaffDirectory).toHaveBeenCalledWith('junru');
61
+ fireEvent.click(
62
+ screen.getByRole('button', { name: 'Junru Wang (junrujrwang)' }),
63
+ );
64
+ expect(onChange).toHaveBeenCalledWith('junrujrwang');
65
+ expect(onPersonChange).toHaveBeenCalledWith(
66
+ expect.objectContaining({ userId: 'junrujrwang' }),
67
+ );
68
+ });
69
+ });
@@ -0,0 +1,145 @@
1
+ import { Empty, Select, Space, Spin, Typography, type SelectProps } from 'antd';
2
+ import { useEffect, useMemo, useRef, useState } from 'react';
3
+ import {
4
+ searchStaffDirectory,
5
+ type StaffDirectoryPerson,
6
+ } from './staff-directory.api';
7
+
8
+ export interface StaffSelectProps {
9
+ value?: string;
10
+ onChange?(value?: string): void;
11
+ onPersonChange?(person?: StaffDirectoryPerson): void;
12
+ disabled?: boolean;
13
+ placeholder?: string;
14
+ allowClear?: boolean;
15
+ initialPerson?: StaffDirectoryPerson;
16
+ style?: SelectProps['style'];
17
+ }
18
+
19
+ export function StaffSelect({
20
+ value,
21
+ onChange,
22
+ onPersonChange,
23
+ disabled,
24
+ placeholder = '输入姓名或企业微信账号搜索',
25
+ allowClear = true,
26
+ initialPerson,
27
+ style,
28
+ }: StaffSelectProps) {
29
+ const [people, setPeople] = useState<StaffDirectoryPerson[]>(
30
+ initialPerson ? [initialPerson] : [],
31
+ );
32
+ const [loading, setLoading] = useState(false);
33
+ const [searched, setSearched] = useState(false);
34
+ const [error, setError] = useState(false);
35
+ const timer = useRef<ReturnType<typeof setTimeout>>();
36
+ const requestSequence = useRef(0);
37
+
38
+ useEffect(
39
+ () => () => {
40
+ clearTimeout(timer.current);
41
+ requestSequence.current += 1;
42
+ },
43
+ [],
44
+ );
45
+
46
+ const peopleById = useMemo(
47
+ () => new Map(people.map((person) => [person.userId, person])),
48
+ [people],
49
+ );
50
+
51
+ function search(keyword: string) {
52
+ clearTimeout(timer.current);
53
+ const query = keyword.trim();
54
+ if (!query) {
55
+ requestSequence.current += 1;
56
+ setPeople(initialPerson ? [initialPerson] : []);
57
+ setLoading(false);
58
+ setSearched(false);
59
+ setError(false);
60
+ return;
61
+ }
62
+ const sequence = ++requestSequence.current;
63
+ timer.current = setTimeout(async () => {
64
+ setLoading(true);
65
+ setSearched(true);
66
+ setError(false);
67
+ try {
68
+ const result = await searchStaffDirectory(query);
69
+ if (sequence !== requestSequence.current) return;
70
+ const selected = value ? peopleById.get(value) : undefined;
71
+ setPeople(
72
+ selected &&
73
+ !result.some((person) => person.userId === selected.userId)
74
+ ? [selected, ...result]
75
+ : result,
76
+ );
77
+ } catch {
78
+ if (sequence === requestSequence.current) {
79
+ setPeople(initialPerson ? [initialPerson] : []);
80
+ setError(true);
81
+ }
82
+ } finally {
83
+ if (sequence === requestSequence.current) setLoading(false);
84
+ }
85
+ }, 300);
86
+ }
87
+
88
+ return (
89
+ <Select
90
+ showSearch
91
+ value={value}
92
+ disabled={disabled}
93
+ allowClear={allowClear}
94
+ placeholder={placeholder}
95
+ filterOption={false}
96
+ loading={loading}
97
+ onSearch={search}
98
+ onChange={(nextValue?: string) => {
99
+ const person = nextValue ? peopleById.get(nextValue) : undefined;
100
+ onChange?.(nextValue);
101
+ onPersonChange?.(person);
102
+ }}
103
+ options={people.map((person) => ({
104
+ value: person.userId,
105
+ label: `${person.displayName} (${person.userId})`,
106
+ person,
107
+ }))}
108
+ optionRender={(option) => {
109
+ const person = option.data.person as StaffDirectoryPerson;
110
+ const organization = [person.businessGroup, person.department]
111
+ .filter(Boolean)
112
+ .join(' · ');
113
+ return (
114
+ <Space direction="vertical" size={0}>
115
+ <Typography.Text>
116
+ {person.displayName} ({person.userId})
117
+ </Typography.Text>
118
+ {organization && (
119
+ <Typography.Text type="secondary" style={{ fontSize: 12 }}>
120
+ {organization}
121
+ </Typography.Text>
122
+ )}
123
+ </Space>
124
+ );
125
+ }}
126
+ notFoundContent={
127
+ loading ? (
128
+ <Spin size="small" />
129
+ ) : error ? (
130
+ <Typography.Text type="danger">
131
+ 人员搜索暂时不可用,请稍后重试
132
+ </Typography.Text>
133
+ ) : searched ? (
134
+ <Empty
135
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
136
+ description="未找到人员"
137
+ />
138
+ ) : (
139
+ <Typography.Text type="secondary">输入关键词开始搜索</Typography.Text>
140
+ )
141
+ }
142
+ style={{ width: '100%', ...style }}
143
+ />
144
+ );
145
+ }
@@ -0,0 +1,2 @@
1
+ export * from './StaffSelect';
2
+ export type { StaffDirectoryPerson } from './staff-directory.api';
@@ -0,0 +1,16 @@
1
+ import { customRequest } from 'helpers/http';
2
+
3
+ export interface StaffDirectoryPerson {
4
+ userId: string;
5
+ displayName: string;
6
+ businessGroup?: string;
7
+ department?: string;
8
+ }
9
+
10
+ export function searchStaffDirectory(keyword: string) {
11
+ return customRequest<StaffDirectoryPerson[]>(
12
+ 'staff-directory/search',
13
+ 'GET',
14
+ { keyword },
15
+ );
16
+ }
@@ -8,3 +8,4 @@ export * from './pagination-total';
8
8
  export * from './tags';
9
9
  export * from './text';
10
10
  export * from './WorkflowActionButton';
11
+ export * from './StaffSelect';
@@ -8,3 +8,13 @@ describe('workflow route placement', () => {
8
8
  );
9
9
  });
10
10
  });
11
+
12
+ describe('person and access routes', () => {
13
+ it('keeps people, groups and access authorization as separate pages', () => {
14
+ expect(getRoutePath('person_directory')).toBe('/admin/permission/people');
15
+ expect(getRoutePath('people_group')).toBe(
16
+ '/admin/permission/people-groups',
17
+ );
18
+ expect(getRoutePath('user')).toBe('/admin/permission/user');
19
+ });
20
+ });
@@ -191,14 +191,32 @@ export const routeRegistry: Record<string, RouteEntry> = {
191
191
  })),
192
192
  ),
193
193
  },
194
- // 用户管理 — sortOrder 1030, code: admin.permission.user
194
+ // 人员目录 — code: person_directory
195
+ person_directory: {
196
+ path: 'people',
197
+ component: lazyWithReload(() =>
198
+ import('routes/person-directory').then((m) => ({
199
+ default: m.default,
200
+ })),
201
+ ),
202
+ },
203
+ // 访问授权 — 保留 user code/path,兼容既有页面权限和链接
195
204
  user: {
196
205
  path: 'user',
197
206
  component: lazyWithReload(() =>
198
207
  import('routes/user').then((m) => ({ default: m.UserListPage })),
199
208
  ),
200
209
  },
201
- // 角色管理 — sortOrder 1040, code: admin.permission.role
210
+ // 人员组 — code: people_group
211
+ people_group: {
212
+ path: 'people-groups',
213
+ component: lazyWithReload(() =>
214
+ import('routes/people-groups').then((m) => ({
215
+ default: m.default,
216
+ })),
217
+ ),
218
+ },
219
+ // 角色管理
202
220
  role: {
203
221
  path: 'role-list',
204
222
  component: lazyWithReload(() =>
@@ -6,6 +6,9 @@ import {
6
6
  BgColorsOutlined,
7
7
  ScheduleOutlined,
8
8
  ApartmentOutlined,
9
+ SafetyCertificateOutlined,
10
+ TeamOutlined,
11
+ UserOutlined,
9
12
  } from '@ant-design/icons';
10
13
  import { getRoutePath } from 'config/routeRegistry';
11
14
  import { useUserPageAccess } from './useUserPageAccess';
@@ -46,6 +49,9 @@ export const iconMapping: Record<string, React.ReactNode> = {
46
49
  canvas: <BgColorsOutlined />,
47
50
  agenda: <ScheduleOutlined />,
48
51
  workflow: <ApartmentOutlined />,
52
+ person_directory: <UserOutlined />,
53
+ user: <SafetyCertificateOutlined />,
54
+ people_group: <TeamOutlined />,
49
55
  };
50
56
 
51
57
  // Pages whose children are tabs (not separate menu items)
@@ -162,18 +162,21 @@
162
162
  "taskDetailValue": "Field value",
163
163
  "whoCanApprove": "Who can approve",
164
164
  "description": "Choose fixed approvers or call an API inside this node to look them up dynamically.",
165
- "fixedApprovers": "Fixed approvers",
165
+ "fixedApprovers": "Fixed approver sources",
166
+ "fixedUsers": "Fixed people",
167
+ "fixedUserGroups": "Fixed people groups",
168
+ "addFixedUsers": "Add people",
169
+ "addFixedUserGroups": "Add people group",
170
+ "removeFixedSource": "Remove {{name}}",
171
+ "noFixedApprovers": "No fixed people or people groups added",
166
172
  "approvedBranch": "Approved",
167
173
  "rejectedBranch": "Rejected",
168
174
  "dynamicApprovers": "Dynamic approvers",
169
- "addUsers": "Add dynamic users",
170
- "addGroups": "Add dynamic user groups",
175
+ "addUsers": "Add dynamic approvers",
171
176
  "noDynamicInputs": "No dynamic approvers added",
172
177
  "lookupDescription": "Calls an API and transforms its response into one or more approver IDs",
173
- "dynamicUsers": "Look up users",
174
- "dynamicGroups": "Look up user groups",
178
+ "dynamicUsers": "Look up approvers",
175
179
  "dynamicUserDefaultName": "Look up approvers",
176
- "dynamicGroupDefaultName": "Look up approver groups",
177
180
  "dynamicLookupName": "Lookup name",
178
181
  "dynamicLookupNamePlaceholder": "For example: Find direct manager",
179
182
  "lookupRequest": "Look up approvers",
@@ -229,7 +232,7 @@
229
232
  "input": "The result received by the approval node from the previous node.",
230
233
  "workflow": "The original data received when the Workflow started.",
231
234
  "response": "The approver lookup response: { status, data, headers }.",
232
- "return": "Return { subjects: [{ provider, refs }] } to select approvers for this task."
235
+ "return": "Return an array of user IDs, for example ['alice', 'bob']."
233
236
  },
234
237
  "approvalCreation": {
235
238
  "input": "The result received by the approval node from the previous node.",
@@ -293,6 +296,11 @@
293
296
  "loadFailed": "Unable to load connections",
294
297
  "disabled": "Disabled",
295
298
  "edit": "Edit connection",
299
+ "deleteAria": "Delete {{name}}",
300
+ "deleteConfirm": "Delete connection {{name}}?",
301
+ "deleteDescription": "This cannot be undone. Connections used by a Workflow cannot be deleted.",
302
+ "deleteSuccess": "Connection deleted",
303
+ "deleteFailed": "Unable to delete connection",
296
304
  "create": "Create connection",
297
305
  "saveChanges": "Save changes",
298
306
  "authentication": "Authentication",
@@ -560,6 +568,8 @@
560
568
  },
561
569
  "database": {
562
570
  "sql": "SQL statement",
571
+ "readOnly": "Read-only SQL",
572
+ "writeEnabled": "Writes enabled",
563
573
  "allowWrite": "Allow writes",
564
574
  "readOnlyDescription": "When off, this node can only query data.",
565
575
  "readWriteDescription": "When on, this node can query, insert, update, or delete data.",
@@ -622,10 +632,16 @@
622
632
  "enableConfirm": "Enable this node instance?",
623
633
  "disableConfirm": "Disable this node instance?",
624
634
  "detailDescription": "Review this reusable configuration and the Workflows that reference it.",
635
+ "detailSummaryDescription": "Review the instance purpose, node type, and maintenance details.",
625
636
  "referencesLoadFailed": "References could not be loaded",
626
637
  "createdAt": "Created",
638
+ "instanceId": "Instance ID",
639
+ "referenceCount": "References",
640
+ "noDescription": "No description",
627
641
  "noConfiguration": "This instance has no configuration",
642
+ "configurationDescription": "Review the saved {{name}} execution parameters in read-only mode.",
628
643
  "referencedBy": "Referenced by",
644
+ "referencesDescription": "These Workflows currently use this reusable configuration.",
629
645
  "noReferences": "No Workflows reference this instance",
630
646
  "node": "Node",
631
647
  "new": "New Instance",
@@ -734,7 +750,12 @@
734
750
  "add": "Add",
735
751
  "template": "Node template",
736
752
  "templateOptional": "Use a template or configure this node directly",
737
- "createTemplate": "New template",
753
+ "saveCurrentAsTemplate": "Save current configuration as template",
754
+ "saveCurrentAsTemplateHint": "Create a template from the current node configuration and immediately use it for this node. Save the Workflow from the top of the page to persist this reference.",
755
+ "saveAndUseTemplate": "Save and use template",
756
+ "templateName": "Template name",
757
+ "templateSavedAndApplied": "Template created and applied to this node",
758
+ "templateSaveFailed": "Failed to save template",
738
759
  "selectTemplate": "Select a template",
739
760
  "noTemplates": "No templates available",
740
761
  "loadingInstances": "Loading templates…",
@@ -777,6 +798,14 @@
777
798
  "string": "Text"
778
799
  },
779
800
  "fieldLabels": {
801
+ "event_trigger": {
802
+ "operation": "Operation type",
803
+ "table": "Source table",
804
+ "primaryKey": "Primary key",
805
+ "before": "Data before the change",
806
+ "after": "Data after the change",
807
+ "changedFields": "Changed fields"
808
+ },
780
809
  "webhook_trigger": {
781
810
  "body": "Request body",
782
811
  "headers": "Request headers",
@@ -813,6 +842,14 @@
813
842
  }
814
843
  },
815
844
  "fields": {
845
+ "event_trigger": {
846
+ "operation": "Database operation: INSERT, UPDATE, or DELETE",
847
+ "table": "The changed table, including its schema and table name",
848
+ "primaryKey": "The primary key of the changed row",
849
+ "before": "The complete row before the change; null for INSERT",
850
+ "after": "The complete row after the change; null for DELETE",
851
+ "changedFields": "Changed watched fields for UPDATE; all row fields for INSERT or DELETE"
852
+ },
816
853
  "webhook_trigger": {
817
854
  "body": "",
818
855
  "headers": "",
@@ -859,12 +896,9 @@
859
896
  "anyValue": "Output is determined at runtime"
860
897
  }
861
898
  },
862
- "saveAsInstance": "Also save as a template",
863
- "instanceNamePlaceholder": "Template name (required)",
864
899
  "aiEditHint": "Describe what to change",
865
900
  "aiEditPlaceholder": "For example: change the timeout to 30 minutes",
866
901
  "send": "Send",
867
- "saveChanges": "Save changes",
868
902
  "aiGenerating": "AI is generating workflow…",
869
903
  "aiGeneratingHint": "Please wait. The workflow canvas will update automatically.",
870
904
  "untitled": "Untitled Workflow",
@@ -988,6 +1022,7 @@
988
1022
  "completed": "Completed",
989
1023
  "running": "Running",
990
1024
  "failed": "Failed",
1025
+ "cancelled": "Cancelled",
991
1026
  "publishedStatus": "Published",
992
1027
  "status": "Status",
993
1028
  "version": "Version",
@@ -1038,6 +1073,9 @@
1038
1073
  "openTemporal": "Open in Temporal",
1039
1074
  "cancel": "Cancel run",
1040
1075
  "executionDetails": "Run information",
1076
+ "cancellationRequestedBy": "Cancelled by",
1077
+ "cancellationRequestedAt": "Cancelled at",
1078
+ "cancellationReason": "Cancellation reason",
1041
1079
  "result": "Final result",
1042
1080
  "retryAll": "Run entire Workflow again",
1043
1081
  "retryAllConfirm": "Run the entire Workflow again?",
@@ -162,18 +162,21 @@
162
162
  "taskDetailValue": "字段值",
163
163
  "whoCanApprove": "审批人设置",
164
164
  "description": "选择固定审批人,或在节点内调用接口动态查询审批人。",
165
- "fixedApprovers": "固定审批人",
165
+ "fixedApprovers": "固定审批来源",
166
+ "fixedUsers": "固定人员",
167
+ "fixedUserGroups": "固定人员组",
168
+ "addFixedUsers": "添加人员",
169
+ "addFixedUserGroups": "添加人员组",
170
+ "removeFixedSource": "删除{{name}}",
171
+ "noFixedApprovers": "暂未添加固定人员或人员组",
166
172
  "approvedBranch": "通过",
167
173
  "rejectedBranch": "拒绝",
168
174
  "dynamicApprovers": "动态审批人",
169
- "addUsers": "添加动态用户",
170
- "addGroups": "添加动态用户组",
175
+ "addUsers": "添加动态审批人",
171
176
  "noDynamicInputs": "暂未添加动态审批人",
172
177
  "lookupDescription": "调用接口并把响应转换为一个或多个审批人 ID",
173
- "dynamicUsers": "动态查询用户",
174
- "dynamicGroups": "动态查询用户组",
178
+ "dynamicUsers": "动态查询审批人",
175
179
  "dynamicUserDefaultName": "查询审批人",
176
- "dynamicGroupDefaultName": "查询审批用户组",
177
180
  "dynamicLookupName": "查询名称",
178
181
  "dynamicLookupNamePlaceholder": "例如:查询直属领导",
179
182
  "lookupRequest": "查询审批人",
@@ -229,7 +232,7 @@
229
232
  "input": "人工审批节点从上一个节点收到的结果。",
230
233
  "workflow": "Workflow 最初收到的启动数据。",
231
234
  "response": "查询审批人接口返回的 { status, data, headers }。",
232
- "return": "返回 { subjects: [{ provider, refs }] },用于确定本次审批人。"
235
+ "return": "返回人员 ID 数组,例如 ['zhangsan', 'lisi']。"
233
236
  },
234
237
  "approvalCreation": {
235
238
  "input": "人工审批节点从上一个节点收到的结果。",
@@ -293,6 +296,11 @@
293
296
  "loadFailed": "加载连接失败",
294
297
  "disabled": "停用",
295
298
  "edit": "编辑连接",
299
+ "deleteAria": "删除 {{name}}",
300
+ "deleteConfirm": "删除连接 {{name}}?",
301
+ "deleteDescription": "删除后将无法恢复。正在被 Workflow 使用的连接不能删除。",
302
+ "deleteSuccess": "连接已删除",
303
+ "deleteFailed": "连接删除失败",
296
304
  "create": "创建连接",
297
305
  "saveChanges": "保存修改",
298
306
  "authentication": "认证方式",
@@ -560,6 +568,8 @@
560
568
  },
561
569
  "database": {
562
570
  "sql": "SQL 语句",
571
+ "readOnly": "只读 SQL",
572
+ "writeEnabled": "允许写入",
563
573
  "allowWrite": "允许写入",
564
574
  "readOnlyDescription": "关闭时只能查询数据。",
565
575
  "readWriteDescription": "开启后可以查询、新增、更新或删除数据。",
@@ -622,10 +632,16 @@
622
632
  "enableConfirm": "确定启用此节点实例吗?",
623
633
  "disableConfirm": "确定停用此节点实例吗?",
624
634
  "detailDescription": "查看可复用配置及引用它的工作流。",
635
+ "detailSummaryDescription": "确认实例用途、节点类型和维护信息。",
625
636
  "referencesLoadFailed": "引用关系加载失败",
626
637
  "createdAt": "创建时间",
638
+ "instanceId": "实例 ID",
639
+ "referenceCount": "引用数",
640
+ "noDescription": "暂无描述",
627
641
  "noConfiguration": "此实例没有配置项",
642
+ "configurationDescription": "只读查看 {{name}} 当前保存的执行参数。",
628
643
  "referencedBy": "引用此实例的工作流",
644
+ "referencesDescription": "以下 Workflow 当前正在使用这份可复用配置。",
629
645
  "noReferences": "暂无工作流引用此实例",
630
646
  "node": "节点",
631
647
  "new": "新建实例",
@@ -734,7 +750,12 @@
734
750
  "add": "添加",
735
751
  "template": "节点模板",
736
752
  "templateOptional": "可以使用模板,也可以直接配置",
737
- "createTemplate": "新建模板",
753
+ "saveCurrentAsTemplate": "将当前配置保存为模板",
754
+ "saveCurrentAsTemplateHint": "将使用当前节点配置创建模板,并立即让当前节点引用该模板。Workflow 仍需通过页面顶部的“保存”进行保存。",
755
+ "saveAndUseTemplate": "保存并使用模板",
756
+ "templateName": "模板名称",
757
+ "templateSavedAndApplied": "模板已创建并应用到当前节点",
758
+ "templateSaveFailed": "保存模板失败",
738
759
  "selectTemplate": "选择模板",
739
760
  "noTemplates": "暂无可用模板",
740
761
  "loadingInstances": "正在加载模板…",
@@ -777,6 +798,14 @@
777
798
  "string": "文本"
778
799
  },
779
800
  "fieldLabels": {
801
+ "event_trigger": {
802
+ "operation": "操作类型",
803
+ "table": "数据表",
804
+ "primaryKey": "主键",
805
+ "before": "变更前的数据",
806
+ "after": "变更后的数据",
807
+ "changedFields": "发生变化的字段"
808
+ },
780
809
  "webhook_trigger": {
781
810
  "body": "请求内容",
782
811
  "headers": "请求头",
@@ -813,6 +842,14 @@
813
842
  }
814
843
  },
815
844
  "fields": {
845
+ "event_trigger": {
846
+ "operation": "数据库操作类型:INSERT(新增)、UPDATE(更新)或 DELETE(删除)",
847
+ "table": "发生变化的数据表,包含 schema 和表名",
848
+ "primaryKey": "发生变化的这一行数据的主键",
849
+ "before": "变更前的整行数据;新增时为 null",
850
+ "after": "变更后的整行数据;删除时为 null",
851
+ "changedFields": "更新时为实际变化的监听字段;新增或删除时为整行字段"
852
+ },
816
853
  "webhook_trigger": {
817
854
  "body": "",
818
855
  "headers": "",
@@ -859,12 +896,9 @@
859
896
  "anyValue": "输出内容在运行时确定"
860
897
  }
861
898
  },
862
- "saveAsInstance": "同时保存为模板",
863
- "instanceNamePlaceholder": "模板名称(必填)",
864
899
  "aiEditHint": "描述要修改的内容",
865
900
  "aiEditPlaceholder": "例如:将超时时间改为 30 分钟",
866
901
  "send": "发送",
867
- "saveChanges": "保存修改",
868
902
  "aiGenerating": "AI 正在生成工作流…",
869
903
  "aiGeneratingHint": "请稍候,工作流画布会自动更新。",
870
904
  "untitled": "未命名工作流",
@@ -988,6 +1022,7 @@
988
1022
  "completed": "已完成",
989
1023
  "running": "运行中",
990
1024
  "failed": "失败",
1025
+ "cancelled": "已取消",
991
1026
  "publishedStatus": "已发布",
992
1027
  "status": "状态",
993
1028
  "version": "版本",
@@ -1038,6 +1073,9 @@
1038
1073
  "openTemporal": "在 Temporal 中查看",
1039
1074
  "cancel": "取消运行",
1040
1075
  "executionDetails": "运行信息",
1076
+ "cancellationRequestedBy": "取消人",
1077
+ "cancellationRequestedAt": "取消时间",
1078
+ "cancellationReason": "取消原因",
1041
1079
  "result": "最终结果",
1042
1080
  "retryAll": "重新运行整个流程",
1043
1081
  "retryAllConfirm": "确定重新运行整个流程吗?",