Skip to content

Schema-driven UI and worker dispatch by converter id - #3

Closed
fedyunin wants to merge 1 commit into
feat/kml-to-miffrom
feat/dispatch-ui
Closed

Schema-driven UI and worker dispatch by converter id#3
fedyunin wants to merge 1 commit into
feat/kml-to-miffrom
feat/dispatch-ui

Conversation

@fedyunin

Copy link
Copy Markdown
Owner

Summary

Stops the UI from knowing about individual converters. Worker dispatches by converterId to whatever is in the registry; the renderer builds its options form from each converter's declarative options[] schema. Adding a new format is now: one folder under src/core/converters/, one test fixture, one entry in the registry — and it appears in the desktop app automatically.

Stacked on top of #2.

What changed

Renderer

  • New Converter card with a dropdown of registered converters and a per-converter description line.
  • Options card is now empty in HTML and populated dynamically from the selected converter's schema (boolean → checkbox, enum → select, number → number input, string → text). Saved per converter — switching direction keeps each one's last values.
  • File picker and drop-zone filters use the current converter's inputs.extensions (e.g. .mif/.mid for mif-to-xlsx, .kml/.kmz for kml-to-mif).
  • All converter-specific HTML and JS for the Excel exporter is gone — the same form generator handles both shipped converters.

Worker / IPC

  • worker.js now dispatches converters.get(id).run({inputs, output, options}, ctx). Runs converters.validateOptions() before invocation; surfaces option errors as a fatal error message.
  • main.js exposes converters:list returning a lean serializable view of the registry. selectFiles accepts the current converter's allowed extensions for native dialog filters.
  • preload.js exposes listConverters() and the extension-aware selectFiles(options).
  • convert:start payload moved from {inputMode, inputFolder, selectedFiles, recursive, paintRows, ...} to the contract-aligned {converterId, inputs, output, options}.

Settings (v2 with migration)

{
  "version": 2,
  "language": "en",
  "inputMode": "folder",
  "inputFolder": "...",
  "outputFolder": "...",
  "selectedFiles": [],
  "converterId": "kml-to-mif",
  "converterOptions": {
    "mif-to-xlsx": { "paintRows": true, "skipBlack": true, /* ... */ },
    "kml-to-mif": { "flat": false, "charset": "WindowsCyrillic" }
  }
}

migrate() lifts legacy flat option keys into converterOptions['mif-to-xlsx'] so existing 1.0.x users see no behavior change after the upgrade. saveSettings always stamps the current version so future migrations can branch on it.

i18n

New shared keys (section.converter, field.converter, hint.optionsEmpty); the subtitle and drop hint are now format-agnostic. EN / RU / KK updated. Per-option labels currently come straight from the schema (English) — a follow-up PR can add an optional i18nKey on options without touching the renderer.

Tests

81 passing (75 from #2 + 6 new settings migration tests):

  • defaults are on the current version with the new shape
  • migrate lifts every legacy flat key into converterOptions['mif-to-xlsx']
  • migrate of already-current settings preserves everything and returns a fresh copy
  • migrate returns defaults on garbage input
  • round-trip writes the version field; loadSettings on a v1 file auto-migrates

Renderer is browser-only JS — validated by node --check. Real smoke test is manual:

npm run dev
# Pick "MapInfo → Excel/CSV", convert a folder, confirm output matches 1.0.4
# Switch to "KML/KMZ → MapInfo MIF/MID", convert the Karaganda KMZ, confirm 9 layers / 1854 features

Test plan

  • npm test is green (81)
  • node --check on every JS file
  • manual: open the app, both converters render their options panels from the schema
  • manual: settings.json from 1.0.4 in app.getPath('userData') loads with identical behavior
  • manual: each converter remembers its own options after switching back and forth

Follow-ups

  • feat/clibin/mifkit convert <id> <input> <output> --flag=value over the same registry. Schema validation already covers CLI flag parsing.
  • feat/i18n-options — optional i18nKey on option definitions so option labels can be translated without renderer changes.
  • feat/mif-to-kml — reverse direction (MapInfo → Google Earth).

🤖 Generated with Claude Code

UI and worker now talk to the registry instead of the legacy convert.js
engine directly. Adding a converter is one folder under
src/core/converters/ — the desktop app auto-renders its options panel
from the option schema; no UI changes required to surface it.

Renderer
- New "Converter" card with a dropdown of registered converters and a
  per-converter description line.
- "Options" card rendered dynamically from the selected converter's
  options[] schema (boolean -> checkbox, enum -> select, number ->
  number input, string -> text). Saved per-converter so switching
  direction keeps each one's last values.
- Drop-zone and file picker now filter by the current converter's
  inputs.extensions (e.g. .mif/.mid for mif-to-xlsx, .kml/.kmz for
  kml-to-mif).
- Removed all converter-specific HTML/JS for the Excel exporter; the
  same form generator handles both shipped converters.

Worker / IPC
- worker.js dispatches converters.get(id).run({inputs, output, options},
  ctx) and runs converters.validateOptions() before invoking run.
- main.js: new IPC channel converters:list returns a serializable lean
  view of the registry (id, name, description, io extensions, options).
  selectFiles accepts the current converter's allowed extensions.
- preload.js exposes listConverters() and the extension-aware
  selectFiles(options).
- convert:start payload moved from the legacy {inputMode, inputFolder,
  selectedFiles, recursive, paintRows, ...} bag to the new
  {converterId, inputs, output, options} contract.

Settings
- New format v2: shared top-level (language, inputMode, inputFolder,
  outputFolder, selectedFiles), plus converterId and converterOptions
  keyed by converter id.
- migrate() lifts legacy flat option keys (paintRows, skipBlack,
  combineIntoOneWorkbook, etc.) into converterOptions['mif-to-xlsx']
  so existing users see identical behavior on first launch.
- saveSettings stamps the version on every write so future migrations
  can branch on it.

i18n
- New shared keys: section.converter, field.converter,
  hint.optionsEmpty. Subtitle and drop hint reworded to be
  format-agnostic. English / Russian / Kazakh updated.
- Per-option labels currently come from the schema (English). Future
  PR can add optional i18nKey on options without touching the
  renderer.

Tests: 81 passing (75 + 6 settings migration). Renderer is browser-only
JS so it is not unit-tested here; verified via node --check.

Manual smoke (run by maintainer): `npm run dev`, pick "MapInfo -> Excel/CSV",
confirm the same form as 1.0.4 renders and conversion behavior is
unchanged; switch to "KML/KMZ -> MapInfo MIF/MID", confirm the new
options (flat, charset, recursive) render and a real KMZ converts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fedyunin

Copy link
Copy Markdown
Owner Author

Superseded by #5 after the stacked base chain broke when #1 was merged. All commits from this PR are present in #5.

@fedyunin fedyunin closed this May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant