adminforth 1.0.30 → 1.0.32

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.
@@ -147,7 +147,7 @@ class PostgresConnector {
147
147
 
148
148
  async getRecordByPrimaryKey(resource, key) {
149
149
  const tableName = resource.table;
150
- const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
150
+ const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
151
151
  const stmt = await this.db.query(`SELECT ${columns} FROM ${tableName} WHERE ${this.getPrimaryKey(resource)} = $1`, [key]);
152
152
  const row = stmt.rows[0];
153
153
  if (!row) {
@@ -177,7 +177,7 @@ class PostgresConnector {
177
177
  }
178
178
 
179
179
  async getData({ resource, limit, offset, sort, filters }) {
180
- const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
180
+ const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => `"${col.name}"`).join(', ');
181
181
  const tableName = resource.table;
182
182
 
183
183
  for (const filter of filters) {
@@ -199,7 +199,7 @@ class PostgresConnector {
199
199
  } else {
200
200
  totalCounter += 1;
201
201
  }
202
- return `${field} ${operator} ${placeholder}`
202
+ return `"${field}" ${operator} ${placeholder}`
203
203
  }).join(' AND ')}` : '';
204
204
 
205
205
  const filterValues = [];
@@ -267,17 +267,20 @@ class PostgresConnector {
267
267
  return record[colName];
268
268
  }
269
269
  });
270
+ for (let i = 0; i < columns.length; i++) {
271
+ columns[i] = `"${columns[i]}"`;
272
+ }
270
273
  await this.db.query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`, values);
271
274
  }
272
275
 
273
276
  async updateRecord({ resource, recordId, record, newValues }) {
274
277
  const values = [...Object.values(newValues), recordId];
275
- const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `${col} = $${i + 1}`).join(', ');
276
- await this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = $${values.length}`, values);
278
+ const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `"${col}" = $${i + 1}`).join(', ');
279
+ await this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`, values);
277
280
  }
278
281
 
279
282
  async deleteRecord({ resource, recordId }) {
280
- await this.db.query(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = $1`, [recordId]);
283
+ await this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
281
284
  }
282
285
 
283
286
  async close() {
@@ -148,7 +148,7 @@ class PostgresConnector {
148
148
  getRecordByPrimaryKey(resource, key) {
149
149
  return __awaiter(this, void 0, void 0, function* () {
150
150
  const tableName = resource.table;
151
- const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
151
+ const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
152
152
  const stmt = yield this.db.query(`SELECT ${columns} FROM ${tableName} WHERE ${this.getPrimaryKey(resource)} = $1`, [key]);
153
153
  const row = stmt.rows[0];
154
154
  if (!row) {
@@ -180,7 +180,7 @@ class PostgresConnector {
180
180
  }
181
181
  getData(_a) {
182
182
  return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
183
- const columns = resource.dataSourceColumns.filter(c => !c.virtual).map((col) => col.name).join(', ');
183
+ const columns = resource.dataSourceColumns.filter(c => !c.virtual).map((col) => `"${col.name}"`).join(', ');
184
184
  const tableName = resource.table;
185
185
  for (const filter of filters) {
186
186
  if (!this.OperatorsMap[filter.operator]) {
@@ -202,7 +202,7 @@ class PostgresConnector {
202
202
  else {
203
203
  totalCounter += 1;
204
204
  }
205
- return `${field} ${operator} ${placeholder}`;
205
+ return `"${field}" ${operator} ${placeholder}`;
206
206
  }).join(' AND ')}` : '';
207
207
  const filterValues = [];
208
208
  filters.length ? filters.forEach((f) => {
@@ -272,19 +272,22 @@ class PostgresConnector {
272
272
  return record[colName];
273
273
  }
274
274
  });
275
+ for (let i = 0; i < columns.length; i++) {
276
+ columns[i] = `"${columns[i]}"`;
277
+ }
275
278
  yield this.db.query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`, values);
276
279
  });
277
280
  }
278
281
  updateRecord(_a) {
279
282
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId, record, newValues }) {
280
283
  const values = [...Object.values(newValues), recordId];
281
- const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `${col} = $${i + 1}`).join(', ');
282
- yield this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = $${values.length}`, values);
284
+ const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `"${col}" = $${i + 1}`).join(', ');
285
+ yield this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`, values);
283
286
  });
284
287
  }
285
288
  deleteRecord(_a) {
286
289
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
287
- yield this.db.query(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = $1`, [recordId]);
290
+ yield this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
288
291
  });
289
292
  }
290
293
  close() {
package/dist/index.js CHANGED
@@ -22,6 +22,14 @@ import { guessLabelFromName } from './modules/utils.js';
22
22
  import ExpressServer from './servers/express.js';
23
23
  import { v1 as uuid } from 'uuid';
24
24
  import fs from 'fs';
25
+ let package_json;
26
+ if (fs.existsSync('../package.json')) {
27
+ // in prod we are in dist folder
28
+ package_json = JSON.parse(fs.readFileSync('../package.json', 'utf8'));
29
+ }
30
+ else {
31
+ package_json = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
32
+ }
25
33
  import { AdminForthFilterOperators, AdminForthTypes } from './types.js';
26
34
  const AVAILABLE_SHOW_IN = ['list', 'edit', 'create', 'filter', 'show'];
27
35
  const DEFAULT_ALLOWED_ACTIONS = { create: true, edit: true, show: true, delete: true };
@@ -409,6 +417,7 @@ class AdminForth {
409
417
  usernameField: this.config.auth.usernameField,
410
418
  },
411
419
  adminUser,
420
+ version: package_json.version,
412
421
  };
413
422
  }),
414
423
  });
@@ -455,10 +464,73 @@ class AdminForth {
455
464
  return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
456
465
  }),
457
466
  });
467
+ server.endpoint({
468
+ method: 'POST',
469
+ path: '/get_resource_foreign_data',
470
+ handler: (_h) => __awaiter(this, [_h], void 0, function* ({ body, adminUser }) {
471
+ var _j, _k, _l, _m;
472
+ const { resourceId, column } = body;
473
+ if (!this.statuses.dbDiscover) {
474
+ return { error: 'Database discovery not started' };
475
+ }
476
+ if (this.statuses.dbDiscover !== 'done') {
477
+ return { error: 'Database discovery is still in progress, please try later' };
478
+ }
479
+ const resource = this.config.resources.find((res) => res.resourceId == resourceId);
480
+ if (!resource) {
481
+ return { error: `Resource ${resourceId} not found` };
482
+ }
483
+ const columnConfig = resource.columns.find((col) => col.name == column);
484
+ if (!columnConfig.foreignResource) {
485
+ return { error: `Column ${column} in resource ${resourceId} is not a foreign key` };
486
+ }
487
+ const targetResourceId = columnConfig.foreignResource.resourceId;
488
+ const targetResource = this.config.resources.find((res) => res.resourceId == targetResourceId);
489
+ if ((_j = columnConfig.foreignResource.hooks) === null || _j === void 0 ? void 0 : _j.beforeDatasourceRequest) {
490
+ const resp = yield ((_k = column.foreignResource.hooks) === null || _k === void 0 ? void 0 : _k.beforeDatasourceRequest({ query: body, adminUser }));
491
+ if (!resp || (!resp.ok && !resp.error)) {
492
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
493
+ }
494
+ if (resp.error) {
495
+ return { error: resp.error };
496
+ }
497
+ }
498
+ const { limit, offset, filters, sort } = body;
499
+ const dbDataItems = yield this.connectors[targetResource.dataSource].getData({
500
+ resource: targetResource,
501
+ limit,
502
+ offset,
503
+ filters: filters || [],
504
+ sort: sort || [],
505
+ });
506
+ const items = dbDataItems.data.map((item) => {
507
+ const pk = item[targetResource.columns.find((col) => col.primaryKey).name];
508
+ const labler = targetResource.itemLabel || ((record) => `${targetResource.label} ${pk}`);
509
+ return {
510
+ value: pk,
511
+ label: labler(item),
512
+ _item: item, // user might need it in hook to form new label
513
+ };
514
+ });
515
+ const response = {
516
+ items
517
+ };
518
+ if ((_l = columnConfig.foreignResource.hooks) === null || _l === void 0 ? void 0 : _l.afterDatasourceRequest) {
519
+ const resp = yield ((_m = column.foreignResource.hooks) === null || _m === void 0 ? void 0 : _m.afterDatasourceRequest({ response, adminUser }));
520
+ if (!resp || (!resp.ok && !resp.error)) {
521
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
522
+ }
523
+ if (resp.error) {
524
+ return { error: resp.error };
525
+ }
526
+ }
527
+ return response;
528
+ }),
529
+ });
458
530
  server.endpoint({
459
531
  method: 'POST',
460
532
  path: '/get_min_max_for_columns',
461
- handler: (_h) => __awaiter(this, [_h], void 0, function* ({ body }) {
533
+ handler: (_o) => __awaiter(this, [_o], void 0, function* ({ body }) {
462
534
  const { resourceId } = body;
463
535
  if (!this.statuses.dbDiscover) {
464
536
  return { error: 'Database discovery not started' };
@@ -487,8 +559,8 @@ class AdminForth {
487
559
  server.endpoint({
488
560
  method: 'POST',
489
561
  path: '/get_record',
490
- handler: (_j) => __awaiter(this, [_j], void 0, function* ({ body, adminUser }) {
491
- var _k, _l;
562
+ handler: (_p) => __awaiter(this, [_p], void 0, function* ({ body, adminUser }) {
563
+ var _q, _r;
492
564
  const { resourceId, primaryKey } = body;
493
565
  const resource = this.config.resources.find((res) => res.resourceId == resourceId);
494
566
  const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
@@ -498,8 +570,8 @@ class AdminForth {
498
570
  return { error: `Record with ${primaryKeyColumn.name} ${primaryKey} not found` };
499
571
  }
500
572
  // execute hook if needed
501
- if ((_k = resource.hooks) === null || _k === void 0 ? void 0 : _k.show) {
502
- const resp = yield ((_l = resource.hooks) === null || _l === void 0 ? void 0 : _l.show({ resource, record, adminUser }));
573
+ if ((_q = resource.hooks) === null || _q === void 0 ? void 0 : _q.show) {
574
+ const resp = yield ((_r = resource.hooks) === null || _r === void 0 ? void 0 : _r.show({ resource, record, adminUser }));
503
575
  if (!resp || (!resp.ok && !resp.error)) {
504
576
  throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
505
577
  }
@@ -516,8 +588,8 @@ class AdminForth {
516
588
  noAuth: true, // TODO
517
589
  method: 'POST',
518
590
  path: '/create_record',
519
- handler: (_m) => __awaiter(this, [_m], void 0, function* ({ body, adminUser }) {
520
- var _o, _p, _q, _r, _s, _t, _u, _v, _w;
591
+ handler: (_s) => __awaiter(this, [_s], void 0, function* ({ body, adminUser }) {
592
+ var _t, _u, _v, _w, _x, _y, _z, _0, _1;
521
593
  console.log('create_record', body, this.config.resources);
522
594
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
523
595
  if (!resource) {
@@ -525,8 +597,8 @@ class AdminForth {
525
597
  }
526
598
  const record = body['record'];
527
599
  // execute hook if needed
528
- if ((_p = (_o = resource.hooks) === null || _o === void 0 ? void 0 : _o.create) === null || _p === void 0 ? void 0 : _p.beforeSave) {
529
- const resp = yield ((_r = (_q = resource.hooks) === null || _q === void 0 ? void 0 : _q.create) === null || _r === void 0 ? void 0 : _r.beforeSave({ resource, record, adminUser }));
600
+ if ((_u = (_t = resource.hooks) === null || _t === void 0 ? void 0 : _t.create) === null || _u === void 0 ? void 0 : _u.beforeSave) {
601
+ const resp = yield ((_w = (_v = resource.hooks) === null || _v === void 0 ? void 0 : _v.create) === null || _w === void 0 ? void 0 : _w.beforeSave({ resource, record, adminUser }));
530
602
  if (!resp || (!resp.ok && !resp.error)) {
531
603
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
532
604
  }
@@ -542,7 +614,7 @@ class AdminForth {
542
614
  });
543
615
  }
544
616
  }
545
- if (((_s = column.required) === null || _s === void 0 ? void 0 : _s.create) && body['record'][column.name] === undefined) {
617
+ if (((_x = column.required) === null || _x === void 0 ? void 0 : _x.create) && body['record'][column.name] === undefined) {
546
618
  return { error: `Column '${column.name}' is required` };
547
619
  }
548
620
  if (column.isUnique) {
@@ -567,8 +639,8 @@ class AdminForth {
567
639
  const connector = this.connectors[resource.dataSource];
568
640
  yield connector.createRecord({ resource, record });
569
641
  // execute hook if needed
570
- if ((_u = (_t = resource.hooks) === null || _t === void 0 ? void 0 : _t.create) === null || _u === void 0 ? void 0 : _u.afterSave) {
571
- const resp = yield ((_w = (_v = resource.hooks) === null || _v === void 0 ? void 0 : _v.create) === null || _w === void 0 ? void 0 : _w.afterSave({ resource, record, adminUser }));
642
+ if ((_z = (_y = resource.hooks) === null || _y === void 0 ? void 0 : _y.create) === null || _z === void 0 ? void 0 : _z.afterSave) {
643
+ const resp = yield ((_1 = (_0 = resource.hooks) === null || _0 === void 0 ? void 0 : _0.create) === null || _1 === void 0 ? void 0 : _1.afterSave({ resource, record, adminUser }));
572
644
  if (!resp || (!resp.ok && !resp.error)) {
573
645
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
574
646
  }
@@ -585,8 +657,8 @@ class AdminForth {
585
657
  noAuth: true, // TODO
586
658
  method: 'POST',
587
659
  path: '/update_record',
588
- handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body, adminUser }) {
589
- var _y, _z, _0, _1, _2, _3, _4, _5;
660
+ handler: (_2) => __awaiter(this, [_2], void 0, function* ({ body, adminUser }) {
661
+ var _3, _4, _5, _6, _7, _8, _9, _10;
590
662
  console.log('update_record', body);
591
663
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
592
664
  if (!resource) {
@@ -601,8 +673,8 @@ class AdminForth {
601
673
  }
602
674
  const record = body['record'];
603
675
  // execute hook if needed
604
- if ((_z = (_y = resource.hooks) === null || _y === void 0 ? void 0 : _y.edit) === null || _z === void 0 ? void 0 : _z.beforeSave) {
605
- const resp = yield ((_1 = (_0 = resource.hooks) === null || _0 === void 0 ? void 0 : _0.edit) === null || _1 === void 0 ? void 0 : _1.beforeSave({ resource, record, adminUser }));
676
+ if ((_4 = (_3 = resource.hooks) === null || _3 === void 0 ? void 0 : _3.edit) === null || _4 === void 0 ? void 0 : _4.beforeSave) {
677
+ const resp = yield ((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.edit) === null || _6 === void 0 ? void 0 : _6.beforeSave({ resource, record, adminUser }));
606
678
  if (!resp || (!resp.ok && !resp.error)) {
607
679
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
608
680
  }
@@ -620,8 +692,8 @@ class AdminForth {
620
692
  yield connector.updateRecord({ resource, recordId, record, newValues });
621
693
  }
622
694
  // execute hook if needed
623
- if ((_3 = (_2 = resource.hooks) === null || _2 === void 0 ? void 0 : _2.edit) === null || _3 === void 0 ? void 0 : _3.afterSave) {
624
- const resp = yield ((_5 = (_4 = resource.hooks) === null || _4 === void 0 ? void 0 : _4.edit) === null || _5 === void 0 ? void 0 : _5.afterSave({ resource, record, adminUser }));
695
+ if ((_8 = (_7 = resource.hooks) === null || _7 === void 0 ? void 0 : _7.edit) === null || _8 === void 0 ? void 0 : _8.afterSave) {
696
+ const resp = yield ((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.edit) === null || _10 === void 0 ? void 0 : _10.afterSave({ resource, record, adminUser }));
625
697
  if (!resp || (!resp.ok && !resp.error)) {
626
698
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
627
699
  }
@@ -638,16 +710,16 @@ class AdminForth {
638
710
  noAuth: true, // TODO
639
711
  method: 'POST',
640
712
  path: '/delete_record',
641
- handler: (_6) => __awaiter(this, [_6], void 0, function* ({ body, adminUser }) {
642
- var _7, _8, _9, _10, _11, _12, _13, _14;
713
+ handler: (_11) => __awaiter(this, [_11], void 0, function* ({ body, adminUser }) {
714
+ var _12, _13, _14, _15, _16, _17, _18, _19;
643
715
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
644
716
  const record = yield this.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
645
717
  if (!resource) {
646
718
  return { error: `Resource '${body['resourceId']}' not found` };
647
719
  }
648
720
  // execute hook if needed
649
- if ((_8 = (_7 = resource.hooks) === null || _7 === void 0 ? void 0 : _7.delete) === null || _8 === void 0 ? void 0 : _8.beforeSave) {
650
- const resp = yield ((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.delete) === null || _10 === void 0 ? void 0 : _10.beforeSave({ resource, record, adminUser }));
721
+ if ((_13 = (_12 = resource.hooks) === null || _12 === void 0 ? void 0 : _12.delete) === null || _13 === void 0 ? void 0 : _13.beforeSave) {
722
+ const resp = yield ((_15 = (_14 = resource.hooks) === null || _14 === void 0 ? void 0 : _14.delete) === null || _15 === void 0 ? void 0 : _15.beforeSave({ resource, record, adminUser }));
651
723
  if (!resp || (!resp.ok && !resp.error)) {
652
724
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
653
725
  }
@@ -658,8 +730,8 @@ class AdminForth {
658
730
  const connector = this.connectors[resource.dataSource];
659
731
  yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
660
732
  // execute hook if needed
661
- if ((_12 = (_11 = resource.hooks) === null || _11 === void 0 ? void 0 : _11.delete) === null || _12 === void 0 ? void 0 : _12.afterSave) {
662
- const resp = yield ((_14 = (_13 = resource.hooks) === null || _13 === void 0 ? void 0 : _13.delete) === null || _14 === void 0 ? void 0 : _14.afterSave({ resource, record, adminUser }));
733
+ if ((_17 = (_16 = resource.hooks) === null || _16 === void 0 ? void 0 : _16.delete) === null || _17 === void 0 ? void 0 : _17.afterSave) {
734
+ const resp = yield ((_19 = (_18 = resource.hooks) === null || _18 === void 0 ? void 0 : _18.delete) === null || _19 === void 0 ? void 0 : _19.afterSave({ resource, record, adminUser }));
663
735
  if (!resp || (!resp.ok && !resp.error)) {
664
736
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
665
737
  }
@@ -676,7 +748,7 @@ class AdminForth {
676
748
  noAuth: true, // TODO
677
749
  method: 'POST',
678
750
  path: '/start_bulk_action',
679
- handler: (_15) => __awaiter(this, [_15], void 0, function* ({ body }) {
751
+ handler: (_20) => __awaiter(this, [_20], void 0, function* ({ body }) {
680
752
  const { resourceId, actionId, recordIds } = body;
681
753
  const resource = this.config.resources.find((res) => res.resourceId == resourceId);
682
754
  if (!resource) {
@@ -63,9 +63,8 @@ class CodeInjector {
63
63
  rmTmpDir() {
64
64
  return __awaiter(this, void 0, void 0, function* () {
65
65
  // remove spa_tmp folder if it is exists
66
- const spaTmpPath = CodeInjector.SPA_TMP_PATH;
67
66
  try {
68
- yield fs.promises.rm(spaTmpPath, { recursive: true });
67
+ yield fs.promises.rm(CodeInjector.SPA_TMP_PATH, { recursive: true });
69
68
  }
70
69
  catch (e) {
71
70
  // ignore
@@ -74,7 +73,7 @@ class CodeInjector {
74
73
  }
75
74
  prepareSources(_a) {
76
75
  return __awaiter(this, arguments, void 0, function* ({ filesUpdated, verbose = false }) {
77
- var _b, _c, _d;
76
+ var _b, _c, _d, _e, _f, _g;
78
77
  const spaTmpPath = CodeInjector.SPA_TMP_PATH;
79
78
  // check SPA_TMP_PATH exists and create if not
80
79
  try {
@@ -186,23 +185,35 @@ class CodeInjector {
186
185
  }
187
186
  yield fs.promises.writeFile(appVuePath, appVueContent);
188
187
  /* generate custom rotes */
188
+ const homepageMenuItem = this.adminforth.config.menu.find((mi) => mi.homepage);
189
+ let childrenHomePageMenuItem = this.adminforth.config.menu.find((mi) => { var _a; return mi.children && ((_a = mi.children) === null || _a === void 0 ? void 0 : _a.find((mi) => mi.homepage)); });
190
+ let childrenHomepage = (_e = childrenHomePageMenuItem === null || childrenHomePageMenuItem === void 0 ? void 0 : childrenHomePageMenuItem.children) === null || _e === void 0 ? void 0 : _e.find((mi) => mi.homepage);
191
+ let homePagePath = (homepageMenuItem === null || homepageMenuItem === void 0 ? void 0 : homepageMenuItem.path) || `resource/${childrenHomepage === null || childrenHomepage === void 0 ? void 0 : childrenHomepage.resourceId}`;
192
+ if (!homePagePath) {
193
+ homePagePath = ((_f = this.adminforth.config.menu.filter((mi) => mi.path)[0]) === null || _f === void 0 ? void 0 : _f.path) || `resource/${(_g = this.adminforth.config.menu.filter((mi) => mi.children)[0]) === null || _g === void 0 ? void 0 : _g.resourceId}`;
194
+ }
195
+ routes += `{
196
+ path: '/',
197
+ name: 'home',
198
+ //redirect to login
199
+ redirect: '/${homePagePath}'
200
+ },\n`;
189
201
  const routerVuePath = path.join(spaTmpPath, 'src', 'router', 'index.ts');
190
202
  let routerVueContent = yield fs.promises.readFile(routerVuePath, 'utf-8');
191
203
  routerVueContent = routerVueContent.replace('/* IMPORTANT:ADMINFORTH ROUTES */', routes);
192
204
  yield fs.promises.writeFile(routerVuePath, routerVueContent);
193
205
  /* hash checking */
194
- const packageLockPath = path.join(spaTmpPath, 'package-lock.json');
195
- const packageLock = JSON.parse(yield fs.promises.readFile(packageLockPath, 'utf-8'));
196
- const lockHash = hashify(packageLock);
206
+ const spaPackageLockPath = path.join(spaTmpPath, 'package-lock.json');
207
+ const spaPackageLock = JSON.parse(yield fs.promises.readFile(spaPackageLockPath, 'utf-8'));
208
+ const spaLockHash = hashify(spaPackageLock);
197
209
  /* customPackageLock */
198
- const customPackagePath = path.join('./package.json');
199
- const customPackage = JSON.parse(yield fs.promises.readFile(customPackagePath, 'utf-8'));
200
- const customPackageHash = hashify(customPackage);
201
- const customLockPath = path.join('./package-lock.json');
202
- const customLock = JSON.parse(yield fs.promises.readFile(customLockPath, 'utf-8'));
203
- const customLockHash = hashify(customLock);
210
+ const usersPackagePath = path.join('./package.json');
211
+ const usersPackage = JSON.parse(yield fs.promises.readFile(usersPackagePath, 'utf-8'));
212
+ const usersLockPath = path.join('./package-lock.json');
213
+ const usersLock = JSON.parse(yield fs.promises.readFile(usersLockPath, 'utf-8'));
214
+ const usersLockHash = hashify(usersLock);
204
215
  const packagesNamesHash = hashify(packageNames);
205
- const fullHash = hashify([lockHash, packagesNamesHash, customLockHash]);
216
+ const fullHash = `${spaLockHash}::${packagesNamesHash}::${usersLockHash}`;
206
217
  const hashPath = path.join(spaTmpPath, 'node_modules', '.adminforth_hash');
207
218
  try {
208
219
  const existingHash = yield fs.promises.readFile(hashPath, 'utf-8');
@@ -210,14 +221,25 @@ class CodeInjector {
210
221
  console.log('Hashes match, skipping npm ci/install');
211
222
  return;
212
223
  }
224
+ else {
225
+ if (verbose) {
226
+ console.log(`Hashes do not match: existing ${existingHash} new ${fullHash}, proceeding with npm ci/install`);
227
+ }
228
+ }
213
229
  }
214
230
  catch (e) {
215
231
  // ignore
232
+ if (verbose) {
233
+ console.log('Hash file does not exist, proceeding with npm ci/install');
234
+ }
216
235
  }
217
236
  yield this.runNpmShell({ command: 'ci', verbose, cwd: spaTmpPath });
218
237
  // get packages with version from customPackage
219
- const customPackgeNames = [...Object.keys(customPackage.dependencies), ...Object.keys(customPackage.devDependencies || [])].reduce((acc, packageName) => {
220
- const version = customLock.packages[`node_modules/${packageName}`].version;
238
+ const IGNORE_PACKAGES = ['tsx', 'typescript', 'express', 'nodemon'];
239
+ const customPackgeNames = [...Object.keys(usersPackage.dependencies), ...Object.keys(usersPackage.devDependencies || [])]
240
+ .filter((packageName) => !IGNORE_PACKAGES.includes(packageName))
241
+ .reduce((acc, packageName) => {
242
+ const version = usersLock.packages[`node_modules/${packageName}`].version;
221
243
  acc.push(`${packageName}@${version}`);
222
244
  return acc;
223
245
  }, []);
@@ -9,12 +9,15 @@
9
9
  "version": "0.0.0",
10
10
  "dependencies": {
11
11
  "@iconify-prerendered/vue-flowbite": "^0.23.1714023977",
12
+ "@vueuse/core": "^10.10.0",
12
13
  "dayjs": "^1.11.11",
14
+ "debounce": "^2.1.0",
13
15
  "flowbite": "^2.3.0",
14
16
  "flowbite-datepicker": "^1.2.6",
15
17
  "pinia": "^2.1.7",
16
18
  "vue": "^3.4.21",
17
- "vue-router": "^4.3.0"
19
+ "vue-router": "^4.3.0",
20
+ "vue-slider-component": "^4.1.0-beta.7"
18
21
  },
19
22
  "devDependencies": {
20
23
  "@rushstack/eslint-patch": "^1.8.0",
@@ -950,6 +953,11 @@
950
953
  "undici-types": "~5.26.4"
951
954
  }
952
955
  },
956
+ "node_modules/@types/web-bluetooth": {
957
+ "version": "0.0.20",
958
+ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
959
+ "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
960
+ },
953
961
  "node_modules/@typescript-eslint/eslint-plugin": {
954
962
  "version": "7.9.0",
955
963
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz",
@@ -1330,6 +1338,89 @@
1330
1338
  "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
1331
1339
  "dev": true
1332
1340
  },
1341
+ "node_modules/@vueuse/core": {
1342
+ "version": "10.10.0",
1343
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.10.0.tgz",
1344
+ "integrity": "sha512-vexJ/YXYs2S42B783rI95lMt3GzEwkxzC8Hb0Ndpd8rD+p+Lk/Za4bd797Ym7yq4jXqdSyj3JLChunF/vyYjUw==",
1345
+ "dependencies": {
1346
+ "@types/web-bluetooth": "^0.0.20",
1347
+ "@vueuse/metadata": "10.10.0",
1348
+ "@vueuse/shared": "10.10.0",
1349
+ "vue-demi": ">=0.14.7"
1350
+ },
1351
+ "funding": {
1352
+ "url": "https://github.com/sponsors/antfu"
1353
+ }
1354
+ },
1355
+ "node_modules/@vueuse/core/node_modules/vue-demi": {
1356
+ "version": "0.14.8",
1357
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
1358
+ "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
1359
+ "hasInstallScript": true,
1360
+ "bin": {
1361
+ "vue-demi-fix": "bin/vue-demi-fix.js",
1362
+ "vue-demi-switch": "bin/vue-demi-switch.js"
1363
+ },
1364
+ "engines": {
1365
+ "node": ">=12"
1366
+ },
1367
+ "funding": {
1368
+ "url": "https://github.com/sponsors/antfu"
1369
+ },
1370
+ "peerDependencies": {
1371
+ "@vue/composition-api": "^1.0.0-rc.1",
1372
+ "vue": "^3.0.0-0 || ^2.6.0"
1373
+ },
1374
+ "peerDependenciesMeta": {
1375
+ "@vue/composition-api": {
1376
+ "optional": true
1377
+ }
1378
+ }
1379
+ },
1380
+ "node_modules/@vueuse/metadata": {
1381
+ "version": "10.10.0",
1382
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.10.0.tgz",
1383
+ "integrity": "sha512-UNAo2sTCAW5ge6OErPEHb5z7NEAg3XcO9Cj7OK45aZXfLLH1QkexDcZD77HBi5zvEiLOm1An+p/4b5K3Worpug==",
1384
+ "funding": {
1385
+ "url": "https://github.com/sponsors/antfu"
1386
+ }
1387
+ },
1388
+ "node_modules/@vueuse/shared": {
1389
+ "version": "10.10.0",
1390
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.10.0.tgz",
1391
+ "integrity": "sha512-2aW33Ac0Uk0U+9yo3Ypg9s5KcR42cuehRWl7vnUHadQyFvCktseyxxEPBi1Eiq4D2yBGACOnqLZpx1eMc7g5Og==",
1392
+ "dependencies": {
1393
+ "vue-demi": ">=0.14.7"
1394
+ },
1395
+ "funding": {
1396
+ "url": "https://github.com/sponsors/antfu"
1397
+ }
1398
+ },
1399
+ "node_modules/@vueuse/shared/node_modules/vue-demi": {
1400
+ "version": "0.14.8",
1401
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
1402
+ "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
1403
+ "hasInstallScript": true,
1404
+ "bin": {
1405
+ "vue-demi-fix": "bin/vue-demi-fix.js",
1406
+ "vue-demi-switch": "bin/vue-demi-switch.js"
1407
+ },
1408
+ "engines": {
1409
+ "node": ">=12"
1410
+ },
1411
+ "funding": {
1412
+ "url": "https://github.com/sponsors/antfu"
1413
+ },
1414
+ "peerDependencies": {
1415
+ "@vue/composition-api": "^1.0.0-rc.1",
1416
+ "vue": "^3.0.0-0 || ^2.6.0"
1417
+ },
1418
+ "peerDependenciesMeta": {
1419
+ "@vue/composition-api": {
1420
+ "optional": true
1421
+ }
1422
+ }
1423
+ },
1333
1424
  "node_modules/acorn": {
1334
1425
  "version": "8.11.3",
1335
1426
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@@ -1716,6 +1807,17 @@
1716
1807
  "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
1717
1808
  "dev": true
1718
1809
  },
1810
+ "node_modules/debounce": {
1811
+ "version": "2.1.0",
1812
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.1.0.tgz",
1813
+ "integrity": "sha512-OkL3+0pPWCqoBc/nhO9u6TIQNTK44fnBnzuVtJAbp13Naxw9R6u21x+8tVTka87AhDZ3htqZ2pSSsZl9fqL2Wg==",
1814
+ "engines": {
1815
+ "node": ">=18"
1816
+ },
1817
+ "funding": {
1818
+ "url": "https://github.com/sponsors/sindresorhus"
1819
+ }
1820
+ },
1719
1821
  "node_modules/debug": {
1720
1822
  "version": "4.3.4",
1721
1823
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -3970,6 +4072,11 @@
3970
4072
  "vue": "^3.2.0"
3971
4073
  }
3972
4074
  },
4075
+ "node_modules/vue-slider-component": {
4076
+ "version": "4.1.0-beta.7",
4077
+ "resolved": "https://registry.npmjs.org/vue-slider-component/-/vue-slider-component-4.1.0-beta.7.tgz",
4078
+ "integrity": "sha512-Qb7K920ZG7PoQswoF6Ias+i3W2rd3k4fpk04JUl82kEUcN86Yg6et7bVSKWt/7VpQe8a5IT3BqCKSCOZ7AJgCA=="
4079
+ },
3973
4080
  "node_modules/vue-template-compiler": {
3974
4081
  "version": "2.7.16",
3975
4082
  "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
@@ -13,12 +13,15 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@iconify-prerendered/vue-flowbite": "^0.23.1714023977",
16
+ "@vueuse/core": "^10.10.0",
16
17
  "dayjs": "^1.11.11",
18
+ "debounce": "^2.1.0",
17
19
  "flowbite": "^2.3.0",
18
20
  "flowbite-datepicker": "^1.2.6",
19
21
  "pinia": "^2.1.7",
20
22
  "vue": "^3.4.21",
21
- "vue-router": "^4.3.0"
23
+ "vue-router": "^4.3.0",
24
+ "vue-slider-component": "^4.1.0-beta.7"
22
25
  },
23
26
  "devDependencies": {
24
27
  "@rushstack/eslint-patch": "^1.8.0",
@@ -32,7 +32,7 @@
32
32
 
33
33
  </button>
34
34
  </div>
35
- <div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600 dark:shadow-xl" id="dropdown-user">
35
+ <div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:shadow-black dark:bg-gray-700 dark:divide-gray-600 dark:shadow-black" id="dropdown-user">
36
36
  <div class="px-4 py-3" role="none">
37
37
  <p class="text-sm text-gray-900 dark:text-white" role="none" v-if="coreStore.userFullname">
38
38
  {{ coreStore.userFullname }}
@@ -112,7 +112,7 @@
112
112
  </div>
113
113
  </div>
114
114
 
115
- <div v-else>
115
+ <div v-else-if="routerIsReady">
116
116
  <RouterView/>
117
117
  </div>
118
118
  <AcceptModal />
@@ -16,7 +16,7 @@ const modalStore = useModalStore();
16
16
  <Teleport to="body">
17
17
  <div v-if="modalStore.isOpened" class="bg-gray-900/50 dark:bg-gray-900/80 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
18
18
  <div class="relative p-4 w-full max-w-md max-h-full top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 " >
19
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
19
+ <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black">
20
20
  <button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
21
21
  <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
22
22
  <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"/>