openxiangda 1.0.124 → 1.0.125

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/README.md CHANGED
@@ -335,6 +335,7 @@ AI-authored workflows can use compile-time SDK resources:
335
335
  - Read-only preview: `preview.json`
336
336
  - Local check: `openxiangda workflow compile src/workflows/<resourceCode>/workflow.ts --check`
337
337
  - Runtime operations: use `sdk.process.resolveCapabilities(...)` or `ProcessActionBar` / `ProcessTimeline` from `openxiangda/runtime/react` instead of hard-coded workflow buttons.
338
+ - Runtime task centers: use `sdk.workCenter.listItems({ boxType: "todo" })` and `sdk.workCenter.getStats()` for the current user's todo/done/cc/initiated lists and counts; do not build end-user todo pages by reading workflow operation logs or raw process-task tables.
338
339
  - Delayed approval start: save a process-form draft without starting workflow via `StandardFormPage submitBehavior="save-draft"` or `sdk.form.create({ formUuid, data, saveAsDraft: true, startProcess: false })`; later call `sdk.process.startFromExistingInstance({ formUuid, formInstId })` or render `StandardFormPage` with `submitBehavior="start-existing-process"` to start approval in place. Do not create a second process instance and delete the draft.
339
340
  - AI workflow cookbook and action payload table: read `openxiangda-skills/references/workflow-v3.md` for the draft -> start existing instance -> return to initiator -> resubmit flow, and for operation payload details such as `approve` using process `instanceId` while `transfer` / `return` / `resubmit` use `taskId`.
340
341
 
@@ -164,7 +164,7 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
164
164
  - Use JS_CODE for node-local cross-form data queries, create/update/batch update operations, process termination, platform API calls, external HTTP calls, and backend trigger orchestration. For logic that pages, automations, and workflows should reuse through a stable backend entry, prefer App Function. Do not use JS_CODE for simple UI interactions, ordinary form validation, or display-only page behavior.
165
165
  - For workflow/automation JS_CODE nodes, prefer V2 `runtimeMode: "trusted_node"`. AI-authored source must be TypeScript under `src/js-code-nodes/<scriptCode>/index.ts`, `src/automations/<resourceCode>/index.ts`, or `src/functions/<functionCode>/index.ts`. `pnpm build-js-code --script <scriptCode>` runs TypeScript validation before bundling, and `sourceFile.localPath` should point to the TS source; the CLI builds, uploads, and replaces it with snapshot metadata during validate/create.
166
166
  - Form permission group resources must have stable local codes. Use unique `code` values such as `ticket_reporter_view` and `ticket_repairer_view`; do not rely on the form code when one form has multiple groups.
167
- - Workflow resources should prefer `workflowFile` + `defineWorkflow` semantic DSL over hand-written raw JSON. For workflows bound by `formCode`, run `openxiangda workspace publish --form <formCode>` first so the process form schema/table is initialized, then run `openxiangda workflow compile <workflow.ts> --check` and `openxiangda resource publish --dry-run --profile <name>` before publish; use `sdk.process.resolveCapabilities(...)` or `ProcessActionBar` / `ProcessTimeline` from `openxiangda/runtime/react` for runtime buttons and timelines instead of hard-coded operation lists. For delayed approval start from an existing saved draft, first save without starting workflow via `StandardFormPage submitBehavior="save-draft"` or `sdk.form.create({ formUuid, data, saveAsDraft: true, startProcess: false })`; later use `sdk.process.startFromExistingInstance({ formUuid, formInstId })` or `StandardFormPage submitBehavior="start-existing-process"`; do not create a duplicate process instance and delete the draft. For custom workflow UI, return-to-initiator, resubmit, and action payload details, read `references/workflow-v3.md` sections `Cookbook: draft, start, return, resubmit` and `Capability action reference`.
167
+ - Workflow resources should prefer `workflowFile` + `defineWorkflow` semantic DSL over hand-written raw JSON. For workflows bound by `formCode`, run `openxiangda workspace publish --form <formCode>` first so the process form schema/table is initialized, then run `openxiangda workflow compile <workflow.ts> --check` and `openxiangda resource publish --dry-run --profile <name>` before publish; use `sdk.process.resolveCapabilities(...)` or `ProcessActionBar` / `ProcessTimeline` from `openxiangda/runtime/react` for runtime buttons and timelines instead of hard-coded operation lists. For end-user task centers, use `sdk.workCenter.listItems({ boxType: "todo" | "done" | "cc" | "initiated" })` and `sdk.workCenter.getStats()` instead of reading workflow logs or process-task tables. For delayed approval start from an existing saved draft, first save without starting workflow via `StandardFormPage submitBehavior="save-draft"` or `sdk.form.create({ formUuid, data, saveAsDraft: true, startProcess: false })`; later use `sdk.process.startFromExistingInstance({ formUuid, formInstId })` or `StandardFormPage submitBehavior="start-existing-process"`; do not create a duplicate process instance and delete the draft. For custom workflow UI, return-to-initiator, resubmit, and action payload details, read `references/workflow-v3.md` sections `Cookbook: draft, start, return, resubmit` and `Capability action reference`.
168
168
  - Workflow resources can be created as drafts. After resource publish, verify `openxiangda workflow list --profile <name> --json` and run `openxiangda workflow publish <workflowCode> --profile <name>` until `isPublished: true` is visible. `workflow list` hides platform shell workflows with empty `resourceCode` by default; pass `--all` only when diagnosing raw platform rows.
