Frappe Draw: Share dialog UI wired to sharing backend (view/comment/edit)#13
Conversation
…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>
Confidence Score: 4/5Safe 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 |
| 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 |
There was a problem hiding this comment.
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!
| @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", | ||
| ) |
There was a problem hiding this comment.
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 realdraw.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) + enrichedget_diagram_shares→{user, full_name, user_image, level, can_edit}+ rawread/write/comment(level = edit|comment|view).useShare.js: callsdraw.api.share.get_diagram_shares/share_diagram(idempotent add+update) /unshare_diagram/search_users/set_public;addMember/setMemberRolenow take a level string.ShareMenu.vue: invite + per-member selects gain "Can comment" (view / comment / edit).Testing
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
required_app.🤖 Generated with Claude Code