Esposter

Resource Page Parity

Azure command-bar and destructive-operation parity on /resources/[id]/[[blade]]: labeled toolbar commands with a overflow, Refresh, a Duplicate command, and a type-the-name delete confirmation.

Command bar

  • Presentation (BladeActions): variant="text" buttons with prepend-icon + label (Refresh, Rename, Delete, Duplicate, Publish/Unpublish, Import, Export), v-divider vertical between groups; Delete keeps color="error".
  • Overflow: on smAndDown, every command collapses into a single menu (labels always visible in the menu), rendered by BladeActions from the same gates as the wide bar; the close ✕ never collapses.
  • Refresh: re-runs useResource's load (row + publication) with the toolbar button showing the loading state.
  • Duplicate: resource.duplicateResource — copies the row as {name} (copy) + the content blob; never the publication (a copy starts as Draft). Routes to the new resource's Overview and raises a "Go to resource" notification. Capability-independent (every type supports it).

Destructive-operation guard

StyledDeleteFormDialog takes an optional confirmName prop: a text field whose value must equal it before Delete enables (Azure's "type the resource name to confirm"). The blade Delete command and the /all row delete type the resource name; bulk delete on /all types the selection count (delete {n}list filters & views).

Save-conflict surface

A saveResourceContent rejected for a stale contentVersion routes into the notifications store as "'{name}' was modified elsewhere — refresh to load the latest", with a Refresh action that hard-reloads (the one path guaranteed to re-run every blade's content loader).

sequenceDiagram
  participant A as Tab A (editor blade)
  participant S as saveResourceContent
  participant B as Tab B (same resource)

  B->>S: save (contentVersion n) → n+1
  A->>S: save (stale contentVersion n)
  S-->>A: rejected (optimistic concurrency)
  A->>A: warning notification "modified elsewhere" + Refresh action

Procedures

ProcedureAuthInputPurpose
resource.duplicateResourcegetOwnerProcedure{ id }copy row ({name} (copy), fresh id, no publication) + copy content blob

Key files

FileRole
app/components/Resource/BladeActions.vuelabeled buttons, dividers, narrow-viewport menu
app/components/Styled/DeleteFormDialog.vueconfirmName guard prop
app/composables/resource/useResource.tsrefresh/duplicate actions, conflict + outcome notifications

Notes

  • Commands stay capability-gated exactly as before — this changed presentation and added Refresh/Duplicate, not the gating model.
  • Publish history (list {id}/published/{n} snapshots, view/rollback) is a separate roadmap investigation — blob retention across re-publishes must be verified first.
  • JSON view / export-template parity is out of scope.