@rytass/bpm-core-client 0.1.3 → 0.1.5

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 (62) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +69 -3
  4. package/package.json +5 -4
  5. package/src/index.js +7 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/api-auth-client.d.ts +73 -0
  8. package/src/lib/api-auth-client.js +121 -0
  9. package/src/lib/api-auth-client.js.map +1 -0
  10. package/src/lib/form/form-api.d.ts +48 -0
  11. package/src/lib/form/form-api.js +228 -0
  12. package/src/lib/form/form-api.js.map +1 -0
  13. package/src/lib/form/form-rendering.d.ts +52 -0
  14. package/src/lib/form/form-rendering.js +341 -0
  15. package/src/lib/form/form-rendering.js.map +1 -0
  16. package/src/lib/form/index.js +6 -0
  17. package/src/lib/form/index.js.map +1 -0
  18. package/src/lib/graphql-client.d.ts +45 -0
  19. package/src/lib/graphql-client.js +92 -0
  20. package/src/lib/graphql-client.js.map +1 -0
  21. package/src/lib/member-api.d.ts +49 -0
  22. package/src/lib/member-api.js +72 -0
  23. package/src/lib/member-api.js.map +1 -0
  24. package/src/lib/organization/index.js +5 -0
  25. package/src/lib/organization/index.js.map +1 -0
  26. package/src/lib/organization/organization-api.d.ts +168 -0
  27. package/src/lib/organization/organization-api.js +394 -0
  28. package/src/lib/organization/organization-api.js.map +1 -0
  29. package/src/lib/template/index.js +5 -0
  30. package/src/lib/template/index.js.map +1 -0
  31. package/src/lib/template/template-api.d.ts +150 -0
  32. package/src/lib/template/template-api.js +407 -0
  33. package/src/lib/template/template-api.js.map +1 -0
  34. package/src/lib/workflow/index.js +5 -0
  35. package/src/lib/workflow/index.js.map +1 -0
  36. package/src/lib/workflow/workflow-api.d.ts +376 -0
  37. package/src/lib/workflow/workflow-api.js +867 -0
  38. package/src/lib/workflow/workflow-api.js.map +1 -0
  39. package/eslint.config.mjs +0 -19
  40. package/jest.config.cts +0 -10
  41. package/project.json +0 -66
  42. package/src/lib/api-auth-client.ts +0 -169
  43. package/src/lib/form/form-api.spec.ts +0 -81
  44. package/src/lib/form/form-api.ts +0 -388
  45. package/src/lib/form/form-rendering.ts +0 -580
  46. package/src/lib/graphql-client.spec.ts +0 -65
  47. package/src/lib/graphql-client.ts +0 -114
  48. package/src/lib/member-api.ts +0 -129
  49. package/src/lib/organization/organization-api.spec.ts +0 -90
  50. package/src/lib/organization/organization-api.ts +0 -710
  51. package/src/lib/template/template-api.spec.ts +0 -88
  52. package/src/lib/template/template-api.ts +0 -772
  53. package/src/lib/workflow/workflow-api.spec.ts +0 -132
  54. package/src/lib/workflow/workflow-api.ts +0 -1749
  55. package/tsconfig.json +0 -27
  56. package/tsconfig.lib.json +0 -16
  57. package/tsconfig.spec.json +0 -16
  58. /package/src/{index.ts → index.d.ts} +0 -0
  59. /package/src/lib/form/{index.ts → index.d.ts} +0 -0
  60. /package/src/lib/organization/{index.ts → index.d.ts} +0 -0
  61. /package/src/lib/template/{index.ts → index.d.ts} +0 -0
  62. /package/src/lib/workflow/{index.ts → index.d.ts} +0 -0
