timescale.info
Sign inSign up

How OpenChronology was built

Every merged pull request of openchronology/timeline-app, its first week of commits and its releases; and before them the 2020 PureScript editor, from snapshots of its deleted repositories in the Wayback Machine. Written to this server through the HTTP API.

327 moments · 2020-03-09T00:15:08Z CE – 2026-11-02T20:11:21Z CE · by @athan · @athan

#21 · Make durations first-class entities with fixed or moment-anchored endpoints

  • timeline-app
  • pull request

Stacked on #18, since duration endpoints reuse its date/time dialog. GitHub will retarget this to `main` once #18 merges. Durations are now entities in their own right instead of links stored inside a start moment's metadata. ### Model - **Format:** a top-level `durations` array. Each entry is `{id, start, end, metadata}`, and each endpoint is an exact time string or `{"moment": " "}` that **follows that moment**. Fixed and anchored endpoints can be mixed. - **Legacy links convert on read.** They become durations anchored to both of their original moments, so existing timelines behave as before. This applies to `.ochx`, `.och`, server timelines, history and merges. New saves write only the new format. - **`npm run migrate` converts stored server timelines once**, without changing their `updated_at`. Immutable history snapshots are left untouched and convert when read. - **Deleting a moment no longer deletes its durations.** Until the deletion is saved they stay anchored, so undo restores them. When saved or exported, that endpoint is fixed at the moment's last time. ### Storage - **Browser, PostgreSQL and SQLite** each build an exact interval tree over the new definitions, resolving anchors to their moments' times. - **PostgreSQL** stores each definition on its interval-index row (new `definition` column plus an index on the duration ID). - **SQLite** uses a constrained `durations` table: exactly one of time/moment per endpoint, and times must be canonical rationals. - **Opening a duration** fetches its full definition through a new `duration` query, on both the HTTP API and the native bridge. - **Sparse saves** (server and desktop) send `durationChanges` next to the moment changes. A moment deleted in the same save pins the durations that followed it. - **Merges** compare durations by ID and field, like moments, and pin anchors whose moments the merge deletes. - **Search text** includes duration titles and notes. - **Browser-copy limits** count durations. ### UI - **Creating:** **+ Duration** in the toolbar, or **New duration starting here** in a moment's details. - **Opening:** click a band, a duration listed in a moment's details, or its hover card. - **The duration dialog** edits the title, notes, plugin fields and extra metadata. Each endpoint is either **Fixed time**, which uses the Gregorian date/time dialog, or **Follows a moment**, chosen from a list loaded 25 moments at a time, with **Open moment** to jump to it. - **Undo/Redo** covers creating, editing and deleting durations. ### Plugins - **New optional `targets` field** in plugin manifests (`moments` and/or `durations`). - **Colors and hover cards apply to durations by default.** This also covers older saved manifests. - **Stacks, shapes, sizes, icons and summary expansion stay moment-only.** ### Tests - **Unit:** new duration tests cover resolution, pinning and undo, legacy conversion, validation, interval pruning, sparse overlay/patch/apply on both client and server, save rebasing, merges, and plugin targeting. - **Rust:** legacy conversion, anchored bands, sparse duration changes and anchor validation. - **PostgreSQL:** standalone definitions, pinned deletion, immutable history, and migrating real legacy-shaped rows. - **Browser:** the duration-dialog flow, hover cards, the pin-then-undo behaviour, and the desktop sparse path, where a duration is opened by ID and saved as a patch. - **Run locally and passing:** 165 unit tests; 16 Rust tests; the converter contract; every PostgreSQL suite except `sql-oracle`, which needs the database on the same host and runs in CI; and the Chromium served, offline and desktop-cache browser suites. Fixes #20

Sources

Open #21 · Make durations first-class entities with fixed or moment-anchored endpoints in the timeline