You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Non-breaking for default consumers.** Builds on #4183 (`corePageTabs`), #4184 (org tabs), #4185 (Account chrome), and #4187 (Admin chrome + `coreConfirmDialog` + `coreAvatarUploader`). Locks in one chrome convention across all "section + tab bar + routed children" layouts.
10
+
11
+
### The convention
12
+
13
+
Layouts (Account, Organization detail, Admin) use the same shape:
-`PageHeader` and `CoreSurfaceTabBar` are **siblings inside the container** — NEVER pass tabs via PageHeader's `#tabs` slot. That slot replaces the icon+title row and is reserved for future cases that intentionally suppress the title (none in this codebase today).
28
+
-`<router-view />` is **outside** the layout's `<v-container fluid>` — children supply their own gutter.
29
+
30
+
Routed children wrap their primary content like this:
The `<v-card color="surface">` provides the visible pane background. Content that already provides its own surface (e.g. `coreDataTableComponent`) skips the wrap card to avoid double-surface — wrap the data table directly in `<v-col cols="12">` without an inner `<v-card>`.
49
+
50
+
### Detail-page breadcrumb (admin only)
51
+
52
+
Admin sub-views that drill into a single record publish a breadcrumb to the layout instead of carrying their own header:
In breadcrumb mode the layout hides `<CoreSurfaceTabBar>` (user is "drilled in") and renders `Section › <title>` via `<PageHeader>`'s `#breadcrumb` slot.
71
+
72
+
### Shared destructive-confirm dialog
73
+
74
+
`<coreConfirmDialog>` (from `src/modules/core/components/core.confirmDialog.component.vue`) replaces inline `<v-dialog>` blocks for destructive actions:
75
+
76
+
```vue
77
+
<coreConfirmDialog
78
+
v-model="confirmDelete"
79
+
title="Delete X"
80
+
:confirm-text="confirmTarget"
81
+
confirm-label="Delete"
82
+
confirm-color="error"
83
+
@confirm="remove"
84
+
>
85
+
<!-- optional default slot for rich body content -->
86
+
</coreConfirmDialog>
87
+
```
88
+
89
+
Supports a simple yes/no (no `confirm-text`) OR a typed-gate (`confirm-text="DELETE"` or `:confirm-text="orgName"` — confirm button stays disabled until the user types the exact string).
Posts to `/users/avatar` by default; `endpoint` and `field` props let it serve other upload contracts (logos, banners) without forking.
100
+
101
+
### Action for downstream projects
102
+
103
+
**Default consumers (no admin extras, no custom account chrome):** no action required. The convention is applied uniformly inside devkit.
104
+
105
+
**Projects with `config.admin.tabs` extras:** no structural change — extras are merged with the canonical `BUILT_IN_TABS` (Users, Organizations, Readiness, Activity) and passed through `CoreSurfaceTabBar`, which handles validation + CASL filtering via `resolveSurfaceTabs`. Existing tab descriptors (`{ value, label, icon, route, action?, subject? }`) work as-is.
106
+
107
+
**Projects with module-specific tabs under a page title** (e.g. trawl_vue's `/developers`, `/scraps`, custom dashboards): you can now adopt the homogeneous `PageHeader + CoreSurfaceTabBar` sibling pattern instead of the legacy `<v-card><v-tabs><v-window>` in-card pattern. Migration is opt-in — the legacy pattern still works, but the new pattern integrates visually with Account / Organization / Admin and gets CASL gating for free.
Plus `config.developers.tabs = [{ value: 'keys', label: 'API Keys', icon: 'fa-solid fa-key', route: 'keys' }, { value: 'webhooks', label: 'Webhooks', icon: 'fa-solid fa-globe', route: 'webhooks' }]`, then split the keys / webhooks tabs into routed children (`developers.keys.view.vue`, `developers.webhooks.view.vue`) each wrapping its content per the child-view shape above. Dialogs (`showCreateKeyDialog`, `showPlainKeyDialog`, etc.) move into the child views that own them.
150
+
151
+
This migration is **opt-in per module** — coordinate with the maintainer of each module before applying.
152
+
153
+
### Why
154
+
155
+
`/admin/users`, `/users/profile`, `/users/organizations` looked visually disconnected from `/developers`, `/tasks` after #4187 (no surface background on routed panes, no section title on admin, ad-hoc padding). Locking in one convention makes every "section + tabs + content" layout in the app visually identical and lets downstream projects opt their own modules in cheaply.
0 commit comments