Skip to content

🔧 PUT-1590: Mark shared items in the file listings - #3646

Merged
jfcastro92 merged 7 commits into
juancastro/put-1585-share-flag-in-readdir-shared-users-in-statfrom
juancastro/put-1590-sharing-shared-files-are-not-different-than-regular-files
Aug 26, 2026
Merged

🔧 PUT-1590: Mark shared items in the file listings#3646
jfcastro92 merged 7 commits into
juancastro/put-1585-share-flag-in-readdir-shared-users-in-statfrom
juancastro/put-1590-sharing-shared-files-are-not-different-than-regular-files

Conversation

@jfcastro92

@jfcastro92 jfcastro92 commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #3644 (PUT-1585), which is where is_shared comes from. Base branch is that one, not main.

What this does

A shared file looked exactly like a regular one. The data to tell them apart arrived with the readdir/stat share flag; nothing rendered it.

A blue dot on the item's icon, lower-right, in both listings:

File Change
UI/UIItem.js marker inside .item-icon — desktop, explorer windows, file dialogs
UI/Dashboard/TabFiles.js same marker in the dashboard's own row markup
helpers/sharedBadge.js (new) has_direct_share(shares) + mark_item_shared(path, on)
UI/UIWindowShare.js, UI/Dashboard/UIShareModal.js hook the marker into each dialog's single render(), so a grant or revoke updates it without waiting for a re-listing
helpers/refresh_item_container.js, helpers/apply_item_added_to_containers.js pass the flag through when building items
css/style.css, css/dashboard.css 9px on the desktop's 45px icons, 7px on the dashboard's 24px rows

The string was already in the tree and unused — item_shared_by_you ("You have shared this item with at least one other user"), present in 40 locales. No new i18n key.

Design notes

  • On the icon, not in the badge cluster. .item-badges is pinned to the row's top-left in the dashboard, not to the icon, so a badge there could never sit on the file. Anchoring to .item-icon keeps the marker on the corner at both icon sizes.
  • A dot, not a glyph. At 7–9px the two-person icon is an illegible smudge; colour is the signal the ticket asked for. The white ring is what keeps it visible against both a light row and a dark icon.
  • Inherited access is not marked. It is a state of the folder that was shared, so marking every file inside would repeat one fact across hundreds of rows — the backend flag is direct-only for the same reason.

Validated in a running local Puter

Playwright against npm start: one shared and one plain item of each kind, badge state read from the rendered DOM. Nothing clicked between the share and the read.

Item data-is_shared Marker
shared file 1 visible
plain file 0 hidden
shared folder 1 visible
plain folder 0 hidden
system folders (Desktop, Documents, …) 0 hidden

Captured in both surfaces — the dashboard's Files list and the classic desktop's icon view. GUI suite: 351 passing, including 5 new cases for has_direct_share (direct, inherited-only, mixed, unclaimed invite, empty).

Worth knowing before testing this on a deployment

