feat(viewer): Artistic Introduction pages + exporter data fixes (#1420)

Commit: ffdd2a0b6eb55ac63277fc99ef0fab7fefda1966
Date: 2026-07-05 01:29:55 +0200
Author: PascalHavelange

Commit Message

feat(viewer): Artistic Introduction pages + exporter data fixes (#1420)

* feat(viewer): add Artistic Introduction pages; fix exporter data gaps

Ports the legacy "Artistic Introduction" (gai) feature: a splash page
listing themes (e.g. "The Umayyads") and a per-theme page with
Monuments/Objects tabs, a thumbnail grid, and a detail panel showing
per-item captions and curatorial justification text, linking through
to the existing item detail page.

Getting there required two exporter fixes, since collections.json
didn't carry what the feature needs:
- internal_name is now included in the output, the only reliable way
  to identify artintro collections among the many other features that
  reuse the same generic `type` values.
- collection_item.extra (per-item caption/override text) is now
  selected and mapped into a `caption` field per item, instead of only
  exporting bare item ids.

Both fixes exposed a latent bug: parseJson() assumed MySQL JSON
columns came back as strings, but mysql2 auto-decodes them to
objects, so JSON.parse(object) silently threw and returned null.
Fixed in collection-exporter, item-exporter (monument history/patrons,
picture photographer/copyright), and partner-exporter (contact
persons, image credits).

The viewer also works around a handful of legacy translation gaps
where the importer falls back to a synthetic placeholder title
(e.g. "Artintro Page 17") when a language's page_title is empty --
falls back to the English title instead of leaking the placeholder.

* fix(tools): add README to tools

* fix (artistic introductions)

Added [artintro-root-collection-importer.ts](scripts/importer/src/importers/phase-01/artintro-root-collection-importer.ts) — a new `ArtintroRootCollectionImporter`, following the exact same shape as `ThgRootCollectionsImporter`/`ExploreRootCollectionsImporter`/`TravelsRootCollectionImporter`: idempotent (skips if `mwnf3:artintro:root` already exists), creates one "Artistic Introduction" collection as a child of the ISL project collection, with a translation.

Wired it into the pipeline:
- Registered in [phase-01/index.ts](scripts/importer/src/importers/phase-01/index.ts), [importers/index.ts](scripts/importer/src/importers/index.ts), and the CLI's dependency graph in [import.ts](scripts/importer/src/cli/import.ts) — runs after `project`/`language`, before `mwnf3-exhibition`.
- Updated [mwnf3-exhibition-importer.ts](scripts/importer/src/importers/phase-01/mwnf3-exhibition-importer.ts) so the existing artintro root (`mwnf3:artintros:1`) now nests under this new marker collection instead of directly under the ISL project collection — same `mwnf3:artintro:root` backward_compatibility key your exporter fix would key off of later.

**Verified** (type-check clean, lint clean, and dry-run against the real project/target DB via the tunnel — read-only, no writes):
- `artintro-root-collection` alone: correctly finds the ISL project collection and reports it would create the marker.
- `mwnf3-exhibition` with the new parent-lookup logic: no runtime errors.

* refactor(viewer,exporter): detect Artistic Introduction via parent collection

Now that ArtintroRootCollectionImporter creates a dedicated "Artistic
Introduction" marker collection (mwnf3:artintro:root, child of the ISL
project collection), the viewer no longer needs to guess membership
from internal_name prefixes.

- collection-exporter.ts: expose backward_compatibility on each
  collection, so the marker can be resolved by its stable key.
- useInventoryData.js: resolve the artintro root as the marker's child,
  then walk parent_id alone for themes and pages -- no internal_name
  matching left in the detection path.

Requires the pending re-import to create the marker and reparent the
artintro root under it. Until then, the composable resolves no marker,
so the feature degrades gracefully to "not available" (verified: no
console errors, no crash) rather than silently going back to guessing.

* feat(viewer,importer,exporter): add Exhibitions pages

Ports the legacy "Exhibitions" feature: a splash page listing ISL
exhibitions, a per-exhibition splash (intro text + "Introduction" link
+ theme list), an Introduction page (exhibition-level text + directly
attached items), and a theme page (Monuments/Objects-style page tabs,
thumbnail grid, detail panel with per-item captions/justification, and
a multi-variant "detail" selector for items that have curated close-up
sub-images), linking through to the existing item detail page.

Same gap as Artistic Introduction: neither type='exhibition' nor the
mwnf3:exhibitions:{id} backward_compatibility key are project-scoped
in the legacy schema (shared with Baroque Art, Sharing History, THG).
Added ExhibitionsRootCollectionImporter (mirrors
ArtintroRootCollectionImporter) to create an unambiguous "Exhibitions"
marker collection under the ISL project collection; ISL exhibitions
now nest under it while every other project's exhibitions keep nesting
directly under their own project collection, unchanged. Exporter/viewer
resolve it by backward_compatibility with graceful degradation (no
crash) if the marker isn't present yet -- same pattern as artintro,
pending the upcoming re-import.

Also fixes a real, confirmed exporter bug found along the way:
collection_item.extra.details (nested "detail" sub-images -- close-up
variants of the same item, actively used by the Baroque Art project)
was imported into the DB but silently dropped by the exporter. Now
surfaced as a details[] array per item entry.

---------

Co-authored-by: Pascal HAVELANGE <havelangep@hotmail.com>

Files Changed


This documentation was automatically generated from Git commit data.