Skip to content

feat: bundle management in the Tracker UI, collection dialog redesign and browser UX fixes - #99

Merged
simoncodes-ca merged 13 commits into
simoncodes-ca:developfrom
SimonNodel-AI:simponImprovements
Sep 17, 2026
Merged

simoncodes-ca merged 13 commits into
simoncodes-ca:developfrom
SimonNodel-AI:simponImprovements

Conversation

@SimonNodel-AI

Copy link
Copy Markdown
Collaborator

Summary

Bundles become a first-class object across core, API and the Tracker UI, the collection dialogs get a redesign, and a handful of browser UX fixes land alongside. Twelve commits, all conventional-commit style.

Bundles end to end

core — Bundles were generate-only and CLI-shaped. New planBundle runs a dry run that never writes and reports the files it would produce, keys per locale, key conflicts and one worked example key. validateBundleDefinition returns every problem at once instead of throwing on the first. Config-file CRUD (add/update/deleteBundleDefinition) validates inside the updater and preserves key order. generateBundle gains an onProgress callback and keysPerLocale; generateBundleTypes accepts an unsaved definition.

domain — Pure JavaScript identifier validation for the generated token constant name, reachable from CLI, API and UI.

data-transfer — Bundle DTOs: definition, create/update payloads, dry-run request and result, and the generation job snapshot. LingoTrackerConfigDto now carries bundles and projectName, which the config mapper used to drop.

api — POST/PUT/DELETE /api/bundles, POST /api/bundles/dry-run, and POST /api/bundles/:name/generate, which answers 202 with a job id polled via GET /api/bundles/jobs/:jobId. Runs are sequential through a promise queue with eviction of finished jobs, mirroring the translation job shape.

tracker — The collections page becomes a split view with a sticky column of bundle cards. A bundle can be created, edited, deleted and generated alone or all together; progress and a result strip render inside the card. Hover or focus draws a coral connector from each consumed collection into one port on the bundle. The bundle form is a master-detail dialog with a live preview column driven by a debounced dry run, folding responsively under 1200px and 800px. Run state is mirrored to session storage so a result survives the dev-server reload that generating the tracker's own bundle triggers.

Collection dialogs

Create and edit dialogs move from a flat stack of fields to three labelled groups (Source, Locales, Options). Locales are pill chips with a BASE tag; the base is set by clicking while creating and locked while editing. Read-only is a switch row with the node_modules auto-detection explained inline. Tags and protected terms sit behind a disclosure with counts. Adds 17 collections.dialog.* resources.

Browser fixes

  • Compact rows show one locale consistently: default to base, persist the selection, simpler annotations.
  • Indexing state shows while cache status is still loading.
  • Locale values can be selected and copied. Double-click on a value no longer opens the editor; it is plain selectable text with a palette-tinted selection in both densities. The header, drag glyph and labels still open the editor, as do E, long-press and the actions menu.

Design records

DESIGN.md with a design.json sidecar derived from shipped tokens, plus surface briefs for the collection dialog, collections page and bundle form. Records the Connector Rule, the quiet third button rung, and equal-row collection cards. Impeccable mock and review captures are gitignored.

Testing

  • Unit tests added or updated across core, api and tracker, including the new double-click and selection coverage.
  • Tracker lint clean.
  • Bundle flows and the copy behaviour verified manually in the running app in both densities.

🤖 Generated with Claude Code

SimonNodel-AI and others added 13 commits September 14, 2026 09:24
- Initialize collection cache status as `not-started`
- Add coverage for the pending cache status request
- Default compact mode to the base locale
- Persist compact locale selections and update filter labels
- Simplify compact row annotations and styling
Replace the flat stack of outlined fields with three labelled groups
(Source, Locales, Options). Locales become pill chips with a BASE tag;
clicking a chip sets the base while creating, and the base is locked
while editing, including a base inherited from the global config.
Read-only is a switch row with the node_modules auto-detection explained
inline, and tags and protected terms sit behind a disclosure row with
counts. Header, top rule and footer match the translation editor.

