adminforth 1.0.46 → 1.0.48
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 +0 -1
- package/dist/dataConnectors/sqlite.js +0 -1
- package/dist/index.js +70 -41
- package/dist/modules/codeInjector.js +48 -11
- package/dist/spa/spa/package-lock.json +63 -0
- package/dist/spa/spa/package.json +1 -0
- package/dist/spa/spa/src/App.vue +18 -1
- package/dist/spa/spa/src/utils.ts +3 -3
- package/dist/spa/spa/src/views/CreateView.vue +6 -8
- package/dist/spa/spa/src/views/EditView.vue +16 -10
- package/dist/spa/spa/src/views/ListView.vue +7 -8
- package/dist/spa/spa/src/views/ShowView.vue +5 -9
- package/index.ts +45 -9
- package/modules/codeInjector.ts +47 -7
- package/package.json +1 -1
- package/spa/package-lock.json +63 -0
- package/spa/package.json +1 -0
- package/spa/src/App.vue +18 -1
- package/spa/src/utils.ts +3 -3
- package/spa/src/views/CreateView.vue +6 -8
- package/spa/src/views/EditView.vue +16 -10
- package/spa/src/views/ListView.vue +7 -8
- package/spa/src/views/ShowView.vue +5 -9
- package/types/AdminForthConfig.ts +4 -2
package/dataConnectors/sqlite.ts
CHANGED
|
@@ -138,7 +138,6 @@ class SQLiteConnector {
|
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
getData({ resource, limit, offset, sort, filters }) {
|
|
141
|
-
console.log('SQLITE getData', { resource, limit, offset, sort, filters });
|
|
142
141
|
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
143
142
|
const tableName = resource.table;
|
|
144
143
|
|
|
@@ -148,7 +148,6 @@ class SQLiteConnector {
|
|
|
148
148
|
return value;
|
|
149
149
|
}
|
|
150
150
|
getData({ resource, limit, offset, sort, filters }) {
|
|
151
|
-
console.log('SQLITE getData', { resource, limit, offset, sort, filters });
|
|
152
151
|
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
153
152
|
const tableName = resource.table;
|
|
154
153
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
package/dist/index.js
CHANGED
|
@@ -193,6 +193,15 @@ class AdminForth {
|
|
|
193
193
|
if (item.component && !item.path) {
|
|
194
194
|
errors.push(`Menu item with component must have path : ${JSON.stringify(item)}`);
|
|
195
195
|
}
|
|
196
|
+
if (item.type === 'resource' && !item.resourceId) {
|
|
197
|
+
errors.push(`Menu item with type 'resource' must have resourceId : ${JSON.stringify(item)}`);
|
|
198
|
+
}
|
|
199
|
+
if (item.resourceId && !this.config.resources.find((res) => res.resourceId === item.resourceId)) {
|
|
200
|
+
errors.push(`Menu item with type 'resourceId' has resourceId which is not in resources: ${JSON.stringify(item)}`);
|
|
201
|
+
}
|
|
202
|
+
if (item.type === 'component' && !item.component) {
|
|
203
|
+
errors.push(`Menu item with type 'component' must have component : ${JSON.stringify(item)}`);
|
|
204
|
+
}
|
|
196
205
|
// make sure component starts with @@
|
|
197
206
|
if (item.component) {
|
|
198
207
|
if (!item.component.startsWith('@@')) {
|
|
@@ -384,6 +393,7 @@ class AdminForth {
|
|
|
384
393
|
method: 'GET',
|
|
385
394
|
path: '/get_base_config',
|
|
386
395
|
handler: (_e) => __awaiter(this, [_e], void 0, function* ({ input, adminUser, cookies }) {
|
|
396
|
+
var _f;
|
|
387
397
|
const cookieParsed = this.auth.verify(cookies['adminforth_jwt']);
|
|
388
398
|
let username = '';
|
|
389
399
|
let userFullName = '';
|
|
@@ -424,6 +434,7 @@ class AdminForth {
|
|
|
424
434
|
deleteConfirmation: this.config.deleteConfirmation,
|
|
425
435
|
auth: this.config.auth,
|
|
426
436
|
usernameField: this.config.auth.usernameField,
|
|
437
|
+
title: (_f = this.config) === null || _f === void 0 ? void 0 : _f.title,
|
|
427
438
|
},
|
|
428
439
|
adminUser,
|
|
429
440
|
version: ADMINFORTH_VERSION,
|
|
@@ -433,7 +444,7 @@ class AdminForth {
|
|
|
433
444
|
server.endpoint({
|
|
434
445
|
method: 'POST',
|
|
435
446
|
path: '/get_resource_columns',
|
|
436
|
-
handler: (
|
|
447
|
+
handler: (_g) => __awaiter(this, [_g], void 0, function* ({ body }) {
|
|
437
448
|
const { resourceId } = body;
|
|
438
449
|
if (!this.statuses.dbDiscover) {
|
|
439
450
|
return { error: 'Database discovery not started' };
|
|
@@ -451,8 +462,8 @@ class AdminForth {
|
|
|
451
462
|
server.endpoint({
|
|
452
463
|
method: 'POST',
|
|
453
464
|
path: '/get_resource_data',
|
|
454
|
-
handler: (
|
|
455
|
-
var
|
|
465
|
+
handler: (_h) => __awaiter(this, [_h], void 0, function* ({ body, adminUser }) {
|
|
466
|
+
var _j, _k, _l, _m, _o, _p, _q, _r;
|
|
456
467
|
const { resourceId, source } = body;
|
|
457
468
|
if (['show', 'list'].includes(source) === false) {
|
|
458
469
|
return { error: 'Invalid source, should be list or show' };
|
|
@@ -467,8 +478,8 @@ class AdminForth {
|
|
|
467
478
|
if (!resource) {
|
|
468
479
|
return { error: `Resource ${resourceId} not found` };
|
|
469
480
|
}
|
|
470
|
-
if ((
|
|
471
|
-
const resp = yield ((
|
|
481
|
+
if ((_k = (_j = resource.hooks) === null || _j === void 0 ? void 0 : _j[source]) === null || _k === void 0 ? void 0 : _k.beforeDatasourceRequest) {
|
|
482
|
+
const resp = yield ((_m = (_l = resource.hooks) === null || _l === void 0 ? void 0 : _l[source]) === null || _m === void 0 ? void 0 : _m.beforeDatasourceRequest({ resource, query: body, adminUser }));
|
|
472
483
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
473
484
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
474
485
|
}
|
|
@@ -533,12 +544,19 @@ class AdminForth {
|
|
|
533
544
|
data.data.forEach((item) => {
|
|
534
545
|
item[col.name] = targetDataMap[item[col.name]];
|
|
535
546
|
});
|
|
547
|
+
data.data.forEach((item) => {
|
|
548
|
+
Object.keys(item).forEach((key) => {
|
|
549
|
+
if (!targetResource.columns.find((col) => col.name === key) || targetResource.columns.find((col) => col.name === key && col.backendOnly)) {
|
|
550
|
+
delete item[key];
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
});
|
|
536
554
|
})));
|
|
537
555
|
data.data.forEach((item) => {
|
|
538
556
|
item._label = resource.itemLabel(item);
|
|
539
557
|
});
|
|
540
|
-
if ((
|
|
541
|
-
const resp = yield ((
|
|
558
|
+
if ((_p = (_o = resource.hooks) === null || _o === void 0 ? void 0 : _o[source]) === null || _p === void 0 ? void 0 : _p.afterDatasourceRequest) {
|
|
559
|
+
const resp = yield ((_r = (_q = resource.hooks) === null || _q === void 0 ? void 0 : _q[source]) === null || _r === void 0 ? void 0 : _r.afterDatasourceRequest({ resource, response: data.data, adminUser }));
|
|
542
560
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
543
561
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
544
562
|
}
|
|
@@ -546,14 +564,22 @@ class AdminForth {
|
|
|
546
564
|
return { error: resp.error };
|
|
547
565
|
}
|
|
548
566
|
}
|
|
567
|
+
// remove all columns which are not defined in resources, or defined but backendOnly
|
|
568
|
+
data.data.forEach((item) => {
|
|
569
|
+
Object.keys(item).forEach((key) => {
|
|
570
|
+
if (!resource.columns.find((col) => col.name === key) || resource.columns.find((col) => col.name === key && col.backendOnly)) {
|
|
571
|
+
delete item[key];
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
});
|
|
549
575
|
return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
|
|
550
576
|
}),
|
|
551
577
|
});
|
|
552
578
|
server.endpoint({
|
|
553
579
|
method: 'POST',
|
|
554
580
|
path: '/get_resource_foreign_data',
|
|
555
|
-
handler: (
|
|
556
|
-
var
|
|
581
|
+
handler: (_s) => __awaiter(this, [_s], void 0, function* ({ body, adminUser }) {
|
|
582
|
+
var _t, _u, _v, _w;
|
|
557
583
|
const { resourceId, column } = body;
|
|
558
584
|
if (!this.statuses.dbDiscover) {
|
|
559
585
|
return { error: 'Database discovery not started' };
|
|
@@ -574,8 +600,8 @@ class AdminForth {
|
|
|
574
600
|
}
|
|
575
601
|
const targetResourceId = columnConfig.foreignResource.resourceId;
|
|
576
602
|
const targetResource = this.config.resources.find((res) => res.resourceId == targetResourceId);
|
|
577
|
-
if ((
|
|
578
|
-
const resp = yield ((
|
|
603
|
+
if ((_t = columnConfig.foreignResource.hooks) === null || _t === void 0 ? void 0 : _t.beforeDatasourceRequest) {
|
|
604
|
+
const resp = yield ((_u = column.foreignResource.hooks) === null || _u === void 0 ? void 0 : _u.beforeDatasourceRequest({ query: body, adminUser }));
|
|
579
605
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
580
606
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
581
607
|
}
|
|
@@ -603,8 +629,8 @@ class AdminForth {
|
|
|
603
629
|
const response = {
|
|
604
630
|
items
|
|
605
631
|
};
|
|
606
|
-
if ((
|
|
607
|
-
const resp = yield ((
|
|
632
|
+
if ((_v = columnConfig.foreignResource.hooks) === null || _v === void 0 ? void 0 : _v.afterDatasourceResponse) {
|
|
633
|
+
const resp = yield ((_w = column.foreignResource.hooks) === null || _w === void 0 ? void 0 : _w.afterDatasourceResponse({ response, adminUser }));
|
|
608
634
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
609
635
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
610
636
|
}
|
|
@@ -618,7 +644,7 @@ class AdminForth {
|
|
|
618
644
|
server.endpoint({
|
|
619
645
|
method: 'POST',
|
|
620
646
|
path: '/get_min_max_for_columns',
|
|
621
|
-
handler: (
|
|
647
|
+
handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body }) {
|
|
622
648
|
const { resourceId } = body;
|
|
623
649
|
if (!this.statuses.dbDiscover) {
|
|
624
650
|
return { error: 'Database discovery not started' };
|
|
@@ -645,11 +671,10 @@ class AdminForth {
|
|
|
645
671
|
}),
|
|
646
672
|
});
|
|
647
673
|
server.endpoint({
|
|
648
|
-
noAuth: true, // TODO
|
|
649
674
|
method: 'POST',
|
|
650
675
|
path: '/create_record',
|
|
651
|
-
handler: (
|
|
652
|
-
var
|
|
676
|
+
handler: (_y) => __awaiter(this, [_y], void 0, function* ({ body, adminUser }) {
|
|
677
|
+
var _z, _0, _1, _2, _3, _4, _5, _6, _7;
|
|
653
678
|
console.log('create_record', body, this.config.resources);
|
|
654
679
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
655
680
|
if (!resource) {
|
|
@@ -657,8 +682,8 @@ class AdminForth {
|
|
|
657
682
|
}
|
|
658
683
|
const record = body['record'];
|
|
659
684
|
// execute hook if needed
|
|
660
|
-
if ((
|
|
661
|
-
const resp = yield ((
|
|
685
|
+
if ((_0 = (_z = resource.hooks) === null || _z === void 0 ? void 0 : _z.create) === null || _0 === void 0 ? void 0 : _0.beforeSave) {
|
|
686
|
+
const resp = yield ((_2 = (_1 = resource.hooks) === null || _1 === void 0 ? void 0 : _1.create) === null || _2 === void 0 ? void 0 : _2.beforeSave({ resource, record, adminUser }));
|
|
662
687
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
663
688
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
664
689
|
}
|
|
@@ -674,7 +699,7 @@ class AdminForth {
|
|
|
674
699
|
});
|
|
675
700
|
}
|
|
676
701
|
}
|
|
677
|
-
if (((
|
|
702
|
+
if (((_3 = column.required) === null || _3 === void 0 ? void 0 : _3.create) && body['record'][column.name] === undefined) {
|
|
678
703
|
return { error: `Column '${column.name}' is required` };
|
|
679
704
|
}
|
|
680
705
|
if (column.isUnique) {
|
|
@@ -699,8 +724,8 @@ class AdminForth {
|
|
|
699
724
|
const connector = this.connectors[resource.dataSource];
|
|
700
725
|
yield connector.createRecord({ resource, record });
|
|
701
726
|
// execute hook if needed
|
|
702
|
-
if ((
|
|
703
|
-
const resp = yield ((
|
|
727
|
+
if ((_5 = (_4 = resource.hooks) === null || _4 === void 0 ? void 0 : _4.create) === null || _5 === void 0 ? void 0 : _5.afterSave) {
|
|
728
|
+
const resp = yield ((_7 = (_6 = resource.hooks) === null || _6 === void 0 ? void 0 : _6.create) === null || _7 === void 0 ? void 0 : _7.afterSave({ resource, record, adminUser }));
|
|
704
729
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
705
730
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
706
731
|
}
|
|
@@ -714,11 +739,10 @@ class AdminForth {
|
|
|
714
739
|
})
|
|
715
740
|
});
|
|
716
741
|
server.endpoint({
|
|
717
|
-
noAuth: true, // TODO
|
|
718
742
|
method: 'POST',
|
|
719
743
|
path: '/update_record',
|
|
720
|
-
handler: (
|
|
721
|
-
var
|
|
744
|
+
handler: (_8) => __awaiter(this, [_8], void 0, function* ({ body, adminUser }) {
|
|
745
|
+
var _9, _10, _11, _12, _13, _14, _15, _16;
|
|
722
746
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
723
747
|
if (!resource) {
|
|
724
748
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -732,8 +756,8 @@ class AdminForth {
|
|
|
732
756
|
}
|
|
733
757
|
const record = body['record'];
|
|
734
758
|
// execute hook if needed
|
|
735
|
-
if ((
|
|
736
|
-
const resp = yield ((
|
|
759
|
+
if ((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.edit) === null || _10 === void 0 ? void 0 : _10.beforeSave) {
|
|
760
|
+
const resp = yield ((_12 = (_11 = resource.hooks) === null || _11 === void 0 ? void 0 : _11.edit) === null || _12 === void 0 ? void 0 : _12.beforeSave({ resource, record, adminUser }));
|
|
737
761
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
738
762
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
739
763
|
}
|
|
@@ -742,17 +766,24 @@ class AdminForth {
|
|
|
742
766
|
}
|
|
743
767
|
}
|
|
744
768
|
const newValues = {};
|
|
745
|
-
for (const
|
|
746
|
-
if (record[
|
|
747
|
-
|
|
769
|
+
for (const recordField in record) {
|
|
770
|
+
if (record[recordField] !== oldRecord[recordField]) {
|
|
771
|
+
const column = resource.columns.find((col) => col.name === recordField);
|
|
772
|
+
if (column) {
|
|
773
|
+
newValues[recordField] = connector.setFieldValue(column, record[recordField]);
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
newValues[recordField] = record[recordField];
|
|
777
|
+
}
|
|
748
778
|
}
|
|
749
779
|
}
|
|
780
|
+
console.log('✅ newValues', newValues);
|
|
750
781
|
if (Object.keys(newValues).length > 0) {
|
|
751
782
|
yield connector.updateRecord({ resource, recordId, record, newValues });
|
|
752
783
|
}
|
|
753
784
|
// execute hook if needed
|
|
754
|
-
if ((
|
|
755
|
-
const resp = yield ((
|
|
785
|
+
if ((_14 = (_13 = resource.hooks) === null || _13 === void 0 ? void 0 : _13.edit) === null || _14 === void 0 ? void 0 : _14.afterSave) {
|
|
786
|
+
const resp = yield ((_16 = (_15 = resource.hooks) === null || _15 === void 0 ? void 0 : _15.edit) === null || _16 === void 0 ? void 0 : _16.afterSave({ resource, record, adminUser }));
|
|
756
787
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
757
788
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
758
789
|
}
|
|
@@ -766,19 +797,18 @@ class AdminForth {
|
|
|
766
797
|
})
|
|
767
798
|
});
|
|
768
799
|
server.endpoint({
|
|
769
|
-
noAuth: true, // TODO
|
|
770
800
|
method: 'POST',
|
|
771
801
|
path: '/delete_record',
|
|
772
|
-
handler: (
|
|
773
|
-
var
|
|
802
|
+
handler: (_17) => __awaiter(this, [_17], void 0, function* ({ body, adminUser }) {
|
|
803
|
+
var _18, _19, _20, _21, _22, _23, _24, _25;
|
|
774
804
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
775
805
|
const record = yield this.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
|
|
776
806
|
if (!resource) {
|
|
777
807
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
778
808
|
}
|
|
779
809
|
// execute hook if needed
|
|
780
|
-
if ((
|
|
781
|
-
const resp = yield ((
|
|
810
|
+
if ((_19 = (_18 = resource.hooks) === null || _18 === void 0 ? void 0 : _18.delete) === null || _19 === void 0 ? void 0 : _19.beforeSave) {
|
|
811
|
+
const resp = yield ((_21 = (_20 = resource.hooks) === null || _20 === void 0 ? void 0 : _20.delete) === null || _21 === void 0 ? void 0 : _21.beforeSave({ resource, record, adminUser }));
|
|
782
812
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
783
813
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
784
814
|
}
|
|
@@ -789,8 +819,8 @@ class AdminForth {
|
|
|
789
819
|
const connector = this.connectors[resource.dataSource];
|
|
790
820
|
yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
|
|
791
821
|
// execute hook if needed
|
|
792
|
-
if ((
|
|
793
|
-
const resp = yield ((
|
|
822
|
+
if ((_23 = (_22 = resource.hooks) === null || _22 === void 0 ? void 0 : _22.delete) === null || _23 === void 0 ? void 0 : _23.afterSave) {
|
|
823
|
+
const resp = yield ((_25 = (_24 = resource.hooks) === null || _24 === void 0 ? void 0 : _24.delete) === null || _25 === void 0 ? void 0 : _25.afterSave({ resource, record, adminUser }));
|
|
794
824
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
795
825
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
796
826
|
}
|
|
@@ -804,10 +834,9 @@ class AdminForth {
|
|
|
804
834
|
})
|
|
805
835
|
});
|
|
806
836
|
server.endpoint({
|
|
807
|
-
noAuth: true, // TODO
|
|
808
837
|
method: 'POST',
|
|
809
838
|
path: '/start_bulk_action',
|
|
810
|
-
handler: (
|
|
839
|
+
handler: (_26) => __awaiter(this, [_26], void 0, function* ({ body }) {
|
|
811
840
|
const { resourceId, actionId, recordIds } = body;
|
|
812
841
|
const resource = this.config.resources.find((res) => res.resourceId == resourceId);
|
|
813
842
|
if (!resource) {
|
|
@@ -7,14 +7,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import fs from 'fs';
|
|
11
|
-
import fsExtra from 'fs-extra';
|
|
12
|
-
import filewatcher from 'filewatcher';
|
|
13
10
|
import { exec, spawn } from 'child_process';
|
|
14
|
-
import { promisify } from 'util';
|
|
15
|
-
import path from 'path';
|
|
16
11
|
import crypto from 'crypto';
|
|
12
|
+
import filewatcher from 'filewatcher';
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import fsExtra from 'fs-extra';
|
|
17
15
|
import os from 'os';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { promisify } from 'util';
|
|
18
18
|
import { ADMIN_FORTH_ABSOLUTE_PATH } from './utils.js';
|
|
19
19
|
let TMP_DIR;
|
|
20
20
|
try {
|
|
@@ -71,7 +71,7 @@ class CodeInjector {
|
|
|
71
71
|
}
|
|
72
72
|
prepareSources(_a) {
|
|
73
73
|
return __awaiter(this, arguments, void 0, function* ({ filesUpdated, verbose = false }) {
|
|
74
|
-
var _b, _c, _d, _e, _f, _g;
|
|
74
|
+
var _b, _c, _d, _e, _f, _g, _h;
|
|
75
75
|
// check SPA_TMP_PATH exists and create if not
|
|
76
76
|
try {
|
|
77
77
|
yield fs.promises.access(CodeInjector.SPA_TMP_PATH, fs.constants.F_OK);
|
|
@@ -154,6 +154,25 @@ class CodeInjector {
|
|
|
154
154
|
}).join('');
|
|
155
155
|
return `import { ${PascalIconName} } from '@iconify-prerendered/vue-${collection}';`;
|
|
156
156
|
}).join('\n');
|
|
157
|
+
// for each custom component generate import statement
|
|
158
|
+
const customComponentsDir = (_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.customComponentsDir;
|
|
159
|
+
let customComponentsImports = '';
|
|
160
|
+
if (customComponentsDir) {
|
|
161
|
+
// if file - return, if dir - go recursively
|
|
162
|
+
const customComponents = yield fs.promises.readdir(customComponentsDir);
|
|
163
|
+
for (const filePath of customComponents) {
|
|
164
|
+
fs.stat(`${customComponentsDir}/${filePath}`, (err, data) => {
|
|
165
|
+
if (err) {
|
|
166
|
+
console.log(err);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (data.isFile()) {
|
|
170
|
+
const componentName = filePath.split('.')[0].replace('/', '');
|
|
171
|
+
customComponentsImports += `import ${componentName} from '@/custom/${filePath}';\n`;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
157
176
|
// Generate Vue.component statements for each icon
|
|
158
177
|
const iconComponents = uniqueIcons.map((icon) => {
|
|
159
178
|
const [collection, iconName] = icon.split(':');
|
|
@@ -162,26 +181,44 @@ class CodeInjector {
|
|
|
162
181
|
}).join('');
|
|
163
182
|
return `app.component('${PascalIconName}', ${PascalIconName});`;
|
|
164
183
|
}).join('\n');
|
|
184
|
+
// Generate Vue.component statements for each custom component
|
|
185
|
+
let customComponentsComponents = '';
|
|
186
|
+
if (customComponentsDir) {
|
|
187
|
+
const customComponents = yield fs.promises.readdir(customComponentsDir);
|
|
188
|
+
for (const filePath of customComponents) {
|
|
189
|
+
fs.stat(`${customComponentsDir}/${filePath}`, (err, data) => {
|
|
190
|
+
if (err) {
|
|
191
|
+
console.log('Custom components importing error: ', err);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (data.isFile()) {
|
|
195
|
+
const componentName = filePath.split('.')[0].replace('/', '');
|
|
196
|
+
customComponentsComponents += `app.component('${componentName}', ${componentName});\n`;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
165
201
|
let imports = iconImports + '\n';
|
|
166
|
-
|
|
202
|
+
imports += customComponentsImports + '\n';
|
|
203
|
+
if ((_d = this.adminforth.config.customization) === null || _d === void 0 ? void 0 : _d.vueUsesFile) {
|
|
167
204
|
imports += `import addCustomUses from '${this.adminforth.config.customization.vueUsesFile}';\n`;
|
|
168
205
|
}
|
|
169
206
|
// inject that code into spa_tmp/src/App.vue
|
|
170
207
|
const appVuePath = path.join(CodeInjector.SPA_TMP_PATH, 'src', 'main.ts');
|
|
171
208
|
let appVueContent = yield fs.promises.readFile(appVuePath, 'utf-8');
|
|
172
209
|
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH IMPORTS */', imports);
|
|
173
|
-
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH COMPONENT REGISTRATIONS */', iconComponents + '\n');
|
|
174
|
-
if ((
|
|
210
|
+
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH COMPONENT REGISTRATIONS */', iconComponents + '\n' + customComponentsComponents + '\n');
|
|
211
|
+
if ((_e = this.adminforth.config.customization) === null || _e === void 0 ? void 0 : _e.vueUsesFile) {
|
|
175
212
|
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH CUSTOM USES */', 'addCustomUses(app);');
|
|
176
213
|
}
|
|
177
214
|
yield fs.promises.writeFile(appVuePath, appVueContent);
|
|
178
215
|
/* generate custom rotes */
|
|
179
216
|
const homepageMenuItem = this.adminforth.config.menu.find((mi) => mi.homepage);
|
|
180
217
|
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)); });
|
|
181
|
-
let childrenHomepage = (
|
|
218
|
+
let childrenHomepage = (_f = childrenHomePageMenuItem === null || childrenHomePageMenuItem === void 0 ? void 0 : childrenHomePageMenuItem.children) === null || _f === void 0 ? void 0 : _f.find((mi) => mi.homepage);
|
|
182
219
|
let homePagePath = (homepageMenuItem === null || homepageMenuItem === void 0 ? void 0 : homepageMenuItem.path) || `/resource/${childrenHomepage === null || childrenHomepage === void 0 ? void 0 : childrenHomepage.resourceId}`;
|
|
183
220
|
if (!homePagePath) {
|
|
184
|
-
homePagePath = ((
|
|
221
|
+
homePagePath = ((_g = this.adminforth.config.menu.filter((mi) => mi.path)[0]) === null || _g === void 0 ? void 0 : _g.path) || `/resource/${(_h = this.adminforth.config.menu.filter((mi) => mi.children)[0]) === null || _h === void 0 ? void 0 : _h.resourceId}`;
|
|
185
222
|
}
|
|
186
223
|
routes += `{
|
|
187
224
|
path: '/',
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"flowbite": "^2.3.0",
|
|
16
16
|
"flowbite-datepicker": "^1.2.6",
|
|
17
17
|
"pinia": "^2.1.7",
|
|
18
|
+
"unhead": "^1.9.12",
|
|
18
19
|
"vue": "^3.4.21",
|
|
19
20
|
"vue-router": "^4.3.0",
|
|
20
21
|
"vue-slider-component": "^4.1.0-beta.7"
|
|
@@ -1149,6 +1150,41 @@
|
|
|
1149
1150
|
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
|
1150
1151
|
"dev": true
|
|
1151
1152
|
},
|
|
1153
|
+
"node_modules/@unhead/dom": {
|
|
1154
|
+
"version": "1.9.12",
|
|
1155
|
+
"resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.9.12.tgz",
|
|
1156
|
+
"integrity": "sha512-3MY1TbZmEjGNZapi3wvJW0vWNS2CLKHt7/m57sScDHCNvNBe1mTwrIOhtZFDgAndhml2EVQ68RMa0Vhum/M+cw==",
|
|
1157
|
+
"dependencies": {
|
|
1158
|
+
"@unhead/schema": "1.9.12",
|
|
1159
|
+
"@unhead/shared": "1.9.12"
|
|
1160
|
+
},
|
|
1161
|
+
"funding": {
|
|
1162
|
+
"url": "https://github.com/sponsors/harlan-zw"
|
|
1163
|
+
}
|
|
1164
|
+
},
|
|
1165
|
+
"node_modules/@unhead/schema": {
|
|
1166
|
+
"version": "1.9.12",
|
|
1167
|
+
"resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.9.12.tgz",
|
|
1168
|
+
"integrity": "sha512-ue2FKyIZKsuZDpWJBMlBGwMm4s+vFeU3NUWsNt8Z+2JkOUIqO/VG43LxNgY1M595bOS71Gdxk+G9VtzfKJ5uEA==",
|
|
1169
|
+
"dependencies": {
|
|
1170
|
+
"hookable": "^5.5.3",
|
|
1171
|
+
"zhead": "^2.2.4"
|
|
1172
|
+
},
|
|
1173
|
+
"funding": {
|
|
1174
|
+
"url": "https://github.com/sponsors/harlan-zw"
|
|
1175
|
+
}
|
|
1176
|
+
},
|
|
1177
|
+
"node_modules/@unhead/shared": {
|
|
1178
|
+
"version": "1.9.12",
|
|
1179
|
+
"resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.9.12.tgz",
|
|
1180
|
+
"integrity": "sha512-72wlLXG3FP3sXUrwd42Uv8jYpHSg4R6IFJcsl+QisRjKM89JnjOFSw1DqWO4IOftW5xOxS4J5v7SQyJ4NJo7Bw==",
|
|
1181
|
+
"dependencies": {
|
|
1182
|
+
"@unhead/schema": "1.9.12"
|
|
1183
|
+
},
|
|
1184
|
+
"funding": {
|
|
1185
|
+
"url": "https://github.com/sponsors/harlan-zw"
|
|
1186
|
+
}
|
|
1187
|
+
},
|
|
1152
1188
|
"node_modules/@vitejs/plugin-vue": {
|
|
1153
1189
|
"version": "5.0.4",
|
|
1154
1190
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
|
|
@@ -2471,6 +2507,11 @@
|
|
|
2471
2507
|
"he": "bin/he"
|
|
2472
2508
|
}
|
|
2473
2509
|
},
|
|
2510
|
+
"node_modules/hookable": {
|
|
2511
|
+
"version": "5.5.3",
|
|
2512
|
+
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
|
2513
|
+
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
|
|
2514
|
+
},
|
|
2474
2515
|
"node_modules/ignore": {
|
|
2475
2516
|
"version": "5.3.1",
|
|
2476
2517
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
|
@@ -3914,6 +3955,20 @@
|
|
|
3914
3955
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
|
3915
3956
|
"dev": true
|
|
3916
3957
|
},
|
|
3958
|
+
"node_modules/unhead": {
|
|
3959
|
+
"version": "1.9.12",
|
|
3960
|
+
"resolved": "https://registry.npmjs.org/unhead/-/unhead-1.9.12.tgz",
|
|
3961
|
+
"integrity": "sha512-s6VxcTV45hy8c/IioKQOonFnAO+kBOSpgDfqEHhnU0YVSQYaRPEp9pzW1qSPf0lx+bg9RKeOQyNNbSGGUP26aQ==",
|
|
3962
|
+
"dependencies": {
|
|
3963
|
+
"@unhead/dom": "1.9.12",
|
|
3964
|
+
"@unhead/schema": "1.9.12",
|
|
3965
|
+
"@unhead/shared": "1.9.12",
|
|
3966
|
+
"hookable": "^5.5.3"
|
|
3967
|
+
},
|
|
3968
|
+
"funding": {
|
|
3969
|
+
"url": "https://github.com/sponsors/harlan-zw"
|
|
3970
|
+
}
|
|
3971
|
+
},
|
|
3917
3972
|
"node_modules/update-browserslist-db": {
|
|
3918
3973
|
"version": "1.0.16",
|
|
3919
3974
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
|
|
@@ -4260,6 +4315,14 @@
|
|
|
4260
4315
|
"funding": {
|
|
4261
4316
|
"url": "https://github.com/sponsors/sindresorhus"
|
|
4262
4317
|
}
|
|
4318
|
+
},
|
|
4319
|
+
"node_modules/zhead": {
|
|
4320
|
+
"version": "2.2.4",
|
|
4321
|
+
"resolved": "https://registry.npmjs.org/zhead/-/zhead-2.2.4.tgz",
|
|
4322
|
+
"integrity": "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==",
|
|
4323
|
+
"funding": {
|
|
4324
|
+
"url": "https://github.com/sponsors/harlan-zw"
|
|
4325
|
+
}
|
|
4263
4326
|
}
|
|
4264
4327
|
}
|
|
4265
4328
|
}
|
package/dist/spa/spa/src/App.vue
CHANGED
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
</div>
|
|
65
65
|
</nav>
|
|
66
66
|
|
|
67
|
+
|
|
67
68
|
<aside
|
|
68
69
|
v-if="loggedIn"
|
|
69
70
|
|
|
@@ -132,10 +133,22 @@ import AcceptModal from './components/AcceptModal.vue';
|
|
|
132
133
|
import MenuLink from './components/MenuLink.vue';
|
|
133
134
|
import { useRoute, useRouter } from 'vue-router';
|
|
134
135
|
import { getIcon } from '@/utils';
|
|
136
|
+
import { useHead } from 'unhead'
|
|
137
|
+
import { createHead } from 'unhead'
|
|
138
|
+
const coreStore = useCoreStore();
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
createHead()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
135
146
|
|
|
136
147
|
|
|
137
148
|
const route = useRoute();
|
|
138
149
|
const router = useRouter();
|
|
150
|
+
const title = ref('');
|
|
151
|
+
|
|
139
152
|
|
|
140
153
|
const routerIsReady = ref(false);
|
|
141
154
|
|
|
@@ -153,7 +166,6 @@ async function logout() {
|
|
|
153
166
|
router.push({ name: 'login' });
|
|
154
167
|
}
|
|
155
168
|
|
|
156
|
-
const coreStore = useCoreStore();
|
|
157
169
|
|
|
158
170
|
|
|
159
171
|
|
|
@@ -167,6 +179,11 @@ onMounted(async () => {
|
|
|
167
179
|
initRouter();
|
|
168
180
|
initFlowbite();
|
|
169
181
|
await coreStore.fetchMenuAndResource();
|
|
182
|
+
title.value = coreStore.config.title || 'Admin Forth';
|
|
183
|
+
useHead({
|
|
184
|
+
title: title.value,
|
|
185
|
+
|
|
186
|
+
})
|
|
170
187
|
})
|
|
171
188
|
|
|
172
189
|
</script>
|
|
@@ -29,9 +29,9 @@ export async function callAdminForthApi({ path, method, body=undefined }) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
export function getCustomComponent(name) {
|
|
33
|
+
return resolveComponent(name);
|
|
34
|
+
}
|
|
35
35
|
|
|
36
36
|
export function getIcon(icon: string) {
|
|
37
37
|
// icon format is "feather:icon-name". We need to get IconName in pascal case
|
|
@@ -45,9 +45,9 @@ import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
|
45
45
|
import ResourceForm from '@/components/ResourceForm.vue';
|
|
46
46
|
import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
47
47
|
import { useCoreStore } from '@/stores/core';
|
|
48
|
-
import { callAdminForthApi } from '@/utils';
|
|
48
|
+
import { callAdminForthApi, getCustomComponent } from '@/utils';
|
|
49
49
|
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
|
|
50
|
-
import {
|
|
50
|
+
import { onMounted, ref } from 'vue';
|
|
51
51
|
import { useRoute, useRouter } from 'vue-router';
|
|
52
52
|
|
|
53
53
|
const isValid = ref(false);
|
|
@@ -75,12 +75,10 @@ onMounted(async () => {
|
|
|
75
75
|
resourceId: route.params.resourceId
|
|
76
76
|
});
|
|
77
77
|
createComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
acc
|
|
82
|
-
}
|
|
83
|
-
return acc;
|
|
78
|
+
if (column.component?.show) {
|
|
79
|
+
acc[column.name] = getCustomComponent(column.component.create.replace('@@', '').replace('./custom/', '')).split('.')[0];
|
|
80
|
+
}
|
|
81
|
+
return acc;
|
|
84
82
|
}, {});
|
|
85
83
|
loading.value = false;
|
|
86
84
|
});
|