@gadmin2n/schematics 0.0.147 → 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.
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +67 -15
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +17 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +5 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.spec.ts +24 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.ts +15 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.spec.ts +2 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.spec.ts +28 -29
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +16 -34
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.spec.ts +61 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.spec.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/index.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.controller.ts +11 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.spec.ts +126 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +136 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.controller.ts +24 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.dto.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.service.spec.ts +62 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.service.ts +94 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staff-directory.types.ts +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/staffDirectory/staffDirectory.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user.provider.ts +6 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.spec.ts +20 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.ts +21 -19
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +11 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +97 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.ts +150 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.controller.ts +13 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.dto.ts +13 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.errors.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.spec.ts +125 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.ts +118 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +20 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +6 -9
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-runtime.facade.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.spec.ts +4 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +5 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +44 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +15 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +2 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.spec.ts +33 -22
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +10 -23
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/StaffSelect.test.tsx +69 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/StaffSelect.tsx +145 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/index.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/StaffSelect/staff-directory.api.ts +16 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/index.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.test.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +20 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +49 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +49 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/PeopleGroupModal.tsx +181 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/index.tsx +203 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/people-groups/people-groups.api.ts +145 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/PersonModal.tsx +112 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/index.tsx +214 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/person-directory/person-directory.api.ts +79 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/form-modal.tsx +7 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +7 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.test.tsx +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +97 -28
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +87 -119
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.test.tsx +22 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.tsx +8 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connections.css +8 -46
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connectionsApi.ts +7 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.test.tsx +32 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +163 -106
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +8 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +26 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +34 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-config.css +13 -16
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +185 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +224 -105
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.test.tsx +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +21 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +1 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +160 -8
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +125 -55
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +47 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.test.tsx +33 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.tsx +28 -46
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/human-approval-config.css +16 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/subject-provider.api.ts +0 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.test.tsx +24 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +14 -17
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +1 -0
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CreateNodeInstanceDrawer.tsx +0 -162
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupCreateModal.tsx +0 -72
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
DisconnectOutlined,
|
|
3
3
|
MinusCircleOutlined,
|
|
4
4
|
PlusOutlined,
|
|
5
|
+
SaveOutlined,
|
|
5
6
|
SearchOutlined,
|
|
6
7
|
SendOutlined,
|
|
7
8
|
} from '@ant-design/icons';
|
|
@@ -9,11 +10,11 @@ import {
|
|
|
9
10
|
Alert,
|
|
10
11
|
Button,
|
|
11
12
|
Card,
|
|
12
|
-
Checkbox,
|
|
13
13
|
Form,
|
|
14
14
|
Input,
|
|
15
15
|
InputNumber,
|
|
16
16
|
message,
|
|
17
|
+
Modal,
|
|
17
18
|
Segmented,
|
|
18
19
|
Select,
|
|
19
20
|
Space,
|
|
@@ -44,7 +45,6 @@ import type {
|
|
|
44
45
|
WorkflowNodeType,
|
|
45
46
|
} from '../types';
|
|
46
47
|
import { NodeOutputSummary } from './NodeOutputSummary';
|
|
47
|
-
import { CreateNodeInstanceDrawer } from './CreateNodeInstanceDrawer';
|
|
48
48
|
import { WorkflowCodeEditor } from './WorkflowCodeEditor';
|
|
49
49
|
import '../node-instances/node-config.css';
|
|
50
50
|
import type { ReferencedConfigStatus } from '../hooks/useReferencedNodeInstanceConfigs';
|
|
@@ -186,12 +186,11 @@ function NodePropertyPanelImpl(
|
|
|
186
186
|
const [instances, setInstances] = useState<WorkflowNodeInstance[]>([]);
|
|
187
187
|
const [instanceLoading, setInstanceLoading] = useState(false);
|
|
188
188
|
const [instanceLoadError, setInstanceLoadError] = useState(false);
|
|
189
|
-
const [
|
|
189
|
+
const [saveTemplateOpen, setSaveTemplateOpen] = useState(false);
|
|
190
190
|
const [paletteQuery, setPaletteQuery] = useState('');
|
|
191
|
-
const [
|
|
192
|
-
const [
|
|
193
|
-
const [
|
|
194
|
-
const [alsoSaveAsInstance, setAlsoSaveAsInstance] = useState(false);
|
|
191
|
+
const [templateName, setTemplateName] = useState('');
|
|
192
|
+
const [templateDescription, setTemplateDescription] = useState('');
|
|
193
|
+
const [templateSaving, setTemplateSaving] = useState(false);
|
|
195
194
|
const [configForm] = Form.useForm();
|
|
196
195
|
|
|
197
196
|
// Find configSchema for current node type
|
|
@@ -326,7 +325,6 @@ function NodePropertyPanelImpl(
|
|
|
326
325
|
]);
|
|
327
326
|
setDirty(false);
|
|
328
327
|
setPrompt('');
|
|
329
|
-
setAlsoSaveAsInstance(false);
|
|
330
328
|
}
|
|
331
329
|
}, [node?.id, currentNodeType]);
|
|
332
330
|
|
|
@@ -414,8 +412,7 @@ function NodePropertyPanelImpl(
|
|
|
414
412
|
|
|
415
413
|
// Reset selection when node changes
|
|
416
414
|
useEffect(() => {
|
|
417
|
-
|
|
418
|
-
setCreateInstanceOpen(false);
|
|
415
|
+
setSaveTemplateOpen(false);
|
|
419
416
|
}, [node?.id]);
|
|
420
417
|
|
|
421
418
|
const buildCurrentUpdates = useCallback((): NodePropertyUpdates | null => {
|
|
@@ -590,57 +587,51 @@ function NodePropertyPanelImpl(
|
|
|
590
587
|
}
|
|
591
588
|
}
|
|
592
589
|
|
|
593
|
-
|
|
594
|
-
if (!node) return;
|
|
590
|
+
function openSaveTemplate() {
|
|
591
|
+
if (!node || node.instanceRef) return;
|
|
592
|
+
setTemplateName(node.label.trim());
|
|
593
|
+
setTemplateDescription('');
|
|
594
|
+
setSaveTemplateOpen(true);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async function handleSaveAsTemplate() {
|
|
598
|
+
if (!node || node.instanceRef || !currentNodeType || !templateName.trim())
|
|
599
|
+
return;
|
|
595
600
|
const updates = buildCurrentUpdates();
|
|
596
601
|
if (!updates?.config) return;
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
setInstances((prev) => [...prev, created]);
|
|
630
|
-
setAlsoSaveAsInstance(false);
|
|
631
|
-
setNewInstanceName('');
|
|
632
|
-
setNewInstanceDesc('');
|
|
633
|
-
message.success('已保存并创建新实例');
|
|
634
|
-
} catch (e: any) {
|
|
635
|
-
message.error(e?.message ?? '创建实例失败');
|
|
636
|
-
} finally {
|
|
637
|
-
setSaveAsLoading(false);
|
|
638
|
-
}
|
|
639
|
-
} else {
|
|
640
|
-
onSave(node.id, updates);
|
|
641
|
-
message.success('节点已保存');
|
|
602
|
+
setTemplateSaving(true);
|
|
603
|
+
try {
|
|
604
|
+
const created = await customRequest<WorkflowNodeInstance>(
|
|
605
|
+
'workflowNodeInstance/createOne',
|
|
606
|
+
'POST',
|
|
607
|
+
{
|
|
608
|
+
nodeTypeId: Number(currentNodeType.id),
|
|
609
|
+
name: templateName.trim(),
|
|
610
|
+
description: templateDescription.trim() || null,
|
|
611
|
+
config: updates.config,
|
|
612
|
+
isEnabled: true,
|
|
613
|
+
},
|
|
614
|
+
);
|
|
615
|
+
onSave(node.id, {
|
|
616
|
+
label,
|
|
617
|
+
config: created.config,
|
|
618
|
+
configOverride: null,
|
|
619
|
+
instanceRef: {
|
|
620
|
+
instanceId: String(created.id),
|
|
621
|
+
instanceCode: created.code,
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
setInstances((current) => [
|
|
625
|
+
created,
|
|
626
|
+
...current.filter((item) => item.id !== created.id),
|
|
627
|
+
]);
|
|
628
|
+
setSaveTemplateOpen(false);
|
|
629
|
+
message.success(t('editor.templateSavedAndApplied'));
|
|
630
|
+
} catch (error: any) {
|
|
631
|
+
message.error(error?.message ?? t('editor.templateSaveFailed'));
|
|
632
|
+
} finally {
|
|
633
|
+
setTemplateSaving(false);
|
|
642
634
|
}
|
|
643
|
-
setDirty(false);
|
|
644
635
|
}
|
|
645
636
|
|
|
646
637
|
function handleAiSubmit() {
|
|
@@ -1017,10 +1008,11 @@ function NodePropertyPanelImpl(
|
|
|
1017
1008
|
<Button
|
|
1018
1009
|
size="small"
|
|
1019
1010
|
className="workflow-panel-action"
|
|
1020
|
-
icon={<
|
|
1021
|
-
|
|
1011
|
+
icon={<SaveOutlined />}
|
|
1012
|
+
disabled={referencedConfigUnavailable}
|
|
1013
|
+
onClick={openSaveTemplate}
|
|
1022
1014
|
>
|
|
1023
|
-
{t('editor.
|
|
1015
|
+
{t('editor.saveCurrentAsTemplate')}
|
|
1024
1016
|
</Button>
|
|
1025
1017
|
</div>
|
|
1026
1018
|
<Select
|
|
@@ -1225,64 +1217,40 @@ function NodePropertyPanelImpl(
|
|
|
1225
1217
|
</Card>
|
|
1226
1218
|
)}
|
|
1227
1219
|
</div>
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
)}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
referencedConfigUnavailable ||
|
|
1263
|
-
(!node.instanceRef &&
|
|
1264
|
-
alsoSaveAsInstance &&
|
|
1265
|
-
!newInstanceName.trim())
|
|
1266
|
-
}
|
|
1267
|
-
onClick={handleSave}
|
|
1268
|
-
>
|
|
1269
|
-
{t('editor.saveChanges')}
|
|
1270
|
-
</Button>
|
|
1271
|
-
</footer>
|
|
1272
|
-
)}
|
|
1273
|
-
<CreateNodeInstanceDrawer
|
|
1274
|
-
open={createInstanceOpen}
|
|
1275
|
-
nodeType={currentNodeType}
|
|
1276
|
-
onCancel={() => setCreateInstanceOpen(false)}
|
|
1277
|
-
onCreated={(instance) => {
|
|
1278
|
-
setCreateInstanceOpen(false);
|
|
1279
|
-
setInstances((current) => [
|
|
1280
|
-
instance,
|
|
1281
|
-
...current.filter((item) => item.id !== instance.id),
|
|
1282
|
-
]);
|
|
1283
|
-
referenceInstance(instance);
|
|
1284
|
-
}}
|
|
1285
|
-
/>
|
|
1220
|
+
<Modal
|
|
1221
|
+
open={saveTemplateOpen}
|
|
1222
|
+
title={t('editor.saveCurrentAsTemplate')}
|
|
1223
|
+
okText={t('editor.saveAndUseTemplate')}
|
|
1224
|
+
cancelText={t('common.cancel')}
|
|
1225
|
+
confirmLoading={templateSaving}
|
|
1226
|
+
okButtonProps={{ disabled: !templateName.trim() }}
|
|
1227
|
+
onOk={() => void handleSaveAsTemplate()}
|
|
1228
|
+
onCancel={() => setSaveTemplateOpen(false)}
|
|
1229
|
+
destroyOnHidden
|
|
1230
|
+
>
|
|
1231
|
+
<Typography.Paragraph type="secondary">
|
|
1232
|
+
{t('editor.saveCurrentAsTemplateHint')}
|
|
1233
|
+
</Typography.Paragraph>
|
|
1234
|
+
<Form layout="vertical">
|
|
1235
|
+
<Form.Item label={t('editor.templateName')} required>
|
|
1236
|
+
<Input
|
|
1237
|
+
aria-label={t('editor.templateName')}
|
|
1238
|
+
value={templateName}
|
|
1239
|
+
onChange={(event) => setTemplateName(event.target.value)}
|
|
1240
|
+
autoFocus
|
|
1241
|
+
/>
|
|
1242
|
+
</Form.Item>
|
|
1243
|
+
<Form.Item label={t('common.description')}>
|
|
1244
|
+
<Input.TextArea
|
|
1245
|
+
aria-label={t('common.description')}
|
|
1246
|
+
value={templateDescription}
|
|
1247
|
+
onChange={(event) => setTemplateDescription(event.target.value)}
|
|
1248
|
+
placeholder={t('common.optionalDescription')}
|
|
1249
|
+
rows={3}
|
|
1250
|
+
/>
|
|
1251
|
+
</Form.Item>
|
|
1252
|
+
</Form>
|
|
1253
|
+
</Modal>
|
|
1286
1254
|
</div>
|
|
1287
1255
|
);
|
|
1288
1256
|
}
|
|
@@ -5,14 +5,19 @@ import { WorkflowCodeEditor } from './WorkflowCodeEditor';
|
|
|
5
5
|
|
|
6
6
|
vi.mock('@monaco-editor/react', () => ({
|
|
7
7
|
default: ({
|
|
8
|
+
language,
|
|
8
9
|
value,
|
|
9
10
|
onChange,
|
|
11
|
+
options,
|
|
10
12
|
}: {
|
|
13
|
+
language?: string;
|
|
11
14
|
value?: string;
|
|
12
15
|
onChange?(value: string): void;
|
|
16
|
+
options?: { ariaLabel?: string };
|
|
13
17
|
}) => (
|
|
14
18
|
<textarea
|
|
15
|
-
aria-label=
|
|
19
|
+
aria-label={options?.ariaLabel ?? 'shared editor'}
|
|
20
|
+
data-language={language}
|
|
16
21
|
value={value}
|
|
17
22
|
onChange={(event) => onChange?.(event.target.value)}
|
|
18
23
|
/>
|
|
@@ -39,4 +44,20 @@ describe('WorkflowCodeEditor', () => {
|
|
|
39
44
|
});
|
|
40
45
|
expect(onChange).toHaveBeenCalledWith('{"ok":true}');
|
|
41
46
|
});
|
|
47
|
+
|
|
48
|
+
it('enables Monaco SQL mode and labels the status bar', () => {
|
|
49
|
+
render(
|
|
50
|
+
<WorkflowCodeEditor
|
|
51
|
+
language="sql"
|
|
52
|
+
value="SELECT * FROM users"
|
|
53
|
+
ariaLabel="SQL 语句"
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(screen.getByRole('textbox', { name: 'SQL 语句' })).toHaveAttribute(
|
|
58
|
+
'data-language',
|
|
59
|
+
'sql',
|
|
60
|
+
);
|
|
61
|
+
expect(screen.getByText('SQL')).toBeInTheDocument();
|
|
62
|
+
});
|
|
42
63
|
});
|
|
@@ -2,7 +2,13 @@ import Editor from '@monaco-editor/react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import './workflow-code-editor.css';
|
|
4
4
|
|
|
5
|
-
type WorkflowEditorLanguage = 'json' | 'javascript';
|
|
5
|
+
type WorkflowEditorLanguage = 'json' | 'javascript' | 'sql';
|
|
6
|
+
|
|
7
|
+
const LANGUAGE_LABELS: Record<WorkflowEditorLanguage, string> = {
|
|
8
|
+
json: 'JSON',
|
|
9
|
+
javascript: 'JavaScript',
|
|
10
|
+
sql: 'SQL',
|
|
11
|
+
};
|
|
6
12
|
|
|
7
13
|
export function WorkflowCodeEditor({
|
|
8
14
|
language,
|
|
@@ -67,7 +73,7 @@ export function WorkflowCodeEditor({
|
|
|
67
73
|
}}
|
|
68
74
|
/>
|
|
69
75
|
<div className="workflow-code-editor__status" aria-hidden="true">
|
|
70
|
-
<span>{language
|
|
76
|
+
<span>{LANGUAGE_LABELS[language]}</span>
|
|
71
77
|
<span>UTF-8</span>
|
|
72
78
|
<span>{t('editor.indentSpaces')}: 2</span>
|
|
73
79
|
</div>
|
|
@@ -1,53 +1,15 @@
|
|
|
1
|
-
.workflow-connection-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.workflow-connection-card:focus-visible {
|
|
7
|
-
outline: 2px solid var(--ant-color-primary);
|
|
8
|
-
outline-offset: 2px;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.workflow-connection-card .ant-card-body {
|
|
12
|
-
display: flex;
|
|
13
|
-
flex-direction: column;
|
|
14
|
-
height: 100%;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.workflow-connection-card__header,
|
|
18
|
-
.workflow-connection-card__footer {
|
|
19
|
-
display: flex;
|
|
20
|
-
align-items: flex-start;
|
|
21
|
-
justify-content: space-between;
|
|
22
|
-
gap: 12px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.workflow-connection-card__description {
|
|
26
|
-
min-height: 40px;
|
|
27
|
-
margin: 14px 0 8px;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.workflow-connection-card__url {
|
|
31
|
-
margin: 0 0 14px;
|
|
32
|
-
color: var(--ant-color-text);
|
|
1
|
+
.workflow-connection-table__code {
|
|
2
|
+
display: block;
|
|
3
|
+
margin-top: 2px;
|
|
33
4
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
34
5
|
font-size: 12px;
|
|
35
6
|
}
|
|
36
7
|
|
|
37
|
-
.workflow-connection-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.workflow-connection-card__action {
|
|
45
|
-
display: inline-flex;
|
|
46
|
-
flex: none;
|
|
47
|
-
align-items: center;
|
|
48
|
-
gap: 6px;
|
|
49
|
-
color: var(--ant-color-primary);
|
|
50
|
-
font-weight: 500;
|
|
8
|
+
.workflow-connection-table__url {
|
|
9
|
+
display: block;
|
|
10
|
+
max-width: 260px;
|
|
11
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
12
|
+
font-size: 12px;
|
|
51
13
|
}
|
|
52
14
|
|
|
53
15
|
.workflow-connection-form__section-title {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import i18n from '../../../i18n';
|
|
5
|
-
import { fetchConnections } from './connectionsApi';
|
|
5
|
+
import { deleteConnection, fetchConnections } from './connectionsApi';
|
|
6
6
|
import ConnectionsPage from './index';
|
|
7
7
|
|
|
8
8
|
vi.mock('components', () => ({
|
|
@@ -16,6 +16,7 @@ vi.mock('components', () => ({
|
|
|
16
16
|
|
|
17
17
|
vi.mock('./connectionsApi', () => ({
|
|
18
18
|
fetchConnections: vi.fn(),
|
|
19
|
+
deleteConnection: vi.fn(),
|
|
19
20
|
}));
|
|
20
21
|
|
|
21
22
|
vi.mock('./ConnectionModal', () => ({
|
|
@@ -42,6 +43,11 @@ Object.defineProperty(window, 'matchMedia', {
|
|
|
42
43
|
|
|
43
44
|
describe('ConnectionsPage', () => {
|
|
44
45
|
beforeEach(async () => {
|
|
46
|
+
vi.clearAllMocks();
|
|
47
|
+
const getComputedStyle = window.getComputedStyle.bind(window);
|
|
48
|
+
vi.spyOn(window, 'getComputedStyle').mockImplementation((element) =>
|
|
49
|
+
getComputedStyle(element),
|
|
50
|
+
);
|
|
45
51
|
await i18n.changeLanguage('zh_CN');
|
|
46
52
|
vi.mocked(fetchConnections).mockResolvedValue([
|
|
47
53
|
{
|
|
@@ -57,9 +63,12 @@ describe('ConnectionsPage', () => {
|
|
|
57
63
|
updatedAt: '2026-08-13T00:00:00.000Z',
|
|
58
64
|
},
|
|
59
65
|
]);
|
|
66
|
+
vi.mocked(deleteConnection).mockResolvedValue({ code: 'ticket-system' });
|
|
60
67
|
});
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
afterEach(() => vi.restoreAllMocks());
|
|
70
|
+
|
|
71
|
+
it('opens the connection editor from the table row action', async () => {
|
|
63
72
|
const user = userEvent.setup();
|
|
64
73
|
render(<ConnectionsPage />);
|
|
65
74
|
|
|
@@ -72,4 +81,24 @@ describe('ConnectionsPage', () => {
|
|
|
72
81
|
expect(screen.getByText('正在编辑:工单系统')).toBeInTheDocument(),
|
|
73
82
|
);
|
|
74
83
|
});
|
|
84
|
+
|
|
85
|
+
it('deletes the connection after confirmation', async () => {
|
|
86
|
+
const user = userEvent.setup();
|
|
87
|
+
render(<ConnectionsPage />);
|
|
88
|
+
|
|
89
|
+
await user.click(
|
|
90
|
+
await screen.findByRole('button', { name: '删除 工单系统' }),
|
|
91
|
+
);
|
|
92
|
+
await screen.findByText('删除连接 工单系统?');
|
|
93
|
+
const confirmButton = document.querySelector<HTMLButtonElement>(
|
|
94
|
+
'.ant-popconfirm-buttons .ant-btn-primary',
|
|
95
|
+
);
|
|
96
|
+
expect(confirmButton).not.toBeNull();
|
|
97
|
+
await user.click(confirmButton!);
|
|
98
|
+
|
|
99
|
+
await waitFor(() =>
|
|
100
|
+
expect(deleteConnection).toHaveBeenCalledWith('ticket-system'),
|
|
101
|
+
);
|
|
102
|
+
expect(screen.queryByText('ticket-system')).not.toBeInTheDocument();
|
|
103
|
+
});
|
|
75
104
|
});
|