Skip to content

Frappe Draw: Share dialog UI wired to sharing backend (view/comment/edit)#13

Merged
vibhavkatre merged 1 commit into
mainfrom
feat/share-dialog-ui
Jul 17, 2026
Merged

Frappe Draw: Share dialog UI wired to sharing backend (view/comment/edit)#13
vibhavkatre merged 1 commit into
mainfrom
feat/share-dialog-ui

Conversation

@vibhavkatre

Copy link
Copy Markdown
Collaborator

What & why

The Share dialog (ShareMenu.vue + useShare.js) already existed but called backend methods that were never built (draw.api.diagram.*). This wires it to the real draw.api.share.* API (from the sharing-backend PR), adds the third "Can comment" level end-to-end, and adds the user-search endpoint the invite box needs. Sharing is now a complete, user-facing feature.

Changes

  • api/share.py: search_users(txt) (enabled users, name/full-name match) + enriched get_diagram_shares{user, full_name, user_image, level, can_edit} + raw read/write/comment (level = edit|comment|view).
  • useShare.js: calls draw.api.share.get_diagram_shares / share_diagram (idempotent add+update) / unshare_diagram / search_users / set_public; addMember/setMemberRole now take a level string.
  • ShareMenu.vue: invite + per-member selects gain "Can comment" (view / comment / edit).

Testing

  • Build ✅ · 7 Python tests ✅ (adds a level-reporting case).
  • Live app ✅ — opening Share → inviting a user at "comment" creates the correct DocShare (read=1, write=0, comment=1, level=comment); the member renders with a "Can comment" select and the "Shared with…" toast fires (screenshot); no page errors.

Remaining roadmap

  • Realtime collab (Yjs, per Writer) — large separate milestone.
  • Drive file-tree registration — needs Drive installed as a required_app.

🤖 Generated with Claude Code

…nt/edit)

The Share dialog (ShareMenu.vue + useShare.js) already existed but called backend
methods that were never built (draw.api.diagram.*). Point it at the real
draw.api.share.* API, add the third "Can comment" access level end to end, and add
the user-search endpoint the invite box needs.

- api/share.py: add search_users(txt) (enabled users, name/full-name match) and
  enrich get_diagram_shares to return {user, full_name, user_image, level,
  can_edit} + raw read/write/comment (level = edit|comment|view).
- useShare.js: call draw.api.share.get_diagram_shares / share_diagram (idempotent
  add+update) / unshare_diagram / search_users / set_public; addMember/setMemberRole
  now take a level string instead of a can_edit boolean.
- ShareMenu.vue: invite + per-member selects gain "Can comment" (view/comment/edit).

Verified: build + 7 Python tests (adds a level-reporting case) + live app — opening
Share, inviting a user at "comment" creates the right DocShare
(read=1,write=0,comment=1,level=comment), the member shows with a "Can comment"
select, and the "Shared with…" toast fires (screenshot); no page errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vibhavkatre
vibhavkatre merged commit 657338a into main Jul 17, 2026
3 checks passed
@vibhavkatre
vibhavkatre deleted the feat/share-dialog-ui branch July 17, 2026 07:16
@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

Safe to merge; the new sharing logic is correct and tested. The two issues are minor and won't break functionality.

The core sharing flow—invite, level update, revoke, public toggle—is correctly wired and covered by 7 Python tests. The N+1 query in get_diagram_shares only matters at scale, and the open search_users endpoint is likely acceptable for the invite UX but worth an intentional call.

draw/api/share.py — both findings live here; everything else is straightforward glue.

Reviews (1): Last reviewed commit: "Frappe Draw: wire the Share dialog to th..." | Re-trigger Greptile

Comment thread draw/api/share.py
Comment on lines +62 to +79
shares = []
for row in frappe.share.get_users("Draw Diagram", name):
if row.get("everyone") or not row.get("user"):
continue
info = frappe.db.get_value("User", row.user, ["full_name", "user_image"], as_dict=True) or {}
shares.append(
{
"user": row.user,
"full_name": info.get("full_name"),
"user_image": info.get("user_image"),
"read": row.read,
"write": row.write,
"comment": row.get("comment"),
"level": _level_of(row),
"can_edit": bool(row.write),
}
)
return shares

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 N+1 query per share row

frappe.db.get_value is called once per shared user. Batch this with a single frappe.get_all("User", filters={"name": ["in", user_list]}, fields=["name","full_name","user_image"]) keyed by name, then look up each row from that dict.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread draw/api/share.py
Comment on lines +82 to +94
@frappe.whitelist()
def search_users(txt: str = "") -> list:
"""Enabled users matching `txt` (name or full name), for the invite box.
Excludes Guest/Administrator."""
like = f"%{txt or ''}%"
return frappe.get_all(
"User",
filters={"enabled": 1, "name": ["not in", ("Administrator", "Guest")]},
or_filters={"name": ["like", like], "full_name": ["like", like]},
fields=["name", "full_name", "user_image"],
limit=10,
order_by="full_name asc",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 User enumeration open to any logged-in user

search_users has no "can share any diagram" gate — any authenticated user can call it to enumerate all enabled site users. If that's intentional for the invite UX, it should be documented; if not, add a permission check.

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