Release 0.0.5

This commit is contained in:
2026-04-20 21:02:04 +00:00
parent 5e1096ebae
commit f3ed47420b
4 changed files with 28 additions and 19 deletions

View File

@@ -2,7 +2,7 @@
"id": "kosmos-storage-audit", "id": "kosmos-storage-audit",
"title": "Kosmos Storage Audit", "title": "Kosmos Storage Audit",
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.", "description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
"version": "0.0.4", "version": "0.0.5",
"compatibility": { "compatibility": {
"minimum": "13", "minimum": "13",
"verified": "13" "verified": "13"

View File

@@ -26,6 +26,8 @@ function worldCollectionEntries() {
if (!game.world) return []; if (!game.world) return [];
const entries = []; const entries = [];
for (const collection of game.collections ?? []) { for (const collection of game.collections ?? []) {
const collectionDocumentName = collection.documentName ?? null;
if (collectionDocumentName === "ChatMessage") continue;
const docs = Array.from(collection.values?.() ?? []); const docs = Array.from(collection.values?.() ?? []);
for (const doc of docs) { for (const doc of docs) {
entries.push({ entries.push({
@@ -34,7 +36,7 @@ function worldCollectionEntries() {
ownerType: "world", ownerType: "world",
ownerId: game.world.id, ownerId: game.world.id,
systemId: game.world.system, systemId: game.world.system,
subtype: doc.documentName?.toLowerCase() ?? collection.documentName?.toLowerCase() ?? "document" subtype: doc.documentName?.toLowerCase() ?? collectionDocumentName?.toLowerCase() ?? "document"
}, },
sourceLabel: `${doc.documentName ?? "Document"} ${doc.id}`, sourceLabel: `${doc.documentName ?? "Document"} ${doc.id}`,
sourceName: doc.name ?? null, sourceName: doc.name ?? null,

View File

@@ -7,8 +7,7 @@ export class StorageAuditReportApp extends foundry.applications.api.ApplicationV
runAnalysis: StorageAuditReportApp.#onRunAnalysis, runAnalysis: StorageAuditReportApp.#onRunAnalysis,
toggleShowAll: StorageAuditReportApp.#onToggleShowAll, toggleShowAll: StorageAuditReportApp.#onToggleShowAll,
toggleRaw: StorageAuditReportApp.#onToggleRaw, toggleRaw: StorageAuditReportApp.#onToggleRaw,
exportReport: StorageAuditReportApp.#onExportReport, exportReport: StorageAuditReportApp.#onExportReport
openSource: StorageAuditReportApp.#onOpenSource
}, },
window: { window: {
title: "Kosmos Storage Audit", title: "Kosmos Storage Audit",
@@ -88,6 +87,13 @@ export class StorageAuditReportApp extends foundry.applications.api.ApplicationV
_replaceHTML(result, content) { _replaceHTML(result, content) {
content.replaceChildren(result); content.replaceChildren(result);
for (const link of content.querySelectorAll(".content-link[data-uuid]")) {
link.addEventListener("click", event => {
event.preventDefault();
event.stopPropagation();
void openSourceUuid(link.dataset.uuid);
});
}
} }
async runAnalysis() { async runAnalysis() {
@@ -199,20 +205,6 @@ export class StorageAuditReportApp extends foundry.applications.api.ApplicationV
return this.exportReport(); return this.exportReport();
} }
static async #onOpenSource(_event, button) {
const uuid = button?.dataset?.uuid;
if (!uuid) return;
const document = await fromUuid(uuid);
if (document?.sheet) {
document.sheet.render(true, { focus: true });
return;
}
if (document?.parent?.sheet) {
document.parent.sheet.render(true, { focus: true });
return;
}
ui.notifications.warn(format("KSA.Notify.OpenSourceFailed", { uuid }));
}
} }
function renderProgress(progress, loading) { function renderProgress(progress, loading) {
@@ -558,5 +550,19 @@ function renderLocalizedCodeText(key, data, codeValues) {
function renderSourceLink(source) { function renderSourceLink(source) {
const label = source.sourceName ? `${source.sourceLabel} (${source.sourceName})` : source.sourceLabel; const label = source.sourceName ? `${source.sourceLabel} (${source.sourceName})` : source.sourceLabel;
if (!source.sourceUuid) return escapeHtml(label); if (!source.sourceUuid) return escapeHtml(label);
return `<a href="#" data-action="openSource" data-uuid="${escapeHtml(source.sourceUuid)}"><code>${escapeHtml(source.sourceUuid)}</code></a>${label ? ` <span>${escapeHtml(label)}</span>` : ""}`; return `<a class="content-link" draggable="true" data-link data-uuid="${escapeHtml(source.sourceUuid)}" data-tooltip="${escapeHtml(label)}"><i class="fa-solid fa-file-lines"></i><code>${escapeHtml(source.sourceUuid)}</code></a>${label ? ` <span>${escapeHtml(label)}</span>` : ""}`;
}
async function openSourceUuid(uuid) {
if (!uuid) return;
const document = await fromUuid(uuid);
if (document?.sheet) {
document.sheet.render(true, { focus: true });
return;
}
if (document?.parent?.sheet) {
document.parent.sheet.render(true, { focus: true });
return;
}
ui.notifications.warn(format("KSA.Notify.OpenSourceFailed", { uuid }));
} }

View File

@@ -48,6 +48,7 @@ async function* listWorldSources() {
const collectionsDir = path.join(dataRoot, "worlds", worldId, "data"); const collectionsDir = path.join(dataRoot, "worlds", worldId, "data");
const collectionNames = await fs.readdir(collectionsDir); const collectionNames = await fs.readdir(collectionsDir);
for (const collectionName of collectionNames.sort()) { for (const collectionName of collectionNames.sort()) {
if (collectionName === "messages") continue;
const dbPath = path.join(collectionsDir, collectionName); const dbPath = path.join(collectionsDir, collectionName);
const db = new ClassicLevel(dbPath, { keyEncoding: "utf8", valueEncoding: "json" }); const db = new ClassicLevel(dbPath, { keyEncoding: "utf8", valueEncoding: "json" });
await db.open(); await db.open();