#420 · A timeline can open separated by default, by tags or by relationships (#416)
- timeline-app
- pull request
Closes #416 Someone who can edit a timeline can now save a **default view**: a separation by tags, or by **Separate related** / **Separate all connected**. Readers, embeds and shared links open the timeline that way, and so do imported `.ochx`/`.och` files, desktop files and browser drafts. **Rejoin** still returns to the whole timeline. This PR doesn't depend on #415 (separated arcs), and the two branches merge cleanly. With both merged, a timeline that opens separated also shows its arcs between the tracks. ## Where it lives It is a timeline-level setting in the document, next to `title`, `tags` and `image`, so it travels with everything that carries settings: saves, `.ochx`/`.och` exports, forks, copies, merges, pull requests, saved history and drafts. ```json { "view": { "separation": { "tags": ["war", "trade"] } } } { "view": { "separation": { "related": { "moment": "launch" }, "depth": "all" } } } ``` - **Validation** (`src/default-view.ts`, `validateTimelineView`): - only `separation`; - tags normalized like entity tags (1–40 tags, 1–64 characters each, no commas); - or an entity reference (as relationship ends name one) with `depth` `direct` or `all`. - Anything else is refused on save or import. - The entity may not exist (it may have been deleted since). It is kept, and the timeline then opens whole, quietly. - Only the separation is stored. The bar's label is the entity's title, read when the timeline opens. - **Server:** a new `oc_timelines.view jsonb` column, handled like `image`. Saves, rebuilds and sparse saves (`applyIncrementally`) write it; `timelineSettings`, snapshots and branch documents read it. Forks copy it (`TIMELINE_INDEX`). It is in the history settings, merges (`SETTINGS`, so save-merge too), retention's saves and the log writer's settings. `GET /api/timelines/:id` returns it, like the other columns. - **Desktop:** `Document.view` in `native-store`, stored in the `.och` file's `timeline_extras` JSON (`{"tags","assets","view"}`) and passed through `och-convert`. Sparse saves keep it. A new `moment` query by ID alone, like the server's, looks up the entity's title. - **Editor:** `TimelineIndex.view` is in `document()` and the sparse-save settings (`SETTING_KEYS`, with conflict naming "The default view"), browser drafts' settings records, and the pull request diff's settings list. - **OpenAPI:** a `TimelineView` schema; `view` on the Document, TimelineSettings and TimelineMetadata schemas. ## UI - **Separation bar** (for those who can edit the timeline, not in View mode): - **Make this the default view** when the separation shown isn't the default; - **Clear default view** when it is; - for everyone, a note: "This is the timeline's default view: it opens this way for everyone" (or "…once saved" while unsaved on a server or desktop timeline). - **Separate by tags dialog:** when there is a default, it says what the timeline opens separated by, and editors get **Clear default view**. - Setting or clearing it is a settings change like the title or tags. A browser draft keeps it at once. A server or desktop timeline needs a save, as before: rejoin (the tracks are read-only), then save. The toast says so. - A separated timeline now keeps its own title and moment count. Before, the heading said "Timeline comparison · 2 timelines", which readers would now see first. ## How it fits with the rest - **Reloads:** a server timeline's tab already remembers its view (#128). If the tab stored a view, it wins, separated or rejoined. Otherwise (a new tab, a shared link) the default applies. So a reader who rejoins and reloads stays rejoined. - **Links to a moment, duration or search** (`/moments/ `, `#moment/…`, `#duration/…`, `#search/…`) open the whole timeline with that event's details or the search, as they already skipped a stored separation: they name something to show and open, and separated tracks are read-only. A range link (`#view/…`) opens the default view over that range. - **Comparisons** of timelines igno…