UI: reuse attachment count and duration formatters #310

Open
opened 2026-09-28 07:32:23 +00:00 by kayg · 2 comments
Owner

Evidence

Two formatting rules are implemented more than once in the UI:

  • packages/ui/src/components/calendar/attachments.ts:82-83 owns attachmentCountLabel(). packages/ui/src/components/composer/DraftStack.svelte:42-43 repeats the singular/plural rule for attachment counts. DraftStack can keep Empty draft for zero items.
  • packages/ui/src/time.ts:368-373 owns formatDuration(). apps/web/src/lib/composer/recorder.svelte.ts:44-46 defines another helper with the same name. The first rounds milliseconds and can show hours; the second floors milliseconds and always shows minutes. The difference can show the same duration differently at a second boundary or after one hour.

The file-size formatter and the memoised date formatter already have one shared owner.

Rule

The reuse gate says duplicated logic is a defect.

Fix

Use the shared attachment label for positive counts. Make the duration display contract explicit, then call one shared formatter from both places or add a named option for the required clock form and rounding rule.

Owner

packages/ui/src/components/calendar/attachments.ts owns the attachment count label. packages/ui/src/time.ts owns duration formatting. The Composer should call those shared helpers.

## Evidence Two formatting rules are implemented more than once in the UI: - `packages/ui/src/components/calendar/attachments.ts:82-83` owns `attachmentCountLabel()`. `packages/ui/src/components/composer/DraftStack.svelte:42-43` repeats the singular/plural rule for attachment counts. DraftStack can keep `Empty draft` for zero items. - `packages/ui/src/time.ts:368-373` owns `formatDuration()`. `apps/web/src/lib/composer/recorder.svelte.ts:44-46` defines another helper with the same name. The first rounds milliseconds and can show hours; the second floors milliseconds and always shows minutes. The difference can show the same duration differently at a second boundary or after one hour. The file-size formatter and the memoised date formatter already have one shared owner. ## Rule The reuse gate says duplicated logic is a defect. ## Fix Use the shared attachment label for positive counts. Make the duration display contract explicit, then call one shared formatter from both places or add a named option for the required clock form and rounding rule. ## Owner `packages/ui/src/components/calendar/attachments.ts` owns the attachment count label. `packages/ui/src/time.ts` owns duration formatting. The Composer should call those shared helpers.
Author
Owner

Consistency-hunt update from current dev at dfb5964a2fcf13dc8b9a50a319eee09bc386f322 (2026-09-30). Both prior duplicates remain: DraftStack.svelte:43 repeats the attachment singular/plural rule from packages/ui/src/components/calendar/attachments.ts:82, and apps/web/src/lib/composer/recorder.svelte.ts:44 has another duration formatter beside packages/ui/src/time.ts:388. A new file-size formatter appears in apps/web/src/lib/mail/MailView.svelte:147; Files already owns formatSize() at apps/web/src/lib/files/model.ts:332. Mail uses 1024-based KB/MB; Files uses decimal units and localized byte wording, so preserve the difference with a named format option if both policies are needed.

Rule: duplicated formatting logic has one owner. Fix: share the attachment and duration helpers, and extend the size helper with an explicit unit policy. Owners: packages/ui/src/components/calendar/attachments.ts, packages/ui/src/time.ts, and the existing Files size helper in apps/web/src/lib/files/model.ts (or promote it once if Mail cannot depend on Files).

Consistency-hunt update from current `dev` at `dfb5964a2fcf13dc8b9a50a319eee09bc386f322` (2026-09-30). Both prior duplicates remain: `DraftStack.svelte:43` repeats the attachment singular/plural rule from `packages/ui/src/components/calendar/attachments.ts:82`, and `apps/web/src/lib/composer/recorder.svelte.ts:44` has another duration formatter beside `packages/ui/src/time.ts:388`. A new file-size formatter appears in `apps/web/src/lib/mail/MailView.svelte:147`; Files already owns `formatSize()` at `apps/web/src/lib/files/model.ts:332`. Mail uses 1024-based `KB`/`MB`; Files uses decimal units and localized byte wording, so preserve the difference with a named format option if both policies are needed. Rule: duplicated formatting logic has one owner. Fix: share the attachment and duration helpers, and extend the size helper with an explicit unit policy. Owners: `packages/ui/src/components/calendar/attachments.ts`, `packages/ui/src/time.ts`, and the existing Files size helper in `apps/web/src/lib/files/model.ts` (or promote it once if Mail cannot depend on Files).
Author
Owner

Consistency hunt on origin/dev 3601719b80a39f712daf07b37879b22929dfffa0 (2026-10-07): both duplicated formatting contracts remain. packages/ui/src/components/composer/DraftStack.svelte:44 still repeats singular/plural attachment wording instead of calling attachments.ts's shared label. apps/web/src/lib/composer/recorder.svelte.ts:52 still floors milliseconds and emits M:SS; packages/ui/src/time.ts:491 rounds and supports hours. Keep the recorder’s clock and rounding contract explicit when consolidating.

Consistency hunt on origin/dev `3601719b80a39f712daf07b37879b22929dfffa0` (2026-10-07): both duplicated formatting contracts remain. `packages/ui/src/components/composer/DraftStack.svelte:44` still repeats singular/plural attachment wording instead of calling `attachments.ts`'s shared label. `apps/web/src/lib/composer/recorder.svelte.ts:52` still floors milliseconds and emits `M:SS`; `packages/ui/src/time.ts:491` rounds and supports hours. Keep the recorder’s clock and rounding contract explicit when consolidating.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal-v0#310
No description provided.