@fishawack/lab-velocity 2.0.0-beta.5 → 2.0.0-beta.50

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.
Files changed (111) hide show
  1. package/README.md +467 -36
  2. package/_Build/js/libs/build-id.js +14 -0
  3. package/_Build/js/libs/filters.js +36 -0
  4. package/_Build/js/libs/globals.js +7 -0
  5. package/_Build/js/libs/router.js +22 -0
  6. package/_Build/js/libs/routes.js +29 -0
  7. package/_Build/js/libs/store.js +21 -0
  8. package/_Build/js/libs/utility.js +161 -0
  9. package/_Build/vue/components/basic/Button.vue +1 -1
  10. package/_Build/vue/components/form/Avatar.vue +90 -0
  11. package/_Build/vue/components/form/Checkbox.vue +10 -0
  12. package/_Build/vue/components/form/InputNumber.vue +1 -1
  13. package/_Build/vue/components/form/Select.vue +223 -33
  14. package/_Build/vue/components/form/Spinner.vue +5 -0
  15. package/_Build/vue/components/layout/Alert.vue +5 -5
  16. package/_Build/vue/components/layout/Audit.vue +143 -0
  17. package/_Build/vue/{modules/AuthModule/components/VBreadcrumbs.vue → components/layout/Breadcrumbs.vue} +4 -4
  18. package/_Build/vue/{modules/AuthModule/components → components/layout}/Chips.vue +2 -2
  19. package/_Build/vue/components/layout/Footer.vue +11 -10
  20. package/_Build/vue/{modules/AuthModule/components/VFormFooter.vue → components/layout/FormFooter.vue} +13 -7
  21. package/_Build/vue/{modules/AuthModule/components → components/layout}/FormRole.vue +10 -8
  22. package/_Build/vue/components/layout/Layout.vue +94 -0
  23. package/_Build/vue/components/layout/Navigation.vue +77 -0
  24. package/_Build/vue/{modules/AuthModule/components/VPageHeader.vue → components/layout/PageHeader.vue} +14 -8
  25. package/_Build/vue/components/layout/SideBar.vue +26 -0
  26. package/_Build/vue/{modules/AuthModule/components/VTable.vue → components/layout/Table.vue} +37 -16
  27. package/_Build/vue/{modules/AuthModule/components/VTableSorter.vue → components/layout/TableSorter.vue} +108 -52
  28. package/_Build/vue/components/layout/TokenDisplay.vue +52 -0
  29. package/_Build/vue/components/layout/pageTitle.vue +1 -1
  30. package/_Build/vue/components/navigation/MenuItem.vue +7 -2
  31. package/_Build/vue/components/navigation/MenuItemGroup.vue +7 -2
  32. package/_Build/vue/modules/AuthModule/js/axios.js +21 -1
  33. package/_Build/vue/modules/AuthModule/js/guest-request.js +32 -0
  34. package/_Build/vue/modules/AuthModule/js/impersonation-banner.js +102 -0
  35. package/_Build/vue/modules/AuthModule/js/router.js +91 -114
  36. package/_Build/vue/modules/AuthModule/js/store.js +23 -6
  37. package/_Build/vue/modules/AuthModule/routes/PCompanies/columns.js +268 -0
  38. package/_Build/vue/modules/AuthModule/routes/PCompanies/resource.js +213 -0
  39. package/_Build/vue/modules/AuthModule/routes/PIntegrations/columns.js +58 -0
  40. package/_Build/vue/modules/AuthModule/routes/PIntegrations/resource.js +79 -0
  41. package/_Build/vue/modules/AuthModule/routes/PTeams/columns.js +78 -0
  42. package/_Build/vue/modules/AuthModule/routes/PTeams/resource.js +251 -0
  43. package/_Build/vue/modules/AuthModule/routes/PUsers/SetPasswordAction.vue +51 -0
  44. package/_Build/vue/modules/AuthModule/routes/PUsers/SetPasswordDialog.vue +138 -0
  45. package/_Build/vue/modules/AuthModule/routes/PUsers/columns.js +349 -0
  46. package/_Build/vue/modules/AuthModule/routes/PUsers/resource.js +239 -0
  47. package/_Build/vue/modules/AuthModule/routes/account-exists.vue +2 -2
  48. package/_Build/vue/modules/AuthModule/routes/change-password.vue +28 -32
  49. package/_Build/vue/modules/AuthModule/routes/container.vue +2 -11
  50. package/_Build/vue/modules/AuthModule/routes/expired-reset.vue +4 -4
  51. package/_Build/vue/modules/AuthModule/routes/expired-verification.vue +10 -9
  52. package/_Build/vue/modules/AuthModule/routes/force-reset.vue +44 -58
  53. package/_Build/vue/modules/AuthModule/routes/forgot.vue +10 -5
  54. package/_Build/vue/modules/AuthModule/routes/login.vue +12 -19
  55. package/_Build/vue/modules/AuthModule/routes/logincallback.vue +1 -3
  56. package/_Build/vue/modules/AuthModule/routes/loginsso.vue +14 -10
  57. package/_Build/vue/modules/AuthModule/routes/logout.vue +17 -5
  58. package/_Build/vue/modules/AuthModule/routes/logoutheadless.vue +1 -3
  59. package/_Build/vue/modules/AuthModule/routes/register.vue +24 -28
  60. package/_Build/vue/modules/AuthModule/routes/reset.vue +20 -14
  61. package/_Build/vue/modules/AuthModule/routes/success-forgot.vue +14 -8
  62. package/_Build/vue/modules/AuthModule/routes/success-reset.vue +2 -2
  63. package/_Build/vue/modules/AuthModule/routes/success-verify.vue +1 -3
  64. package/_Build/vue/modules/AuthModule/routes/verify.vue +11 -14
  65. package/_Build/vue/modules/resource/Children/create.vue +81 -0
  66. package/_Build/vue/modules/resource/Children/edit.vue +106 -0
  67. package/_Build/vue/modules/resource/Children/index.vue +42 -0
  68. package/_Build/vue/modules/resource/Children/partials/form.vue +111 -0
  69. package/_Build/vue/modules/resource/Children/show.vue +166 -0
  70. package/_Build/vue/modules/resource/index.js +561 -0
  71. package/_Build/vue/modules/resource/parent.vue +63 -0
  72. package/_Build/vue/modules/resource/trashable.js +104 -0
  73. package/_base.scss +0 -1
  74. package/_defaults.scss +2 -13
  75. package/_variables.scss +9 -4
  76. package/{modules/_AuthModule.scss → components/_auth.scss} +19 -68
  77. package/components/_datepicker.scss +1 -0
  78. package/components/_descriptions.scss +2 -0
  79. package/components/_footer.scss +1 -0
  80. package/components/_form.scss +18 -0
  81. package/components/_header.scss +3 -27
  82. package/components/_layout.scss +56 -0
  83. package/components/_menu.scss +0 -5
  84. package/components/_sidebar.scss +12 -27
  85. package/components/_table.scss +3 -0
  86. package/components/_token-display.scss +41 -0
  87. package/general.scss +1 -0
  88. package/index.js +31 -1
  89. package/package.json +7 -4
  90. package/vendor.scss +0 -1
  91. package/_Build/vue/components/layout/sideBar.vue +0 -25
  92. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/Upload/upload.vue +0 -251
  93. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/create.vue +0 -62
  94. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/edit.vue +0 -98
  95. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/index.vue +0 -90
  96. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/partials/form.vue +0 -173
  97. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/show.vue +0 -262
  98. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/parent.vue +0 -36
  99. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/create.vue +0 -112
  100. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/edit.vue +0 -103
  101. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/index.vue +0 -112
  102. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/partials/form.vue +0 -169
  103. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/show.vue +0 -120
  104. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/parent.vue +0 -36
  105. package/components/_input.scss +0 -0
  106. package/modules/_AuthVariables.scss +0 -7
  107. /package/_Build/vue/{modules/AuthModule/components → components/layout}/AuthModal.vue +0 -0
  108. /package/_Build/vue/{modules/AuthModule/components → components/layout}/Chip.vue +0 -0
  109. /package/_Build/vue/{modules/AuthModule/components/VPasswordValidation.vue → components/layout/PasswordValidation.vue} +0 -0
  110. /package/_Build/vue/{modules/AuthModule/components/VRoleLegend.vue → components/layout/RoleLegend.vue} +0 -0
  111. /package/{modules → components}/_modal.scss +0 -0
