@fishawack/lab-velocity 2.0.0-beta.40 → 2.0.0-beta.42

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 (30) hide show
  1. package/README.md +4 -2
  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/form/Avatar.vue +86 -0
  10. package/_Build/vue/components/layout/Audit.vue +124 -56
  11. package/_Build/vue/components/layout/Layout.vue +19 -1
  12. package/_Build/vue/components/layout/TableSorter.vue +42 -12
  13. package/_Build/vue/modules/AuthModule/js/router.js +20 -36
  14. package/_Build/vue/modules/AuthModule/routes/PCompanies/columns.js +268 -0
  15. package/_Build/vue/modules/AuthModule/routes/PCompanies/resource.js +173 -232
  16. package/_Build/vue/modules/AuthModule/routes/PIntegrations/resource.js +122 -0
  17. package/_Build/vue/modules/AuthModule/routes/PTeams/resource.js +1 -0
  18. package/_Build/vue/modules/AuthModule/routes/PUsers/columns.js +349 -0
  19. package/_Build/vue/modules/AuthModule/routes/PUsers/resource.js +142 -262
  20. package/_Build/vue/modules/resource/Children/create.vue +2 -2
  21. package/_Build/vue/modules/resource/Children/edit.vue +2 -2
  22. package/_Build/vue/modules/resource/Children/partials/form.vue +71 -21
  23. package/_Build/vue/modules/resource/Children/show.vue +24 -2
  24. package/_Build/vue/modules/resource/index.js +12 -4
  25. package/components/_form.scss +18 -0
  26. package/components/_menu.scss +0 -5
  27. package/index.js +16 -0
  28. package/package.json +3 -1
  29. package/_Build/vue/modules/AuthModule/routes/PCompanies/form.vue +0 -205
  30. package/_Build/vue/modules/AuthModule/routes/PUsers/form.vue +0 -193
@@ -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
+ ];