feat(files): a Files section over the caller's whole space
Nightly Build / build (push) Successful in 5m36s
Nightly Build / build (push) Successful in 5m36s
Until now file browsing existed only inside a project, and the two memory
stores were reachable only by the agent's tools. `#files` is the general
surface: home, both memory stores, the shared folders and projects the
caller belongs to, plus the read-only skills and docs trees.
The root is virtual, and that is the design. Anchoring at `~` is wrong:
the explorer reads host-side, while `shared/`, `projects/`, `skills/` and
`docs/` are bind mounts inside the container — a page rooted at the home
would show less than the user has with no way to reach the rest, and on
native Linux would show Docker's empty mountpoint stubs, a door that
appears to work and leads nowhere. So level 0 is a synthetic list from the
new `GET /api/files/roots`, serialized from the caller's `UserFs` plus the
two virtual memory roots. It sends `kind`, never a label: labels are copy
and get translated.
`GET /api/files/dir` now answers `{ path, can_write, entries }`, and a
memory path is classified before `resolve_view_path` (which refuses one)
and listed from `memory_docs`: one level derived from the flat key space
by the pure `memory_docs::immediate_children`, over a single query whose
unslashed prefix also spots an exact note as "not a directory". Memory is
read-only from the page — every writer routes through `resolve_view_path`,
and `shared-memory/*` is `@fs_write require` for the agent, so a button
that walks past that rule is a decision of its own.
The explorer moves out of projects into `shared/file-explorer.js`, taking
`root` + `rootLabel` and reading `can_write` from the listing rather than
from its host: writability changes per branch and comes from the same
`UserFs::can_write_to` the server rejects writes with, so the buttons
offered and the writes accepted cannot disagree. Deep-linking needed it
steerable without a two-way binding, hence `rel` in and
`explorer-navigate` out — the event fires only for a click, never for a
`rel` the host set, so echoing it back is a no-op.
The URL carries the agent path of the open folder in one parameter, the
same vocabulary the assistant uses, so a link is shareable and pasteable
into a conversation; which root it belongs to is derived, not stored.
docs/: a new files.md, plus two pages this made false — shared-folders.md
claimed in three places that a shared folder has no explorer, and
memory.md never said a user can now read their own notes.
This commit is contained in:
+36
-20
@@ -8,6 +8,7 @@ export default {
|
||||
'nav.inbox': 'Inbox',
|
||||
'nav.dashboard': 'Dashboard',
|
||||
'nav.projects': 'Projects',
|
||||
'nav.files': 'Files',
|
||||
'nav.tasks': 'Task Manager',
|
||||
'nav.tasks.running': 'Running Tasks',
|
||||
'nav.tasks.cron': 'Cron Jobs',
|
||||
@@ -266,26 +267,40 @@ export default {
|
||||
'projects.share.access.readwrite':'Read & write',
|
||||
'projects.tabs.files': 'Files',
|
||||
'projects.tabs.sharing': 'Sharing',
|
||||
'projects.files.col.name': 'Name',
|
||||
'projects.files.col.created': 'Created',
|
||||
'projects.files.col.modified': 'Modified',
|
||||
'projects.files.col.size': 'Size',
|
||||
'projects.files.empty': 'This folder is empty.',
|
||||
'projects.files.refresh': 'Refresh',
|
||||
'projects.files.drop': 'Drop files here to upload',
|
||||
'projects.files.btn.new_folder': 'New folder',
|
||||
'projects.files.btn.upload': 'Upload',
|
||||
'projects.files.btn.download': 'Download ZIP',
|
||||
'projects.files.uploading': 'Uploading…',
|
||||
'projects.files.action.download': 'Download',
|
||||
'projects.files.action.rename': 'Rename',
|
||||
'projects.files.action.delete': 'Delete',
|
||||
'projects.files.confirm.delete_file': 'Delete "{name}"?',
|
||||
'projects.files.confirm.delete_dir': 'Delete the folder "{name}" and everything inside it?',
|
||||
'projects.files.modal.mkdir': 'New folder',
|
||||
'projects.files.modal.rename': 'Rename "{name}"',
|
||||
'projects.files.modal.name': 'Name',
|
||||
'projects.files.error.name': 'Enter a valid name (no slashes).',
|
||||
|
||||
// ── File explorer (shared component: projects, Files section) ───────────────
|
||||
'files.col.name': 'Name',
|
||||
'files.col.created': 'Created',
|
||||
'files.col.modified': 'Modified',
|
||||
'files.col.size': 'Size',
|
||||
'files.empty': 'This folder is empty.',
|
||||
'files.refresh': 'Refresh',
|
||||
'files.drop': 'Drop files here to upload',
|
||||
'files.btn.new_folder': 'New folder',
|
||||
'files.btn.upload': 'Upload',
|
||||
'files.btn.download': 'Download ZIP',
|
||||
'files.uploading': 'Uploading…',
|
||||
'files.action.download': 'Download',
|
||||
'files.action.rename': 'Rename',
|
||||
'files.action.delete': 'Delete',
|
||||
'files.confirm.delete_file': 'Delete "{name}"?',
|
||||
'files.confirm.delete_dir': 'Delete the folder "{name}" and everything inside it?',
|
||||
'files.modal.mkdir': 'New folder',
|
||||
'files.modal.rename': 'Rename "{name}"',
|
||||
'files.modal.name': 'Name',
|
||||
'files.error.name': 'Enter a valid name (no slashes).',
|
||||
'files.title': 'Files',
|
||||
'files.note.roots': 'Everywhere you can go: your home, your two memory stores, and the folders shared with you. These are the same paths the assistant uses.',
|
||||
'files.back': 'All files',
|
||||
'files.badge.readonly': 'Read-only',
|
||||
'files.error.unknown_path': '"{path}" is not one of your folders.',
|
||||
'files.root.home': 'Home',
|
||||
'files.root.user_memory': 'Personal memory',
|
||||
'files.root.shared_memory': 'Shared memory',
|
||||
'files.root.shared': 'Shared folder',
|
||||
'files.root.project': 'Project',
|
||||
'files.root.skills': 'Skills',
|
||||
'files.root.docs': 'Documentation',
|
||||
|
||||
// ── Project detail ──────────────────────────────────────────────────────────
|
||||
'project_board.back': 'Projects',
|
||||
@@ -1226,6 +1241,7 @@ export default {
|
||||
'common.cancel': 'Cancel',
|
||||
'common.loading': 'Loading…',
|
||||
'common.saved': 'Saved',
|
||||
'common.create': 'Create',
|
||||
|
||||
// ── Shared Folders (blueprint §6) ────────────────────────────────────────────
|
||||
'nav.shared_folders': 'Shared Folders',
|
||||
|
||||
Reference in New Issue
Block a user