The GUI loads puter.js from the CDN (https://js.puter.com/v2/), not from a local build, so the marker stays hidden until #3644's SDK change is publishedis_shared arrives as null until then. The backend wire is already correct (/fs/readdir returns isShared: true); it is purely the SDK in the page being the published one. The test routes that URL to src/puter-js/dist/puter.dev.js, the way the repo's own browser runner does.

Not verified

The live update when sharing from a dialog — the marker appearing without a re-listing. It is a one-liner in each dialog's single render() funnel and has_direct_share is unit-tested, but I did not drive the dialog through the UI.

A shared file looked exactly like a regular one. The data to tell them
apart arrived with the readdir/stat share flag; nothing rendered it.

Adds the badge to both listings — UIItem (desktop, explorer windows,
file dialogs) and the dashboard's Files rows — fed from is_shared, and
keeps it in step with the share dialogs: both funnel every grant, mode
change and revoke through one render, so the badge follows without
waiting for a re-listing.

Inherited access is deliberately not badged. It is a state of the folder
that was shared, so marking every file inside would repeat one fact on
hundreds of items; the backend flag is direct-only for the same reason.

The icon (owner-shared.svg) and the strings (item_shared_by_you, in 40
locales) were already in the tree, unused — only the wiring was missing.
The blue ring is doing the work: list view shrinks badges to 8px, where
a glyph is illegible and the white circle the sibling badges use
disappears into the row.
@jfcastro92

jfcastro92 commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

Validated in a running local Puter

Playwright against npm start: created one shared + one plain item of each kind, then read the rendered badge state. Nothing was clicked in the browser between the share and the read.

Item data-is_shared Badge
shared file 1 visible
plain file 0 hidden
shared folder 1 visible
plain folder 0 hidden
system folders (Desktop, Documents, …) 0 hidden

Tooltip resolves to "You have shared this item with at least one other user." (item_shared_by_you, already present in 40 locales).

Screenshots

put-1590-icon-crop put-1590-list-crop put-1590-list-view

GUI suite: 351 passing, including 5 new cases for has_direct_share — direct share, inherited-only, mixed, unclaimed invite, and empty.

Not verified

The live update path — sharing from the dialog and watching the badge appear without a re-listing. It is a one-liner in each dialog's single render() funnel and has_direct_share is unit-tested, but I did not drive the dialog through the UI.

Deliberate omission

Inherited access is not badged. It is a state of the folder that was shared, so marking every file inside would repeat one fact across hundreds of rows — the backend flag is direct-only for the same reason.

@jfcastro92 jfcastro92 changed the title Mark shared items in the file listings :style: PUT-1590: Mark shared items in the file listings Aug 26, 2026
@jfcastro92 jfcastro92 changed the title :style: PUT-1590: Mark shared items in the file listings 💄 PUT-1590: Mark shared items in the file listings Aug 26, 2026
@jfcastro92 jfcastro92 changed the title 💄 PUT-1590: Mark shared items in the file listings 🔧 PUT-1590: Mark shared items in the file listings Aug 26, 2026
@jfcastro92
jfcastro92 requested review from Salazareo and jelveh August 26, 2026 15:01
Review feedback: too big, and in the wrong place. It sat in the badge
cluster, which the dashboard pins to the row's top-left corner rather
than to the icon — and at 12px it dominated a 24px row icon.

Now a dot on the icon itself, lower-right: 9px on the desktop's 45px
icons, 7px on the dashboard's 24px rows. Anchoring to .item-icon rather
than to the badge cluster is what keeps it on the corner at both sizes.

Dropping the people glyph with it — unreadable at either size, and
colour was the signal the ticket asked for.
It sat on the icon box's corner, which is 5px outside the artwork on
every side, so the dot read as clipped — half of it hanging over empty
padding with the icon's own drop-shadow falling across it. Nudged in on
both axes: 7px on the desktop, 2px on the dashboard rows.
A recipient given "can edit & share" could not pass that level on: the
dialog offered it, the server refused it, and the refusal was a bare
403 Forbidden that reads as a bug. Handing out manage needs authority
over manage, which only the owner has — the refusal is right, the dead
end and the silence were not.

The dropdown now withholds it from anyone who does not own the item; a
row already set to it keeps it, so opening the dialog cannot downgrade
the owner's own grant, and a mixed selection follows its strictest item.

The server says why, and only to someone who can already share the item
— a stranger still gets the ACL's own safe error, which does not admit
the node exists.

Verified against a running server: a delegate grants read and write as
before, and manage now answers cannot_delegate_manage with a sentence
naming the owner as the one who can.
Sharing a file with someone who already had it answered "Shared with
X", the same as a first share, so the dialog claimed to have done
something it had not.

The service already knew — it computes isNew to decide whether to
notify the recipient — but the flag stopped at the controller. It now
travels on share results only; a listing describes standing access and
says nothing about it.

Which of the three things happened is settled client-side, since the
mode each recipient holds is already on screen: created access, raised
or lowered it, or changed nothing. That keeps the previous mode off the
wire, and an older backend that omits isNew still reads as a share,
which is what these dialogs said before.
…-dialog-correctness

🐛 PUT-1586 + PUT-1599: Share dialog says what it can grant, and what it did
…n-readdir-shared-users-in-stat' into juancastro/put-1590-sharing-shared-files-are-not-different-than-regular-files

# Conflicts:
#	src/gui/src/UI/Dashboard/UIShareModal.js
#	src/gui/src/UI/UIWindowShare.js
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for puter.js SDK

Status Category Percentage Covered / Total
🔵 Lines 60.94%
⬆️ +0.05%
3954 / 6488
🔵 Statements 59.69%
⬆️ +0.03%
4166 / 6979
🔵 Functions 61.6%
🟰 ±0%
759 / 1232
🔵 Branches 53.74%
⬆️ +0.02%
2553 / 4750
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/puter-js/src/modules/FileSystem/operations/shareUtil.js 80%
🟰 ±0%
68.85%
⬆️ +1.06%
88.88%
🟰 ±0%
85.18%
🟰 ±0%
45-46, 99, 102-103
Generated in workflow #198 for commit 3f7dac6 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 93.66%
🟰 ±0%
24573 / 26235
🔵 Statements 91.94%
🟰 ±0%
26544 / 28869
🔵 Functions 89.88%
🟰 ±0%
4292 / 4775
🔵 Branches 80.57%
🟰 ±0%
17935 / 22258
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/backend/controllers/share/clientShare.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/services/share/ShareService.ts 92.54%
⬆️ +0.06%
81.3%
⬆️ +0.23%
95.12%
🟰 ±0%
95.39%
⬆️ +0.04%
77, 88, 100-104, 109, 116-120, 133, 183, 184, 267-269, 301-306, 355, 360, 370, 459, 482, 518, 544, 608, 750, 770, 835, 885, 893-894, 904-905, 920-921, 930, 943-944, 952-956, 1013-1014, 1046-1048, 1069-1071, 1100, 1247-1248
Generated in workflow #845 for commit 3f7dac6 by the Vitest Coverage Report Action

@jfcastro92
jfcastro92 merged commit 7bd6a2d into juancastro/put-1585-share-flag-in-readdir-shared-users-in-stat Aug 26, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants