@objectstack/plugin-approvals 17.0.0-rc.0 → 17.0.0-rc.1
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/CHANGELOG.md +439 -0
- package/dist/index.d.mts +2304 -3491
- package/dist/index.d.ts +2304 -3491
- package/dist/index.js +116 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -41
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -9
- package/.turbo/turbo-build.log +0 -22
- package/scripts/i18n-extract.config.ts +0 -38
- package/src/action-link-pages.ts +0 -102
- package/src/approval-actor-impersonation.test.ts +0 -330
- package/src/approval-node.test.ts +0 -356
- package/src/approval-node.ts +0 -196
- package/src/approval-revise.test.ts +0 -418
- package/src/approval-service.test.ts +0 -2858
- package/src/approval-service.ts +0 -3617
- package/src/approvals-plugin.ts +0 -294
- package/src/approver-cross-org.integration.test.ts +0 -206
- package/src/approver-org-scope.test.ts +0 -201
- package/src/approver-org-scope.ts +0 -261
- package/src/index.ts +0 -42
- package/src/lifecycle-hooks.ts +0 -201
- package/src/nav-contribution.test.ts +0 -50
- package/src/record-lock-schedule-run.integration.test.ts +0 -206
- package/src/status-mirror-cascade.integration.test.ts +0 -224
- package/src/sys-approval-action.object.ts +0 -149
- package/src/sys-approval-approver.object.ts +0 -85
- package/src/sys-approval-delegation.object.test.ts +0 -42
- package/src/sys-approval-delegation.object.ts +0 -142
- package/src/sys-approval-request.object.test.ts +0 -116
- package/src/sys-approval-request.object.ts +0 -413
- package/src/sys-approval-token.object.ts +0 -101
- package/src/translations/bundle-ownership.test.ts +0 -48
- package/src/translations/en.objects.generated.ts +0 -311
- package/src/translations/es-ES.objects.generated.ts +0 -311
- package/src/translations/index.ts +0 -23
- package/src/translations/ja-JP.objects.generated.ts +0 -311
- package/src/translations/zh-CN.objects.generated.ts +0 -311
- package/tsconfig.json +0 -10
package/dist/index.mjs
CHANGED
|
@@ -245,6 +245,14 @@ var init_en_objects_generated = __esm({
|
|
|
245
245
|
comment: {
|
|
246
246
|
label: "Comment"
|
|
247
247
|
},
|
|
248
|
+
reassign_from: {
|
|
249
|
+
label: "Reassigned From",
|
|
250
|
+
help: "User whose pending-approver slot was handed over (reassign actions only)"
|
|
251
|
+
},
|
|
252
|
+
reassign_to: {
|
|
253
|
+
label: "Reassigned To",
|
|
254
|
+
help: "User who received the pending-approver slot (reassign actions only)"
|
|
255
|
+
},
|
|
248
256
|
attachments: {
|
|
249
257
|
label: "Attachments",
|
|
250
258
|
help: "Files supporting this action \u2014 e.g. a signed contract or evidence (#3266)."
|
|
@@ -554,6 +562,14 @@ var init_zh_CN_objects_generated = __esm({
|
|
|
554
562
|
comment: {
|
|
555
563
|
label: "\u8BC4\u8BBA"
|
|
556
564
|
},
|
|
565
|
+
reassign_from: {
|
|
566
|
+
label: "\u8F6C\u51FA\u4EBA",
|
|
567
|
+
help: "\u88AB\u79FB\u4EA4\u5F85\u5BA1\u6279\u69FD\u4F4D\u7684\u7528\u6237\uFF08\u4EC5\u8F6C\u7B7E\u64CD\u4F5C\uFF09"
|
|
568
|
+
},
|
|
569
|
+
reassign_to: {
|
|
570
|
+
label: "\u8F6C\u5165\u4EBA",
|
|
571
|
+
help: "\u63A5\u6536\u5F85\u5BA1\u6279\u69FD\u4F4D\u7684\u7528\u6237\uFF08\u4EC5\u8F6C\u7B7E\u64CD\u4F5C\uFF09"
|
|
572
|
+
},
|
|
557
573
|
attachments: {
|
|
558
574
|
label: "\u9644\u4EF6",
|
|
559
575
|
help: "\u652F\u6301\u8BE5\u64CD\u4F5C\u7684\u6587\u4EF6\u2014\u2014\u4F8B\u5982\u5DF2\u7B7E\u7F72\u7684\u5408\u540C\u6216\u8BC1\u660E\u6750\u6599\uFF08#3266\uFF09\u3002"
|
|
@@ -863,6 +879,14 @@ var init_ja_JP_objects_generated = __esm({
|
|
|
863
879
|
comment: {
|
|
864
880
|
label: "\u30B3\u30E1\u30F3\u30C8"
|
|
865
881
|
},
|
|
882
|
+
reassign_from: {
|
|
883
|
+
label: "\u5F15\u304D\u7D99\u304E\u5143",
|
|
884
|
+
help: "\u627F\u8A8D\u5F85\u3061\u30B9\u30ED\u30C3\u30C8\u3092\u5F15\u304D\u6E21\u3057\u305F\u30E6\u30FC\u30B6\u30FC\uFF08\u5F15\u304D\u7D99\u304E\u64CD\u4F5C\u306E\u307F\uFF09"
|
|
885
|
+
},
|
|
886
|
+
reassign_to: {
|
|
887
|
+
label: "\u5F15\u304D\u7D99\u304E\u5148",
|
|
888
|
+
help: "\u627F\u8A8D\u5F85\u3061\u30B9\u30ED\u30C3\u30C8\u3092\u53D7\u3051\u53D6\u3063\u305F\u30E6\u30FC\u30B6\u30FC\uFF08\u5F15\u304D\u7D99\u304E\u64CD\u4F5C\u306E\u307F\uFF09"
|
|
889
|
+
},
|
|
866
890
|
attachments: {
|
|
867
891
|
label: "\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB",
|
|
868
892
|
help: "\u3053\u306E\u64CD\u4F5C\u3092\u88CF\u4ED8\u3051\u308B\u30D5\u30A1\u30A4\u30EB\u2014\u2014\u7F72\u540D\u6E08\u307F\u5951\u7D04\u66F8\u3084\u8A3C\u6191\u306A\u3069\uFF08#3266\uFF09\u3002"
|
|
@@ -1172,6 +1196,14 @@ var init_es_ES_objects_generated = __esm({
|
|
|
1172
1196
|
comment: {
|
|
1173
1197
|
label: "Comentario"
|
|
1174
1198
|
},
|
|
1199
|
+
reassign_from: {
|
|
1200
|
+
label: "Reasignado de",
|
|
1201
|
+
help: "Usuario cuyo turno de aprobaci\xF3n pendiente fue traspasado (solo acciones de reasignaci\xF3n)"
|
|
1202
|
+
},
|
|
1203
|
+
reassign_to: {
|
|
1204
|
+
label: "Reasignado a",
|
|
1205
|
+
help: "Usuario que recibi\xF3 el turno de aprobaci\xF3n pendiente (solo acciones de reasignaci\xF3n)"
|
|
1206
|
+
},
|
|
1175
1207
|
attachments: {
|
|
1176
1208
|
label: "Adjuntos",
|
|
1177
1209
|
help: "Archivos que respaldan esta acci\xF3n, p. ej. un contrato firmado o pruebas (#3266)."
|
|
@@ -1273,6 +1305,7 @@ var init_translations = __esm({
|
|
|
1273
1305
|
|
|
1274
1306
|
// src/sys-approval-request.object.ts
|
|
1275
1307
|
import { ObjectSchema, Field } from "@objectstack/spec/data";
|
|
1308
|
+
import { APPROVAL_STATUSES } from "@objectstack/spec/contracts";
|
|
1276
1309
|
var SysApprovalRequest = ObjectSchema.create({
|
|
1277
1310
|
name: "sys_approval_request",
|
|
1278
1311
|
label: "Approval Request",
|
|
@@ -1371,9 +1404,10 @@ var SysApprovalRequest = ObjectSchema.create({
|
|
|
1371
1404
|
group: "Target"
|
|
1372
1405
|
}),
|
|
1373
1406
|
status: Field.select(
|
|
1374
|
-
//
|
|
1375
|
-
//
|
|
1376
|
-
|
|
1407
|
+
// Spread from the contract, not re-typed (#3786). `APPROVAL_STATUSES` is
|
|
1408
|
+
// where the list and the reason for each entry live; `ApprovalStatus` is
|
|
1409
|
+
// derived from it, so this column and the contract cannot disagree.
|
|
1410
|
+
[...APPROVAL_STATUSES],
|
|
1377
1411
|
{
|
|
1378
1412
|
label: "Status",
|
|
1379
1413
|
required: true,
|
|
@@ -1642,6 +1676,7 @@ var SysApprovalRequest = ObjectSchema.create({
|
|
|
1642
1676
|
|
|
1643
1677
|
// src/sys-approval-action.object.ts
|
|
1644
1678
|
import { ObjectSchema as ObjectSchema2, Field as Field2 } from "@objectstack/spec/data";
|
|
1679
|
+
import { APPROVAL_ACTION_KINDS } from "@objectstack/spec/contracts";
|
|
1645
1680
|
var SysApprovalAction = ObjectSchema2.create({
|
|
1646
1681
|
name: "sys_approval_action",
|
|
1647
1682
|
label: "Approval Action",
|
|
@@ -1720,12 +1755,11 @@ var SysApprovalAction = ObjectSchema2.create({
|
|
|
1720
1755
|
group: "Target"
|
|
1721
1756
|
}),
|
|
1722
1757
|
action: Field2.select(
|
|
1723
|
-
//
|
|
1724
|
-
//
|
|
1725
|
-
//
|
|
1726
|
-
//
|
|
1727
|
-
|
|
1728
|
-
["submit", "approve", "reject", "recall", "escalate", "reassign", "remind", "request_info", "comment", "revise", "resubmit", "ooo_substitute"],
|
|
1758
|
+
// Spread from the contract, not re-typed (#3786). `APPROVAL_ACTION_KINDS`
|
|
1759
|
+
// is where the list and the per-kind notes live (which kinds move the flow
|
|
1760
|
+
// and which are thread-only); `ApprovalActionKind` is derived from it, so
|
|
1761
|
+
// this column and the contract cannot disagree.
|
|
1762
|
+
[...APPROVAL_ACTION_KINDS],
|
|
1729
1763
|
{
|
|
1730
1764
|
label: "Action",
|
|
1731
1765
|
required: true,
|
|
@@ -1738,6 +1772,23 @@ var SysApprovalAction = ObjectSchema2.create({
|
|
|
1738
1772
|
group: "Action"
|
|
1739
1773
|
}),
|
|
1740
1774
|
comment: Field2.textarea({ label: "Comment", required: false, group: "Action" }),
|
|
1775
|
+
// Structured hand-off parties for `action: 'reassign'` (#4365). Before
|
|
1776
|
+
// these existed the pair lived only inside a default free-text comment
|
|
1777
|
+
// ("<from_id> → <to_id>"), which no client could parse or render readably.
|
|
1778
|
+
// `comment` is pure user input again; timelines render "from A to B" from
|
|
1779
|
+
// these fields.
|
|
1780
|
+
reassign_from: Field2.lookup("sys_user", {
|
|
1781
|
+
label: "Reassigned From",
|
|
1782
|
+
required: false,
|
|
1783
|
+
group: "Action",
|
|
1784
|
+
description: "User whose pending-approver slot was handed over (reassign actions only)"
|
|
1785
|
+
}),
|
|
1786
|
+
reassign_to: Field2.lookup("sys_user", {
|
|
1787
|
+
label: "Reassigned To",
|
|
1788
|
+
required: false,
|
|
1789
|
+
group: "Action",
|
|
1790
|
+
description: "User who received the pending-approver slot (reassign actions only)"
|
|
1791
|
+
}),
|
|
1741
1792
|
attachments: Field2.file({
|
|
1742
1793
|
label: "Attachments",
|
|
1743
1794
|
required: false,
|
|
@@ -1929,6 +1980,7 @@ import {
|
|
|
1929
1980
|
normalizeDecisionOutputs
|
|
1930
1981
|
} from "@objectstack/spec/automation";
|
|
1931
1982
|
import { ExpressionEngine, collectCelRootIdentifiers } from "@objectstack/formula";
|
|
1983
|
+
import { keysetWalk } from "@objectstack/types";
|
|
1932
1984
|
import {
|
|
1933
1985
|
ADMIN_FULL_ACCESS,
|
|
1934
1986
|
ORGANIZATION_ADMIN_GRANTS,
|
|
@@ -1949,7 +2001,7 @@ function fail(message) {
|
|
|
1949
2001
|
async function findOrg(engine, where) {
|
|
1950
2002
|
try {
|
|
1951
2003
|
const rows = await engine.find("sys_organization", {
|
|
1952
|
-
|
|
2004
|
+
where,
|
|
1953
2005
|
fields: ["id", "slug", "parent_organization_id"],
|
|
1954
2006
|
limit: 1,
|
|
1955
2007
|
context: SYSTEM_CTX
|
|
@@ -2036,7 +2088,7 @@ async function filterApproversWhoCanRead(deps, userIds, requestOrgId, context) {
|
|
|
2036
2088
|
let members = [];
|
|
2037
2089
|
try {
|
|
2038
2090
|
members = await deps.engine.find("sys_member", {
|
|
2039
|
-
|
|
2091
|
+
where: { organization_id: requestOrg, user_id: { $in: userIds } },
|
|
2040
2092
|
fields: ["user_id"],
|
|
2041
2093
|
limit: 1e4,
|
|
2042
2094
|
context: SYSTEM_CTX
|
|
@@ -2106,6 +2158,12 @@ function csvSplit(raw) {
|
|
|
2106
2158
|
if (Array.isArray(raw)) return raw.map(String).filter(Boolean);
|
|
2107
2159
|
return String(raw).split(",").map((s) => s.trim()).filter(Boolean);
|
|
2108
2160
|
}
|
|
2161
|
+
function isBlankDecisionOutput(value) {
|
|
2162
|
+
if (value === void 0 || value === null) return true;
|
|
2163
|
+
if (typeof value === "string") return value.trim() === "";
|
|
2164
|
+
if (Array.isArray(value)) return value.filter((v) => v !== null && v !== void 0 && String(v).trim() !== "").length === 0;
|
|
2165
|
+
return false;
|
|
2166
|
+
}
|
|
2109
2167
|
function prettifyMachineName(raw) {
|
|
2110
2168
|
if (!raw) return void 0;
|
|
2111
2169
|
const base = String(raw).replace(/^flow:/, "").trim();
|
|
@@ -2198,6 +2256,9 @@ function rowFromAction(row) {
|
|
|
2198
2256
|
action: row.action,
|
|
2199
2257
|
actor_id: row.actor_id ?? void 0,
|
|
2200
2258
|
comment: row.comment ?? void 0,
|
|
2259
|
+
// Structured reassign hand-off parties (#4365).
|
|
2260
|
+
reassign_from: row.reassign_from ?? void 0,
|
|
2261
|
+
reassign_to: row.reassign_to ?? void 0,
|
|
2201
2262
|
// Decision attachments (#3266): rich descriptors carrying the display name +
|
|
2202
2263
|
// download URL, so consumers label/open them without reading `sys_file`.
|
|
2203
2264
|
attachments: attachments.length ? attachments : void 0,
|
|
@@ -2337,9 +2398,10 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2337
2398
|
* (having also put them on the context). Those are the only two callers that
|
|
2338
2399
|
* hold a trustworthy actor with no session behind them.
|
|
2339
2400
|
*
|
|
2340
|
-
* A caller with NO identity at all cannot act.
|
|
2341
|
-
*
|
|
2342
|
-
*
|
|
2401
|
+
* A caller with NO identity at all cannot act. Belt-and-suspenders: the REST
|
|
2402
|
+
* anonymous-deny now denies every anonymous request (#3963), but this service
|
|
2403
|
+
* must not rely on a caller upstream — an anonymous actor could otherwise
|
|
2404
|
+
* decide approvals outright by naming one.
|
|
2343
2405
|
*/
|
|
2344
2406
|
async resolveActor(actorId, context) {
|
|
2345
2407
|
if (context?.isSystem) {
|
|
@@ -2625,7 +2687,7 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2625
2687
|
let rows = [];
|
|
2626
2688
|
try {
|
|
2627
2689
|
rows = await this.engine.find("sys_team_member", {
|
|
2628
|
-
|
|
2690
|
+
where: { team_id: teamId },
|
|
2629
2691
|
fields: ["user_id"],
|
|
2630
2692
|
limit: 1e4,
|
|
2631
2693
|
context: SYSTEM_CTX2
|
|
@@ -2664,7 +2726,7 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2664
2726
|
if (!businessUnitId) return [];
|
|
2665
2727
|
try {
|
|
2666
2728
|
const seed = await this.engine.find("sys_business_unit", {
|
|
2667
|
-
|
|
2729
|
+
where: this.businessUnitOrgScope({ id: businessUnitId }, organizationId),
|
|
2668
2730
|
fields: ["id", "active"],
|
|
2669
2731
|
limit: 1,
|
|
2670
2732
|
context: SYSTEM_CTX2
|
|
@@ -2699,7 +2761,7 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2699
2761
|
let rows = [];
|
|
2700
2762
|
try {
|
|
2701
2763
|
rows = await this.engine.find("sys_business_unit_member", {
|
|
2702
|
-
|
|
2764
|
+
where: { business_unit_id: { $in: Array.from(seen) } },
|
|
2703
2765
|
fields: ["user_id"],
|
|
2704
2766
|
limit: 1e4,
|
|
2705
2767
|
context: SYSTEM_CTX2
|
|
@@ -2759,7 +2821,7 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2759
2821
|
async lookupManager(userId) {
|
|
2760
2822
|
try {
|
|
2761
2823
|
const rows = await this.engine.find("sys_user", {
|
|
2762
|
-
|
|
2824
|
+
where: { id: userId },
|
|
2763
2825
|
fields: ["id", "manager_id"],
|
|
2764
2826
|
limit: 1,
|
|
2765
2827
|
context: SYSTEM_CTX2
|
|
@@ -2809,7 +2871,7 @@ var _ApprovalService = class _ApprovalService {
|
|
|
2809
2871
|
let rows = [];
|
|
2810
2872
|
try {
|
|
2811
2873
|
rows = await this.engine.find("sys_approval_delegation", {
|
|
2812
|
-
|
|
2874
|
+
where: { delegator_id: delegatorId },
|
|
2813
2875
|
fields: ["id", "delegator_id", "delegate_id", "valid_from", "valid_until", "reason", "organization_id"],
|
|
2814
2876
|
limit: 50,
|
|
2815
2877
|
context: SYSTEM_CTX2
|
|
@@ -3135,8 +3197,9 @@ var _ApprovalService = class _ApprovalService {
|
|
|
3135
3197
|
const now = this.clock.now().toISOString();
|
|
3136
3198
|
const outputKeys = input.outputs ? Object.keys(input.outputs) : [];
|
|
3137
3199
|
let acceptedOutputs;
|
|
3200
|
+
const declaredDefs = normalizeDecisionOutputs(config.decisionOutputs);
|
|
3138
3201
|
if (outputKeys.length) {
|
|
3139
|
-
const declared =
|
|
3202
|
+
const declared = declaredDefs.map((d) => d.key);
|
|
3140
3203
|
if (!declared.length) {
|
|
3141
3204
|
throw new Error(
|
|
3142
3205
|
`VALIDATION_FAILED: this approval node declares no decisionOutputs \u2014 outputs are not accepted. Declare the keys on the node config (decisionOutputs: [${outputKeys.map((k) => `'${k}'`).join(", ")}]) to let approvers hand them to the flow.`
|
|
@@ -3156,6 +3219,14 @@ var _ApprovalService = class _ApprovalService {
|
|
|
3156
3219
|
}
|
|
3157
3220
|
acceptedOutputs = { ...input.outputs };
|
|
3158
3221
|
}
|
|
3222
|
+
if (input.decision === "approve") {
|
|
3223
|
+
const missing = declaredDefs.filter((d) => d.required === true && isBlankDecisionOutput(input.outputs?.[d.key])).map((d) => d.key);
|
|
3224
|
+
if (missing.length) {
|
|
3225
|
+
throw new Error(
|
|
3226
|
+
`VALIDATION_FAILED: decision output(s) \`${missing.join("`, `")}\` are required to approve this request \u2014 open the approval and fill them in before approving.`
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3159
3230
|
await this.engine.insert("sys_approval_action", {
|
|
3160
3231
|
id: uid("aact"),
|
|
3161
3232
|
request_id: requestId,
|
|
@@ -3690,8 +3761,13 @@ var _ApprovalService = class _ApprovalService {
|
|
|
3690
3761
|
step_name: raw.flow_node_id ?? raw.current_step ?? null,
|
|
3691
3762
|
step_index: 0,
|
|
3692
3763
|
action: "reassign",
|
|
3764
|
+
// The hand-off parties are STRUCTURED fields (#4365) — the old default
|
|
3765
|
+
// comment (`"<from> → <to>"`) baked raw user ids into user-facing text.
|
|
3766
|
+
// `comment` is pure user input: absent unless the actor wrote one.
|
|
3693
3767
|
actor_id: actorId,
|
|
3694
|
-
|
|
3768
|
+
reassign_from: from,
|
|
3769
|
+
reassign_to: to,
|
|
3770
|
+
comment: input.comment ?? null,
|
|
3695
3771
|
created_at: now
|
|
3696
3772
|
}, { context: SYSTEM_CTX2 });
|
|
3697
3773
|
let configPatch = {};
|
|
@@ -4499,35 +4575,28 @@ var _ApprovalService = class _ApprovalService {
|
|
|
4499
4575
|
async rebuildApproverIndex() {
|
|
4500
4576
|
const desired = /* @__PURE__ */ new Map();
|
|
4501
4577
|
const PAGE = 500;
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4578
|
+
const requests = keysetWalk(
|
|
4579
|
+
(q) => this.engine.find("sys_approval_request", {
|
|
4580
|
+
...q,
|
|
4505
4581
|
fields: ["id", "pending_approvers", "organization_id"],
|
|
4506
|
-
limit: PAGE,
|
|
4507
|
-
offset,
|
|
4508
4582
|
context: SYSTEM_CTX2
|
|
4509
|
-
})
|
|
4510
|
-
|
|
4583
|
+
}),
|
|
4584
|
+
{ where: { status: "pending" }, pageSize: PAGE }
|
|
4585
|
+
);
|
|
4586
|
+
for await (const rows of requests.pages()) {
|
|
4511
4587
|
for (const r of rows) {
|
|
4512
4588
|
desired.set(String(r.id), {
|
|
4513
4589
|
approvers: new Set(csvSplit(r.pending_approvers)),
|
|
4514
4590
|
org: r.organization_id ?? null
|
|
4515
4591
|
});
|
|
4516
4592
|
}
|
|
4517
|
-
if (rows.length < PAGE) break;
|
|
4518
4593
|
}
|
|
4519
4594
|
const indexRows = [];
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
context: SYSTEM_CTX2
|
|
4526
|
-
});
|
|
4527
|
-
const rows = Array.isArray(batch) ? batch : [];
|
|
4528
|
-
indexRows.push(...rows);
|
|
4529
|
-
if (rows.length < PAGE) break;
|
|
4530
|
-
}
|
|
4595
|
+
const index = keysetWalk(
|
|
4596
|
+
(q) => this.engine.find("sys_approval_approver", { ...q, context: SYSTEM_CTX2 }),
|
|
4597
|
+
{ pageSize: PAGE }
|
|
4598
|
+
);
|
|
4599
|
+
for await (const rows of index.pages()) indexRows.push(...rows);
|
|
4531
4600
|
let inserted = 0;
|
|
4532
4601
|
let deleted = 0;
|
|
4533
4602
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -4911,11 +4980,15 @@ var _ApprovalService = class _ApprovalService {
|
|
|
4911
4980
|
});
|
|
4912
4981
|
const actions = Array.isArray(rows) ? rows.map(rowFromAction) : [];
|
|
4913
4982
|
const names = await this.resolveUserNames(
|
|
4914
|
-
actions.
|
|
4983
|
+
actions.flatMap((a) => [a.actor_id, a.reassign_from, a.reassign_to]).filter((id) => id && !id.includes(":"))
|
|
4915
4984
|
);
|
|
4916
4985
|
for (const a of actions) {
|
|
4917
4986
|
const n = a.actor_id ? names.get(String(a.actor_id)) : void 0;
|
|
4918
4987
|
if (n) a.actor_name = n;
|
|
4988
|
+
const fromName = a.reassign_from ? names.get(String(a.reassign_from)) : void 0;
|
|
4989
|
+
if (fromName) a.reassign_from_name = fromName;
|
|
4990
|
+
const toName = a.reassign_to ? names.get(String(a.reassign_to)) : void 0;
|
|
4991
|
+
if (toName) a.reassign_to_name = toName;
|
|
4919
4992
|
}
|
|
4920
4993
|
return actions;
|
|
4921
4994
|
}
|