First of the intent-driven actions that replace raw-YAML editing as the front
door. Right-click a folder (or the pane) → "Manage access…" → a dialog of
people + friendly levels; the raw .zddc editor is demoted to "Edit raw policy
(.zddc)…" as the advanced escape. Both gated by the same admin authority.
- browse/js/manage-access.js: reads the folder's on-disk .zddc, presents
principals as View / Contribute / Edit / Manage (admins: membership), plus an
"inherit from parent" toggle (uncheck = make private). Save maps levels back
to verbs (r / rc / rwc / admins:), merges ONLY the access bits into the doc
(every other key preserved), and PUTs. Unrecognised verb strings show as
"Custom" and are preserved untouched.
- Menu: "Manage access…" (guided) is now primary; "Edit raw policy (.zddc)…"
is the escape hatch.
- Self-contained modal + CSS; refreshes the listing on save.
Sets the pattern for the remaining operator tasks (role members, display label,
project convert vars, register a party).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Export context-menu offered only md↔docx↔html (a symmetric set), so PDF
— which the server supports only as md→pdf — was missing. The markdown
editor's DOCX/HTML/PDF buttons hardcoded their own list, so the two could
drift.
Introduce a single source of truth in download.js: EXPORT_MATRIX mirrors
zddc/internal/convert.Convert() exactly (md→docx|html|pdf, docx→md|html,
html→md|docx), exposed as download.exportTargets(ext) + download.convertUrl().
The Export submenu and the editor's buttons both consume it, so a .md file now
offers PDF in the menu and the two surfaces can never disagree. PDF stays
markdown-only (no docx→pdf / html→pdf path exists server-side).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an "Export" item to the row context menu with a submenu:
- a folder offers ".zip" (reuses download.downloadFolder; works offline + server)
- an md/docx/html file offers the OTHER two formats, each triggering a
server-side conversion download via the new download.exportFile (builds the
sibling-extension URL and lets the browser pull the converted bytes). File
conversion is server-only, so it's hidden in offline (FS) mode; a zip is
already an archive and gets no Export.
menu-model's toMenuItem now passes a descriptor's `items` through as a submenu
(resolved against the captured browse ctx) instead of only emitting action rows.
Verified: 11/11 browse Playwright specs pass (incl. menu/context + Download ZIP);
a logic harness confirms the per-type submenu contents and that clicks route to
download.exportFile / downloadFolder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Menu refinements per review:
- "Open" now navigates into a folder (rescope); the separate "Navigate into"
item is removed. Zip → expand inline (can't navigate in); file → preview.
Inline expand stays on single-click / chevron / arrow keys.
- "New markdown file" → "New file".
- New folder / New file / Rename / Delete are now HIDDEN when the user lacks
the create/write/delete capability (folded into appliesTo) instead of shown
greyed — a guest gets a lean menu; users who can still see them. New
folder/file also remain on the toolbar.
- "Edit access rules…" is shown only when the user can actually edit them
(admin verb 'a' or subtree/site admin) — hidden otherwise, not greyed.
- Removed "Copy path" / "Copy name" — the info box (hovercard) carries the
name and a clickable URL now.
Info box (hovercard): dropped the on-disk "Path" row; the "URL" is rendered as
a clickable hyperlink (via the existing kvLink helper) — the shareable
reference, openable or right-click-to-copy.
Tests updated: file row omits New folder/file + Copy + Navigate; permission-
gated Rename/Delete are HIDDEN for a read-only server node and PRESENT for a
read/write/delete node (pure menuModel unit). All browse+conflict+diff green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reworks the browse menu/tree interaction into a declarative, contextually
honest model and moves view settings onto a toolbar — the menu is the UI to
the system, so it should be familiar, inviting, and only ever offer what
applies.
New declarative menu model (browse/js/menu-model.js):
- Every action is one descriptor with a TYPE predicate (appliesTo) and a
CAPABILITY predicate (enabled)+tooltip. Row/pane menus are projections over
it; separators are derived from group changes. Designed data-shaped so a
future server-sourced manifest (zddc.zip) can supply/extend it.
- Hybrid visibility: type-inapplicable actions are OMITTED (New folder on a
file, Expand on a file); permission/role/tier-gated actions are SHOWN
DISABLED with a reason — so a lower tier sees what a higher role unlocks.
- Roles are NOT hardcoded: ordinary actions gate on the verbs the server
returns (node.verbs / path_verbs), so any operator-defined role works. Only
the two intrinsically-special tiers are recognised by name — site admin
(is_super_admin) and project/subtree admin (path_is_admin), surfaced as the
"Edit access rules…" item; both come from the existing /.profile/access.
- The headline fix: New folder / New markdown file no longer appear on file
rows (they target a folder or the current dir).
events.js: deletes the ~350-line inline buildTreeRowMenu/buildPaneMenu/
SORT_BY_ITEMS; opens menus via menuModel projections through one openRowMenuFor
/openPaneMenu path shared by right-click, the hover kebab, and the keyboard
menu key (ContextMenu / Shift+F10). Injects action impls via menuModel.configure
to avoid a circular dep. Prefetches the scope /.profile/access (memoised) on
load/rescope/refresh/popstate so menus never fetch at open time.
Discoverability + a11y: a per-row ⋯ kebab (tree.js + new icon-ellipsis sprite,
revealed on hover/selection/focus) opens the same menu; keyboard menu key
supported.
Toolbar: Sort + Show-hidden moved OUT of per-row right-click menus into the
tree-pane toolbar, plus New folder / New file buttons (act on the current dir,
greyed with a reason when create access is lacking). Help copy updated.
Icons: dropped the 3 stray emoji from menu items (consistent, VS Code/Finder
style); only new sprite is the kebab's icon-ellipsis.
Tests: +5 browse specs (file row omits New-folder; folder row shows it; a
read-only server node greys Rename with a "write access" tooltip via a pure
menuModel unit; toolbar Sort/Show-hidden drive state + New buttons present;
kebab and Shift+F10 both open the menu). All 23 browse+conflict+diff green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>