Bring the v13 line to parity with v14 (Quests, image upload, bug fixes) - #48
Merged
Conversation
Investigation found v13 and v14 already share the same ApplicationV2 sheet framework (contrary to the assumption that v13 used a legacy FormApplication) — the two lines diverged in features/fixes, not platform. Diffed main against the v14 line's pre-Quest-work state to scope this precisely rather than guessing. Ported wholesale (confirmed no v13-only content lost in each case): - Full Quest feature (this session's finished version, not the half-built one) and Journal support: new quest.hbs/journal.hbs sheets, archivist-api.js CRUD + normalization, config/utils map entries, reconcile-service/journal-manager quest+journal handling. - Both API augments from the v14 branch: local image upload (Character/Item/Faction/Location) and link PATCH. - Sync dialog UX fixes: shift-click multi-select, live progress indicator during sync (ported templates/sync-dialog.hbs + styles/sync-dialog.css to match), per-row error handling with a fail/success count instead of a blanket message, confirm-before- delete. - Bug fixes: markdownToStoredHtml's double-escaping/library-lookup fix, a sidebar tab-ordering fix (insertBefore instead of append, applied to both places it was duplicated), session-summary now markdown-converted before sync like every other entity type. - Dead code: removed the unreferenced scripts/modules/utils.js.bak (confirmed zero references on either line). - New "Quests" tab on Character/Item/Location/Faction sheets, and the Cursor API docs' Quest/Journal/Links section. Deliberately NOT ported: - The Sidebar.TABS removal — v14 dropped it because that dynamic-tab API doesn't work there, but it's the mechanism v13 actually uses for the chat sidebar tab today. Kept v13's registration in both the `init` and `setup` hooks, layered the rest of the v14 file's Quest/ Journal registrations and hooks on top. - module.json stays untouched (1.x / compat 13.x). Included as a side effect of a wholesale file copy (flagged, not hand- picked): world-setup-dialog.js's large diff is mostly an unrelated dead-code removal (a legacy "Step 4 mapping" wizard step already guarded by `if (false && ...)`) that happened on the v14 line before the Quest work — same dead code existed on main, so removing it here is inert cleanup, not a functional change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same fix as the v14 line (projection/*.js is shared, unversioned logic — confirmed byte-identical pre-fix). Project Descriptions is documented as "Append an Archivist section to the most likely description field," but projectDescription() only appended for HTML-flagged slots. For the one plain-text slot in the registry (dnd5e/pf2e Actor system.details.notes, adapter-registry.js html:false) — which becomes the top candidate for actor subtypes lacking a biography field, e.g. dnd5e's vehicle/group types — the code did stripHtml(archivistHtml) with no reference to the field's existing content, silently replacing whatever was there. Matches user reports of losing existing descriptions. Added mergeArchivistPlainSection (merge.js): wraps Archivist content in a recognizable marker, appends it if none exists yet, and replaces only that marked block on future syncs — never touching the rest of the field's content, mirroring what mergeArchivistSection already did for HTML fields. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same fix as the v14 line. Quests were already being auto-imported exactly like Factions/Recaps (_importArchivistMissing() pulls them in unconditionally, no reconcile/selection step), and the count was already computed (count.imp.quests / plan.importFromArchivist.quests) — it just never made it into the summaryRows array the Step 6 table renders from. Added a Quests row identical in shape to the Recaps row. Not porting the matching Step 4 helper-note text update from v14: that note (and the wizard-cleanup rewrite it lives in) doesn't exist in this branch's older world-setup-dialog.hbs, and this branch's Step 6 table is otherwise the same generic summaryRows-driven markup, so the new row renders correctly without it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same fix as the v14 line (these files were wholesale-copied from there during the parity backport, confirmed identical pre-fix). Two real bugs, both regressions from the Quests/image-upload work: 1. The upload-local-image button reused .archivist-edit-toggle's exact absolute-position slot with no offset, rendering directly on top of the edit-mode toggle and making it unclickable. Added .archivist-upload-toggle (right: 48px) so they sit side by side. 2. _onRender fired the grid/quest/actor-item population functions without awaiting them. Verified against Foundry's own core source that _render() awaits _onRender via _doEvent — but since ours wasn't async, that await resolved before population finished. Opening a sheet via a card click in another custom sheet could leave cards populated but tab counts never applied. Made _onRender (base class, plus the Location and Quest overrides) async and properly awaited. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…l work Same fixes as the v14 line (feat/api-augments-v14) — these files were already wholesale-copied from there during the parity backport, confirmed identical pre-fix. Not porting his module.json/compatibility changes or the ask-chat-sidebar-tab.js deletion from the same source branch — that reintroduces the exact incident this project started from (v14-only code with a compat.minimum permissive enough for v13 clients, missing the Sidebar.TABS registration this branch still needs). - sync-dialog.js: journal content was being dropped on import/sync (never checked row.content, where Journal's actual content lives); shift+click range-select got flipped back by the row click handler; unescaped journal names in the delete-confirmation dialog; no folder fallback for journals/quests on pre-migration worlds. Wholesale- replaced with the fixed version, re-added this branch's own relatedEntityRefs hydration needed by the richer quest-linking UI. - world-setup-dialog.js (+ its template): added _updateSyncStatusUI() direct-DOM progress updates to the six always-imported-in-full loops, replacing a full render() per entity. - archivist-sync.js: the quest content-edit realtime hook no longer PATCHes the unchanged quest name to the API on every keystroke commit (renames are already handled by a separate title-sync hook). - archivist-api.js: _normalizeQuestPayload rewritten to a strict whitelist matching QuestCreate/QuestUpdate's extra="forbid" schema, and the keepalive guard is now conditional on body size (Chromium rejects keepalive fetches over ~64KB). - merge.js: stripHtml no longer calls the nonexistent foundry.utils.TextEditor.stripHTML. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: camrun01 <cameron.b.llewellyn@gmail.com>
Same as the v14 line — wholesale-copied (confirmed identical pre-change). Adopts camrun91's _localize(key) helper: tries game.i18n.localize() and returns null (not the raw key) on a miss, so statusLabel/categoryLabel can chain `|| fallback` to the existing hardcoded English strings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: camrun01 <cameron.b.llewellyn@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 17779f13e0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: Cameron Llewellyn <cameron.b.llewellyn@gmail.com>
Populate flags.archivist.questData from the createQuest response so newly created quest sheets show API defaults without waiting for reconcile. Delete campaign_id after shared quest payload normalization in updateQuest so incidental worldId/campaignId inputs cannot 422 QuestUpdate. Co-authored-by: Cameron Llewellyn <cameron.b.llewellyn@gmail.com>
World-setup journal/character/item/location/faction imports were passing API markdown through toMarkdownIfHtml (HTML→text) before storing in Foundry journal pages. Use markdownToStoredHtml to match reconcile and sync-dialog so markdown renders instead of showing literal **bold** etc. Co-authored-by: Cameron Llewellyn <cameron.b.llewellyn@gmail.com>
Reconcile was writing raw markdown with format:2; recap pages need HTML at format:1 so Foundry renders them correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Companion to #47. This backports the finished Quests feature, the image-upload/link-PATCH API work, and the bug fixes from that PR onto
main(the legacy v13 line), so both lines stay at feature parity instead ofmainfalling further behindstaging.Turned out
mainand the v14 line already share the same ApplicationV2 sheet framework — v13 doesn't need a FormApplication rewrite here, just the same feature/fix set applied on top. Diffedmainagainst v14's pre-Quest-work state first to scope this precisely rather than guessing what was safe to port; most of it was a clean wholesale copy of already-reviewed v14 files, verified file-by-file that nothing v13-only was getting lost in the process.What's here
Same feature set as #47 (Quests completion, image upload, link PATCH, the #46-derived bug fixes — see that PR's description for the full list), plus a few things specific to backporting cleanly:
compatibilitystays untouched:minimum: "13.341",verified: "13.351". This branch is v13-only, same asmainis today.Sidebar.TABSregistration (ask-chat-sidebar-tab.js+ theinit/setuphook wiring) — v14 had to drop this because that API doesn't support dynamic tab addition there, but it's the mechanism this line actually needs for the chat sidebar tab. Layered the rest of the v14 file's Quest/Journal registrations and hooks on top of it rather than deleting it.module.json'scompatibility.verifiedwas"13.351"whileminimumwas"14.359"on the pre-work v14 line (verified lower than minimum, which is nonsensical) — looks like the kind of v13/v14 field cross-contamination that likely caused the original v14-breaks-v13 incident this whole effort traces back to. Not present onmainitself, just flagging since it's the same failure mode as the compat-field issue called out in Finish Quests feature, add image upload + link PATCH, fold in review fixes from #46 #47.markdownToStoredHtml's no-library fallback, a sidebar tab-ordering fix (insertBeforeinstead ofappendChild, fixed in both places it was duplicated), session-summary now markdown-converted before sync like every other entity type.scripts/modules/utils.js.bak— an unreferenced stray backup file, confirmed zero references anywhere.Testing
npm run lint: 0 errors. All touched files passnode --check. Same caveat as #47 — no live Foundry pass yet, worth testing both PRs side by side if possible since they're meant to behave identically modulo the v13/v14-specific bits called out above.🤖 Generated with Claude Code
Greptile Summary
This PR backports the completed Quests feature, image upload/link PATCH API support, and several bug fixes from the v14 staging line onto
main(v13). The majority of changed files are clean wholesale ports of already-reviewed v14 code, with v13-specific elements (notablySidebar.TABSregistration inask-chat-tab.js) carefully preserved.reconcile-service.jsfetches and upserts quest journals with fullquestDataflags;world-setup-dialog.jsimports quests during setup;page-sheet-v2.jsaddsQuestPageSheetV2with objectives, progress log, and related-entity drop targets; the RTScreateJournalEntryhook now seedsquestDatafrom the API create response so newly synced quests render without waiting for reconcile.markdownToStoredHtml's no-library fallback corrected (escape first, then apply inline patterns); sidebar tab injected viainsertBeforeinstead ofappendChildfor correct ordering; session summaries now converted withmarkdownToStoredHtmlbefore storage (format: 1) on creation; world-setup import paths all switched fromtoMarkdownIfHtml(no-op on markdown) tomarkdownToStoredHtml.initImageUpload→uploadImageBytes→completeImageUpload) andupdateLinkadded toarchivist-api.js;updateQuestnow deletescampaign_idafter_normalizeQuestPayloadto prevent 422 rejections fromQuestUpdate'sadditionalProperties: falseschema.Confidence Score: 5/5
This PR is safe to merge. All previously flagged issues have been addressed and the backport is a clean, well-scoped port of already-reviewed v14 code.
All three previously raised issues (quest RTS questData seeding, updateQuest leaking campaign_id, world-setup using the wrong markdown converter) are confirmed fixed in the diff. The new quest reconcile path, image upload flow, and link PATCH are all logically sound.
Files Needing Attention: No files require special attention. The most behaviorally complex additions are the QuestPageSheetV2 save/commit path in page-sheet-v2.js and the three-step image upload in archivist-api.js — both follow established patterns cleanly.
Important Files Changed
Reviews (4): Last reviewed commit: "fix: convert reconcile session recap sum..." | Re-trigger Greptile