@jskit-ai/shell-web 0.1.64 → 0.1.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.descriptor.mjs +200 -16
- package/package.json +8 -7
- package/src/client/components/ShellErrorHost.vue +88 -15
- package/src/client/components/ShellLayout.vue +551 -50
- package/src/client/components/ShellOutlet.vue +34 -4
- package/src/client/components/ShellOutletMenuWidget.vue +1 -8
- package/src/client/components/ShellRouteTransition.vue +480 -0
- package/src/client/components/ShellTabLinkItem.vue +22 -6
- package/src/client/composables/useShellLayoutState.js +12 -1
- package/src/client/error/normalize.js +17 -0
- package/src/client/error/policy.js +25 -11
- package/src/client/error/runtime.js +2 -0
- package/src/client/index.js +1 -0
- package/src/client/placement/index.js +5 -0
- package/src/client/placement/runtime.js +149 -16
- package/src/client/placement/validators.js +36 -8
- package/src/client/providers/ShellWebClientProvider.js +189 -24
- package/src/client/stores/useShellLayoutStore.js +21 -1
- package/src/test/adaptiveShellSmoke.js +121 -0
- package/templates/expected-existing/src/pages/home/index.vue +40 -10
- package/templates/src/components/ShellLayout.vue +10 -90
- package/templates/src/components/menus/TabLinkItem.vue +4 -0
- package/templates/src/error.js +7 -1
- package/templates/src/pages/home/index.vue +64 -23
- package/templates/src/pages/home/settings/general/index.vue +12 -9
- package/templates/src/pages/home/settings.vue +68 -24
- package/templates/src/placement.js +7 -6
- package/templates/src/placementTopology.js +149 -0
- package/templates/tests/e2e/adaptive-shell.spec.ts +4 -0
- package/test/errorRuntime.test.js +42 -0
- package/test/linkItemScaffoldContract.test.js +9 -2
- package/test/outletMenuWidgetContract.test.js +2 -2
- package/test/placementRegistry.test.js +3 -3
- package/test/placementRuntime.test.js +144 -14
- package/test/provider.test.js +97 -5
- package/test/settingsPlacementContract.test.js +234 -20
- package/test/useShellLayoutState.test.js +19 -0
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/shell-web",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.66",
|
|
5
5
|
kind: "runtime",
|
|
6
6
|
description: "Web shell layout runtime with outlet-based placement contributions.",
|
|
7
7
|
dependsOn: [],
|
|
@@ -30,7 +30,7 @@ export default Object.freeze({
|
|
|
30
30
|
surfaces: [
|
|
31
31
|
{
|
|
32
32
|
subpath: "./client",
|
|
33
|
-
summary: "Exports shell layout/outlet/outlet-menu/error-host components and ShellWebClientProvider."
|
|
33
|
+
summary: "Exports shell layout/outlet/outlet-menu/route-transition/error-host components and ShellWebClientProvider."
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
subpath: "./client/placement",
|
|
@@ -43,6 +43,10 @@ export default Object.freeze({
|
|
|
43
43
|
{
|
|
44
44
|
subpath: "./client/bootstrap",
|
|
45
45
|
summary: "Exports the shared client bootstrap handler registry used to extend /api/bootstrap handling."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
subpath: "./test/adaptiveShellSmoke",
|
|
49
|
+
summary: "Exports reusable Playwright smoke coverage for generated adaptive shell layouts."
|
|
46
50
|
}
|
|
47
51
|
],
|
|
48
52
|
containerTokens: {
|
|
@@ -51,8 +55,7 @@ export default Object.freeze({
|
|
|
51
55
|
"runtime.web-placement.client",
|
|
52
56
|
"runtime.web-bootstrap.client",
|
|
53
57
|
"runtime.web-error.client",
|
|
54
|
-
"runtime.web-error.presentation-store.client"
|
|
55
|
-
"shell.web.query-client"
|
|
58
|
+
"runtime.web-error.presentation-store.client"
|
|
56
59
|
]
|
|
57
60
|
}
|
|
58
61
|
},
|
|
@@ -71,46 +74,213 @@ export default Object.freeze({
|
|
|
71
74
|
},
|
|
72
75
|
{
|
|
73
76
|
target: "shell-layout:primary-menu",
|
|
74
|
-
|
|
77
|
+
surfaces: ["*"],
|
|
78
|
+
source: "src/client/components/ShellLayout.vue"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
target: "shell-layout:primary-bottom-nav",
|
|
75
82
|
surfaces: ["*"],
|
|
76
83
|
source: "src/client/components/ShellLayout.vue"
|
|
77
84
|
},
|
|
78
85
|
{
|
|
79
86
|
target: "shell-layout:secondary-menu",
|
|
80
|
-
|
|
87
|
+
surfaces: ["*"],
|
|
88
|
+
source: "src/client/components/ShellLayout.vue"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
target: "shell-layout:supporting-bottom-sheet",
|
|
92
|
+
surfaces: ["*"],
|
|
93
|
+
source: "src/client/components/ShellLayout.vue"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
target: "shell-layout:supporting-side-panel",
|
|
81
97
|
surfaces: ["*"],
|
|
82
98
|
source: "src/client/components/ShellLayout.vue"
|
|
83
99
|
},
|
|
84
100
|
{
|
|
85
101
|
target: "home-settings:primary-menu",
|
|
86
|
-
defaultLinkComponentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
87
102
|
surfaces: ["home"],
|
|
88
103
|
source: "templates/src/pages/home/settings.vue"
|
|
89
104
|
}
|
|
90
105
|
],
|
|
106
|
+
topology: {
|
|
107
|
+
placements: [
|
|
108
|
+
{
|
|
109
|
+
id: "shell.primary-nav",
|
|
110
|
+
description: "Primary top-level navigation for the current surface.",
|
|
111
|
+
surfaces: ["*"],
|
|
112
|
+
default: true,
|
|
113
|
+
variants: {
|
|
114
|
+
compact: {
|
|
115
|
+
outlet: "shell-layout:primary-bottom-nav",
|
|
116
|
+
renderers: {
|
|
117
|
+
link: "local.main.ui.tab-link-item"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
medium: {
|
|
121
|
+
outlet: "shell-layout:primary-menu",
|
|
122
|
+
renderers: {
|
|
123
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
expanded: {
|
|
127
|
+
outlet: "shell-layout:primary-menu",
|
|
128
|
+
renderers: {
|
|
129
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "shell.status",
|
|
136
|
+
description: "Surface status, connection, and utility indicators.",
|
|
137
|
+
surfaces: ["*"],
|
|
138
|
+
variants: {
|
|
139
|
+
compact: {
|
|
140
|
+
outlet: "shell-layout:top-right"
|
|
141
|
+
},
|
|
142
|
+
medium: {
|
|
143
|
+
outlet: "shell-layout:top-right"
|
|
144
|
+
},
|
|
145
|
+
expanded: {
|
|
146
|
+
outlet: "shell-layout:top-right"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: "shell.secondary-nav",
|
|
152
|
+
description: "Secondary navigation for lower-priority shell links.",
|
|
153
|
+
surfaces: ["*"],
|
|
154
|
+
variants: {
|
|
155
|
+
compact: {
|
|
156
|
+
outlet: "shell-layout:secondary-menu",
|
|
157
|
+
renderers: {
|
|
158
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
medium: {
|
|
162
|
+
outlet: "shell-layout:secondary-menu",
|
|
163
|
+
renderers: {
|
|
164
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
expanded: {
|
|
168
|
+
outlet: "shell-layout:secondary-menu",
|
|
169
|
+
renderers: {
|
|
170
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: "shell.identity",
|
|
177
|
+
description: "Current user, workspace, and surface identity controls.",
|
|
178
|
+
surfaces: ["*"],
|
|
179
|
+
variants: {
|
|
180
|
+
compact: {
|
|
181
|
+
outlet: "shell-layout:top-left"
|
|
182
|
+
},
|
|
183
|
+
medium: {
|
|
184
|
+
outlet: "shell-layout:top-left"
|
|
185
|
+
},
|
|
186
|
+
expanded: {
|
|
187
|
+
outlet: "shell-layout:top-left"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: "shell.global-actions",
|
|
193
|
+
description: "Global surface actions that should stay outside primary navigation.",
|
|
194
|
+
surfaces: ["*"],
|
|
195
|
+
variants: {
|
|
196
|
+
compact: {
|
|
197
|
+
outlet: "shell-layout:top-right",
|
|
198
|
+
renderers: {
|
|
199
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
medium: {
|
|
203
|
+
outlet: "shell-layout:top-right",
|
|
204
|
+
renderers: {
|
|
205
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
expanded: {
|
|
209
|
+
outlet: "shell-layout:top-right",
|
|
210
|
+
renderers: {
|
|
211
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "page.supporting-content",
|
|
218
|
+
description: "Supporting page content that opens as a bottom sheet on compact layouts and a side panel on wider layouts.",
|
|
219
|
+
surfaces: ["*"],
|
|
220
|
+
variants: {
|
|
221
|
+
compact: {
|
|
222
|
+
outlet: "shell-layout:supporting-bottom-sheet"
|
|
223
|
+
},
|
|
224
|
+
medium: {
|
|
225
|
+
outlet: "shell-layout:supporting-side-panel"
|
|
226
|
+
},
|
|
227
|
+
expanded: {
|
|
228
|
+
outlet: "shell-layout:supporting-side-panel"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "page.section-nav",
|
|
234
|
+
owner: "home-settings",
|
|
235
|
+
description: "Navigation between child pages in the home settings section.",
|
|
236
|
+
surfaces: ["home"],
|
|
237
|
+
variants: {
|
|
238
|
+
compact: {
|
|
239
|
+
outlet: "home-settings:primary-menu",
|
|
240
|
+
renderers: {
|
|
241
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
medium: {
|
|
245
|
+
outlet: "home-settings:primary-menu",
|
|
246
|
+
renderers: {
|
|
247
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
expanded: {
|
|
251
|
+
outlet: "home-settings:primary-menu",
|
|
252
|
+
renderers: {
|
|
253
|
+
link: "local.main.ui.surface-aware-menu-link-item"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
},
|
|
91
260
|
contributions: [
|
|
92
261
|
{
|
|
93
262
|
id: "shell-web.home.menu.home",
|
|
94
|
-
target: "shell
|
|
263
|
+
target: "shell.primary-nav",
|
|
264
|
+
kind: "link",
|
|
95
265
|
surfaces: ["home"],
|
|
96
266
|
order: 50,
|
|
97
|
-
componentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
98
267
|
source: "templates/src/placement.js"
|
|
99
268
|
},
|
|
100
269
|
{
|
|
101
270
|
id: "shell-web.home.menu.settings",
|
|
102
|
-
target: "shell
|
|
271
|
+
target: "shell.primary-nav",
|
|
272
|
+
kind: "link",
|
|
103
273
|
surfaces: ["home"],
|
|
104
274
|
order: 100,
|
|
105
|
-
componentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
106
275
|
source: "templates/src/placement.js"
|
|
107
276
|
},
|
|
108
277
|
{
|
|
109
278
|
id: "shell-web.home.settings.general",
|
|
110
|
-
target: "
|
|
279
|
+
target: "page.section-nav",
|
|
280
|
+
owner: "home-settings",
|
|
281
|
+
kind: "link",
|
|
111
282
|
surfaces: ["home"],
|
|
112
283
|
order: 100,
|
|
113
|
-
componentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
114
284
|
source: "templates/src/placement.js"
|
|
115
285
|
}
|
|
116
286
|
]
|
|
@@ -121,9 +291,7 @@ export default Object.freeze({
|
|
|
121
291
|
dependencies: {
|
|
122
292
|
runtime: {
|
|
123
293
|
"@mdi/js": "^7.4.47",
|
|
124
|
-
"@
|
|
125
|
-
"@jskit-ai/kernel": "0.1.65",
|
|
126
|
-
"vuetify": "^4.0.0"
|
|
294
|
+
"@jskit-ai/kernel": "0.1.67"
|
|
127
295
|
},
|
|
128
296
|
dev: {}
|
|
129
297
|
},
|
|
@@ -254,6 +422,14 @@ export default Object.freeze({
|
|
|
254
422
|
category: "shell-web",
|
|
255
423
|
id: "shell-web-placement-registry"
|
|
256
424
|
},
|
|
425
|
+
{
|
|
426
|
+
from: "templates/src/placementTopology.js",
|
|
427
|
+
to: "src/placementTopology.js",
|
|
428
|
+
ownership: "app",
|
|
429
|
+
reason: "Install app-owned semantic placement topology used by shell-web placement runtime.",
|
|
430
|
+
category: "shell-web",
|
|
431
|
+
id: "shell-web-placement-topology"
|
|
432
|
+
},
|
|
257
433
|
{
|
|
258
434
|
from: "templates/src/pages/home.vue",
|
|
259
435
|
toSurface: "home",
|
|
@@ -300,6 +476,14 @@ export default Object.freeze({
|
|
|
300
476
|
reason: "Install shell-driven general settings child page with a tiny browser-local shell preference example.",
|
|
301
477
|
category: "shell-web",
|
|
302
478
|
id: "shell-web-page-home-settings-general"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
from: "templates/tests/e2e/adaptive-shell.spec.ts",
|
|
482
|
+
to: "tests/e2e/adaptive-shell.spec.ts",
|
|
483
|
+
ownership: "app",
|
|
484
|
+
reason: "Install compact/medium/expanded Playwright smoke coverage for the adaptive shell.",
|
|
485
|
+
category: "shell-web",
|
|
486
|
+
id: "shell-web-test-adaptive-shell-smoke"
|
|
303
487
|
}
|
|
304
488
|
]
|
|
305
489
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/shell-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.66",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -15,22 +15,23 @@
|
|
|
15
15
|
"./client/components/ShellLayout": "./src/client/components/ShellLayout.vue",
|
|
16
16
|
"./client/components/ShellOutlet": "./src/client/components/ShellOutlet.vue",
|
|
17
17
|
"./client/components/ShellOutletMenuWidget": "./src/client/components/ShellOutletMenuWidget.vue",
|
|
18
|
+
"./client/components/ShellRouteTransition": "./src/client/components/ShellRouteTransition.vue",
|
|
18
19
|
"./client/components/ShellErrorHost": "./src/client/components/ShellErrorHost.vue",
|
|
19
20
|
"./client/components/ShellMenuLinkItem": "./src/client/components/ShellMenuLinkItem.vue",
|
|
20
21
|
"./client/components/ShellSurfaceAwareMenuLinkItem": "./src/client/components/ShellSurfaceAwareMenuLinkItem.vue",
|
|
21
22
|
"./client/components/ShellTabLinkItem": "./src/client/components/ShellTabLinkItem.vue",
|
|
22
23
|
"./client/composables/useShellLayoutState": "./src/client/composables/useShellLayoutState.js",
|
|
23
|
-
"./client/providers/ShellWebClientProvider": "./src/client/providers/ShellWebClientProvider.js"
|
|
24
|
+
"./client/providers/ShellWebClientProvider": "./src/client/providers/ShellWebClientProvider.js",
|
|
25
|
+
"./test/adaptiveShellSmoke": "./src/test/adaptiveShellSmoke.js"
|
|
24
26
|
},
|
|
25
27
|
"dependencies": {
|
|
26
28
|
"@mdi/js": "^7.4.47",
|
|
27
|
-
"@
|
|
28
|
-
"@jskit-ai/kernel": "0.1.65",
|
|
29
|
-
"pinia": "^3.0.4",
|
|
30
|
-
"vuetify": "^4.0.0"
|
|
29
|
+
"@jskit-ai/kernel": "0.1.67"
|
|
31
30
|
},
|
|
32
31
|
"peerDependencies": {
|
|
32
|
+
"pinia": "^3.0.4",
|
|
33
33
|
"vue": "^3.5.13",
|
|
34
|
-
"vue-router": "^5.0.4"
|
|
34
|
+
"vue-router": "^5.0.4",
|
|
35
|
+
"vuetify": "^4.0.0"
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed } from "vue";
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
3
|
import {
|
|
4
4
|
useShellWebErrorRuntime
|
|
5
5
|
} from "../error/inject.js";
|
|
@@ -8,9 +8,57 @@ import { useShellErrorPresentationStore } from "../stores/useShellErrorPresentat
|
|
|
8
8
|
const runtime = useShellWebErrorRuntime();
|
|
9
9
|
const store = useShellErrorPresentationStore();
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const snackbarEntries = computed(() => store.channels.snackbar || []);
|
|
12
12
|
const bannerEntries = computed(() => store.channels.banner || []);
|
|
13
13
|
const dialogEntry = computed(() => store.channels.dialog[0] || null);
|
|
14
|
+
const displayedSnackbarEntry = ref(null);
|
|
15
|
+
const snackbarOpen = ref(false);
|
|
16
|
+
|
|
17
|
+
function isSameSnackbarEntry(left = null, right = null) {
|
|
18
|
+
return Boolean(left?.id && right?.id && left.id === right.id);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hasSnackbarEntry(entry = null) {
|
|
22
|
+
if (!entry?.id) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return snackbarEntries.value.some((candidate) => isSameSnackbarEntry(candidate, entry));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function openNextSnackbarEntry() {
|
|
30
|
+
const nextEntry = snackbarEntries.value[0] || null;
|
|
31
|
+
if (!nextEntry) {
|
|
32
|
+
displayedSnackbarEntry.value = null;
|
|
33
|
+
snackbarOpen.value = false;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
displayedSnackbarEntry.value = nextEntry;
|
|
38
|
+
snackbarOpen.value = true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
watch(
|
|
42
|
+
snackbarEntries,
|
|
43
|
+
(entries) => {
|
|
44
|
+
const currentEntry = displayedSnackbarEntry.value;
|
|
45
|
+
if (!currentEntry) {
|
|
46
|
+
openNextSnackbarEntry();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const matchingEntry = entries.find((entry) => isSameSnackbarEntry(entry, currentEntry)) || null;
|
|
51
|
+
if (matchingEntry) {
|
|
52
|
+
displayedSnackbarEntry.value = matchingEntry;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
snackbarOpen.value = false;
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
immediate: true
|
|
60
|
+
}
|
|
61
|
+
);
|
|
14
62
|
|
|
15
63
|
function resolveSeverityColor(severity = "error") {
|
|
16
64
|
const normalized = String(severity || "error").trim().toLowerCase();
|
|
@@ -26,6 +74,20 @@ function resolveSeverityColor(severity = "error") {
|
|
|
26
74
|
return "error";
|
|
27
75
|
}
|
|
28
76
|
|
|
77
|
+
function resolveSeverityIcon(severity = "error") {
|
|
78
|
+
const normalized = String(severity || "error").trim().toLowerCase();
|
|
79
|
+
if (normalized === "info") {
|
|
80
|
+
return "mdi-information-outline";
|
|
81
|
+
}
|
|
82
|
+
if (normalized === "success") {
|
|
83
|
+
return "mdi-check-circle-outline";
|
|
84
|
+
}
|
|
85
|
+
if (normalized === "warning") {
|
|
86
|
+
return "mdi-alert-outline";
|
|
87
|
+
}
|
|
88
|
+
return "mdi-alert-outline";
|
|
89
|
+
}
|
|
90
|
+
|
|
29
91
|
function resolveTimeout(entry) {
|
|
30
92
|
if (!entry) {
|
|
31
93
|
return -1;
|
|
@@ -56,8 +118,8 @@ function runAction(entry) {
|
|
|
56
118
|
source: "shell-web.error-host.action",
|
|
57
119
|
message: "Error action failed.",
|
|
58
120
|
cause: error,
|
|
59
|
-
|
|
60
|
-
|
|
121
|
+
intent: "blocking",
|
|
122
|
+
severity: "error"
|
|
61
123
|
});
|
|
62
124
|
}
|
|
63
125
|
|
|
@@ -67,8 +129,9 @@ function runAction(entry) {
|
|
|
67
129
|
}
|
|
68
130
|
|
|
69
131
|
function onSnackbarModelValue(nextValue) {
|
|
70
|
-
if (nextValue === false &&
|
|
71
|
-
|
|
132
|
+
if (nextValue === false && displayedSnackbarEntry.value) {
|
|
133
|
+
snackbarOpen.value = false;
|
|
134
|
+
dismiss(displayedSnackbarEntry.value);
|
|
72
135
|
}
|
|
73
136
|
}
|
|
74
137
|
|
|
@@ -77,6 +140,14 @@ function onDialogModelValue(nextValue) {
|
|
|
77
140
|
dismiss(dialogEntry.value);
|
|
78
141
|
}
|
|
79
142
|
}
|
|
143
|
+
|
|
144
|
+
function onSnackbarAfterLeave() {
|
|
145
|
+
if (hasSnackbarEntry(displayedSnackbarEntry.value)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
openNextSnackbarEntry();
|
|
150
|
+
}
|
|
80
151
|
</script>
|
|
81
152
|
|
|
82
153
|
<template>
|
|
@@ -87,6 +158,7 @@ function onDialogModelValue(nextValue) {
|
|
|
87
158
|
v-for="entry in bannerEntries"
|
|
88
159
|
:key="entry.id"
|
|
89
160
|
:type="resolveSeverityColor(entry.severity)"
|
|
161
|
+
:icon="resolveSeverityIcon(entry.severity)"
|
|
90
162
|
variant="elevated"
|
|
91
163
|
density="comfortable"
|
|
92
164
|
rounded="lg"
|
|
@@ -113,28 +185,29 @@ function onDialogModelValue(nextValue) {
|
|
|
113
185
|
</div>
|
|
114
186
|
|
|
115
187
|
<v-snackbar
|
|
116
|
-
:model-value="
|
|
188
|
+
:model-value="snackbarOpen"
|
|
117
189
|
location="bottom end"
|
|
118
|
-
:timeout="resolveTimeout(
|
|
119
|
-
:color="resolveSeverityColor(
|
|
190
|
+
:timeout="resolveTimeout(displayedSnackbarEntry)"
|
|
191
|
+
:color="displayedSnackbarEntry ? resolveSeverityColor(displayedSnackbarEntry.severity) : undefined"
|
|
120
192
|
@update:model-value="onSnackbarModelValue"
|
|
193
|
+
@after-leave="onSnackbarAfterLeave"
|
|
121
194
|
>
|
|
122
|
-
<span v-if="
|
|
195
|
+
<span v-if="displayedSnackbarEntry">{{ displayedSnackbarEntry.message }}</span>
|
|
123
196
|
|
|
124
197
|
<template #actions>
|
|
125
198
|
<v-btn
|
|
126
|
-
v-if="
|
|
199
|
+
v-if="displayedSnackbarEntry?.action"
|
|
127
200
|
variant="text"
|
|
128
201
|
size="small"
|
|
129
|
-
@click="runAction(
|
|
202
|
+
@click="runAction(displayedSnackbarEntry)"
|
|
130
203
|
>
|
|
131
|
-
{{
|
|
204
|
+
{{ displayedSnackbarEntry.action.label }}
|
|
132
205
|
</v-btn>
|
|
133
206
|
<v-btn
|
|
134
|
-
v-if="
|
|
207
|
+
v-if="displayedSnackbarEntry"
|
|
135
208
|
variant="text"
|
|
136
209
|
size="small"
|
|
137
|
-
@click="dismiss(
|
|
210
|
+
@click="dismiss(displayedSnackbarEntry)"
|
|
138
211
|
>
|
|
139
212
|
Dismiss
|
|
140
213
|
</v-btn>
|