Phase 10E.1: Word Companion Resolve Diagnostics and Outline Display Cleanup
This commit is contained in:
parent
8c4525d3b3
commit
6049ac2c87
@ -82,6 +82,52 @@
|
|||||||
</div>
|
</div>
|
||||||
<span>Scene Status</span>
|
<span>Scene Status</span>
|
||||||
<p class="word-companion-message" data-plotdirector-scene-status>Select a PlotDirector book.</p>
|
<p class="word-companion-message" data-plotdirector-scene-status>Select a PlotDirector book.</p>
|
||||||
|
<div class="word-companion-resolve-diagnostics" aria-label="Resolve diagnostics">
|
||||||
|
<div>
|
||||||
|
<span>Selected Project ID</span>
|
||||||
|
<strong data-resolve-project-id>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Selected Project</span>
|
||||||
|
<strong data-resolve-project-title>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Selected Book ID</span>
|
||||||
|
<strong data-resolve-book-id>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Selected Book</span>
|
||||||
|
<strong data-resolve-book-title>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Detected Chapter</span>
|
||||||
|
<strong data-resolve-detected-chapter>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Detected Scene</span>
|
||||||
|
<strong data-resolve-detected-scene>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Resolve Request Chapter</span>
|
||||||
|
<strong data-resolve-request-chapter>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Resolve Request Scene</span>
|
||||||
|
<strong data-resolve-request-scene>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Resolve Result</span>
|
||||||
|
<strong data-resolve-result>Not run</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Chapter ID</span>
|
||||||
|
<strong data-resolve-chapter-id>-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Scene ID</span>
|
||||||
|
<strong data-resolve-scene-id>-</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="word-companion-scene-details" data-plotdirector-scene-details hidden>
|
<div class="word-companion-scene-details" data-plotdirector-scene-details hidden>
|
||||||
<div>
|
<div>
|
||||||
<span>Scene Title</span>
|
<span>Scene Title</span>
|
||||||
|
|||||||
@ -174,18 +174,29 @@ body {
|
|||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.word-companion-resolve-diagnostics,
|
||||||
.word-companion-scene-details,
|
.word-companion-scene-details,
|
||||||
.word-companion-link-groups {
|
.word-companion-link-groups {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.word-companion-resolve-diagnostics div,
|
||||||
.word-companion-scene-details div,
|
.word-companion-scene-details div,
|
||||||
.word-companion-link-groups div {
|
.word-companion-link-groups div {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.word-companion-resolve-diagnostics {
|
||||||
|
border-top: 1px solid var(--companion-line);
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-companion-resolve-diagnostics strong {
|
||||||
|
font-size: 0.86rem;
|
||||||
|
}
|
||||||
|
|
||||||
.word-companion-brief {
|
.word-companion-brief {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|||||||
@ -37,6 +37,17 @@
|
|||||||
const characterChips = document.querySelector("[data-character-chips]");
|
const characterChips = document.querySelector("[data-character-chips]");
|
||||||
const assetChips = document.querySelector("[data-asset-chips]");
|
const assetChips = document.querySelector("[data-asset-chips]");
|
||||||
const locationChips = document.querySelector("[data-location-chips]");
|
const locationChips = document.querySelector("[data-location-chips]");
|
||||||
|
const resolveProjectId = document.querySelector("[data-resolve-project-id]");
|
||||||
|
const resolveProjectTitle = document.querySelector("[data-resolve-project-title]");
|
||||||
|
const resolveBookId = document.querySelector("[data-resolve-book-id]");
|
||||||
|
const resolveBookTitle = document.querySelector("[data-resolve-book-title]");
|
||||||
|
const resolveDetectedChapter = document.querySelector("[data-resolve-detected-chapter]");
|
||||||
|
const resolveDetectedScene = document.querySelector("[data-resolve-detected-scene]");
|
||||||
|
const resolveRequestChapter = document.querySelector("[data-resolve-request-chapter]");
|
||||||
|
const resolveRequestScene = document.querySelector("[data-resolve-request-scene]");
|
||||||
|
const resolveResult = document.querySelector("[data-resolve-result]");
|
||||||
|
const resolveChapterId = document.querySelector("[data-resolve-chapter-id]");
|
||||||
|
const resolveSceneId = document.querySelector("[data-resolve-scene-id]");
|
||||||
const runDiagnosticsButton = document.querySelector("[data-run-diagnostics]");
|
const runDiagnosticsButton = document.querySelector("[data-run-diagnostics]");
|
||||||
const diagnosticHost = document.querySelector("[data-diagnostic-host]");
|
const diagnosticHost = document.querySelector("[data-diagnostic-host]");
|
||||||
const diagnosticPlatform = document.querySelector("[data-diagnostic-platform]");
|
const diagnosticPlatform = document.querySelector("[data-diagnostic-platform]");
|
||||||
@ -181,6 +192,37 @@
|
|||||||
setHidden(plotDirectorLinkGroups, false);
|
setHidden(plotDirectorLinkGroups, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const normalizeWhitespace = (value) => String(value || "").trim().replace(/\s+/g, " ");
|
||||||
|
|
||||||
|
const normalizeTitleForResolve = (title, type) => {
|
||||||
|
const original = normalizeWhitespace(title);
|
||||||
|
if (!original) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = type === "scene" ? "scene" : "chapter";
|
||||||
|
const ordinal = "(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)";
|
||||||
|
const prefix = new RegExp(`^${label}\\s+${ordinal}\\s*(?::|-|\\u2013|\\u2014)\\s*`, "i");
|
||||||
|
const normalized = normalizeWhitespace(original.replace(prefix, ""));
|
||||||
|
return normalized || original;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setResolveDiagnostics = (values) => {
|
||||||
|
const hasValue = (name) => Object.prototype.hasOwnProperty.call(values, name);
|
||||||
|
|
||||||
|
if (hasValue("projectId")) setText(resolveProjectId, displayValue(values.projectId));
|
||||||
|
if (hasValue("projectTitle")) setText(resolveProjectTitle, displayValue(values.projectTitle));
|
||||||
|
if (hasValue("bookId")) setText(resolveBookId, displayValue(values.bookId));
|
||||||
|
if (hasValue("bookTitle")) setText(resolveBookTitle, displayValue(values.bookTitle));
|
||||||
|
if (hasValue("detectedChapter")) setText(resolveDetectedChapter, displayValue(values.detectedChapter));
|
||||||
|
if (hasValue("detectedScene")) setText(resolveDetectedScene, displayValue(values.detectedScene));
|
||||||
|
if (hasValue("requestChapter")) setText(resolveRequestChapter, displayValue(values.requestChapter));
|
||||||
|
if (hasValue("requestScene")) setText(resolveRequestScene, displayValue(values.requestScene));
|
||||||
|
if (hasValue("result")) setText(resolveResult, displayValue(values.result));
|
||||||
|
if (hasValue("chapterId")) setText(resolveChapterId, displayValue(values.chapterId));
|
||||||
|
if (hasValue("sceneId")) setText(resolveSceneId, displayValue(values.sceneId));
|
||||||
|
};
|
||||||
|
|
||||||
const findSceneRevisionStatus = async (bookId, sceneId) => {
|
const findSceneRevisionStatus = async (bookId, sceneId) => {
|
||||||
const structure = await fetchJson(`/api/word-companion/books/${bookId}/structure`);
|
const structure = await fetchJson(`/api/word-companion/books/${bookId}/structure`);
|
||||||
const chapters = Array.isArray(structure?.chapters) ? structure.chapters : [];
|
const chapters = Array.isArray(structure?.chapters) ? structure.chapters : [];
|
||||||
@ -475,14 +517,14 @@
|
|||||||
chapterBlock.className = "word-companion-outline-chapter";
|
chapterBlock.className = "word-companion-outline-chapter";
|
||||||
|
|
||||||
const chapterTitle = document.createElement("strong");
|
const chapterTitle = document.createElement("strong");
|
||||||
chapterTitle.textContent = `Chapter ${chapter.index}: ${chapter.title}`;
|
chapterTitle.textContent = chapter.title;
|
||||||
chapterBlock.append(chapterTitle);
|
chapterBlock.append(chapterTitle);
|
||||||
|
|
||||||
if (chapter.scenes.length > 0) {
|
if (chapter.scenes.length > 0) {
|
||||||
const sceneList = document.createElement("ul");
|
const sceneList = document.createElement("ul");
|
||||||
for (const sceneItem of chapter.scenes) {
|
for (const sceneItem of chapter.scenes) {
|
||||||
const sceneRow = document.createElement("li");
|
const sceneRow = document.createElement("li");
|
||||||
sceneRow.textContent = `Scene ${sceneItem.index}: ${sceneItem.title}`;
|
sceneRow.textContent = sceneItem.title;
|
||||||
sceneList.append(sceneRow);
|
sceneList.append(sceneRow);
|
||||||
}
|
}
|
||||||
chapterBlock.append(sceneList);
|
chapterBlock.append(sceneList);
|
||||||
@ -613,14 +655,34 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const refreshPlotDirectorScene = async () => {
|
const refreshPlotDirectorScene = async () => {
|
||||||
|
const project = selectedProject();
|
||||||
const book = selectedBook();
|
const book = selectedBook();
|
||||||
|
const requestChapterTitle = normalizeTitleForResolve(detectedChapterTitle, "chapter");
|
||||||
|
const requestSceneTitle = normalizeTitleForResolve(detectedSceneTitle, "scene");
|
||||||
|
|
||||||
|
setResolveDiagnostics({
|
||||||
|
projectId: project?.projectId,
|
||||||
|
projectTitle: project?.title,
|
||||||
|
bookId: book?.bookId,
|
||||||
|
bookTitle: book?.title,
|
||||||
|
detectedChapter: detectedChapterTitle,
|
||||||
|
detectedScene: detectedSceneTitle,
|
||||||
|
requestChapter: requestChapterTitle,
|
||||||
|
requestScene: requestSceneTitle,
|
||||||
|
result: "Not run",
|
||||||
|
chapterId: null,
|
||||||
|
sceneId: null
|
||||||
|
});
|
||||||
|
|
||||||
if (!book) {
|
if (!book) {
|
||||||
resetPlotDirectorScene("Select a PlotDirector book.");
|
resetPlotDirectorScene("Select a PlotDirector book.");
|
||||||
|
setResolveDiagnostics({ result: "Error" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!detectedChapterTitle || !detectedSceneTitle) {
|
if (!detectedChapterTitle || !detectedSceneTitle) {
|
||||||
resetPlotDirectorScene("No scene detected in Word.");
|
resetPlotDirectorScene("No scene detected in Word.");
|
||||||
|
setResolveDiagnostics({ result: "Error" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,19 +701,30 @@
|
|||||||
let resolvedSceneId = null;
|
let resolvedSceneId = null;
|
||||||
try {
|
try {
|
||||||
const resolveResponse = await postJson(`/api/word-companion/books/${book.bookId}/resolve-scene`, {
|
const resolveResponse = await postJson(`/api/word-companion/books/${book.bookId}/resolve-scene`, {
|
||||||
chapterTitle: detectedChapterTitle,
|
chapterTitle: requestChapterTitle,
|
||||||
sceneTitle: detectedSceneTitle
|
sceneTitle: requestSceneTitle
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!resolveResponse?.matched || !resolveResponse.sceneId) {
|
if (!resolveResponse?.matched || !resolveResponse.sceneId) {
|
||||||
resetPlotDirectorScene("Scene not found in PlotDirector.");
|
resetPlotDirectorScene("No exact match found for this chapter/scene in the selected book.");
|
||||||
|
setResolveDiagnostics({
|
||||||
|
result: "Not matched",
|
||||||
|
chapterId: resolveResponse?.chapterId,
|
||||||
|
sceneId: resolveResponse?.sceneId
|
||||||
|
});
|
||||||
restorePlotDirectorSceneButton();
|
restorePlotDirectorSceneButton();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedSceneId = resolveResponse.sceneId;
|
resolvedSceneId = resolveResponse.sceneId;
|
||||||
|
setResolveDiagnostics({
|
||||||
|
result: "Matched",
|
||||||
|
chapterId: resolveResponse.chapterId,
|
||||||
|
sceneId: resolveResponse.sceneId
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
resetPlotDirectorScene("Unable to resolve scene.");
|
resetPlotDirectorScene("Unable to resolve scene.");
|
||||||
|
setResolveDiagnostics({ result: "Error" });
|
||||||
restorePlotDirectorSceneButton();
|
restorePlotDirectorSceneButton();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -667,6 +740,7 @@
|
|||||||
renderCompanionData(companionData);
|
renderCompanionData(companionData);
|
||||||
} catch {
|
} catch {
|
||||||
resetPlotDirectorScene("Unable to load PlotDirector scene data.");
|
resetPlotDirectorScene("Unable to load PlotDirector scene data.");
|
||||||
|
setResolveDiagnostics({ result: "Error" });
|
||||||
} finally {
|
} finally {
|
||||||
restorePlotDirectorSceneButton();
|
restorePlotDirectorSceneButton();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user