diff --git a/lang/de.json b/lang/de.json
index d33fbb4..7a2f10d 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -76,6 +76,11 @@
"Target": "Ziel",
"Source": "Quelle"
},
+ "Table": {
+ "Severity": "Stufe",
+ "References": "Refs",
+ "Note": "Hinweis"
+ },
"FindingKind": {
"non-package-to-package-reference": "Unverankerte Paketziele",
"broken-reference": "Kaputte Ziele",
diff --git a/lang/en.json b/lang/en.json
index 1a3d4ca..bc6837c 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -76,6 +76,11 @@
"Target": "Target",
"Source": "Source"
},
+ "Table": {
+ "Severity": "Severity",
+ "References": "Refs",
+ "Note": "Note"
+ },
"FindingKind": {
"non-package-to-package-reference": "Unanchored package targets",
"broken-reference": "Broken targets",
diff --git a/module.json b/module.json
index 898dde7..d640605 100644
--- a/module.json
+++ b/module.json
@@ -2,7 +2,7 @@
"id": "kosmos-storage-audit",
"title": "Kosmos Storage Audit",
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
- "version": "0.0.16",
+ "version": "0.0.17",
"compatibility": {
"minimum": "13",
"verified": "13"
diff --git a/scripts/apps/audit-report-app.js b/scripts/apps/audit-report-app.js
index 9a14d00..a7b3c5c 100644
--- a/scripts/apps/audit-report-app.js
+++ b/scripts/apps/audit-report-app.js
@@ -267,23 +267,11 @@ function renderGroupedFindingList(groupedFindings, hasAnalysis, loading, showAll
sections.push(renderGroupedSection(
localize("KSA.Section.UnanchoredPackageTargets"),
localize("KSA.Section.UnanchoredPackageTargetsDesc"),
- groupedFindings.nonPackageToPackage,
- group => `
-
-
- ${severityLabel(group.severity)}
- ${formatCount(group.count, "KSA.Summary.References")}
-
- ${escapeHtml(group.target)}
- ${escapeHtml(group.shortReason)}
-
- - ${localize("KSA.Field.OwnerPackage")}
${escapeHtml(group.ownerLabel)}
- ${localize("KSA.Field.Assessment")}${escapeHtml(group.explanation)}
-
- ${escapeHtml(group.recommendation)}
- ${renderSampleSources(group.sources)}
-
- `
+ renderGroupedTable(groupedFindings.nonPackageToPackage, {
+ includeOwner: true,
+ includeReason: true,
+ includeSources: true
+ })
));
}
@@ -291,20 +279,11 @@ function renderGroupedFindingList(groupedFindings, hasAnalysis, loading, showAll
sections.push(renderGroupedSection(
localize("KSA.Section.BrokenTargets"),
localize("KSA.Section.BrokenTargetsDesc"),
- groupedFindings.brokenReferences,
- group => `
-
-
- ${severityLabel(group.severity)}
- ${formatCount(group.count, "KSA.Summary.References")}
-
- ${escapeHtml(group.target)}
- ${escapeHtml(group.shortReason)}
- ${group.targetKind === "wildcard" ? `${localize("KSA.Finding.WildcardNoMatch")}
` : ""}
- ${escapeHtml(group.recommendation)}
- ${renderSampleSources(group.sources)}
-
- `
+ renderGroupedTable(groupedFindings.brokenReferences, {
+ includeOwner: false,
+ includeReason: true,
+ includeSources: true
+ })
));
}
@@ -312,18 +291,11 @@ function renderGroupedFindingList(groupedFindings, hasAnalysis, loading, showAll
sections.push(renderGroupedSection(
localize("KSA.Section.OrphanCandidates"),
localize("KSA.Section.OrphanCandidatesDesc"),
- groupedFindings.orphans,
- group => `
-
-
- ${severityLabel(group.severity)}
- ${humanizeKind(group.kind)}
-
- ${escapeHtml(group.target)}
- ${escapeHtml(group.reason)}
- ${escapeHtml(group.recommendation)}
-
- `
+ renderGroupedTable(groupedFindings.orphans, {
+ includeOwner: false,
+ includeReason: true,
+ includeSources: false
+ })
));
}
@@ -341,19 +313,60 @@ function renderGroupedFindingList(groupedFindings, hasAnalysis, loading, showAll
return ``;
}
-function renderGroupedSection(title, description, groups, renderGroup) {
- const items = groups.map(renderGroup).join("");
+function renderGroupedSection(title, description, content) {
return `
`;
}
+function renderGroupedTable(groups, { includeOwner=false, includeReason=false, includeSources=false }={}) {
+ const headers = [
+ `${localize("KSA.Table.Severity")} | `,
+ `${localize("KSA.Field.Target")} | `,
+ `${localize("KSA.Table.References")} | `
+ ];
+ if (includeOwner) headers.push(`${localize("KSA.Field.OwnerPackage")} | `);
+ if (includeReason) headers.push(`${localize("KSA.Table.Note")} | `);
+ if (includeSources) headers.push(`${localize("KSA.Field.Source")} | `);
+
+ const rows = groups.map(group => {
+ const cells = [
+ `${severityLabel(group.severity)} | `,
+ `${escapeHtml(group.target)} | `,
+ `${group.count ?? ""} | `
+ ];
+ if (includeOwner) cells.push(`${escapeHtml(group.ownerLabel ?? "")} | `);
+ if (includeReason) {
+ const note = group.targetKind === "wildcard"
+ ? `${group.shortReason ?? group.reason ?? ""} ${localize("KSA.Finding.WildcardNoMatch")}`
+ : (group.shortReason ?? group.reason ?? "");
+ cells.push(`${escapeHtml(note.trim())} | `);
+ }
+ if (includeSources) {
+ cells.push(`${renderGroupedSourcesCell(group.sources ?? [])} | `);
+ }
+ return `${cells.join("")}
`;
+ }).join("");
+
+ return `
+
+ ${headers.join("")}
+ ${rows}
+
+ `;
+}
+
+function renderGroupedSourcesCell(sources) {
+ if (!sources.length) return "";
+ return `${sources.map(source => `
${source.renderedSource ?? renderPlainSourceLabel(source)}
`).join("")}
`;
+}
+
function renderFindingList(findings, hasAnalysis, loading, showAll, showRaw) {
if (loading) {
return `${localize("KSA.Section.Running")}
`;
@@ -391,12 +404,6 @@ function renderFindingList(findings, hasAnalysis, loading, showAll, showRaw) {
`;
}
-function renderSampleSources(sources) {
- if (!sources.length) return "";
- const rows = sources.map(source => `${source.renderedSource ?? renderPlainSourceLabel(source)}`).join("");
- return `${localize("KSA.Section.Samples")} `;
-}
-
function groupFindings(findings) {
return {
brokenReferences: groupByTarget(findings.filter(f => f.kind === "broken-reference")),
diff --git a/styles/audit.css b/styles/audit.css
index e3a32cf..357a7f4 100644
--- a/styles/audit.css
+++ b/styles/audit.css
@@ -35,6 +35,11 @@
gap: 1rem;
}
+.storage-audit__table-wrap {
+ padding: 0 1.1rem 1.1rem;
+ overflow-x: auto;
+}
+
.storage-audit__progress {
padding: 1rem 1.1rem;
}
@@ -194,6 +199,42 @@
padding: 1rem;
}
+.storage-audit__table {
+ width: 100%;
+ border-collapse: collapse;
+ table-layout: fixed;
+}
+
+.storage-audit__table th,
+.storage-audit__table td {
+ padding: 0.55rem 0.5rem;
+ vertical-align: top;
+ text-align: left;
+ border-top: 1px solid color-mix(in srgb, currentColor 10%, transparent);
+ overflow-wrap: anywhere;
+}
+
+.storage-audit__table thead th {
+ border-top: 0;
+ opacity: 0.75;
+ font-weight: 700;
+}
+
+.storage-audit__table td:first-child,
+.storage-audit__table th:first-child {
+ width: 7rem;
+}
+
+.storage-audit__table td:nth-child(3),
+.storage-audit__table th:nth-child(3) {
+ width: 7rem;
+}
+
+.storage-audit__source-list {
+ display: grid;
+ gap: 0.35rem;
+}
+
.storage-audit__list--raw h3 {
margin-top: 0;
}
@@ -223,6 +264,10 @@
letter-spacing: 0.04em;
}
+.storage-audit__severity--inline {
+ min-width: 0;
+}
+
.severity-high .storage-audit__severity {
background: color-mix(in srgb, #b03e29 80%, transparent);
color: white;