@fishawack/lab-velocity 2.0.0-beta.13 → 2.0.0-beta.15

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/README.md CHANGED
@@ -78,6 +78,17 @@ import { Auth } from "@fishawack/lab-velocity";
78
78
  ];
79
79
  ```
80
80
 
81
+ You can override the default setup for companies & user resources by passing an optional second object to the `adminRoutes` method. See the [resources](#Resources) section below for available options.
82
+
83
+ ```js
84
+ ...Auth.Router.adminRoutes(node, {
85
+ userResource: {
86
+ label: "Custom User label",
87
+ api: `/api/v2/users`,
88
+ }
89
+ })
90
+ ```
91
+
81
92
  ### Configure store
82
93
 
83
94
  ##### store.js
@@ -252,8 +263,8 @@ export function meta(name, properties = {}) {
252
263
  pageLink: name,
253
264
  api: `/api/${name}`,
254
265
  permissions: {
255
- create: true,
256
- edit: true,
266
+ create: () => true,
267
+ edit: () => true,
257
268
  },
258
269
  searchable: {
259
270
  value: "name",
@@ -264,30 +275,73 @@ export function meta(name, properties = {}) {
264
275
  fields: () => ({}),
265
276
  },
266
277
  table: {
267
- structure: [],
278
+ structure: [
279
+ {
280
+ key: "id",
281
+ },
282
+ ],
268
283
  },
269
- index: {
270
- actions: [],
284
+ description: {
271
285
  structure: [
272
286
  {
273
- render: ({ resource }) =>
274
- h(VTableSorter, {
275
- key: "PIndex",
276
- "json-data": {
277
- ...resource,
278
- tableStructure: resource.table.structure,
279
- },
280
- defaults: resource.defaults,
281
- "fixed-height": false,
282
- "display-edit-action":
283
- resource.permissions.create,
284
- }),
287
+ key: "id",
288
+ },
289
+ ],
290
+ },
291
+ index: {
292
+ actions: [],
293
+ layout: [
294
+ (props) => {
295
+ const { resource } = props;
296
+
297
+ return h(VTableSorter, {
298
+ key: "PIndex",
299
+ "json-data": {
300
+ ...resource,
301
+ tableStructure: resource.table.structure,
302
+ },
303
+ defaults: resource.defaults,
304
+ "fixed-height": false,
305
+ "display-edit-action":
306
+ resource.permissions.create(props),
307
+ });
285
308
  },
286
309
  ],
287
310
  },
288
311
  show: {
289
312
  actions: [],
290
- structure: [],
313
+ layout: [
314
+ (props) => {
315
+ const { resource, model } = props;
316
+
317
+ return h(
318
+ ElDescriptions,
319
+ {
320
+ border: true,
321
+ column: 1,
322
+ },
323
+ resource.description.structure.map((item, index) =>
324
+ h(
325
+ ElDescriptionsItem,
326
+ {
327
+ key: index,
328
+ labelWidth: "20%",
329
+ },
330
+ {
331
+ label: () =>
332
+ item.label ||
333
+ item.key[0].toUpperCase() +
334
+ item.key.slice(1),
335
+ default: () =>
336
+ item.render
337
+ ? h(item.render(props))
338
+ : model?.[item.key] || "",
339
+ },
340
+ ),
341
+ ),
342
+ );
343
+ },
344
+ ],
291
345
  },
292
346
  defaults: "",
293
347
  icon: `icon-${singular}`,
@@ -297,7 +351,7 @@ export function meta(name, properties = {}) {
297
351
  }
298
352
  ```
299
353
 
300
- The structure arrays typically take a simple payload for their built in rendering but allow a render function for more complex layouts i.e
354
+ Layout is an array of functions that return render functions
301
355
 