169
169
 
170
170
  ## Subskills
@@ -149,6 +149,9 @@ Filters:
149
149
  - Runtime query filters use output aliases such as `ticketTitle`.
150
150
  - Aggregate definition `having` and runtime stats `having` also use output aliases such as `ticketCount`.
151
151
  - Supported operators include `=`, `!=`, `<>`, `>`, `>=`, `<`, `<=`, `contains`, `notContains`, `in`, `isEmpty`, and `isNotEmpty`, with aliases such as `eq`, `neq`, `gte`, `lte`, `like`, `is_null`, and `is_not_null`.
152
+ - Runtime SDK filters may be a search group/rule object or an array, for example `{ key: "statusValue", operator: "EQ", value: "已发布" }`; `field` is also accepted. Use output aliases, not source references.
153
+ - If a row view outputs a full option-like JSON field, runtime string `EQ` and `IN` filters can match the JSON text for compatibility. For new data views, prefer selecting `.value` or `.label` into scalar aliases such as `statusValue` and indexing those aliases for exact, predictable filters.
154
+ - Data view `permissionGroups.dataPermission` should use scalar hidden scope aliases such as `ownerUserScopeKey`, `unionGroupScopeKey`, or `departmentScopeKey`. Do not rely on fuzzy JSON option matching for permission boundaries.
152
155
 
153
156
  Refresh:
154
157
 
