Require Word marker save acknowledgement
This commit is contained in:
parent
fbe8e60d59
commit
adf93a075c
@ -14,6 +14,7 @@ public sealed class WordCompanionFollowHub(
|
|||||||
IOnboardingRepository onboarding,
|
IOnboardingRepository onboarding,
|
||||||
IManuscriptScanPreviewStore scanStore,
|
IManuscriptScanPreviewStore scanStore,
|
||||||
IOnboardingService onboardingService,
|
IOnboardingService onboardingService,
|
||||||
|
IOnboardingBuildRepository onboardingBuilds,
|
||||||
ILogger<WordCompanionFollowHub> logger) : Hub
|
ILogger<WordCompanionFollowHub> logger) : Hub
|
||||||
{
|
{
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
@ -223,13 +224,55 @@ public sealed class WordCompanionFollowHub(
|
|||||||
var companionConnectionId = await presence.GetCompanionConnectionIdAsync(userId);
|
var companionConnectionId = await presence.GetCompanionConnectionIdAsync(userId);
|
||||||
if (!string.IsNullOrWhiteSpace(companionConnectionId))
|
if (!string.IsNullOrWhiteSpace(companionConnectionId))
|
||||||
{
|
{
|
||||||
|
await onboardingBuilds.MarkMarkerSyncSentAsync(result.BuildID);
|
||||||
await Clients.Client(companionConnectionId).SendAsync("UpdateOnboardingBuildMarkers", result);
|
await Clients.Client(companionConnectionId).SendAsync("UpdateOnboardingBuildMarkers", result);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await onboardingBuilds.MarkMarkerSyncFailedAsync(result.BuildID, "The Word Companion disconnected before marker sync could be sent.");
|
||||||
|
await Clients.Group(PresenceGroup(userId)).SendAsync("OnboardingBuildProgress", new OnboardingBuildProgress
|
||||||
|
{
|
||||||
|
Status = "Failed",
|
||||||
|
Message = "The Word Companion disconnected before PlotDirector could update and save Word markers.",
|
||||||
|
PercentComplete = 90,
|
||||||
|
ChaptersCreated = result.ChaptersCreated,
|
||||||
|
ScenesCreated = result.ScenesCreated,
|
||||||
|
CharactersCreated = result.CharactersCreated + result.CharactersReused,
|
||||||
|
SceneAppearancesCreated = result.SceneAppearancesCreated,
|
||||||
|
PreviewID = previewId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await Clients.Group(PresenceGroup(userId)).SendAsync("OnboardingBuildCompleted", result);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CompleteOnboardingBuildMarkerSync(int buildId)
|
||||||
|
{
|
||||||
|
var userId = RequireUserId();
|
||||||
|
await onboardingBuilds.MarkMarkerSyncCompletedAsync(buildId);
|
||||||
|
await Clients.Group(PresenceGroup(userId)).SendAsync("OnboardingBuildProgress", new OnboardingBuildProgress
|
||||||
|
{
|
||||||
|
Status = "Complete",
|
||||||
|
Message = "Manuscript structure has been created and saved. Word and this browser page may now be closed.",
|
||||||
|
PercentComplete = 100
|
||||||
|
});
|
||||||
|
await Clients.Group(PresenceGroup(userId)).SendAsync("OnboardingBuildMarkerSyncCompleted", new { buildId });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task FailOnboardingBuildMarkerSync(int buildId, string message)
|
||||||
|
{
|
||||||
|
var userId = RequireUserId();
|
||||||
|
await onboardingBuilds.MarkMarkerSyncFailedAsync(buildId, message);
|
||||||
|
await Clients.Group(PresenceGroup(userId)).SendAsync("OnboardingBuildProgress", new OnboardingBuildProgress
|
||||||
|
{
|
||||||
|
Status = "Failed",
|
||||||
|
Message = string.IsNullOrWhiteSpace(message)
|
||||||
|
? "Word marker sync failed. Keep Word open and try again."
|
||||||
|
: message,
|
||||||
|
PercentComplete = 90
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Exception? exception)
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||||
{
|
{
|
||||||
int? disconnectedUserId = null;
|
int? disconnectedUserId = null;
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
@model OnboardingManuscriptBuildResult
|
@model OnboardingManuscriptBuildResult
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Chapters prepared";
|
ViewData["Title"] = "Manuscript imported";
|
||||||
}
|
}
|
||||||
|
|
||||||
<section class="onboarding-shell" aria-labelledby="build-complete-title">
|
<section class="onboarding-shell" aria-labelledby="build-complete-title">
|
||||||
<div class="onboarding-panel onboarding-review-panel">
|
<div class="onboarding-panel onboarding-review-panel">
|
||||||
<ol class="onboarding-stepper onboarding-stepper--complete" aria-label="Story setup journey">
|
<ol class="onboarding-stepper onboarding-stepper--complete" aria-label="Story setup journey">
|
||||||
@foreach (var label in new[] { "Welcome", "Writing Preferences", "Project", "Book", "Connect Word", "Scan", "Review", "Prepare Chapters", "Complete" })
|
@foreach (var label in new[] { "Welcome", "Writing Preferences", "Project", "Book", "Connect Word", "Scan", "Review", "Create Structure", "Complete" })
|
||||||
{
|
{
|
||||||
<li class="is-complete">
|
<li class="is-complete">
|
||||||
<span></span>
|
<span></span>
|
||||||
@ -15,12 +15,12 @@
|
|||||||
}
|
}
|
||||||
</ol>
|
</ol>
|
||||||
<div class="onboarding-copy">
|
<div class="onboarding-copy">
|
||||||
<p class="eyebrow">Prepare Chapters</p>
|
<p class="eyebrow">Core Import Complete</p>
|
||||||
<div class="onboarding-success-heading">
|
<div class="onboarding-success-heading">
|
||||||
<span aria-hidden="true">✓</span>
|
<span aria-hidden="true">✓</span>
|
||||||
<h1 id="build-complete-title">Your chapters are ready.</h1>
|
<h1 id="build-complete-title">Your manuscript has been imported.</h1>
|
||||||
</div>
|
</div>
|
||||||
<p>@(Model.AlreadyBuilt ? "These chapters have already been prepared in PlotDirector, so nothing was duplicated." : "PlotDirector prepared the approved chapters. Story Intelligence will create scenes after you review the analysis.")</p>
|
<p>@(Model.AlreadyBuilt ? "This manuscript structure has already been created in PlotDirector, so nothing was duplicated." : "PlotDirector created the approved chapters and scenes, updated the Word markers, and saved the manuscript. Word and this browser page may now be closed.")</p>
|
||||||
@if (!string.IsNullOrWhiteSpace(Model.MarkerWarning))
|
@if (!string.IsNullOrWhiteSpace(Model.MarkerWarning))
|
||||||
{
|
{
|
||||||
<p class="text-warning">@Model.MarkerWarning</p>
|
<p class="text-warning">@Model.MarkerWarning</p>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<strong>@Model.ChaptersCreated</strong>
|
<strong>@Model.ChaptersCreated</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Scenes created now</span>
|
<span>Scenes</span>
|
||||||
<strong>@Model.ScenesCreated</strong>
|
<strong>@Model.ScenesCreated</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -47,12 +47,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="onboarding-complete-next">
|
<section class="onboarding-complete-next">
|
||||||
<h2>Next: analyse manuscript</h2>
|
<h2>Optional: analyse manuscript</h2>
|
||||||
<p>Story Intelligence will detect scenes from the approved chapter text. You will review the results before PlotDirector creates scenes.</p>
|
<p>Story Intelligence can now enrich the existing scenes with summaries, context, relationships, knowledge, timeline details and metrics. You can analyse now or return later.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="onboarding-actions">
|
<div class="onboarding-actions">
|
||||||
<a class="btn btn-primary" asp-controller="Onboarding" asp-action="StoryIntelligence">Analyse manuscript</a>
|
<a class="btn btn-primary" asp-controller="Onboarding" asp-action="StoryIntelligence">Analyse my book</a>
|
||||||
|
<a class="btn btn-outline-secondary" asp-controller="Projects" asp-action="Details" asp-route-id="@Model.ProjectID">Not now</a>
|
||||||
<a class="btn btn-outline-primary" asp-controller="Projects" asp-action="Details" asp-route-id="@Model.ProjectID">Open Project Overview</a>
|
<a class="btn btn-outline-primary" asp-controller="Projects" asp-action="Details" asp-route-id="@Model.ProjectID">Open Project Overview</a>
|
||||||
<a class="btn btn-outline-secondary" asp-controller="Writer" asp-action="Index" asp-route-projectId="@Model.ProjectID">Open Writer Workspace</a>
|
<a class="btn btn-outline-secondary" asp-controller="Writer" asp-action="Index" asp-route-projectId="@Model.ProjectID">Open Writer Workspace</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -300,8 +300,8 @@
|
|||||||
{
|
{
|
||||||
<div class="onboarding-build-panel" data-onboarding-build-panel>
|
<div class="onboarding-build-panel" data-onboarding-build-panel>
|
||||||
<div>
|
<div>
|
||||||
<p class="onboarding-scan-next">Review saved. PlotDirector can now analyse the approved chapters.</p>
|
<p class="onboarding-scan-next">Review saved. PlotDirector can now import the approved manuscript structure.</p>
|
||||||
<p class="onboarding-build-message" data-onboarding-build-message>Next: analyse the manuscript and review suggested scenes.</p>
|
<p class="onboarding-build-message" data-onboarding-build-message>Next: detect scene boundaries, create PlotDirector scenes, then update and save Word markers.</p>
|
||||||
</div>
|
</div>
|
||||||
<strong data-onboarding-build-percent></strong>
|
<strong data-onboarding-build-percent></strong>
|
||||||
<div class="onboarding-scan-progress onboarding-build-progress" aria-hidden="true">
|
<div class="onboarding-scan-progress onboarding-build-progress" aria-hidden="true">
|
||||||
@ -319,7 +319,12 @@
|
|||||||
</form>
|
</form>
|
||||||
@if (Model.IsMicrosoftWordPath && string.Equals(Model.ScanState.ReviewStatus, ManuscriptScanReviewStatuses.ReadyToImport, StringComparison.Ordinal))
|
@if (Model.IsMicrosoftWordPath && string.Equals(Model.ScanState.ReviewStatus, ManuscriptScanReviewStatuses.ReadyToImport, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
<a class="btn btn-primary" asp-controller="Onboarding" asp-action="StoryIntelligence">Analyse manuscript</a>
|
<button class="btn btn-primary"
|
||||||
|
type="button"
|
||||||
|
data-onboarding-build-start
|
||||||
|
data-preview-id="@Model.ScanState.PreviewID">
|
||||||
|
Import manuscript
|
||||||
|
</button>
|
||||||
}
|
}
|
||||||
else if (Model.IsMicrosoftWordPath && Model.ScanState.IsComplete)
|
else if (Model.IsMicrosoftWordPath && Model.ScanState.IsComplete)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="onboarding-copy story-live-hero">
|
<div class="onboarding-copy story-live-hero">
|
||||||
<p class="eyebrow">Analyse manuscript</p>
|
<p class="eyebrow">Analyse manuscript</p>
|
||||||
<h1 id="story-progress-title">Reading your manuscript</h1>
|
<h1 id="story-progress-title">Reading your manuscript</h1>
|
||||||
<p>PlotDirector is analysing your chapters and preparing scenes for review. Keep Word and the Companion open until PlotDirector has finished creating the scene structure you need.</p>
|
<p>PlotDirector is enriching the imported scenes with summaries, context, relationships, knowledge, timeline details and metrics.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (TempData["OnboardingStoryIntelligenceError"] is string error)
|
@if (TempData["OnboardingStoryIntelligenceError"] is string error)
|
||||||
@ -30,7 +30,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<section class="alert alert-info">
|
<section class="alert alert-info">
|
||||||
PlotDirector will keep analysing your manuscript on the server. Do not close Word yet if you need this manuscript to receive PlotDirector scene markers for the writing workspace.
|
PlotDirector will keep analysing your imported scenes on the server. The manuscript structure and Word markers are already saved, so Word does not need to remain open for this analysis.
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="story-live-progress-card" aria-label="Import progress">
|
<section class="story-live-progress-card" aria-label="Import progress">
|
||||||
|
|||||||
@ -2199,13 +2199,19 @@
|
|||||||
return scene;
|
return scene;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addWords = (text, words) => {
|
const addWords = (paragraph, text, words) => {
|
||||||
if (!chapter || !scene || words <= 0) {
|
if (!chapter || !scene || words <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chapter.wordCount += words;
|
chapter.wordCount += words;
|
||||||
chapter.chapterTextParagraphs.push(text);
|
chapter.chapterTextParagraphs.push(text);
|
||||||
|
chapter.paragraphMap = chapter.paragraphMap || [];
|
||||||
|
chapter.paragraphMap.push({
|
||||||
|
structuralParagraphOrdinal: chapter.chapterTextParagraphs.length,
|
||||||
|
wordParagraphIndex: Number.isInteger(paragraph?.index) ? paragraph.index : -1,
|
||||||
|
text
|
||||||
|
});
|
||||||
scene.wordCount += words;
|
scene.wordCount += words;
|
||||||
if (!scene.openingTextPreview && text && !sceneSeparatorTexts.has(text)) {
|
if (!scene.openingTextPreview && text && !sceneSeparatorTexts.has(text)) {
|
||||||
scene.openingTextPreview = text.length > 180 ? `${text.slice(0, 177)}...` : text;
|
scene.openingTextPreview = text.length > 180 ? `${text.slice(0, 177)}...` : text;
|
||||||
@ -2233,6 +2239,12 @@
|
|||||||
totalWordCount += words;
|
totalWordCount += words;
|
||||||
chapter.wordCount += words;
|
chapter.wordCount += words;
|
||||||
chapter.chapterTextParagraphs.push(text);
|
chapter.chapterTextParagraphs.push(text);
|
||||||
|
chapter.paragraphMap = chapter.paragraphMap || [];
|
||||||
|
chapter.paragraphMap.push({
|
||||||
|
structuralParagraphOrdinal: chapter.chapterTextParagraphs.length,
|
||||||
|
wordParagraphIndex: Number.isInteger(paragraph?.index) ? paragraph.index : -1,
|
||||||
|
text
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2249,7 +2261,7 @@
|
|||||||
if (isBuiltInHeading(paragraph, 2)) {
|
if (isBuiltInHeading(paragraph, 2)) {
|
||||||
startScene(paragraph, text);
|
startScene(paragraph, text);
|
||||||
totalWordCount += words;
|
totalWordCount += words;
|
||||||
addWords(text, words);
|
addWords(paragraph, text, words);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2259,7 +2271,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
totalWordCount += words;
|
totalWordCount += words;
|
||||||
addWords(text, words);
|
addWords(paragraph, text, words);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (totalWordCount === 0) {
|
if (totalWordCount === 0) {
|
||||||
@ -2391,20 +2403,48 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateOnboardingBuildMarkers = async (result) => {
|
const updateOnboardingBuildMarkers = async (result) => {
|
||||||
if (!lastOnboardingScanPreview || !wordHostAvailable || !window.Word || typeof window.Word.run !== "function") {
|
if (!wordHostAvailable || !window.Word || typeof window.Word.run !== "function") {
|
||||||
throw new Error("Word document access is unavailable.");
|
throw new Error("Word document access is unavailable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildId = Number.parseInt(result?.buildID || result?.BuildID || "0", 10);
|
||||||
const chapterMap = new Map((result?.chapterMappings || result?.ChapterMappings || [])
|
const chapterMap = new Map((result?.chapterMappings || result?.ChapterMappings || [])
|
||||||
.map((item) => [item.temporaryChapterKey || item.TemporaryChapterKey, item.chapterID || item.ChapterID]));
|
.map((item) => [item.temporaryChapterKey || item.TemporaryChapterKey, item.chapterID || item.ChapterID]));
|
||||||
const sceneMap = new Map((result?.sceneMappings || result?.SceneMappings || [])
|
const sceneMap = new Map((result?.sceneMappings || result?.SceneMappings || [])
|
||||||
.map((item) => [item.temporarySceneKey || item.TemporarySceneKey, item.sceneID || item.SceneID]));
|
.map((item) => [item.temporarySceneKey || item.TemporarySceneKey, item.sceneID || item.SceneID]));
|
||||||
|
const chapterInstructions = result?.chapterMarkerInstructions || result?.ChapterMarkerInstructions || [];
|
||||||
|
const sceneInstructions = result?.sceneMarkerInstructions || result?.SceneMarkerInstructions || [];
|
||||||
|
if (!lastOnboardingScanPreview && chapterInstructions.length === 0 && sceneInstructions.length === 0) {
|
||||||
|
throw new Error("Word marker instructions are unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
await window.Word.run(async (context) => {
|
await window.Word.run(async (context) => {
|
||||||
const paragraphs = context.document.body.paragraphs;
|
const paragraphs = context.document.body.paragraphs;
|
||||||
paragraphs.load("items/text,items/style,items/styleBuiltIn");
|
paragraphs.load("items/text,items/style,items/styleBuiltIn");
|
||||||
await context.sync();
|
await context.sync();
|
||||||
|
|
||||||
|
if (chapterInstructions.length > 0 || sceneInstructions.length > 0) {
|
||||||
|
for (const instruction of chapterInstructions) {
|
||||||
|
const index = Number.parseInt(instruction.wordParagraphIndex ?? instruction.WordParagraphIndex, 10);
|
||||||
|
const tag = instruction.markerTag || instruction.MarkerTag;
|
||||||
|
const title = instruction.markerTitle || instruction.MarkerTitle || "PlotDirector Chapter";
|
||||||
|
const prefix = instruction.markerPrefix || instruction.MarkerPrefix || "PD-CHAPTER";
|
||||||
|
if (tag && Number.isInteger(index) && paragraphs.items[index]) {
|
||||||
|
ensureAnchorControl(paragraphs.items[index], title, tag, prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const instruction of sceneInstructions) {
|
||||||
|
const index = Number.parseInt(instruction.wordParagraphIndex ?? instruction.WordParagraphIndex, 10);
|
||||||
|
const tag = instruction.markerTag || instruction.MarkerTag;
|
||||||
|
const title = instruction.markerTitle || instruction.MarkerTitle || "PlotDirector Scene";
|
||||||
|
const prefix = instruction.markerPrefix || instruction.MarkerPrefix || "PD-SCENE";
|
||||||
|
if (tag && Number.isInteger(index) && paragraphs.items[index]) {
|
||||||
|
ensureAnchorControl(paragraphs.items[index], title, tag, prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (const chapter of lastOnboardingScanPreview.chapters || []) {
|
for (const chapter of lastOnboardingScanPreview.chapters || []) {
|
||||||
const chapterId = chapterMap.get(chapter.temporaryChapterKey);
|
const chapterId = chapterMap.get(chapter.temporaryChapterKey);
|
||||||
const index = Number.parseInt(chapter.startPosition, 10);
|
const index = Number.parseInt(chapter.startPosition, 10);
|
||||||
@ -2420,10 +2460,26 @@
|
|||||||
ensureAnchorControl(paragraphs.items[index], "PlotDirector Scene", `PD-SCENE-${sceneId}`, "PD-SCENE");
|
ensureAnchorControl(paragraphs.items[index], "PlotDirector Scene", `PD-SCENE-${sceneId}`, "PD-SCENE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await context.sync();
|
await context.sync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const saved = await saveWordDocumentIfAvailable();
|
||||||
|
if (!saved) {
|
||||||
|
throw new Error("Word markers were inserted, but the document could not be saved.");
|
||||||
|
}
|
||||||
|
|
||||||
await inspectPlotDirectorMarkers().catch(() => null);
|
await inspectPlotDirectorMarkers().catch(() => null);
|
||||||
|
if (Number.isInteger(buildId) && buildId > 0) {
|
||||||
|
await companionPresenceConnection.invoke("CompleteOnboardingBuildMarkerSync", buildId);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (Number.isInteger(buildId) && buildId > 0) {
|
||||||
|
await companionPresenceConnection.invoke("FailOnboardingBuildMarkerSync", buildId, errorText(error));
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const friendlyScanError = (error) => {
|
const friendlyScanError = (error) => {
|
||||||
|
|||||||
@ -154,6 +154,7 @@
|
|||||||
.withUrl("/hubs/word-companion-follow")
|
.withUrl("/hubs/word-companion-follow")
|
||||||
.withAutomaticReconnect()
|
.withAutomaticReconnect()
|
||||||
.build();
|
.build();
|
||||||
|
let pendingBuildPreviewId = "";
|
||||||
|
|
||||||
connection.on("WordCompanionPresenceChanged", applyStatus);
|
connection.on("WordCompanionPresenceChanged", applyStatus);
|
||||||
connection.on("OnboardingScanStateChanged", applyScanState);
|
connection.on("OnboardingScanStateChanged", applyScanState);
|
||||||
@ -183,6 +184,11 @@
|
|||||||
window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(previewId)}`;
|
window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(previewId)}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
connection.on("OnboardingBuildMarkerSyncCompleted", () => {
|
||||||
|
if (pendingBuildPreviewId) {
|
||||||
|
window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(pendingBuildPreviewId)}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
connection.onreconnecting(() => applyStatus({ status: "Connecting", isConnected: false }));
|
connection.onreconnecting(() => applyStatus({ status: "Connecting", isConnected: false }));
|
||||||
connection.onreconnected(() => connection.invoke("WatchCompanionPresence").then(applyStatus).catch(() => {}));
|
connection.onreconnected(() => connection.invoke("WatchCompanionPresence").then(applyStatus).catch(() => {}));
|
||||||
connection.onclose(() => applyStatus({ status: "Offline", isConnected: false }));
|
connection.onclose(() => applyStatus({ status: "Offline", isConnected: false }));
|
||||||
@ -229,8 +235,10 @@
|
|||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const result = await connection.invoke("StartOnboardingProjectBuild", previewId);
|
const result = await connection.invoke("StartOnboardingProjectBuild", previewId);
|
||||||
const returnedPreviewId = field(result, "previewID", "PreviewID") || previewId;
|
pendingBuildPreviewId = field(result, "previewID", "PreviewID") || previewId;
|
||||||
window.location.href = `/onboarding/build-complete?previewId=${encodeURIComponent(returnedPreviewId)}`;
|
document.querySelectorAll("[data-onboarding-build-message]").forEach((node) => {
|
||||||
|
node.textContent = "Updating and saving Word markers. Keep Word and this browser page open.";
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
document.querySelectorAll("[data-onboarding-build-panel]").forEach((node) => {
|
document.querySelectorAll("[data-onboarding-build-panel]").forEach((node) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user