302
356
  ```js
303
357
  import { h, resolveComponent } from "vue";
@@ -305,34 +359,66 @@ import { h, resolveComponent } from "vue";
305
359
  {
306
360
  // ...
307
361
  show: {
362
+ layout: [
363
+ ({ model }) =>
364
+ h(resolveComponent("router-link"), {
365
+ class: "underline",
366
+ to: {
367
+ name: "companies.show",
368
+ params: { id: model.company_id },
369
+ },
370
+ text: model.company.name,
371
+ })
372
+ ],
373
+ },
374
+ }
375
+ ```
376
+
377
+ You can see above that the show & index route have a default render function returned for a table and description block. If you want to keep this you can grab the existing render function from the `defaultResource` export.
378
+
379
+ ```js
380
+ import { defaultResource, meta } from "../../../resource/index.js";
381
+
382
+ {
383
+ // ...
384
+ index: {
385
+ layout: [
386
+ () => h("div", "I appear above"),
387
+ ...defaultResource.index.layout,
388
+ () => h("div", "I appear below"),
389
+ ],
390
+ },
391
+ }
392
+ ```
393
+
394
+ Structure arrays take objects. The objects require a key only but have other optional properties. A render function can also be passed to fully customize the rendering that happens.
395
+
396
+ ```js
397
+ {
398
+ table: {
308
399
  structure: [
309
- [
310
- {
311
- label: "Email",
312
- key: "email",
313
- },
314
- {
315
- label: "Company",
316
- render: ({ model }) =>
317
- h(resolveComponent("router-link"), {
318
- class: "underline",
319
- to: {
320
- name: "companies.show",
321
- params: { id: model.company_id },
322
- },
323
- text: model.company.name,
324
- }),
325
- },
326
- ],
327
400
  {
328
- render: ({ model }) =>
329
- h(VelFormRole, {
330
- overrides: model.overrides_roles_and_permissions,
331
- form: { roles: model.roles.map((d) => d.id) },
332
- readonly: true,
333
- }),
401
+ key: "name",
402
+ sortable: true,
403
+ },
404
+ {
405
+ key: "role",
406
+ render: () => h("div", "Custom template"),
334
407
  },
335
408
  ],
336
409
  },
410
+ form: {
411
+ structure: [
412
+ {
413
+ key: "name",
414
+ },
415
+ {
416
+ key: "provider_name",
417
+ label: "Provider",
418
+ render: ({ model }) => h("span", model?.provider_name.label ?? ""),
419
+ initial: ({ model }) => model?.provider_name.value ?? null,
420
+ }
421
+ ]
422
+ }
337
423
  }
338
424
  ```
@@ -1,13 +1,15 @@
1
1
  <template>
2
2
  <div class="vel-app">
3
3
  <VelHeader class="justify-end-dive">
4
- <GSvg
5
- class="logo"
6
- style="width: 180px"
7
- embed
8
- asis
9
- :name="$store.state.auth.logo"
10
- />
4
+ <router-link :to="{ name: 'index' }">
5
+ <GSvg
6
+ class="logo"
7
+ style="width: 180px"
8
+ embed
9
+ asis
10
+ :name="$store.state.auth.logo"
11
+ />
12
+ </router-link>
11
13
  <template #links>
12
14
  <div class="flex items-center pr">
13
15
  <GIcon
@@ -22,7 +22,9 @@
22
22
  >
23
23
  <!-- Support a custom render function -->
24
24
  <template v-if="item.render" #default="scope">
25
- <component :is="item.render(scope.row, this)" />
25
+ <component
26
+ :is="item.render({ model: scope.row, ...this })"
27
+ />
26
28
  </template>
27
29
  </el-table-column>
28
30
  </template>
@@ -6,7 +6,7 @@ import VelTableSorter from "../../../../components/layout/TableSorter.vue";
6
6
  import VelRoleLegend from "../../../../components/layout/RoleLegend.vue";
7
7
  import component from "./form.vue";
8
8
  import userResource from "../PUsers/resource.js";
9
- import { meta } from "../../../resource/index.js";
9
+ import { defaultResource, meta } from "../../../resource/index.js";
10
10
 
