Share to Esbabbler
A Share command on published resources: pick one of your rooms, add an optional note, and the public /view/[type]/[id] link lands there as a message. It is the first real bridge between the platform and esbabbler, and it is deliberately the smallest one that works — client-side only, reusing the existing message-create path, with no new procedures and no schema.
Before it, sharing meant copying the link off the Overview blade and pasting it into a room by hand. That still works; this just does it in place.
How it works
flowchart LR
CMD["Share command<br/>(command bar, published only)"] --> DLG["ShareDialog"]
DLG -->|room.readRooms| ROOMS["your rooms → v-select"]
DLG --> MSG["getShareMessage<br/>note + newline + public URL"]
MSG -->|"message.createMessage<br/>{ roomId, message }"| ROOM[("room message")]
ROOM --> OK["notification: Shared to {room}<br/>+ Open room action"]
- The command appears for
PublishableResourceTypeonly while published. An unpublished resource has no public URL, so there is nothing to share until it has one — the command is absent, not disabled. It sits beside the publish toggle in the command bar and collapses into the…overflow on narrow viewports with everything else. - The dialog reads your rooms once per open (it mounts only while open) into a
v-select, with an optional note field. No rooms is an empty state pointing at esbabbler, not a disabled button with no explanation. - The message is sanitized HTML with an explicit anchor — message bodies render through
v-htmland nothing in the pipeline autolinks bare text, sogetShareMessagebuilds the link itself (<a href … target="_blank">) and wraps the escaped note above it, newlines as line breaks. It goes through the standardmessage.createMessagemutation, so RBAC, rate limits, profanity filtering, and the whole message pipeline apply unchanged; rich embeds/unfurls stay deferred. - The dialog validates what it sends — the length rule checks the composed message (note + markup + link) against the message cap, not just the raw note, so a note that fits the counter can never produce a message the server rejects.
- Success lands in the notifications store with an Open room action.
Key files
| File | Role |
|---|---|
app/components/Resource/ShareDialog.vue | room picker, note, send, empty state |
app/components/Resource/BladeActions.vue | the Share command (publishable + published) |
app/services/resource/getShareMessage.ts | note + link composition |
Notes
- Deliberately one direction (platform → room). Surfacing "shared with me" inside the explorer is a different feature needing read-model thought, and is not in this cut.
- The message is the caller's own message in their own room — no special message type, no service-to-service write, no elevated permission. Deleting the resource later leaves a dead link, exactly like any pasted URL.
Previous
Resource Tags
Azure tag parity — name:value pairs on every resource, shown in Essentials, editable in place, filterable on the list.
Next
Shell Cohesion
The shared chrome primitives — page header, breadcrumbs, empty/loading states, and the launcher — that make the platform read as one product.