Skip to content

feat(UI): import preview page with entity diff and normalisation decisions #113

Description

@pskillen

Problem

Import today stops at aggregate counts in a confirm modal (previewImportMergeImportMergeReport with added/updated/unchanged/removed per entity type). Operators cannot see which channels, zones, contacts, talk groups, or RX group lists will land in the project, what field-level changes merge would apply, or what normalisation decisions the adapter made before merge.

Flow Today Gap
New project (Home → ImportDropzone) Parses files and creates project immediately No preview step; no continue/cancel
Active project (ImportIntoActivePanel on Import & export) Modal with file summary + count lines No per-entity list; no field diff; no visibility into merge heuristics

#58 shipped merge/overwrite with a lightweight confirm modal and explicitly deferred field-level diffs to a follow-up. This ticket is that follow-up, expanded to both import entry points and future import normalisation features.

Intended outcome

A dedicated import preview step in the import workflow — a route or full-page panel (not only a modal) — that runs before any codeplug is created or mutated. The operator reviews what will happen, then continues or cancels.

Preview content (all adapters)

For the selected vendor format / adapter, show a structured preview of the parsed import result before apply:

Section Contents
Files Recognised, skipped, and error files (existing ImportResult messages)
Channels List of channels to import — name, mode, frequencies, key refs
Zones Zone names + member channel names (resolved where possible)
Contacts / talk groups / RX group lists Names and membership summaries
Warnings Unresolved zone members, parse warnings, profile-specific notes

Adapter-agnostic UI: entity shapes come from internal ImportResult / parsed models, not vendor column names in the preview layer.

Normalisation decisions (show when applicable)

When import adapters apply best-effort collapse heuristics, the preview must surface what was decided — not silently merge:

Feature Issue Preview should show
Multi-mode channel merge #46 e.g. "Merged GB7GL + GB7GL DMR → one multi-mode channel (FM + DMR)" or "Left as 2 separate channels (ambiguous)"
Multi-talkgroup channel collapse #36 e.g. "Collapsed GB7XX TG235 + GB7XX TG2351 → one logical channel with 2 talk groups"
Other adapter warnings Any ImportMessage with severity warning tied to a decision

Decisions belong in ImportResult (or a sibling ImportPreview type) at the import boundary — the UI only renders them.

Merge / overwrite diff (active project only)

When importing into an existing codeplug with merge or overwrite mode, show the diff that would be applied against the active project:

Change type Per entity Detail level (v1 target)
Added Channels, zones, contacts, TGs, RGLs Name + summary fields (mode, freqs)
Updated Same Name + changed fields (field-level diff where importEntityCompare detects inequality)
Removed Same (overwrite mode) Names of rows that will be dropped
Unchanged Collapsed by default Expandable count

Reuse / extend previewImportMerge and importEntityCompare.ts to return entity-level change lists, not only EntityImportStats aggregates.

For overwrite, clearly warn which entire entity arrays will be replaced (existing behaviour) and list removed names.

Workflow integration

flowchart TD
  Drop["Drop files / folder"] --> Parse["importFiles → ImportResult"]
  Parse --> Preview["Import preview page"]
  Preview --> Cancel["Cancel — no mutation"]
  Preview --> Continue["Continue"]
  Continue --> NewProj["importNewProject (Home)"]
  Continue --> ActiveMerge["applyImportToActive (Import & export)"]
Loading
  1. New codeplug from import (Home) — after parse, navigate to preview with parsed payload in session/state; Continue creates the project; Cancel returns without side effects.
  2. Merge / overwrite (Import & export) — after parse + mode selection, navigate to preview showing diff vs active codeplug; Continue calls applyImportToActive; Cancel discards pending import.

Replace or supersede the current ImportIntoActivePanel confirm modal with the preview page (modal may remain for trivial no-change cases if desired).

UX notes

  • Preview is read-only — no inline editing of import rows in v1.
  • Group by entity type; filter/search for large codeplugs.
  • Show merge mode (merge vs overwrite) prominently on active-project preview.
  • "No changes" path: short message + Close (idempotent re-import).

Affected

Notes / dependencies

  • Builds on #58 (active import + previewImportMerge) and #7 (adapter registry).
  • Pairs with #46 and #36 — preview must expose their merge/collapse decisions when those features ship; design the ImportDecision shape now so adapters can populate it incrementally.
  • Vendor boundaries: diff compares internal model fields; wire column names stay in adapter/reference docs only.
  • Privacy: parsed import stays in browser memory / session until Continue; never commit operator exports.

Out of scope

  • Editing import rows on the preview page (change in CRUD after import instead).
  • Three-way merge or conflict resolution UI (imported values win on update).
  • Undo after Continue (operator re-imports a backup).
  • Export preview (separate concern).

Workflow note

Branch from origin/main, atomic conventional commits (preview data layer → page UI → wire Home + active flows → tests/docs), PR linking Closes #N. Pair with docs/features / progress-tracking skills for multi-slice work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquality-of-lifefeature to improve the QOL of the person making a codeplugstretchStretch objectives - high value, but high work required

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions