adminforth 1.0.45 → 1.0.47
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/dist/index.js +36 -34
- package/dist/spa/spa/package-lock.json +63 -0
- package/dist/spa/spa/package.json +1 -0
- package/dist/spa/spa/src/App.vue +22 -2
- package/index.ts +1 -0
- package/package.json +1 -1
- package/spa/package-lock.json +63 -0
- package/spa/package.json +1 -0
- package/spa/src/App.vue +22 -2
- package/types/AdminForthConfig.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -384,6 +384,7 @@ class AdminForth {
|
|
|
384
384
|
method: 'GET',
|
|
385
385
|
path: '/get_base_config',
|
|
386
386
|
handler: (_e) => __awaiter(this, [_e], void 0, function* ({ input, adminUser, cookies }) {
|
|
387
|
+
var _f;
|
|
387
388
|
const cookieParsed = this.auth.verify(cookies['adminforth_jwt']);
|
|
388
389
|
let username = '';
|
|
389
390
|
let userFullName = '';
|
|
@@ -424,6 +425,7 @@ class AdminForth {
|
|
|
424
425
|
deleteConfirmation: this.config.deleteConfirmation,
|
|
425
426
|
auth: this.config.auth,
|
|
426
427
|
usernameField: this.config.auth.usernameField,
|
|
428
|
+
title: (_f = this.config) === null || _f === void 0 ? void 0 : _f.title,
|
|
427
429
|
},
|
|
428
430
|
adminUser,
|
|
429
431
|
version: ADMINFORTH_VERSION,
|
|
@@ -433,7 +435,7 @@ class AdminForth {
|
|
|
433
435
|
server.endpoint({
|
|
434
436
|
method: 'POST',
|
|
435
437
|
path: '/get_resource_columns',
|
|
436
|
-
handler: (
|
|
438
|
+
handler: (_g) => __awaiter(this, [_g], void 0, function* ({ body }) {
|
|
437
439
|
const { resourceId } = body;
|
|
438
440
|
if (!this.statuses.dbDiscover) {
|
|
439
441
|
return { error: 'Database discovery not started' };
|
|
@@ -451,8 +453,8 @@ class AdminForth {
|
|
|
451
453
|
server.endpoint({
|
|
452
454
|
method: 'POST',
|
|
453
455
|
path: '/get_resource_data',
|
|
454
|
-
handler: (
|
|
455
|
-
var
|
|
456
|
+
handler: (_h) => __awaiter(this, [_h], void 0, function* ({ body, adminUser }) {
|
|
457
|
+
var _j, _k, _l, _m, _o, _p, _q, _r;
|
|
456
458
|
const { resourceId, source } = body;
|
|
457
459
|
if (['show', 'list'].includes(source) === false) {
|
|
458
460
|
return { error: 'Invalid source, should be list or show' };
|
|
@@ -467,8 +469,8 @@ class AdminForth {
|
|
|
467
469
|
if (!resource) {
|
|
468
470
|
return { error: `Resource ${resourceId} not found` };
|
|
469
471
|
}
|
|
470
|
-
if ((
|
|
471
|
-
const resp = yield ((
|
|
472
|
+
if ((_k = (_j = resource.hooks) === null || _j === void 0 ? void 0 : _j[source]) === null || _k === void 0 ? void 0 : _k.beforeDatasourceRequest) {
|
|
473
|
+
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
474
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
473
475
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
474
476
|
}
|
|
@@ -537,8 +539,8 @@ class AdminForth {
|
|
|
537
539
|
data.data.forEach((item) => {
|
|
538
540
|
item._label = resource.itemLabel(item);
|
|
539
541
|
});
|
|
540
|
-
if ((
|
|
541
|
-
const resp = yield ((
|
|
542
|
+
if ((_p = (_o = resource.hooks) === null || _o === void 0 ? void 0 : _o[source]) === null || _p === void 0 ? void 0 : _p.afterDatasourceRequest) {
|
|
543
|
+
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
544
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
543
545
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
544
546
|
}
|
|
@@ -552,8 +554,8 @@ class AdminForth {
|
|
|
552
554
|
server.endpoint({
|
|
553
555
|
method: 'POST',
|
|
554
556
|
path: '/get_resource_foreign_data',
|
|
555
|
-
handler: (
|
|
556
|
-
var
|
|
557
|
+
handler: (_s) => __awaiter(this, [_s], void 0, function* ({ body, adminUser }) {
|
|
558
|
+
var _t, _u, _v, _w;
|
|
557
559
|
const { resourceId, column } = body;
|
|
558
560
|
if (!this.statuses.dbDiscover) {
|
|
559
561
|
return { error: 'Database discovery not started' };
|
|
@@ -574,8 +576,8 @@ class AdminForth {
|
|
|
574
576
|
}
|
|
575
577
|
const targetResourceId = columnConfig.foreignResource.resourceId;
|
|
576
578
|
const targetResource = this.config.resources.find((res) => res.resourceId == targetResourceId);
|
|
577
|
-
if ((
|
|
578
|
-
const resp = yield ((
|
|
579
|
+
if ((_t = columnConfig.foreignResource.hooks) === null || _t === void 0 ? void 0 : _t.beforeDatasourceRequest) {
|
|
580
|
+
const resp = yield ((_u = column.foreignResource.hooks) === null || _u === void 0 ? void 0 : _u.beforeDatasourceRequest({ query: body, adminUser }));
|
|
579
581
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
580
582
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
581
583
|
}
|
|
@@ -603,8 +605,8 @@ class AdminForth {
|
|
|
603
605
|
const response = {
|
|
604
606
|
items
|
|
605
607
|
};
|
|
606
|
-
if ((
|
|
607
|
-
const resp = yield ((
|
|
608
|
+
if ((_v = columnConfig.foreignResource.hooks) === null || _v === void 0 ? void 0 : _v.afterDatasourceResponse) {
|
|
609
|
+
const resp = yield ((_w = column.foreignResource.hooks) === null || _w === void 0 ? void 0 : _w.afterDatasourceResponse({ response, adminUser }));
|
|
608
610
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
609
611
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
610
612
|
}
|
|
@@ -618,7 +620,7 @@ class AdminForth {
|
|
|
618
620
|
server.endpoint({
|
|
619
621
|
method: 'POST',
|
|
620
622
|
path: '/get_min_max_for_columns',
|
|
621
|
-
handler: (
|
|
623
|
+
handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body }) {
|
|
622
624
|
const { resourceId } = body;
|
|
623
625
|
if (!this.statuses.dbDiscover) {
|
|
624
626
|
return { error: 'Database discovery not started' };
|
|
@@ -648,8 +650,8 @@ class AdminForth {
|
|
|
648
650
|
noAuth: true, // TODO
|
|
649
651
|
method: 'POST',
|
|
650
652
|
path: '/create_record',
|
|
651
|
-
handler: (
|
|
652
|
-
var
|
|
653
|
+
handler: (_y) => __awaiter(this, [_y], void 0, function* ({ body, adminUser }) {
|
|
654
|
+
var _z, _0, _1, _2, _3, _4, _5, _6, _7;
|
|
653
655
|
console.log('create_record', body, this.config.resources);
|
|
654
656
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
655
657
|
if (!resource) {
|
|
@@ -657,8 +659,8 @@ class AdminForth {
|
|
|
657
659
|
}
|
|
658
660
|
const record = body['record'];
|
|
659
661
|
// execute hook if needed
|
|
660
|
-
if ((
|
|
661
|
-
const resp = yield ((
|
|
662
|
+
if ((_0 = (_z = resource.hooks) === null || _z === void 0 ? void 0 : _z.create) === null || _0 === void 0 ? void 0 : _0.beforeSave) {
|
|
663
|
+
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
664
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
663
665
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
664
666
|
}
|
|
@@ -674,7 +676,7 @@ class AdminForth {
|
|
|
674
676
|
});
|
|
675
677
|
}
|
|
676
678
|
}
|
|
677
|
-
if (((
|
|
679
|
+
if (((_3 = column.required) === null || _3 === void 0 ? void 0 : _3.create) && body['record'][column.name] === undefined) {
|
|
678
680
|
return { error: `Column '${column.name}' is required` };
|
|
679
681
|
}
|
|
680
682
|
if (column.isUnique) {
|
|
@@ -699,8 +701,8 @@ class AdminForth {
|
|
|
699
701
|
const connector = this.connectors[resource.dataSource];
|
|
700
702
|
yield connector.createRecord({ resource, record });
|
|
701
703
|
// execute hook if needed
|
|
702
|
-
if ((
|
|
703
|
-
const resp = yield ((
|
|
704
|
+
if ((_5 = (_4 = resource.hooks) === null || _4 === void 0 ? void 0 : _4.create) === null || _5 === void 0 ? void 0 : _5.afterSave) {
|
|
705
|
+
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
706
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
705
707
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
706
708
|
}
|
|
@@ -717,8 +719,8 @@ class AdminForth {
|
|
|
717
719
|
noAuth: true, // TODO
|
|
718
720
|
method: 'POST',
|
|
719
721
|
path: '/update_record',
|
|
720
|
-
handler: (
|
|
721
|
-
var
|
|
722
|
+
handler: (_8) => __awaiter(this, [_8], void 0, function* ({ body, adminUser }) {
|
|
723
|
+
var _9, _10, _11, _12, _13, _14, _15, _16;
|
|
722
724
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
723
725
|
if (!resource) {
|
|
724
726
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -732,8 +734,8 @@ class AdminForth {
|
|
|
732
734
|
}
|
|
733
735
|
const record = body['record'];
|
|
734
736
|
// execute hook if needed
|
|
735
|
-
if ((
|
|
736
|
-
const resp = yield ((
|
|
737
|
+
if ((_10 = (_9 = resource.hooks) === null || _9 === void 0 ? void 0 : _9.edit) === null || _10 === void 0 ? void 0 : _10.beforeSave) {
|
|
738
|
+
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
739
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
738
740
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
739
741
|
}
|
|
@@ -751,8 +753,8 @@ class AdminForth {
|
|
|
751
753
|
yield connector.updateRecord({ resource, recordId, record, newValues });
|
|
752
754
|
}
|
|
753
755
|
// execute hook if needed
|
|
754
|
-
if ((
|
|
755
|
-
const resp = yield ((
|
|
756
|
+
if ((_14 = (_13 = resource.hooks) === null || _13 === void 0 ? void 0 : _13.edit) === null || _14 === void 0 ? void 0 : _14.afterSave) {
|
|
757
|
+
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
758
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
757
759
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
758
760
|
}
|
|
@@ -769,16 +771,16 @@ class AdminForth {
|
|
|
769
771
|
noAuth: true, // TODO
|
|
770
772
|
method: 'POST',
|
|
771
773
|
path: '/delete_record',
|
|
772
|
-
handler: (
|
|
773
|
-
var
|
|
774
|
+
handler: (_17) => __awaiter(this, [_17], void 0, function* ({ body, adminUser }) {
|
|
775
|
+
var _18, _19, _20, _21, _22, _23, _24, _25;
|
|
774
776
|
const resource = this.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
775
777
|
const record = yield this.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
|
|
776
778
|
if (!resource) {
|
|
777
779
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
778
780
|
}
|
|
779
781
|
// execute hook if needed
|
|
780
|
-
if ((
|
|
781
|
-
const resp = yield ((
|
|
782
|
+
if ((_19 = (_18 = resource.hooks) === null || _18 === void 0 ? void 0 : _18.delete) === null || _19 === void 0 ? void 0 : _19.beforeSave) {
|
|
783
|
+
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
784
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
783
785
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
784
786
|
}
|
|
@@ -789,8 +791,8 @@ class AdminForth {
|
|
|
789
791
|
const connector = this.connectors[resource.dataSource];
|
|
790
792
|
yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
|
|
791
793
|
// execute hook if needed
|
|
792
|
-
if ((
|
|
793
|
-
const resp = yield ((
|
|
794
|
+
if ((_23 = (_22 = resource.hooks) === null || _22 === void 0 ? void 0 : _22.delete) === null || _23 === void 0 ? void 0 : _23.afterSave) {
|
|
795
|
+
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
796
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
795
797
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
796
798
|
}
|
|
@@ -807,7 +809,7 @@ class AdminForth {
|
|
|
807
809
|
noAuth: true, // TODO
|
|
808
810
|
method: 'POST',
|
|
809
811
|
path: '/start_bulk_action',
|
|
810
|
-
handler: (
|
|
812
|
+
handler: (_26) => __awaiter(this, [_26], void 0, function* ({ body }) {
|
|
811
813
|
const { resourceId, actionId, recordIds } = body;
|
|
812
814
|
const resource = this.config.resources.find((res) => res.resourceId == resourceId);
|
|
813
815
|
if (!resource) {
|
|
@@ -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
|
|
|
@@ -73,6 +74,9 @@
|
|
|
73
74
|
<template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
|
|
74
75
|
<div v-if="item.type === 'divider'" class="border-t border-gray-200 dark:border-gray-700"></div>
|
|
75
76
|
<div v-else-if="item.type === 'gap'" class="flex items-center justify-center h-8"></div>
|
|
77
|
+
<div v-else-if="item.type === 'heading'" class="flex items-center justify-left pl-2 h-8 opacity-40
|
|
78
|
+
">{{ item.label }}</div>
|
|
79
|
+
|
|
76
80
|
|
|
77
81
|
<li v-else-if="item.children">
|
|
78
82
|
<button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
|
@@ -87,7 +91,7 @@
|
|
|
87
91
|
</svg>
|
|
88
92
|
</button>
|
|
89
93
|
|
|
90
|
-
<ul :id="`dropdown-example${i}`" role="none" class="
|
|
94
|
+
<ul :id="`dropdown-example${i}`" role="none" class="pt-1 space-y-1" :class="{ 'hidden': !item.open }">
|
|
91
95
|
<template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
|
|
92
96
|
<li>
|
|
93
97
|
<MenuLink :item="child" isChild="true" />
|
|
@@ -129,10 +133,22 @@ import AcceptModal from './components/AcceptModal.vue';
|
|
|
129
133
|
import MenuLink from './components/MenuLink.vue';
|
|
130
134
|
import { useRoute, useRouter } from 'vue-router';
|
|
131
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
|
+
|
|
132
146
|
|
|
133
147
|
|
|
134
148
|
const route = useRoute();
|
|
135
149
|
const router = useRouter();
|
|
150
|
+
const title = ref('');
|
|
151
|
+
|
|
136
152
|
|
|
137
153
|
const routerIsReady = ref(false);
|
|
138
154
|
|
|
@@ -150,7 +166,6 @@ async function logout() {
|
|
|
150
166
|
router.push({ name: 'login' });
|
|
151
167
|
}
|
|
152
168
|
|
|
153
|
-
const coreStore = useCoreStore();
|
|
154
169
|
|
|
155
170
|
|
|
156
171
|
|
|
@@ -164,6 +179,11 @@ onMounted(async () => {
|
|
|
164
179
|
initRouter();
|
|
165
180
|
initFlowbite();
|
|
166
181
|
await coreStore.fetchMenuAndResource();
|
|
182
|
+
title.value = coreStore.config.title || 'Admin Forth';
|
|
183
|
+
useHead({
|
|
184
|
+
title: title.value,
|
|
185
|
+
|
|
186
|
+
})
|
|
167
187
|
})
|
|
168
188
|
|
|
169
189
|
</script>
|
package/index.ts
CHANGED
package/package.json
CHANGED
package/spa/package-lock.json
CHANGED
|
@@ -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/spa/package.json
CHANGED
package/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
|
|
|
@@ -73,6 +74,9 @@
|
|
|
73
74
|
<template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
|
|
74
75
|
<div v-if="item.type === 'divider'" class="border-t border-gray-200 dark:border-gray-700"></div>
|
|
75
76
|
<div v-else-if="item.type === 'gap'" class="flex items-center justify-center h-8"></div>
|
|
77
|
+
<div v-else-if="item.type === 'heading'" class="flex items-center justify-left pl-2 h-8 opacity-40
|
|
78
|
+
">{{ item.label }}</div>
|
|
79
|
+
|
|
76
80
|
|
|
77
81
|
<li v-else-if="item.children">
|
|
78
82
|
<button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
|
@@ -87,7 +91,7 @@
|
|
|
87
91
|
</svg>
|
|
88
92
|
</button>
|
|
89
93
|
|
|
90
|
-
<ul :id="`dropdown-example${i}`" role="none" class="
|
|
94
|
+
<ul :id="`dropdown-example${i}`" role="none" class="pt-1 space-y-1" :class="{ 'hidden': !item.open }">
|
|
91
95
|
<template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
|
|
92
96
|
<li>
|
|
93
97
|
<MenuLink :item="child" isChild="true" />
|
|
@@ -129,10 +133,22 @@ import AcceptModal from './components/AcceptModal.vue';
|
|
|
129
133
|
import MenuLink from './components/MenuLink.vue';
|
|
130
134
|
import { useRoute, useRouter } from 'vue-router';
|
|
131
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
|
+
|
|
132
146
|
|
|
133
147
|
|
|
134
148
|
const route = useRoute();
|
|
135
149
|
const router = useRouter();
|
|
150
|
+
const title = ref('');
|
|
151
|
+
|
|
136
152
|
|
|
137
153
|
const routerIsReady = ref(false);
|
|
138
154
|
|
|
@@ -150,7 +166,6 @@ async function logout() {
|
|
|
150
166
|
router.push({ name: 'login' });
|
|
151
167
|
}
|
|
152
168
|
|
|
153
|
-
const coreStore = useCoreStore();
|
|
154
169
|
|
|
155
170
|
|
|
156
171
|
|
|
@@ -164,6 +179,11 @@ onMounted(async () => {
|
|
|
164
179
|
initRouter();
|
|
165
180
|
initFlowbite();
|
|
166
181
|
await coreStore.fetchMenuAndResource();
|
|
182
|
+
title.value = coreStore.config.title || 'Admin Forth';
|
|
183
|
+
useHead({
|
|
184
|
+
title: title.value,
|
|
185
|
+
|
|
186
|
+
})
|
|
167
187
|
})
|
|
168
188
|
|
|
169
189
|
</script>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
export type AdminForthConfigMenuItem = {
|
|
4
|
+
type: 'heading' | 'group' | 'resource' | 'page' | undefined,
|
|
4
5
|
label: string,
|
|
5
6
|
icon?: string,
|
|
6
7
|
path?: string,
|
|
@@ -107,6 +108,7 @@ export type AdminForthConfig = {
|
|
|
107
108
|
brandName?: string,
|
|
108
109
|
datesFormat?: string,
|
|
109
110
|
deleteConfirmation?: boolean,
|
|
111
|
+
title?: string,
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
export type AllowedActions = {
|