@objectstack/plugin-approvals 9.1.0 → 9.2.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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +135 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/approval-service.test.ts +31 -0
- package/src/approval-service.ts +134 -29
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/plugin-approvals@9.
|
|
2
|
+
> @objectstack/plugin-approvals@9.2.0 build /home/runner/work/framework/framework/packages/plugins/plugin-approvals
|
|
3
3
|
> tsup --config ../../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
|
14
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[
|
|
15
|
-
[32mESM[39m ⚡️ Build success in
|
|
16
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
17
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
18
|
-
[32mCJS[39m ⚡️ Build success in
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m67.42 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m119.54 KB[39m
|
|
15
|
+
[32mESM[39m ⚡️ Build success in 167ms
|
|
16
|
+
[32mCJS[39m [1mdist/index.js [22m[32m68.76 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m120.72 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 169ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m334.
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m334.
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 24561ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m334.84 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m334.84 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @objectstack/plugin-approvals
|
|
2
2
|
|
|
3
|
+
## 9.2.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [2f57b75]
|
|
8
|
+
- Updated dependencies [2f57b75]
|
|
9
|
+
- @objectstack/spec@9.2.0
|
|
10
|
+
- @objectstack/core@9.2.0
|
|
11
|
+
- @objectstack/formula@9.2.0
|
|
12
|
+
- @objectstack/metadata-core@9.2.0
|
|
13
|
+
- @objectstack/platform-objects@9.2.0
|
|
14
|
+
|
|
3
15
|
## 9.1.0
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -7550,10 +7550,21 @@ declare class ApprovalService implements IApprovalService {
|
|
|
7550
7550
|
private resolveDisplayField;
|
|
7551
7551
|
private static pickTitle;
|
|
7552
7552
|
/**
|
|
7553
|
-
*
|
|
7554
|
-
*
|
|
7555
|
-
|
|
7556
|
-
|
|
7553
|
+
* Batch-resolve `sys_user` display names for identifiers that may be user
|
|
7554
|
+
* ids or emails. Best-effort — failures leave entries unresolved.
|
|
7555
|
+
*/
|
|
7556
|
+
private resolveUserNames;
|
|
7557
|
+
/** Lookup-typed fields (key + referenced object) of an object's schema. */
|
|
7558
|
+
private resolveLookupFields;
|
|
7559
|
+
/**
|
|
7560
|
+
* Attach inbox display fields to rows so clients never render a raw
|
|
7561
|
+
* identifier: `record_title`, `submitter_name`, `object_label`,
|
|
7562
|
+
* `pending_approver_names` (user-id approvers), and `payload_display`
|
|
7563
|
+
* (lookup foreign keys in the snapshot → referenced record titles).
|
|
7564
|
+
* Batched: one query per distinct object (target + referenced) plus one
|
|
7565
|
+
* `sys_user` lookup. Best-effort — a deleted record falls back to the
|
|
7566
|
+
* payload snapshot, and any failure leaves the field unset rather than
|
|
7567
|
+
* failing the list.
|
|
7557
7568
|
*/
|
|
7558
7569
|
private enrichRows;
|
|
7559
7570
|
listRequests(filter: {
|
package/dist/index.d.ts
CHANGED
|
@@ -7550,10 +7550,21 @@ declare class ApprovalService implements IApprovalService {
|
|
|
7550
7550
|
private resolveDisplayField;
|
|
7551
7551
|
private static pickTitle;
|
|
7552
7552
|
/**
|
|
7553
|
-
*
|
|
7554
|
-
*
|
|
7555
|
-
|
|
7556
|
-
|
|
7553
|
+
* Batch-resolve `sys_user` display names for identifiers that may be user
|
|
7554
|
+
* ids or emails. Best-effort — failures leave entries unresolved.
|
|
7555
|
+
*/
|
|
7556
|
+
private resolveUserNames;
|
|
7557
|
+
/** Lookup-typed fields (key + referenced object) of an object's schema. */
|
|
7558
|
+
private resolveLookupFields;
|
|
7559
|
+
/**
|
|
7560
|
+
* Attach inbox display fields to rows so clients never render a raw
|
|
7561
|
+
* identifier: `record_title`, `submitter_name`, `object_label`,
|
|
7562
|
+
* `pending_approver_names` (user-id approvers), and `payload_display`
|
|
7563
|
+
* (lookup foreign keys in the snapshot → referenced record titles).
|
|
7564
|
+
* Batched: one query per distinct object (target + referenced) plus one
|
|
7565
|
+
* `sys_user` lookup. Best-effort — a deleted record falls back to the
|
|
7566
|
+
* payload snapshot, and any failure leaves the field unset rather than
|
|
7567
|
+
* failing the list.
|
|
7557
7568
|
*/
|
|
7558
7569
|
private enrichRows;
|
|
7559
7570
|
listRequests(filter: {
|
package/dist/index.js
CHANGED
|
@@ -1464,10 +1464,67 @@ var ApprovalService = class _ApprovalService {
|
|
|
1464
1464
|
return void 0;
|
|
1465
1465
|
}
|
|
1466
1466
|
/**
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
|
|
1470
|
-
|
|
1467
|
+
* Batch-resolve `sys_user` display names for identifiers that may be user
|
|
1468
|
+
* ids or emails. Best-effort — failures leave entries unresolved.
|
|
1469
|
+
*/
|
|
1470
|
+
async resolveUserNames(identifiers) {
|
|
1471
|
+
const names = /* @__PURE__ */ new Map();
|
|
1472
|
+
const targets = Array.from(new Set(identifiers.filter(Boolean)));
|
|
1473
|
+
if (!targets.length) return names;
|
|
1474
|
+
try {
|
|
1475
|
+
const users = await this.engine.find("sys_user", {
|
|
1476
|
+
where: { id: { $in: targets } },
|
|
1477
|
+
fields: ["id", "name", "email"],
|
|
1478
|
+
limit: targets.length,
|
|
1479
|
+
context: SYSTEM_CTX
|
|
1480
|
+
});
|
|
1481
|
+
for (const u of users ?? []) {
|
|
1482
|
+
if (u?.id && (u.name || u.email)) names.set(String(u.id), String(u.name ?? u.email));
|
|
1483
|
+
}
|
|
1484
|
+
} catch {
|
|
1485
|
+
}
|
|
1486
|
+
const unresolvedEmails = targets.filter((t) => !names.has(t) && t.includes("@"));
|
|
1487
|
+
if (unresolvedEmails.length) {
|
|
1488
|
+
try {
|
|
1489
|
+
const users = await this.engine.find("sys_user", {
|
|
1490
|
+
where: { email: { $in: unresolvedEmails } },
|
|
1491
|
+
fields: ["email", "name"],
|
|
1492
|
+
limit: unresolvedEmails.length,
|
|
1493
|
+
context: SYSTEM_CTX
|
|
1494
|
+
});
|
|
1495
|
+
for (const u of users ?? []) {
|
|
1496
|
+
if (u?.email && u.name) names.set(String(u.email), String(u.name));
|
|
1497
|
+
}
|
|
1498
|
+
} catch {
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
return names;
|
|
1502
|
+
}
|
|
1503
|
+
/** Lookup-typed fields (key + referenced object) of an object's schema. */
|
|
1504
|
+
resolveLookupFields(object) {
|
|
1505
|
+
try {
|
|
1506
|
+
const schema = this.engine.getSchema?.(object);
|
|
1507
|
+
const fields = schema?.fields ?? {};
|
|
1508
|
+
const out = [];
|
|
1509
|
+
for (const [key, f] of Object.entries(fields)) {
|
|
1510
|
+
if ((f?.type === "lookup" || f?.type === "master_detail") && f?.reference) {
|
|
1511
|
+
out.push({ key, reference: String(f.reference) });
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return out;
|
|
1515
|
+
} catch {
|
|
1516
|
+
return [];
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Attach inbox display fields to rows so clients never render a raw
|
|
1521
|
+
* identifier: `record_title`, `submitter_name`, `object_label`,
|
|
1522
|
+
* `pending_approver_names` (user-id approvers), and `payload_display`
|
|
1523
|
+
* (lookup foreign keys in the snapshot → referenced record titles).
|
|
1524
|
+
* Batched: one query per distinct object (target + referenced) plus one
|
|
1525
|
+
* `sys_user` lookup. Best-effort — a deleted record falls back to the
|
|
1526
|
+
* payload snapshot, and any failure leaves the field unset rather than
|
|
1527
|
+
* failing the list.
|
|
1471
1528
|
*/
|
|
1472
1529
|
async enrichRows(rows) {
|
|
1473
1530
|
if (!rows.length) return;
|
|
@@ -1482,7 +1539,13 @@ var ApprovalService = class _ApprovalService {
|
|
|
1482
1539
|
set.add(r.record_id);
|
|
1483
1540
|
}
|
|
1484
1541
|
const titles = /* @__PURE__ */ new Map();
|
|
1542
|
+
const objectLabels = /* @__PURE__ */ new Map();
|
|
1485
1543
|
for (const [object, idSet] of byObject) {
|
|
1544
|
+
try {
|
|
1545
|
+
const schema = this.engine.getSchema?.(object);
|
|
1546
|
+
if (schema?.label) objectLabels.set(object, String(schema.label));
|
|
1547
|
+
} catch {
|
|
1548
|
+
}
|
|
1486
1549
|
const ids = Array.from(idSet);
|
|
1487
1550
|
const displayField = this.resolveDisplayField(object);
|
|
1488
1551
|
try {
|
|
@@ -1493,47 +1556,81 @@ var ApprovalService = class _ApprovalService {
|
|
|
1493
1556
|
});
|
|
1494
1557
|
for (const rec of recs ?? []) {
|
|
1495
1558
|
const title = _ApprovalService.pickTitle(rec, displayField);
|
|
1496
|
-
if (rec?.id && title) titles.set(`${object}
|
|
1559
|
+
if (rec?.id && title) titles.set(`${object} ${rec.id}`, title);
|
|
1497
1560
|
}
|
|
1498
1561
|
} catch {
|
|
1499
1562
|
}
|
|
1500
1563
|
}
|
|
1501
|
-
const
|
|
1502
|
-
const
|
|
1503
|
-
|
|
1564
|
+
const lookupFieldsByObject = /* @__PURE__ */ new Map();
|
|
1565
|
+
for (const object of byObject.keys()) {
|
|
1566
|
+
const lookups = this.resolveLookupFields(object);
|
|
1567
|
+
if (lookups.length) lookupFieldsByObject.set(object, lookups);
|
|
1568
|
+
}
|
|
1569
|
+
const refIds = /* @__PURE__ */ new Map();
|
|
1570
|
+
for (const r of rows) {
|
|
1571
|
+
const lookups = lookupFieldsByObject.get(r.object_name);
|
|
1572
|
+
const payload = r.payload;
|
|
1573
|
+
if (!lookups || !payload || typeof payload !== "object") continue;
|
|
1574
|
+
for (const { key, reference } of lookups) {
|
|
1575
|
+
const v = payload[key];
|
|
1576
|
+
if (v == null || typeof v === "object" || !String(v).trim()) continue;
|
|
1577
|
+
let set = refIds.get(reference);
|
|
1578
|
+
if (!set) {
|
|
1579
|
+
set = /* @__PURE__ */ new Set();
|
|
1580
|
+
refIds.set(reference, set);
|
|
1581
|
+
}
|
|
1582
|
+
set.add(String(v));
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
const refTitles = /* @__PURE__ */ new Map();
|
|
1586
|
+
for (const [object, idSet] of refIds) {
|
|
1587
|
+
const ids = Array.from(idSet);
|
|
1588
|
+
const displayField = this.resolveDisplayField(object);
|
|
1504
1589
|
try {
|
|
1505
|
-
const
|
|
1506
|
-
where: { id: { $in:
|
|
1507
|
-
|
|
1508
|
-
limit: submitters.length,
|
|
1590
|
+
const recs = await this.engine.find(object, {
|
|
1591
|
+
where: { id: { $in: ids } },
|
|
1592
|
+
limit: ids.length,
|
|
1509
1593
|
context: SYSTEM_CTX
|
|
1510
1594
|
});
|
|
1511
|
-
for (const
|
|
1512
|
-
|
|
1595
|
+
for (const rec of recs ?? []) {
|
|
1596
|
+
const title = _ApprovalService.pickTitle(rec, displayField);
|
|
1597
|
+
if (rec?.id && title) refTitles.set(`${object} ${rec.id}`, title);
|
|
1513
1598
|
}
|
|
1514
1599
|
} catch {
|
|
1515
1600
|
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
limit: unresolvedEmails.length,
|
|
1523
|
-
context: SYSTEM_CTX
|
|
1524
|
-
});
|
|
1525
|
-
for (const u of users ?? []) {
|
|
1526
|
-
if (u?.email && u.name) names.set(String(u.email), String(u.name));
|
|
1527
|
-
}
|
|
1528
|
-
} catch {
|
|
1529
|
-
}
|
|
1601
|
+
}
|
|
1602
|
+
const userIdentifiers = [];
|
|
1603
|
+
for (const r of rows) {
|
|
1604
|
+
userIdentifiers.push(r.submitter_id);
|
|
1605
|
+
for (const a of r.pending_approvers ?? []) {
|
|
1606
|
+
if (a && !a.includes(":")) userIdentifiers.push(a);
|
|
1530
1607
|
}
|
|
1531
1608
|
}
|
|
1609
|
+
const names = await this.resolveUserNames(userIdentifiers);
|
|
1532
1610
|
for (const r of rows) {
|
|
1533
|
-
const title = titles.get(`${r.object_name}
|
|
1611
|
+
const title = titles.get(`${r.object_name} ${r.record_id}`) ?? _ApprovalService.pickTitle(r.payload, void 0);
|
|
1534
1612
|
if (title) r.record_title = title;
|
|
1535
1613
|
const name = r.submitter_id ? names.get(String(r.submitter_id)) : void 0;
|
|
1536
1614
|
if (name) r.submitter_name = name;
|
|
1615
|
+
const label = objectLabels.get(r.object_name);
|
|
1616
|
+
if (label) r.object_label = label;
|
|
1617
|
+
const approverNames = {};
|
|
1618
|
+
for (const a of r.pending_approvers ?? []) {
|
|
1619
|
+
const n = names.get(String(a));
|
|
1620
|
+
if (n) approverNames[a] = n;
|
|
1621
|
+
}
|
|
1622
|
+
if (Object.keys(approverNames).length) r.pending_approver_names = approverNames;
|
|
1623
|
+
const lookups = lookupFieldsByObject.get(r.object_name);
|
|
1624
|
+
if (lookups && r.payload && typeof r.payload === "object") {
|
|
1625
|
+
const display = {};
|
|
1626
|
+
for (const { key, reference } of lookups) {
|
|
1627
|
+
const v = r.payload[key];
|
|
1628
|
+
if (v == null) continue;
|
|
1629
|
+
const t = refTitles.get(`${reference} ${String(v)}`);
|
|
1630
|
+
if (t) display[key] = t;
|
|
1631
|
+
}
|
|
1632
|
+
if (Object.keys(display).length) r.payload_display = display;
|
|
1633
|
+
}
|
|
1537
1634
|
}
|
|
1538
1635
|
}
|
|
1539
1636
|
// ── Read API ─────────────────────────────────────────────────
|
|
@@ -1592,7 +1689,15 @@ var ApprovalService = class _ApprovalService {
|
|
|
1592
1689
|
orderBy: [{ field: "created_at", direction: "asc" }],
|
|
1593
1690
|
context: SYSTEM_CTX
|
|
1594
1691
|
});
|
|
1595
|
-
|
|
1692
|
+
const actions = Array.isArray(rows) ? rows.map(rowFromAction) : [];
|
|
1693
|
+
const names = await this.resolveUserNames(
|
|
1694
|
+
actions.map((a) => a.actor_id).filter((id) => id && !id.includes(":"))
|
|
1695
|
+
);
|
|
1696
|
+
for (const a of actions) {
|
|
1697
|
+
const n = a.actor_id ? names.get(String(a.actor_id)) : void 0;
|
|
1698
|
+
if (n) a.actor_name = n;
|
|
1699
|
+
}
|
|
1700
|
+
return actions;
|
|
1596
1701
|
}
|
|
1597
1702
|
};
|
|
1598
1703
|
|