@@ -1,1749 +0,0 @@
1
- import {
2
- FormDefinitionSchema,
3
- FormFieldDefinition,
4
- FormFieldValue,
5
- FormUiSchema,
6
- SelectFieldDefinition,
7
- } from '@rytass/bpm-core-shared/form';
8
- import { WorkflowDefinition } from '@rytass/bpm-core-shared/workflow';
9
- import { requestGraphQl } from '../graphql-client';
10
-
11
- export type ApprovalInstanceState =
12
- | 'APPROVED'
13
- | 'CANCELLED'
14
- | 'DRAFT'
15
- | 'EXPIRED'
16
- | 'REJECTED'
17
- | 'RETURNED'
18
- | 'RUNNING';
19
-
20
- export type TaskStatus =
21
- | 'CANCELLED'
22
- | 'COMPLETED'
23
- | 'IN_PROGRESS'
24
- | 'PENDING'
25
- | 'TRANSFERRED';
26
-
27
- export type TaskAssignmentType = 'CANDIDATE_GROUP' | 'DIRECT_MEMBER';
28
-
29
- export type TaskDecisionAction =
30
- | 'APPROVED'
31
- | 'REJECTED'
32
- | 'RETURNED'
33
- | 'TRANSFERRED';
34
-
35
- export interface ApprovalInstanceRecord {
36
- readonly completedAt: string | null;
37
- readonly formData: WorkflowFormData;
38
- readonly formDataJson: string;
39
- readonly formDefinitionSnapshot: FormDefinitionSnapshot;
40
- readonly formDefinitionSnapshotJson: string;
41
- readonly id: string;
42
- readonly initiatorMemberId: string;
43
- readonly startedAt: string;
44
- readonly state: ApprovalInstanceState;
45
- readonly templateId: string;
46
- readonly templateVersionId: string;
47
- readonly title: string;
48
- readonly workflowSnapshot: WorkflowDefinition;
49
- readonly workflowSnapshotJson: string;
50
- }
51
-
52
- export interface FormDefinitionSnapshot {
53
- readonly formDefinitionVersionId?: string;
54
- readonly schema?: FormDefinitionSchema;
55
- readonly uiSchema?: FormUiSchema;
56
- readonly version?: number;
57
- }
58
-
59
- export type WorkflowFormData = Readonly<
60
- Record<string, FormFieldValue | undefined>
61
- >;
62
-
63
- export interface TaskRecord {
64
- readonly assigneeMemberId: string | null;
65
- readonly assignmentType: TaskAssignmentType;
66
- readonly candidateMemberIds: readonly string[];
67
- readonly completedAt: string | null;
68
- readonly createdAt: string;
69
- readonly decisionPolicySnapshotJson: string;
70
- readonly delegationChainJson: string;
71
- readonly id: string;
72
- readonly instanceId: string;
73
- readonly nodeId: string;
74
- readonly openedAt: string | null;
75
- readonly originalAssigneeMemberId: string | null;
76
- readonly slaDueAt: string | null;
77
- readonly status: TaskStatus;
78
- readonly tokenId: string;
79
- }
80
-
81
- export interface TaskCandidateRecord {
82
- readonly claimedAt: string | null;
83
- readonly createdAt: string;
84
- readonly decidedAt: string | null;
85
- readonly delegationChainJson: string;
86
- readonly id: string;
87
- readonly memberId: string;
88
- readonly originalMemberId: string;
89
- readonly sourceType: string;
90
- readonly status: string;
91
- readonly taskId: string;
92
- }
93
-
94
- export interface WorkflowTokenRecord {
95
- readonly consumedAt: string | null;
96
- readonly createdAt: string;
97
- readonly currentNodeId: string;
98
- readonly id: string;
99
- readonly instanceId: string;
100
- readonly parentTokenId: string | null;
101
- readonly status: 'ACTIVE' | 'CONSUMED' | 'WAITING';
102
- }
103
-
104
- export interface TaskDecisionRecord {
105
- readonly action: TaskDecisionAction;
106
- readonly comment: string | null;
107
- readonly decidedAt: string;
108
- readonly decidedByMemberId: string;
109
- readonly id: string;
110
- readonly returnToNodeId: string | null;
111
- readonly signatureId: string | null;
112
- readonly taskId: string;
113
- readonly transferToMemberId: string | null;
114
- }
115
-
116
- export interface ActivityLogRecord {
117
- readonly actorMemberId: string | null;
118
- readonly createdAt: string;
119
- readonly eventType: string;
120
- readonly id: string;
121
- readonly nodeId: string | null;
122
- readonly payloadJson: string;
123
- readonly taskId: string | null;
124
- }
125
-
126
- export interface MemberProfileRecord {
127
- readonly email: string;
128
- readonly memberId: string;
129
- readonly name: string;
130
- }
131
-
132
- export interface MemberDirectoryPage {
133
- readonly members: readonly MemberProfileRecord[];
134
- readonly totalCount: number;
135
- }
136
-
137
- export type DelegationScopeType = 'ALL' | 'CONDITION_BASED' | 'TEMPLATE_LIST';
138
-
139
- export type DelegationRuleStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED';
140
-
141
- export type NotificationChannel = 'EMAIL' | 'IN_APP' | 'WEBHOOK';
142
-
143
- export type NotificationDigestMode = 'DAILY' | 'INSTANT';
144
-
145
- export type NotificationStatus = 'FAILED' | 'PENDING' | 'READ' | 'SENT';
146
-
147
- export type NotificationType =
148
- | 'INSTANCE_COMPLETED'
149
- | 'SLA_OVERDUE'
150
- | 'SLA_WARNING'
151
- | 'TASK_ASSIGNED'
152
- | 'TASK_TRANSFERRED';
153
-
154
- export interface NotificationRecord {
155
- readonly attemptCount: number;
156
- readonly body: string;
157
- readonly channel: NotificationChannel;
158
- readonly createdAt: string;
159
- readonly deliveredAt: string | null;
160
- readonly deliveryError: string | null;
161
- readonly deliveryTarget: string | null;
162
- readonly id: string;
163
- readonly instanceId: string | null;
164
- readonly lastAttemptAt: string | null;
165
- readonly nextRetryAt: string | null;
166
- readonly payloadJson: string;
167
- readonly readAt: string | null;
168
- readonly recipientMemberId: string;
169
- readonly sentAt: string | null;
170
- readonly status: NotificationStatus;
171
- readonly taskId: string | null;
172
- readonly title: string;
173
- readonly type: NotificationType;
174
- }
175
-
176
- export interface NotificationPreferenceRecord {
177
- readonly emailDigestMode: NotificationDigestMode;
178
- readonly emailEnabled: boolean;
179
- readonly inAppEnabled: boolean;
180
- readonly memberId: string;
181
- readonly quietHoursEnd: string | null;
182
- readonly quietHoursStart: string | null;
183
- readonly updatedAt: string;
184
- }
185
-
186
- export interface DelegationRuleRecord {
187
- readonly agentMemberId: string;
188
- readonly createdAt: string;
189
- readonly createdByMemberId: string | null;
190
- readonly endAt: string | null;
191
- readonly id: string;
192
- readonly principalMemberId: string;
193
- readonly priority: number;
194
- readonly requiresConfirmation: boolean;
195
- readonly revokedAt: string | null;
196
- readonly revokedByMemberId: string | null;
197
- readonly scopeConditionCel: string | null;
198
- readonly scopeTemplateIds: readonly string[];
199
- readonly scopeType: DelegationScopeType;
200
- readonly startAt: string;
201
- readonly status: DelegationRuleStatus;
202
- readonly updatedAt: string;
203
- }
204
-
205
- export interface AttachmentRecord {
206
- readonly checksumSha256: string;
207
- readonly createdAt: string;
208
- readonly filename: string;
209
- readonly formFieldPath: string | null;
210
- readonly id: string;
211
- readonly instanceId: string | null;
212
- readonly mimeType: string;
213
- readonly sizeBytes: string;
214
- readonly storageKey: string;
215
- readonly storageProvider: string;
216
- readonly taskId: string | null;
217
- readonly uploaderMemberId: string;
218
- }
219
-
220
- export interface SignatureRecord {
221
- readonly algorithm: string;
222
- readonly id: string;
223
- readonly instanceId: string;
224
- readonly keyVersion: number;
225
- readonly previousSignatureHash: string | null;
226
- readonly signature: string;
227
- readonly signedAt: string;
228
- readonly signedPayloadHash: string;
229
- readonly signedPayloadJson: string;
230
- readonly signerMemberId: string;
231
- readonly taskId: string | null;
232
- readonly timestampTokenBase64: string | null;
233
- }
234
-
235
- export interface SignatureVerificationRecord {
236
- readonly checkedCount: number;
237
- readonly errors: readonly string[];
238
- readonly instanceId: string;
239
- readonly valid: boolean;
240
- }
241
-
242
- export interface ApprovalTemplateRecord {
243
- readonly currentVersionId: string | null;
244
- readonly id: string;
245
- readonly name: string;
246
- readonly updatedAt?: string;
247
- }
248
-
249
- export interface ApprovalTemplateVersionRecord {
250
- readonly formDefinitionVersionId: string | null;
251
- readonly id: string;
252
- readonly status: 'ARCHIVED' | 'DRAFT' | 'PUBLISHED';
253
- readonly version: number;
254
- }
255
-
256
- export interface LaunchContext {
257
- readonly formVersion: {
258
- readonly id: string;
259
- readonly schema: FormDefinitionSchema;
260
- readonly uiSchema: FormUiSchema;
261
- readonly version: number;
262
- };
263
- readonly template: ApprovalTemplateRecord;
264
- readonly templateVersion: ApprovalTemplateVersionRecord;
265
- }
266
-
267
- export interface LaunchableTemplateRecord {
268
- readonly currentVersionId: string;
269
- readonly formDefinitionVersionId: string;
270
- readonly id: string;
271
- readonly name: string;
272
- readonly updatedAt: string;
273
- readonly version: number;
274
- }
275
-
276
- export type ApprovalInstanceView = 'ALL' | 'CC' | 'SENT';
277
-
278
- export interface ApprovalInstancesPageInput {
279
- readonly page: number;
280
- readonly pageSize: number;
281
- readonly searchText: string | null;
282
- readonly state: ApprovalInstanceState | null;
283
- readonly templateId: string | null;
284
- readonly view: ApprovalInstanceView;
285
- }
286
-
287
- export interface ApprovalInstancesPageResult {
288
- readonly instances: readonly ApprovalInstanceRecord[];
289
- readonly pageInfo: ApprovalInstancePageInfoRecord;
290
- readonly totalCount: number;
291
- }
292
-
293
- export interface ApprovalInstancePageInfoRecord {
294
- readonly hasNextPage: boolean;
295
- readonly hasPreviousPage: boolean;
296
- readonly page: number;
297
- readonly pageSize: number;
298
- readonly totalCount: number;
299
- readonly totalPages: number;
300
- }
301
-
302
- export interface WorkflowDashboardSummaryRecord {
303
- readonly activeInstanceCount: number;
304
- readonly completedInstanceCount: number;
305
- readonly overdueTaskCount: number;
306
- readonly pendingTaskCount: number;
307
- readonly rejectedInstanceCount: number;
308
- readonly totalInstanceCount: number;
309
- readonly unreadNotificationCount: number;
310
- }
311
-
312
- interface ApprovalInstancesQueryData {
313
- readonly approvalInstances: readonly InstanceJsonRecord[];
314
- }
315
-
316
- interface ApprovalInstancePageInfoQueryData {
317
- readonly approvalInstancePageInfo: ApprovalInstancePageInfoRecord;
318
- }
319
-
320
- interface WorkflowDashboardSummaryQueryData {
321
- readonly workflowDashboardSummary: Omit<
322
- WorkflowDashboardSummaryRecord,
323
- 'unreadNotificationCount'
324
- >;
325
- }
326
-
327
- interface ApprovalInstanceQueryData {
328
- readonly approvalInstance: InstanceJsonRecord;
329
- readonly activityLogs: readonly ActivityLogRecord[];
330
- readonly tasks: readonly TaskRecord[];
331
- readonly workflowTokens: readonly WorkflowTokenRecord[];
332
- }
333
-
334
- interface InboxTasksQueryData {
335
- readonly inboxTasks: readonly TaskRecord[];
336
- }
337
-
338
- interface ApprovalHistoryTasksQueryData {
339
- readonly approvalHistoryTasks: readonly TaskRecord[];
340
- }
341
-
342
- interface TaskDecisionsQueryData {
343
- readonly taskDecisions: readonly TaskDecisionRecord[];
344
- }
345
-
346
- interface AttachmentsQueryData {
347
- readonly attachments: readonly AttachmentRecord[];
348
- }
349
-
350
- interface AttachmentDownloadUrlQueryData {
351
- readonly attachmentDownloadUrl: string;
352
- }
353
-
354
- interface AttachmentPreviewUrlQueryData {
355
- readonly attachmentPreviewUrl: string;
356
- }
357
-
358
- interface SignaturesQueryData {
359
- readonly signatures: readonly SignatureRecord[];
360
- readonly verifySignatureChain: SignatureVerificationRecord;
361
- }
362
-
363
- interface UploadAttachmentMutationData {
364
- readonly uploadAttachment: AttachmentRecord;
365
- }
366
-
367
- interface MembersQueryData {
368
- readonly members: readonly MemberProfileRecord[];
369
- }
370
-
371
- interface SearchMembersQueryData {
372
- readonly searchMembers: readonly MemberProfileRecord[];
373
- }
374
-
375
- interface MemberDirectoryPageQueryData {
376
- readonly memberCount: number;
377
- readonly searchMembers: readonly MemberProfileRecord[];
378
- }
379
-
380
- interface DelegationRulesQueryData {
381
- readonly delegationRules: readonly DelegationRuleRecord[];
382
- }
383
-
384
- interface DelegationRulesPageQueryData extends DelegationRulesQueryData {
385
- readonly delegationRuleCount: number;
386
- }
387
-
388
- interface NotificationsQueryData {
389
- readonly notificationCount: number;
390
- readonly notifications: readonly NotificationRecord[];
391
- readonly unreadNotificationCount: number;
392
- }
393
-
394
- interface NotificationPreferenceQueryData {
395
- readonly notificationPreference: NotificationPreferenceRecord;
396
- }
397
-
398
- interface CreateDelegationRuleMutationData {
399
- readonly createDelegationRule: DelegationRuleRecord;
400
- }
401
-
402
- interface RevokeDelegationRuleMutationData {
403
- readonly revokeDelegationRule: DelegationRuleRecord;
404
- }
405
-
406
- interface MarkNotificationReadMutationData {
407
- readonly markNotificationRead: Pick<
408
- NotificationRecord,
409
- 'id' | 'readAt' | 'status'
410
- >;
411
- }
412
-
413
- interface UpdateNotificationPreferenceMutationData {
414
- readonly updateNotificationPreference: NotificationPreferenceRecord;
415
- }
416
-
417
- interface SubmitApprovalInstanceMutationData {
418
- readonly submitApprovalInstance: Pick<ApprovalInstanceRecord, 'id'>;
419
- }
420
-
421
- interface DecideTaskMutationData {
422
- readonly decideTask: TaskDecisionRecord;
423
- }
424
-
425
- interface CancelApprovalInstanceMutationData {
426
- readonly cancelApprovalInstance: Pick<ApprovalInstanceRecord, 'id' | 'state'>;
427
- }
428
-
429
- interface ResubmitApprovalInstanceMutationData {
430
- readonly resubmitApprovalInstance: Pick<
431
- ApprovalInstanceRecord,
432
- 'id' | 'state'
433
- >;
434
- }
435
-
436
- interface LaunchTemplateQueryData {
437
- readonly approvalTemplate: ApprovalTemplateRecord & {
438
- readonly updatedAt: string;
439
- };
440
- readonly approvalTemplateVersions: readonly ApprovalTemplateVersionRecord[];
441
- readonly launchableApprovalTemplates?: readonly (ApprovalTemplateRecord & {
442
- readonly updatedAt: string;
443
- })[];
444
- }
445
-
446
- interface LaunchTemplatesQueryData {
447
- readonly approvalTemplates?: readonly (ApprovalTemplateRecord & {
448
- readonly updatedAt: string;
449
- })[];
450
- readonly launchableApprovalTemplates?: readonly (ApprovalTemplateRecord & {
451
- readonly updatedAt: string;
452
- })[];
453
- }
454
-
455
- interface LaunchTemplateVersionsQueryData {
456
- readonly approvalTemplateVersions: readonly ApprovalTemplateVersionRecord[];
457
- }
458
-
459
- interface LaunchFormVersionQueryData {
460
- readonly formDefinitionVersion: {
461
- readonly id: string;
462
- readonly schemaJson: string;
463
- readonly uiSchemaJson: string;
464
- readonly version: number;
465
- };
466
- }
467
-
468
- interface InstanceJsonRecord extends Omit<
469
- ApprovalInstanceRecord,
470
- 'formData' | 'formDefinitionSnapshot' | 'workflowSnapshot'
471
- > {
472
- readonly formDataJson: string;
473
- readonly formDefinitionSnapshotJson: string;
474
- readonly workflowSnapshotJson: string;
475
- }
476
-
477
- export async function listApprovalInstances(): Promise<
478
- readonly ApprovalInstanceRecord[]
479
- > {
480
- const data = await requestGraphQl<ApprovalInstancesQueryData>(
481
- `query ApprovalInstances {
482
- approvalInstances {
483
- completedAt
484
- formDataJson
485
- formDefinitionSnapshotJson
486
- id
487
- initiatorMemberId
488
- startedAt
489
- state
490
- templateId
491
- templateVersionId
492
- title
493
- workflowSnapshotJson
494
- }
495
- }`,
496
- );
497
-
498
- return data.approvalInstances.map(parseInstanceJson);
499
- }
500
-
501
- export async function listApprovalInstancesPage({
502
- page,
503
- pageSize,
504
- searchText,
505
- state,
506
- templateId,
507
- view,
508
- }: ApprovalInstancesPageInput): Promise<ApprovalInstancesPageResult> {
509
- const variables = {
510
- page,
511
- pageSize,
512
- searchText: searchText?.trim() || null,
513
- state: state ? [state] : null,
514
- templateId: templateId?.trim() || null,
515
- view,
516
- };
517
- const [pageData, pageInfoData] = await Promise.all([
518
- requestGraphQl<ApprovalInstancesQueryData>(
519
- `query ApprovalInstancesPage(
520
- $view: ApprovalInstanceListView
521
- $searchText: String
522
- $state: [ApprovalInstanceState!]
523
- $templateId: String
524
- $page: Int
525
- $pageSize: Int
526
- ) {
527
- approvalInstances(
528
- view: $view
529
- searchText: $searchText
530
- state: $state
531
- templateId: $templateId
532
- page: $page
533
- pageSize: $pageSize
534
- ) {
535
- completedAt
536
- formDataJson
537
- formDefinitionSnapshotJson
538
- id
539
- initiatorMemberId
540
- startedAt
541
- state
542
- templateId
543
- templateVersionId
544
- title
545
- workflowSnapshotJson
546
- }
547
- }`,
548
- variables,
549
- ),
550
- requestGraphQl<ApprovalInstancePageInfoQueryData>(
551
- `query ApprovalInstancePageInfo(
552
- $view: ApprovalInstanceListView
553
- $searchText: String
554
- $state: [ApprovalInstanceState!]
555
- $templateId: String
556
- $page: Int
557
- $pageSize: Int
558
- ) {
559
- approvalInstancePageInfo(
560
- view: $view
561
- searchText: $searchText
562
- state: $state
563
- templateId: $templateId
564
- page: $page
565
- pageSize: $pageSize
566
- ) {
567
- hasNextPage
568
- hasPreviousPage
569
- page
570
- pageSize
571
- totalCount
572
- totalPages
573
- }
574
- }`,
575
- variables,
576
- ),
577
- ]);
578
- const pageInfo = pageInfoData.approvalInstancePageInfo;
579
-
580
- return {
581
- instances: pageData.approvalInstances.map(parseInstanceJson),
582
- pageInfo,
583
- totalCount: pageInfo.totalCount,
584
- };
585
- }
586
-
587
- export async function readLaunchContext(
588
- templateId: string,
589
- ): Promise<LaunchContext> {
590
- const templateData = await requestGraphQl<LaunchTemplateQueryData>(
591
- `query LaunchTemplate($id: String!) {
592
- approvalTemplate(id: $id) {
593
- currentVersionId
594
- id
595
- name
596
- }
597
- approvalTemplateVersions(templateId: $id) {
598
- formDefinitionVersionId
599
- id
600
- status
601
- version
602
- }
603
- launchableApprovalTemplates {
604
- currentVersionId
605
- id
606
- name
607
- updatedAt
608
- }
609
- }`,
610
- { id: templateId },
611
- );
612
- const templateVersion = templateData.approvalTemplateVersions.find(
613
- (version) => version.id === templateData.approvalTemplate.currentVersionId,
614
- );
615
-
616
- if (!templateVersion || templateVersion.status !== 'PUBLISHED') {
617
- throw new Error('模板尚未發布,無法發起簽核。');
618
- }
619
-
620
- if (!templateVersion.formDefinitionVersionId) {
621
- throw new Error('模板尚未綁定表單版本,無法發起簽核。');
622
- }
623
-
624
- const launchableApprovalTemplates =
625
- templateData.launchableApprovalTemplates ?? [templateData.approvalTemplate];
626
-
627
- if (
628
- !launchableApprovalTemplates.some((template) => template.id === templateId)
629
- ) {
630
- throw new Error('目前登入者沒有此模板的發起權限。');
631
- }
632
-
633
- const formData = await requestGraphQl<LaunchFormVersionQueryData>(
634
- `query LaunchFormVersion($id: String!) {
635
- formDefinitionVersion(id: $id) {
636
- id
637
- schemaJson
638
- uiSchemaJson
639
- version
640
- }
641
- }`,
642
- { id: templateVersion.formDefinitionVersionId },
643
- );
644
-
645
- return {
646
- formVersion: {
647
- id: formData.formDefinitionVersion.id,
648
- schema: JSON.parse(
649
- formData.formDefinitionVersion.schemaJson,
650
- ) as FormDefinitionSchema,
651
- uiSchema: JSON.parse(
652
- formData.formDefinitionVersion.uiSchemaJson,
653
- ) as FormUiSchema,
654
- version: formData.formDefinitionVersion.version,
655
- },
656
- template: templateData.approvalTemplate,
657
- templateVersion,
658
- };
659
- }
660
-
661
- export async function listLaunchableTemplates(): Promise<
662
- readonly LaunchableTemplateRecord[]
663
- > {
664
- const templateData = await requestGraphQl<LaunchTemplatesQueryData>(
665
- `query ApprovalTemplates {
666
- launchableApprovalTemplates {
667
- currentVersionId
668
- id
669
- name
670
- updatedAt
671
- }
672
- }`,
673
- );
674
- const launchableApprovalTemplates =
675
- templateData.launchableApprovalTemplates ??
676
- templateData.approvalTemplates ??
677
- [];
678
- const versionLists = await Promise.all(
679
- launchableApprovalTemplates.map((template) =>
680
- requestGraphQl<LaunchTemplateVersionsQueryData>(
681
- `query LaunchTemplateVersions($templateId: String!) {
682
- approvalTemplateVersions(templateId: $templateId) {
683
- formDefinitionVersionId
684
- id
685
- status
686
- version
687
- }
688
- }`,
689
- { templateId: template.id },
690
- ),
691
- ),
692
- );
693
-
694
- return launchableApprovalTemplates.flatMap((template, index) => {
695
- const currentVersion = versionLists[index]?.approvalTemplateVersions.find(
696
- (version) => version.id === template.currentVersionId,
697
- );
698
-
699
- return currentVersion?.status === 'PUBLISHED' &&
700
- currentVersion.formDefinitionVersionId
701
- ? [
702
- {
703
- currentVersionId: currentVersion.id,
704
- formDefinitionVersionId: currentVersion.formDefinitionVersionId,
705
- id: template.id,
706
- name: template.name,
707
- updatedAt: template.updatedAt,
708
- version: currentVersion.version,
709
- },
710
- ]
711
- : [];
712
- });
713
- }
714
-
715
- export async function readApprovalInstance(instanceId: string): Promise<{
716
- readonly activityLogs: readonly ActivityLogRecord[];
717
- readonly instance: ApprovalInstanceRecord;
718
- readonly tasks: readonly TaskRecord[];
719
- readonly workflowTokens: readonly WorkflowTokenRecord[];
720
- }> {
721
- const data = await requestGraphQl<ApprovalInstanceQueryData>(
722
- `query ApprovalInstance($id: String!) {
723
- approvalInstance(id: $id) {
724
- completedAt
725
- formDataJson
726
- formDefinitionSnapshotJson
727
- id
728
- initiatorMemberId
729
- startedAt
730
- state
731
- templateId
732
- templateVersionId
733
- title
734
- workflowSnapshotJson
735
- }
736
- tasks(instanceId: $id) {
737
- assigneeMemberId
738
- assignmentType
739
- candidateMemberIds
740
- completedAt
741
- createdAt
742
- decisionPolicySnapshotJson
743
- delegationChainJson
744
- id
745
- instanceId
746
- nodeId
747
- openedAt
748
- originalAssigneeMemberId
749
- slaDueAt
750
- status
751
- tokenId
752
- }
753
- workflowTokens(instanceId: $id) {
754
- consumedAt
755
- createdAt
756
- currentNodeId
757
- id
758
- instanceId
759
- parentTokenId
760
- status
761
- }
762
- activityLogs(instanceId: $id) {
763
- actorMemberId
764
- createdAt
765
- eventType
766
- id
767
- nodeId
768
- payloadJson
769
- taskId
770
- }
771
- }`,
772
- { id: instanceId },
773
- );
774
-
775
- return {
776
- activityLogs: data.activityLogs,
777
- instance: parseInstanceJson(data.approvalInstance),
778
- tasks: normalizeTaskRecords(data.tasks),
779
- workflowTokens: data.workflowTokens,
780
- };
781
- }
782
-
783
- export async function listInboxTasks(
784
- assigneeMemberId: string,
785
- ): Promise<readonly TaskRecord[]> {
786
- const data = await requestGraphQl<InboxTasksQueryData>(
787
- `query InboxTasks($assigneeMemberId: String!) {
788
- inboxTasks(assigneeMemberId: $assigneeMemberId) {
789
- assigneeMemberId
790
- assignmentType
791
- candidateMemberIds
792
- completedAt
793
- createdAt
794
- decisionPolicySnapshotJson
795
- delegationChainJson
796
- id
797
- instanceId
798
- nodeId
799
- openedAt
800
- originalAssigneeMemberId
801
- slaDueAt
802
- status
803
- tokenId
804
- }
805
- }`,
806
- { assigneeMemberId },
807
- );
808
-
809
- return normalizeTaskRecords(data.inboxTasks);
810
- }
811
-
812
- export async function listApprovalHistoryTasks(
813
- assigneeMemberId: string,
814
- ): Promise<readonly TaskRecord[]> {
815
- const data = await requestGraphQl<ApprovalHistoryTasksQueryData>(
816
- `query ApprovalHistoryTasks($assigneeMemberId: String!) {
817
- approvalHistoryTasks(assigneeMemberId: $assigneeMemberId) {
818
- assigneeMemberId
819
- assignmentType
820
- candidateMemberIds
821
- completedAt
822
- createdAt
823
- decisionPolicySnapshotJson
824
- delegationChainJson
825
- id
826
- instanceId
827
- nodeId
828
- openedAt
829
- originalAssigneeMemberId
830
- slaDueAt
831
- status
832
- tokenId
833
- }
834
- }`,
835
- { assigneeMemberId },
836
- );
837
-
838
- return normalizeTaskRecords(data.approvalHistoryTasks);
839
- }
840
-
841
- export async function readWorkflowDashboardSummary({
842
- currentMemberId,
843
- from,
844
- to,
845
- }: {
846
- readonly currentMemberId: string;
847
- readonly from: string | null;
848
- readonly to: string | null;
849
- }): Promise<WorkflowDashboardSummaryRecord> {
850
- const [summaryData, notificationResult] = await Promise.all([
851
- requestGraphQl<WorkflowDashboardSummaryQueryData>(
852
- `query WorkflowDashboardSummary($from: DateTime, $to: DateTime) {
853
- workflowDashboardSummary(from: $from, to: $to) {
854
- activeInstanceCount
855
- completedInstanceCount
856
- overdueTaskCount
857
- pendingTaskCount
858
- rejectedInstanceCount
859
- totalInstanceCount
860
- }
861
- }`,
862
- { from, to },
863
- ),
864
- listNotifications({
865
- includeRead: true,
866
- page: 1,
867
- pageSize: 1,
868
- recipientMemberId: currentMemberId,
869
- }),
870
- ]);
871
-
872
- return {
873
- ...summaryData.workflowDashboardSummary,
874
- unreadNotificationCount: notificationResult.unreadCount,
875
- };
876
- }
877
-
878
- function normalizeTaskRecords(
879
- tasks: readonly TaskRecord[],
880
- ): readonly TaskRecord[] {
881
- return tasks.map((task) => ({
882
- ...task,
883
- assignmentType: task.assignmentType ?? 'DIRECT_MEMBER',
884
- candidateMemberIds: task.candidateMemberIds ?? [],
885
- decisionPolicySnapshotJson:
886
- task.decisionPolicySnapshotJson ?? JSON.stringify({ type: 'SINGLE' }),
887
- }));
888
- }
889
-
890
- export async function listTaskDecisions(
891
- taskId: string,
892
- ): Promise<readonly TaskDecisionRecord[]> {
893
- const data = await requestGraphQl<TaskDecisionsQueryData>(
894
- `query TaskDecisions($taskId: String!) {
895
- taskDecisions(taskId: $taskId) {
896
- action
897
- comment
898
- decidedAt
899
- decidedByMemberId
900
- id
901
- returnToNodeId
902
- signatureId
903
- taskId
904
- transferToMemberId
905
- }
906
- }`,
907
- { taskId },
908
- );
909
-
910
- return data.taskDecisions;
911
- }
912
-
913
- export async function listAttachments(
914
- instanceId: string,
915
- ): Promise<readonly AttachmentRecord[]> {
916
- const data = await requestGraphQl<AttachmentsQueryData>(
917
- `query InstanceAttachments($instanceId: String!) {
918
- attachments(instanceId: $instanceId) {
919
- checksumSha256
920
- createdAt
921
- filename
922
- formFieldPath
923
- id
924
- instanceId
925
- mimeType
926
- sizeBytes
927
- storageKey
928
- storageProvider
929
- taskId
930
- uploaderMemberId
931
- }
932
- }`,
933
- { instanceId },
934
- );
935
-
936
- return data.attachments ?? [];
937
- }
938
-
939
- export async function uploadAttachment({
940
- file,
941
- formFieldPath,
942
- }: {
943
- readonly file: File;
944
- readonly formFieldPath: string;
945
- }): Promise<AttachmentRecord> {
946
- const contentBase64 = await readFileBase64(file);
947
- const checksumSha256 = await hashFileSha256(file);
948
- const data = await requestGraphQl<UploadAttachmentMutationData>(
949
- `mutation UploadAttachment($input: UploadAttachmentInput!) {
950
- uploadAttachment(input: $input) {
951
- checksumSha256
952
- createdAt
953
- filename
954
- formFieldPath
955
- id
956
- instanceId
957
- mimeType
958
- sizeBytes
959
- storageKey
960
- storageProvider
961
- taskId
962
- uploaderMemberId
963
- }
964
- }`,
965
- {
966
- input: {
967
- checksumSha256,
968
- contentBase64,
969
- filename: file.name,
970
- formFieldPath,
971
- instanceId: null,
972
- mimeType: file.type || 'application/octet-stream',
973
- sizeBytes: file.size,
974
- taskId: null,
975
- },
976
- },
977
- );
978
-
979
- return data.uploadAttachment;
980
- }
981
-
982
- export async function readAttachmentDownloadUrl({
983
- id,
984
- }: {
985
- readonly id: string;
986
- }): Promise<string> {
987
- const data = await requestGraphQl<AttachmentDownloadUrlQueryData>(
988
- `query AttachmentDownloadUrl($id: String!) {
989
- attachmentDownloadUrl(id: $id)
990
- }`,
991
- { id },
992
- );
993
-
994
- return data.attachmentDownloadUrl;
995
- }
996
-
997
- export async function readAttachmentPreviewUrl({
998
- id,
999
- }: {
1000
- readonly id: string;
1001
- }): Promise<string> {
1002
- const data = await requestGraphQl<AttachmentPreviewUrlQueryData>(
1003
- `query AttachmentPreviewUrl($id: String!) {
1004
- attachmentPreviewUrl(id: $id)
1005
- }`,
1006
- { id },
1007
- );
1008
-
1009
- return data.attachmentPreviewUrl;
1010
- }
1011
-
1012
- export async function readInstanceSignatures(instanceId: string): Promise<{
1013
- readonly signatures: readonly SignatureRecord[];
1014
- readonly verification: SignatureVerificationRecord;
1015
- }> {
1016
- const data = await requestGraphQl<SignaturesQueryData>(
1017
- `query InstanceSignatures($instanceId: String!) {
1018
- signatures(instanceId: $instanceId) {
1019
- algorithm
1020
- id
1021
- instanceId
1022
- keyVersion
1023
- previousSignatureHash
1024
- signature
1025
- signedAt
1026
- signedPayloadHash
1027
- signedPayloadJson
1028
- signerMemberId
1029
- taskId
1030
- timestampTokenBase64
1031
- }
1032
- verifySignatureChain(instanceId: $instanceId) {
1033
- checkedCount
1034
- errors
1035
- instanceId
1036
- valid
1037
- }
1038
- }`,
1039
- { instanceId },
1040
- );
1041
-
1042
- return {
1043
- signatures: data.signatures ?? [],
1044
- verification: data.verifySignatureChain ?? {
1045
- checkedCount: 0,
1046
- errors: [],
1047
- instanceId,
1048
- valid: true,
1049
- },
1050
- };
1051
- }
1052
-
1053
- export async function resolveMemberProfiles(
1054
- memberIds: readonly string[],
1055
- ): Promise<readonly MemberProfileRecord[]> {
1056
- if (memberIds.length === 0) {
1057
- return [];
1058
- }
1059
-
1060
- const data = await requestGraphQl<MembersQueryData>(
1061
- `query InstanceMembers($memberIds: [String!]!) {
1062
- members(memberIds: $memberIds) {
1063
- email
1064
- memberId
1065
- name
1066
- }
1067
- }`,
1068
- { memberIds },
1069
- );
1070
-
1071
- return data.members;
1072
- }
1073
-
1074
- export async function searchMembers(
1075
- searchText: string,
1076
- ): Promise<readonly MemberProfileRecord[]> {
1077
- const data = await requestGraphQl<SearchMembersQueryData>(
1078
- `query SearchMembers($searchText: String!) {
1079
- searchMembers(searchText: $searchText) {
1080
- email
1081
- memberId
1082
- name
1083
- }
1084
- }`,
1085
- { searchText },
1086
- );
1087
-
1088
- return data.searchMembers;
1089
- }
1090
-
1091
- export async function listMemberDirectoryPage({
1092
- page,
1093
- pageSize,
1094
- searchText = '',
1095
- }: {
1096
- readonly page: number;
1097
- readonly pageSize: number;
1098
- readonly searchText?: string;
1099
- }): Promise<MemberDirectoryPage> {
1100
- const data = await requestGraphQl<MemberDirectoryPageQueryData>(
1101
- `query MemberDirectoryPage($page: Int, $pageSize: Int, $searchText: String!) {
1102
- searchMembers(page: $page, pageSize: $pageSize, searchText: $searchText) {
1103
- email
1104
- memberId
1105
- name
1106
- }
1107
- memberCount(searchText: $searchText)
1108
- }`,
1109
- { page, pageSize, searchText },
1110
- );
1111
-
1112
- return {
1113
- members: data.searchMembers,
1114
- totalCount: data.memberCount,
1115
- };
1116
- }
1117
-
1118
- export async function listDelegationRules({
1119
- includeInactive = true,
1120
- principalMemberId = null,
1121
- }: {
1122
- readonly includeInactive?: boolean;
1123
- readonly principalMemberId?: string | null;
1124
- } = {}): Promise<readonly DelegationRuleRecord[]> {
1125
- const data = await requestGraphQl<DelegationRulesQueryData>(
1126
- `query DelegationRules($includeInactive: Boolean, $principalMemberId: String) {
1127
- delegationRules(
1128
- includeInactive: $includeInactive
1129
- principalMemberId: $principalMemberId
1130
- ) {
1131
- agentMemberId
1132
- createdAt
1133
- createdByMemberId
1134
- endAt
1135
- id
1136
- principalMemberId
1137
- priority
1138
- requiresConfirmation
1139
- revokedAt
1140
- revokedByMemberId
1141
- scopeConditionCel
1142
- scopeTemplateIds
1143
- scopeType
1144
- startAt
1145
- status
1146
- updatedAt
1147
- }
1148
- }`,
1149
- { includeInactive, principalMemberId },
1150
- );
1151
-
1152
- return data.delegationRules;
1153
- }
1154
-
1155
- export async function listDelegationRulesPage({
1156
- agentMemberId = null,
1157
- includeInactive = true,
1158
- page = 1,
1159
- pageSize = 10,
1160
- principalMemberId = null,
1161
- scopeType = null,
1162
- status = null,
1163
- }: {
1164
- readonly agentMemberId?: string | null;
1165
- readonly includeInactive?: boolean;
1166
- readonly page?: number;
1167
- readonly pageSize?: number;
1168
- readonly principalMemberId?: string | null;
1169
- readonly scopeType?: DelegationScopeType | null;
1170
- readonly status?: DelegationRuleStatus | null;
1171
- } = {}): Promise<{
1172
- readonly rules: readonly DelegationRuleRecord[];
1173
- readonly totalCount: number;
1174
- }> {
1175
- const data = await requestGraphQl<DelegationRulesPageQueryData>(
1176
- `query DelegationRulesPage(
1177
- $includeInactive: Boolean
1178
- $page: Int
1179
- $pageSize: Int
1180
- $principalMemberId: String
1181
- $agentMemberId: String
1182
- $scopeType: DelegationScopeType
1183
- $status: DelegationRuleStatus
1184
- ) {
1185
- delegationRules(
1186
- agentMemberId: $agentMemberId
1187
- includeInactive: $includeInactive
1188
- page: $page
1189
- pageSize: $pageSize
1190
- principalMemberId: $principalMemberId
1191
- scopeType: $scopeType
1192
- status: $status
1193
- ) {
1194
- agentMemberId
1195
- createdAt
1196
- createdByMemberId
1197
- endAt
1198
- id
1199
- principalMemberId
1200
- priority
1201
- requiresConfirmation
1202
- revokedAt
1203
- revokedByMemberId
1204
- scopeConditionCel
1205
- scopeTemplateIds
1206
- scopeType
1207
- startAt
1208
- status
1209
- updatedAt
1210
- }
1211
- delegationRuleCount(
1212
- agentMemberId: $agentMemberId
1213
- includeInactive: $includeInactive
1214
- principalMemberId: $principalMemberId
1215
- scopeType: $scopeType
1216
- status: $status
1217
- )
1218
- }`,
1219
- {
1220
- agentMemberId,
1221
- includeInactive,
1222
- page,
1223
- pageSize,
1224
- principalMemberId,
1225
- scopeType,
1226
- status,
1227
- },
1228
- );
1229
-
1230
- return {
1231
- rules: data.delegationRules,
1232
- totalCount: data.delegationRuleCount,
1233
- };
1234
- }
1235
-
1236
- export async function createDelegationRule(input: {
1237
- readonly agentMemberId: string;
1238
- readonly createdByMemberId: string | null;
1239
- readonly endAt: string | null;
1240
- readonly principalMemberId: string;
1241
- readonly priority: number;
1242
- readonly requiresConfirmation: boolean;
1243
- readonly scopeConditionCel: string | null;
1244
- readonly scopeTemplateIds: readonly string[];
1245
- readonly scopeType: DelegationScopeType;
1246
- readonly startAt: string | null;
1247
- }): Promise<DelegationRuleRecord> {
1248
- const data = await requestGraphQl<CreateDelegationRuleMutationData>(
1249
- `mutation CreateDelegationRule($input: CreateDelegationRuleInput!) {
1250
- createDelegationRule(input: $input) {
1251
- agentMemberId
1252
- createdAt
1253
- createdByMemberId
1254
- endAt
1255
- id
1256
- principalMemberId
1257
- priority
1258
- requiresConfirmation
1259
- revokedAt
1260
- revokedByMemberId
1261
- scopeConditionCel
1262
- scopeTemplateIds
1263
- scopeType
1264
- startAt
1265
- status
1266
- updatedAt
1267
- }
1268
- }`,
1269
- { input },
1270
- );
1271
-
1272
- return data.createDelegationRule;
1273
- }
1274
-
1275
- export async function revokeDelegationRule({
1276
- id,
1277
- revokedByMemberId,
1278
- }: {
1279
- readonly id: string;
1280
- readonly revokedByMemberId: string | null;
1281
- }): Promise<DelegationRuleRecord> {
1282
- const data = await requestGraphQl<RevokeDelegationRuleMutationData>(
1283
- `mutation RevokeDelegationRule($id: String!, $revokedByMemberId: String) {
1284
- revokeDelegationRule(id: $id, revokedByMemberId: $revokedByMemberId) {
1285
- agentMemberId
1286
- createdAt
1287
- createdByMemberId
1288
- endAt
1289
- id
1290
- principalMemberId
1291
- priority
1292
- requiresConfirmation
1293
- revokedAt
1294
- revokedByMemberId
1295
- scopeConditionCel
1296
- scopeTemplateIds
1297
- scopeType
1298
- startAt
1299
- status
1300
- updatedAt
1301
- }
1302
- }`,
1303
- { id, revokedByMemberId },
1304
- );
1305
-
1306
- return data.revokeDelegationRule;
1307
- }
1308
-
1309
- export async function listNotifications({
1310
- includeRead = true,
1311
- page = 1,
1312
- pageSize = 10,
1313
- recipientMemberId,
1314
- }: {
1315
- readonly includeRead?: boolean;
1316
- readonly page?: number;
1317
- readonly pageSize?: number;
1318
- readonly recipientMemberId: string;
1319
- }): Promise<{
1320
- readonly notifications: readonly NotificationRecord[];
1321
- readonly totalCount: number;
1322
- readonly unreadCount: number;
1323
- }> {
1324
- const data = await requestGraphQl<NotificationsQueryData>(
1325
- `query Notifications(
1326
- $recipientMemberId: String!
1327
- $includeRead: Boolean
1328
- $page: Int
1329
- $pageSize: Int
1330
- ) {
1331
- notifications(
1332
- includeRead: $includeRead
1333
- page: $page
1334
- pageSize: $pageSize
1335
- recipientMemberId: $recipientMemberId
1336
- ) {
1337
- attemptCount
1338
- body
1339
- channel
1340
- createdAt
1341
- deliveredAt
1342
- deliveryError
1343
- deliveryTarget
1344
- id
1345
- instanceId
1346
- lastAttemptAt
1347
- nextRetryAt
1348
- payloadJson
1349
- readAt
1350
- recipientMemberId
1351
- sentAt
1352
- status
1353
- taskId
1354
- title
1355
- type
1356
- }
1357
- notificationCount(
1358
- includeRead: $includeRead
1359
- recipientMemberId: $recipientMemberId
1360
- )
1361
- unreadNotificationCount(recipientMemberId: $recipientMemberId)
1362
- }`,
1363
- { includeRead, page, pageSize, recipientMemberId },
1364
- );
1365
-
1366
- return {
1367
- notifications: data.notifications,
1368
- totalCount: data.notificationCount,
1369
- unreadCount: data.unreadNotificationCount,
1370
- };
1371
- }
1372
-
1373
- export async function readUnreadNotificationCount(
1374
- recipientMemberId: string,
1375
- ): Promise<number> {
1376
- const data = await requestGraphQl<{
1377
- readonly unreadNotificationCount: number;
1378
- }>(
1379
- `query UnreadNotificationCount($recipientMemberId: String!) {
1380
- unreadNotificationCount(recipientMemberId: $recipientMemberId)
1381
- }`,
1382
- { recipientMemberId },
1383
- );
1384
-
1385
- return data.unreadNotificationCount;
1386
- }
1387
-
1388
- export async function markNotificationRead({
1389
- id,
1390
- readerMemberId,
1391
- }: {
1392
- readonly id: string;
1393
- readonly readerMemberId: string;
1394
- }): Promise<Pick<NotificationRecord, 'id' | 'readAt' | 'status'>> {
1395
- const data = await requestGraphQl<MarkNotificationReadMutationData>(
1396
- `mutation MarkNotificationRead($id: String!, $readerMemberId: String) {
1397
- markNotificationRead(id: $id, readerMemberId: $readerMemberId) {
1398
- id
1399
- readAt
1400
- status
1401
- }
1402
- }`,
1403
- { id, readerMemberId },
1404
- );
1405
-
1406
- return data.markNotificationRead;
1407
- }
1408
-
1409
- export async function markAllNotificationsRead({
1410
- recipientMemberId,
1411
- }: {
1412
- readonly recipientMemberId: string;
1413
- }): Promise<number> {
1414
- const data = await requestGraphQl<{
1415
- readonly markAllNotificationsRead: number;
1416
- }>(
1417
- `mutation MarkAllNotificationsRead($recipientMemberId: String) {
1418
- markAllNotificationsRead(recipientMemberId: $recipientMemberId)
1419
- }`,
1420
- { recipientMemberId },
1421
- );
1422
-
1423
- return data.markAllNotificationsRead;
1424
- }
1425
-
1426
- export async function readNotificationPreference(
1427
- memberId: string,
1428
- ): Promise<NotificationPreferenceRecord> {
1429
- const data = await requestGraphQl<NotificationPreferenceQueryData>(
1430
- `query NotificationPreference($memberId: String!) {
1431
- notificationPreference(memberId: $memberId) {
1432
- emailDigestMode
1433
- emailEnabled
1434
- inAppEnabled
1435
- memberId
1436
- quietHoursEnd
1437
- quietHoursStart
1438
- updatedAt
1439
- }
1440
- }`,
1441
- { memberId },
1442
- );
1443
-
1444
- return data.notificationPreference;
1445
- }
1446
-
1447
- export async function updateNotificationPreference(input: {
1448
- readonly emailDigestMode: NotificationDigestMode;
1449
- readonly emailEnabled: boolean;
1450
- readonly inAppEnabled: boolean;
1451
- readonly memberId: string;
1452
- readonly quietHoursEnd: string | null;
1453
- readonly quietHoursStart: string | null;
1454
- }): Promise<NotificationPreferenceRecord> {
1455
- const data = await requestGraphQl<UpdateNotificationPreferenceMutationData>(
1456
- `mutation UpdateNotificationPreference($input: UpdateNotificationPreferenceInput!) {
1457
- updateNotificationPreference(input: $input) {
1458
- emailDigestMode
1459
- emailEnabled
1460
- inAppEnabled
1461
- memberId
1462
- quietHoursEnd
1463
- quietHoursStart
1464
- updatedAt
1465
- }
1466
- }`,
1467
- { input },
1468
- );
1469
-
1470
- return data.updateNotificationPreference;
1471
- }
1472
-
1473
- export async function submitApprovalInstance({
1474
- formData,
1475
- initiatorMemberId,
1476
- templateId,
1477
- title,
1478
- }: {
1479
- readonly formData: Readonly<Record<string, unknown>>;
1480
- readonly initiatorMemberId: string;
1481
- readonly templateId: string;
1482
- readonly title: string | null;
1483
- }): Promise<string> {
1484
- const data = await requestGraphQl<SubmitApprovalInstanceMutationData>(
1485
- `mutation SubmitApprovalInstance($input: SubmitApprovalInstanceInput!) {
1486
- submitApprovalInstance(input: $input) {
1487
- id
1488
- }
1489
- }`,
1490
- {
1491
- input: {
1492
- formDataJson: JSON.stringify(formData),
1493
- initiatorMemberId,
1494
- initiatorMetadataSnapshotJson: null,
1495
- templateId,
1496
- title,
1497
- },
1498
- },
1499
- );
1500
-
1501
- return data.submitApprovalInstance.id;
1502
- }
1503
-
1504
- export async function decideTask({
1505
- action,
1506
- comment,
1507
- decidedByMemberId,
1508
- returnToNodeId = null,
1509
- taskId,
1510
- transferToMemberId = null,
1511
- }: {
1512
- readonly action: TaskDecisionAction;
1513
- readonly comment: string | null;
1514
- readonly decidedByMemberId: string;
1515
- readonly returnToNodeId?: string | null;
1516
- readonly taskId: string;
1517
- readonly transferToMemberId?: string | null;
1518
- }): Promise<TaskDecisionRecord> {
1519
- const data = await requestGraphQl<DecideTaskMutationData>(
1520
- `mutation DecideTask($input: DecideTaskInput!) {
1521
- decideTask(input: $input) {
1522
- action
1523
- comment
1524
- decidedAt
1525
- decidedByMemberId
1526
- id
1527
- returnToNodeId
1528
- signatureId
1529
- taskId
1530
- transferToMemberId
1531
- }
1532
- }`,
1533
- {
1534
- input: {
1535
- action,
1536
- comment,
1537
- decidedByMemberId,
1538
- returnToNodeId,
1539
- taskId,
1540
- transferToMemberId,
1541
- },
1542
- },
1543
- );
1544
-
1545
- return data.decideTask;
1546
- }
1547
-
1548
- export async function cancelApprovalInstance({
1549
- cancelledByMemberId,
1550
- comment,
1551
- instanceId,
1552
- }: {
1553
- readonly cancelledByMemberId: string;
1554
- readonly comment: string | null;
1555
- readonly instanceId: string;
1556
- }): Promise<void> {
1557
- await requestGraphQl<CancelApprovalInstanceMutationData>(
1558
- `mutation CancelApprovalInstance($input: CancelApprovalInstanceInput!) {
1559
- cancelApprovalInstance(input: $input) {
1560
- id
1561
- state
1562
- }
1563
- }`,
1564
- {
1565
- input: {
1566
- cancelledByMemberId,
1567
- comment,
1568
- instanceId,
1569
- },
1570
- },
1571
- );
1572
- }
1573
-
1574
- export async function resubmitApprovalInstance({
1575
- formData,
1576
- initiatorMemberId,
1577
- instanceId,
1578
- title,
1579
- }: {
1580
- readonly formData: Readonly<Record<string, unknown>>;
1581
- readonly initiatorMemberId: string;
1582
- readonly instanceId: string;
1583
- readonly title: string | null;
1584
- }): Promise<void> {
1585
- await requestGraphQl<ResubmitApprovalInstanceMutationData>(
1586
- `mutation ResubmitApprovalInstance($input: ResubmitApprovalInstanceInput!) {
1587
- resubmitApprovalInstance(input: $input) {
1588
- id
1589
- state
1590
- }
1591
- }`,
1592
- {
1593
- input: {
1594
- formDataJson: JSON.stringify(formData),
1595
- initiatorMemberId,
1596
- instanceId,
1597
- title,
1598
- },
1599
- },
1600
- );
1601
- }
1602
-
1603
- export function readApprovalInstanceCaseTitle(
1604
- instance: ApprovalInstanceRecord,
1605
- ): string {
1606
- return readFormDataCaseTitle({
1607
- fallbackTitle: instance.title || instance.id,
1608
- formData: instance.formData,
1609
- schema: instance.formDefinitionSnapshot.schema ?? null,
1610
- uiSchema: instance.formDefinitionSnapshot.uiSchema ?? null,
1611
- });
1612
- }
1613
-
1614
- export function readFormDataCaseTitle({
1615
- fallbackTitle,
1616
- formData,
1617
- schema,
1618
- uiSchema,
1619
- }: {
1620
- readonly fallbackTitle: string;
1621
- readonly formData: WorkflowFormData;
1622
- readonly schema: FormDefinitionSchema | null;
1623
- readonly uiSchema: FormUiSchema | null;
1624
- }): string {
1625
- const firstField = readFirstCaseTitleField(schema, uiSchema);
1626
-
1627
- if (!firstField) {
1628
- return fallbackTitle;
1629
- }
1630
-
1631
- const valueLabel = readFieldValueLabel(
1632
- firstField,
1633
- formData[firstField.fieldKey],
1634
- );
1635
-
1636
- return valueLabel ? `${firstField.label}:${valueLabel}` : fallbackTitle;
1637
- }
1638
-
1639
- function parseInstanceJson(record: InstanceJsonRecord): ApprovalInstanceRecord {
1640
- return {
1641
- ...record,
1642
- formData: JSON.parse(record.formDataJson) as WorkflowFormData,
1643
- formDefinitionSnapshot: JSON.parse(
1644
- record.formDefinitionSnapshotJson,
1645
- ) as FormDefinitionSnapshot,
1646
- workflowSnapshot: JSON.parse(
1647
- record.workflowSnapshotJson,
1648
- ) as WorkflowDefinition,
1649
- };
1650
- }
1651
-
1652
- async function readFileBase64(file: File): Promise<string> {
1653
- const buffer = await file.arrayBuffer();
1654
- const bytes = new Uint8Array(buffer);
1655
- const chunkSize = 0x8000;
1656
- const chunks = Array.from(
1657
- { length: Math.ceil(bytes.length / chunkSize) },
1658
- (_, index): string =>
1659
- String.fromCharCode(
1660
- ...bytes.slice(index * chunkSize, (index + 1) * chunkSize),
1661
- ),
1662
- );
1663
-
1664
- return btoa(chunks.join(''));
1665
- }
1666
-
1667
- async function hashFileSha256(file: File): Promise<string> {
1668
- const digest = await crypto.subtle.digest(
1669
- 'SHA-256',
1670
- await file.arrayBuffer(),
1671
- );
1672
- const bytes = Array.from(new Uint8Array(digest));
1673
-
1674
- return bytes.map((byte) => byte.toString(16).padStart(2, '0')).join('');
1675
- }
1676
-
1677
- function readFirstCaseTitleField(
1678
- schema: FormDefinitionSchema | null,
1679
- uiSchema: FormUiSchema | null,
1680
- ): FormFieldDefinition | null {
1681
- if (!schema?.fields.length) {
1682
- return null;
1683
- }
1684
-
1685
- const fieldsByKey = new Map(
1686
- schema.fields.map((field) => [field.fieldKey, field]),
1687
- );
1688
- const firstLayoutField = uiSchema?.layout
1689
- .map((layoutItem) => fieldsByKey.get(layoutItem.fieldKey) ?? null)
1690
- .find((field): field is FormFieldDefinition => Boolean(field));
1691
-
1692
- return firstLayoutField ?? schema.fields[0] ?? null;
1693
- }
1694
-
1695
- function readFieldValueLabel(
1696
- field: FormFieldDefinition,
1697
- value: FormFieldValue | undefined,
1698
- ): string | null {
1699
- if (typeof value === 'undefined' || value === null) {
1700
- return null;
1701
- }
1702
-
1703
- if (Array.isArray(value)) {
1704
- return readArrayFieldValueLabel(field, value);
1705
- }
1706
-
1707
- if (field.type === 'boolean') {
1708
- return value === true ? '是' : '否';
1709
- }
1710
-
1711
- if (isSelectFieldDefinition(field) && typeof value === 'string') {
1712
- return readSelectOptionLabel(field, value);
1713
- }
1714
-
1715
- const valueLabel = String(value).trim();
1716
-
1717
- return valueLabel || null;
1718
- }
1719
-
1720
- function readArrayFieldValueLabel(
1721
- field: FormFieldDefinition,
1722
- value: readonly string[],
1723
- ): string | null {
1724
- const labels = isSelectFieldDefinition(field)
1725
- ? value.map((item) => readSelectOptionLabel(field, item))
1726
- : value;
1727
- const label = labels.filter((item) => item.trim()).join('、');
1728
-
1729
- return label || null;
1730
- }
1731
-
1732
- function readSelectOptionLabel(
1733
- field: SelectFieldDefinition,
1734
- value: string,
1735
- ): string {
1736
- return (
1737
- field.options.find((option) => option.value === value)?.label ?? value
1738
- ).trim();
1739
- }
1740
-
1741
- function isSelectFieldDefinition(
1742
- field: FormFieldDefinition,
1743
- ): field is SelectFieldDefinition {
1744
- return (
1745
- field.type === 'select' ||
1746
- field.type === 'radio' ||
1747
- field.type === 'checkbox'
1748
- );
1749
- }