adminforth 1.2.50 → 1.2.52
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/modules/configValidator.js +1 -1
- package/dist/modules/restApi.js +39 -35
- package/dist/modules/styles.js +7 -7
- package/dist/spa/spa/src/components/ResourceListTable.vue +1 -0
- package/dist/spa/spa/src/components/Toast.vue +9 -3
- package/dist/spa/spa/src/views/LoginView.vue +19 -2
- package/dist/spa/spa/src/views/ShowView.vue +2 -2
- package/modules/configValidator.ts +1 -1
- package/modules/restApi.ts +6 -1
- package/modules/styles.ts +7 -7
- package/package.json +1 -1
- package/spa/src/components/ResourceListTable.vue +1 -0
- package/spa/src/components/Toast.vue +9 -3
- package/spa/src/views/LoginView.vue +19 -2
- package/spa/src/views/ShowView.vue +2 -2
- package/types/AdminForthConfig.ts +11 -0
|
@@ -54,7 +54,7 @@ export default class ConfigValidator {
|
|
|
54
54
|
if (!this.config.rootUser.password) {
|
|
55
55
|
throw new Error('rootUser.password is required');
|
|
56
56
|
}
|
|
57
|
-
console.log('\n
|
|
57
|
+
console.log('\n ☝️☝️☝️ [INSECURE ALERT] config.rootUser is set, please create a new user to login in backoffice and remove config.rootUser from config ASAP when you are in production\n');
|
|
58
58
|
}
|
|
59
59
|
if (!this.config.customization.customComponentsDir) {
|
|
60
60
|
this.config.customization.customComponentsDir = './custom';
|
package/dist/modules/restApi.js
CHANGED
|
@@ -20,13 +20,15 @@ export default class AdminForthRestAPI {
|
|
|
20
20
|
method: 'POST',
|
|
21
21
|
path: '/login',
|
|
22
22
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
|
|
23
|
-
var _b, _c, _d, _e;
|
|
23
|
+
var _b, _c, _d, _e, _f;
|
|
24
24
|
const INVALID_MESSAGE = 'Invalid username or password';
|
|
25
25
|
const { username, password } = body;
|
|
26
26
|
let adminUser;
|
|
27
27
|
let toReturn = { ok: true, allowedLogin: true };
|
|
28
28
|
let token;
|
|
29
|
-
if (
|
|
29
|
+
if (this.adminforth.config.rootUser
|
|
30
|
+
&& username === this.adminforth.config.rootUser.username
|
|
31
|
+
&& password === ((_b = this.adminforth.config.rootUser) === null || _b === void 0 ? void 0 : _b.password)) {
|
|
30
32
|
this.adminforth.auth.setAuthCookie({ response, username, pk: null });
|
|
31
33
|
adminUser = { isRoot: true, dbUser: null, pk: null, username: this.adminforth.config.rootUser.username };
|
|
32
34
|
}
|
|
@@ -46,7 +48,7 @@ export default class AdminForthRestAPI {
|
|
|
46
48
|
});
|
|
47
49
|
console.log('Adding passwordHashField to userResource', userResource);
|
|
48
50
|
}
|
|
49
|
-
const userRecord = (
|
|
51
|
+
const userRecord = (_c = (yield this.adminforth.connectors[userResource.dataSource].getData({
|
|
50
52
|
resource: userResource,
|
|
51
53
|
filters: [
|
|
52
54
|
{ field: this.adminforth.config.auth.usernameField, operator: AdminForthFilterOperators.EQ, value: username },
|
|
@@ -54,7 +56,7 @@ export default class AdminForthRestAPI {
|
|
|
54
56
|
limit: 1,
|
|
55
57
|
offset: 0,
|
|
56
58
|
sort: [],
|
|
57
|
-
})).data) === null ||
|
|
59
|
+
})).data) === null || _c === void 0 ? void 0 : _c[0];
|
|
58
60
|
if (!userRecord) {
|
|
59
61
|
return { error: 'User not found' };
|
|
60
62
|
}
|
|
@@ -70,8 +72,8 @@ export default class AdminForthRestAPI {
|
|
|
70
72
|
if (beforeLoginConfirmation === null || beforeLoginConfirmation === void 0 ? void 0 : beforeLoginConfirmation.length) {
|
|
71
73
|
for (const hook of beforeLoginConfirmation) {
|
|
72
74
|
const resp = yield hook({ adminUser, response });
|
|
73
|
-
if ((
|
|
74
|
-
toReturn = { ok: resp.ok, redirectTo: (
|
|
75
|
+
if ((_d = resp === null || resp === void 0 ? void 0 : resp.body) === null || _d === void 0 ? void 0 : _d.redirectTo) {
|
|
76
|
+
toReturn = { ok: resp.ok, redirectTo: (_e = resp === null || resp === void 0 ? void 0 : resp.body) === null || _e === void 0 ? void 0 : _e.redirectTo, allowedLogin: (_f = resp === null || resp === void 0 ? void 0 : resp.body) === null || _f === void 0 ? void 0 : _f.allowedLogin };
|
|
75
77
|
break;
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -90,7 +92,7 @@ export default class AdminForthRestAPI {
|
|
|
90
92
|
server.endpoint({
|
|
91
93
|
method: 'POST',
|
|
92
94
|
path: '/check_auth',
|
|
93
|
-
handler: (
|
|
95
|
+
handler: (_g) => __awaiter(this, [_g], void 0, function* ({ adminUser }) {
|
|
94
96
|
return { ok: true };
|
|
95
97
|
}),
|
|
96
98
|
});
|
|
@@ -98,7 +100,7 @@ export default class AdminForthRestAPI {
|
|
|
98
100
|
noAuth: true,
|
|
99
101
|
method: 'POST',
|
|
100
102
|
path: '/logout',
|
|
101
|
-
handler: (
|
|
103
|
+
handler: (_h) => __awaiter(this, [_h], void 0, function* ({ response }) {
|
|
102
104
|
this.adminforth.auth.removeAuthCookie(response);
|
|
103
105
|
return { ok: true };
|
|
104
106
|
}),
|
|
@@ -107,8 +109,8 @@ export default class AdminForthRestAPI {
|
|
|
107
109
|
noAuth: true,
|
|
108
110
|
method: 'GET',
|
|
109
111
|
path: '/get_public_config',
|
|
110
|
-
handler: (
|
|
111
|
-
var
|
|
112
|
+
handler: (_j) => __awaiter(this, [_j], void 0, function* ({ body }) {
|
|
113
|
+
var _k;
|
|
112
114
|
// find resource
|
|
113
115
|
if (!this.adminforth.config.auth) {
|
|
114
116
|
throw new Error('No config.auth defined');
|
|
@@ -120,15 +122,17 @@ export default class AdminForthRestAPI {
|
|
|
120
122
|
brandName: this.adminforth.config.customization.brandName,
|
|
121
123
|
usernameFieldName: usernameColumn.label,
|
|
122
124
|
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
|
|
123
|
-
title: (
|
|
125
|
+
title: (_k = this.adminforth.config.customization) === null || _k === void 0 ? void 0 : _k.title,
|
|
126
|
+
demoCredentials: this.adminforth.config.auth.demoCredentials,
|
|
127
|
+
loginPromptHTML: this.adminforth.config.auth.loginPromptHTML,
|
|
124
128
|
};
|
|
125
129
|
}),
|
|
126
130
|
});
|
|
127
131
|
server.endpoint({
|
|
128
132
|
method: 'GET',
|
|
129
133
|
path: '/get_base_config',
|
|
130
|
-
handler: (
|
|
131
|
-
var
|
|
134
|
+
handler: (_l) => __awaiter(this, [_l], void 0, function* ({ input, adminUser, cookies }) {
|
|
135
|
+
var _m, _o;
|
|
132
136
|
let username = '';
|
|
133
137
|
let userFullName = '';
|
|
134
138
|
if (adminUser.isRoot) {
|
|
@@ -189,8 +193,8 @@ export default class AdminForthRestAPI {
|
|
|
189
193
|
deleteConfirmation: this.adminforth.config.deleteConfirmation,
|
|
190
194
|
auth: this.adminforth.config.auth,
|
|
191
195
|
usernameField: this.adminforth.config.auth.usernameField,
|
|
192
|
-
title: (
|
|
193
|
-
emptyFieldPlaceholder: (
|
|
196
|
+
title: (_m = this.adminforth.config.customization) === null || _m === void 0 ? void 0 : _m.title,
|
|
197
|
+
emptyFieldPlaceholder: (_o = this.adminforth.config.customization) === null || _o === void 0 ? void 0 : _o.emptyFieldPlaceholder,
|
|
194
198
|
},
|
|
195
199
|
adminUser,
|
|
196
200
|
version: ADMINFORTH_VERSION,
|
|
@@ -229,7 +233,7 @@ export default class AdminForthRestAPI {
|
|
|
229
233
|
server.endpoint({
|
|
230
234
|
method: 'POST',
|
|
231
235
|
path: '/get_resource',
|
|
232
|
-
handler: (
|
|
236
|
+
handler: (_p) => __awaiter(this, [_p], void 0, function* ({ body, adminUser }) {
|
|
233
237
|
const { resourceId } = body;
|
|
234
238
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
235
239
|
return { error: 'Database discovery not started' };
|
|
@@ -260,8 +264,8 @@ export default class AdminForthRestAPI {
|
|
|
260
264
|
server.endpoint({
|
|
261
265
|
method: 'POST',
|
|
262
266
|
path: '/get_resource_data',
|
|
263
|
-
handler: (
|
|
264
|
-
var
|
|
267
|
+
handler: (_q) => __awaiter(this, [_q], void 0, function* ({ body, adminUser }) {
|
|
268
|
+
var _r, _s, _t, _u;
|
|
265
269
|
const { resourceId, source } = body;
|
|
266
270
|
if (['show', 'list'].includes(source) === false) {
|
|
267
271
|
return { error: 'Invalid source, should be list or show' };
|
|
@@ -281,7 +285,7 @@ export default class AdminForthRestAPI {
|
|
|
281
285
|
if (!allowed) {
|
|
282
286
|
return { error };
|
|
283
287
|
}
|
|
284
|
-
for (const hook of listify((
|
|
288
|
+
for (const hook of listify((_s = (_r = resource.hooks) === null || _r === void 0 ? void 0 : _r[source]) === null || _s === void 0 ? void 0 : _s.beforeDatasourceRequest)) {
|
|
285
289
|
const resp = yield hook({ resource, query: body, adminUser });
|
|
286
290
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
287
291
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -360,7 +364,7 @@ export default class AdminForthRestAPI {
|
|
|
360
364
|
item._label = resource.recordLabel(item);
|
|
361
365
|
});
|
|
362
366
|
// only after adminforth made all post processing, give user ability to edit it
|
|
363
|
-
for (const hook of listify((
|
|
367
|
+
for (const hook of listify((_u = (_t = resource.hooks) === null || _t === void 0 ? void 0 : _t[source]) === null || _u === void 0 ? void 0 : _u.afterDatasourceResponse)) {
|
|
364
368
|
const resp = yield hook({ resource, response: data.data, adminUser });
|
|
365
369
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
366
370
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -375,8 +379,8 @@ export default class AdminForthRestAPI {
|
|
|
375
379
|
server.endpoint({
|
|
376
380
|
method: 'POST',
|
|
377
381
|
path: '/get_resource_foreign_data',
|
|
378
|
-
handler: (
|
|
379
|
-
var
|
|
382
|
+
handler: (_v) => __awaiter(this, [_v], void 0, function* ({ body, adminUser }) {
|
|
383
|
+
var _w, _x, _y, _z;
|
|
380
384
|
const { resourceId, column } = body;
|
|
381
385
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
382
386
|
return { error: 'Database discovery not started' };
|
|
@@ -397,7 +401,7 @@ export default class AdminForthRestAPI {
|
|
|
397
401
|
}
|
|
398
402
|
const targetResourceId = columnConfig.foreignResource.resourceId;
|
|
399
403
|
const targetResource = this.adminforth.config.resources.find((res) => res.resourceId == targetResourceId);
|
|
400
|
-
for (const hook of listify((
|
|
404
|
+
for (const hook of listify((_x = (_w = columnConfig.foreignResource.hooks) === null || _w === void 0 ? void 0 : _w.dropdownList) === null || _x === void 0 ? void 0 : _x.beforeDatasourceRequest)) {
|
|
401
405
|
const resp = yield hook({ query: body, adminUser, resource: targetResource });
|
|
402
406
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
403
407
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -426,7 +430,7 @@ export default class AdminForthRestAPI {
|
|
|
426
430
|
const response = {
|
|
427
431
|
items
|
|
428
432
|
};
|
|
429
|
-
for (const hook of listify((
|
|
433
|
+
for (const hook of listify((_z = (_y = columnConfig.foreignResource.hooks) === null || _y === void 0 ? void 0 : _y.dropdownList) === null || _z === void 0 ? void 0 : _z.afterDatasourceResponse)) {
|
|
430
434
|
const resp = yield hook({ response, adminUser, resource: targetResource });
|
|
431
435
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
432
436
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -441,7 +445,7 @@ export default class AdminForthRestAPI {
|
|
|
441
445
|
server.endpoint({
|
|
442
446
|
method: 'POST',
|
|
443
447
|
path: '/get_min_max_for_columns',
|
|
444
|
-
handler: (
|
|
448
|
+
handler: (_0) => __awaiter(this, [_0], void 0, function* ({ body }) {
|
|
445
449
|
const { resourceId } = body;
|
|
446
450
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
447
451
|
return { error: 'Database discovery not started' };
|
|
@@ -470,7 +474,7 @@ export default class AdminForthRestAPI {
|
|
|
470
474
|
server.endpoint({
|
|
471
475
|
method: 'POST',
|
|
472
476
|
path: '/create_record',
|
|
473
|
-
handler: (
|
|
477
|
+
handler: (_1) => __awaiter(this, [_1], void 0, function* ({ body, adminUser }) {
|
|
474
478
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
475
479
|
if (!resource) {
|
|
476
480
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -494,8 +498,8 @@ export default class AdminForthRestAPI {
|
|
|
494
498
|
server.endpoint({
|
|
495
499
|
method: 'POST',
|
|
496
500
|
path: '/update_record',
|
|
497
|
-
handler: (
|
|
498
|
-
var
|
|
501
|
+
handler: (_2) => __awaiter(this, [_2], void 0, function* ({ body, adminUser }) {
|
|
502
|
+
var _3, _4, _5, _6;
|
|
499
503
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
500
504
|
if (!resource) {
|
|
501
505
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -514,7 +518,7 @@ export default class AdminForthRestAPI {
|
|
|
514
518
|
return { error };
|
|
515
519
|
}
|
|
516
520
|
// execute hook if needed
|
|
517
|
-
for (const hook of listify((
|
|
521
|
+
for (const hook of listify((_4 = (_3 = resource.hooks) === null || _3 === void 0 ? void 0 : _3.edit) === null || _4 === void 0 ? void 0 : _4.beforeSave)) {
|
|
518
522
|
const resp = yield hook({ resource, record, adminUser });
|
|
519
523
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
520
524
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -541,7 +545,7 @@ export default class AdminForthRestAPI {
|
|
|
541
545
|
yield connector.updateRecord({ resource, recordId, newValues });
|
|
542
546
|
}
|
|
543
547
|
// execute hook if needed
|
|
544
|
-
for (const hook of listify((
|
|
548
|
+
for (const hook of listify((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.edit) === null || _6 === void 0 ? void 0 : _6.afterSave)) {
|
|
545
549
|
const resp = yield hook({ resource, record, adminUser, oldRecord });
|
|
546
550
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
547
551
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -558,8 +562,8 @@ export default class AdminForthRestAPI {
|
|
|
558
562
|
server.endpoint({
|
|
559
563
|
method: 'POST',
|
|
560
564
|
path: '/delete_record',
|
|
561
|
-
handler: (
|
|
562
|
-
var
|
|
565
|
+
handler: (_7) => __awaiter(this, [_7], void 0, function* ({ body, adminUser }) {
|
|
566
|
+
var _8, _9, _10, _11;
|
|
563
567
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
564
568
|
const record = yield this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
|
|
565
569
|
if (!resource) {
|
|
@@ -577,7 +581,7 @@ export default class AdminForthRestAPI {
|
|
|
577
581
|
return { error };
|
|
578
582
|
}
|
|
579
583
|
// execute hook if needed
|
|
580
|
-
for (const hook of listify((
|
|
584
|
+
for (const hook of listify((_9 = (_8 = resource.hooks) === null || _8 === void 0 ? void 0 : _8.delete) === null || _9 === void 0 ? void 0 : _9.beforeSave)) {
|
|
581
585
|
const resp = yield hook({ resource, record, adminUser });
|
|
582
586
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
583
587
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -589,7 +593,7 @@ export default class AdminForthRestAPI {
|
|
|
589
593
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
590
594
|
yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
|
|
591
595
|
// execute hook if needed
|
|
592
|
-
for (const hook of listify((
|
|
596
|
+
for (const hook of listify((_11 = (_10 = resource.hooks) === null || _10 === void 0 ? void 0 : _10.delete) === null || _11 === void 0 ? void 0 : _11.afterSave)) {
|
|
593
597
|
const resp = yield hook({ resource, record, adminUser });
|
|
594
598
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
595
599
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -606,7 +610,7 @@ export default class AdminForthRestAPI {
|
|
|
606
610
|
server.endpoint({
|
|
607
611
|
method: 'POST',
|
|
608
612
|
path: '/start_bulk_action',
|
|
609
|
-
handler: (
|
|
613
|
+
handler: (_12) => __awaiter(this, [_12], void 0, function* ({ body, adminUser }) {
|
|
610
614
|
const { resourceId, actionId, recordIds } = body;
|
|
611
615
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
|
|
612
616
|
if (!resource) {
|
package/dist/modules/styles.js
CHANGED
|
@@ -7,11 +7,11 @@ export const styles = () => ({
|
|
|
7
7
|
lightNavbarTextHover: "alias:lightNavbarText darken", // navbar text hover
|
|
8
8
|
lightNavbarTextActive: "alias:lightNavbarText darken", // navbar text active
|
|
9
9
|
lightNavbarIcons: "alias:lightNavbarText opacity:0.7", // navbar icons
|
|
10
|
-
lightSidebar: "#
|
|
11
|
-
lightSidebarBorder: "alias:lightSidebarText opacity:0.
|
|
12
|
-
lightSidebarItemHover: "alias:lightSidebarText opacity:0.
|
|
13
|
-
lightSidebarItemActive: "alias:lightSidebarText opacity:0.
|
|
14
|
-
lightSidebarText: "#
|
|
10
|
+
lightSidebar: "#f9fafb", // sidebar background
|
|
11
|
+
lightSidebarBorder: "alias:lightSidebarText opacity:0.05", // sidebar right border
|
|
12
|
+
lightSidebarItemHover: "alias:lightSidebarText opacity:0.05", // sidebar list item hover
|
|
13
|
+
lightSidebarItemActive: "alias:lightSidebarText opacity:0.05", // sidebar list item active
|
|
14
|
+
lightSidebarText: "#213045", // sidebar list item text
|
|
15
15
|
lightSidebarTextHover: "alias:lightSidebarText darken", // sidebar list item text hover
|
|
16
16
|
lightSidebarTextActive: "alias:lightSidebarText darken", // sidebar list item text active
|
|
17
17
|
lightSidebarDevider: "alias:lightSidebarText opacity:0.3", // sidebar devider
|
|
@@ -21,7 +21,7 @@ export const styles = () => ({
|
|
|
21
21
|
lightList: "#FFFFFF", // list view background
|
|
22
22
|
lightListTable: "#FFFFFF", // list view table background
|
|
23
23
|
lightListTableHeading: "alias:lightListTableHeadingText opacity:0.04", // list view table heading
|
|
24
|
-
lightListTableHeadingText: "#
|
|
24
|
+
lightListTableHeadingText: "#43445B", // list view table heading text
|
|
25
25
|
lightListTableText: "#333333", // list view table text
|
|
26
26
|
lightListTableRowHover: "rgb(249 250 251)", // list view row hover
|
|
27
27
|
lightListBreadcrumbsText: "#666666", // list view breadcrumbs text
|
|
@@ -87,6 +87,6 @@ export const styles = () => ({
|
|
|
87
87
|
"headerText-size": "1rem"
|
|
88
88
|
},
|
|
89
89
|
borderRadius: {
|
|
90
|
-
"default": "
|
|
90
|
+
"default": ".5rem"
|
|
91
91
|
}
|
|
92
92
|
});
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500
|
|
4
|
+
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500 rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert"
|
|
5
|
+
:class="
|
|
6
|
+
{
|
|
7
|
+
'danger': 'bg-red-100',
|
|
8
|
+
}[toast.variant]
|
|
9
|
+
"
|
|
10
|
+
>
|
|
5
11
|
<div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
|
6
12
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
|
7
13
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
|
|
@@ -27,8 +33,8 @@
|
|
|
27
33
|
<span class="sr-only">Check icon</span>
|
|
28
34
|
</div>
|
|
29
35
|
|
|
30
|
-
<div class="ms-3 text-sm font-normal max-w-xs" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
31
|
-
<div class="ms-3 text-sm font-normal max-w-xs" v-else>{{toast.message}}</div>
|
|
36
|
+
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
37
|
+
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-else>{{toast.message}}</div>
|
|
32
38
|
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" >
|
|
33
39
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
34
40
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
@@ -61,6 +61,17 @@
|
|
|
61
61
|
</div>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
|
+
|
|
65
|
+
<div v-if="coreStore.config?.loginPromptHTML"
|
|
66
|
+
class="flex items-center p-4 mb-4 text-sm text-gray-800 rounded-lg bg-gray-50 dark:bg-gray-800 dark:text-gray-400" role="alert"
|
|
67
|
+
>
|
|
68
|
+
<svg class="flex-shrink-0 inline w-4 h-4 me-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
|
69
|
+
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/>
|
|
70
|
+
</svg>
|
|
71
|
+
<span class="sr-only">Info</span>
|
|
72
|
+
<div v-html="coreStore.config?.loginPromptHTML"></div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
64
75
|
<button
|
|
65
76
|
@click="login"
|
|
66
77
|
type="submit" class="flex items-center justify-center gap-1 w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
|
|
@@ -106,8 +117,14 @@ const showPw = ref(false);
|
|
|
106
117
|
|
|
107
118
|
const error = ref(null);
|
|
108
119
|
|
|
109
|
-
onMounted(() => {
|
|
110
|
-
coreStore.getPublicConfig();
|
|
120
|
+
onMounted(async () => {
|
|
121
|
+
await coreStore.getPublicConfig();
|
|
122
|
+
if (coreStore.config?.demoCredentials) {
|
|
123
|
+
console.log('Setting demo credentials');
|
|
124
|
+
const [username, password] = coreStore.config.demoCredentials.split(':');
|
|
125
|
+
usernameInput.value.value = username;
|
|
126
|
+
passwordInput.value.value = password;
|
|
127
|
+
}
|
|
111
128
|
usernameInput.value.focus();
|
|
112
129
|
});
|
|
113
130
|
|
|
@@ -124,7 +124,7 @@ import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbi
|
|
|
124
124
|
import { onMounted, ref } from 'vue';
|
|
125
125
|
import { useRoute,useRouter } from 'vue-router';
|
|
126
126
|
import {callAdminForthApi} from '@/utils';
|
|
127
|
-
import {showSuccesTost} from '@/composables/useFrontendApi';
|
|
127
|
+
import { showSuccesTost, showErrorTost } from '@/composables/useFrontendApi';
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
const item = ref(null);
|
|
@@ -170,7 +170,7 @@ async function deleteRecord(row) {
|
|
|
170
170
|
router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
|
|
171
171
|
showSuccesTost('Record deleted successfully')
|
|
172
172
|
} else {
|
|
173
|
-
|
|
173
|
+
showErrorTost(res.error)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
} catch (e) {
|
|
@@ -59,7 +59,7 @@ export default class ConfigValidator implements IConfigValidator {
|
|
|
59
59
|
throw new Error('rootUser.password is required');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
console.log('\n
|
|
62
|
+
console.log('\n ☝️☝️☝️ [INSECURE ALERT] config.rootUser is set, please create a new user to login in backoffice and remove config.rootUser from config ASAP when you are in production\n');
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
if (!this.config.customization.customComponentsDir) {
|
package/modules/restApi.ts
CHANGED
|
@@ -42,7 +42,10 @@ export default class AdminForthRestAPI {
|
|
|
42
42
|
let toReturn: { ok: boolean, redirectTo?: string, allowedLogin:boolean } = { ok: true, allowedLogin:true};
|
|
43
43
|
|
|
44
44
|
let token;
|
|
45
|
-
if (
|
|
45
|
+
if (this.adminforth.config.rootUser
|
|
46
|
+
&& username === this.adminforth.config.rootUser.username
|
|
47
|
+
&& password === this.adminforth.config.rootUser?.password
|
|
48
|
+
) {
|
|
46
49
|
this.adminforth.auth.setAuthCookie({ response, username, pk: null });
|
|
47
50
|
adminUser = { isRoot: true, dbUser: null, pk: null, username: this.adminforth.config.rootUser.username};
|
|
48
51
|
} else {
|
|
@@ -147,6 +150,8 @@ export default class AdminForthRestAPI {
|
|
|
147
150
|
usernameFieldName: usernameColumn.label,
|
|
148
151
|
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
|
|
149
152
|
title: this.adminforth.config.customization?.title,
|
|
153
|
+
demoCredentials: this.adminforth.config.auth.demoCredentials,
|
|
154
|
+
loginPromptHTML: this.adminforth.config.auth.loginPromptHTML,
|
|
150
155
|
};
|
|
151
156
|
},
|
|
152
157
|
});
|
package/modules/styles.ts
CHANGED
|
@@ -11,11 +11,11 @@ export const styles = () => ({
|
|
|
11
11
|
lightNavbarTextActive: "alias:lightNavbarText darken", // navbar text active
|
|
12
12
|
lightNavbarIcons: "alias:lightNavbarText opacity:0.7", // navbar icons
|
|
13
13
|
|
|
14
|
-
lightSidebar: "#
|
|
15
|
-
lightSidebarBorder: "alias:lightSidebarText opacity:0.
|
|
16
|
-
lightSidebarItemHover: "alias:lightSidebarText opacity:0.
|
|
17
|
-
lightSidebarItemActive: "alias:lightSidebarText opacity:0.
|
|
18
|
-
lightSidebarText: "#
|
|
14
|
+
lightSidebar: "#f9fafb", // sidebar background
|
|
15
|
+
lightSidebarBorder: "alias:lightSidebarText opacity:0.05", // sidebar right border
|
|
16
|
+
lightSidebarItemHover: "alias:lightSidebarText opacity:0.05", // sidebar list item hover
|
|
17
|
+
lightSidebarItemActive: "alias:lightSidebarText opacity:0.05", // sidebar list item active
|
|
18
|
+
lightSidebarText: "#213045", // sidebar list item text
|
|
19
19
|
lightSidebarTextHover: "alias:lightSidebarText darken", // sidebar list item text hover
|
|
20
20
|
lightSidebarTextActive: "alias:lightSidebarText darken", // sidebar list item text active
|
|
21
21
|
lightSidebarDevider: "alias:lightSidebarText opacity:0.3", // sidebar devider
|
|
@@ -26,7 +26,7 @@ export const styles = () => ({
|
|
|
26
26
|
lightList: "#FFFFFF", // list view background
|
|
27
27
|
lightListTable: "#FFFFFF", // list view table background
|
|
28
28
|
lightListTableHeading: "alias:lightListTableHeadingText opacity:0.04", // list view table heading
|
|
29
|
-
lightListTableHeadingText: "#
|
|
29
|
+
lightListTableHeadingText: "#43445B", // list view table heading text
|
|
30
30
|
lightListTableText: "#333333", // list view table text
|
|
31
31
|
lightListTableRowHover: "rgb(249 250 251)", // list view row hover
|
|
32
32
|
lightListBreadcrumbsText: "#666666", // list view breadcrumbs text
|
|
@@ -103,7 +103,7 @@ export const styles = () => ({
|
|
|
103
103
|
"headerText-size": "1rem"
|
|
104
104
|
},
|
|
105
105
|
borderRadius: {
|
|
106
|
-
"default": "
|
|
106
|
+
"default": ".5rem"
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500
|
|
4
|
+
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500 rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert"
|
|
5
|
+
:class="
|
|
6
|
+
{
|
|
7
|
+
'danger': 'bg-red-100',
|
|
8
|
+
}[toast.variant]
|
|
9
|
+
"
|
|
10
|
+
>
|
|
5
11
|
<div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
|
6
12
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
|
7
13
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
|
|
@@ -27,8 +33,8 @@
|
|
|
27
33
|
<span class="sr-only">Check icon</span>
|
|
28
34
|
</div>
|
|
29
35
|
|
|
30
|
-
<div class="ms-3 text-sm font-normal max-w-xs" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
31
|
-
<div class="ms-3 text-sm font-normal max-w-xs" v-else>{{toast.message}}</div>
|
|
36
|
+
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
37
|
+
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-else>{{toast.message}}</div>
|
|
32
38
|
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" >
|
|
33
39
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
34
40
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
@@ -61,6 +61,17 @@
|
|
|
61
61
|
</div>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
|
+
|
|
65
|
+
<div v-if="coreStore.config?.loginPromptHTML"
|
|
66
|
+
class="flex items-center p-4 mb-4 text-sm text-gray-800 rounded-lg bg-gray-50 dark:bg-gray-800 dark:text-gray-400" role="alert"
|
|
67
|
+
>
|
|
68
|
+
<svg class="flex-shrink-0 inline w-4 h-4 me-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
|
69
|
+
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/>
|
|
70
|
+
</svg>
|
|
71
|
+
<span class="sr-only">Info</span>
|
|
72
|
+
<div v-html="coreStore.config?.loginPromptHTML"></div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
64
75
|
<button
|
|
65
76
|
@click="login"
|
|
66
77
|
type="submit" class="flex items-center justify-center gap-1 w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
|
|
@@ -106,8 +117,14 @@ const showPw = ref(false);
|
|
|
106
117
|
|
|
107
118
|
const error = ref(null);
|
|
108
119
|
|
|
109
|
-
onMounted(() => {
|
|
110
|
-
coreStore.getPublicConfig();
|
|
120
|
+
onMounted(async () => {
|
|
121
|
+
await coreStore.getPublicConfig();
|
|
122
|
+
if (coreStore.config?.demoCredentials) {
|
|
123
|
+
console.log('Setting demo credentials');
|
|
124
|
+
const [username, password] = coreStore.config.demoCredentials.split(':');
|
|
125
|
+
usernameInput.value.value = username;
|
|
126
|
+
passwordInput.value.value = password;
|
|
127
|
+
}
|
|
111
128
|
usernameInput.value.focus();
|
|
112
129
|
});
|
|
113
130
|
|
|
@@ -124,7 +124,7 @@ import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbi
|
|
|
124
124
|
import { onMounted, ref } from 'vue';
|
|
125
125
|
import { useRoute,useRouter } from 'vue-router';
|
|
126
126
|
import {callAdminForthApi} from '@/utils';
|
|
127
|
-
import {showSuccesTost} from '@/composables/useFrontendApi';
|
|
127
|
+
import { showSuccesTost, showErrorTost } from '@/composables/useFrontendApi';
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
const item = ref(null);
|
|
@@ -170,7 +170,7 @@ async function deleteRecord(row) {
|
|
|
170
170
|
router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
|
|
171
171
|
showSuccesTost('Record deleted successfully')
|
|
172
172
|
} else {
|
|
173
|
-
|
|
173
|
+
showErrorTost(res.error)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
} catch (e) {
|
|
@@ -1058,6 +1058,17 @@ export type AdminForthConfig = {
|
|
|
1058
1058
|
* This field will be used to display user name in the top right corner of the admin panel.
|
|
1059
1059
|
*/
|
|
1060
1060
|
userFullNameField?: string,
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Pair of login and pass substitution for demo mode. Split by ':'
|
|
1064
|
+
* ! This option is for demo purposes only, never use it for your projects
|
|
1065
|
+
*/
|
|
1066
|
+
demoCredentials?: string,
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Any prompt to show users on login. Supports HTML.
|
|
1070
|
+
*/
|
|
1071
|
+
loginPromptHTML?: string,
|
|
1061
1072
|
},
|
|
1062
1073
|
/**
|
|
1063
1074
|
* Array of resources which will be displayed in the admin panel.
|