aboutsummaryrefslogtreecommitdiffstats
path: root/docs/apps.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/apps.md')
-rw-r--r--docs/apps.md40
1 files changed, 38 insertions, 2 deletions
diff --git a/docs/apps.md b/docs/apps.md
index 1cd6339..ef8cc1a 100644
--- a/docs/apps.md
+++ b/docs/apps.md
@@ -80,6 +80,39 @@ needs — a new app does not get a bespoke prop list. Notable ones:
| `transportRef`, `gekRef` | refs to the live MNP transport and the imported group key | never state — a ref, so reconnects don't force a re-render of every app |
| `mayUpload` | `memberUpload || isNodeAdmin`, computed once | Files' toolbar and Chat's composer both gate on it; a second derivation would eventually disagree with the first |
+### 2b. The same app, rendered by the Search page
+
+Videos, Music and Photos are mounted twice: by `group-page.js` for one group,
+and by `search-page.js` across every group the reader belongs to. The second
+caller passes the same prop shape, and the difference lives entirely on the
+**entries**, in underscore-prefixed fields the group page never sets:
+
+| Field | What it is |
+|---|---|
+| `groupId`, `groupName`, `groupOwner` | which group serves this entry |
+| `_tRef`, `_gRef` | that group's transport and key — read as `entry._tRef \|\| transportRef`, which is why a single-group mount needs no special case |
+| `_connGen` | bumped when that group reconnects; use it as a refetch key so a tile recovers instead of staying a spinner |
+| `_sources` | every group that has this file, after the de-duplication below |
+
+**A file shared by two groups is one entry, not two** (`source-merge.js`,
+`docs/refactoring-search.md`). Entries are folded on their content hash and one
+source is resolved per *unit* — a film, a show, an album — using each app's own
+grouping function to decide what a unit is. Two consequences for a new app:
+
+- if it renders a group name, use **`SourceTag`** from `group-name.js` rather
+ than `entry.groupName`: a merged entry has several groups and must say
+ `N sources` instead of naming one. Pass it the **whole unit** (a show's
+ episodes, an album's tracks), not the entry the card was drawn from — that
+ entry is usually chosen for its thumbnail, and would under-report;
+- if it needs a merge unit key of its own, add a `<name>Units()` helper to
+ `search-page.js` that calls the app's **exported** grouping function. Never
+ re-derive the keys there: a copy keeps agreeing until one of them changes,
+ and the symptom is a show whose episodes stream from two different nodes.
+
+The Files explorer is deliberately **not** merged — there each group is a
+top-level folder, and merging would remove a file from one of them.
+`test_search_files_unmerged.py` refuses a build that changes this.
+
An app that needs **local** state (Files' `selecting`/`sortKey`/`currentPath`,
for instance) owns it itself with `useState`, same as before the split. One
thing worth keeping if you add a tab with a notion of "current location within
@@ -160,8 +193,11 @@ registry, so a newly-registered app gets a checkbox for free.
5. **`webapp.py`'s `_ASSETS`** tuple: add the new file. This is the
cache-busting hash's input list — a file imported by the page but missing
here can change without the served URL changing, which is the exact bug
- class `test_asset_versioning.py` exists for. Forgetting this step is
- silent: nothing errors, a browser just keeps an old copy.
+ class `test_asset_versioning.py` exists for. Forgetting this step used to be
+ silent: nothing errors, a browser just keeps an old copy. It is now caught —
+ `test_every_static_script_participates_in_the_fingerprint` holds `_ASSETS`
+ to every `.js` in `static/` (`sw.js` excepted, unversioned on purpose).
+ Written after `source-merge.js` shipped missing from the list.
6. **Test coverage that scans the file set**: `test_hook_ordering.py`
(`STATIC_FILES`) and `test_transport_contracts.py`
(`test_no_setter_survives_the_state_it_belonged_to`, `SPLIT_FILES`) walk a