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.
@@ -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 ⚠️⚠️⚠️ [INSECURE ALERT] config.rootUser is set, please create a new user and remove config.rootUser from config ASAP when you are in production\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';
@@ -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 (username === this.adminforth.config.rootUser.username && password === this.adminforth.config.rootUser.password) {
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 = (_b = (yield this.adminforth.connectors[userResource.dataSource].getData({
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 || _b === void 0 ? void 0 : _b[0];
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 ((_c = resp === null || resp === void 0 ? void 0 : resp.body) === null || _c === void 0 ? void 0 : _c.redirectTo) {
74
- toReturn = { ok: resp.ok, redirectTo: (_d = resp === null || resp === void 0 ? void 0 : resp.body) === null || _d === void 0 ? void 0 : _d.redirectTo, allowedLogin: (_e = resp === null || resp === void 0 ? void 0 : resp.body) === null || _e === void 0 ? void 0 : _e.allowedLogin };
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: (_f) => __awaiter(this, [_f], void 0, function* ({ adminUser }) {
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: (_g) => __awaiter(this, [_g], void 0, function* ({ response }) {
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: (_h) => __awaiter(this, [_h], void 0, function* ({ body }) {
111
- var _j;
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: (_j = this.adminforth.config.customization) === null || _j === void 0 ? void 0 : _j.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: (_k) => __awaiter(this, [_k], void 0, function* ({ input, adminUser, cookies }) {
131
- var _l, _m;
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: (_l = this.adminforth.config.customization) === null || _l === void 0 ? void 0 : _l.title,
193
- emptyFieldPlaceholder: (_m = this.adminforth.config.customization) === null || _m === void 0 ? void 0 : _m.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: (_o) => __awaiter(this, [_o], void 0, function* ({ body, adminUser }) {
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: (_p) => __awaiter(this, [_p], void 0, function* ({ body, adminUser }) {
264
- var _q, _r, _s, _t;
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((_r = (_q = resource.hooks) === null || _q === void 0 ? void 0 : _q[source]) === null || _r === void 0 ? void 0 : _r.beforeDatasourceRequest)) {
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((_t = (_s = resource.hooks) === null || _s === void 0 ? void 0 : _s[source]) === null || _t === void 0 ? void 0 : _t.afterDatasourceResponse)) {
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: (_u) => __awaiter(this, [_u], void 0, function* ({ body, adminUser }) {
379
- var _v, _w, _x, _y;
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((_w = (_v = columnConfig.foreignResource.hooks) === null || _v === void 0 ? void 0 : _v.dropdownList) === null || _w === void 0 ? void 0 : _w.beforeDatasourceRequest)) {
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((_y = (_x = columnConfig.foreignResource.hooks) === null || _x === void 0 ? void 0 : _x.dropdownList) === null || _y === void 0 ? void 0 : _y.afterDatasourceResponse)) {
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: (_z) => __awaiter(this, [_z], void 0, function* ({ body }) {
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: (_0) => __awaiter(this, [_0], void 0, function* ({ body, adminUser }) {
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: (_1) => __awaiter(this, [_1], void 0, function* ({ body, adminUser }) {
498
- var _2, _3, _4, _5;
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((_3 = (_2 = resource.hooks) === null || _2 === void 0 ? void 0 : _2.edit) === null || _3 === void 0 ? void 0 : _3.beforeSave)) {
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((_5 = (_4 = resource.hooks) === null || _4 === void 0 ? void 0 : _4.edit) === null || _5 === void 0 ? void 0 : _5.afterSave)) {
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: (_6) => __awaiter(this, [_6], void 0, function* ({ body, adminUser }) {
562
- var _7, _8, _9, _10;
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((_8 = (_7 = resource.hooks) === null || _7 === void 0 ? void 0 : _7.delete) === null || _8 === void 0 ? void 0 : _8.beforeSave)) {
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((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.delete) === null || _10 === void 0 ? void 0 : _10.afterSave)) {
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: (_11) => __awaiter(this, [_11], void 0, function* ({ body, adminUser }) {
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) {
@@ -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: "#ffffff", // sidebar background
11
- lightSidebarBorder: "alias:lightSidebarText opacity:0.3", // sidebar right border
12
- lightSidebarItemHover: "alias:lightSidebarText opacity:0.1", // sidebar list item hover
13
- lightSidebarItemActive: "alias:lightSidebarText opacity:0.4", // sidebar list item active
14
- lightSidebarText: "#1f2937", // sidebar list item text
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: "#333333", // list view table heading text
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": "2px"
90
+ "default": ".5rem"
91
91
  }
92
92
  });
@@ -375,6 +375,7 @@ async function deleteRecord(row) {
375
375
  primaryKey: row._primaryKeyValue,
376
376
  }
377
377
  });
378
+ console.log('safsa', res)
378
379
  if (!res.error){
379
380
  emits('update:records', true)
380
381
  showSuccesTost('Record deleted successfully')
@@ -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 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert">
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
- console.error(res.error)
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 ⚠️⚠️⚠️ [INSECURE ALERT] config.rootUser is set, please create a new user and remove config.rootUser from config ASAP when you are in production\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) {
@@ -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 (username === this.adminforth.config.rootUser.username && password === this.adminforth.config.rootUser.password) {
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: "#ffffff", // sidebar background
15
- lightSidebarBorder: "alias:lightSidebarText opacity:0.3", // sidebar right border
16
- lightSidebarItemHover: "alias:lightSidebarText opacity:0.1", // sidebar list item hover
17
- lightSidebarItemActive: "alias:lightSidebarText opacity:0.4", // sidebar list item active
18
- lightSidebarText: "#1f2937", // sidebar list item text
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: "#333333", // list view table heading text
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": "2px"
106
+ "default": ".5rem"
107
107
  }
108
108
  });
109
109
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.2.50",
3
+ "version": "1.2.52",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -375,6 +375,7 @@ async function deleteRecord(row) {
375
375
  primaryKey: row._primaryKeyValue,
376
376
  }
377
377
  });
378
+ console.log('safsa', res)
378
379
  if (!res.error){
379
380
  emits('update:records', true)
380
381
  showSuccesTost('Record deleted successfully')
@@ -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 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert">
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
- console.error(res.error)
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.