filegrc 0.16.8 → 0.16.10
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/package.json +1 -1
- package/src/applicability-scope.js +52 -10
- package/src/audit-preparation.js +3 -0
- package/src/program-readiness.js +16 -1
- package/src/web.js +55 -40
- package/src/workflow.js +3 -2
package/package.json
CHANGED
|
@@ -117,13 +117,16 @@ export function applicabilityScopeRevision(record, program, resources, model, op
|
|
|
117
117
|
policies: resources
|
|
118
118
|
.filter(({ type, id }) => type === "policy" && selectedPolicyIds.has(id))
|
|
119
119
|
.sort(compareRecordIds)
|
|
120
|
-
.map((policy) => options.legacyPolicyStatus
|
|
120
|
+
.map((policy) => options.legacyPolicyStatus || options.legacyPolicyOverrides
|
|
121
121
|
? pick({
|
|
122
122
|
...policy,
|
|
123
|
-
status: options.legacyPolicyStatus
|
|
124
|
-
?
|
|
125
|
-
effectiveOn: options.
|
|
126
|
-
? undefined : policy.effectiveOn
|
|
123
|
+
status: (options.legacyPolicyOverrides?.[policy.id]?.status || options.legacyPolicyStatus || "current") === "current"
|
|
124
|
+
? policy.status : options.legacyPolicyOverrides?.[policy.id]?.status || options.legacyPolicyStatus,
|
|
125
|
+
effectiveOn: (options.legacyPolicyOverrides?.[policy.id]?.withoutEffectiveOn
|
|
126
|
+
?? options.legacyPolicyWithoutEffectiveOn) ? undefined : policy.effectiveOn,
|
|
127
|
+
approvedContentRevisions: (options.legacyPolicyOverrides?.[policy.id]?.withoutApprovalBinding
|
|
128
|
+
?? options.legacyPolicyWithoutApprovalBinding)
|
|
129
|
+
? undefined : policy.approvedContentRevisions
|
|
127
130
|
}, [
|
|
128
131
|
"id", "status", "policyKind", "version", "programRole", "effectiveOn",
|
|
129
132
|
"requirementIds", "audience", "acknowledgementRequired",
|
|
@@ -168,11 +171,50 @@ export function applicabilityReviewIsCurrent(review, record, program, resources,
|
|
|
168
171
|
if (!review?.scopeRevision) return false;
|
|
169
172
|
const matches = (revision) => revisionsMatch("applicability-scope", review.scopeRevision, revision);
|
|
170
173
|
if (matches(applicabilityScopeRevision(record, program, resources, model))) return true;
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
// Older reviews hashed Policy approval metadata alongside scope facts.
|
|
175
|
+
// Reconstruct each Policy independently because other Policies may already
|
|
176
|
+
// have been approved when one Policy changes. Material fields stay current.
|
|
177
|
+
for (const legacyPolicyStatus of ["current", "draft", "in-review", "approved", "active"]) {
|
|
178
|
+
for (const legacyPolicyWithoutApprovalBinding of [false, true]) {
|
|
179
|
+
for (const legacyPolicyWithoutEffectiveOn of [false, true]) {
|
|
180
|
+
if (matches(applicabilityScopeRevision(record, program, resources, model, {
|
|
181
|
+
legacyPolicyStatus,
|
|
182
|
+
legacyPolicyWithoutApprovalBinding,
|
|
183
|
+
legacyPolicyWithoutEffectiveOn
|
|
184
|
+
}))) return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const selectedControlIds = new Set(program?.controlIds || []);
|
|
189
|
+
const selectedPolicyIds = new Set(resources
|
|
190
|
+
.filter(({ type, id }) => type === "control" && selectedControlIds.has(id))
|
|
191
|
+
.flatMap(({ policyIds }) => policyIds || []));
|
|
192
|
+
for (const id of record.policyIds || []) selectedPolicyIds.add(id);
|
|
193
|
+
const policies = resources.filter(({ type, id }) => type === "policy" && selectedPolicyIds.has(id));
|
|
194
|
+
// One Policy may advance while the others retain different approval states.
|
|
195
|
+
// Reconstruct that Policy's former lifecycle fields without changing any
|
|
196
|
+
// material scope fact or searching combinations of unrelated Policies.
|
|
197
|
+
for (const policy of policies) {
|
|
198
|
+
for (const value of legacyPolicyAlternatives(policy)) {
|
|
199
|
+
if (matches(applicabilityScopeRevision(record, program, resources, model, {
|
|
200
|
+
legacyPolicyOverrides: { [policy.id]: value }
|
|
201
|
+
}))) return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function legacyPolicyAlternatives(policy) {
|
|
208
|
+
const prior = {
|
|
209
|
+
active: ["approved", "in-review", "draft"],
|
|
210
|
+
approved: ["in-review", "draft"],
|
|
211
|
+
"in-review": ["draft"]
|
|
212
|
+
}[policy.status] || [];
|
|
213
|
+
return prior.map((status) => ({
|
|
214
|
+
status,
|
|
215
|
+
withoutApprovalBinding: status === "draft" || status === "in-review",
|
|
216
|
+
withoutEffectiveOn: true
|
|
217
|
+
}));
|
|
176
218
|
}
|
|
177
219
|
|
|
178
220
|
function pick(record, fields, model, objectType = null) {
|
package/src/audit-preparation.js
CHANGED
|
@@ -1831,6 +1831,9 @@ function item(id, status, title, message, resource = {}, options = {}) {
|
|
|
1831
1831
|
message,
|
|
1832
1832
|
...(resource.type ? { resourceType: resource.type } : {}),
|
|
1833
1833
|
...(resource.id ? { resourceId: resource.id } : {}),
|
|
1834
|
+
...(resource.type ? { destination: resource.id
|
|
1835
|
+
? { kind: "record", resourceType: resource.type, resourceId: resource.id }
|
|
1836
|
+
: { kind: "collection", resourceType: resource.type } } : {}),
|
|
1834
1837
|
...(options.commands?.length ? { commands: options.commands } : {}),
|
|
1835
1838
|
...(options.affectedActionItemIds?.length ? { affectedActionItemIds: options.affectedActionItemIds } : {}),
|
|
1836
1839
|
...(options.affectedEventIds?.length ? { affectedEventIds: options.affectedEventIds } : {}),
|
package/src/program-readiness.js
CHANGED
|
@@ -774,9 +774,23 @@ export function collectionReviewReadinessItem(assessment) {
|
|
|
774
774
|
? { id: firstIncomplete.resourceId, type: assessment.resourceType }
|
|
775
775
|
: needsFirstRecord ? { type: assessment.resourceType }
|
|
776
776
|
: approvalAction ? { type: approvalAction.resourceType, ...(approvalAction.resourceId ? { id: approvalAction.resourceId } : {}) }
|
|
777
|
-
:
|
|
777
|
+
: { type: assessment.resourceType },
|
|
778
778
|
{
|
|
779
779
|
resourceType: approvalAction?.resourceType || assessment.resourceType,
|
|
780
|
+
...(!proposalAction && !needsFirstRecord && !approvalAction && assessment.review?.id
|
|
781
|
+
? { subject: { type: "collection-review", id: assessment.review.id } }
|
|
782
|
+
: {}),
|
|
783
|
+
destination: proposalAction
|
|
784
|
+
? { kind: "record", resourceType: assessment.resourceType, resourceId: firstIncomplete.resourceId }
|
|
785
|
+
: needsFirstRecord
|
|
786
|
+
? { kind: "collection", resourceType: assessment.resourceType, create: true }
|
|
787
|
+
: approvalAction
|
|
788
|
+
? approvalAction.reviewCollection
|
|
789
|
+
? { kind: "collection-review", resourceType: approvalAction.resourceType }
|
|
790
|
+
: approvalAction.resourceId
|
|
791
|
+
? { kind: "record", resourceType: approvalAction.resourceType, resourceId: approvalAction.resourceId }
|
|
792
|
+
: { kind: "collection", resourceType: approvalAction.resourceType, ...(approvalAction.createResource ? { create: true, scheduleDocument: true } : {}) }
|
|
793
|
+
: { kind: "collection-review", resourceType: assessment.resourceType },
|
|
780
794
|
reviewPoints: assessment.configuration.reviewPoints,
|
|
781
795
|
...(approvalAction?.createResource ? { createResource: true } : {}),
|
|
782
796
|
...(pendingRetentionRow && !proposalAction ? { unresolvedAssignments: [{
|
|
@@ -842,6 +856,7 @@ function collectionApprovalIssueAction(assessment) {
|
|
|
842
856
|
if (issue.code === "unreviewed-similar-information-types") return {
|
|
843
857
|
title: "Review similar Information Types",
|
|
844
858
|
resourceType: "information-type",
|
|
859
|
+
reviewCollection: true,
|
|
845
860
|
commands: ["npx filegrc list information-type --workflow --json", "npx filegrc review-collection information-type --scaffold > REVIEW.json", "npx filegrc review-collection information-type REVIEW.json --preview --json", "npx filegrc review-collection information-type REVIEW.json --yes --json"]
|
|
846
861
|
};
|
|
847
862
|
return {
|
package/src/web.js
CHANGED
|
@@ -53,6 +53,38 @@ export function pageActionIdentity(href = "", fallback = "") {
|
|
|
53
53
|
return route.startsWith("#/resource/") ? route : fallback || href;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export function resolveWorkflowDestination(destination, options = {}) {
|
|
57
|
+
if (!destination?.resourceType) return "";
|
|
58
|
+
if (options.resourceTypes && !options.resourceTypes[destination.resourceType]) return "";
|
|
59
|
+
const type = encodeURIComponent(destination.resourceType);
|
|
60
|
+
if (destination.kind === "record") {
|
|
61
|
+
const exists = !options.resources || options.resources.some((entry) => {
|
|
62
|
+
const record = entry.record || entry;
|
|
63
|
+
return record.type === destination.resourceType && record.id === destination.resourceId;
|
|
64
|
+
});
|
|
65
|
+
return destination.resourceId && exists
|
|
66
|
+
? `#/resource/${type}/${encodeURIComponent(destination.resourceId)}${destination.edit ? "?edit=1" : ""}`
|
|
67
|
+
: resolveWorkflowDestination({ kind: "collection", resourceType: destination.resourceType }, options);
|
|
68
|
+
}
|
|
69
|
+
if (destination.kind === "collection-review") {
|
|
70
|
+
if (destination.resourceType === "retention-schedule-item" && options.retentionScheduleApproval) {
|
|
71
|
+
return "#/retention-schedule";
|
|
72
|
+
}
|
|
73
|
+
return `#/resources/${type}?review-collection=1`;
|
|
74
|
+
}
|
|
75
|
+
if (destination.kind === "collection") {
|
|
76
|
+
const create = destination.create && !options.readOnly;
|
|
77
|
+
if (destination.resourceType === "retention-schedule-item" && options.retentionScheduleApproval) {
|
|
78
|
+
return create ? "#/retention-schedule?new=1" : "#/retention-schedule";
|
|
79
|
+
}
|
|
80
|
+
if (destination.resourceType === "document" && create && destination.scheduleDocument) {
|
|
81
|
+
return "#/resources/document?new=1&documentScope=program&documentKind=schedule&programRole=required&title=Data%20Retention%20Schedule";
|
|
82
|
+
}
|
|
83
|
+
return `#/resources/${type}${create ? "?new=1" : ""}`;
|
|
84
|
+
}
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
|
|
56
88
|
export function renderIndex(state = null) {
|
|
57
89
|
const snapshot = state
|
|
58
90
|
? `<script id="filegrc-data" type="application/json">${safeJson(state)}</script>`
|
|
@@ -100,6 +132,7 @@ const RESOURCE_GUIDE_OUTPUTS = ${JSON.stringify(RESOURCE_OUTPUTS)};
|
|
|
100
132
|
const dashboardProgramReadiness = ${dashboardProgramReadiness.toString()};
|
|
101
133
|
const workflowHrefBelongsToPage = ${workflowHrefBelongsToPage.toString()};
|
|
102
134
|
const pageActionIdentity = ${pageActionIdentity.toString()};
|
|
135
|
+
const resolveWorkflowDestination = ${resolveWorkflowDestination.toString()};
|
|
103
136
|
const selectDefaultAudit = ${selectDefaultAudit.toString()};
|
|
104
137
|
const STAGE_PAGE_SUMMARIES = ${JSON.stringify({
|
|
105
138
|
...RESOURCE_PAGE_SUMMARIES,
|
|
@@ -786,11 +819,7 @@ function renderRetentionScheduleIssues() {
|
|
|
786
819
|
));
|
|
787
820
|
if (!actions.length) return "";
|
|
788
821
|
return '<section class="retention-issues"><div class="section-head"><div><p class="kicker">Before approval</p><h2>Items to resolve</h2></div></div><div class="retention-issue-list">' + actions.map((item) => {
|
|
789
|
-
const href = item.href || (item
|
|
790
|
-
? retentionScheduleItemHref(item)
|
|
791
|
-
: item.resourceId && item.resourceType
|
|
792
|
-
? '#/resource/' + encodeURIComponent(item.resourceType) + '/' + encodeURIComponent(item.resourceId)
|
|
793
|
-
: '#/resources/' + encodeURIComponent(item.resourceType || "retention-schedule-item"));
|
|
822
|
+
const href = item.href || workflowItemHref(item) || "#/retention-schedule";
|
|
794
823
|
return '<a href="' + href + '"><span><strong>' + esc(item.title) + '</strong><small>' + esc(item.message) + '</small></span><b>Review</b></a>';
|
|
795
824
|
}).join("") + '</div></section>';
|
|
796
825
|
}
|
|
@@ -1286,9 +1315,7 @@ function renderFinishStepThree() {
|
|
|
1286
1315
|
));
|
|
1287
1316
|
const next = implementationItems.find(({ status }) => status !== "complete");
|
|
1288
1317
|
if (!oversightItem) {
|
|
1289
|
-
const href = next?.id?.startsWith("
|
|
1290
|
-
? "#/resources/" + encodeURIComponent(next.resourceType) + "?review-collection=1"
|
|
1291
|
-
: next?.id?.startsWith("source-family-")
|
|
1318
|
+
const href = next?.id?.startsWith("source-family-")
|
|
1292
1319
|
? "#/evidence-sources"
|
|
1293
1320
|
: next ? workflowItemHref({ ...next, state: next.status }) || "#/resources/control" : "#/resources/control";
|
|
1294
1321
|
return '<section class="finish-step panel blocked"><div><p class="kicker">Finish Step 3</p><h2>Complete implementation first</h2><p>' + esc(next?.message || "Finish the Step 3 work areas before the final review becomes available.") + '</p></div><a class="button primary" href="' + esc(href) + '">Continue implementation</a></section>';
|
|
@@ -1490,6 +1517,16 @@ function openCollectionReviewDialog(type) {
|
|
|
1490
1517
|
}
|
|
1491
1518
|
|
|
1492
1519
|
function workflowItemHref(item) {
|
|
1520
|
+
const destinationOptions = {
|
|
1521
|
+
retentionScheduleApproval: modelSupports("retention-schedule-approval"),
|
|
1522
|
+
readOnly: state.readOnly,
|
|
1523
|
+
resourceTypes: state.model.resources,
|
|
1524
|
+
resources: state.resources
|
|
1525
|
+
};
|
|
1526
|
+
const destinationHref = (destination) => resolveWorkflowDestination(destination, destinationOptions);
|
|
1527
|
+
if (item.destination) {
|
|
1528
|
+
return destinationHref(item.destination);
|
|
1529
|
+
}
|
|
1493
1530
|
const source = item.source?.id && item.source?.type && item.source.type !== "unknown"
|
|
1494
1531
|
? item.source
|
|
1495
1532
|
: null;
|
|
@@ -1518,19 +1555,18 @@ function workflowItemHref(item) {
|
|
|
1518
1555
|
&& item.subject?.id
|
|
1519
1556
|
&& state.resources.some(({ record }) => record.type === applicabilityType && record.id === item.subject.id)
|
|
1520
1557
|
) {
|
|
1521
|
-
return "
|
|
1558
|
+
return destinationHref({ kind: "record", resourceType: applicabilityType, resourceId: item.subject.id });
|
|
1522
1559
|
}
|
|
1523
1560
|
if (commands.some((command) => command.includes(" scaffold retention-schedule-item"))) {
|
|
1524
1561
|
return retentionScheduleItemHref(item);
|
|
1525
1562
|
}
|
|
1526
1563
|
if (applicabilityType && state.model.resources[applicabilityType]) {
|
|
1527
|
-
return "
|
|
1564
|
+
return destinationHref({ kind: "collection", resourceType: applicabilityType }) + "?review=1";
|
|
1528
1565
|
}
|
|
1529
1566
|
const collectionReviewCommand = commands.find((command) => command.includes(" review-collection "));
|
|
1530
1567
|
const collectionReviewType = collectionReviewCommand?.match(/review-collection\s+([a-z0-9-]+)/)?.[1];
|
|
1531
1568
|
if (collectionReviewType && state.model.collectionReviews?.[collectionReviewType]) {
|
|
1532
|
-
|
|
1533
|
-
return "#/resources/" + encodeURIComponent(collectionReviewType) + "?review-collection=1";
|
|
1569
|
+
return destinationHref({ kind: "collection-review", resourceType: collectionReviewType });
|
|
1534
1570
|
}
|
|
1535
1571
|
if (
|
|
1536
1572
|
commands.some((command) => command.includes(" get ") && command.includes(" --mutation"))
|
|
@@ -1538,25 +1574,25 @@ function workflowItemHref(item) {
|
|
|
1538
1574
|
&& item.subject?.type
|
|
1539
1575
|
&& state.model.resources[item.subject.type]
|
|
1540
1576
|
) {
|
|
1541
|
-
return "
|
|
1577
|
+
return destinationHref({ kind: "record", resourceType: item.subject.type, resourceId: item.subject.id, edit: true });
|
|
1542
1578
|
}
|
|
1543
1579
|
if (commands.some((command) => command.includes(" external-reviewer-setup"))) {
|
|
1544
1580
|
const reviewer = resourcesOfType("appointment")
|
|
1545
1581
|
.find(({ record }) => record.appointmentKind === "independent-policy-reviewer");
|
|
1546
|
-
if (reviewer) return "
|
|
1582
|
+
if (reviewer) return destinationHref({ kind: "record", resourceType: "appointment", resourceId: reviewer.record.id });
|
|
1547
1583
|
}
|
|
1548
1584
|
if (commands.some((command) => command.includes(" evidence-map"))) return "#/stage/controls";
|
|
1549
1585
|
const reference = item.subject?.id && item.subject?.type
|
|
1550
1586
|
? item.subject
|
|
1551
1587
|
: source;
|
|
1552
1588
|
if (reference && reference.type !== "unknown") {
|
|
1553
|
-
return "
|
|
1589
|
+
return destinationHref({ kind: "record", resourceType: reference.type, resourceId: reference.id });
|
|
1554
1590
|
}
|
|
1555
1591
|
const missingType = item.subject?.type && state.model.resources[item.subject.type]
|
|
1556
1592
|
? item.subject.type
|
|
1557
1593
|
: null;
|
|
1558
1594
|
if (missingType) {
|
|
1559
|
-
return "
|
|
1595
|
+
return destinationHref({ kind: "collection", resourceType: missingType, create: !state.readOnly });
|
|
1560
1596
|
}
|
|
1561
1597
|
if (item.auditId) return "#/audit-packet?auditId=" + encodeURIComponent(item.auditId);
|
|
1562
1598
|
const stage = {
|
|
@@ -1714,13 +1750,9 @@ function retentionSchedulePageItems() {
|
|
|
1714
1750
|
...item,
|
|
1715
1751
|
key: item.id,
|
|
1716
1752
|
state: "ready",
|
|
1717
|
-
href: item.id
|
|
1718
|
-
? retentionCollectionActionHref(item)
|
|
1719
|
-
: item.id?.startsWith("retention-use-")
|
|
1753
|
+
href: item.id?.startsWith("retention-use-")
|
|
1720
1754
|
? retentionScheduleItemHref(item)
|
|
1721
|
-
: item
|
|
1722
|
-
? '#/resource/' + encodeURIComponent(item.resourceType) + '/' + encodeURIComponent(item.resourceId)
|
|
1723
|
-
: workflowItemHref(item) || "#/retention-schedule",
|
|
1755
|
+
: workflowItemHref(item) || "#/retention-schedule",
|
|
1724
1756
|
subject: item.resourceId && item.resourceType
|
|
1725
1757
|
? { type: item.resourceType, id: item.resourceId }
|
|
1726
1758
|
: item.subject
|
|
@@ -1728,19 +1760,6 @@ function retentionSchedulePageItems() {
|
|
|
1728
1760
|
]);
|
|
1729
1761
|
}
|
|
1730
1762
|
|
|
1731
|
-
function retentionCollectionActionHref(item) {
|
|
1732
|
-
if (item.resourceType === "document") return item.resourceId
|
|
1733
|
-
? '#/resource/document/' + encodeURIComponent(item.resourceId) + '?stage=policies'
|
|
1734
|
-
: item.createResource
|
|
1735
|
-
? '#/resources/document?new=1&documentScope=program&documentKind=schedule&programRole=required&title=Data%20Retention%20Schedule'
|
|
1736
|
-
: '#/resources/document';
|
|
1737
|
-
if (item.resourceType === "information-type") return '#/resources/information-type?review-collection=1';
|
|
1738
|
-
if (item.resourceType === "retention-schedule-item" && item.resourceId && item.resourceId !== item.id) {
|
|
1739
|
-
return '#/resource/retention-schedule-item/' + encodeURIComponent(item.resourceId) + '?stage=policies';
|
|
1740
|
-
}
|
|
1741
|
-
return "#/retention-schedule";
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
1763
|
function distinctPageActionItems(items) {
|
|
1745
1764
|
const distinct = new Map();
|
|
1746
1765
|
for (const item of items) {
|
|
@@ -3017,11 +3036,7 @@ function renderAuditPreparation(preparation) {
|
|
|
3017
3036
|
const status = preparation.status === "management-ready" ? "Management work complete" : preparation.counts.action + " actions remaining";
|
|
3018
3037
|
const stages = preparation.stages.map((stage) => {
|
|
3019
3038
|
const items = stage.items.map((item) => {
|
|
3020
|
-
const href = item
|
|
3021
|
-
? '#/resource/' + encodeURIComponent(item.resourceType) + '/' + encodeURIComponent(item.resourceId)
|
|
3022
|
-
: item.resourceType
|
|
3023
|
-
? '#/resources/' + encodeURIComponent(item.resourceType)
|
|
3024
|
-
: "";
|
|
3039
|
+
const href = workflowItemHref(item);
|
|
3025
3040
|
const content = '<span class="preparation-status ' + esc(item.status) + '" aria-hidden="true">' + preparationStatusMark(item.status) + '</span><span><strong>' + esc(item.title) + '</strong><small>' + esc(item.message) + '</small></span>';
|
|
3026
3041
|
return href ? '<a href="' + href + '">' + content + '</a>' : '<div>' + content + '</div>';
|
|
3027
3042
|
}).join("");
|
package/src/workflow.js
CHANGED
|
@@ -1115,9 +1115,9 @@ export function packetDeliveryIssue(delivery) {
|
|
|
1115
1115
|
|
|
1116
1116
|
function normalizeFinding(code, item, context) {
|
|
1117
1117
|
const state = findingState(item.status);
|
|
1118
|
-
const subject = item.resourceType
|
|
1118
|
+
const subject = item.subject || (item.resourceType
|
|
1119
1119
|
? { type: item.resourceType, ...(item.resourceId ? { id: item.resourceId } : {}) }
|
|
1120
|
-
: null;
|
|
1120
|
+
: null);
|
|
1121
1121
|
const dependencies = (item.unresolvedAssignments || []).map((assignment) => ({
|
|
1122
1122
|
type: assignment.resourceType,
|
|
1123
1123
|
id: assignment.resourceId,
|
|
@@ -1138,6 +1138,7 @@ function normalizeFinding(code, item, context) {
|
|
|
1138
1138
|
.filter(([, passed]) => passed === false)
|
|
1139
1139
|
.map(([name]) => name) } : {}),
|
|
1140
1140
|
...(item.resourceId ? { resourceId: item.resourceId } : {}),
|
|
1141
|
+
...(item.destination ? { destination: item.destination } : {}),
|
|
1141
1142
|
...(item.createResourceType ? { createResourceType: item.createResourceType } : {}),
|
|
1142
1143
|
...(item.sourceResourceIds ? { sourceResourceIds: item.sourceResourceIds } : {}),
|
|
1143
1144
|
...(item.informationTypeId ? { informationTypeId: item.informationTypeId } : {}),
|