@fishawack/lab-velocity 2.0.0-beta.6 → 2.0.0-beta.61

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 +221 -31
  14. package/_Build/vue/components/form/Wysiwyg2.vue +87 -2
  15. package/_Build/vue/components/form/wysiwyg2-video.js +41 -0
  16. package/_Build/vue/components/layout/Alert.vue +5 -5
  17. package/_Build/vue/components/layout/Audit.vue +159 -0
  18. package/_Build/vue/{modules/AuthModule/components/VBreadcrumbs.vue → components/layout/Breadcrumbs.vue} +4 -4
  19. package/_Build/vue/{modules/AuthModule/components → components/layout}/Chips.vue +2 -2
  20. package/_Build/vue/components/layout/Footer.vue +11 -10
  21. package/_Build/vue/{modules/AuthModule/components/VFormFooter.vue → components/layout/FormFooter.vue} +2 -2
  22. package/_Build/vue/{modules/AuthModule/components → components/layout}/FormRole.vue +8 -8
  23. package/_Build/vue/components/layout/Layout.vue +94 -0
  24. package/_Build/vue/components/layout/Navigation.vue +83 -0
  25. package/_Build/vue/{modules/AuthModule/components/VPageHeader.vue → components/layout/PageHeader.vue} +14 -8
  26. package/_Build/vue/components/layout/SideBar.vue +26 -0
  27. package/_Build/vue/{modules/AuthModule/components/VTable.vue → components/layout/Table.vue} +24 -12
  28. package/_Build/vue/{modules/AuthModule/components/VTableSorter.vue → components/layout/TableSorter.vue} +92 -48
  29. package/_Build/vue/components/layout/TokenDisplay.vue +52 -0
  30. package/_Build/vue/components/layout/pageTitle.vue +1 -1
  31. package/_Build/vue/components/navigation/Menu.vue +6 -1
  32. package/_Build/vue/components/navigation/MenuItem.vue +7 -2
  33. package/_Build/vue/components/navigation/MenuItemGroup.vue +7 -2
  34. package/_Build/vue/modules/AuthModule/js/axios.js +21 -1
  35. package/_Build/vue/modules/AuthModule/js/clear-cookies.js +34 -0
  36. package/_Build/vue/modules/AuthModule/js/guest-request.js +32 -0
  37. package/_Build/vue/modules/AuthModule/js/impersonation-banner.js +102 -0
  38. package/_Build/vue/modules/AuthModule/js/router.js +91 -114
  39. package/_Build/vue/modules/AuthModule/js/store.js +23 -6
  40. package/_Build/vue/modules/AuthModule/routes/PCompanies/columns.js +268 -0
  41. package/_Build/vue/modules/AuthModule/routes/PCompanies/resource.js +213 -0
  42. package/_Build/vue/modules/AuthModule/routes/PIntegrations/columns.js +58 -0
  43. package/_Build/vue/modules/AuthModule/routes/PIntegrations/resource.js +79 -0
  44. package/_Build/vue/modules/AuthModule/routes/PTeams/columns.js +78 -0
  45. package/_Build/vue/modules/AuthModule/routes/PTeams/resource.js +251 -0
  46. package/_Build/vue/modules/AuthModule/routes/PUsers/SetPasswordAction.vue +51 -0
  47. package/_Build/vue/modules/AuthModule/routes/PUsers/SetPasswordDialog.vue +138 -0
  48. package/_Build/vue/modules/AuthModule/routes/PUsers/columns.js +349 -0
  49. package/_Build/vue/modules/AuthModule/routes/PUsers/resource.js +239 -0
  50. package/_Build/vue/modules/AuthModule/routes/account-exists.vue +2 -2
  51. package/_Build/vue/modules/AuthModule/routes/change-password.vue +28 -32
  52. package/_Build/vue/modules/AuthModule/routes/container.vue +2 -11
  53. package/_Build/vue/modules/AuthModule/routes/expired-reset.vue +4 -4
  54. package/_Build/vue/modules/AuthModule/routes/expired-verification.vue +10 -9
  55. package/_Build/vue/modules/AuthModule/routes/force-reset.vue +44 -58
  56. package/_Build/vue/modules/AuthModule/routes/forgot.vue +10 -5
  57. package/_Build/vue/modules/AuthModule/routes/login.vue +12 -19
  58. package/_Build/vue/modules/AuthModule/routes/logincallback.vue +1 -3
  59. package/_Build/vue/modules/AuthModule/routes/loginsso.vue +14 -10
  60. package/_Build/vue/modules/AuthModule/routes/logout.vue +14 -5
  61. package/_Build/vue/modules/AuthModule/routes/logoutheadless.vue +16 -5
  62. package/_Build/vue/modules/AuthModule/routes/register.vue +24 -28
  63. package/_Build/vue/modules/AuthModule/routes/reset.vue +20 -14
  64. package/_Build/vue/modules/AuthModule/routes/success-forgot.vue +14 -8
  65. package/_Build/vue/modules/AuthModule/routes/success-reset.vue +2 -2
  66. package/_Build/vue/modules/AuthModule/routes/success-verify.vue +1 -3
  67. package/_Build/vue/modules/AuthModule/routes/verify.vue +11 -14
  68. package/_Build/vue/modules/resource/Children/create.vue +99 -0
  69. package/_Build/vue/modules/resource/Children/edit.vue +124 -0
  70. package/_Build/vue/modules/resource/Children/index.vue +42 -0
  71. package/_Build/vue/modules/resource/Children/partials/form.vue +111 -0
  72. package/_Build/vue/modules/resource/Children/show.vue +170 -0
  73. package/_Build/vue/modules/resource/index.js +562 -0
  74. package/_Build/vue/modules/resource/parent.vue +63 -0
  75. package/_Build/vue/modules/resource/trashable.js +104 -0
  76. package/_base.scss +0 -1
  77. package/_defaults.scss +2 -2
  78. package/components/_auth.scss +19 -61
  79. package/components/_datepicker.scss +1 -0
  80. package/components/_descriptions.scss +2 -0
  81. package/components/_footer.scss +1 -0
  82. package/components/_form.scss +18 -0
  83. package/components/_header.scss +3 -27
  84. package/components/_layout.scss +56 -0
  85. package/components/_menu.scss +0 -5
  86. package/components/_sidebar.scss +12 -27
  87. package/components/_table.scss +3 -0
  88. package/components/_token-display.scss +41 -0
  89. package/components/_wysiwyg2.scss +10 -0
  90. package/general.scss +1 -0
  91. package/index.js +31 -1
  92. package/package.json +7 -4
  93. package/_Build/vue/components/layout/sideBar.vue +0 -25
  94. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/Upload/upload.vue +0 -259
  95. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/create.vue +0 -62
  96. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/edit.vue +0 -98
  97. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/index.vue +0 -90
  98. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/partials/form.vue +0 -181
  99. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/Children/show.vue +0 -266
  100. package/_Build/vue/modules/AuthModule/adminRoutes/PCompanies/parent.vue +0 -36
  101. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/create.vue +0 -112
  102. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/edit.vue +0 -103
  103. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/index.vue +0 -112
  104. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/partials/form.vue +0 -173
  105. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/Children/show.vue +0 -123
  106. package/_Build/vue/modules/AuthModule/adminRoutes/PUsers/parent.vue +0 -36
  107. package/components/_input.scss +0 -0
  108. /package/_Build/vue/{modules/AuthModule/components → components/layout}/AuthModal.vue +0 -0
  109. /package/_Build/vue/{modules/AuthModule/components → components/layout}/Chip.vue +0 -0
  110. /package/_Build/vue/{modules/AuthModule/components/VPasswordValidation.vue → components/layout/PasswordValidation.vue} +0 -0
  111. /package/_Build/vue/{modules/AuthModule/components/VRoleLegend.vue → components/layout/RoleLegend.vue} +0 -0
@@ -0,0 +1,349 @@
1
+ import { h, resolveComponent, ref } from "vue";
2
+ import { debounce } from "lodash";
3
+ import axios from "axios";
4
+
5
+ import VelBasic from "../../../../components/form/basic.vue";
6
+ import VelButton from "../../../../components/basic/Button.vue";
7
+ import VelCheckbox from "../../../../components/form/Checkbox.vue";
8
+ import VelFormRole from "../../../../components/layout/FormRole.vue";
9
+ import Chip from "../../../../components/layout/Chip.vue";
10
+ import Chips from "../../../../components/layout/Chips.vue";
11
+
12
+ import companyResource from "../PCompanies/resource.js";
13
+ import { meta } from "../../../resource/index.js";
14
+
15
+ /**
16
+ * Shared reactive state for SSO company detection.
17
+ * Used by the email column's render.write and by form.submit in resource.js.
18
+ */
19
+ export const detectedCompany = ref(null);
20
+
21
+ const debouncedFetchCompany = debounce((domain) => {
22
+ if (domain) {
23
+ axios
24
+ .get("/api/companies", {
25
+ params: {
26
+ "filter[domains.domain]": domain,
27
+ },
28
+ })
29
+ .then((res) => {
30
+ detectedCompany.value = res.data.data[0] || null;
31
+ })
32
+ .catch(() => {
33
+ detectedCompany.value = null;
34
+ });
35
+ } else {
36
+ detectedCompany.value = null;
37
+ }
38
+ }, 500);
39
+
40
+ /**
41
+ * Hoisted inline component for the email column's render.write.
42
+ * Must be a stable reference so Vue doesn't remount on every render.
43
+ */
44
+ const EmailField = {
45
+ props: ["form"],
46
+ data() {
47
+ return {
48
+ company: detectedCompany.value,
49
+ };
50
+ },
51
+ watch: {
52
+ "form.email": {
53
+ handler(val) {
54
+ const domain = val?.split("@")[1];
55
+ debouncedFetchCompany(domain);
56
+ },
57
+ },
58
+ },
59
+ created() {
60
+ this.$watch(
61
+ () => detectedCompany.value,
62
+ (val) => {
63
+ this.company = val;
64
+ },
65
+ );
66
+ },
67
+ render() {
68
+ const form = this.form;
69
+ const company = this.company;
70
+ const isSSOCompany = !!company?.sso_enabled;
71
+
72
+ return h("div", [
73
+ h(VelBasic, {
74
+ modelValue: form.email,
75
+ "onUpdate:modelValue": (val) => {
76
+ form.email = val;
77
+ },
78
+ placeholder: "Email",
79
+ label: "Email",
80
+ type: "text",
81
+ name: "email",
82
+ error: form.errors,
83
+ }),
84
+ h("p", { class: "mb-1" }, ["Company: ", h("span", company?.name)]),
85
+ h("hr", { class: "my-3 hr-muted" }),
86
+ isSSOCompany
87
+ ? h("p", { class: "mb-3" }, [
88
+ "This user belongs to an SSO-enabled company. They will authenticate via SSO on first login. No password is required.",
89
+ ])
90
+ : h("div", [
91
+ h(VelCheckbox, {
92
+ modelValue: form.notify_user,
93
+ "onUpdate:modelValue": (val) => {
94
+ form.notify_user = val;
95
+ },
96
+ name: "notify_user",
97
+ error: form.errors,
98
+ label: "Send email to notify user of account and password",
99
+ }),
100
+ h(VelCheckbox, {
101
+ modelValue: form.force_password_change,
102
+ "onUpdate:modelValue": (val) => {
103
+ form.force_password_change = val;
104
+ },
105
+ name: "force_password_change",
106
+ error: form.errors,
107
+ label: "Force password change on first login",
108
+ }),
109
+ h(VelCheckbox, {
110
+ modelValue: form.set_password,
111
+ "onUpdate:modelValue": (val) => {
112
+ form.set_password = val;
113
+ },
114
+ name: "set_password",
115
+ error: form.errors,
116
+ label: "Auto generate password",
117
+ }),
118
+ !form.set_password &&
119
+ h("div", [
120
+ h(VelBasic, {
121
+ modelValue: form.password,
122
+ "onUpdate:modelValue": (val) => {
123
+ form.password = val;
124
+ },
125
+ name: "password",
126
+ error: form.errors,
127
+ type: "password",
128
+ placeholder: "Password",
129
+ label: "Password",
130
+ }),
131
+ h(VelBasic, {
132
+ modelValue: form.password_confirmation,
133
+ "onUpdate:modelValue": (val) => {
134
+ form.password_confirmation = val;
135
+ },
136
+ name: "password_confirmation",
137
+ error: form.errors,
138
+ type: "password",
139
+ placeholder: "Password Confirmation",
140
+ label: "Password Confirmation",
141
+ }),
142
+ ]),
143
+ ]),
144
+ h("hr", { class: "my-5 hr-muted" }),
145
+ ]);
146
+ },
147
+ };
148
+
149
+ /**
150
+ * Hoisted inline component for the roles column's render.write.
151
+ * Must be a stable reference so Vue doesn't remount on every render.
152
+ */
153
+ const RolesField = {
154
+ props: ["form"],
155
+ data() {
156
+ return {
157
+ enableRoles: null,
158
+ };
159
+ },
160
+ watch: {
161
+ "form.roles": {
162
+ immediate: true,
163
+ handler(newVal) {
164
+ if (this.enableRoles === null) {
165
+ this.enableRoles = newVal && newVal.length > 0;
166
+ }
167
+ },
168
+ },
169
+ },
170
+ render() {
171
+ const form = this.form;
172
+
173
+ if (this.enableRoles) {
174
+ return h("div", [
175
+ h(
176
+ VelButton,
177
+ {
178
+ onClick: () => {
179
+ form.roles = [];
180
+ this.enableRoles = false;
181
+ },
182
+ },
183
+ "Reset roles",
184
+ ),
185
+ h(VelFormRole, { form }),
186
+ h("hr", { class: "my-5 hr-muted" }),
187
+ ]);
188
+ }
189
+
190
+ return h("div", [
191
+ h(
192
+ VelButton,
193
+ {
194
+ onClick: () => {
195
+ this.enableRoles = true;
196
+ },
197
+ },
198
+ () => [
199
+ h(resolveComponent("GIcon"), {
200
+ name: "icon-plus",
201
+ embed: true,
202
+ asis: true,
203
+ class: "fill-0 icon--0.5 mr",
204
+ }),
205
+ "Override roles",
206
+ ],
207
+ ),
208
+ h("p", { class: "mt-2" }, [
209
+ "Roles will be inherited from the company level.",
210
+ ]),
211
+ h("hr", { class: "my-5 hr-muted" }),
212
+ ]);
213
+ },
214
+ };
215
+
216
+ export default [
217
+ {
218
+ key: "name",
219
+ sortable: true,
220
+ condition: {
221
+ form: {
222
+ write: ({ method }) => method === "post",
223
+ },
224
+ },
225
+ },
226
+ {
227
+ key: "email",
228
+ condition: {
229
+ form: {
230
+ write: ({ method }) => method === "post",
231
+ },
232
+ },
233
+ render: {
234
+ write: ({ form }) => h(EmailField, { form }),
235
+ },
236
+ initial: ({ model }) => model?.email ?? null,
237
+ },
238
+ {
239
+ key: "company",
240
+ sortable: true,
241
+ condition: {
242
+ form: false,
243
+ },
244
+ render: {
245
+ read: ({ model }) =>
246
+ !model.company
247
+ ? h("span", "")
248
+ : model.company.deleted_at
249
+ ? h(
250
+ "span",
251
+ { class: "vel-basic__error" },
252
+ model.company.name,
253
+ )
254
+ : h(resolveComponent("router-link"), {
255
+ class: "underline",
256
+ to: {
257
+ name: "companies.show",
258
+ params: {
259
+ [meta(...companyResource).id]:
260
+ model.company_id,
261
+ },
262
+ },
263
+ text: model.company.name,
264
+ }),
265
+ },
266
+ },
267
+ {
268
+ key: "email_verified_at",
269
+ label: "Email Verified",
270
+ condition: {
271
+ table: false,
272
+ form: false,
273
+ },
274
+ render: {
275
+ read: ({ model }) =>
276
+ h(
277
+ "span",
278
+ {},
279
+ model.email_verified_at
280
+ ? new Date(model.email_verified_at).toLocaleString()
281
+ : "Not verified",
282
+ ),
283
+ },
284
+ },
285
+ {
286
+ key: "verified",
287
+ label: "Verified",
288
+ condition: {
289
+ description: false,
290
+ form: false,
291
+ },
292
+ render: {
293
+ read: ({ model }) =>
294
+ h(
295
+ "span",
296
+ {
297
+ title: model.email_verified_at
298
+ ? `Verified: ${new Date(model.email_verified_at).toLocaleString()}`
299
+ : "Not verified",
300
+ style: {
301
+ color: model.email_verified_at ? "green" : "red",
302
+ fontSize: "18px",
303
+ },
304
+ },
305
+ model.email_verified_at ? "✓" : "✗",
306
+ ),
307
+ },
308
+ },
309
+ {
310
+ key: "roles",
311
+ label: "Role",
312
+ condition: {
313
+ description: false,
314
+ form: {
315
+ write: ({ $store }) => $store.getters.can("edit roles"),
316
+ },
317
+ },
318
+ initial: ({ model }) =>
319
+ model?.overrides_roles_and_permissions
320
+ ? model?.roles.map((val) => ({
321
+ label: val.label,
322
+ value: val.id,
323
+ }))
324
+ : [],
325
+ preparation: ({ form }) =>
326
+ form.roles.map((d) => (typeof d === "object" ? d.value : d)),
327
+ render: {
328
+ read: ({ model }) =>
329
+ h(
330
+ !model.overrides_roles_and_permissions ||
331
+ model.roles.length === 1
332
+ ? Chip
333
+ : Chips,
334
+ !model.overrides_roles_and_permissions
335
+ ? {
336
+ name: "inherited",
337
+ label: "Inherited",
338
+ }
339
+ : model.roles.length === 1
340
+ ? {
341
+ name: model.roles[0].name,
342
+ label: model.roles[0].label,
343
+ }
344
+ : { array: model.roles },
345
+ ),
346
+ write: ({ model, form }) => h(RolesField, { form }),
347
+ },
348
+ },
349
+ ];
@@ -0,0 +1,239 @@
1
+ import { merge } from "lodash";
2
+ import { h } from "vue";
3
+ import axios from "axios";
4
+ import { ElMessageBox, ElNotification } from "element-plus";
5
+
6
+ import { columns, defaultResource } from "../../../resource/index.js";
7
+ import usersColumns, { detectedCompany } from "./columns.js";
8
+
9
+ import VelFormRole from "../../../../components/layout/FormRole.vue";
10
+ import VelButton from "../../../../components/basic/Button.vue";
11
+ import VelRoleLegend from "../../../../components/layout/RoleLegend.vue";
12
+ import SetPasswordAction from "./SetPasswordAction.vue";
13
+
14
+ function generatePassword(
15
+ length = 20,
16
+ characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$",
17
+ ) {
18
+ return (
19
+ Array.from(crypto.getRandomValues(new Uint32Array(length)))
20
+ .map((x) => characters[x % characters.length])
21
+ .join("") + Math.floor(Math.random() * 10)
22
+ );
23
+ }
24
+
25
+ export default [
26
+ "users",
27
+ {
28
+ api: {
29
+ params: {
30
+ index: () => ({
31
+ include: "company",
32
+ }),
33
+ show: () => ({ include: "company" }),
34
+ },
35
+ },
36
+ searchable: {
37
+ value: "email",
38
+ },
39
+ auditable: true,
40
+ trashable: true,
41
+ permissions: {
42
+ create: ({ $store }) => $store.getters.can("write users"),
43
+ edit: ({ $store }) => $store.getters.can("write users"),
44
+ delete: ({ $store }) => $store.getters.can("delete users"),
45
+ },
46
+ ...merge(columns(usersColumns), {
47
+ form: {
48
+ fields: ({ model, method }) => ({
49
+ ...columns(usersColumns).form.fields({ model }),
50
+ ...(method === "post"
51
+ ? {
52
+ notify_user: true,
53
+ force_password_change: true,
54
+ set_password: true,
55
+ password: null,
56
+ password_confirmation: null,
57
+ }
58
+ : {}),
59
+ }),
60
+ async submit(props) {
61
+ const { model, form, $router, $store, method, resource } =
62
+ props;
63
+
64
+ const hold = form.data();
65
+
66
+ try {
67
+ form.populate(resource.form.preparation(props));
68
+
69
+ if (method === "post") {
70
+ const isSSOCompany =
71
+ !!detectedCompany.value?.sso_enabled;
72
+
73
+ if (!isSSOCompany && form.set_password) {
74
+ const password = generatePassword();
75
+ form.password = password;
76
+ form.password_confirmation = password;
77
+ }
78
+
79
+ let res = await form.post(`/api/users`);
80
+
81
+ if (
82
+ !isSSOCompany &&
83
+ form.set_password &&
84
+ !form.notify_user
85
+ ) {
86
+ ElMessageBox.alert(
87
+ `<p>The password below will not be shown again. Ensure you've taken a copy if you plan to send manually. <br><br><strong>Email</strong>: ${form.email}<br> <strong>Password</strong>: ${form.password}</p>`,
88
+ "User Created",
89
+ {
90
+ confirmButtonText: "Ok",
91
+ dangerouslyUseHTMLString: true,
92
+ },
93
+ )
94
+ .then(() => {
95
+ $router.replace({
96
+ name: "users.show",
97
+ params: {
98
+ [resource.id]: res.data.id,
99
+ },
100
+ });
101
+ })
102
+ .catch(() => {});
103
+ } else {
104
+ ElNotification({
105
+ title: "Success",
106
+ message: isSSOCompany
107
+ ? "SSO user pre-provisioned successfully"
108
+ : "User created a notified of their new account",
109
+ type: "success",
110
+ });
111
+
112
+ $router.replace({
113
+ name: "users.show",
114
+ params: {
115
+ [resource.id]: res.data.id,
116
+ },
117
+ });
118
+ }
119
+ } else {
120
+ let res = await form.post(`/api/users/${model.id}`);
121
+
122
+ if (res.data.id === $store.state.auth.user.id) {
123
+ await $store.dispatch("getUser");
124
+ }
125
+
126
+ $router.replace({
127
+ name: "users.show",
128
+ params: {
129
+ [resource.id]: res.data.id,
130
+ },
131
+ });
132
+ }
133
+ } catch (e) {
134
+ console.log(e);
135
+ } finally {
136
+ if (
137
+ !form.successful ||
138
+ !form.__options.resetOnSuccess
139
+ ) {
140
+ form.populate(hold);
141
+ }
142
+ }
143
+ },
144
+ },
145
+ index: {
146
+ layout: [
147
+ ...defaultResource.index.layout,
148
+ () =>
149
+ h(VelRoleLegend, {
150
+ class: "mt-5",
151
+ }),
152
+ ],
153
+ },
154
+ show: {
155
+ actions: [
156
+ ({ model, $store }) =>
157
+ $store.getters.can("write users") &&
158
+ !model.email_verified_at &&
159
+ h(
160
+ VelButton,
161
+ {
162
+ async onClick() {
163
+ try {
164
+ const res = await axios.post(
165
+ `/api/users/${model.id}/verify`,
166
+ );
167
+
168
+ Object.assign(model, res.data.data);
169
+
170
+ ElNotification({
171
+ title: "Success",
172
+ message: "User marked as verified",
173
+ type: "success",
174
+ });
175
+ } catch (e) {
176
+ console.log(e);
177
+ }
178
+ },
179
+ },
180
+ "Mark as Verified",
181
+ ),
182
+ ({ model, $store }) => {
183
+ if (!$store.getters.can("write users")) {
184
+ return;
185
+ }
186
+
187
+ return h(SetPasswordAction, {
188
+ userId: model.id,
189
+ model,
190
+ });
191
+ },
192
+ ({ model, $store, $root }) =>
193
+ $store.getters.can("impersonate users") &&
194
+ h(
195
+ VelButton,
196
+ {
197
+ type: "danger",
198
+ async onClick() {
199
+ try {
200
+ const user = (
201
+ await axios.post(
202
+ `/api/users/impersonate`,
203
+ {
204
+ user_id: model.id,
205
+ },
206
+ )
207
+ ).data.data;
208
+
209
+ $store.commit("setUser", user);
210
+
211
+ if (!$store.getters.can("view admin")) {
212
+ window.location = `${$root.spaUrl}?authenticated=1`;
213
+ }
214
+ } catch (e) {
215
+ console.log(e);
216
+ }
217
+ },
218
+ },
219
+ "Impersonate",
220
+ ),
221
+ ...defaultResource.show.actions,
222
+ ],
223
+ tabs: [
224
+ ...defaultResource.show.tabs,
225
+ ({ model }) => ({
226
+ label: "Access control",
227
+ component: h(VelFormRole, {
228
+ overrides: model.overrides_roles_and_permissions,
229
+ form: {
230
+ roles: model.roles.map((d) => d.id),
231
+ },
232
+ readonly: true,
233
+ }),
234
+ }),
235
+ ],
236
+ },
237
+ }),
238
+ },
239
+ ];
@@ -3,10 +3,10 @@
3
3
  <section id="resetPasswordForm">
4
4
  <h1 class="h2">Account already exists</h1>
5
5
 
6
- <p class="mt AM-mb-0 color-21">
6
+ <p class="mt mb-0 color-21">
7
7
  <strong class="">Company: {{ $route.query.company }}</strong>
8
8
  </p>
9
- <p class="AM-mt-0.5">Your company already has an active account.</p>
9
+ <p class="mt-0.5">Your company already has an active account.</p>
10
10
 
11
11
  <elButton
12
12
  tag="router-link"