1 Commits
Author SHA1 Message Date
Nariman Jelveh 1b2cf27926 Restore missing projects, and stop the project list losing them (#177)
* Restore missing projects, and stop the project list losing them

A project is its chat file plus its app directory, but the sidebar lists only what chat-history/chat-list.json names. Three ways an entry was lost while the files stayed intact:

- A project created (or renamed, or pinned) while a list write was in flight was recorded as synced. The next save read it as deleted in another tab and dropped it.
- A rebuild from the chat files skipped any file it could not read at that moment, then saved the result.
- A save whose read of the list failed wrote this tab's list over whatever was on disk.

Settings has a new Projects tab (/?settings=projects) that looks for chat files no entry names and, when asked, adds their entries back. It only adds list entries, after saving and confirming a copy of the list.

* Keep keyboard focus in Settings while looking for and restoring projects

The Look and Restore buttons were disabled while they worked, which dropped keyboard focus to <body>, out of the dialog. Restoring then removed the focused Restore button, with the same result. They are aria-disabled while waiting, as the app's other busy buttons are, and focus returns to the Look button when the results are rebuilt.

* Let the Settings tab strip scroll on a phone

With a fourth tab the strip was wider than a phone screen: the Projects tab was cut off and the whole dialog scrolled sideways. The strip now scrolls on its own, tabs stay on one line, and the selected tab is brought into view, including when a link opens Settings on it. Desktop rendering is unchanged.

* Stop retrying every chat file when reads are failing across the board

Each retried read costs a second and two more requests. Rebuilding the list from the chat files while offline or throttled retried every file: with 300 projects, boot waited five minutes on it and made three times the requests. After two files have failed despite their retries, the rest of a pass are read once. Completing unverified entries in the background stops at the first file that still can't be read, and tries again at the next load.

* Keep a session's own entry over a stand-in when the list loads late

When boot could not load the list, the first save loads it. If that late rebuild could not read the file of a project made in the meantime, its stand-in entry replaced the complete one already in memory, and the project's next save took the stand-in's title and pin for its own.

* Record the synced list without parsing the written text back

The save parsed its own output to remember what it wrote, which made that step about half again as slow at 500 projects. The same map is now built from the list in the same tick the text is serialized, before the write is awaited, at the cost it had before. Adds a test that a rename or a new project made during a write survives the next save.

* Show the missing projects in one scrolling list, with Restore above it

The list had its own scroller inside the dialog's. With more than a handful of projects that cut the last row and the note under the button off, and a list with nothing focusable in it can't be scrolled by keyboard in every browser. The list now scrolls with the dialog, as the server list does, and the Restore button sits above it so it never ends up below the fold.

* Say so when a Settings link can't open Settings

If the module Settings is built on never finished loading, a /?settings= link waited fifteen seconds and then did nothing. It now opens Settings anyway, which reports that it isn't ready the same way its toolbar button does. Adds tests that run the link handler.

* Say where restored projects actually land in the sidebar

The message said restored projects were at the top of the sidebar. Once anything is pinned the sidebar is split into Pinned and Recent, and a restored project goes to the top of whichever its own pin puts it in.
2026-11-12 18:06:09 -07:00