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

#114 · Add plugin suites

  • timeline-app
  • pull request
  • plugins

Closes #78. ## Suites A suite (`src/suites.ts`) is `{ apiVersion: 1, id, version, name, description, plugins }`. It carries its plugins' **full definitions** (1–32 distinct plugins, at most 128 KiB), so it installs the same offline, on the desktop and from any server, custom plugins included. Official suites, included in every build: - **Causal factor analysis**: Moment stacks, Moment shapes, Moment colors. - **History education**: Moment icons, Duration backgrounds, Expand on hover, Rich text notes, Headings. **Adding a suite** (`addSuite`) appends the plugins the timeline lacks, enabled, in the suite's order. A plugin already on the timeline stays exactly as it is, including its version and whether it's enabled, and the toast says which were added and which were kept. The 32-plugin limit still applies. ## Editor The Plugins dialog gains **Add suite** and **Create suite**. **Add suite** lists: - the server's library, or the official suites included with the app when there's no server (offline, or a desktop that isn't connected) or the server can't be reached; - each suite's plugins, marking those already installed; - a server chip when a desktop is connected to several servers. It also has **Import suite file…**. **Create suite** packages the timeline's chosen plugins with a name, description and version. From there you can: - **Export suite file**, which downloads a `.suite.json`; - **Publish to library**, when signed in. ## Server - Table `oc_plugin_suites`, with the same versioning as `oc_plugins`. - Publishing: - IDs are namespaced as `u- - `, and versions are immutable (409 on reuse). - Each account may publish 200 versions. - The plugin-publish rate limit and the human check apply, as for plugins. - Storage is tracked through `oc_storage_entries`, so published suites count toward quotas. - Routes: - `GET /api/plugins/suites` and `POST /api/plugins/suites/search` search the newest version of each suite, including by plugin names. - `GET /api/plugins/suites/ / ` reads one version. - `POST /api/plugins/suites/publish` publishes. - They sit under `/api/plugins/…`, so the Next routes and the desktop's allowed API paths already cover them. - The readiness check requires the new table, so run the migration before deploying. - The website's `/plugins` page lists matching suites above the plugins. ## Tests - **Unit tests** (`test/suites.test.mjs`) cover: - the official suites; - validation (empty, duplicate, unknown, invalid plugin, over 32 plugins, over 128 KiB); - slugs; - `addSuite` keeping installed plugins and enforcing the limit; - search and versions; - the HTTP routes without PostgreSQL. - **PostgreSQL** (`test/postgres.mjs`) covers: - publishing refused when signed out (401) and without CSRF (403); - the namespaced ID, and storage increasing; - the 409 on reusing a version, and another account blocked from the namespace; - version 2; - search and detail. - **Browser test** (`test/suites-browser.mjs`) covers: - the official suites without a server, and a server's community suites; - adding History education while keeping a disabled Moment icons; - an already-installed suite showing "Installed"; - create, export, and import into another timeline; - the error for an invalid file. - Passes in Chromium, Firefox and WebKit; the full Chromium and offline suites pass locally. - `test/next-platform.mjs` checks that `/plugins` lists the suites. ## Also: a stored-windows race (found by this PR's CI) The Firefox browser job failed once in `viewport-store-browser`: "the first view was not kept after hiding the page". **Cause:** when a page is shown again, it takes its windows back from storage asynchronously. If it was hidden again before they were back, it stored only the windows it held and deleted the ones still being restored. A quick tab switch could lose stored windows the same way. **Fix:** hiding now waits for a pending restore before storing and releasing. **Verification:** with a 1.5 s delay added to the restore step, the…

Sources

Open #114 · Add plugin suites in the timeline