adminforth 1.0.32 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dataConnectors/sqlite.ts +1 -0
- package/dist/dataConnectors/sqlite.js +1 -0
- package/dist/index.js +87 -74
- package/dist/modules/utils.js +11 -0
- package/dist/spa/spa/src/App.vue +0 -3
- package/dist/spa/spa/src/components/CustomDatePicker.vue +3 -3
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +3 -3
- package/dist/spa/spa/src/components/CustomRangePicker.vue +32 -19
- package/dist/spa/spa/src/components/Dropdown.vue +6 -1
- package/dist/spa/spa/src/components/ResourceForm.vue +125 -102
- package/dist/spa/spa/src/components/ValueRenderer.vue +11 -1
- package/dist/spa/spa/src/stores/core.ts +21 -19
- package/dist/spa/spa/src/views/CreateView.vue +16 -6
- package/dist/spa/spa/src/views/EditView.vue +15 -5
- package/dist/spa/spa/src/views/ListView.vue +31 -17
- package/dist/spa/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/spa/src/views/ShowView.vue +21 -6
- package/dist/types/AdminForthConfig.js +1 -0
- package/index.ts +73 -149
- package/modules/utils.ts +16 -0
- package/package.json +1 -1
- package/spa/src/App.vue +0 -3
- package/spa/src/components/CustomDatePicker.vue +3 -3
- package/spa/src/components/CustomDateRangePicker.vue +3 -3
- package/spa/src/components/CustomRangePicker.vue +32 -19
- package/spa/src/components/Dropdown.vue +6 -1
- package/spa/src/components/ResourceForm.vue +125 -102
- package/spa/src/components/ValueRenderer.vue +11 -1
- package/spa/src/stores/core.ts +21 -19
- package/spa/src/views/CreateView.vue +16 -6
- package/spa/src/views/EditView.vue +15 -5
- package/spa/src/views/ListView.vue +31 -17
- package/spa/src/views/ResourceParent.vue +1 -1
- package/spa/src/views/ShowView.vue +21 -6
- package/types/AdminForthConfig.ts +159 -0
package/dataConnectors/sqlite.ts
CHANGED
|
@@ -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,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,14 +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
|
-
|
|
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
|
+
import { ADMINFORTH_VERSION } from './modules/utils.js';
|
|
33
26
|
import { AdminForthFilterOperators, AdminForthTypes } from './types.js';
|
|
34
27
|
const AVAILABLE_SHOW_IN = ['list', 'edit', 'create', 'filter', 'show'];
|
|
35
28
|
const DEFAULT_ALLOWED_ACTIONS = { create: true, edit: true, show: true, delete: true };
|
|
@@ -45,6 +38,7 @@ class AdminForth {
|
|
|
45
38
|
this.codeInjector = new CodeInjector(this);
|
|
46
39
|
this.connectors = {};
|
|
47
40
|
this.statuses = {};
|
|
41
|
+
console.log(`🚀 AdminForth v${ADMINFORTH_VERSION} starting up`);
|
|
48
42
|
}
|
|
49
43
|
validateConfig() {
|
|
50
44
|
if (this.config.rootUser) {
|
|
@@ -257,7 +251,7 @@ class AdminForth {
|
|
|
257
251
|
if (!this.config.databaseConnectors[dbType]) {
|
|
258
252
|
throw new Error(`Database type ${dbType} is not supported, consider using databaseConnectors in AdminForth config`);
|
|
259
253
|
}
|
|
260
|
-
this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({ url: ds.url
|
|
254
|
+
this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({ url: ds.url });
|
|
261
255
|
});
|
|
262
256
|
yield Promise.all(this.config.resources.map((res) => __awaiter(this, void 0, void 0, function* () {
|
|
263
257
|
if (!this.connectors[res.dataSource]) {
|
|
@@ -287,11 +281,6 @@ class AdminForth {
|
|
|
287
281
|
// console.log('⚙️⚙️⚙️ Database discovery done', JSON.stringify(this.config.resources, null, 2));
|
|
288
282
|
});
|
|
289
283
|
}
|
|
290
|
-
init() {
|
|
291
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
-
console.log('AdminForth init');
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
284
|
bundleNow(_b) {
|
|
296
285
|
return __awaiter(this, arguments, void 0, function* ({ hotReload = false, verbose = false }) {
|
|
297
286
|
this.codeInjector.bundleNow({ hotReload, verbose });
|
|
@@ -396,11 +385,11 @@ class AdminForth {
|
|
|
396
385
|
return { error: 'Unauthorized' };
|
|
397
386
|
}
|
|
398
387
|
username = user.data[0][this.config.auth.usernameField];
|
|
399
|
-
userFullName = user.data[0][this.config.auth.
|
|
388
|
+
userFullName = user.data[0][this.config.auth.userFullNameField];
|
|
400
389
|
}
|
|
401
390
|
const userData = {
|
|
402
391
|
[this.config.auth.usernameField]: username,
|
|
403
|
-
[this.config.auth.
|
|
392
|
+
[this.config.auth.userFullNameField]: userFullName
|
|
404
393
|
};
|
|
405
394
|
return {
|
|
406
395
|
user: userData,
|
|
@@ -417,7 +406,7 @@ class AdminForth {
|
|
|
417
406
|
usernameField: this.config.auth.usernameField,
|
|
418
407
|
},
|
|
419
408
|
adminUser,
|
|
420
|
-
version:
|
|
409
|
+
version: ADMINFORTH_VERSION,
|
|
421
410
|
};
|
|
422
411
|
}),
|
|
423
412
|
});
|
|
@@ -442,8 +431,12 @@ class AdminForth {
|
|
|
442
431
|
server.endpoint({
|
|
443
432
|
method: 'POST',
|
|
444
433
|
path: '/get_resource_data',
|
|
445
|
-
handler: (_g) => __awaiter(this, [_g], void 0, function* ({ body }) {
|
|
446
|
-
|
|
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
|
+
}
|
|
447
440
|
if (!this.statuses.dbDiscover) {
|
|
448
441
|
return { error: 'Database discovery not started' };
|
|
449
442
|
}
|
|
@@ -454,6 +447,16 @@ class AdminForth {
|
|
|
454
447
|
if (!resource) {
|
|
455
448
|
return { error: `Resource ${resourceId} not found` };
|
|
456
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;
|
|
457
460
|
const data = yield this.connectors[resource.dataSource].getData({
|
|
458
461
|
resource,
|
|
459
462
|
limit,
|
|
@@ -461,14 +464,52 @@ class AdminForth {
|
|
|
461
464
|
filters,
|
|
462
465
|
sort,
|
|
463
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
|
+
}
|
|
464
505
|
return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
|
|
465
506
|
}),
|
|
466
507
|
});
|
|
467
508
|
server.endpoint({
|
|
468
509
|
method: 'POST',
|
|
469
510
|
path: '/get_resource_foreign_data',
|
|
470
|
-
handler: (
|
|
471
|
-
var
|
|
511
|
+
handler: (_r) => __awaiter(this, [_r], void 0, function* ({ body, adminUser }) {
|
|
512
|
+
var _s, _t, _u, _v;
|
|
472
513
|
const { resourceId, column } = body;
|
|
473
514
|
if (!this.statuses.dbDiscover) {
|
|
474
515
|
return { error: 'Database discovery not started' };
|
|
@@ -486,8 +527,8 @@ class AdminForth {
|
|
|
486
527
|
}
|
|
487
528
|
const targetResourceId = columnConfig.foreignResource.resourceId;
|
|
488
529
|
const targetResource = this.config.resources.find((res) => res.resourceId == targetResourceId);
|
|
489
|
-
if ((
|
|
490
|
-
const resp = yield ((
|
|
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 }));
|
|
491
532
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
492
533
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
493
534
|
}
|
|
@@ -515,8 +556,8 @@ class AdminForth {
|
|
|
515
556
|
const response = {
|
|
516
557
|
items
|
|
517
558
|
};
|
|
518
|
-
if ((
|
|
519
|
-
const resp = yield ((
|
|
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 }));
|
|
520
561
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
521
562
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
522
563
|
}
|
|
@@ -530,7 +571,7 @@ class AdminForth {
|
|
|
530
571
|
server.endpoint({
|
|
531
572
|
method: 'POST',
|
|
532
573
|
path: '/get_min_max_for_columns',
|
|
533
|
-
handler: (
|
|
574
|
+
handler: (_w) => __awaiter(this, [_w], void 0, function* ({ body }) {
|
|
534
575
|
const { resourceId } = body;
|
|
535
576
|
if (!this.statuses.dbDiscover) {
|
|
536
577
|
return { error: 'Database discovery not started' };
|
|
@@ -556,40 +597,12 @@ class AdminForth {
|
|
|
556
597
|
return item;
|
|
557
598
|
}),
|
|
558
599
|
});
|
|
559
|
-
server.endpoint({
|
|
560
|
-
method: 'POST',
|
|
561
|
-
path: '/get_record',
|
|
562
|
-
handler: (_p) => __awaiter(this, [_p], void 0, function* ({ body, adminUser }) {
|
|
563
|
-
var _q, _r;
|
|
564
|
-
const { resourceId, primaryKey } = body;
|
|
565
|
-
const resource = this.config.resources.find((res) => res.resourceId == resourceId);
|
|
566
|
-
const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
|
|
567
|
-
const connector = this.connectors[resource.dataSource];
|
|
568
|
-
const record = yield connector.getRecordByPrimaryKey(resource, primaryKey);
|
|
569
|
-
if (!record) {
|
|
570
|
-
return { error: `Record with ${primaryKeyColumn.name} ${primaryKey} not found` };
|
|
571
|
-
}
|
|
572
|
-
// execute hook if needed
|
|
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 }));
|
|
575
|
-
if (!resp || (!resp.ok && !resp.error)) {
|
|
576
|
-
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
577
|
-
}
|
|
578
|
-
if (resp.error) {
|
|
579
|
-
return { error: resp.error };
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
const labler = resource.itemLabel || ((record) => `${resource.label} ${record[primaryKeyColumn.name]}`);
|
|
583
|
-
record._label = labler(record);
|
|
584
|
-
return record;
|
|
585
|
-
})
|
|
586
|
-
});
|
|
587
600
|
server.endpoint({
|
|
588
601
|
noAuth: true, // TODO
|
|
589
602
|
method: 'POST',
|
|
590
603
|
path: '/create_record',
|
|
591
|
-
handler: (
|
|
592
|
-
var
|
|
604
|
+
handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body, adminUser }) {
|
|
605
|
+
var _y, _z, _0, _1, _2, _3, _4, _5, _6;
|
|
593
606
|
console.log('create_record', body, this.config.resources);
|
|
594
607
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
595
608
|
if (!resource) {
|
|
@@ -597,8 +610,8 @@ class AdminForth {
|
|
|
597
610
|
}
|
|
598
611
|
const record = body['record'];
|
|
599
612
|
// execute hook if needed
|
|
600
|
-
if ((
|
|
601
|
-
const resp = yield ((
|
|
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 }));
|
|
602
615
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
603
616
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
604
617
|
}
|
|
@@ -614,7 +627,7 @@ class AdminForth {
|
|
|
614
627
|
});
|
|
615
628
|
}
|
|
616
629
|
}
|
|
617
|
-
if (((
|
|
630
|
+
if (((_2 = column.required) === null || _2 === void 0 ? void 0 : _2.create) && body['record'][column.name] === undefined) {
|
|
618
631
|
return { error: `Column '${column.name}' is required` };
|
|
619
632
|
}
|
|
620
633
|
if (column.isUnique) {
|
|
@@ -639,8 +652,8 @@ class AdminForth {
|
|
|
639
652
|
const connector = this.connectors[resource.dataSource];
|
|
640
653
|
yield connector.createRecord({ resource, record });
|
|
641
654
|
// execute hook if needed
|
|
642
|
-
if ((
|
|
643
|
-
const resp = yield ((
|
|
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 }));
|
|
644
657
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
645
658
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
646
659
|
}
|
|
@@ -657,8 +670,8 @@ class AdminForth {
|
|
|
657
670
|
noAuth: true, // TODO
|
|
658
671
|
method: 'POST',
|
|
659
672
|
path: '/update_record',
|
|
660
|
-
handler: (
|
|
661
|
-
var
|
|
673
|
+
handler: (_7) => __awaiter(this, [_7], void 0, function* ({ body, adminUser }) {
|
|
674
|
+
var _8, _9, _10, _11, _12, _13, _14, _15;
|
|
662
675
|
console.log('update_record', body);
|
|
663
676
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
664
677
|
if (!resource) {
|
|
@@ -673,8 +686,8 @@ class AdminForth {
|
|
|
673
686
|
}
|
|
674
687
|
const record = body['record'];
|
|
675
688
|
// execute hook if needed
|
|
676
|
-
if ((
|
|
677
|
-
const resp = yield ((
|
|
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 }));
|
|
678
691
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
679
692
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
680
693
|
}
|
|
@@ -692,8 +705,8 @@ class AdminForth {
|
|
|
692
705
|
yield connector.updateRecord({ resource, recordId, record, newValues });
|
|
693
706
|
}
|
|
694
707
|
// execute hook if needed
|
|
695
|
-
if ((
|
|
696
|
-
const resp = yield ((
|
|
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 }));
|
|
697
710
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
698
711
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
699
712
|
}
|
|
@@ -710,16 +723,16 @@ class AdminForth {
|
|
|
710
723
|
noAuth: true, // TODO
|
|
711
724
|
method: 'POST',
|
|
712
725
|
path: '/delete_record',
|
|
713
|
-
handler: (
|
|
714
|
-
var
|
|
726
|
+
handler: (_16) => __awaiter(this, [_16], void 0, function* ({ body, adminUser }) {
|
|
727
|
+
var _17, _18, _19, _20, _21, _22, _23, _24;
|
|
715
728
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
716
729
|
const record = yield this.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
|
|
717
730
|
if (!resource) {
|
|
718
731
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
719
732
|
}
|
|
720
733
|
// execute hook if needed
|
|
721
|
-
if ((
|
|
722
|
-
const resp = yield ((
|
|
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 }));
|
|
723
736
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
724
737
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
725
738
|
}
|
|
@@ -730,8 +743,8 @@ class AdminForth {
|
|
|
730
743
|
const connector = this.connectors[resource.dataSource];
|
|
731
744
|
yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
|
|
732
745
|
// execute hook if needed
|
|
733
|
-
if ((
|
|
734
|
-
const resp = yield ((
|
|
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 }));
|
|
735
748
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
736
749
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
737
750
|
}
|
|
@@ -748,7 +761,7 @@ class AdminForth {
|
|
|
748
761
|
noAuth: true, // TODO
|
|
749
762
|
method: 'POST',
|
|
750
763
|
path: '/start_bulk_action',
|
|
751
|
-
handler: (
|
|
764
|
+
handler: (_25) => __awaiter(this, [_25], void 0, function* ({ body }) {
|
|
752
765
|
const { resourceId, actionId, recordIds } = body;
|
|
753
766
|
const resource = this.config.resources.find((res) => res.resourceId == resourceId);
|
|
754
767
|
if (!resource) {
|
package/dist/modules/utils.js
CHANGED
|
@@ -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,11 @@ 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
|
+
console.log('📦 __filename', __dirname);
|
|
20
|
+
console.log('📦 __dirname', __dirname);
|
|
21
|
+
export const ADMIN_FORTH_ABSOLUTE_PATH = __dirname;
|
|
22
|
+
package_json = JSON.parse(fs.readFileSync(path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'package.json'), 'utf8'));
|
|
23
|
+
export const ADMINFORTH_VERSION = package_json.version;
|
package/dist/spa/spa/src/App.vue
CHANGED
|
@@ -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' }}
|
|
@@ -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
|
|
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
|
|
135
|
+
if (!props.valueStart) {
|
|
136
136
|
datepickerStartEl.value.value = '';
|
|
137
137
|
startTime.value = '';
|
|
138
138
|
}
|
|
139
|
-
if (props.valueEnd
|
|
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
|
-
|
|
80
|
+
updateStartFromProps();
|
|
81
|
+
updateEndFromProps();
|
|
88
82
|
|
|
89
|
-
watch(() =>
|
|
90
|
-
|
|
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
|
-
|
|
114
|
+
console.log('⚡ emit', start.value)
|
|
96
115
|
emit('update:valueStart', start.value)
|
|
97
116
|
})
|
|
98
117
|
|
|
99
118
|
watch(end, () => {
|
|
100
|
-
|
|
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>
|
|
@@ -78,7 +78,12 @@ const selectedItems = ref([]);
|
|
|
78
78
|
function updateFromProps() {
|
|
79
79
|
if (props.modelValue !== undefined) {
|
|
80
80
|
if (props.single) {
|
|
81
|
-
|
|
81
|
+
const el = props.options.find(item => item.value === props.modelValue);
|
|
82
|
+
if (el) {
|
|
83
|
+
selectedItems.value = [el];
|
|
84
|
+
} else {
|
|
85
|
+
selectedItems.value = [];
|
|
86
|
+
}
|
|
82
87
|
} else {
|
|
83
88
|
selectedItems.value = props.options.filter(item => props.modelValue.includes(item.value));
|
|
84
89
|
}
|