Adds 17 collections.dialog.* resources via the CLI; other locales are
left as new entries for translation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add the first token-bearing DESIGN.md with its design.json sidecar,
derived from the shipped tokens and components, plus the surface brief
holding the collection dialog's direction contract.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bundle type generation lets the caller name the generated token constant,
which has to be a valid JavaScript identifier. The check is a pure regex
over a string, so it belongs in domain where the API, the CLI and the
Tracker UI can all reach it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bundles were generate-only and CLI-shaped. Three additions open them up to
the API and the Tracker UI without changing what the CLI does:

- planBundle: a dry run that never writes. Returns the files it would
  produce, whether each already exists, keys per locale, key conflicts and
  one worked example key, so a form can show the consequences of a
  definition before it is saved.
- validateBundleDefinition: returns every problem with a definition rather
  than throwing on the first, so a form can mark all of its fields at once.
- addBundleDefinition / updateBundleDefinition / deleteBundleDefinition:
  config-file CRUD that validates inside the updater and preserves key
  order.

generateBundle grows an optional onProgress callback and reports
keysPerLocale, which is what lets a caller drive a progress bar and a
result summary. generateBundleTypes now accepts the definition it should
use instead of always reading it back out of the config, so a dry run can
type-check a definition that has not been saved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contracts for the bundle endpoints, shared by the API and the Tracker UI:
the definition itself, create/update payloads, the dry-run request and
result, and the generation job snapshot. Plain interfaces with locally
declared unions, so the browser never has to reach into core.

LingoTrackerConfigDto also gains bundles and projectName; the config
mapper was dropping bundles entirely and the UI has no other source for
the served project's name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
POST/PUT/DELETE /api/bundles for the definitions, POST /api/bundles/dry-run
for a plan of an unsaved definition, and POST /api/bundles/:name/generate
which answers 202 with a job id that GET /api/bundles/jobs/:jobId polls.
Generation writes files and can take a while, so it follows the same
job-and-poll shape as translation, with a promise queue that keeps runs
sequential and eviction of finished jobs.

GET /api/config now carries bundles, which the mapper used to drop, and
projectName from the API process's working directory.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The collections page becomes a split view: collections on the left, a
sticky column of bundle cards on the right. A bundle can be created,
edited, deleted, generated on its own or with every other one, and its run
reports progress and then a result strip inside its own card, so the
developer never leaves the page to find out what was written.

Hovering or focusing a bundle draws a coral connector from each collection
it consumes into a single port on the bundle card, so several inputs
visibly converge on one output. The connector layer sits behind the cards,
which lets a line cross the inner column and re-emerge rather than
scribbling over another card's content; the lines stand down once the
layout stacks and there is no gutter to route through.

The bundle form is a master-detail dialog: a sections rail, the form
itself, and a live preview column driven by a debounced dry run that shows
the files the definition would write, the counts, and one worked example
key. Under 1200px the preview folds into a disclosure at the bottom of the
pane and under 800px the rail becomes a horizontal strip.

Run state is mirrored to session storage. Generating the tracker bundle
rewrites the Tracker's own i18n assets, which reloads the dev server page
mid-run, and without the mirror the result strip vanished the moment it
was earned.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Surface briefs for the collections page and the bundle form dialog, plus
the DESIGN.md entries the build settled: the bundle card and its result
strip, the segmented control, the master-detail dialog, and the rules that
came out of the polish pass.

The Connector Rule replaces the Hover-Link Rule: a relationship is drawn
from each input's edge into one port on the output rather than stated by
dimming everything it excludes. Buttons gain a quiet third rung, because
frequency should set prominence and a section's create action is not
automatically its loudest. Collection cards move to equal rows, since a
card is an identity rather than a measurement.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ning the editor

Double-click on a translation row opened the edit dialog from anywhere on
the card, which collided with the OS word-select gesture people use before
Cmd+C. Values in both densities (compact value, base and locale values in
full view, and the note) are now plain selectable text with a text cursor
and a palette-tinted selection. Double-click on the header, drag glyph or
labels still opens the editor, as do E, long-press and the actions menu.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@simoncodes-ca
simoncodes-ca merged commit 737d031 into simoncodes-ca:develop Sep 17, 2026
1 check passed
@lingo-tracker-release

Copy link
Copy Markdown

🎉 This PR is included in version 0.19.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants