adminforth 1.0.31 → 1.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dataConnectors/postgres.ts +9 -6
  2. package/dataConnectors/sqlite.ts +1 -0
  3. package/dist/dataConnectors/postgres.js +9 -6
  4. package/dist/dataConnectors/sqlite.js +1 -0
  5. package/dist/index.js +87 -65
  6. package/dist/modules/utils.js +9 -0
  7. package/dist/spa/spa/src/App.vue +0 -7
  8. package/dist/spa/spa/src/components/CustomDatePicker.vue +3 -3
  9. package/dist/spa/spa/src/components/CustomDateRangePicker.vue +3 -3
  10. package/dist/spa/spa/src/components/CustomRangePicker.vue +32 -19
  11. package/dist/spa/spa/src/components/Dropdown.vue +6 -2
  12. package/dist/spa/spa/src/components/ResourceForm.vue +125 -102
  13. package/dist/spa/spa/src/components/ValueRenderer.vue +11 -1
  14. package/dist/spa/spa/src/stores/core.ts +21 -19
  15. package/dist/spa/spa/src/views/CreateView.vue +16 -6
  16. package/dist/spa/spa/src/views/EditView.vue +15 -5
  17. package/dist/spa/spa/src/views/ListView.vue +31 -21
  18. package/dist/spa/spa/src/views/ResourceParent.vue +1 -1
  19. package/dist/spa/spa/src/views/ShowView.vue +21 -6
  20. package/dist/types/AdminForthConfig.js +1 -0
  21. package/index.ts +73 -141
  22. package/modules/utils.ts +14 -0
  23. package/package.json +1 -1
  24. package/spa/src/App.vue +0 -7
  25. package/spa/src/components/CustomDatePicker.vue +3 -3
  26. package/spa/src/components/CustomDateRangePicker.vue +3 -3
  27. package/spa/src/components/CustomRangePicker.vue +32 -19
  28. package/spa/src/components/Dropdown.vue +6 -2
  29. package/spa/src/components/ResourceForm.vue +125 -102
  30. package/spa/src/components/ValueRenderer.vue +11 -1
  31. package/spa/src/stores/core.ts +21 -19
  32. package/spa/src/views/CreateView.vue +16 -6
  33. package/spa/src/views/EditView.vue +15 -5
  34. package/spa/src/views/ListView.vue +31 -21
  35. package/spa/src/views/ResourceParent.vue +1 -1
  36. package/spa/src/views/ShowView.vue +21 -6
  37. package/types/AdminForthConfig.ts +159 -0
