@objectstack/plugin-approvals 17.0.0-rc.5 → 17.0.0

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/index.js CHANGED
@@ -63,11 +63,11 @@ var init_en_objects_generated = __esm({
63
63
  label: "Status",
64
64
  help: "Lifecycle state of the request",
65
65
  options: {
66
- pending: "pending",
67
- approved: "approved",
68
- rejected: "rejected",
69
- recalled: "recalled",
70
- returned: "returned"
66
+ pending: "Pending",
67
+ approved: "Approved",
68
+ rejected: "Rejected",
69
+ recalled: "Recalled",
70
+ returned: "Returned"
71
71
  }
72
72
  },
73
73
  current_step: {
@@ -140,7 +140,7 @@ var init_en_objects_generated = __esm({
140
140
  },
141
141
  approval_reject: {
142
142
  label: "Reject",
143
- confirmText: "Reject this request? A rejection is final for every approver.",
143
+ description: "Reject this request? A rejection is final for every approver.",
144
144
  successMessage: "Rejected.",
145
145
  params: {
146
146
  comment: {
@@ -193,7 +193,7 @@ var init_en_objects_generated = __esm({
193
193
  },
194
194
  approval_recall: {
195
195
  label: "Recall",
196
- confirmText: "Recall this request? Approvers can no longer act on it and the record is unlocked.",
196
+ description: "Recall this request? Approvers can no longer act on it and the record is unlocked.",
197
197
  successMessage: "Recalled.",
198
198
  params: {
199
199
  comment: {
@@ -237,18 +237,18 @@ var init_en_objects_generated = __esm({
237
237
  action: {
238
238
  label: "Action",
239
239
  options: {
240
- submit: "submit",
241
- approve: "approve",
242
- reject: "reject",
243
- recall: "recall",
244
- escalate: "escalate",
245
- reassign: "reassign",
246
- remind: "remind",
247
- request_info: "request_info",
248
- comment: "comment",
249
- revise: "revise",
250
- resubmit: "resubmit",
251
- ooo_substitute: "ooo_substitute"
240
+ submit: "Submit",
241
+ approve: "Approve",
242
+ reject: "Reject",
243
+ recall: "Recall",
244
+ escalate: "Escalate",
245
+ reassign: "Reassign",
246
+ remind: "Remind",
247
+ request_info: "Request Info",
248
+ comment: "Comment",
249
+ revise: "Revise",
250
+ resubmit: "Resubmit",
251
+ ooo_substitute: "Out-of-Office Substitution"
252
252
  }
253
253
  },
254
254
  actor_id: {
@@ -384,7 +384,7 @@ var init_zh_CN_objects_generated = __esm({
384
384
  label: "\u72B6\u6001",
385
385
  help: "\u8BF7\u6C42\u7684\u751F\u547D\u5468\u671F\u72B6\u6001",
386
386
  options: {
387
- pending: "\u5F85\u5904\u7406",
387
+ pending: "\u5F85\u5BA1\u6279",
388
388
  approved: "\u5DF2\u6279\u51C6",
389
389
  rejected: "\u5DF2\u62D2\u7EDD",
390
390
  recalled: "\u5DF2\u64A4\u56DE",
@@ -430,9 +430,9 @@ var init_zh_CN_objects_generated = __esm({
430
430
  },
431
431
  _views: {
432
432
  my_pending: {
433
- label: "\u6211\u7684\u5F85\u529E",
433
+ label: "\u5F85\u6211\u5BA1\u6279",
434
434
  emptyState: {
435
- title: "\u6682\u65E0\u5F85\u529E\u5BA1\u6279",
435
+ title: "\u6682\u65E0\u5F85\u5BA1\u6279\u7684\u8BF7\u6C42",
436
436
  message: "\u5168\u90E8\u5904\u7406\u5B8C\u6BD5\uFF0C\u6CA1\u6709\u7B49\u5F85\u4F60\u5BA1\u6279\u7684\u8BF7\u6C42\u3002"
437
437
  }
438
438
  },
@@ -461,7 +461,7 @@ var init_zh_CN_objects_generated = __esm({
461
461
  },
462
462
  approval_reject: {
463
463
  label: "\u62D2\u7EDD",
464
- confirmText: "\u62D2\u7EDD\u8BE5\u8BF7\u6C42\uFF1F\u62D2\u7EDD\u5BF9\u6240\u6709\u5BA1\u6279\u4EBA\u7ACB\u5373\u751F\u6548\u3002",
464
+ description: "\u62D2\u7EDD\u8BE5\u8BF7\u6C42\uFF1F\u62D2\u7EDD\u5BF9\u6240\u6709\u5BA1\u6279\u4EBA\u7ACB\u5373\u751F\u6548\u3002",
465
465
  successMessage: "\u5DF2\u62D2\u7EDD\u3002",
466
466
  params: {
467
467
  comment: {
@@ -514,7 +514,7 @@ var init_zh_CN_objects_generated = __esm({
514
514
  },
515
515
  approval_recall: {
516
516
  label: "\u64A4\u56DE",
517
- confirmText: "\u64A4\u56DE\u8BE5\u8BF7\u6C42\uFF1F\u64A4\u56DE\u540E\u5BA1\u6279\u4EBA\u5C06\u65E0\u6CD5\u7EE7\u7EED\u5904\u7406\uFF0C\u8BB0\u5F55\u968F\u5373\u89E3\u9501\u3002",
517
+ description: "\u64A4\u56DE\u8BE5\u8BF7\u6C42\uFF1F\u64A4\u56DE\u540E\u5BA1\u6279\u4EBA\u5C06\u65E0\u6CD5\u7EE7\u7EED\u5904\u7406\uFF0C\u8BB0\u5F55\u968F\u5373\u89E3\u9501\u3002",
518
518
  successMessage: "\u5DF2\u64A4\u56DE\u3002",
519
519
  params: {
520
520
  comment: {
@@ -751,7 +751,7 @@ var init_ja_JP_objects_generated = __esm({
751
751
  },
752
752
  _views: {
753
753
  my_pending: {
754
- label: "\u81EA\u5206\u306E\u4FDD\u7559\u4E2D",
754
+ label: "\u627F\u8A8D\u5F85\u3061",
755
755
  emptyState: {
756
756
  title: "\u627F\u8A8D\u5F85\u3061\u306F\u3042\u308A\u307E\u305B\u3093",
757
757
  message: "\u3059\u3079\u3066\u51E6\u7406\u6E08\u307F\u3067\u3059\u3002\u3042\u306A\u305F\u306E\u627F\u8A8D\u3092\u5F85\u3064\u30EA\u30AF\u30A8\u30B9\u30C8\u306F\u3042\u308A\u307E\u305B\u3093\u3002"
@@ -782,7 +782,7 @@ var init_ja_JP_objects_generated = __esm({
782
782
  },
783
783
  approval_reject: {
784
784
  label: "\u5374\u4E0B",
785
- confirmText: "\u3053\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u5374\u4E0B\u3057\u307E\u3059\u304B\uFF1F\u5374\u4E0B\u306F\u3059\u3079\u3066\u306E\u627F\u8A8D\u8005\u306B\u5BFE\u3057\u3066\u6700\u7D42\u6C7A\u5B9A\u306B\u306A\u308A\u307E\u3059\u3002",
785
+ description: "\u3053\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u5374\u4E0B\u3057\u307E\u3059\u304B\uFF1F\u5374\u4E0B\u306F\u3059\u3079\u3066\u306E\u627F\u8A8D\u8005\u306B\u5BFE\u3057\u3066\u6700\u7D42\u6C7A\u5B9A\u306B\u306A\u308A\u307E\u3059\u3002",
786
786
  successMessage: "\u5374\u4E0B\u3057\u307E\u3057\u305F\u3002",
787
787
  params: {
788
788
  comment: {
@@ -835,7 +835,7 @@ var init_ja_JP_objects_generated = __esm({
835
835
  },
836
836
  approval_recall: {
837
837
  label: "\u53D6\u308A\u4E0B\u3052",
838
- confirmText: "\u3053\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u53D6\u308A\u4E0B\u3052\u307E\u3059\u304B\uFF1F\u627F\u8A8D\u8005\u306F\u64CD\u4F5C\u3067\u304D\u306A\u304F\u306A\u308A\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u30ED\u30C3\u30AF\u304C\u89E3\u9664\u3055\u308C\u307E\u3059\u3002",
838
+ description: "\u3053\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u53D6\u308A\u4E0B\u3052\u307E\u3059\u304B\uFF1F\u627F\u8A8D\u8005\u306F\u64CD\u4F5C\u3067\u304D\u306A\u304F\u306A\u308A\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u30ED\u30C3\u30AF\u304C\u89E3\u9664\u3055\u308C\u307E\u3059\u3002",
839
839
  successMessage: "\u53D6\u308A\u4E0B\u3052\u307E\u3057\u305F\u3002",
840
840
  params: {
841
841
  comment: {
@@ -1072,7 +1072,7 @@ var init_es_ES_objects_generated = __esm({
1072
1072
  },
1073
1073
  _views: {
1074
1074
  my_pending: {
1075
- label: "Mis pendientes",
1075
+ label: "Aprobaciones pendientes",
1076
1076
  emptyState: {
1077
1077
  title: "Sin aprobaciones pendientes",
1078
1078
  message: "Est\xE1s al d\xEDa: nada espera tu aprobaci\xF3n."
@@ -1103,7 +1103,7 @@ var init_es_ES_objects_generated = __esm({
1103
1103
  },
1104
1104
  approval_reject: {
1105
1105
  label: "Rechazar",
1106
- confirmText: "\xBFRechazar esta solicitud? Un rechazo es definitivo para todos los aprobadores.",
1106
+ description: "\xBFRechazar esta solicitud? Un rechazo es definitivo para todos los aprobadores.",
1107
1107
  successMessage: "Rechazada.",
1108
1108
  params: {
1109
1109
  comment: {
@@ -1156,7 +1156,7 @@ var init_es_ES_objects_generated = __esm({
1156
1156
  },
1157
1157
  approval_recall: {
1158
1158
  label: "Retirar",
1159
- confirmText: "\xBFRetirar esta solicitud? Los aprobadores ya no podr\xE1n actuar sobre ella y el registro se desbloquear\xE1.",
1159
+ description: "\xBFRetirar esta solicitud? Los aprobadores ya no podr\xE1n actuar sobre ella y el registro se desbloquear\xE1.",
1160
1160
  successMessage: "Retirada.",
1161
1161
  params: {
1162
1162
  comment: {
@@ -1447,10 +1447,13 @@ var SysApprovalRequest = import_data.ObjectSchema.create({
1447
1447
  group: "Target"
1448
1448
  }),
1449
1449
  status: import_data.Field.select(
1450
- // Spread from the contract, not re-typed (#3786). `APPROVAL_STATUSES` is
1450
+ // Derived from the contract, not re-typed (#3786). `APPROVAL_STATUSES` is
1451
1451
  // where the list and the reason for each entry live; `ApprovalStatus` is
1452
- // derived from it, so this column and the contract cannot disagree.
1453
- [...import_contracts.APPROVAL_STATUSES],
1452
+ // derived from it, so this column and the contract cannot disagree. The
1453
+ // authored English label per entry lives beside it in
1454
+ // `APPROVAL_STATUS_LABELS` (#8543) — mapped here, never re-typed, so the
1455
+ // `en` bundle regenerates from the contract's own text.
1456
+ import_contracts.APPROVAL_STATUSES.map((value) => ({ value, label: import_contracts.APPROVAL_STATUS_LABELS[value] })),
1454
1457
  {
1455
1458
  label: "Status",
1456
1459
  required: true,
@@ -1582,6 +1585,15 @@ var SysApprovalRequest = import_data.ObjectSchema.create({
1582
1585
  {
1583
1586
  name: "approval_reject",
1584
1587
  label: "Reject",
1588
+ // The confirm question lives HERE, not in `confirmText`: this action
1589
+ // collects params, so the console would otherwise chain a confirm dialog
1590
+ // and then the param dialog for one decision — and the first one already
1591
+ // reads as "the action ran" (#7278, maintainer ruling 2026-08-10). The
1592
+ // param dialog renders this as its description, and nothing is POSTed
1593
+ // until its own Confirm: one condition, one wording, one dialog.
1594
+ // NB: the top-level action `description` (#7367), never `ai.description`
1595
+ // — that one is the LLM-facing tool contract and is not shown to anyone.
1596
+ description: "Reject this request? A rejection is final for every approver.",
1585
1597
  icon: "x-circle",
1586
1598
  // Destructive decision — rendered in the console's danger styling so it
1587
1599
  // reads as the irreversible action it is (objectui#2762 P1-5).
@@ -1594,7 +1606,6 @@ var SysApprovalRequest = import_data.ObjectSchema.create({
1594
1606
  { name: "attachments", label: "Attachments", type: "file", multiple: true, required: false }
1595
1607
  ],
1596
1608
  visible: "record.viewer.can_act || record.viewer.can_override",
1597
- confirmText: "Reject this request? A rejection is final for every approver.",
1598
1609
  locations: ["record_section", "list_item"],
1599
1610
  successMessage: "Rejected.",
1600
1611
  refreshAfter: true
@@ -1678,6 +1689,9 @@ var SysApprovalRequest = import_data.ObjectSchema.create({
1678
1689
  {
1679
1690
  name: "approval_recall",
1680
1691
  label: "Recall",
1692
+ // Confirm question as the param dialog's description, not `confirmText`
1693
+ // — same one-decision-one-dialog rule as `approval_reject` above (#7278).
1694
+ description: "Recall this request? Approvers can no longer act on it and the record is unlocked.",
1681
1695
  icon: "undo-2",
1682
1696
  type: "api",
1683
1697
  method: "POST",
@@ -1688,7 +1702,6 @@ var SysApprovalRequest = import_data.ObjectSchema.create({
1688
1702
  // Recall applies while the request is live for the submitter — pending
1689
1703
  // (withdraw) or returned (abandon the revision instead of resubmitting).
1690
1704
  visible: '(record.status == "pending" || record.status == "returned") && record.viewer.is_submitter',
1691
- confirmText: "Recall this request? Approvers can no longer act on it and the record is unlocked.",
1692
1705
  locations: ["record_section"],
1693
1706
  successMessage: "Recalled.",
1694
1707
  refreshAfter: true
@@ -1798,11 +1811,14 @@ var SysApprovalAction = import_data2.ObjectSchema.create({
1798
1811
  group: "Target"
1799
1812
  }),
1800
1813
  action: import_data2.Field.select(
1801
- // Spread from the contract, not re-typed (#3786). `APPROVAL_ACTION_KINDS`
1814
+ // Derived from the contract, not re-typed (#3786). `APPROVAL_ACTION_KINDS`
1802
1815
  // is where the list and the per-kind notes live (which kinds move the flow
1803
1816
  // and which are thread-only); `ApprovalActionKind` is derived from it, so
1804
- // this column and the contract cannot disagree.
1805
- [...import_contracts2.APPROVAL_ACTION_KINDS],
1817
+ // this column and the contract cannot disagree. The authored English label
1818
+ // per kind lives beside it in `APPROVAL_ACTION_KIND_LABELS` (#8580 — the
1819
+ // #7232 humanization pass missed this field) — mapped here, never
1820
+ // re-typed, so the `en` bundle regenerates from the contract's own text.
1821
+ import_contracts2.APPROVAL_ACTION_KINDS.map((value) => ({ value, label: import_contracts2.APPROVAL_ACTION_KIND_LABELS[value] })),
1806
1822
  {
1807
1823
  label: "Action",
1808
1824
  required: true,
@@ -4401,10 +4417,14 @@ var _ApprovalService = class _ApprovalService {
4401
4417
  * class of failure stayed silent.
4402
4418
  *
4403
4419
  * It also could not have answered the question even if it looked: its
4404
- * liveness oracle is `getRun`, which reads the execution LOG, and after a
4405
- * restart that returns `null` for a perfectly ALIVE suspended run. It treats
4406
- * `null` as alive (conservative, correct) but that means it has no way to
4407
- * say "this run is really gone".
4420
+ * liveness oracle is `getRun`, which treats both `null` and `paused` as alive
4421
+ * (conservative, correct) so it has no way to say "this run is really
4422
+ * gone". (Until #8050 that oracle was weaker still: after a restart it
4423
+ * returned `null` for a perfectly ALIVE suspended run, so "alive" and
4424
+ * "unknown" were the same answer. It now reports such a run as `paused`,
4425
+ * which does not change any branch here — both already meant "leave alone" —
4426
+ * but it is why the sweep below needs `hasSuspendedRun` as a second oracle
4427
+ * rather than a sharper reading of the first.)
4408
4428
  *
4409
4429
  * So this uses BOTH oracles, and a row must fail both to be reported:
4410
4430
  *
@@ -5756,7 +5776,7 @@ function registerApprovalReviseNode(automation, logger) {
5756
5776
  paradigms: ["flow"],
5757
5777
  source: "plugin",
5758
5778
  supportsPause: true,
5759
- isAsync: true,
5779
+ // (`isAsync` stood here — retired in #6748, ADR-0049: nothing read it)
5760
5780
  // #3823 / amended ADR-0044: THE point of this node type. The revise
5761
5781
  // window is a service-owned continuation, so the #3801 gate must refuse
5762
5782
  // a raw resume of it — which it does for any node type declaring this.
@@ -5808,7 +5828,7 @@ function registerApprovalNode(automation, service, logger) {
5808
5828
  source: "plugin",
5809
5829
  // Human decision: the run suspends here awaiting an external reply.
5810
5830
  supportsPause: true,
5811
- isAsync: true,
5831
+ // (`isAsync` stood here — retired in #6748, ADR-0049: nothing read it)
5812
5832
  // #3801: this pause is NOT resumable through the generic run-resume
5813
5833
  // route. Continuing an approval is a side effect of a DECISION, and the
5814
5834
  // decision is the thing that must be authorized (the approver slate),
@@ -5859,6 +5879,17 @@ function registerApprovalNode(automation, service, logger) {
5859
5879
  }, {
5860
5880
  ...SYSTEM_CTX4,
5861
5881
  userId: context?.userId,
5882
+ // [#7135] ⚠️ This assertion SURVIVES the annotation widening, and it
5883
+ // is `as ExecutionContext` rather than the `as unknown as
5884
+ // SharingExecutionContext` double cast it replaces. The sole reason
5885
+ // a cast is still needed is `organizationId`, which is not a field
5886
+ // of the envelope at ALL — that spelling has its own history (#5858
5887
+ // / `check:org-identifier`) and was explicitly held out of this
5888
+ // change (#7070), so removing the key here would be a RUNTIME change
5889
+ // belonging to that card. Dropping the second hop matters: `as
5890
+ // unknown as` erases the value entirely, while a single assertion
5891
+ // still requires the literal to be comparable to the envelope, so a
5892
+ // `userId: 42` here is once again a compile error.
5862
5893
  organizationId: context?.organizationId,
5863
5894
  tenantId: context?.tenantId
5864
5895
  });
@@ -5910,12 +5941,23 @@ var ApprovalsServicePlugin = class {
5910
5941
  // ADR-0029 D7 — contribute the Approvals entries into the Setup app's
5911
5942
  // `group_approvals` slot. This plugin owns these objects (K2.b), so it
5912
5943
  // ships their menu too; when the plugin isn't installed the slot is empty.
5944
+ //
5945
+ // #7234 — order inside the slot is ARRAY ORDER: `applyNavContributions`
5946
+ // does `group.children.push(...c.items)` per contribution (sorted by
5947
+ // `priority`), so the inbox being first in this array is what puts it
5948
+ // above the raw tables. Do not reorder without meaning to.
5949
+ //
5950
+ // The inbox entry is the working surface (decision actions, node
5951
+ // progress, drawer); the three object entries below stay as the
5952
+ // admin/diagnostic view of the engine's own tables — reachable only here,
5953
+ // behind `group_approvals`' `manage_platform_settings` gate.
5913
5954
  navigationContributions: [
5914
5955
  {
5915
5956
  app: "setup",
5916
5957
  group: "group_approvals",
5917
5958
  priority: 100,
5918
5959
  items: [
5960
+ { id: "nav_approvals_inbox", type: "component", label: "Approvals Inbox", componentRef: "approvals:inbox", icon: "list-checks" },
5919
5961
  { id: "nav_approval_requests", type: "object", label: "Requests", objectName: "sys_approval_request", icon: "inbox", requiresObject: "sys_approval_request" },
5920
5962
  { id: "nav_approval_actions", type: "object", label: "Action History", objectName: "sys_approval_action", icon: "history", requiresObject: "sys_approval_action" },
5921
5963
  { id: "nav_approval_delegations", type: "object", label: "Delegations (OOO)", objectName: "sys_approval_delegation", icon: "user-clock", requiresObject: "sys_approval_delegation" }
@@ -6028,7 +6070,14 @@ var ApprovalsServicePlugin = class {
6028
6070
  };
6029
6071
  const mountActionPages = async () => {
6030
6072
  try {
6031
- const http = ctx.getService("http-server");
6073
+ const readServer = (name) => {
6074
+ try {
6075
+ return ctx.getService(name);
6076
+ } catch {
6077
+ return void 0;
6078
+ }
6079
+ };
6080
+ const http = readServer("http.server") ?? readServer("http-server");
6032
6081
  const rawApp = http && typeof http.getRawApp === "function" ? http.getRawApp() : null;
6033
6082
  if (!rawApp || !this.service) return;
6034
6083
  const svc = this.service;