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

#23 · Search moments and durations in a dialog without moving the view

  • timeline-app
  • pull request

Stacked on #21 (durations), which is stacked on #18. Search results include standalone durations, so this builds on that model. ### Behaviour - **Opening it:** **Search** in the timeline toolbar, or **/** outside text fields. It searches the open timeline's moments and durations by title and notes; a moment also matches through its nested entries, such as stacks. - **Results:** 25 per page, each showing its kind, its time (moments) or extent (durations), and a preview of its notes. **The view does not move while searching.** - **Choosing a result** closes the dialog and moves the view to it. A moment is centred at the current zoom; a duration is fitted with a margin. The marker or band pulses briefly, and nothing else opens. - Every word must match. Search terms are lowercased words of letters and digits (at most eight), so punctuation and operators are never interpreted as query syntax. ### Backends | Timeline | Implementation | | --- | --- | | Server | New `oc_entity_search` table with a stored, weighted `tsvector` (`simple` configuration). Rebuilt with the rational index on every save; `npm run migrate` backfills existing timelines via `oc_timelines.search_version`. Ranked word-prefix matching, scoped to one timeline through the primary key. | | Desktop `.och` | Bounded title/notes scan in the native query, within the existing read budget. Avoids depending on FTS5, which the static macOS/Windows SQLite builds may not enable. ASCII-only case folding (SQLite `lower()`). | | In-memory | Local scan in the browser. | Indexed timelines search the saved version and overlay unsaved edits on the current page. The status then says "includes unsaved edits", and the total is adjusted. ### Also - Duration band elements now persist by duration ID. Previously every render recreated them, so a click landing across a re-render could be lost; I hit this as an intermittent browser-test failure right after Undo. ### Tests - **Unit:** term normalization; in-memory ranking, paging, stacks, durations and Unicode text; HTTP validation of `search` and `duration` queries. - **Rust:** desktop search ranking, nested entries, durations, paging and ASCII case folding. - **PostgreSQL** (`test/search-postgres.mjs`, added to CI): ranked prefix matching, operators treated as text, rebuild on sparse saves, outdated-revision refusal, and backfill. - **Browser** (served and offline): the dialog, paging, the view staying put while searching, navigation and highlighting. - **Desktop:** native search plus the unsaved-edit overlay. - **Locally passing:** all of the above, plus the full unit, Rust, PostgreSQL duration/versioning/core and Chromium browser suites. Fixes #19

Sources

Open #23 · Search moments and durations in a dialog without moving the view in the timeline