filegrc 0.16.3 → 0.16.5
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/agent.js +2 -1
- package/src/audit-preparation.js +6 -1
- package/src/cli.js +71 -33
- package/src/index.js +1 -0
- package/src/program-path.js +141 -75
- package/src/program-readiness.js +194 -25
- package/src/reconciliation.js +1 -0
- package/src/retention-schedule-approval.js +5 -5
- package/src/state.js +1 -0
- package/src/web.js +72 -22
- package/src/workflow.js +1 -0
package/src/web.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
utcCalendarDate,
|
|
11
11
|
validCalendarRecurrence
|
|
12
12
|
} from "./recurrence.js";
|
|
13
|
-
import { PROGRAM_PATH, programPathForModel, RESOURCE_INSTRUCTIONS, RESOURCE_PAGE_SUMMARIES } from "./program-path.js";
|
|
13
|
+
import { PROGRAM_PATH, programPathForModel, RESOURCE_INSTRUCTIONS, RESOURCE_OUTPUTS, RESOURCE_PAGE_SUMMARIES } from "./program-path.js";
|
|
14
14
|
import { formatCalendarDate, formatLocalDateTime } from "./time.js";
|
|
15
15
|
|
|
16
16
|
export function dashboardProgramReadiness(programReadiness = {}) {
|
|
@@ -96,6 +96,7 @@ let READINESS_STAGES = SHARED_PROGRAM_STAGES.map((stage) => ({
|
|
|
96
96
|
number: String(stage.number)
|
|
97
97
|
}));
|
|
98
98
|
const RESOURCE_GUIDE_INSTRUCTIONS = ${JSON.stringify(RESOURCE_INSTRUCTIONS)};
|
|
99
|
+
const RESOURCE_GUIDE_OUTPUTS = ${JSON.stringify(RESOURCE_OUTPUTS)};
|
|
99
100
|
const dashboardProgramReadiness = ${dashboardProgramReadiness.toString()};
|
|
100
101
|
const workflowHrefBelongsToPage = ${workflowHrefBelongsToPage.toString()};
|
|
101
102
|
const pageActionIdentity = ${pageActionIdentity.toString()};
|
|
@@ -246,6 +247,7 @@ function normalizeAppState(next) {
|
|
|
246
247
|
function blockingStateSections(route) {
|
|
247
248
|
if (route.name === "home") return ["program", "obligations", "workflow"];
|
|
248
249
|
if (route.name === "repository") return ["repository"];
|
|
250
|
+
if (route.name === "list" && route.type === "control") return ["program"];
|
|
249
251
|
if (route.name === "list" && route.type === "obligation") return ["obligations"];
|
|
250
252
|
if (route.name === "obligations" || route.name === "stage" && route.stageId === "run") return ["program", "obligations"];
|
|
251
253
|
if (route.name === "audit-packet") return ["repository", "program", "obligations", "audits"];
|
|
@@ -576,8 +578,8 @@ function readinessOverview() {
|
|
|
576
578
|
const stage = READINESS_STAGES.find((candidate) => candidate.id === id);
|
|
577
579
|
const current = stageProgress(stage);
|
|
578
580
|
const remaining = current.total - current.complete;
|
|
579
|
-
const status =
|
|
580
|
-
return [stage.title, stage.summary, href, status,
|
|
581
|
+
const status = current.status === "In progress" ? remaining + " pages need work" : current.status;
|
|
582
|
+
return [stage.title, stage.summary, href, status, current.tone];
|
|
581
583
|
};
|
|
582
584
|
const stages = [
|
|
583
585
|
programStage("scope", "#/stage/scope"),
|
|
@@ -613,7 +615,7 @@ function renderStageOverview(main, stageId, params = new URLSearchParams()) {
|
|
|
613
615
|
const progress = stageProgress(stage);
|
|
614
616
|
main.innerHTML = '<div class="page stage-overview-page"><nav class="breadcrumbs"><a href="#/">Overview</a><span>/</span><span>' + esc(stage.title) + '</span></nav>' +
|
|
615
617
|
'<section class="stage-overview-hero"><div><p class="kicker">Step ' + esc(stage.number) + ' of 5</p><h2>' + esc(stage.title) + '</h2><p>' + esc(stage.summary) + '</p></div>' + stageProgressCard(progress) + '</section>' +
|
|
616
|
-
renderStagePageIndex(stage) + (stage.id === "controls" ? renderFinishStepThree() : "") + (stage.id === "audit" ? renderAuditDocumentActivationAssessments() : "") + '</div>';
|
|
618
|
+
renderStageInstructions(stage) + renderStagePageIndex(stage) + (stage.id === "controls" ? renderFinishStepThree() : "") + (stage.id === "audit" ? renderAuditDocumentActivationAssessments() : "") + '</div>';
|
|
617
619
|
main.querySelector("[data-show-evidence-families]")?.addEventListener("click", (event) => {
|
|
618
620
|
main.querySelectorAll("[data-evidence-family-extra]").forEach((card) => { card.hidden = false; });
|
|
619
621
|
event.currentTarget.remove();
|
|
@@ -634,7 +636,8 @@ function renderPoliciesPage(main, params = new URLSearchParams()) {
|
|
|
634
636
|
}
|
|
635
637
|
|
|
636
638
|
function policyContentGuide() {
|
|
637
|
-
|
|
639
|
+
const section = READINESS_STAGES.find(({ id }) => id === "policies")?.sections.find(({ id }) => id === "policy-content");
|
|
640
|
+
return '<section class="page-guide resource-guide-popover" id="resource-guide" role="dialog" aria-label="How to use Policies" hidden><div><span>Do now</span><p>' + esc(section?.instructions || "Review and approve the program's governing content.") + '</p></div><div><span>Output</span><p>' + esc(section?.output || "Approved content bound to the reviewed revisions.") + '</p></div></section>';
|
|
638
641
|
}
|
|
639
642
|
|
|
640
643
|
function renderRetentionSchedulePage(main, params = new URLSearchParams()) {
|
|
@@ -784,6 +787,7 @@ function wireRetentionScheduleTable(total, initialPage = 1) {
|
|
|
784
787
|
function renderRetentionScheduleIssues() {
|
|
785
788
|
const actions = retentionSchedulePageItems().filter((item) => (
|
|
786
789
|
item.id !== "collection-review-retention-schedule-item"
|
|
790
|
+
|| !item.commands?.some((command) => command.includes(" review-collection retention-schedule-item"))
|
|
787
791
|
));
|
|
788
792
|
if (!actions.length) return "";
|
|
789
793
|
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) => {
|
|
@@ -846,7 +850,7 @@ function renderPolicyApprovalGuidance() {
|
|
|
846
850
|
: "";
|
|
847
851
|
return '<article><strong>' + esc(proposal.title) + '</strong><p>' + esc(proposal.message) + '</p>' + review + '<div class="evidence-map-references">' + proposal.policyIds.map((id) => formatReference(id)).join("") + '</div></article>';
|
|
848
852
|
}).join("");
|
|
849
|
-
return '<section class="policy-lifecycle-note panel ' + (proposalRows ? "" : "single") + '"><div><p class="kicker">Step 2 approval</p><h3>Approve the governed content</h3><p>
|
|
853
|
+
return '<section class="policy-lifecycle-note panel ' + (proposalRows ? "" : "single") + '"><div><p class="kicker">Step 2 approval</p><h3>Approve the governed content</h3><p>Replace placeholders and confirm the intended values. Have a separate approver review the exact Markdown revision and record the approval date.</p></div>' + (proposalRows ? '<div class="policy-library-proposals">' + proposalRows + '</div>' : "") + '</section>';
|
|
850
854
|
}
|
|
851
855
|
|
|
852
856
|
function renderPoliciesTable(params = new URLSearchParams()) {
|
|
@@ -963,7 +967,8 @@ function renderDocumentActivationAssessments() {
|
|
|
963
967
|
}
|
|
964
968
|
|
|
965
969
|
function renderAuditDocumentActivationAssessments() {
|
|
966
|
-
const audits = resourcesOfType("audit").map(({ record }) => record)
|
|
970
|
+
const audits = resourcesOfType("audit").map(({ record }) => record)
|
|
971
|
+
.filter((record) => !state.selectedProgramId || record.programId === state.selectedProgramId);
|
|
967
972
|
const audit = selectDefaultAudit(audits, state.programReadiness?.asOf || currentDate());
|
|
968
973
|
const preparation = audit ? state.auditPreparations?.[audit.id] : null;
|
|
969
974
|
const assessments = preparation?.documentActivations || [];
|
|
@@ -1182,7 +1187,10 @@ function workflowGuidance(options = {}) {
|
|
|
1182
1187
|
const visible = items.slice(0, 6);
|
|
1183
1188
|
const renderRow = (item) => {
|
|
1184
1189
|
const href = workflowItemHref(item);
|
|
1185
|
-
const
|
|
1190
|
+
const guidance = options.type === "control" && item.nextSteps?.length
|
|
1191
|
+
? '<ol class="control-next-steps">' + item.nextSteps.map((step) => '<li>' + esc(step) + '</li>').join("") + '</ol>'
|
|
1192
|
+
: '<small>' + esc(item.message || workflowItemDetail(item)) + '</small>';
|
|
1193
|
+
const body = '<span class="workflow-finding-status ' + esc(item.state) + '">' + esc(properCase(item.state)) + '</span><span><strong>' + esc(item.title) + '</strong>' + guidance + '</span>';
|
|
1186
1194
|
return href ? '<a href="' + href + '">' + body + '</a>' : '<div>' + body + '</div>';
|
|
1187
1195
|
};
|
|
1188
1196
|
const rows = visible.map(renderRow).join("");
|
|
@@ -1712,7 +1720,7 @@ function retentionSchedulePageItems() {
|
|
|
1712
1720
|
key: item.id,
|
|
1713
1721
|
state: "ready",
|
|
1714
1722
|
href: item.id === "collection-review-retention-schedule-item"
|
|
1715
|
-
?
|
|
1723
|
+
? retentionCollectionActionHref(item)
|
|
1716
1724
|
: item.id?.startsWith("retention-use-")
|
|
1717
1725
|
? retentionScheduleItemHref(item)
|
|
1718
1726
|
: item.resourceId && item.resourceType
|
|
@@ -1725,6 +1733,19 @@ function retentionSchedulePageItems() {
|
|
|
1725
1733
|
]);
|
|
1726
1734
|
}
|
|
1727
1735
|
|
|
1736
|
+
function retentionCollectionActionHref(item) {
|
|
1737
|
+
if (item.resourceType === "document") return item.resourceId
|
|
1738
|
+
? '#/resource/document/' + encodeURIComponent(item.resourceId) + '?stage=policies'
|
|
1739
|
+
: item.createResource
|
|
1740
|
+
? '#/resources/document?new=1&documentScope=program&documentKind=schedule&programRole=required&title=Data%20Retention%20Schedule'
|
|
1741
|
+
: '#/resources/document';
|
|
1742
|
+
if (item.resourceType === "information-type") return '#/resources/information-type?review-collection=1';
|
|
1743
|
+
if (item.resourceType === "retention-schedule-item" && item.resourceId && item.resourceId !== item.id) {
|
|
1744
|
+
return '#/resource/retention-schedule-item/' + encodeURIComponent(item.resourceId) + '?stage=policies';
|
|
1745
|
+
}
|
|
1746
|
+
return "#/retention-schedule";
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1728
1749
|
function distinctPageActionItems(items) {
|
|
1729
1750
|
const distinct = new Map();
|
|
1730
1751
|
for (const item of items) {
|
|
@@ -1750,6 +1771,12 @@ function renderStagePageIndex(stage) {
|
|
|
1750
1771
|
return '<section class="stage-pages" aria-label="Step ' + esc(stage.number) + ' pages"><div class="stage-page-grid">' + cards + '</div></section>';
|
|
1751
1772
|
}
|
|
1752
1773
|
|
|
1774
|
+
function renderStageInstructions(stage) {
|
|
1775
|
+
return '<details class="stage-instructions"><summary>How to complete Step ' + esc(stage.number) + '</summary><div class="stage-instructions-body">' + stage.sections.map((section) => (
|
|
1776
|
+
'<section><h3>' + esc(section.title) + '</h3><ol>' + section.steps.map((step) => '<li>' + esc(step) + '</li>').join("") + '</ol></section>'
|
|
1777
|
+
)).join("") + '</div></details>';
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1753
1780
|
function stagePageDestinations(stage) {
|
|
1754
1781
|
return stage.sections.flatMap((section) => sectionDestinations(section)
|
|
1755
1782
|
.filter((destination) => destination.utility !== "obligation-board")
|
|
@@ -1820,7 +1847,7 @@ function derivedStagePageState(stage, destination) {
|
|
|
1820
1847
|
if (
|
|
1821
1848
|
stage.id === "audit"
|
|
1822
1849
|
&& state.workflow?.assessments?.auditReadiness?.status === "not-started"
|
|
1823
|
-
&& (destination.type === "audit" || destination.utility === "audit-packet")
|
|
1850
|
+
&& (destination.type === "audit" || destination.type === "document" && destination.href.includes("documentScope=audit") || destination.utility === "audit-packet")
|
|
1824
1851
|
) {
|
|
1825
1852
|
return { complete: false, label: "No engagement" };
|
|
1826
1853
|
}
|
|
@@ -1829,14 +1856,14 @@ function derivedStagePageState(stage, destination) {
|
|
|
1829
1856
|
.filter(({ id }) => id.startsWith("source-family-")) || [];
|
|
1830
1857
|
const incomplete = evidenceItems.filter(({ status }) => status !== "complete").length;
|
|
1831
1858
|
return incomplete
|
|
1832
|
-
? { complete: false, label: incomplete + " " + pluralize("source", incomplete) + " need work" }
|
|
1859
|
+
? { complete: false, label: incomplete + " " + pluralize("source", incomplete) + (incomplete === 1 ? " needs work" : " need work") }
|
|
1833
1860
|
: { complete: evidenceItems.length > 0, label: evidenceItems.length ? "Ready" : "Not configured", countsTowardProgress: evidenceItems.length > 0 };
|
|
1834
1861
|
}
|
|
1835
1862
|
if (destination.utility === "retention-schedule") {
|
|
1836
1863
|
const incomplete = retentionSchedulePageItems().length;
|
|
1837
1864
|
return !incomplete
|
|
1838
1865
|
? { complete: true, label: "Approved" }
|
|
1839
|
-
: { complete: false, label: incomplete ? incomplete + " " + pluralize("item", incomplete) + " need work" : "Approval needed" };
|
|
1866
|
+
: { complete: false, label: incomplete ? incomplete + " " + pluralize("item", incomplete) + (incomplete === 1 ? " needs work" : " need work") : "Approval needed" };
|
|
1840
1867
|
}
|
|
1841
1868
|
const items = stagePageItems(stage, destination);
|
|
1842
1869
|
const deferredStates = new Set(["later", "scheduled", "upcoming", "waiting-external"]);
|
|
@@ -1855,6 +1882,11 @@ function derivedStagePageState(stage, destination) {
|
|
|
1855
1882
|
? { complete: true, label: "Reviewed" }
|
|
1856
1883
|
: { complete: false, label: "Review scope" };
|
|
1857
1884
|
}
|
|
1885
|
+
if (stage.id === "audit" && destination.type === "document" && destination.href.includes("documentScope=audit")) {
|
|
1886
|
+
if (!resourcesOfType("document").some(({ record }) => auditSpecificDocument(record))) {
|
|
1887
|
+
return { complete: false, countsTowardProgress: false, label: "Only if needed" };
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1858
1890
|
if (destination.type && resourcesOfType(destination.type).length === 0) {
|
|
1859
1891
|
return { complete: false, countsTowardProgress: false, label: "Only if needed" };
|
|
1860
1892
|
}
|
|
@@ -2005,7 +2037,7 @@ function sectionDestinations(section) {
|
|
|
2005
2037
|
destinations.push({ type, kind: "Record page", label: titleCase(definition.pluralTitle), href: "#/resources/" + encodeURIComponent(type), description: definition.description });
|
|
2006
2038
|
}
|
|
2007
2039
|
for (const link of section.relatedLinks || []) {
|
|
2008
|
-
destinations.push({ type: link.type, kind: "Record page", label: link.label, href: link.href, description: section.description });
|
|
2040
|
+
destinations.push({ type: link.type, kind: "Record page", label: link.label, href: link.href, description: link.summary || section.description });
|
|
2009
2041
|
}
|
|
2010
2042
|
if (section.utility === "obligation-board") destinations.push({ utility: section.utility, kind: "Working page", label: "Work Queue", href: "#/stage/run", description: "Complete recurring work, Policy Event tasks, and assigned follow-up with its due windows and linked proof." });
|
|
2011
2043
|
if (section.utility === "evidence-sources") destinations.push({ utility: section.utility, kind: "Coverage page", label: "Evidence Sources", href: "#/evidence-sources", description: section.description });
|
|
@@ -2083,6 +2115,7 @@ function renderObligations(main, params = new URLSearchParams()) {
|
|
|
2083
2115
|
: "";
|
|
2084
2116
|
main.innerHTML = '<div class="page obligation-board-page stage-overview-page"><nav class="breadcrumbs"><a href="#/">Overview</a><span>/</span><span>' + esc(stage.title) + '</span></nav>' +
|
|
2085
2117
|
'<section class="stage-overview-hero"><div><p class="kicker">Step ' + esc(stage.number) + ' of 5</p><h2>' + esc(stage.title) + '</h2><p>' + esc(stage.summary) + '</p></div>' + stageProgressCard(stageProgress(stage)) + '</section>' +
|
|
2118
|
+
renderStageInstructions(stage) +
|
|
2086
2119
|
feedback +
|
|
2087
2120
|
operationGate +
|
|
2088
2121
|
activeOperation +
|
|
@@ -2744,6 +2777,13 @@ function openNextAuditCycleDialog(prior) {
|
|
|
2744
2777
|
});
|
|
2745
2778
|
}
|
|
2746
2779
|
|
|
2780
|
+
function controlApplicabilityPending(record) {
|
|
2781
|
+
if (!record.applicabilityReview) return true;
|
|
2782
|
+
const item = state.programReadiness?.stages?.find(({ id }) => id === "controls")?.items
|
|
2783
|
+
.find(({ resourceType, resourceId }) => resourceType === "control" && resourceId === record.id);
|
|
2784
|
+
return item?.checks?.applicability === false;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2747
2787
|
function openApplicabilityReviewDialog(type, entries) {
|
|
2748
2788
|
const definition = state.model.resources[type];
|
|
2749
2789
|
const reviewPoints = definition?.guidance?.reviewPoints || [];
|
|
@@ -2752,8 +2792,9 @@ function openApplicabilityReviewDialog(type, entries) {
|
|
|
2752
2792
|
const pending = entries.filter(({ record }) => (
|
|
2753
2793
|
type === "requirement" && modelSupports("program-scope")
|
|
2754
2794
|
? !reviewedRequirements.has(record.id)
|
|
2755
|
-
:
|
|
2756
|
-
|
|
2795
|
+
: type === "control"
|
|
2796
|
+
? controlApplicabilityPending(record)
|
|
2797
|
+
: !record.applicabilityReview || type === "requirement" && record.applicability === "undetermined"
|
|
2757
2798
|
));
|
|
2758
2799
|
const dialog = document.createElement("dialog");
|
|
2759
2800
|
dialog.className = "commit-dialog applicability-dialog";
|
|
@@ -3102,7 +3143,9 @@ function renderList(main, type, params = new URLSearchParams()) {
|
|
|
3102
3143
|
const hasPendingApplicability = entries.some(({ record }) => (
|
|
3103
3144
|
type === "requirement" && modelSupports("program-scope")
|
|
3104
3145
|
? !reviewedRequirements.has(record.id)
|
|
3105
|
-
:
|
|
3146
|
+
: type === "control"
|
|
3147
|
+
? controlApplicabilityPending(record)
|
|
3148
|
+
: !record.applicabilityReview || type === "requirement" && record.applicability === "undetermined"
|
|
3106
3149
|
));
|
|
3107
3150
|
const applicabilityButton = !state.readOnly
|
|
3108
3151
|
&& ["requirement", "control", "commitment", "complementary-control"].includes(type)
|
|
@@ -3112,8 +3155,11 @@ function renderList(main, type, params = new URLSearchParams()) {
|
|
|
3112
3155
|
const guideTrigger = '<button class="guide-trigger" id="resource-guide-trigger" type="button" aria-label="About ' + esc(definition.pluralTitle) + '" aria-haspopup="dialog" aria-controls="resource-guide" aria-expanded="false"><svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="8"></circle><path d="M7.8 7.5a2.4 2.4 0 1 1 3.25 2.25c-.7.31-1.05.72-1.05 1.5v.25M10 14.5v.1"></path></svg></button>';
|
|
3113
3156
|
const listTools = '<div class="list-tools list-header-tools"><label><span class="sr-only">Filter list</span><input id="list-search" type="search" placeholder="Filter ' + esc(definition.pluralTitle.toLowerCase()) + '"></label>' +
|
|
3114
3157
|
filters.map(({ name, label, values }) => '<select class="field-filter" data-field="' + esc(name) + '" aria-label="Filter by ' + esc(label.toLowerCase()) + '"><option value="">Any ' + esc(properCase(label)) + '</option>' + values.map((value) => '<option value="' + esc(value) + '">' + esc(filterOptionLabel(value)) + '</option>').join("") + '</select>').join("") + '<span id="result-count" aria-live="polite">' + entries.length + ' records</span>' + applicabilityButton + createButton + '</div>';
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3158
|
+
const relatedGuidance = type === "document" && documentScope === "audit"
|
|
3159
|
+
? listStage?.sections.flatMap((section) => section.relatedLinks || []).find((link) => link.type === "document" && link.instructions)
|
|
3160
|
+
: null;
|
|
3161
|
+
const pageSummary = relatedGuidance?.summary || STAGE_PAGE_SUMMARIES[type] || definition.description;
|
|
3162
|
+
main.innerHTML = '<div class="page"><div class="page-intro"><div><p class="kicker">' + esc(listStage?.title || groupTitle(definition.group)) + '</p><div class="page-title-line"><h2>' + esc(titleCase(listTitle)) + '</h2>' + guideTrigger + '</div><p>' + esc(pageSummary) + '</p></div>' + listTools + '</div>' + resourceGuide(type, relatedGuidance) +
|
|
3117
3163
|
collectionReviewPanel(type) +
|
|
3118
3164
|
'<section class="record-table-wrap"><table class="record-table"><thead><tr><th>' + esc(fieldLabel(type, "title")) + '</th>' + fields.map((name) => '<th>' + esc(fieldLabel(type, name)) + '</th>').join("") + '<th>Next action</th><th>Git file</th></tr></thead><tbody id="record-rows"></tbody></table></section>' +
|
|
3119
3165
|
'<nav class="pagination list-pagination" aria-label="' + esc(definition.pluralTitle) + ' pages" hidden><button class="button" type="button" data-page="previous">Previous</button><span class="page-status" aria-live="polite"></span><button class="button" type="button" data-page="next">Next</button></nav></div>';
|
|
@@ -3191,6 +3237,7 @@ function renderList(main, type, params = new URLSearchParams()) {
|
|
|
3191
3237
|
...(params.get("title") ? { title: params.get("title") } : {}),
|
|
3192
3238
|
...(params.get("documentKind") ? { documentKind: params.get("documentKind") } : {}),
|
|
3193
3239
|
...(documentScope ? { workflowScope: documentScope } : {}),
|
|
3240
|
+
...(params.get("programRole") ? { programRole: params.get("programRole") } : {}),
|
|
3194
3241
|
...relationshipSeed
|
|
3195
3242
|
} : {
|
|
3196
3243
|
...(params.get("title") ? { title: params.get("title") } : {}),
|
|
@@ -3316,7 +3363,7 @@ function renderDetail(main, type, id, params = new URLSearchParams()) {
|
|
|
3316
3363
|
});
|
|
3317
3364
|
const mayDelete = !state.readOnly && !routeSetLocked && !definition.singleton;
|
|
3318
3365
|
const recordMenu = '<details class="record-overflow"><summary aria-label="More record actions" title="More record actions"><svg viewBox="0 0 18 4" aria-hidden="true"><circle cx="2" cy="2" r="2"></circle><circle cx="9" cy="2" r="2"></circle><circle cx="16" cy="2" r="2"></circle></svg></summary><div class="record-overflow-menu" aria-label="Record actions"><button type="button" data-record-modal="info">Record info</button><button type="button" data-record-modal="connections">Connections</button><button type="button" data-record-modal="history"' + (entry.historyLoaded === false ? ' disabled' : '') + '>File history' + (entry.historyLoaded === false ? ' (loading)' : '') + '</button>' + (mayDelete ? '<div class="record-overflow-separator"></div><button class="danger-text" type="button" data-delete-resource>Delete record</button>' : '') + '</div></details>';
|
|
3319
|
-
main.innerHTML = '<div class="page"><div class="detail-head"><div><div class="breadcrumbs header-breadcrumbs"><a href="' + collectionHref + '">' + esc(collectionLabel) + '</a><span>/</span><span>' + esc(entry.record.title) + '</span></div><h2>' + esc(titleCase(entry.record.title)) + '</h2></div><div class="actions">' + reportingRouteSetActions + auditCycleAction + auditPopulationCorrectionAction + (type === "audit" ? '<a class="button primary" href="#/audit-packet?auditId=' + encodeURIComponent(entry.record.id) + '">Audit Evidence & Packet</a>' : "") + governanceActions + lifecycleActions + issueActions + addRecordContentAction + (!state.readOnly && !routeSetLocked ? '<button class="button" id="edit-resource">Edit</button>' : "") + recordMenu + '</div></div><div class="detail-grid ' + (hasRecordBody ? "" : "detail-grid-structured") + '">' + detailMain + supportPanels + '</div></div>';
|
|
3366
|
+
main.innerHTML = '<div class="page"><div class="detail-head"><div><div class="breadcrumbs header-breadcrumbs"><a href="' + collectionHref + '">' + esc(collectionLabel) + '</a><span>/</span><span>' + esc(entry.record.title) + '</span></div><h2>' + esc(titleCase(entry.record.title)) + '</h2></div><div class="actions">' + reportingRouteSetActions + auditCycleAction + auditPopulationCorrectionAction + (type === "audit" ? '<a class="button primary" href="#/audit-packet?auditId=' + encodeURIComponent(entry.record.id) + '">Audit Evidence & Packet</a>' : "") + governanceActions + lifecycleActions + issueActions + addRecordContentAction + (!state.readOnly && !routeSetLocked ? '<button class="button" id="edit-resource">Edit</button>' : "") + recordMenu + '</div></div><div class="detail-grid ' + (hasRecordBody ? "" : "detail-grid-structured") + (type === "control" ? " detail-control" : "") + '">' + detailMain + supportPanels + '</div></div>';
|
|
3320
3367
|
main.querySelectorAll("[data-completion-requirements]").forEach((button) => button.addEventListener("click", () => openCompletionRequirementsDialog(button.dataset.completionRequirements)));
|
|
3321
3368
|
main.querySelector("#edit-resource")?.addEventListener("click", () => openEditor(type, entry));
|
|
3322
3369
|
main.querySelectorAll("[data-record-modal]").forEach((button) => button.addEventListener("click", () => {
|
|
@@ -4251,11 +4298,11 @@ function zonedTimestampFromLocal(value, timezone) {
|
|
|
4251
4298
|
return value + offset;
|
|
4252
4299
|
}
|
|
4253
4300
|
|
|
4254
|
-
function resourceGuide(type) {
|
|
4301
|
+
function resourceGuide(type, pageGuidance = null) {
|
|
4255
4302
|
const definition = state.model.resources[type];
|
|
4256
4303
|
const guidance = definition?.guidance;
|
|
4257
4304
|
if (!definition || !guidance) return "";
|
|
4258
|
-
const instructions = RESOURCE_GUIDE_INSTRUCTIONS[type] || definition.description;
|
|
4305
|
+
const instructions = pageGuidance?.instructions || RESOURCE_GUIDE_INSTRUCTIONS[type] || definition.description;
|
|
4259
4306
|
const sources = (guidance.sourceResourceIds || [])
|
|
4260
4307
|
.map((id) => state.resources.find(({ record }) => record.id === id))
|
|
4261
4308
|
.filter(Boolean);
|
|
@@ -4266,7 +4313,8 @@ function resourceGuide(type) {
|
|
|
4266
4313
|
const reviewGuide = reviewPoints.length
|
|
4267
4314
|
? '<div class="guide-review"><span>When reviewing</span><ul>' + reviewPoints.map((point) => '<li>' + esc(point) + '</li>').join("") + '</ul></div>'
|
|
4268
4315
|
: "";
|
|
4269
|
-
|
|
4316
|
+
const output = pageGuidance?.output || RESOURCE_GUIDE_OUTPUTS[type] || 'A validated ' + definition.title + ' record.';
|
|
4317
|
+
return '<section class="page-guide resource-guide-popover" id="resource-guide" role="dialog" aria-label="How to use ' + esc(definition.pluralTitle) + '" hidden><div><span>Do now</span><p>' + esc(instructions) + '</p></div><div><span>Output</span><p>' + esc(output) + '</p></div><div><span>Policy basis</span><p>' + esc(guidance.policyBasis) + '</p>' + sourceLinks + '</div>' + reviewGuide + '</section>';
|
|
4270
4318
|
}
|
|
4271
4319
|
|
|
4272
4320
|
function setupResourceGuide(main) {
|
|
@@ -6486,6 +6534,7 @@ html,body{height:100%;overflow:hidden}.shell{grid-template-columns:248px minmax(
|
|
|
6486
6534
|
.brand{flex:0 0 auto;margin-bottom:18px}.sidebar-nav{--nav-control-width:14px;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;padding-right:1px}.nav-home{margin-bottom:10px}.nav-stage>.nav-heading{display:grid;grid-template-columns:24px minmax(0,1fr) var(--nav-control-width);gap:6px;align-items:center;padding:7px 6px;border-radius:7px;color:#d5d9ed;text-align:left;text-transform:none;letter-spacing:0}.nav-stage>.nav-heading:hover{background:rgba(255,255,255,.08);color:#fff}.nav-stage-number{display:grid;place-items:center;width:22px;height:22px;border:1px solid rgba(255,255,255,.26);border-radius:50%;font-size:9.6px}.nav-stage-copy,.nav-stage-copy strong,.nav-stage-copy small{display:block;min-width:0}.nav-stage-copy strong{font-size:12px;line-height:1.25}.nav-stage-copy small{margin-top:2px;color:#aeb6d8;font-size:9.6px;line-height:1.25;font-weight:500}.nav-stage>.nav-items{margin:2px 0 8px 17px;padding:1px 0 5px 12px;border-left:1px solid rgba(255,255,255,.14)}.nav-subgroup>.nav-subheading,.nav-subgroup>.nav-items a{width:100%;display:grid;grid-template-columns:minmax(0,1fr) var(--nav-control-width);gap:6px;align-items:center;padding-right:6px}.nav-subgroup>.nav-subheading{border:0;background:none;padding-top:7px;padding-bottom:4px;padding-left:7px;color:#919bc4;text-align:left;text-transform:uppercase;letter-spacing:.09em;font-size:9.6px;font-weight:780;cursor:pointer}.nav-control,.nav-control-slot{justify-self:end;width:var(--nav-control-width);text-align:right}.nav-subgroup>.nav-items{padding:1px 0 4px 3px}.nav-subgroup>.nav-items a{padding-top:6px;padding-bottom:6px;padding-left:8px;font-size:13.2px}.nav-group.open>.nav-heading>.chevron:before,.nav-group.open>.nav-subheading>.chevron:before{transform:rotate(45deg)}.nav-stage.open>.nav-items>.nav-subgroup:not(.open)>.nav-items{display:none}.sidebar-footer{flex:0 0 auto;margin:10px -18px -18px;padding:10px 18px 14px;background:#000024;border-top:1px solid rgba(255,255,255,.14)}.organization-nav{display:grid;grid-template-columns:32px minmax(0,1fr) 12px;gap:9px;align-items:center;padding:8px;border-radius:8px;color:#eef1ff;text-decoration:none}.organization-nav:hover,.organization-nav.current{background:rgba(255,255,255,.11)}.organization-mark{display:grid;place-items:center;width:32px;height:32px;border:1px solid rgba(255,255,255,.25);border-radius:50%;background:rgba(255,255,255,.08);font-size:13.2px;font-weight:800}.organization-nav strong,.organization-nav small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.organization-nav strong{font-size:12px}.organization-nav small{margin-top:2px;color:#aeb6d8;font-size:9.6px}.organization-arrow{color:#aeb6d8;font-size:19.2px}.organization-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.organization-links{display:grid}.organization-links a{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 0;border-top:1px solid var(--line);text-decoration:none}.organization-links a:first-child{padding-top:0;border-top:0}.organization-links strong,.organization-links small{display:block}.organization-links strong{font-size:13.2px}.organization-links small{margin-top:3px;color:var(--muted);font-size:10.8px;line-height:1.4}.organization-links b{color:var(--accent);font-size:13.2px}.organization-links a:hover strong{color:var(--accent)}
|
|
6487
6535
|
.nav-stage>.nav-items>a.nav-direct{display:grid;grid-template-columns:minmax(0,1fr) var(--nav-control-width);gap:6px;align-items:center;width:100%;padding:6px 6px 6px 7px;font-size:13.2px}
|
|
6488
6536
|
.nav-heading-row{display:grid;grid-template-columns:minmax(0,1fr) 24px;gap:2px;align-items:stretch}.nav-heading-row>.nav-heading{display:grid;grid-template-columns:24px minmax(0,1fr);gap:6px;align-items:center;width:100%;padding:7px 6px;border-radius:7px;color:#d5d9ed;text-align:left;text-transform:none;letter-spacing:0;text-decoration:none}.nav-heading-row>.nav-heading:hover,.nav-heading-row>.nav-heading.current{background:rgba(255,255,255,.1);color:#fff}.nav-toggle{display:grid;place-items:center;width:24px;height:auto;min-height:100%;padding:0;border:0;border-radius:6px;background:none;color:#aeb6d8;cursor:pointer}.nav-toggle:hover{background:rgba(255,255,255,.1);color:#fff}.nav-chevron{display:block;width:12px;height:12px;place-self:center;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;transition:transform .15s}.nav-subheading-row{display:grid;grid-template-columns:minmax(0,1fr) 22px;gap:2px;align-items:center;width:100%;padding:0;border:0;border-radius:6px;background:none;color:#919bc4;cursor:pointer}.nav-subheading-row:hover{background:rgba(255,255,255,.1);color:#fff}.nav-subheading-row>.nav-subheading{display:flex;align-items:center;min-width:0;padding:7px;color:inherit;text-align:left;text-transform:uppercase;letter-spacing:.09em;font-size:9.6px;font-weight:780}.nav-group.open>.nav-heading-row .nav-chevron,.nav-group.open>.nav-subheading-row .nav-chevron{transform:rotate(90deg)}
|
|
6537
|
+
.stage-instructions{margin-top:14px;padding:0 18px;background:var(--panel);border:1px solid var(--line);border-radius:10px}.stage-instructions>summary{padding:14px 0;cursor:pointer;font-size:12px;font-weight:700}.stage-instructions-body{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:18px;padding:2px 0 18px}.stage-instructions h3{margin:0 0 7px;font-size:12px}.stage-instructions ol{margin:0;padding-left:20px}.stage-instructions li{margin:0 0 6px;color:var(--muted);font-size:11px;line-height:1.5}
|
|
6489
6538
|
.stage-overview-hero{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:28px;align-items:center;padding:26px 28px;background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow)}.stage-overview-hero h2,.group-overview-head h2{font:500 37.2px Georgia,serif;margin:7px 0}.stage-overview-hero>div>p:not(.kicker),.group-overview-head>div>p:not(.kicker){max-width:760px;color:var(--muted);font-size:14.4px;line-height:1.55;margin:0}.stage-progress-card{padding:15px 17px;background:var(--paper);border:1px solid var(--line);border-radius:9px}.stage-progress-card>div:first-child{display:flex;align-items:center;justify-content:space-between;margin-bottom:11px}.stage-progress-card>div:first-child>strong{font:500 33.6px Georgia,serif}.stage-progress-card p{color:var(--muted);font-size:10.8px;line-height:1.45;margin:9px 0 0}.badge.neutral{background:#e5e8f2;color:#555e73}.stage-overview-layout{display:grid;grid-template-columns:320px minmax(0,1fr);gap:15px;margin-top:15px;align-items:start}.stage-plan ol,.group-plan ol{display:grid;gap:12px;padding-left:20px;margin:0}.stage-plan li,.group-plan li{padding-left:4px;color:var(--ink);font-size:13.2px;line-height:1.5}.stage-groups{min-width:0}.stage-groups>.section-head{margin:4px 0 13px}.stage-group-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.stage-group-card{position:relative;display:block;min-height:138px;padding:18px 38px 17px 18px;background:var(--panel);border:1px solid var(--line);border-radius:10px;text-decoration:none;box-shadow:0 2px 8px rgba(21,40,33,.025)}.stage-group-card:hover{border-color:var(--accent-light)}.stage-group-card h3{font-size:15.6px;margin:0 0 7px}.stage-group-card p{color:var(--muted);font-size:12px;line-height:1.5;margin:0}.stage-group-card small{display:block;color:var(--accent);font-size:9.6px;font-weight:700;margin-top:12px}.stage-group-arrow{position:absolute;right:16px;top:16px;color:var(--accent);font-size:24px}.group-overview-head{display:flex;justify-content:space-between;align-items:end;gap:25px;margin-bottom:15px}.stage-status-link{display:grid;grid-template-columns:auto auto;align-items:center;gap:4px 12px;min-width:155px;padding:12px 14px;background:var(--panel);border:1px solid var(--line);border-radius:9px;text-decoration:none}.stage-status-link>strong{font:500 28.8px Georgia,serif;text-align:right}.stage-status-link>small{grid-column:1/-1;color:var(--muted);font-size:9.6px;text-align:right}.relationship-note{display:grid;grid-template-columns:250px minmax(0,1fr);gap:20px;align-items:center;margin-bottom:15px;padding:17px 20px;background:var(--accent-soft);border:1px solid #cbd3ff;border-radius:10px}.relationship-note h3{font-size:15.6px;margin:5px 0 0}.relationship-note>p{color:var(--muted);font-size:12px;line-height:1.55;margin:0}.relationship-note code{font-size:10.8px}.group-plan{margin-bottom:24px}.group-related-links{display:flex;align-items:center;gap:8px;margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}.group-related-links>span{color:var(--muted);font-size:10.8px;margin-right:auto}.group-destinations>.section-head{margin-bottom:12px}.group-destination-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}.group-destination-card{display:grid;grid-template-columns:minmax(0,1fr) 100px;gap:16px;min-height:150px;padding:18px;background:var(--panel);border:1px solid var(--line);border-radius:10px;text-decoration:none;box-shadow:0 2px 8px rgba(21,40,33,.025)}.group-destination-card:hover{border-color:var(--accent-light)}.group-destination-card h3{font-size:15.6px;margin:5px 0 7px}.group-destination-card p:not(.kicker){color:var(--muted);font-size:10.8px;line-height:1.5;margin:0}.destination-rollup{align-self:center;text-align:right}.destination-rollup strong,.destination-rollup small{display:block}.destination-rollup strong{font:500 32.4px Georgia,serif}.destination-rollup small{color:var(--muted);font-size:9.6px;line-height:1.35;margin-top:3px}
|
|
6490
6539
|
.collection-review-panel{margin:16px 0 22px}.collection-review-panel.required{border-color:#d8bd78}.collection-review-panel.current{border-color:#b9dac6}.collection-review-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px}.collection-review-head h3{margin:4px 0 6px}.collection-review-head p:not(.kicker){max-width:900px;margin:0;color:var(--muted);font-size:11px;line-height:1.5}.collection-review-panel details{margin-top:13px;padding:10px 12px;border:1px solid var(--line);border-radius:7px;background:var(--surface-soft)}.collection-review-panel summary{cursor:pointer;font-size:11px;font-weight:750}.collection-review-panel ul,.collection-review-checks ul{margin:9px 0 0;padding-left:20px;color:var(--muted);font-size:10.4px;line-height:1.55}.collection-review-foot{display:flex;align-items:center;justify-content:space-between;gap:20px;margin-top:13px}.collection-review-result{display:flex;align-items:baseline;gap:8px;margin:0}.collection-review-result strong{font-size:11px}.collection-review-result span{color:var(--muted);font-size:10.4px}.collection-review-checks{margin:13px 0;padding:11px 13px;border:1px solid var(--line);border-radius:7px;background:var(--surface-soft)}.collection-review-checks>strong{font-size:11px}.event-dialog-steps.collection-review-checks{margin:15px 0 0;padding:10px;border:0}.collection-review-dialog textarea{box-sizing:border-box;width:100%;resize:vertical}.review-save-status{margin-right:auto;color:var(--muted);font-size:11px}.resource-review-criteria{margin:16px 0 22px;padding:13px 15px;border:1px solid var(--line);border-radius:8px;background:var(--panel)}.resource-review-criteria>strong{font-size:11px}.resource-review-criteria ul{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 28px;margin:9px 0 0;padding-left:20px;color:var(--muted);font-size:10.4px;line-height:1.5}.commit-dialog .resource-review-criteria{margin:12px 0;background:var(--surface-soft)}.record-workflow-action{display:grid;grid-template-columns:auto minmax(140px,1fr);gap:7px;align-items:start;min-width:240px;text-decoration:none}.record-workflow-action strong,.record-workflow-action small{display:block}.record-workflow-action strong{font-size:10.4px}.record-workflow-action small{margin-top:2px;color:var(--muted);font-size:9.2px;line-height:1.35}.record-workflow-clear{color:var(--muted);font-size:10px;white-space:nowrap}.workflow-guidance{margin:16px 0 22px}.workflow-guidance .panel-head{align-items:flex-start;margin-bottom:12px}.workflow-guidance .panel-head h3{margin:4px 0}.workflow-guidance .panel-head p:not(.kicker){margin:4px 0 0;color:var(--muted);font-size:11px}.workflow-findings{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.workflow-findings>a,.workflow-findings>div{display:grid;grid-template-columns:auto minmax(0,1fr);gap:9px;align-items:start;padding:10px 11px;border:1px solid var(--line);border-radius:7px;background:var(--surface-soft);text-decoration:none}.workflow-findings strong,.workflow-findings small{display:block}.workflow-findings strong{font-size:11px}.workflow-findings small{margin-top:3px;color:var(--muted);font-size:9.6px;line-height:1.4}.workflow-finding-status{min-width:62px;padding:3px 5px;border-radius:99px;background:var(--accent-soft);color:var(--accent);font-size:8.4px;font-weight:750;text-align:center;text-transform:uppercase;letter-spacing:.04em}.workflow-finding-status.overdue,.workflow-finding-status.blocked{background:#f5ded9;color:#8d352c}.workflow-finding-status.ready,.workflow-finding-status.due,.workflow-finding-status.open{background:#f7e9cf;color:#855717}.workflow-finding-status.complete{background:#ddefe5;color:#176143}.workflow-guidance-more{margin:10px 0 0;color:var(--muted);font-size:9.6px}.workflow-guidance-more>summary{cursor:pointer;font-weight:750}.workflow-findings-more{margin-top:9px}.workflow-guidance-more>p{margin:8px 0 0}.context-workflow{display:flex;align-items:center;justify-content:space-between;gap:24px;margin:-8px 0 18px;padding:17px 19px;background:var(--accent-soft);border:1px solid #cbd3ff;border-radius:10px}.context-workflow h3{font-size:16px;margin:4px 0 5px}.context-workflow p:not(.kicker){color:var(--muted);font-size:12px;line-height:1.5;margin:0;max-width:850px}.context-workflow .button{white-space:nowrap}.policy-lifecycle-note{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(260px,1fr);gap:24px;margin-top:18px}.policy-lifecycle-note h3{margin:5px 0 8px}.policy-lifecycle-note p:not(.kicker),.policy-library-proposals p{color:var(--muted);font-size:11px;line-height:1.55}.policy-library-proposals{display:grid;gap:8px}.policy-library-proposals article{padding:11px;border:1px solid var(--line);border-radius:8px;background:var(--surface-soft)}.policy-library-proposals p{margin:5px 0 8px}.policy-activation{display:grid;gap:12px;margin-top:22px}.policy-activation-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.policy-activation-card{padding:17px 18px;border:1px solid #d8bd78;border-radius:10px;background:var(--panel)}.policy-activation-card.active-and-operating{border-color:#b9dac6}.policy-activation-card h3{margin:7px 0 0}.policy-activation-gaps{display:grid;gap:9px;margin-top:13px}.policy-activation-gaps>div{padding-top:8px;border-top:1px solid var(--line)}.policy-activation-gaps small{display:block;margin-bottom:6px;color:var(--muted);font-size:9.6px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}.policy-activation-warning{margin:11px 0 0;padding:9px 10px;border-radius:7px;background:#f7e9cf;color:#6d4917;font-size:10.4px;line-height:1.45}.evidence-map{display:grid;gap:12px;margin-top:18px}.evidence-map-head{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px 22px;background:var(--accent-soft);border:1px solid #cbd3ff;border-radius:11px}.evidence-map-head>div:first-child{max-width:760px}.evidence-map-head h2{font:500 24px Georgia,serif;margin:5px 0 7px}.evidence-map-head p:not(.kicker){color:var(--muted);font-size:12px;line-height:1.55;margin:0}.evidence-map-actions{display:flex;gap:8px}.evidence-map-card{padding:18px 20px;background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:0 2px 8px rgba(21,40,33,.025)}.evidence-map-card.complete{border-color:#b9dac6}.evidence-map-card-head{display:flex;align-items:start;justify-content:space-between;gap:20px}.evidence-map-card-head h3{font-size:16px;margin:7px 0 0}.evidence-map-card-head>small{color:var(--muted);font-size:10px;text-align:right}.evidence-map-card>p{color:var(--muted);font-size:12px;line-height:1.55;margin:12px 0}.evidence-map-expectation{display:grid;grid-template-columns:120px minmax(0,1fr);gap:12px;padding:8px 0;border-top:1px solid var(--line);font-size:11px;line-height:1.5}.evidence-map-expectation strong{color:var(--muted);font-size:9.6px;text-transform:uppercase;letter-spacing:.06em}.evidence-map-expectation code{background:var(--paper);border-radius:4px;padding:2px 5px}.evidence-map-links{display:grid;grid-template-columns:minmax(220px,1fr) minmax(280px,1.2fr);gap:20px;margin-top:13px;padding-top:13px;border-top:1px solid var(--line)}.evidence-map-links>div>small{display:block;color:var(--muted);font-size:9.6px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;margin-bottom:7px}.evidence-map-references,.evidence-map-sources{display:flex;flex-wrap:wrap;gap:5px}.evidence-map-source{display:flex;align-items:center;gap:7px;padding:7px 9px;background:var(--paper);border:1px solid var(--line);border-radius:7px;font-size:11px;text-decoration:none}.evidence-map-source.complete{border-color:#b9dac6;background:#edf7f1}.evidence-map-source small{color:var(--muted);font-size:9px}.evidence-map-status{padding:9px 11px;background:var(--paper);border-radius:7px}.evidence-map-empty{padding:24px;background:var(--panel);border:1px solid var(--line);border-radius:10px}.evidence-map-empty h3{margin:6px 0}.evidence-map-empty p:not(.kicker){color:var(--muted);font-size:12px;margin:0 0 14px}.stage-pages{margin-top:24px}.stage-page-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.stage-page-card{position:relative;display:flex;flex-direction:column;min-width:0;padding:18px;background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:0 2px 8px rgba(21,40,33,.025);transition:border-color .15s,box-shadow .15s}.stage-page-card:hover{border-color:var(--accent-light);box-shadow:0 5px 16px rgba(21,40,33,.07)}.stage-page-card.complete{border-color:#b9dac6}.stage-page-card-head{display:flex;align-items:center;justify-content:space-between;gap:18px}.stage-page-card-head h3{font-size:15.6px;line-height:1.35;margin:4px 0 0}.stage-page-card-head>div>small{display:block;color:var(--accent);font-size:9.6px;font-weight:700}.stage-page-card>p{color:var(--muted);font-size:12px;line-height:1.5;margin:13px 0 0}.stage-page-tasks{position:relative;z-index:2;display:grid;gap:6px;margin-top:13px}.stage-page-tasks>a{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;align-items:start;padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--surface-soft);text-decoration:none}.stage-page-tasks>a:hover{border-color:var(--accent-light)}.stage-page-tasks strong,.stage-page-tasks small{display:block}.stage-page-tasks strong{font-size:10.8px}.stage-page-tasks small{margin-top:2px;color:var(--muted);font-size:9.4px;line-height:1.35}.stage-page-tasks-more{color:var(--muted);font-size:9.4px}.stage-page-rollup{display:flex;flex:0 0 104px;flex-direction:column;justify-content:center;text-align:right}.stage-page-rollup strong,.stage-page-rollup small{display:block}.stage-page-rollup strong{font:500 24px Georgia,serif}.stage-page-rollup small{color:var(--muted);font-size:9.6px;line-height:1.35;margin-top:2px}.stage-page-card-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:auto;padding-top:15px}.stage-page-completion-state{color:var(--muted);font-size:10.8px}.stage-page-completion-state.complete{color:#176143;font-weight:700}.stage-page-open{color:var(--accent);font-size:12px;font-weight:700}.work-queue-section{margin-top:28px}.work-queue-section>.section-head{align-items:end}
|
|
6491
6540
|
.stage-page-card-actions{display:flex;align-items:center;gap:10px}.stage-page-card-actions .stage-page-open{white-space:nowrap}.stage-page-open::after{content:"";position:absolute;inset:0;z-index:1;border-radius:10px}.stage-page-open:focus-visible::after{outline:2px solid var(--focus);outline-offset:2px}.stage-page-open>span{position:relative;z-index:2}
|
|
@@ -6669,6 +6718,7 @@ dialog::backdrop{background:rgba(0,0,24,.62)}
|
|
|
6669
6718
|
@media(max-width:760px){.record-table td:has(.relation){min-width:0}.record-table td[data-label]>.relation{grid-column:2}}
|
|
6670
6719
|
@media(max-width:760px){.diagnostics>div{grid-template-columns:max-content minmax(0,1fr)}}
|
|
6671
6720
|
.workflow-guidance .workflow-status{margin:4px 0 12px;color:var(--muted);font-size:10px}.workflow-completion-requirements{display:inline;appearance:none;-webkit-appearance:none;white-space:nowrap;padding:0;border:0;background:none;color:var(--accent);font:inherit;font-weight:750;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.workflow-completion-requirements:focus-visible{outline:2px solid var(--focus);outline-offset:2px}.completion-requirements-dialog ul{margin:14px 0 0;padding-left:20px;color:var(--muted);font-size:12px;line-height:1.55}
|
|
6721
|
+
.control-next-steps{margin:8px 0 9px;padding-left:18px;font-size:12px;line-height:1.5}.control-next-steps li+li{margin-top:7px}.detail-control aside .detail-workflow-panel{max-height:none;overflow:visible}
|
|
6672
6722
|
.record-completion-state{background:var(--surface-soft)}.record-completion-state h3{margin:4px 0 5px;font-size:16.8px}.record-completion-state p:last-child{margin:0;color:var(--muted);font-size:11px;line-height:1.45}
|
|
6673
6723
|
`;
|
|
6674
6724
|
|
package/src/workflow.js
CHANGED
|
@@ -1128,6 +1128,7 @@ function normalizeFinding(code, item, context) {
|
|
|
1128
1128
|
severity: findingSeverity(state, context.assessment),
|
|
1129
1129
|
title: item.title,
|
|
1130
1130
|
message: item.message,
|
|
1131
|
+
...(item.nextSteps?.length ? { nextSteps: item.nextSteps } : {}),
|
|
1131
1132
|
...(item.resourceId ? { resourceId: item.resourceId } : {}),
|
|
1132
1133
|
...(item.createResourceType ? { createResourceType: item.createResourceType } : {}),
|
|
1133
1134
|
...(item.sourceResourceIds ? { sourceResourceIds: item.sourceResourceIds } : {}),
|