11
11
  import { ElNotification } from "element-plus";
12
12
  import { h } from "vue";
@@ -16,6 +16,10 @@ export default [
16
16
  "companies",
17
17
  {
18
18
  defaults: "include=primary_contact",
19
+ permissions: {
20
+ create: ({ $store }) => $store.getters.can("write companies"),
21
+ edit: ({ $store }) => $store.getters.can("write companies"),
22
+ },
19
23
  singular: "company",
20
24
  icon: "icon-cases",
21
25
  form: {
@@ -34,145 +38,127 @@ export default [
34
38
  table: {
35
39
  structure: [
36
40
  {
37
- label: "Name",
38
41
  key: "name",
39
42
  sortable: true,
40
43
  },
41
44
  {
42
- label: "Total users",
43
45
  key: "user_count",
44
- sortable: false,
46
+ label: "Total users",
45
47
  width: "150",
46
48
  },
47
49
  {
48
- label: "Role",
49
- render: (row) =>
50
+ key: "role",
51
+ render: ({ model }) =>
50
52
  h(
51
- row.roles.length === 1 ? Chip : Chips,
52
- row.roles.length === 1
53
+ model.roles.length === 1 ? Chip : Chips,
54
+ model.roles.length === 1
53
55
  ? {
54
- name: row.roles[0].name,
55
- label: row.roles[0].label,
56
+ name: model.roles[0].name,
57
+ label: model.roles[0].label,
56
58
  }
57
- : { array: row.roles },
59
+ : { array: model.roles },
58
60
  ),
59
61
  },
60
62
  ],
61
63
  },
62
- index: {
64
+ description: {
63
65
  structure: [
64
66
  {
65
- render: ({ resource, $store }) =>
66
- h(VelTableSorter, {
67
- key: "PIndex",
68
- "json-data": {
69
- ...resource,
70
- tableStructure: resource.table.structure,
71
- },
72
- defaults: resource.defaults,
73
- "fixed-height": false,
74
- "display-edit-action":
75
- $store.getters.can("write companies"),
76
- }),
67
+ key: "domains",
68
+ render: ({ model }) => h("span", model.domains.join(", ")),
77
69
  },
78
70
  {
79
- render: () =>
80
- h(VelRoleLegend, {
81
- class: "mt-5",
82
- }),
71
+ key: "sso_enabled",
72
+ label: "SSO Enabled",
83
73
  },
84
- ],
85
- },
86
- show: {
87
- actions: [
88
74
  {
75
+ key: "primary_contact",
76
+ label: "Primary Contact",
89
77
  render: ({ model }) =>
90
- model.primary_contact &&
91
- h(
92
- VelButton,
93
- {
94
- type: "primary",
95
- async onClick() {
96
- try {
97
- const res = await axios.post(
98
- `/api/companies/${model.id}/welcome`,
99
- );
100
- ElNotification({
101
- title: "Success",
102
- message: res.data.message,
103
- type: "success",
104
- });
105
-
106
- model.primary_contact_contacted = true;
107
- } catch (e) {
108
- ElNotification({
109
- title: "Warning",
110
- message:
111
- e.response?.data?.message ||
112
- e.message,
113
- type: "warning",
114
- });
115
- }
116
- },
117
- },
118
- "Send welcome email",
119
- ),
78
+ h("span", model.primary_contact?.name),
120
79
  },
121
- ],
122
- structure: [
123
- [
124
- {
125
- label: "Domains",
126
- render: ({ model }) =>
127
- h("span", model.domains.join(", ")),
128
- },
129
- {
130
- label: "SSO Enabled",
131
- key: "sso_enabled",
132
- },
133
- {
134
- label: "Primary Contact",
135
- render: ({ model }) =>
136
- h("span", model.primary_contact?.name),
137
- },
138
- {
139
- label: "Primary Contact Email",
140
- render: ({ model }) =>
141
- h("span", model.primary_contact?.email),
142
- },
143
- {
144
- label: "Primary Contact Contacted",
145
- render: ({ model }) =>
146
- h("span", !!model.primary_contact_contacted),
147
- },
148
- {
149
- label: "Total users",
150
- key: "user_count",
151
- },
152
- ],
153
80
  {
81
+ key: "primary_contact_email",
82
+ label: "Primary Contact Email",
154
83
  render: ({ model }) =>
155
- h(VelFormRole, {
156
- overrides: model.overrides_roles_and_permissions,
157
- form: { roles: model.roles.map((d) => d.id) },
158
- readonly: true,
159
- }),
84
+ h("span", model.primary_contact?.email),
160
85
  },
161
86
  {
162
- render: ({ model, $store }) => {
163
- const resource = meta(...userResource);
164
- return h(VelTableSorter, {
165
- key: "PIndex",
166
- "json-data": {
167
- ...resource,
168
- tableStructure: resource.table.structure,
87
+ key: "primary_contact_contacted",
88
+ label: "Primary Contact Contacted",
89
+ render: ({ model }) =>
90
+ h("span", !!model.primary_contact_contacted),
91
+ },
92
+ {
93
+ label: "Total users",
94
+ key: "user_count",
95
+ },
96
+ ],
97
+ },
98
+ index: {
99
+ layout: [
100
+ ...defaultResource.index.layout,
101
+ () =>
102
+ h(VelRoleLegend, {
103
+ class: "mt-5",
104
+ }),
105
+ ],
106
+ },
107
+ show: {
108
+ actions: [
109
+ ({ model }) =>
110
+ model.primary_contact &&
111
+ h(
112
+ VelButton,
113
+ {
114
+ type: "primary",
115
+ async onClick() {
116
+ try {
117
+ const res = await axios.post(
118
+ `/api/companies/${model.id}/welcome`,
119
+ );
120
+ ElNotification({
121
+ title: "Success",
122
+ message: res.data.message,
123
+ type: "success",
124
+ });
125
+
126
+ model.primary_contact_contacted = true;
127
+ } catch (e) {
128
+ ElNotification({
129
+ title: "Warning",
130
+ message:
131
+ e.response?.data?.message ||
132
+ e.message,
133
+ type: "warning",
134
+ });
135
+ }
169
136
  },
170
- defaults: `include=company&filter[company_id]=${model.id}`,
171
- "fixed-height": false,
172
- "display-edit-action":
173
- $store.getters.can("write users"),
174
- });
175
- },
137
+ },
138
+ "Send welcome email",
139
+ ),
140
+ ],
141
+ layout: [
142
+ ...defaultResource.show.layout,
143
+ ({ model }) =>
144
+ h(VelFormRole, {
145
+ overrides: model.overrides_roles_and_permissions,
146
+ form: { roles: model.roles.map((d) => d.id) },
147
+ readonly: true,
148
+ }),
149
+ ({ model, $store }) => {
150
+ const resource = meta(...userResource);
151
+ return h(VelTableSorter, {
152
+ key: "PIndex",
153
+ "json-data": {
154
+ ...resource,
155
+ tableStructure: resource.table.structure,
156
+ },
157
+ defaults: `include=company&filter[company_id]=${model.id}`,
158
+ "fixed-height": false,
159
+ "display-edit-action":
160
+ $store.getters.can("write users"),
161
+ });
176
162
  },
177
163
  ],
178
164
  },
@@ -4,6 +4,7 @@ import Chips from "../../../../components/layout/Chips.vue";
4
4
  import VelTableSorter from "../../../../components/layout/TableSorter.vue";
5
5
  import VelRoleLegend from "../../../../components/layout/RoleLegend.vue";
6
6
  import component from "./form.vue";
7
+ import { defaultResource } from "../../../resource/index.js";
7
8
 
8
9
  import { ElMessageBox } from "element-plus";
9
10
  import { ElNotification } from "element-plus";
@@ -27,6 +28,10 @@ export default [
27
28
  searchable: {
28
29
  value: "email",
29
30
  },
31
+ permissions: {
32
+ create: ({ $store }) => $store.getters.can("write users"),
33
+ edit: ({ $store }) => $store.getters.can("write users"),
34
+ },
30
35
  form: {
31
36
  async submit({ model, form, $router, $store, method }) {
32
37
  try {
@@ -111,19 +116,16 @@ export default [
111
116
  table: {
112
117
  structure: [
113
118
  {
114
- label: "Name",
115
119
  key: "name",
116
120
  sortable: true,
117
121
  },
118
122
  {
119
- label: "Email",
120
123
  key: "email",
121
- sortable: true,
122
124
  },
123
125
  {
124
- label: "Company",
126
+ key: "company",
125
127
  sortable: true,
126
- render: (model) =>
128
+ render: ({ model }) =>
127
129
  h(resolveComponent("router-link"), {
128
130
  class: "underline",
129
131
  to: {
@@ -134,80 +136,65 @@ export default [
134
136
  }),
135
137
  },
136
138
  {
137
- label: "Role",
138
- render: (row) =>
139
+ key: "role",
140
+ render: ({ model }) =>
139
141
  h(
140
- !row.overrides_roles_and_permissions ||
141
- row.roles.length === 1
142
+ !model.overrides_roles_and_permissions ||
143
+ model.roles.length === 1
142
144
  ? Chip
143
145
  : Chips,
144
- !row.overrides_roles_and_permissions
146
+ !model.overrides_roles_and_permissions
145
147
  ? {
146
148
  name: "inherited",
147
149
  label: "Inherited",
148
150
  }
149
- : row.roles.length === 1
151
+ : model.roles.length === 1
150
152
  ? {
151
- name: row.roles[0].name,
152
- label: row.roles[0].label,
153
+ name: model.roles[0].name,
154
+ label: model.roles[0].label,
153
155
  }
154
- : { array: row.roles },
156
+ : { array: model.roles },
155
157
  ),
156
158
  },
157
159
  ],
158
160
  },
159
- index: {
161
+ description: {
160
162
  structure: [
161
163
  {
162
- render: ({ resource, $store }) =>
163
- h(VelTableSorter, {
164
- key: "PIndex",
165
- "json-data": {
166
- ...resource,
167
- tableStructure: resource.table.structure,
168
- },
169
- defaults: resource.defaults,
170
- "fixed-height": false,
171
- "display-edit-action":
172
- $store.getters.can("write users"),
173
- }),
164
+ key: "email",
174
165
  },
175
166
  {
176
- render: () =>
177
- h(VelRoleLegend, {
178
- class: "mt-5",
167
+ key: "company",
168
+ render: ({ model }) =>
169
+ h(resolveComponent("router-link"), {
170
+ class: "underline",
171
+ to: {
172
+ name: "companies.show",
173
+ params: { id: model.company_id },
174
+ },
175
+ text: model.company.name,
179
176
  }),
180
177
  },
181
178
  ],
182
179
  },
180
+ index: {
181
+ layout: [
182
+ ...defaultResource.index.layout,
183
+ () =>
184
+ h(VelRoleLegend, {
185
+ class: "mt-5",
186
+ }),
187
+ ],
188
+ },
183
189
  show: {
184
- structure: [
185
- [
186
- {
187
- label: "Email",
188
- key: "email",
189
- },
190
- {
191
- label: "Company",
192
- render: ({ model }) =>
193
- h(resolveComponent("router-link"), {
194
- class: "underline",
195
- to: {
196
- name: "companies.show",
197
- params: { id: model.company_id },
198
- },
199
- text: model.company.name,
200
- }),
201
- },
202
- ],
203
- {
204
- render: ({ model }) =>
205
- h(VelFormRole, {
206
- overrides: model.overrides_roles_and_permissions,
207
- form: { roles: model.roles.map((d) => d.id) },
208
- readonly: true,
209
- }),
210
- },
190
+ layout: [
191
+ ...defaultResource.show.layout,
192
+ ({ model }) =>
193
+ h(VelFormRole, {
194
+ overrides: model.overrides_roles_and_permissions,
195
+ form: { roles: model.roles.map((d) => d.id) },
196
+ readonly: true,
197
+ }),
211
198
  ],
212
199
  },
213
200
  },
@@ -18,6 +18,7 @@
18
18
  :submit="submit"
19
19
  :method="method"
20
20
  :resource="resource"
21
+ :model="model"
21
22
  />
22
23
  </div>
23
24
  </div>
@@ -9,22 +9,18 @@
9
9
 
10
10
  <div class="flex gap items-center justify-end">
11
11
  <template
12
- v-for="(row, index) in resource.index.actions"
12
+ v-for="(render, index) in resource.index.actions"
13
13
  :key="index"
14
14
  >
15
- <template v-if="row.render">
16
- <component :is="row.render(this)" />
17
- </template>
15
+ <component :is="render(this)" />
18
16
  </template>
19
17
  </div>
20
18
 
21
19
  <template
22
- v-for="(row, index) in resource.index.structure"
20
+ v-for="(render, index) in resource.index.layout"
23
21
  :key="index"
24
22
  >
25
- <template v-if="row.render">
26
- <component :is="row.render(this)" />
27
- </template>
23
+ <component :is="render(this)" />
28
24
  </template>
29
25
  </div>
30
26
  </div>
@@ -48,6 +48,10 @@ export default {
48
48
  required: true,
49
49
  type: Object,
50
50
  },
51
+ model: {
52
+ type: Object,
53
+ default: null,
54
+ },
51
55
  },
52
56
  };
53
57
  </script>
@@ -14,15 +14,13 @@
14
14
  :title="`${model.name} ${model.last_name ?? ''}`"
15
15
  >
16
16
  <template
17
- v-for="(row, index) in resource.show.actions"
17
+ v-for="(render, index) in resource.show.actions"
18
18
  :key="index"
19
19
  >
20
- <template v-if="row.render">
21
- <component :is="row.render(this)" />
22
- </template>
20
+ <component :is="render(this)" />
23
21
  </template>
24
22
  <VelButton
25
- v-if="resource.permissions.edit"
23
+ v-if="resource.permissions.edit(this)"
26
24
  tag="a"
27
25
  type="primary"
28
26
  @click="
@@ -45,37 +43,13 @@
45
43
  <hr class="my-3 hr-muted" />
46
44
 
47
45
  <template
48
- v-for="(row, index) in resource.show.structure"
46
+ v-for="(render, index) in resource.show.layout"
49
47
  :key="index"
50
48
  >
51
- <template v-if="row.render">
52
- <component :is="row.render(this)" />
53
- </template>
54
- <el-descriptions v-else border column="1">
55
- <el-descriptions-item
56
- v-for="(item, i) in row"
57
- :key="i"
58
- :label-width="'20%'"
59
- >
60
- <template #label>
61
- {{
62
- item.label ||
63
- item.key[0].toUpperCase() +
64
- item.key.slice(1)
65
- }}
66
- </template>
67
-
68
- <template v-if="item.render">
69
- <component :is="item.render(this)" />
70
- </template>
71
- <template v-else>
72
- {{ model[item.key] }}
73
- </template>
74
- </el-descriptions-item>
75
- </el-descriptions>
49
+ <component :is="render(this)" />
76
50
 
77
51
  <hr
78
- v-if="index < resource.show.structure.length - 1"
52
+ v-if="index < resource.show.layout.length - 1"
79
53
  class="my-3 hr-muted"
80
54
  />
81
55
  </template>
@@ -93,7 +67,6 @@
93
67
  import axios from "axios";
94
68
  import VelSpinner from "../../../components/form/Spinner.vue";
95
69
  import VelButton from "../../../components/basic/Button.vue";
96
- import { ElDescriptions, ElDescriptionsItem } from "element-plus";
97
70
 
98
71
  export default {
99
72
  components: {
@@ -103,8 +76,6 @@ export default {
103
76
  .default,
104
77
  VelSpinner,
105
78
  VelButton,
106
- ElDescriptions,
107
- ElDescriptionsItem,
108
79
  },
109
80
 
110
81
  props: {
@@ -5,8 +5,11 @@ import { merge } from "lodash";
5
5
  import { h } from "vue";
6
6
 
7
7
  import VTableSorter from "../../components/layout/TableSorter.vue";
8
+ import { ElDescriptions, ElDescriptionsItem } from "element-plus";
8
9
 
9
- export function meta(name, properties = {}) {
10
+ export const defaultResource = meta();
11
+
12
+ export function meta(name = "default", properties = {}) {
10
13
  const singular = properties.singular || name.slice(0, -1);
11
14
 
12
15
  return merge(
@@ -19,8 +22,8 @@ export function meta(name, properties = {}) {
19
22
  pageLink: name,
20
23
  api: `/api/${name}`,
21
24
  permissions: {
22
- create: true,
23
- edit: true,
25
+ create: () => true,
26
+ edit: () => true,
24
27
  },
25
28
  searchable: {
26
29
  value: "name",
@@ -29,32 +32,76 @@ export function meta(name, properties = {}) {
29
32
  form: {
30
33
  component: null,
31
34
  fields: () => ({}),
35
+ structure: [],
32
36
  },
33
37
  table: {
34
- structure: [],
38
+ structure: [
39
+ {
40
+ key: "id",
41
+ },
42
+ ],
35
43
  },
36
- index: {
37
- actions: [],
44
+ description: {
38
45
  structure: [
39
46
  {
40
- render: ({ resource }) =>
41
- h(VTableSorter, {
42
- key: "PIndex",
43
- "json-data": {
44
- ...resource,
45
- tableStructure: resource.table.structure,
46
- },
47
- defaults: resource.defaults,
48
- "fixed-height": false,
49
- "display-edit-action":
50
- resource.permissions.create,
51
- }),
47
+ key: "id",
48
+ },
49
+ ],
50
+ },
51
+ index: {
52
+ actions: [],
53
+ layout: [
54
+ (props) => {
55
+ const { resource } = props;
56
+
57
+ return h(VTableSorter, {
58
+ key: "PIndex",
59
+ "json-data": {
60
+ ...resource,
61
+ tableStructure: resource.table.structure,
62
+ },
63
+ defaults: resource.defaults,
64
+ "fixed-height": false,
65
+ "display-edit-action":
66
+ resource.permissions.create(props),
67
+ });
52
68
  },
53
69
  ],
54
70
  },
55
71
  show: {
56
72
  actions: [],
57
- structure: [],
73
+ layout: [
74
+ (props) => {
75
+ const { resource, model } = props;
76
+
77
+ return h(
78
+ ElDescriptions,
79
+ {
80
+ border: true,
81
+ column: 1,
82
+ },
83
+ resource.description.structure.map((item, index) =>
84
+ h(
85
+ ElDescriptionsItem,
86
+ {
87
+ key: index,
88
+ labelWidth: "20%",
89
+ },
90
+ {
91
+ label: () =>
92
+ item.label ||
93
+ item.key[0].toUpperCase() +
94
+ item.key.slice(1),
95
+ default: () =>
96
+ item.render
97
+ ? h(item.render(props))
98
+ : model?.[item.key] || "",
99
+ },
100
+ ),
101
+ ),
102
+ );
103
+ },
104
+ ],
58
105
  },
59
106
  defaults: "",
60
107
  icon: `icon-${singular}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishawack/lab-velocity",
3
- "version": "2.0.0-beta.13",
3
+ "version": "2.0.0-beta.15",
4
4
  "description": "Avalere Health branded style system",
5
5
  "scripts": {
6
6
  "setup": "npm ci || npm i && npm run content",