@@ -0,0 +1,561 @@
1
+ "use strict";
2
+
3
+ import { merge, kebabCase, snakeCase, cloneDeepWith } from "lodash";
4
+ import axios from "axios";
5
+ import { h, resolveComponent } from "vue";
6
+
7
+ import VelTableSorter from "../../components/layout/TableSorter.vue";
8
+ import {
9
+ ElDescriptions,
10
+ ElDescriptionsItem,
11
+ ElPopconfirm,
12
+ ElNotification,
13
+ } from "element-plus";
14
+ import VelButton from "../../components/basic/Button.vue";
15
+ import VelAudit from "../../components/layout/Audit.vue";
16
+ import { applyTrashable } from "./trashable.js";
17
+
18
+ export const defaultResource = meta();
19
+
20
+ export function meta(name = "default", properties = {}) {
21
+ const singular = properties.singular || name.slice(0, -1);
22
+ const slug = properties.slug || kebabCase(name);
23
+
24
+ const result = merge(
25
+ {
26
+ name,
27
+ title: properties.title || name[0].toUpperCase() + name.slice(1),
28
+ singular,
29
+ singularTitle:
30
+ properties.singularTitle ||
31
+ singular[0].toUpperCase() + singular.slice(1),
32
+ label: singular,
33
+ multiLabel: name,
34
+ slug,
35
+ path: properties.path || `/${slug}`,
36
+ routeName: properties.routeName || slug,
37
+ id: properties.id || `${snakeCase(slug)}Id`,
38
+ icon: `icon-${singular}`,
39
+ api: {
40
+ endpoint: () => `/api/${properties.slug || kebabCase(name)}`,
41
+ params: {
42
+ index: () => ({}),
43
+ show: () => ({}),
44
+ },
45
+ },
46
+ permissions: {
47
+ create: () => true,
48
+ edit: () => true,
49
+ delete: () => false,
50
+ },
51
+ searchable: {
52
+ value: "name",
53
+ label: `Search ${name}`,
54
+ },
55
+ auditable: false,
56
+ trashable: false,
57
+ form: {
58
+ component: null,
59
+ submit: null,
60
+ class: "grid__1/2",
61
+ fields: () => ({}),
62
+ preparation: ({ form }) => form.data(),
63
+ structure: [],
64
+ groups: {},
65
+ },
66
+ table: {
67
+ actions: [
68
+ ({ model, resource }, { $router }) =>
69
+ !model.deleted_at &&
70
+ h(
71
+ VelButton,
72
+ {
73
+ tag: "a",
74
+ size: "small",
75
+ type: "primary",
76
+ onClick: () => {
77
+ $router.push({
78
+ name: `${resource.routeName}.show`,
79
+ params: {
80
+ [resource.id]: model.id,
81
+ },
82
+ });
83
+ },
84
+ },
85
+ () => "View",
86
+ ),
87
+ ({ model, resource }, props) => {
88
+ const { $router } = props;
89
+
90
+ if (resource.permissions.edit(props, { model })) {
91
+ return (
92
+ !model.deleted_at &&
93
+ h(
94
+ VelButton,
95
+ {
96
+ tag: "a",
97
+ size: "small",
98
+ onClick: () => {
99
+ $router.push({
100
+ name: `${resource.routeName}.edit`,
101
+ params: {
102
+ [resource.id]: model.id,
103
+ },
104
+ });
105
+ },
106
+ },
107
+ () => "Edit",
108
+ )
109
+ );
110
+ }
111
+ },
112
+ ({ model, resource }, props) => {
113
+ const { $emit } = props;
114
+
115
+ if (resource.permissions.delete(props, { model })) {
116
+ return (
117
+ !model.deleted_at &&
118
+ h({
119
+ data: () => ({
120
+ loading: false,
121
+ }),
122
+ render() {
123
+ return h(
124
+ ElPopconfirm,
125
+ {
126
+ title: `Are you sure you want to delete this ${resource.singular}?`,
127
+ confirmButtonText: "Delete",
128
+ cancelButtonText: "Cancel",
129
+ confirmButtonType: "danger",
130
+ onConfirm: async () => {
131
+ this.loading = true;
132
+
133
+ await axios.delete(
134
+ `${resource.api.endpoint(props)}/${model.id}`,
135
+ );
136
+
137
+ $emit("reload");
138
+
139
+ ElNotification({
140
+ title: "Success",
141
+ message: `${resource.singularTitle} with id ${model.id} deleted.`,
142
+ type: "success",
143
+ });
144
+
145
+ this.loading = false;
146
+ },
147
+ },
148
+ {
149
+ reference: () =>
150
+ h(
151
+ VelButton,
152
+ {
153
+ tag: "a",
154
+ type: "danger",
155
+ size: "small",
156
+ loading:
157
+ this.loading,
158
+ },
159
+ () => `Delete`,
160
+ ),
161
+ },
162
+ );
163
+ },
164
+ })
165
+ );
166
+ }
167
+ },
168
+ ],
169
+ structure: [
170
+ {
171
+ key: "id",
172
+ },
173
+ ],
174
+ },
175
+ description: {
176
+ structure: [
177
+ {
178
+ key: "id",
179
+ },
180
+ ],
181
+ },
182
+ index: {
183
+ structure: (props) => {
184
+ const { resource } = props;
185
+
186
+ return {
187
+ key: "PIndex",
188
+ "json-data": {
189
+ ...resource,
190
+ tableStructure: resource.table
191
+ .structure(props)
192
+ .concat(
193
+ resource.table.actions.length
194
+ ? [
195
+ {
196
+ key: "actions",
197
+ render: ({ model }, props) =>
198
+ h(
199
+ "div",
200
+ {
201
+ class: "flex gap-2",
202
+ },
203
+ resource.table.actions.map(
204
+ (d) =>
205
+ d(
206
+ {
207
+ model,
208
+ resource,
209
+ },
210
+ props,
211
+ ),
212
+ ),
213
+ ),
214
+ },
215
+ ]
216
+ : [],
217
+ ),
218
+ api: resource.api.endpoint(props),
219
+ },
220
+ apiParams: resource.api.params.index(props),
221
+ idKey: resource.id,
222
+ "fixed-height": false,
223
+ displayActions: false,
224
+ };
225
+ },
226
+ actions: [
227
+ (props) => {
228
+ const { resource, $router } = props;
229
+
230
+ if (resource.permissions.create(props)) {
231
+ return h(
232
+ VelButton,
233
+ {
234
+ tag: "a",
235
+ type: "primary",
236
+ size: "large",
237
+ onClick: () => {
238
+ $router.push({
239
+ name: `${resource.routeName}.create`,
240
+ });
241
+ },
242
+ },
243
+ () => [
244
+ h(resolveComponent("GIcon"), {
245
+ class: "fill-0 mr-0.5 icon--0.5",
246
+ name: "icon-plus",
247
+ embed: true,
248
+ artboard: true,
249
+ }),
250
+ `Create ${resource.singular}`,
251
+ ],
252
+ );
253
+ }
254
+ },
255
+ ],
256
+ layout: [
257
+ (props) => {
258
+ const { resource } = props;
259
+
260
+ return h(
261
+ VelTableSorter,
262
+ resource.index.structure(props),
263
+ );
264
+ },
265
+ ],
266
+ },
267
+ show: {
268
+ actions: [
269
+ (props) => {
270
+ const { resource, model, $router } = props;
271
+
272
+ if (resource.permissions.edit(props, { model })) {
273
+ return h(
274
+ VelButton,
275
+ {
276
+ tag: "a",
277
+ type: "primary",
278
+ onClick: () => {
279
+ $router.push({
280
+ name: `${resource.routeName}.edit`,
281
+ params: {
282
+ [resource.id]: model.id,
283
+ },
284
+ });
285
+ },
286
+ },
287
+ () => [
288
+ h(resolveComponent("GIcon"), {
289
+ class: "fill-0 mr-0.5 icon--0.5",
290
+ name: "icon-edit",
291
+ embed: true,
292
+ artboard: true,
293
+ }),
294
+ `Edit ${resource.singular}`,
295
+ ],
296
+ );
297
+ }
298
+ },
299
+ (props) => {
300
+ const { resource, model, $router } = props;
301
+
302
+ if (resource.permissions.delete(props, { model })) {
303
+ return h(
304
+ ElPopconfirm,
305
+ {
306
+ title: `Are you sure you want to delete this ${resource.singular}?`,
307
+ confirmButtonText: "Delete",
308
+ cancelButtonText: "Cancel",
309
+ confirmButtonType: "danger",
310
+ onConfirm: async () => {
311
+ await axios.delete(
312
+ `${resource.api.endpoint(props)}/${model.id}`,
313
+ );
314
+
315
+ $router.push({
316
+ name: `${resource.routeName}.index`,
317
+ });
318
+ },
319
+ },
320
+ {
321
+ reference: () =>
322
+ h(
323
+ VelButton,
324
+ {
325
+ tag: "a",
326
+ type: "danger",
327
+ },
328
+ () => [
329
+ h(resolveComponent("GIcon"), {
330
+ class: "fill-0 mr-0.5 icon--0.5",
331
+ name: "icon-trash",
332
+ embed: true,
333
+ artboard: true,
334
+ }),
335
+ `Delete ${resource.singular}`,
336
+ ],
337
+ ),
338
+ },
339
+ );
340
+ }
341
+ },
342
+ ],
343
+ tabs: [
344
+ (props) => {
345
+ const { resource } = props;
346
+
347
+ return {
348
+ label: "Details",
349
+ component: h(
350
+ "div",
351
+ resource.show.layout
352
+ .map((render) => render(props))
353
+ .filter((d) => d),
354
+ ),
355
+ };
356
+ },
357
+ ],
358
+ layout: [
359
+ (props) => {
360
+ const { resource, model } = props;
361
+
362
+ return h(
363
+ ElDescriptions,
364
+ {
365
+ border: true,
366
+ column: 1,
367
+ },
368
+ () =>
369
+ resource.description
370
+ .structure(props)
371
+ .map((item, index) =>
372
+ h(
373
+ ElDescriptionsItem,
374
+ {
375
+ key: index,
376
+ labelWidth: "20%",
377
+ },
378
+ {
379
+ label: () =>
380
+ item.label ||
381
+ item.key[0].toUpperCase() +
382
+ item.key.slice(1),
383
+ default: () =>
384
+ item.render
385
+ ? h(item.render(props))
386
+ : model?.[item.key] ||
387
+ "",
388
+ },
389
+ ),
390
+ ),
391
+ );
392
+ },
393
+ ],
394
+ },
395
+ },
396
+ properties,
397
+ );
398
+
399
+ if (result.trashable) {
400
+ applyTrashable(result);
401
+ }
402
+
403
+ return result;
404
+ }
405
+
406
+ export function columns(columns = []) {
407
+ return {
408
+ table: {
409
+ structure: (props) =>
410
+ columns
411
+ .filter(
412
+ (column) =>
413
+ resolveProperty(column.condition?.table, props) !==
414
+ false,
415
+ )
416
+ .map((column) => ({
417
+ ...column,
418
+ render: column.render?.read || column.render?.table,
419
+ })),
420
+ },
421
+ description: {
422
+ structure: (props) =>
423
+ columns
424
+ .filter(
425
+ (column) =>
426
+ resolveProperty(
427
+ column.condition?.description,
428
+ props,
429
+ ) !== false,
430
+ )
431
+ .map((column) => ({
432
+ ...column,
433
+ render:
434
+ column.render?.read || column.render?.description,
435
+ })),
436
+ },
437
+ form: {
438
+ fields: (props) =>
439
+ columns
440
+ .filter(
441
+ (column) =>
442
+ resolveProperty(column.condition?.form, props) !==
443
+ false,
444
+ )
445
+ .reduce((fields, column) => {
446
+ fields[column.key] = column.initial
447
+ ? column.initial(props)
448
+ : (props.model?.[column.key] ?? null);
449
+ return fields;
450
+ }, {}),
451
+ preparation: (props) =>
452
+ columns
453
+ .filter(
454
+ (column) =>
455
+ resolveProperty(column.condition?.form, props) !==
456
+ false,
457
+ )
458
+ .reduce((fields, column) => {
459
+ fields[column.key] = column.preparation
460
+ ? column.preparation(props)
461
+ : props.form[column.key];
462
+ return fields;
463
+ }, {}),
464
+ structure: (props) =>
465
+ columns
466
+ .filter(
467
+ (column) =>
468
+ resolveProperty(
469
+ column.condition?.form?.write ??
470
+ column.condition?.form,
471
+ props,
472
+ ) !== false,
473
+ )
474
+ .map((column) => ({
475
+ ...column,
476
+ render: column.render?.write || column.render?.form,
477
+ })),
478
+ },
479
+ };
480
+ }
481
+
482
+ // Export resource
483
+ export function routes(node, name, properties = {}, children = []) {
484
+ const resource = meta(name, properties);
485
+
486
+ return [
487
+ {
488
+ path: resource.path,
489
+ component: node ? "" : require("../resource/parent.vue").default,
490
+ name: `${resource.routeName}`,
491
+ meta: {
492
+ resource,
493
+ title: resource.title,
494
+ icon: resource.icon,
495
+ breadcrumb: () => resource.title,
496
+ ...properties.meta,
497
+ },
498
+ children: [
499
+ {
500
+ path: "",
501
+ component: node
502
+ ? ""
503
+ : resource.index.component ||
504
+ require("../resource/Children/index.vue").default,
505
+ name: `${resource.routeName}.index`,
506
+ },
507
+ {
508
+ path: "create",
509
+ component: node
510
+ ? ""
511
+ : resource.create?.component ||
512
+ require("../resource/Children/create.vue").default,
513
+ name: `${resource.routeName}.create`,
514
+ },
515
+ {
516
+ path: `:${resource.id}`,
517
+ component: node
518
+ ? ""
519
+ : resource.show.component ||
520
+ require("../resource/Children/show.vue").default,
521
+ name: `${resource.routeName}.show`,
522
+ // Remove leading / for nested routes or they'll resolve to the root of the site
523
+ children: cloneDeepWith(children, (value, key) => {
524
+ if (
525
+ key === "path" &&
526
+ typeof value === "string" &&
527
+ value.startsWith("/")
528
+ ) {
529
+ return value.slice(1);
530
+ }
531
+ }),
532
+ meta: {
533
+ breadcrumb: ({ $route }) => $route.params[resource.id],
534
+ },
535
+ },
536
+ {
537
+ path: `:${resource.id}/edit`,
538
+ component: node
539
+ ? ""
540
+ : resource.edit?.component ||
541
+ require("../resource/Children/edit.vue").default,
542
+ name: `${resource.routeName}.edit`,
543
+ meta: {
544
+ breadcrumb: ({ $route }) => $route.params[resource.id],
545
+ },
546
+ },
547
+ ],
548
+ },
549
+ ];
550
+ }
551
+
552
+ export function resolveProperty(value, context) {
553
+ return typeof value === "function" ? value(context) : value;
554
+ }
555
+
556
+ export default {
557
+ routes,
558
+ meta,
559
+ columns,
560
+ defaultResource,
561
+ };
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <!-- Only render title once at the shallowest route -->
3
+ <template v-if="depth === 1">
4
+ <VelPageTitle :title="resource.title" />
5
+ <VelBreadcrumbs
6
+ :items="breadcrumbs"
7
+ class="mb-8"
8
+ container-classes="m-0"
9
+ />
10
+ </template>
11
+
12
+ <router-view
13
+ :key="$route.path"
14
+ v-slot="{ Component }"
15
+ :breadcrumbs="breadcrumbs"
16
+ :resource="resource"
17
+ >
18
+ <component :is="Component" :depth="depth + 1" />
19
+ </router-view>
20
+ </template>
21
+
22
+ <script>
23
+ import VelPageTitle from "../../components/layout/pageTitle.vue";
24
+ import VelBreadcrumbs from "../../components/layout/Breadcrumbs.vue";
25
+
26
+ export default {
27
+ components: {
28
+ VelPageTitle,
29
+ VelBreadcrumbs,
30
+ },
31
+
32
+ props: {
33
+ depth: {
34
+ type: Number,
35
+ default: 1,
36
+ },
37
+ },
38
+
39
+ computed: {
40
+ resource() {
41
+ return this.$route.meta.resource;
42
+ },
43
+ breadcrumbs() {
44
+ return [
45
+ {
46
+ text: "Home",
47
+ href: { name: "index" },
48
+ },
49
+ ].concat(
50
+ this.$route.matched
51
+ .filter((route) => route.meta?.breadcrumb)
52
+ .map((route) => ({
53
+ text: route.meta.breadcrumb(this),
54
+ href: {
55
+ name: route.name,
56
+ params: this.$route.params,
57
+ },
58
+ })),
59
+ );
60
+ },
61
+ },
62
+ };
63
+ </script>