From 9fecaa7bcaef8e268394c5b9c81ca32596604319 Mon Sep 17 00:00:00 2001 From: Suphonchai Phoonsawat Date: Thu, 5 Nov 2026 12:42:02 +0700 Subject: [PATCH] add-in: auto-open taskpane phase 1 + final save after versioning + tracking id = fid - manifest: TaskpaneId -> Office.AutoShowTaskpaneWithDocument (auto-open marker), bump 1.0.0.4 - metadataService.enableAutoOpenTaskpane: tag doc setting (idempotent, best-effort) called from detect() after sign-in - versionFlow: final saveDocumentVerified at end of both versioning flows (bug: stamped docx never persisted -> reopen showed untracked) - tracking id now uses ticket fid (TRACKING_ID_SOURCE="fid", rollback by switching to "guid"), resolveTrackingId + authService.getCurrentFid - WordAddinGate: restore history.pushState/replaceState that office.js nullifies in taskpane (fixes Next App Router crash) Co-Authored-By: Claude Code --- components/wordaddin/TaskpaneApp.tsx | 4 + components/wordaddin/WordAddinGate.tsx | 36 ++++++++- public/wordaddin/manifest.template.xml | 10 ++- tests/wordaddin/metadataService.test.ts | 100 ++++++++++++++++++++++++ tests/wordaddin/versionFlow.test.ts | 18 +++++ wordaddin/services/authService.ts | 6 ++ wordaddin/services/metadataService.ts | 56 +++++++++++++ wordaddin/services/versionFlow.ts | 32 +++++++- 8 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 tests/wordaddin/versionFlow.test.ts diff --git a/components/wordaddin/TaskpaneApp.tsx b/components/wordaddin/TaskpaneApp.tsx index 269d695..957e29a 100644 --- a/components/wordaddin/TaskpaneApp.tsx +++ b/components/wordaddin/TaskpaneApp.tsx @@ -212,6 +212,10 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) => } setUsername(authService.getUsername() ?? null); + // auto-open (2026-11-05) — sign-in ผ่าน = ไฟล์ e-Court: tag ให้ taskpane เด้งเองครั้งถัดไป + // ที่เปิดไฟล์นี้ · fire-and-forget (service กลืน error ทั้งหมด — ไฟล์ทั่วไปไม่มาทางนี้อยู่แล้ว) + void metadataService.enableAutoOpenTaskpane(); + const tracked = properties.savedByAddIn === metadataService.ADDIN_SIGNATURE_GUID; const id = tracked ? properties.documentTrackingId : undefined; if (!id) { diff --git a/components/wordaddin/WordAddinGate.tsx b/components/wordaddin/WordAddinGate.tsx index 2deeb10..326a2d4 100644 --- a/components/wordaddin/WordAddinGate.tsx +++ b/components/wordaddin/WordAddinGate.tsx @@ -31,6 +31,33 @@ const ONREADY_FALLBACK_MS = 5_000; /** เพดานรวมหลัง inject script — ครบแล้วยังไม่มี Office = ไปหน้า error (มีปุ่มลองใหม่) */ const ONREADY_HARD_CAP_MS = 60_000; +/** + * office.js **ลบ `history.pushState`/`replaceState` ทิ้ง** ใน taskpane (set เป็น null — + * กัน add-in พา host ไปที่อื่น: office-js#429) แต่ App Router ของ Next ต้องใช้ History API + * ตอน mount ไม่งั้นพัง "window.history.replaceState is not a function" — เก็บตัวจริงไว้ + * ก่อนฉีด script แล้วคืนคืนหลัง office.js โหลด/พร้อม (workaround มาตรฐานของ SPA ใน + * add-in — taskpane เป็น iframe ของตัวเอง Next ใช้ history เฉพาะ SPA state ภายใน) + */ +const nativeHistory: { pushState?: History["pushState"]; replaceState?: History["replaceState"] } = + typeof window === "undefined" + ? {} + : { + pushState: typeof window.history.pushState === "function" ? window.history.pushState.bind(window.history) : undefined, + replaceState: + typeof window.history.replaceState === "function" ? window.history.replaceState.bind(window.history) : undefined, + }; + +/** คืน History API ที่ office.js ลบทิ้ง — idempotent (มีอยู่แล้ว = ไม่แตะ) */ +function restoreHistoryApi(): void { + if (typeof window === "undefined") return; + if (typeof window.history.pushState !== "function" && nativeHistory.pushState) { + window.history.pushState = nativeHistory.pushState; + } + if (typeof window.history.replaceState !== "function" && nativeHistory.replaceState) { + window.history.replaceState = nativeHistory.replaceState; + } +} + /** * โหลด office.js ครั้งเดียวต่อ page เป็น singleton promise ระดับ module — * ห้ามฉีด