@@ -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() {
@@ -138,6 +138,7 @@ class SQLiteConnector {
138
138
 
139
139
 
140
140
  getData({ resource, limit, offset, sort, filters }) {
141
+ console.log('getDataREQ', { resource, limit, offset, sort, filters });
141
142
  const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
142
143
  const tableName = resource.table;
143
144
 
@@ -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() {
@@ -148,6 +148,7 @@ class SQLiteConnector {
148
148
  return value;
149
149
  }
150
150
  getData({ resource, limit, offset, sort, filters }) {
151
+ console.log('getDataREQ', { resource, limit, offset, sort, filters });
151
152
  const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
152
153
  const tableName = resource.table;
153
154
  for (const filter of filters) {
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ 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
+ import { ADMINFORTH_VERSION } from './modules/utils.js';
25
26
  import { AdminForthFilterOperators, AdminForthTypes } from './types.js';
26
27
  const AVAILABLE_SHOW_IN = ['list', 'edit', 'create', 'filter', 'show'];
27
28
  const DEFAULT_ALLOWED_ACTIONS = { create: true, edit: true, show: true, delete: true };
@@ -37,6 +38,7 @@ class AdminForth {
37
38
  this.codeInjector = new CodeInjector(this);
38
39
  this.connectors = {};
39
40
  this.statuses = {};
41
+ console.log(`🚀 AdminForth v${ADMINFORTH_VERSION} starting up`);
40
42
  }
41
43
  validateConfig() {
42
44
  if (this.config.rootUser) {
@@ -249,7 +251,7 @@ class AdminForth {
249
251
  if (!this.config.databaseConnectors[dbType]) {
250
252
  throw new Error(`Database type ${dbType} is not supported, consider using databaseConnectors in AdminForth config`);
251
253
  }
252
- this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({ url: ds.url, fieldtypesByTable: ds.fieldtypesByTable });
254
+ this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({ url: ds.url });
253
255
  });
254
256
  yield Promise.all(this.config.resources.map((res) => __awaiter(this, void 0, void 0, function* () {
255
257
  if (!this.connectors[res.dataSource]) {
@@ -279,11 +281,6 @@ class AdminForth {
279
281
  // console.log('⚙️⚙️⚙️ Database discovery done', JSON.stringify(this.config.resources, null, 2));
280
282
  });
281
283
  }
282
- init() {
283
- return __awaiter(this, void 0, void 0, function* () {
284
- console.log('AdminForth init');
285
- });
286
- }
287
284
  bundleNow(_b) {
288
285
  return __awaiter(this, arguments, void 0, function* ({ hotReload = false, verbose = false }) {
289
286
  this.codeInjector.bundleNow({ hotReload, verbose });
@@ -388,11 +385,11 @@ class AdminForth {
388
385
  return { error: 'Unauthorized' };
389
386
  }
390
387
  username = user.data[0][this.config.auth.usernameField];
391
- userFullName = user.data[0][this.config.auth.userFullName];
388
+ userFullName = user.data[0][this.config.auth.userFullNameField];
392
389
  }
393
390
  const userData = {
394
391
  [this.config.auth.usernameField]: username,
395
- [this.config.auth.userFullName]: userFullName
392
+ [this.config.auth.userFullNameField]: userFullName
396
393
  };
397
394
  return {
398
395
  user: userData,
@@ -409,6 +406,7 @@ class AdminForth {
409
406
  usernameField: this.config.auth.usernameField,
410
407
  },
411
408
  adminUser,
409
+ version: ADMINFORTH_VERSION,
412
410
  };
413
411
  }),
414
412
  });
@@ -433,8 +431,12 @@ class AdminForth {
433
431
  server.endpoint({
434
432
  method: 'POST',
435
433
  path: '/get_resource_data',
436
- handler: (_g) => __awaiter(this, [_g], void 0, function* ({ body }) {
437
- const { resourceId, limit, offset, filters, sort } = body;
434
+ handler: (_g) => __awaiter(this, [_g], void 0, function* ({ body, adminUser }) {
435
+ var _h, _j, _k, _l, _m, _o, _p, _q;
436
+ const { resourceId, source } = body;
437
+ if (['show', 'list'].includes(source) === false) {
438
+ return { error: 'Invalid source, should be list or show' };
439
+ }
438
440
  if (!this.statuses.dbDiscover) {
439
441
  return { error: 'Database discovery not started' };
440
442
  }
@@ -445,6 +447,16 @@ class AdminForth {
445
447
  if (!resource) {
446
448
  return { error: `Resource ${resourceId} not found` };
447
449
  }
450
+ if ((_j = (_h = resource.hooks) === null || _h === void 0 ? void 0 : _h[source]) === null || _j === void 0 ? void 0 : _j.beforeDatasourceRequest) {
451
+ const resp = yield ((_l = (_k = resource.hooks) === null || _k === void 0 ? void 0 : _k[source]) === null || _l === void 0 ? void 0 : _l.beforeDatasourceRequest({ resource, query: body, adminUser }));
452
+ if (!resp || (!resp.ok && !resp.error)) {
453
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
454
+ }
455
+ if (resp.error) {
456
+ return { error: resp.error };
457
+ }
458
+ }
459
+ const { limit, offset, filters, sort } = body;
448
460
  const data = yield this.connectors[resource.dataSource].getData({
449
461
  resource,
450
462
  limit,
@@ -452,14 +464,52 @@ class AdminForth {
452
464
  filters,
453
465
  sort,
454
466
  });
467
+ // for foreign keys, add references
468
+ yield Promise.all(resource.columns.filter((col) => col.foreignResource).map((col) => __awaiter(this, void 0, void 0, function* () {
469
+ const targetResource = this.config.resources.find((res) => res.resourceId == col.foreignResource.resourceId);
470
+ const targetConnector = this.connectors[targetResource.dataSource];
471
+ const targetResourcePkField = targetResource.columns.find((col) => col.primaryKey).name;
472
+ const targetData = yield targetConnector.getData({
473
+ resource: targetResource,
474
+ limit: limit,
475
+ offset: 0,
476
+ filters: [
477
+ {
478
+ field: targetResourcePkField,
479
+ operator: AdminForthFilterOperators.IN,
480
+ value: data.data.map((item) => item[col.name]),
481
+ }
482
+ ],
483
+ sort: [],
484
+ });
485
+ const targetDataMap = targetData.data.reduce((acc, item) => {
486
+ acc[item[targetResourcePkField]] = {
487
+ label: targetResource.itemLabel ? targetResource.itemLabel(item) : item[targetResourcePkField],
488
+ pk: item[targetResourcePkField],
489
+ };
490
+ return acc;
491
+ }, {});
492
+ data.data.forEach((item) => {
493
+ item[col.name] = targetDataMap[item[col.name]];
494
+ });
495
+ })));
496
+ if ((_o = (_m = resource.hooks) === null || _m === void 0 ? void 0 : _m[source]) === null || _o === void 0 ? void 0 : _o.afterDatasourceRequest) {
497
+ const resp = yield ((_q = (_p = resource.hooks) === null || _p === void 0 ? void 0 : _p[source]) === null || _q === void 0 ? void 0 : _q.afterDatasourceRequest({ resource, response: data.data, adminUser }));
498
+ if (!resp || (!resp.ok && !resp.error)) {
499
+ throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
500
+ }
501
+ if (resp.error) {
502
+ return { error: resp.error };
503
+ }
504
+ }
455
505
  return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
456
506
  }),
457
507
  });
458
508
  server.endpoint({
459
509
  method: 'POST',
460
510
  path: '/get_resource_foreign_data',
461
- handler: (_h) => __awaiter(this, [_h], void 0, function* ({ body, adminUser }) {
462
- var _j, _k, _l, _m;
511
+ handler: (_r) => __awaiter(this, [_r], void 0, function* ({ body, adminUser }) {
512
+ var _s, _t, _u, _v;
463
513
  const { resourceId, column } = body;
464
514
  if (!this.statuses.dbDiscover) {
465
515
  return { error: 'Database discovery not started' };
@@ -477,8 +527,8 @@ class AdminForth {
477
527
  }
478
528
  const targetResourceId = columnConfig.foreignResource.resourceId;
479
529
  const targetResource = this.config.resources.find((res) => res.resourceId == targetResourceId);
480
- if ((_j = columnConfig.foreignResource.hooks) === null || _j === void 0 ? void 0 : _j.beforeDatasourceRequest) {
481
- const resp = yield ((_k = column.foreignResource.hooks) === null || _k === void 0 ? void 0 : _k.beforeDatasourceRequest({ query: body, adminUser }));
530
+ if ((_s = columnConfig.foreignResource.hooks) === null || _s === void 0 ? void 0 : _s.beforeDatasourceRequest) {
531
+ const resp = yield ((_t = column.foreignResource.hooks) === null || _t === void 0 ? void 0 : _t.beforeDatasourceRequest({ query: body, adminUser }));
482
532
  if (!resp || (!resp.ok && !resp.error)) {
483
533
  throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
484
534
  }
@@ -506,8 +556,8 @@ class AdminForth {
506
556
  const response = {
507
557
  items
508
558
  };
509
- if ((_l = columnConfig.foreignResource.hooks) === null || _l === void 0 ? void 0 : _l.afterDatasourceRequest) {
510
- const resp = yield ((_m = column.foreignResource.hooks) === null || _m === void 0 ? void 0 : _m.afterDatasourceRequest({ response, adminUser }));
559
+ if ((_u = columnConfig.foreignResource.hooks) === null || _u === void 0 ? void 0 : _u.afterDatasourceResponse) {
560
+ const resp = yield ((_v = column.foreignResource.hooks) === null || _v === void 0 ? void 0 : _v.afterDatasourceResponse({ response, adminUser }));
511
561
  if (!resp || (!resp.ok && !resp.error)) {
512
562
  throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
513
563
  }
@@ -521,7 +571,7 @@ class AdminForth {
521
571
  server.endpoint({
522
572
  method: 'POST',
523
573
  path: '/get_min_max_for_columns',
524
- handler: (_o) => __awaiter(this, [_o], void 0, function* ({ body }) {
574
+ handler: (_w) => __awaiter(this, [_w], void 0, function* ({ body }) {
525
575
  const { resourceId } = body;
526
576
  if (!this.statuses.dbDiscover) {
527
577
  return { error: 'Database discovery not started' };
@@ -547,40 +597,12 @@ class AdminForth {
547
597
  return item;
548
598
  }),
549
599
  });
550
- server.endpoint({
551
- method: 'POST',
552
- path: '/get_record',
553
- handler: (_p) => __awaiter(this, [_p], void 0, function* ({ body, adminUser }) {
554
- var _q, _r;
555
- const { resourceId, primaryKey } = body;
556
- const resource = this.config.resources.find((res) => res.resourceId == resourceId);
557
- const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
558
- const connector = this.connectors[resource.dataSource];
559
- const record = yield connector.getRecordByPrimaryKey(resource, primaryKey);
560
- if (!record) {
561
- return { error: `Record with ${primaryKeyColumn.name} ${primaryKey} not found` };
562
- }
563
- // execute hook if needed
564
- if ((_q = resource.hooks) === null || _q === void 0 ? void 0 : _q.show) {
565
- const resp = yield ((_r = resource.hooks) === null || _r === void 0 ? void 0 : _r.show({ resource, record, adminUser }));
566
- if (!resp || (!resp.ok && !resp.error)) {
567
- throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
568
- }
569
- if (resp.error) {
570
- return { error: resp.error };
571
- }
572
- }
573
- const labler = resource.itemLabel || ((record) => `${resource.label} ${record[primaryKeyColumn.name]}`);
574
- record._label = labler(record);
575
- return record;
576
- })
577
- });
578
600
  server.endpoint({
579
601
  noAuth: true, // TODO
580
602
  method: 'POST',
581
603
  path: '/create_record',
582
- handler: (_s) => __awaiter(this, [_s], void 0, function* ({ body, adminUser }) {
583
- var _t, _u, _v, _w, _x, _y, _z, _0, _1;
604
+ handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body, adminUser }) {
605
+ var _y, _z, _0, _1, _2, _3, _4, _5, _6;
584
606
  console.log('create_record', body, this.config.resources);
585
607
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
586
608
  if (!resource) {
@@ -588,8 +610,8 @@ class AdminForth {
588
610
  }
589
611
  const record = body['record'];
590
612
  // execute hook if needed
591
- if ((_u = (_t = resource.hooks) === null || _t === void 0 ? void 0 : _t.create) === null || _u === void 0 ? void 0 : _u.beforeSave) {
592
- 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 }));
613
+ if ((_z = (_y = resource.hooks) === null || _y === void 0 ? void 0 : _y.create) === null || _z === void 0 ? void 0 : _z.beforeSave) {
614
+ const resp = yield ((_1 = (_0 = resource.hooks) === null || _0 === void 0 ? void 0 : _0.create) === null || _1 === void 0 ? void 0 : _1.beforeSave({ resource, record, adminUser }));
593
615
  if (!resp || (!resp.ok && !resp.error)) {
594
616
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
595
617
  }
@@ -605,7 +627,7 @@ class AdminForth {
605
627
  });
606
628
  }
607
629
  }
608
- if (((_x = column.required) === null || _x === void 0 ? void 0 : _x.create) && body['record'][column.name] === undefined) {
630
+ if (((_2 = column.required) === null || _2 === void 0 ? void 0 : _2.create) && body['record'][column.name] === undefined) {
609
631
  return { error: `Column '${column.name}' is required` };
610
632
  }
611
633
  if (column.isUnique) {
@@ -630,8 +652,8 @@ class AdminForth {
630
652
  const connector = this.connectors[resource.dataSource];
631
653
  yield connector.createRecord({ resource, record });
632
654
  // execute hook if needed
633
- if ((_z = (_y = resource.hooks) === null || _y === void 0 ? void 0 : _y.create) === null || _z === void 0 ? void 0 : _z.afterSave) {
634
- 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 }));
655
+ if ((_4 = (_3 = resource.hooks) === null || _3 === void 0 ? void 0 : _3.create) === null || _4 === void 0 ? void 0 : _4.afterSave) {
656
+ const resp = yield ((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.create) === null || _6 === void 0 ? void 0 : _6.afterSave({ resource, record, adminUser }));
635
657
  if (!resp || (!resp.ok && !resp.error)) {
636
658
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
637
659
  }
@@ -648,8 +670,8 @@ class AdminForth {
648
670
  noAuth: true, // TODO
649
671
  method: 'POST',
650
672
  path: '/update_record',
651
- handler: (_2) => __awaiter(this, [_2], void 0, function* ({ body, adminUser }) {
652
- var _3, _4, _5, _6, _7, _8, _9, _10;
673
+ handler: (_7) => __awaiter(this, [_7], void 0, function* ({ body, adminUser }) {
674
+ var _8, _9, _10, _11, _12, _13, _14, _15;
653
675
  console.log('update_record', body);
654
676
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
655
677
  if (!resource) {
@@ -664,8 +686,8 @@ class AdminForth {
664
686
  }
665
687
  const record = body['record'];
666
688
  // execute hook if needed
667
- if ((_4 = (_3 = resource.hooks) === null || _3 === void 0 ? void 0 : _3.edit) === null || _4 === void 0 ? void 0 : _4.beforeSave) {
668
- 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 }));
689
+ if ((_9 = (_8 = resource.hooks) === null || _8 === void 0 ? void 0 : _8.edit) === null || _9 === void 0 ? void 0 : _9.beforeSave) {
690
+ const resp = yield ((_11 = (_10 = resource.hooks) === null || _10 === void 0 ? void 0 : _10.edit) === null || _11 === void 0 ? void 0 : _11.beforeSave({ resource, record, adminUser }));
669
691
  if (!resp || (!resp.ok && !resp.error)) {
670
692
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
671
693
  }
@@ -683,8 +705,8 @@ class AdminForth {
683
705
  yield connector.updateRecord({ resource, recordId, record, newValues });
684
706
  }
685
707
  // execute hook if needed
686
- if ((_8 = (_7 = resource.hooks) === null || _7 === void 0 ? void 0 : _7.edit) === null || _8 === void 0 ? void 0 : _8.afterSave) {
687
- 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 }));
708
+ if ((_13 = (_12 = resource.hooks) === null || _12 === void 0 ? void 0 : _12.edit) === null || _13 === void 0 ? void 0 : _13.afterSave) {
709
+ const resp = yield ((_15 = (_14 = resource.hooks) === null || _14 === void 0 ? void 0 : _14.edit) === null || _15 === void 0 ? void 0 : _15.afterSave({ resource, record, adminUser }));
688
710
  if (!resp || (!resp.ok && !resp.error)) {
689
711
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
690
712
  }
@@ -701,16 +723,16 @@ class AdminForth {
701
723
  noAuth: true, // TODO
702
724
  method: 'POST',
703
725
  path: '/delete_record',
704
- handler: (_11) => __awaiter(this, [_11], void 0, function* ({ body, adminUser }) {
705
- var _12, _13, _14, _15, _16, _17, _18, _19;
726
+ handler: (_16) => __awaiter(this, [_16], void 0, function* ({ body, adminUser }) {
727
+ var _17, _18, _19, _20, _21, _22, _23, _24;
706
728
  const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
707
729
  const record = yield this.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
708
730
  if (!resource) {
709
731
  return { error: `Resource '${body['resourceId']}' not found` };
710
732
  }
711
733
  // execute hook if needed
712
- if ((_13 = (_12 = resource.hooks) === null || _12 === void 0 ? void 0 : _12.delete) === null || _13 === void 0 ? void 0 : _13.beforeSave) {
713
- 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 }));
734
+ if ((_18 = (_17 = resource.hooks) === null || _17 === void 0 ? void 0 : _17.delete) === null || _18 === void 0 ? void 0 : _18.beforeSave) {
735
+ const resp = yield ((_20 = (_19 = resource.hooks) === null || _19 === void 0 ? void 0 : _19.delete) === null || _20 === void 0 ? void 0 : _20.beforeSave({ resource, record, adminUser }));
714
736
  if (!resp || (!resp.ok && !resp.error)) {
715
737
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
716
738
  }
@@ -721,8 +743,8 @@ class AdminForth {
721
743
  const connector = this.connectors[resource.dataSource];
722
744
  yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
723
745
  // execute hook if needed
724
- if ((_17 = (_16 = resource.hooks) === null || _16 === void 0 ? void 0 : _16.delete) === null || _17 === void 0 ? void 0 : _17.afterSave) {
725
- 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 }));
746
+ if ((_22 = (_21 = resource.hooks) === null || _21 === void 0 ? void 0 : _21.delete) === null || _22 === void 0 ? void 0 : _22.afterSave) {
747
+ const resp = yield ((_24 = (_23 = resource.hooks) === null || _23 === void 0 ? void 0 : _23.delete) === null || _24 === void 0 ? void 0 : _24.afterSave({ resource, record, adminUser }));
726
748
  if (!resp || (!resp.ok && !resp.error)) {
727
749
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
728
750
  }
@@ -739,7 +761,7 @@ class AdminForth {
739
761
  noAuth: true, // TODO
740
762
  method: 'POST',
741
763
  path: '/start_bulk_action',
742
- handler: (_20) => __awaiter(this, [_20], void 0, function* ({ body }) {
764
+ handler: (_25) => __awaiter(this, [_25], void 0, function* ({ body }) {
743
765
  const { resourceId, actionId, recordIds } = body;
744
766
  const resource = this.config.resources.find((res) => res.resourceId == resourceId);
745
767
  if (!resource) {
@@ -1,3 +1,6 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import fs from 'fs';
1
4
  export function guessLabelFromName(name) {
2
5
  if (name.includes('_')) {
3
6
  return name.split('_').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
@@ -10,3 +13,9 @@ export function guessLabelFromName(name) {
10
13
  return name.split(/(?=[A-Z])/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
11
14
  }
12
15
  }
16
+ let package_json;
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.join(path.dirname(__filename), '..');
19
+ export const ADMIN_FORTH_ABSOLUTE_PATH = __dirname;
20
+ package_json = JSON.parse(fs.readFileSync(path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'package.json'), 'utf8'));
21
+ export const ADMINFORTH_VERSION = package_json.version;
@@ -42,9 +42,6 @@
42
42
  </p>
43
43
  </div>
44
44
  <ul class="py-1" role="none">
45
- <li>
46
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">Dashboard</a>
47
- </li>
48
45
  <li >
49
46
  <span @click="toggleTheme" class=" cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
50
47
  {{ theme === 'dark' ? 'Light' : 'Dark' }}
@@ -141,10 +138,6 @@ const routerIsReady = ref(false);
141
138
 
142
139
  const loggedIn = computed(() => route.name !== 'login' && routerIsReady.value);
143
140
 
144
- watch(loggedIn, (value) => {
145
- console.log('🔻🔻🔻 loggedIn', value);
146
- });
147
-
148
141
  const theme = ref('light');
149
142
 
150
143
  function toggleTheme() {
@@ -5,7 +5,7 @@
5
5
  <label for="start-time" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ label }}</label>
6
6
 
7
7
  <div class="relative">
8
- <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
8
+ <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
9
9
  <IconCalendar class="w-4 h-4 text-gray-500 dark:text-gray-400"/>
10
10
  </div>
11
11
 
@@ -97,7 +97,7 @@ const start = computed(() => {
97
97
  })
98
98
 
99
99
  function updateFromProps() {
100
- if (props.valueStart === undefined) {
100
+ if (!props.valueStart) {
101
101
  datepickerStartEl.value.value = '';
102
102
  startTime.value = '';
103
103
  }
@@ -157,5 +157,5 @@ onMounted(() => {
157
157
 
158
158
  onBeforeUnmount(() => {
159
159
  removeChangeDateListener();
160
- })
160
+ });
161
161
  </script>
@@ -26,7 +26,7 @@
26
26
  <div class="mx-auto grid grid-cols-2 gap-4 mb-2" :class="{hidden: !showTimeInputs}">
27
27
  <div>
28
28
  <div class="relative">
29
- <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
29
+ <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
30
30
  <IconTime class="w-4 h-4 text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700"/>
31
31
  </div>
32
32
 
@@ -132,11 +132,11 @@ const end = computed(() => {
132
132
  })
133
133
 
134
134
  function updateFromProps() {
135
- if (props.valueStart === undefined) {
135
+ if (!props.valueStart) {
136
136
  datepickerStartEl.value.value = '';
137
137
  startTime.value = '';
138
138
  }
139
- if (props.valueEnd === undefined) {
139
+ if (!props.valueEnd) {
140
140
  datepickerEndEl.value.value = '';
141
141
  endTime.value = '';
142
142
  }
@@ -71,33 +71,52 @@ const sliderValue = ref([start.value, end.value]);
71
71
 
72
72
  const updateFromSlider =
73
73
  debounce((value: [number, number]) => {
74
+ console.log('start end', value)
74
75
  start.value = value[0];
75
76
  end.value = value[1];
76
77
  }, 500);
77
78
 
78
- function updateFromProps() {
79
- if (props.valueStart || props.valueEnd) {
80
- setFromProps(props.valueStart, props.valueEnd)
81
- } else {
82
- clear();
83
- }
84
- }
85
-
86
79
  onMounted(() => {
87
- updateFromProps();
80
+ updateStartFromProps();
81
+ updateEndFromProps();
88
82
 
89
- watch(() => [props.valueStart, props.valueEnd], (value) => {
90
- updateFromProps();
83
+ watch(() => props.valueStart, (value) => {
84
+ updateStartFromProps();
85
+ });
86
+
87
+ watch(() => props.valueEnd, (value) => {
88
+ updateEndFromProps();
91
89
  });
92
90
  })
93
91
 
92
+ function updateStartFromProps() {
93
+ if (props.valueStart || props.valueStart === 0) {
94
+ start.value = props.valueStart ? props.valueStart : minFormatted.value;
95
+ sliderValue.value = [start.value, end.value]
96
+ } else {
97
+ console.log(props.valueStart)
98
+ start.value = minFormatted.value;
99
+ sliderValue.value = [minFormatted.value, end.value];
100
+ }
101
+ }
102
+
103
+ function updateEndFromProps() {
104
+ if (props.valueEnd || props.valueStart === 0) {
105
+ end.value = props.valueEnd ? props.valueEnd : minFormatted.value;
106
+ sliderValue.value = [start.value, end.value]
107
+ } else {
108
+ end.value = maxFormatted.value;
109
+ sliderValue.value = [start.value, maxFormatted.value];
110
+ }
111
+ }
112
+
94
113
  watch(start, () => {
95
- //console.log('⚡ emit', start.value)
114
+ console.log('⚡ emit', start.value)
96
115
  emit('update:valueStart', start.value)
97
116
  })
98
117
 
99
118
  watch(end, () => {
100
- //console.log('⚡ emit', end.value)
119
+ console.log('⚡ emit', end.value)
101
120
  emit('update:valueEnd', end.value);
102
121
  })
103
122
 
@@ -106,12 +125,6 @@ const clear = () => {
106
125
  end.value = maxFormatted.value;
107
126
  sliderValue.value = [start.value, end.value]
108
127
  }
109
-
110
- function setFromProps(startValue: number, endValue: number) {
111
- start.value = startValue ? startValue : minFormatted.value
112
- end.value = endValue ? endValue : maxFormatted.value
113
- sliderValue.value = [start.value, end.value]
114
- }
115
128
  </script>
116
129
 
117
130
  <style lang="scss" scoped>
@@ -76,10 +76,14 @@ const showDropdown = ref(false);
76
76
  const selectedItems = ref([]);
77
77
 
78
78
  function updateFromProps() {
79
- console.log('⚡ updateFromProps', props.modelValue)
80
79
  if (props.modelValue !== undefined) {
81
80
  if (props.single) {
82
- selectedItems.value = [props.options.find(item => item.value === props.modelValue)];
81
+ const el = props.options.find(item => item.value === props.modelValue);
82
+ if (el) {
83
+ selectedItems.value = [el];
84
+ } else {
85
+ selectedItems.value = [];
86
+ }
83
87
  } else {
84
88
  selectedItems.value = props.options.filter(item => props.modelValue.includes(item.value));
85
89
  }