adminforth 1.3.39 → 1.3.41
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/dist/index.js +5 -0
- package/dist/modules/configValidator.js +26 -26
- package/index.ts +6 -0
- package/modules/configValidator.ts +29 -29
- package/package.json +1 -1
- package/spa/src/App.vue +10 -5
- package/spa/src/components/ResourceListTable.vue +4 -2
- package/spa/src/components/ThreeDotsMenu.vue +1 -1
- package/spa/src/index.scss +4 -0
- package/spa/src/views/ListView.vue +3 -0
- package/types/AdminForthConfig.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -291,6 +291,7 @@ class AdminForth {
|
|
|
291
291
|
return { error: resp.error };
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
+
return { error: null };
|
|
294
295
|
});
|
|
295
296
|
}
|
|
296
297
|
resource(resourceId) {
|
|
@@ -329,6 +330,10 @@ AdminForth.Utils = {
|
|
|
329
330
|
regExp: '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).+$',
|
|
330
331
|
message: 'Password must include at least one uppercase letter, one lowercase letter, and one number'
|
|
331
332
|
},
|
|
333
|
+
},
|
|
334
|
+
EMAIL_VALIDATOR: {
|
|
335
|
+
regExp: '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$',
|
|
336
|
+
message: 'Email is not valid, must be in format example@test.com',
|
|
332
337
|
}
|
|
333
338
|
};
|
|
334
339
|
export default AdminForth;
|
|
@@ -63,32 +63,6 @@ export default class ConfigValidator {
|
|
|
63
63
|
catch (e) {
|
|
64
64
|
this.config.customization.customComponentsDir = undefined;
|
|
65
65
|
}
|
|
66
|
-
if (this.config.auth) {
|
|
67
|
-
// TODO: remove in future releases
|
|
68
|
-
if (!this.config.auth.usersResourceId && this.config.auth.resourceId) {
|
|
69
|
-
this.config.auth.usersResourceId = this.config.auth.resourceId;
|
|
70
|
-
}
|
|
71
|
-
if (!this.config.auth.usersResourceId) {
|
|
72
|
-
throw new Error('No config.auth.usersResourceId defined');
|
|
73
|
-
}
|
|
74
|
-
if (!this.config.auth.passwordHashField) {
|
|
75
|
-
throw new Error('No config.auth.passwordHashField defined');
|
|
76
|
-
}
|
|
77
|
-
if (!this.config.auth.usernameField) {
|
|
78
|
-
throw new Error('No config.auth.usernameField defined');
|
|
79
|
-
}
|
|
80
|
-
if (this.config.auth.loginBackgroundImage) {
|
|
81
|
-
errors.push(...this.checkCustomFileExists(this.config.auth.loginBackgroundImage));
|
|
82
|
-
}
|
|
83
|
-
const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
|
|
84
|
-
if (!userResource) {
|
|
85
|
-
const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId || res.table), this.config.auth.usersResourceId);
|
|
86
|
-
throw new Error(`Resource with id "${this.config.auth.usersResourceId}" not found. ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
87
|
-
}
|
|
88
|
-
if (!this.config.auth.beforeLoginConfirmation) {
|
|
89
|
-
this.config.auth.beforeLoginConfirmation = [];
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
66
|
if (!this.config.customization) {
|
|
93
67
|
this.config.customization = {};
|
|
94
68
|
}
|
|
@@ -410,6 +384,32 @@ export default class ConfigValidator {
|
|
|
410
384
|
};
|
|
411
385
|
browseMenu(this.config.menu);
|
|
412
386
|
}
|
|
387
|
+
if (this.config.auth) {
|
|
388
|
+
// TODO: remove in future releases
|
|
389
|
+
if (!this.config.auth.usersResourceId && this.config.auth.resourceId) {
|
|
390
|
+
this.config.auth.usersResourceId = this.config.auth.resourceId;
|
|
391
|
+
}
|
|
392
|
+
if (!this.config.auth.usersResourceId) {
|
|
393
|
+
throw new Error('No config.auth.usersResourceId defined');
|
|
394
|
+
}
|
|
395
|
+
if (!this.config.auth.passwordHashField) {
|
|
396
|
+
throw new Error('No config.auth.passwordHashField defined');
|
|
397
|
+
}
|
|
398
|
+
if (!this.config.auth.usernameField) {
|
|
399
|
+
throw new Error('No config.auth.usernameField defined');
|
|
400
|
+
}
|
|
401
|
+
if (this.config.auth.loginBackgroundImage) {
|
|
402
|
+
errors.push(...this.checkCustomFileExists(this.config.auth.loginBackgroundImage));
|
|
403
|
+
}
|
|
404
|
+
const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
|
|
405
|
+
if (!userResource) {
|
|
406
|
+
const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId), this.config.auth.usersResourceId);
|
|
407
|
+
throw new Error(`Resource with id "${this.config.auth.usersResourceId}" not found. ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
408
|
+
}
|
|
409
|
+
if (!this.config.auth.beforeLoginConfirmation) {
|
|
410
|
+
this.config.auth.beforeLoginConfirmation = [];
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
413
|
// check for duplicate resourceIds and show which ones are duplicated
|
|
414
414
|
const resourceIds = this.config.resources.map((res) => res.resourceId);
|
|
415
415
|
const uniqueResourceIds = new Set(resourceIds);
|
package/index.ts
CHANGED
|
@@ -50,6 +50,10 @@ class AdminForth implements IAdminForth {
|
|
|
50
50
|
regExp: '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).+$',
|
|
51
51
|
message: 'Password must include at least one uppercase letter, one lowercase letter, and one number'
|
|
52
52
|
},
|
|
53
|
+
},
|
|
54
|
+
EMAIL_VALIDATOR: {
|
|
55
|
+
regExp: '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$',
|
|
56
|
+
message: 'Email is not valid, must be in format example@test.com',
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
59
|
|
|
@@ -369,6 +373,8 @@ class AdminForth implements IAdminForth {
|
|
|
369
373
|
return { error: resp.error };
|
|
370
374
|
}
|
|
371
375
|
}
|
|
376
|
+
|
|
377
|
+
return { error: null };
|
|
372
378
|
}
|
|
373
379
|
|
|
374
380
|
resource(resourceId: string): IOperationalResource {
|
|
@@ -76,35 +76,6 @@ export default class ConfigValidator implements IConfigValidator {
|
|
|
76
76
|
this.config.customization.customComponentsDir = undefined;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (this.config.auth) {
|
|
80
|
-
// TODO: remove in future releases
|
|
81
|
-
if (!this.config.auth.usersResourceId && this.config.auth.resourceId) {
|
|
82
|
-
this.config.auth.usersResourceId = this.config.auth.resourceId;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!this.config.auth.usersResourceId) {
|
|
86
|
-
throw new Error('No config.auth.usersResourceId defined');
|
|
87
|
-
}
|
|
88
|
-
if (!this.config.auth.passwordHashField) {
|
|
89
|
-
throw new Error('No config.auth.passwordHashField defined');
|
|
90
|
-
}
|
|
91
|
-
if (!this.config.auth.usernameField) {
|
|
92
|
-
throw new Error('No config.auth.usernameField defined');
|
|
93
|
-
}
|
|
94
|
-
if (this.config.auth.loginBackgroundImage) {
|
|
95
|
-
errors.push(...this.checkCustomFileExists(this.config.auth.loginBackgroundImage));
|
|
96
|
-
}
|
|
97
|
-
const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
|
|
98
|
-
if (!userResource) {
|
|
99
|
-
const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId || res.table), this.config.auth.usersResourceId);
|
|
100
|
-
throw new Error(`Resource with id "${this.config.auth.usersResourceId}" not found. ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!this.config.auth.beforeLoginConfirmation) {
|
|
104
|
-
this.config.auth.beforeLoginConfirmation = [];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
79
|
if (!this.config.customization) {
|
|
109
80
|
this.config.customization = {};
|
|
110
81
|
}
|
|
@@ -476,6 +447,35 @@ export default class ConfigValidator implements IConfigValidator {
|
|
|
476
447
|
|
|
477
448
|
}
|
|
478
449
|
|
|
450
|
+
if (this.config.auth) {
|
|
451
|
+
// TODO: remove in future releases
|
|
452
|
+
if (!this.config.auth.usersResourceId && this.config.auth.resourceId) {
|
|
453
|
+
this.config.auth.usersResourceId = this.config.auth.resourceId;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (!this.config.auth.usersResourceId) {
|
|
457
|
+
throw new Error('No config.auth.usersResourceId defined');
|
|
458
|
+
}
|
|
459
|
+
if (!this.config.auth.passwordHashField) {
|
|
460
|
+
throw new Error('No config.auth.passwordHashField defined');
|
|
461
|
+
}
|
|
462
|
+
if (!this.config.auth.usernameField) {
|
|
463
|
+
throw new Error('No config.auth.usernameField defined');
|
|
464
|
+
}
|
|
465
|
+
if (this.config.auth.loginBackgroundImage) {
|
|
466
|
+
errors.push(...this.checkCustomFileExists(this.config.auth.loginBackgroundImage));
|
|
467
|
+
}
|
|
468
|
+
const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
|
|
469
|
+
if (!userResource) {
|
|
470
|
+
const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId ), this.config.auth.usersResourceId);
|
|
471
|
+
throw new Error(`Resource with id "${this.config.auth.usersResourceId}" not found. ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (!this.config.auth.beforeLoginConfirmation) {
|
|
475
|
+
this.config.auth.beforeLoginConfirmation = [];
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
479
|
// check for duplicate resourceIds and show which ones are duplicated
|
|
480
480
|
const resourceIds = this.config.resources.map((res) => res.resourceId);
|
|
481
481
|
const uniqueResourceIds = new Set(resourceIds);
|
package/package.json
CHANGED
package/spa/src/App.vue
CHANGED
|
@@ -313,16 +313,21 @@ function handleCustomLayout() {
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
function humanizeSnake(str: string): string {
|
|
317
|
+
if (!str) {
|
|
318
|
+
return '';
|
|
319
|
+
}
|
|
320
|
+
return str.split('_').map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
|
|
321
|
+
}
|
|
316
322
|
|
|
317
|
-
|
|
318
|
-
watch(route, () => {
|
|
323
|
+
watch([route, () => coreStore.resourceById], async () => {
|
|
319
324
|
handleCustomLayout()
|
|
320
|
-
|
|
325
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
326
|
+
const resourceTitle = coreStore.resourceById[route.params?.resourceId as string]?.label || humanizeSnake(Object.values(route.params)[0] as string);
|
|
327
|
+
title.value = `${coreStore.config?.title || coreStore.config?.brandName || 'Adminforth'} | ${ resourceTitle || route.meta.title || ' '}`;
|
|
321
328
|
useHead({
|
|
322
329
|
title: title.value,
|
|
323
330
|
})
|
|
324
|
-
|
|
325
|
-
|
|
326
331
|
});
|
|
327
332
|
|
|
328
333
|
watch (()=>coreStore.menu, () => {
|
|
@@ -381,17 +381,19 @@ async function onClick(e,row) {
|
|
|
381
381
|
if (window.getSelection().toString()) return;
|
|
382
382
|
else {
|
|
383
383
|
if (e.ctrlKey || e.metaKey) {
|
|
384
|
+
|
|
384
385
|
if (row._clickUrl) {
|
|
385
386
|
window.open(row._clickUrl, '_blank');
|
|
386
387
|
} else {
|
|
387
|
-
|
|
388
|
+
window.open(
|
|
388
389
|
router.resolve({
|
|
389
390
|
name: 'resource-show',
|
|
390
391
|
params: {
|
|
391
392
|
resourceId: props.resource.resourceId,
|
|
392
393
|
primaryKey: row._primaryKeyValue,
|
|
393
394
|
},
|
|
394
|
-
})
|
|
395
|
+
}).fullPath,
|
|
396
|
+
'_blank'
|
|
395
397
|
);
|
|
396
398
|
}
|
|
397
399
|
} else {
|
package/spa/src/index.scss
CHANGED
|
@@ -1442,7 +1442,7 @@ export class Sorts {
|
|
|
1442
1442
|
export interface IOperationalResource {
|
|
1443
1443
|
get: (filter: IAdminForthFilter | IAdminForthFilter[]) => Promise<any | null>;
|
|
1444
1444
|
|
|
1445
|
-
list: (filter: IAdminForthFilter | IAdminForthFilter[], limit
|
|
1445
|
+
list: (filter: IAdminForthFilter | IAdminForthFilter[], limit?: number, offset?: number, sort?: IAdminForthSort | IAdminForthSort[]) => Promise<any[]>;
|
|
1446
1446
|
|
|
1447
1447
|
count: (filter: IAdminForthFilter | IAdminForthFilter[] | undefined) => Promise<number>;
|
|
1448
1448
|
|