@fishawack/lab-velocity 2.0.0-beta.24 → 2.0.0-beta.26

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.
@@ -23,7 +23,15 @@
23
23
  <!-- Support a custom render function -->
24
24
  <template v-if="item.render" #default="scope">
25
25
  <component
26
- :is="item.render({ model: scope.row, ...this })"
26
+ :is="
27
+ item.render(
28
+ {
29
+ model: scope.row,
30
+ ...additionalInfo,
31
+ },
32
+ this,
33
+ )
34
+ "
27
35
  />
28
36
  </template>
29
37
  </el-table-column>
@@ -72,6 +80,12 @@ export default {
72
80
  VelButton,
73
81
  },
74
82
 
83
+ inject: {
84
+ additionalInfo: {
85
+ default: () => ({}),
86
+ },
87
+ },
88
+
75
89
  props: {
76
90
  data: {
77
91
  type: [Array, Object],
@@ -118,7 +132,7 @@ export default {
118
132
  default: true,
119
133
  },
120
134
  },
121
- emits: ["sort"],
135
+ emits: ["sort", "reload"],
122
136
 
123
137
  methods: {
124
138
  handleSort(data) {
@@ -80,6 +80,7 @@
80
80
  :display-show-action="displayShowAction"
81
81
  :display-edit-action="displayEditAction"
82
82
  @sort="handleSort"
83
+ @reload="reload"
83
84
  >
84
85
  <slot name="table-content"></slot>
85
86
  </VelTable>
@@ -128,10 +129,10 @@ export default {
128
129
  default: true,
129
130
  type: Boolean,
130
131
  },
131
- defaults: {
132
+ apiParams: {
132
133
  required: false,
133
- type: String,
134
- default: "",
134
+ type: Object,
135
+ default: () => ({}),
135
136
  },
136
137
  displayActions: {
137
138
  type: Boolean,
@@ -159,7 +160,7 @@ export default {
159
160
  return {
160
161
  search: null,
161
162
  sort: "-id",
162
- query: [],
163
+ query: {},
163
164
  table_data: [],
164
165
  table_meta: null,
165
166
  };
@@ -176,13 +177,21 @@ export default {
176
177
  },
177
178
 
178
179
  methods: {
180
+ reload() {
181
+ this.fetchData({ page: this.table_meta.current_page }).then(
182
+ (data) => {
183
+ this.table_data = data.data;
184
+ this.table_meta = data.meta;
185
+ },
186
+ );
187
+ },
179
188
  handleSearch(data) {
180
189
  if (data === null || data.length < 3) {
181
- this.query = [];
190
+ this.query = {};
182
191
  } else {
183
- this.query = [
184
- `filter[${this.$refs.search.$el.dataset.key}]=${data}`,
185
- ];
192
+ this.query = {
193
+ [`filter[${this.$refs.search.$el.dataset.key}]`]: data,
194
+ };
186
195
  }
187
196
  this.fetchData({}).then((data) => {
188
197
  this.table_data = data.data;
@@ -203,17 +212,15 @@ export default {
203
212
  },
204
213
 
205
214
  fetchData: function ({ page = "1" }) {
206
- const mergedQuery = [
207
- ...this.query,
208
- this.defaults,
209
- `sort=${this.sort}`,
210
- `page=${page}`,
211
- ];
212
-
213
- const query = mergedQuery.join("&");
214
-
215
215
  return axios
216
- .get(`${this.$props.jsonData.api}${query ? "?" + query : ""}`)
216
+ .get(`${this.$props.jsonData.api}`, {
217
+ params: {
218
+ sort: this.sort,
219
+ page: page,
220
+ ...this.query,
221
+ ...this.apiParams,
222
+ },
223
+ })
217
224
  .then((res) => res.data)
218
225
  .catch(console.log);
219
226
  },
@@ -179,7 +179,9 @@ export default {
179
179
 
180
180
  mounted() {
181
181
  axios
182
- .getAll(`/api/users?filter[company_id]=${this.$route.params.id}`)
182
+ .getAll(
183
+ `/api/users?filter[company_id]=${this.$route.params.companiesId}`,
184
+ )
183
185
  .then((res) => {
184
186
  this.users = res.data.data;
185
187
  });
@@ -9,13 +9,17 @@ import userResource from "../PUsers/resource.js";
9
9
  import { defaultResource, meta } from "../../../resource/index.js";
10
10
 
11
11
  import { ElNotification } from "element-plus";
12
- import { h } from "vue";
12
+ import { h, resolveComponent } from "vue";
13
13
  import axios from "axios";
14
14
 
15
15
  export default [
16
16
  "companies",
17
17
  {
18
- defaults: "include=primary_contact",
18
+ api: {
19
+ params: {
20
+ show: { include: "primary_contact" },
21
+ },
22
+ },
19
23
  permissions: {
20
24
  create: ({ $store }) => $store.getters.can("write companies"),
21
25
  edit: ({ $store }) => $store.getters.can("write companies"),
@@ -148,23 +152,47 @@ export default [
148
152
  form: { roles: model.roles.map((d) => d.id) },
149
153
  readonly: true,
150
154
  }),
151
- ({ model, $store }) => {
155
+ ({ model, $store, $router, ...rest }) => {
152
156
  const resource = meta(...userResource);
153
157
 
154
- return h(VelTableSorter, {
155
- key: "PIndex",
156
- "json-data": {
157
- ...resource,
158
- tableStructure: resource.table.structure,
159
- },
160
- defaults: `include=company&filter[company_id]=${model.id}`,
161
- idKey: resource.id,
162
- "fixed-height": false,
163
- "display-create-action":
164
- $store.getters.can("write users"),
165
- "display-edit-action":
166
- $store.getters.can("write users"),
167
- });
158
+ resource.api.params.index["filter[company_id]"] = model.id;
159
+
160
+ const props = {
161
+ model,
162
+ $store,
163
+ $router,
164
+ ...rest,
165
+ resource,
166
+ };
167
+
168
+ return h("div", [
169
+ h("div", { class: "flex justify-end items-end" }, [
170
+ resource.permissions.create(props) &&
171
+ h(
172
+ VelButton,
173
+ {
174
+ tag: "a",
175
+ type: "primary",
176
+ size: "large",
177
+ onClick: () => {
178
+ $router.push({
179
+ name: `${resource.slug}.create`,
180
+ });
181
+ },
182
+ },
183
+ () => [
184
+ h(resolveComponent("GIcon"), {
185
+ class: "fill-0 mr-0.5 icon--0.5",
186
+ name: "icon-plus",
187
+ embed: true,
188
+ artboard: true,
189
+ }),
190
+ `Create ${resource.singular}`,
191
+ ],
192
+ ),
193
+ ]),
194
+ h(VelTableSorter, resource.index.structure(props)),
195
+ ]);
168
196
  },
169
197
  ],
170
198
  },
@@ -24,7 +24,12 @@ function generatePassword(
24
24
  export default [
25
25
  "users",
26
26
  {
27
- defaults: "include=company",
27
+ api: {
28
+ params: {
29
+ index: { include: "company" },
30
+ show: { include: "company" },
31
+ },
32
+ },
28
33
  searchable: {
29
34
  value: "email",
30
35
  },
@@ -136,7 +141,7 @@ export default [
136
141
  model.company_id,
137
142
  },
138
143
  },
139
- text: model.company.name,
144
+ text: model.company?.name,
140
145
  }),
141
146
  },
142
147
  {
@@ -53,7 +53,7 @@ export default {
53
53
  } else {
54
54
  try {
55
55
  let res = await this.form.post(
56
- `${this.resource.api(this)}`,
56
+ `${this.resource.api.endpoint(this)}`,
57
57
  );
58
58
 
59
59
  this.$router.replace({
@@ -51,7 +51,10 @@ export default {
51
51
  async mounted() {
52
52
  window.axios
53
53
  .get(
54
- `${this.resource.api(this)}/${this.$route.params[this.resource.id]}?${this.resource.defaults}`,
54
+ `${this.resource.api.endpoint(this)}/${this.$route.params[this.resource.id]}`,
55
+ {
56
+ params: this.resource.api.params.show,
57
+ },
55
58
  )
56
59
  .then((res) => {
57
60
  this.model = res.data.data;
@@ -72,7 +75,7 @@ export default {
72
75
  } else {
73
76
  try {
74
77
  let res = await this.form.patch(
75
- `${this.resource.api(this)}/${this.model.id}`,
78
+ `${this.resource.api.endpoint(this)}/${this.model.id}`,
76
79
  );
77
80
 
78
81
  this.$router.replace({
@@ -22,6 +22,12 @@
22
22
 
23
23
  <script>
24
24
  export default {
25
+ provide() {
26
+ return {
27
+ additionalInfo: { resource: this.resource },
28
+ };
29
+ },
30
+
25
31
  props: {
26
32
  resource: {
27
33
  type: Object,
@@ -11,7 +11,7 @@
11
11
  <div class="bg-0 p-3 box-shadow-1 border-r-4 mb-6">
12
12
  <VelPageHeader
13
13
  :icon="resource.icon"
14
- :title="`${model.name} ${model.last_name ?? ''}`"
14
+ :title="`${model.name ?? model.id} ${model.last_name ?? ''}`"
15
15
  >
16
16
  <template
17
17
  v-for="(render, index) in resource.show.actions"
@@ -89,7 +89,10 @@ export default {
89
89
 
90
90
  axios
91
91
  .get(
92
- `${this.resource.api(this)}/${this.$route.params[`${this.resource.slug}Id`]}?${this.resource.defaults}`,
92
+ `${this.resource.api.endpoint(this)}/${this.$route.params[`${this.resource.slug}Id`]}`,
93
+ {
94
+ params: this.resource.api.params.show,
95
+ },
93
96
  )
94
97
  .then((res) => {
95
98
  this.model = res.data.data;
@@ -4,8 +4,13 @@ import { merge, kebabCase, cloneDeepWith } from "lodash";
4
4
  import axios from "axios";
5
5
  import { h, resolveComponent } from "vue";
6
6
 
7
- import VTableSorter from "../../components/layout/TableSorter.vue";
8
- import { ElDescriptions, ElDescriptionsItem, ElPopconfirm } from "element-plus";
7
+ import VelTableSorter from "../../components/layout/TableSorter.vue";
8
+ import {
9
+ ElDescriptions,
10
+ ElDescriptionsItem,
11
+ ElPopconfirm,
12
+ ElNotification,
13
+ } from "element-plus";
9
14
  import VelButton from "../../components/basic/Button.vue";
10
15
 
11
16
  export const defaultResource = meta();
@@ -19,11 +24,21 @@ export function meta(name = "default", properties = {}) {
19
24
  name,
20
25
  title: properties.title || name[0].toUpperCase() + name.slice(1),
21
26
  singular,
27
+ singularTitle:
28
+ properties.singularTitle ||
29
+ singular[0].toUpperCase() + singular.slice(1),
22
30
  label: singular,
23
31
  multiLabel: name,
24
32
  slug,
25
33
  id: properties.id || `${slug}Id`,
26
- api: () => `/api/${properties.slug || kebabCase(name)}`,
34
+ icon: `icon-${singular}`,
35
+ api: {
36
+ endpoint: () => `/api/${properties.slug || kebabCase(name)}`,
37
+ params: {
38
+ index: {},
39
+ show: {},
40
+ },
41
+ },
27
42
  permissions: {
28
43
  create: () => true,
29
44
  edit: () => true,
@@ -39,6 +54,100 @@ export function meta(name = "default", properties = {}) {
39
54
  structure: [],
40
55
  },
41
56
  table: {
57
+ actions: [
58
+ ({ model, resource }, { $router }) =>
59
+ h(
60
+ VelButton,
61
+ {
62
+ tag: "a",
63
+ size: "small",
64
+ type: "primary",
65
+ onClick: () => {
66
+ $router.push({
67
+ name: `${resource.slug}.show`,
68
+ params: {
69
+ [resource.id]: model.id,
70
+ },
71
+ });
72
+ },
73
+ },
74
+ () => "View",
75
+ ),
76
+ ({ model, resource }, props) => {
77
+ const { $router } = props;
78
+
79
+ if (resource.permissions.edit(props, { model })) {
80
+ return h(
81
+ VelButton,
82
+ {
83
+ tag: "a",
84
+ size: "small",
85
+ onClick: () => {
86
+ $router.push({
87
+ name: `${resource.slug}.edit`,
88
+ params: {
89
+ [resource.id]: model.id,
90
+ },
91
+ });
92
+ },
93
+ },
94
+ () => "Edit",
95
+ );
96
+ }
97
+ },
98
+ ({ model, resource }, props) => {
99
+ const { $emit } = props;
100
+
101
+ if (resource.permissions.delete(props, { model })) {
102
+ return h({
103
+ data: () => ({
104
+ loading: false,
105
+ }),
106
+ render() {
107
+ return h(
108
+ ElPopconfirm,
109
+ {
110
+ title: `Are you sure you want to delete this ${resource.singular}?`,
111
+ confirmButtonText: "Delete",
112
+ cancelButtonText: "Cancel",
113
+ confirmButtonType: "danger",
114
+ onConfirm: async () => {
115
+ this.loading = true;
116
+
117
+ await axios.delete(
118
+ `${resource.api.endpoint(props)}/${model.id}`,
119
+ );
120
+
121
+ $emit("reload");
122
+
123
+ ElNotification({
124
+ title: "Success",
125
+ message: `${resource.singularTitle} with id ${model.id} deleted.`,
126
+ type: "success",
127
+ });
128
+
129
+ this.loading = false;
130
+ },
131
+ },
132
+ {
133
+ reference: () =>
134
+ h(
135
+ VelButton,
136
+ {
137
+ tag: "a",
138
+ type: "danger",
139
+ size: "small",
140
+ loading: this.loading,
141
+ },
142
+ () => `Delete`,
143
+ ),
144
+ },
145
+ );
146
+ },
147
+ });
148
+ }
149
+ },
150
+ ],
42
151
  structure: [
43
152
  {
44
153
  key: "id",
@@ -53,26 +162,85 @@ export function meta(name = "default", properties = {}) {
53
162
  ],
54
163
  },
55
164
  index: {
56
- actions: [],
165
+ structure: (props) => {
166
+ const { resource } = props;
167
+
168
+ return {
169
+ key: "PIndex",
170
+ "json-data": {
171
+ ...resource,
172
+ tableStructure: resource.table.structure.concat(
173
+ resource.table.actions.length
174
+ ? [
175
+ {
176
+ key: "actions",
177
+ render: ({ model }, props) =>
178
+ h(
179
+ "div",
180
+ {
181
+ class: "flex gap-2",
182
+ },
183
+ resource.table.actions.map(
184
+ (d) =>
185
+ d(
186
+ {
187
+ model,
188
+ resource,
189
+ },
190
+ props,
191
+ ),
192
+ ),
193
+ ),
194
+ },
195
+ ]
196
+ : [],
197
+ ),
198
+ api: resource.api.endpoint(props),
199
+ },
200
+ apiParams: resource.api.params.index,
201
+ idKey: resource.id,
202
+ "fixed-height": false,
203
+ displayActions: false,
204
+ };
205
+ },
206
+ actions: [
207
+ (props) => {
208
+ const { resource, $router } = props;
209
+
210
+ if (resource.permissions.create(props)) {
211
+ return h(
212
+ VelButton,
213
+ {
214
+ tag: "a",
215
+ type: "primary",
216
+ size: "large",
217
+ onClick: () => {
218
+ $router.push({
219
+ name: `${resource.slug}.create`,
220
+ });
221
+ },
222
+ },
223
+ () => [
224
+ h(resolveComponent("GIcon"), {
225
+ class: "fill-0 mr-0.5 icon--0.5",
226
+ name: "icon-plus",
227
+ embed: true,
228
+ artboard: true,
229
+ }),
230
+ `Create ${resource.singular}`,
231
+ ],
232
+ );
233
+ }
234
+ },
235
+ ],
57
236
  layout: [
58
237
  (props) => {
59
238
  const { resource } = props;
60
239
 
61
- return h(VTableSorter, {
62
- key: "PIndex",
63
- "json-data": {
64
- ...resource,
65
- tableStructure: resource.table.structure,
66
- api: resource.api(props),
67
- },
68
- defaults: resource.defaults,
69
- idKey: resource.id,
70
- "fixed-height": false,
71
- "display-create-action":
72
- resource.permissions.create(props),
73
- "display-edit-action":
74
- resource.permissions.edit(props),
75
- });
240
+ return h(
241
+ VelTableSorter,
242
+ resource.index.structure(props),
243
+ );
76
244
  },
77
245
  ],
78
246
  },
@@ -81,7 +249,7 @@ export function meta(name = "default", properties = {}) {
81
249
  (props) => {
82
250
  const { resource, model, $router } = props;
83
251
 
84
- if (resource.permissions.edit(props)) {
252
+ if (resource.permissions.edit(props, { model })) {
85
253
  return h(
86
254
  VelButton,
87
255
  {
@@ -111,7 +279,7 @@ export function meta(name = "default", properties = {}) {
111
279
  (props) => {
112
280
  const { resource, model, $router } = props;
113
281
 
114
- if (resource.permissions.delete(props)) {
282
+ if (resource.permissions.delete(props, { model })) {
115
283
  return h(
116
284
  ElPopconfirm,
117
285
  {
@@ -121,7 +289,7 @@ export function meta(name = "default", properties = {}) {
121
289
  confirmButtonType: "danger",
122
290
  onConfirm: async () => {
123
291
  await axios.delete(
124
- `${resource.api(props)}/${model.id}`,
292
+ `${resource.api.endpoint(props)}/${model.id}`,
125
293
  );
126
294
 
127
295
  $router.push({
@@ -188,8 +356,6 @@ export function meta(name = "default", properties = {}) {
188
356
  },
189
357
  ],
190
358
  },
191
- defaults: "",
192
- icon: `icon-${singular}`,
193
359
  },
194
360
  properties,
195
361
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishawack/lab-velocity",
3
- "version": "2.0.0-beta.24",
3
+ "version": "2.0.0-beta.26",
4
4
  "description": "Avalere Health branded style system",
5
5
  "scripts": {
6
6
  "setup": "npm ci || npm i && npm run content",