@fishawack/lab-velocity 2.0.0-beta.31 → 2.0.0-beta.33

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.
@@ -18,7 +18,12 @@ export default [
18
18
  {
19
19
  api: {
20
20
  params: {
21
- show: () => ({ include: "primary_contact" }),
21
+ index: ({ $route }) => ({
22
+ "filter[withTrashed]": $route.query.trashed,
23
+ }),
24
+ show: () => ({
25
+ include: "primary_contact",
26
+ }),
22
27
  },
23
28
  },
24
29
  permissions: {
@@ -35,12 +40,21 @@ export default [
35
40
  primary_contact: model?.primary_contact?.id || null,
36
41
  domains: model?.domains || [],
37
42
  seats: model?.seats != null ? model.seats : null,
38
- roles: model?.roles.map((val) => val.id) || [],
43
+ roles:
44
+ model?.roles.map((val) => ({
45
+ label: val.label,
46
+ value: val.id,
47
+ })) || [],
39
48
  sso_client_id: model?.sso_client_id || undefined,
40
49
  sso_tenant: model?.sso_tenant || undefined,
41
50
  sso_client_secret: model?.sso_client_secret || undefined,
42
51
  sso_type: model?.sso_type || undefined,
43
52
  }),
53
+ preparation: (props) => {
54
+ const data = props.form.data();
55
+ data.roles = data.roles.map((d) => d.value);
56
+ return data;
57
+ },
44
58
  },
45
59
  table: {
46
60
  structure: [
@@ -1,4 +1,5 @@
1
1
  import VelFormRole from "../../../../components/layout/FormRole.vue";
2
+ import VelButton from "../../../../components/basic/Button.vue";
2
3
  import Chip from "../../../../components/layout/Chip.vue";
3
4
  import Chips from "../../../../components/layout/Chips.vue";
4
5
  import VelRoleLegend from "../../../../components/layout/RoleLegend.vue";
@@ -9,6 +10,7 @@ import { defaultResource, meta } from "../../../resource/index.js";
9
10
  import { ElMessageBox } from "element-plus";
10
11
  import { ElNotification } from "element-plus";
11
12
  import { h, resolveComponent } from "vue";
13
+ import axios from "axios";
12
14
 
13
15
  function generatePassword(
14
16
  length = 20,
@@ -26,7 +28,10 @@ export default [
26
28
  {
27
29
  api: {
28
30
  params: {
29
- index: () => ({ include: "company" }),
31
+ index: ({ $route }) => ({
32
+ include: "company",
33
+ "filter[withTrashed]": $route.query.trashed,
34
+ }),
30
35
  show: () => ({ include: "company" }),
31
36
  },
32
37
  },
@@ -36,11 +41,18 @@ export default [
36
41
  permissions: {
37
42
  create: ({ $store }) => $store.getters.can("write users"),
38
43
  edit: ({ $store }) => $store.getters.can("write users"),
39
- delete: ({ $store }) => $store.getters.can("delete companies"),
44
+ delete: ({ $store }) => $store.getters.can("delete users"),
40
45
  },
41
46
  form: {
42
- async submit({ model, form, $router, $store, method, resource }) {
47
+ async submit(props) {
48
+ const { model, form, $router, $store, method, resource } =
49
+ props;
50
+
51
+ const hold = form.data();
52
+
43
53
  try {
54
+ form.populate(resource.form.preparation(props));
55
+
44
56
  if (method === "post") {
45
57
  if (form.set_password) {
46
58
  const password = generatePassword();
@@ -94,6 +106,10 @@ export default [
94
106
  }
95
107
  } catch (e) {
96
108
  console.log(e);
109
+ } finally {
110
+ if (!form.successful || !form.__options.resetOnSuccess) {
111
+ form.populate(hold);
112
+ }
97
113
  }
98
114
  },
99
115
  component,
@@ -102,9 +118,10 @@ export default [
102
118
  name: model?.name ?? null,
103
119
  email: model?.email ?? null,
104
120
  roles: model?.overrides_roles_and_permissions
105
- ? model?.roles.map((val) => {
106
- return val.id;
107
- })
121
+ ? model?.roles.map((val) => ({
122
+ label: val.label,
123
+ value: val.id,
124
+ }))
108
125
  : [],
109
126
  company_id: model?.company_id ?? null,
110
127
  },
@@ -118,6 +135,11 @@ export default [
118
135
  }
119
136
  : {}),
120
137
  }),
138
+ preparation: (props) => {
139
+ const data = props.form.data();
140
+ data.roles = data.roles.map((d) => d.value);
141
+ return data;
142
+ },
121
143
  },
122
144
  table: {
123
145
  structure: [
@@ -132,17 +154,23 @@ export default [
132
154
  key: "company",
133
155
  sortable: true,
134
156
  render: ({ model }) =>
135
- h(resolveComponent("router-link"), {
136
- class: "underline",
137
- to: {
138
- name: "companies.show",
139
- params: {
140
- [meta(...companyResource).id]:
141
- model.company_id,
142
- },
143
- },
144
- text: model.company?.name,
145
- }),
157
+ model.company && model.company?.deleted_at
158
+ ? h(
159
+ "span",
160
+ { class: "vel-basic__error" },
161
+ model.company.name,
162
+ )
163
+ : h(resolveComponent("router-link"), {
164
+ class: "underline",
165
+ to: {
166
+ name: "companies.show",
167
+ params: {
168
+ [meta(...companyResource).id]:
169
+ model.company_id,
170
+ },
171
+ },
172
+ text: model.company.name,
173
+ }),
146
174
  },
147
175
  {
148
176
  key: "role",
@@ -175,17 +203,23 @@ export default [
175
203
  {
176
204
  key: "company",
177
205
  render: ({ model }) =>
178
- h(resolveComponent("router-link"), {
179
- class: "underline",
180
- to: {
181
- name: "companies.show",
182
- params: {
183
- [meta(...companyResource).id]:
184
- model.company_id,
185
- },
186
- },
187
- text: model.company.name,
188
- }),
206
+ model.company && model.company?.deleted_at
207
+ ? h(
208
+ "span",
209
+ { class: "vel-basic__error" },
210
+ model.company.name,
211
+ )
212
+ : h(resolveComponent("router-link"), {
213
+ class: "underline",
214
+ to: {
215
+ name: "companies.show",
216
+ params: {
217
+ [meta(...companyResource).id]:
218
+ model.company_id,
219
+ },
220
+ },
221
+ text: model.company.name,
222
+ }),
189
223
  },
190
224
  ],
191
225
  },
@@ -199,6 +233,38 @@ export default [
199
233
  ],
200
234
  },
201
235
  show: {
236
+ actions: [
237
+ ({ model, $store, $root }) =>
238
+ $store.getters.can("impersonate users") &&
239
+ h(
240
+ VelButton,
241
+ {
242
+ type: "danger",
243
+ async onClick() {
244
+ try {
245
+ const user = (
246
+ await axios.post(
247
+ `/api/users/impersonate`,
248
+ {
249
+ user_id: model.id,
250
+ },
251
+ )
252
+ ).data.data;
253
+
254
+ $store.commit("setUser", user);
255
+
256
+ if (!$store.getters.can("view admin")) {
257
+ window.location = `${$root.spaUrl}?authenticated=1`;
258
+ }
259
+ } catch (e) {
260
+ console.log(e);
261
+ }
262
+ },
263
+ },
264
+ "Impersonate",
265
+ ),
266
+ ...defaultResource.show.actions,
267
+ ],
202
268
  layout: [
203
269
  ...defaultResource.show.layout,
204
270
  ({ model }) => ({
@@ -1,21 +1,14 @@
1
1
  <template>
2
2
  <div class="relative">
3
3
  <section id="resetPasswordForm">
4
- <h1
5
- class="h2 h2--small"
6
- v-html="!form.successful ? 'Welcome' : 'Success'"
7
- />
4
+ <h1 class="h2 h2--small" v-html="'Welcome'" />
8
5
  <form class="form" @submit.prevent="submit">
9
- <div v-if="!form.successful">
6
+ <div>
10
7
  <p class="mt-2 mb-0 color-highlight">
11
- <strong class=""
12
- >Email:
13
- {{ $store.state?.auth?.user?.email }}</strong
14
- >
8
+ <strong class="">Email: {{ email }}</strong>
15
9
  </p>
16
10
  <p class="mt-0.5">
17
- <strong
18
- >Hello {{ $store.state?.auth?.user?.name }}</strong
11
+ <strong>Hello {{ name }}</strong
19
12
  >, and welcome to {{ $root.appName }}. To maintain
20
13
  security, anyone signing in with a one-time-password
21
14
  must <strong>create a new password</strong> the first
@@ -42,26 +35,13 @@
42
35
  native-type="submit"
43
36
  class="mt-3"
44
37
  type="primary"
45
- :disabled="form.processing || !isPasswordValid"
46
- :loading="form.processing"
38
+ :disabled="loading || !isPasswordValid"
39
+ :loading="loading"
47
40
  @click="onSubmit"
48
41
  >
49
42
  <span v-text="'Update password'" />
50
43
  </elButton>
51
44
  </div>
52
- <div v-else>
53
- <strong class=""
54
- >Email: {{ $store.state.auth?.user?.email }}</strong
55
- >
56
- <p v-text="`Your password has been updated.`" />
57
- <elButton
58
- tag="router-link"
59
- type="primary"
60
- :to="{ name: $store.state.auth.redirect }"
61
- >
62
- <span v-text="'Continue'" />
63
- </elButton>
64
- </div>
65
45
  </form>
66
46
  </section>
67
47
  </div>
@@ -69,6 +49,7 @@
69
49
 
70
50
  <script>
71
51
  import Form from "form-backend-validation";
52
+ import { ElNotification } from "element-plus";
72
53
 
73
54
  export default {
74
55
  components: {
@@ -89,11 +70,17 @@ export default {
89
70
  { resetOnSuccess: false },
90
71
  ),
91
72
  isPasswordValid: false,
73
+ loading: false,
74
+ name: "",
75
+ email: "",
92
76
  };
93
77
  },
94
78
 
95
79
  mounted() {
96
80
  this.$store.dispatch("getUser");
81
+
82
+ this.name = this.$store.state?.auth?.user?.name;
83
+ this.email = this.$store.state?.auth?.user?.email;
97
84
  },
98
85
 
99
86
  methods: {
@@ -110,8 +97,6 @@ export default {
110
97
  }
111
98
  },
112
99
  async login() {
113
- this.loading = true;
114
-
115
100
  try {
116
101
  const res = await this.form.post("/login");
117
102
 
@@ -125,13 +110,21 @@ export default {
125
110
  } catch (e) {
126
111
  console.log(e);
127
112
  } finally {
128
- this.loading = false;
129
113
  await this.postLogin();
130
114
  }
131
115
  },
132
116
 
133
117
  async postLogin() {
134
118
  const { data: user } = await this.$store.dispatch("getUser");
119
+
120
+ this.$router.push({ name: this.$store.state.auth.redirect });
121
+
122
+ ElNotification({
123
+ type: "success",
124
+ message: "Password updated successfully",
125
+ duration: 10000,
126
+ class: "el-notification--success el-notification--right-override",
127
+ });
135
128
  },
136
129
 
137
130
  updatePasswordValidity(isValid) {
@@ -48,11 +48,11 @@ export default {
48
48
 
49
49
  methods: {
50
50
  async submit() {
51
- const hold = this.form.data();
52
-
53
51
  if (this.resource.form.submit) {
54
52
  await this.resource.form.submit(this);
55
53
  } else {
54
+ const hold = this.form.data();
55
+
56
56
  try {
57
57
  this.form.populate(this.resource.form.preparation(this));
58
58
 
@@ -73,11 +73,11 @@ export default {
73
73
 
74
74
  methods: {
75
75
  async submit() {
76
- const hold = this.form.data();
77
-
78
76
  if (this.resource.form.submit) {
79
77
  await this.resource.form.submit(this);
80
78
  } else {
79
+ const hold = this.form.data();
80
+
81
81
  try {
82
82
  this.form.populate(this.resource.form.preparation(this));
83
83
 
@@ -53,11 +53,13 @@ export function meta(name = "default", properties = {}) {
53
53
  form: {
54
54
  component: null,
55
55
  fields: () => ({}),
56
+ preparation: ({ form }) => form.data(),
56
57
  structure: [],
57
58
  },
58
59
  table: {
59
60
  actions: [
60
61
  ({ model, resource }, { $router }) =>
62
+ !model.deleted_at &&
61
63
  h(
62
64
  VelButton,
63
65
  {
@@ -79,21 +81,24 @@ export function meta(name = "default", properties = {}) {
79
81
  const { $router } = props;
80
82
 
81
83
  if (resource.permissions.edit(props, { model })) {
82
- return h(
83
- VelButton,
84
- {
85
- tag: "a",
86
- size: "small",
87
- onClick: () => {
88
- $router.push({
89
- name: `${resource.routeName}.edit`,
90
- params: {
91
- [resource.id]: model.id,
92
- },
93
- });
84
+ return (
85
+ !model.deleted_at &&
86
+ h(
87
+ VelButton,
88
+ {
89
+ tag: "a",
90
+ size: "small",
91
+ onClick: () => {
92
+ $router.push({
93
+ name: `${resource.routeName}.edit`,
94
+ params: {
95
+ [resource.id]: model.id,
96
+ },
97
+ });
98
+ },
94
99
  },
95
- },
96
- () => "Edit",
100
+ () => "Edit",
101
+ )
97
102
  );
98
103
  }
99
104
  },
@@ -101,52 +106,56 @@ export function meta(name = "default", properties = {}) {
101
106
  const { $emit } = props;
102
107
 
103
108
  if (resource.permissions.delete(props, { model })) {
104
- return h({
105
- data: () => ({
106
- loading: false,
107
- }),
108
- render() {
109
- return h(
110
- ElPopconfirm,
111
- {
112
- title: `Are you sure you want to delete this ${resource.singular}?`,
113
- confirmButtonText: "Delete",
114
- cancelButtonText: "Cancel",
115
- confirmButtonType: "danger",
116
- onConfirm: async () => {
117
- this.loading = true;
109
+ return (
110
+ !model.deleted_at &&
111
+ h({
112
+ data: () => ({
113
+ loading: false,
114
+ }),
115
+ render() {
116
+ return h(
117
+ ElPopconfirm,
118
+ {
119
+ title: `Are you sure you want to delete this ${resource.singular}?`,
120
+ confirmButtonText: "Delete",
121
+ cancelButtonText: "Cancel",
122
+ confirmButtonType: "danger",
123
+ onConfirm: async () => {
124
+ this.loading = true;
118
125
 
119
- await axios.delete(
120
- `${resource.api.endpoint(props)}/${model.id}`,
121
- );
126
+ await axios.delete(
127
+ `${resource.api.endpoint(props)}/${model.id}`,
128
+ );
122
129
 
123
- $emit("reload");
130
+ $emit("reload");
124
131
 
125
- ElNotification({
126
- title: "Success",
127
- message: `${resource.singularTitle} with id ${model.id} deleted.`,
128
- type: "success",
129
- });
132
+ ElNotification({
133
+ title: "Success",
134
+ message: `${resource.singularTitle} with id ${model.id} deleted.`,
135
+ type: "success",
136
+ });
130
137
 
131
- this.loading = false;
138
+ this.loading = false;
139
+ },
132
140
  },
133
- },
134
- {
135
- reference: () =>
136
- h(
137
- VelButton,
138
- {
139
- tag: "a",
140
- type: "danger",
141
- size: "small",
142
- loading: this.loading,
143
- },
144
- () => `Delete`,
145
- ),
146
- },
147
- );
148
- },
149
- });
141
+ {
142
+ reference: () =>
143
+ h(
144
+ VelButton,
145
+ {
146
+ tag: "a",
147
+ type: "danger",
148
+ size: "small",
149
+ loading:
150
+ this.loading,
151
+ },
152
+ () => `Delete`,
153
+ ),
154
+ },
155
+ );
156
+ },
157
+ })
158
+ );
150
159
  }
151
160
  },
152
161
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishawack/lab-velocity",
3
- "version": "2.0.0-beta.31",
3
+ "version": "2.0.0-beta.33",
4
4
  "description": "Avalere Health branded style system",
5
5
  "scripts": {
6
6
  "setup": "npm ci || npm i && npm run content",