M9: online files: the app remembers the files it put online

A file put on a server without the server's key stays its owner's after its
tab closes or the app quits. The app records it with the preferences (server,
id, name, owner token, the owner's links, what others join with; at most 200;
validated when read back) and never shows the token: not in command results,
ui.inspect, logs or debug output.

- Home > Online lists your online files: open one as its owner (a new tab, or
  its tab comes to the front), start and stop sharing, copy the code or link,
  rename on the server, remove from the server (confirmed), forget here. One
  request per server when the section opens; offline and gone states.
- collab.files, collab.openFile, collab.forgetFile; collab.manageFile takes
  its server and token from the record and gains share / unshare.
- Server: Admin owned (a compatible addition within protocol version 2) says
  what became of the files a list of owner tokens owns. Older servers leave
  the list as recorded.
- Tabs mark files in a live session (shared, or open only to you); toasts
  about a file that isn't in front name it; after a crash a recorded file
  reopens from its server as its owner.
- Draft catalogs (de, fr, ja, ko, pt-BR, zh-Hans) translate the 71 strings
  and 5 command labels they lacked and the new ones; es and es-419 follow.
- Docs: collab-protocol, server, mcp, control-protocol, parity pages, gaps,
  ROADMAP.
This commit is contained in:
bflatastic
2026-10-13 01:41:14 +07:00
committed by BFlat
parent 517b1a02ce
commit 501e4a6737
43 changed files with 3554 additions and 130 deletions
+11 -3
View File
@@ -111,7 +111,14 @@ document can't be edited now (`readOnly`: the "View only" or "Publishing" reason
session itself is `engine.execute {command: "collab.peers"}` (sharing with a join code, hosting,
joining and publishing are `collab.share`, `collab.host`, `collab.join` and `collab.publish`, opening invite links `collab.registerLinks`,
see [mcp.md](mcp.md#live-sessions)). The app also joins the invite link it
was started with (`figcraft "figcraft://join?…"`).
was started with (`figcraft "figcraft://join?…"`). `online` is the home screen's Online section:
whether it shows (`open`), your online files as its rows read (`files: [{file, name, detail,
shared, state, hasOwnerToken}]`; never a token or a link of yours), whether the servers are being
asked (`checking`), how many couldn't say (`problems`), and the file whose removal is being
confirmed or renamed (`confirmRemove`, `rename`; Escape closes them); the list itself is
`engine.execute {command: "collab.files"}`. `tabs` lists the open files as the tab strip shows
them: `[{name, live}]`, `live` being `"shared"` (in a live session others get into), `"private"`
(a file of yours on a server, open only to you) or null.
### `ui.pointer {kind, x, y | sx, sy, to?, steps?, shift?, alt?, cmd?, ctrl?, pressure?, pressureTo?}`
@@ -169,10 +176,11 @@ separate calls. Returns `{queued}`.
Invoke a menu item exactly like clicking it (this may open a dialog). Returns `{ok, lastError}`.
### `ui.set {rightTab?, leftTab?, theme?, home?, palette?, mainMenu?, focusRegion?, colorPicker?, variables?, layerFilter?, collapseLayers?, exportPreview?, preview?, presentScroll?, colorProfileDialog?, stylePicker?, stylePickerEdit?, stylePickerView?, iconGallery?, protoEditor?, contextMenu?, contextSelectLayer?, commentOpen?, commentDraft?, commentFilter?, commentSort?, commentSearch?, commentReply?, commentEdit?, presentComments?, devCompare?, devCompareMode?, devCompareSplit?, annotationFilter?, resetFrameStats?, pluginsWindow?, pluginsTab?, pluginConfirm?, pluginForm?}`
### `ui.set {rightTab?, leftTab?, theme?, home?, homeSection?, palette?, mainMenu?, focusRegion?, colorPicker?, variables?, layerFilter?, collapseLayers?, exportPreview?, preview?, presentScroll?, colorProfileDialog?, stylePicker?, stylePickerEdit?, stylePickerView?, iconGallery?, protoEditor?, contextMenu?, contextSelectLayer?, commentOpen?, commentDraft?, commentFilter?, commentSort?, commentSearch?, commentReply?, commentEdit?, presentComments?, devCompare?, devCompareMode?, devCompareSplit?, annotationFilter?, resetFrameStats?, pluginsWindow?, pluginsTab?, pluginConfirm?, pluginForm?}`
Switch panels and modes: `rightTab` `design|prototype|inspect`, `leftTab` `file|assets`, `theme`,
`home` (bool), `palette` (bool: the Actions palette), `mainMenu` (bool, or a top-level menu such
`home` (bool), `homeSection` (`recents` or `online`: which section the home screen shows; opening
`online` asks each server once what became of your online files), `palette` (bool: the Actions palette), `mainMenu` (bool, or a top-level menu such
as `"Plugins"` to open the main menu with it open), `pluginsWindow` (bool: Plugins ▸ Manage
plugins…), `pluginsTab` (`installed|browse`: that window's tab), `pluginConfirm` (a plugin id of the
directory listed last: its install confirmation shows, as its Install button would; `null` closes