Files: access button inside a shared folder
The listing reports the shared folder you are in; if you manage it, a lock button beside New folder opens its access list above the content.
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
- App mode: live workflows work in ComfyUI's App view. Each person keeps their own graph or App view through live edits, and App inputs sync. Cursors are off in the App view. Workflows saved as Apps (`.app.json`) show with an app icon in Files and in the Live list, and Save keeps them Apps
|
||||
- In the App view, where ComfyUI shows only its own sidebar tabs, RigShare adds **RigShare** and **Files** buttons to that sidebar, with the unread chat badge. They open the panels in a drawer beside it
|
||||
- The Live tab and People show whether each person is in the node graph or the App view, with ComfyUI's own Graph and App icons
|
||||
- Folder access is managed only in the Files tab. *This tab* in the Live tab still says whether the folder is restricted
|
||||
- Folder access is managed only in the Files tab. *This tab* in the Live tab still says whether the folder is restricted. Inside a shared folder you own, its 🔒 sits next to the new-folder button
|
||||
- ComfyUI's own Workflows and Apps sidebar tabs are hidden, since Files replaces them, and their shortcuts open Files. Admin setting `hide_comfy_file_tabs`, on by default
|
||||
|
||||
## 1.1.0 (2026-09-26)
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ Workflows saved as **Apps** (ComfyUI's App mode, `.app.json`) show with an app i
|
||||
|
||||
Click a workflow to open it. The Files tab marks live workflows with a green dot. **From computer** opens a workflow file from your machine, like ComfyUI's own *Open*.
|
||||
|
||||
Hover a row for its actions: **Rename**, **Move to…**, **Delete**, and on a shared folder you own, 🔒 **Who can open it**. The folder button creates a folder. In the Shared tab it creates a shared folder that you own.
|
||||
Hover a row for its actions: **Rename**, **Move to…**, **Delete**, and on a shared folder you own, 🔒 **Who can open it**. Inside a shared folder you own, the same 🔒 sits next to the new-folder button. The folder button creates a folder. In the Shared tab it creates a shared folder that you own.
|
||||
|
||||
## Saving
|
||||
|
||||
|
||||
@@ -252,7 +252,15 @@ class Workspace:
|
||||
entries.append(self._entry(child, name, os.path.isdir(full), kind, key, perms))
|
||||
can_mkdir = role == "edit" and rel not in ("", "users", "shared")
|
||||
entries.sort(key=lambda e: (e["type"] != "folder", e["name"].lower()))
|
||||
return {"path": rel, "role": role, "entries": entries, "can_mkdir": can_mkdir}
|
||||
out = {"path": rel, "role": role, "entries": entries, "can_mkdir": can_mkdir}
|
||||
# Inside a shared folder: which one, and whether this person manages its access.
|
||||
area, folder = self.area(rel) if rel != "@shared" else (None, None)
|
||||
if area == "shared":
|
||||
meta = self.folders.get(folder) or {}
|
||||
out["shared_folder"] = {"path": folder, "name": folder.split("/", 1)[1], "owner": meta.get("owner"),
|
||||
"restricted": bool(meta.get("acl")),
|
||||
"manage": self.can_manage(folder, kind, key, perms)}
|
||||
return out
|
||||
|
||||
def make_dir(self, parent, name, kind, key, perms):
|
||||
"""New folder. In the Shared root it becomes a shared folder you own."""
|
||||
|
||||
@@ -368,3 +368,25 @@ def test_view_mode_in_presence(run):
|
||||
assert next(c for c in rig.hub.clients.values() if c.key == "alice").view == "app", "unknown views are ignored"
|
||||
await alice.close(); await boss.close()
|
||||
run(scenario())
|
||||
|
||||
|
||||
def test_listing_inside_a_shared_folder(run):
|
||||
async def scenario():
|
||||
async with rig_server() as rig:
|
||||
await rig.setup_admin()
|
||||
alice = await rig.add_user("alice", edit=True)
|
||||
bob = await rig.add_user("bob", edit=True)
|
||||
h = rig.http
|
||||
await h.post(rig.url("/rigshare/api/workspace/mkdir"), json={"parent": "@shared", "name": "FaceSwap"}, headers=alice)
|
||||
await h.post(rig.url("/rigshare/api/workspace/mkdir"), json={"parent": "shared/FaceSwap", "name": "old"}, headers=alice)
|
||||
|
||||
async def here(user, path):
|
||||
r = await h.get(rig.url(f"/rigshare/api/workspace/list?path={path}"), headers=user)
|
||||
return (await r.json()).get("shared_folder")
|
||||
|
||||
# The folder you are in, even deeper down, and whether you manage its access.
|
||||
assert await here(alice, "shared/FaceSwap/old") == {"path": "shared/FaceSwap", "name": "FaceSwap", "owner": "alice",
|
||||
"restricted": False, "manage": True}
|
||||
assert (await here(bob, "shared/FaceSwap"))["manage"] is False
|
||||
assert await here(alice, "users/alice") is None
|
||||
run(scenario())
|
||||
|
||||
@@ -161,7 +161,14 @@ export class FilesBrowser {
|
||||
h("button", { class: `rs-fb-crumb ${i === trail.length - 1 ? "current" : ""}`, onclick: () => this.go(c.path) },
|
||||
c.icon ? h("i", { class: `pi ${c.icon}` }) : null, i === 0 && c.icon ? null : c.label),
|
||||
]).filter(Boolean));
|
||||
const shared = this.listing?.shared_folder;
|
||||
this.actions.replaceChildren(...[
|
||||
// Inside a shared folder: its access list, like the 🔒 on its row one level up.
|
||||
shared?.manage && this.mode === "browse" && this.accessEditor ? h("button", {
|
||||
class: `rs-btn rs-btn-icon ${this.accessFor === shared.path ? "active" : ""}`,
|
||||
title: `Who can open "${shared.name}"${shared.restricted ? " (restricted)" : ""}`,
|
||||
onclick: () => { this.accessFor = this.accessFor === shared.path ? null : shared.path; this.render(); },
|
||||
}, h("i", { class: `pi ${shared.restricted ? "pi-lock" : "pi-lock-open"}` })) : null,
|
||||
this.listing?.can_mkdir && this.mode !== "open" ? h("button", {
|
||||
class: "rs-btn rs-btn-icon", title: this.path === SHARED ? "New shared folder" : "New folder",
|
||||
onclick: () => this.newFolder(),
|
||||
@@ -173,6 +180,14 @@ export class FilesBrowser {
|
||||
|
||||
renderList() {
|
||||
const entries = (this.listing?.entries || []).filter((e) => !this.filter || e.name.toLowerCase().includes(this.filter));
|
||||
// The access editor of the shared folder we are in shows above its content.
|
||||
const here = this.listing?.shared_folder;
|
||||
const top = here && this.accessFor === here.path && this.accessEditor
|
||||
? this.accessEditor(here.path, () => { this.accessFor = null; this.reload(); }) : null;
|
||||
if (top) {
|
||||
this.list.replaceChildren(top, ...entries.map((e) => this.row(e)));
|
||||
return;
|
||||
}
|
||||
if (!entries.length) {
|
||||
this.list.replaceChildren(h("div", { class: "rs-fb-empty" },
|
||||
this.filter ? "Nothing matches." : this.path === `users/${this.me}` ? "Nothing here yet. Save a workflow and choose My files." : "This folder is empty."));
|
||||
|
||||
Reference in New Issue
Block a user