@@ -248,7 +251,8 @@ Direct query:
248
251
  const response = await sdk.dataView.query("ticket_with_customer", {
249
252
  fields: ["ticketId", "ticketTitle", "customerName"],
250
253
  filters: [
251
- { field: "customerName", operator: "contains", value: keyword },
254
+ { key: "customerName", operator: "contains", value: keyword },
255
+ { key: "statusValue", operator: "EQ", value: "已发布" },
252
256
  ],
253
257
  order: [{ field: "ticketTitle", isAsc: "y" }],
254
258
  currentPage: 1,
@@ -262,10 +266,10 @@ Aggregate stats query:
262
266
  const response = await sdk.dataView.stats("ticket_stats_by_customer", {
263
267
  fields: ["customerName", "createdMonth", "ticketCount", "totalAmount"],
264
268
  filters: [
265
- { field: "customerName", operator: "contains", value: keyword },
269
+ { key: "customerName", operator: "contains", value: keyword },
266
270
  ],
267
271
  having: [
268
- { field: "ticketCount", operator: ">", value: 0 },
272
+ { key: "ticketCount", operator: ">", value: 0 },
269
273
  ],
270
274
  order: [{ field: "ticketCount", isAsc: "n" }],
271
275
  currentPage: 1,
@@ -296,7 +300,7 @@ export default {
296
300
  code: "ticket_with_customer",
297
301
  fields: ["ticketId", "ticketTitle", "customerName"],
298
302
  defaultFilter: [
299
- { field: "ticketTitle", operator: "isNotEmpty" }
303
+ { key: "ticketTitle", operator: "isNotEmpty" }
300
304
  ]
301
305
  },
302
306
  {
@@ -305,7 +309,7 @@ export default {
305
309
  code: "ticket_stats_by_customer",
306
310
  fields: ["customerName", "ticketCount"],
307
311
  defaultHaving: [
308
- { field: "ticketCount", operator: ">", value: 0 }
312
+ { key: "ticketCount", operator: ">", value: 0 }
309
313
  ]
310
314
  }
311
315
  ]
@@ -313,7 +317,7 @@ export default {
313
317
 
314
318
  const response = await sdk.dataSource.run("tickets", {
315
319
  filters: [
316
- { field: "customerName", operator: "contains", value: keyword }
320
+ { key: "customerName", operator: "contains", value: keyword }
317
321
  ],
318
322
  pageSize: 20,
319
323
  })
@@ -10,10 +10,13 @@ Guidelines:
10
10
  - Data views can be `storageMode: "materialized"` for refreshed report/list data or `storageMode: "live"` for bounded real-time joins. Page code calls the same SDK methods for both modes and should inspect `response.storageMode` / `response.lastRefreshedAt` when freshness is visible to users.
11
11
  - Data view runtime queries can filter, sort, paginate, and select only output aliases.
12
12
  - Keep data view page calls paginated and field-scoped. Runtime filters/order should use aliases that the data view indexes, especially for aggregate dimensions and date buckets.
13
+ - Runtime data view filters may use `{ key, operator, value }` or `{ field, operator, value }`. Prefer `key` in new page code to match search-expression style.
14
+ - If a data view exposes a full option-like JSON field, runtime string `EQ` and `IN` filters can match it for compatibility. New pages should prefer scalar output aliases such as `statusValue` or `statusLabel` declared by the data view.
13
15
  - Use `sdk.dataSource.run()` with a page data source descriptor when the page config should own the data view code, default fields, or default filters.
14
16
  - Use `sdk.function.invoke(code, { input })` for reusable backend business logic declared under `src/resources/functions/` and `src/functions/`. Do not implement multi-form orchestration, connector fan-out, notification orchestration, or permission-sensitive backend rules directly in a page component.
15
17
  - Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
16
18
  - Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
19
+ - Use `sdk.workCenter.listItems({ boxType })` and `sdk.workCenter.getStats()` for current-user work center lists and counts. `boxType` is one of `todo`, `done`, `cc`, or `initiated`. This is the end-user task/handled/cc/initiated surface; do not build todo pages by reading workflow operation logs, automation logs, or raw process-task tables.
17
20
  - Use `createAuthClient` from `openxiangda/runtime` or `LoginPage` / `useAuth` from `openxiangda/runtime/react` for application login pages. Auth provider App Functions return identity assertions only; platform auth owns create/bind/reject/token decisions.
18
21
  - Use `PublicAccessGate` from `openxiangda/runtime/react` or `createPublicAccessClient` from `openxiangda/runtime` for React SPA public pages under `/view/:appType/public/*`. Do not append old `?publicAccess=guest` links in new apps.
19
22
  - In React SPA apps, wrap route children with `OpenXiangdaPageProvider` inside `OpenXiangdaProvider` before using `usePageSdk()`, `usePageContext()`, `useDataSource()`, or `useFormViewPermissions()`. `OpenXiangdaProvider` alone is not enough and missing the page provider causes `usePageSdkStore 必须在 PageProvider 内使用`.
@@ -31,7 +34,8 @@ Data view query:
31
34
  const response = await sdk.dataView.query("ticket_with_customer", {
32
35
  fields: ["ticketId", "ticketTitle", "customerName"],
33
36
  filters: [
34
- { field: "customerName", operator: "contains", value: keyword },
37
+ { key: "customerName", operator: "contains", value: keyword },
38
+ { key: "statusValue", operator: "EQ", value: "已发布" },
35
39
  ],
36
40
  order: [{ field: "ticketTitle", isAsc: "y" }],
37
41
  currentPage: 1,
@@ -45,10 +49,10 @@ Data view stats:
45
49
  const response = await sdk.dataView.stats("ticket_stats_by_customer", {
46
50
  fields: ["customerName", "ticketCount", "totalAmount"],
47
51
  filters: [
48
- { field: "customerName", operator: "contains", value: keyword },
52
+ { key: "customerName", operator: "contains", value: keyword },
49
53
  ],
50
54
  having: [
51
- { field: "ticketCount", operator: ">", value: 0 },
55
+ { key: "ticketCount", operator: ">", value: 0 },
52
56
  ],
53
57
  order: [{ field: "ticketCount", isAsc: "n" }],
54
58
  currentPage: 1,
@@ -67,7 +71,7 @@ export default {
67
71
  code: "ticket_with_customer",
68
72
  fields: ["ticketId", "ticketTitle", "customerName"],
69
73
  defaultFilter: [
70
- { field: "ticketTitle", operator: "isNotEmpty" }
74
+ { key: "ticketTitle", operator: "isNotEmpty" }
71
75
  ]
72
76
  },
73
77
  {
@@ -76,7 +80,7 @@ export default {
76
80
  code: "ticket_stats_by_customer",
77
81
  fields: ["customerName", "ticketCount"],
78
82
  defaultHaving: [
79
- { field: "ticketCount", operator: ">", value: 0 }
83
+ { key: "ticketCount", operator: ">", value: 0 }
80
84
  ]
81
85
  }
82
86
  ]
@@ -84,13 +88,13 @@ export default {
84
88
 
85
89
  const response = await sdk.dataSource.run("tickets", {
86
90
  filters: [
87
- { field: "customerName", operator: "contains", value: keyword }
91
+ { key: "customerName", operator: "contains", value: keyword }
88
92
  ],
89
93
  pageSize: 20,
90
94
  })
91
95
  ```
92
96
 
93
- Data view filters, having, and fields use output aliases such as `customerName` or `ticketCount`, not source references such as `customer.name`. If the page only needs one form, prefer `sdk.form.advancedSearch`. If the page only needs a simple one-form dropdown, prefer linkedForm options.
97
+ Data view filters, having, and fields use output aliases such as `customerName` or `ticketCount`, not source references such as `customer.name`. For option-like fields, prefer scalar aliases such as `statusValue` in the view definition and page filters. If the page only needs one form, prefer `sdk.form.advancedSearch`. If the page only needs a simple one-form dropdown, prefer linkedForm options.
94
98
 
95
99
  App Function invocation:
96
100
 
@@ -105,6 +109,22 @@ const result = await sdk.function.invoke("reservation_reminder_summary", {
105
109
 
106
110
  Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Runtime invocation requires app automation management permission by default. To let ordinary app users call a function from a page, declare the allowed current app roles in `definitionJson.runtimeInvoke.roleCodes`; keep sensitive admin-only functions without broad grants. Inside the function, authorize sensitive actions with trusted runtime context such as `ctx.operator.roleCodes`, `ctx.operator.currentRoleCode`, `ctx.operator.hasFullAccess`, `ctx.currentUser`, or `ctx.permissions`; do not trust role codes sent in the page input. When the function writes forms with `ctx.form.createOne/updateOne/updateById`, treat the write as a trusted backend operation over declared `resources.forms`; do not open direct submit permission on internal forms just for that page action.
107
111
 
112
+ Work center:
113
+
114
+ ```ts
115
+ const todoList = await sdk.workCenter.listItems({
116
+ boxType: "todo",
117
+ page: 1,
118
+ limit: 20,
119
+ keyword,
120
+ appType,
121
+ })
122
+
123
+ const stats = await sdk.workCenter.getStats({ appType })
124
+ ```
125
+
126
+ Use `actionUrl` from a work-center item when present; otherwise link workflow items with both `formUuid` and `formInstanceId` to the app's process detail route. Keep lists paginated and role-scoped by the platform current user.
127
+
108
128
  Application auth:
109
129
 
110
130
  ```tsx
@@ -106,6 +106,8 @@ openxiangda workflow compile src/workflows/expense_approval/workflow.ts \
106
106
 
107
107
  Runtime pages should not guess buttons. Use `sdk.process.resolveCapabilities(...)` or the React helpers from `openxiangda/runtime/react`: `useProcessCapabilities`, `useProcessActions`, `ProcessActionBar`, `ProcessTimeline`, `ProcessPreviewPanel`, and `InitiatorApproverSelector`. The capability protocol returns `visible`, `enabled`, `disabledReason`, `paramsSchema`, `uiSchema`, return candidates, field permissions, and refresh hints for operations such as approve, reject, transfer, return, save, withdraw, resubmit, callback, retryException, and adminTransfer.
108
108
 
109
+ Runtime todo, done, cc, and initiated lists should use `sdk.workCenter.listItems({ boxType })` plus `sdk.workCenter.getStats()`. These APIs return the current user's projected work-center items with pagination, app/form filters, status/result filters, `actionUrl`, `formUuid`, `formInstanceId`, `taskId`, and node/title snapshots. Do not query workflow operation logs, automation logs, or raw process task tables for end-user task-center pages.
110
+
109
111
  For delayed approval start, do not submit a process form and then delete/recreate records. Save the process-form instance without starting workflow via `StandardFormPage submitBehavior="save-draft"` or `sdk.form.create({ formUuid, data, saveAsDraft: true, startProcess: false })`. Later start approval on that same `formInstId` with `sdk.process.startFromExistingInstance({ formUuid, formInstId })` or `StandardFormPage submitBehavior="start-existing-process"`.
110
112
 
111
113
  For return-to-initiator workflows, prefer `returnPolicy: { scopeType: "initiator", resubmitMode: "resume_current" }` or `flow.action.returnToInitiator()`. The runtime capabilities protocol exposes `resubmit` only on pending `originator_return` tasks. If a user returns to a previous approval node, continuing the flow is a normal `approve` action on that returned approval task.
@@ -24,6 +24,7 @@ Create a workflow only when the scenario has **real approval semantics**: approv
24
24
  - ✅ New AI-authored automations: prefer **code-first** `automation_code_ts` (`src/automations/<code>/index.ts` + `definition.code.json` + `preview.json`).
25
25
  - ✅ New AI-authored workflows: prefer **semantic DSL** `src/workflows/<code>/workflow.ts` using `defineWorkflow`; compile it to v3 designer JSON with `openxiangda workflow compile`.
26
26
  - ✅ Runtime workflow pages: use `sdk.process.resolveCapabilities(...)` or `ProcessActionBar` / `ProcessTimeline` from `openxiangda/runtime/react`; do not hard-code buttons.
27
+ - ✅ Runtime task centers: use `sdk.workCenter.listItems({ boxType: "todo" | "done" | "cc" | "initiated" })` and `sdk.workCenter.getStats()` for current-user lists/counts; do not read workflow logs, automation logs, or raw process-task tables for end-user todo pages.
27
28
  - ✅ Before custom workflow UI or delayed approval work, read `references/workflow-v3.md` sections **Cookbook: draft, start, return, resubmit** and **Capability action reference** for payloads, required IDs, and refresh rules.
28
29
  - ✅ Delayed approval start: save the process-form record first with `StandardFormPage submitBehavior="save-draft"` or `sdk.form.create({ formUuid, data, saveAsDraft: true, startProcess: false })`, then start approval in place with `sdk.process.startFromExistingInstance({ formUuid, formInstId })` or `StandardFormPage submitBehavior="start-existing-process"`.
29
30
  - ✅ Return-to-initiator flows: use `returnPolicy: { scopeType: "initiator", resubmitMode: "resume_current" | "replay" }` or `flow.action.returnToInitiator()`. The runtime capabilities protocol exposes `resubmit` only for pending `originator_return` tasks; return to a previous approval node continues through the normal `approve` action.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.124",
3
+ "version": "1.0.125",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -2486,6 +2486,24 @@ var createPageSdk = (context) => {
2486
2486
  method: "post"
2487
2487
  })
2488
2488
  };
2489
+ const workCenter = {
2490
+ listItems: (params) => request({
2491
+ path: "/work-center/items",
2492
+ method: "get",
2493
+ query: {
2494
+ ...params,
2495
+ appType: resolveAppType(context, params.appType)
2496
+ }
2497
+ }),
2498
+ getStats: (params = {}) => request({
2499
+ path: "/work-center/stats",
2500
+ method: "get",
2501
+ query: {
2502
+ ...params,
2503
+ appType: resolveAppType(context, params.appType)
2504
+ }
2505
+ })
2506
+ };
2489
2507
  const sdk = {
2490
2508
  context,
2491
2509
  request,
@@ -2503,6 +2521,7 @@ var createPageSdk = (context) => {
2503
2521
  permission,
2504
2522
  process: process2,
2505
2523
  notification,
2524
+ workCenter,
2506
2525
  dataView,
2507
2526
  function: appFunction,
2508
2527
  dataSource: {