adminforth 1.2.75 → 1.2.77
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/modules/restApi.js +25 -23
- package/modules/restApi.ts +3 -0
- package/package.json +2 -2
- package/spa/src/App.vue +74 -32
- package/spa/src/router/index.ts +11 -7
- package/spa/src/stores/filters.ts +5 -8
- package/types/AdminForthConfig.ts +67 -4
package/dist/modules/restApi.js
CHANGED
|
@@ -132,7 +132,7 @@ export default class AdminForthRestAPI {
|
|
|
132
132
|
method: 'GET',
|
|
133
133
|
path: '/get_base_config',
|
|
134
134
|
handler: (_k) => __awaiter(this, [_k], void 0, function* ({ input, adminUser, cookies }) {
|
|
135
|
-
var _l, _m, _o;
|
|
135
|
+
var _l, _m, _o, _p, _q;
|
|
136
136
|
let username = '';
|
|
137
137
|
let userFullName = '';
|
|
138
138
|
if (adminUser.isRoot) {
|
|
@@ -180,6 +180,7 @@ export default class AdminForthRestAPI {
|
|
|
180
180
|
}
|
|
181
181
|
newMenu.push(newMenuItem);
|
|
182
182
|
}
|
|
183
|
+
const announcementBadge = (_o = (_m = this.adminforth.config.customization).announcementBadge) === null || _o === void 0 ? void 0 : _o.call(_m, adminUser);
|
|
183
184
|
return {
|
|
184
185
|
user: userData,
|
|
185
186
|
resources: this.adminforth.config.resources.map((res) => ({
|
|
@@ -194,8 +195,9 @@ export default class AdminForthRestAPI {
|
|
|
194
195
|
deleteConfirmation: this.adminforth.config.deleteConfirmation,
|
|
195
196
|
auth: this.adminforth.config.auth,
|
|
196
197
|
usernameField: this.adminforth.config.auth.usernameField,
|
|
197
|
-
title: (
|
|
198
|
-
emptyFieldPlaceholder: (
|
|
198
|
+
title: (_p = this.adminforth.config.customization) === null || _p === void 0 ? void 0 : _p.title,
|
|
199
|
+
emptyFieldPlaceholder: (_q = this.adminforth.config.customization) === null || _q === void 0 ? void 0 : _q.emptyFieldPlaceholder,
|
|
200
|
+
announcementBadge,
|
|
199
201
|
},
|
|
200
202
|
adminUser,
|
|
201
203
|
version: ADMINFORTH_VERSION,
|
|
@@ -234,7 +236,7 @@ export default class AdminForthRestAPI {
|
|
|
234
236
|
server.endpoint({
|
|
235
237
|
method: 'POST',
|
|
236
238
|
path: '/get_resource',
|
|
237
|
-
handler: (
|
|
239
|
+
handler: (_r) => __awaiter(this, [_r], void 0, function* ({ body, adminUser }) {
|
|
238
240
|
const { resourceId } = body;
|
|
239
241
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
240
242
|
return { error: 'Database discovery not started' };
|
|
@@ -265,8 +267,8 @@ export default class AdminForthRestAPI {
|
|
|
265
267
|
server.endpoint({
|
|
266
268
|
method: 'POST',
|
|
267
269
|
path: '/get_resource_data',
|
|
268
|
-
handler: (
|
|
269
|
-
var
|
|
270
|
+
handler: (_s) => __awaiter(this, [_s], void 0, function* ({ body, adminUser }) {
|
|
271
|
+
var _t, _u, _v, _w;
|
|
270
272
|
const { resourceId, source } = body;
|
|
271
273
|
if (['show', 'list'].includes(source) === false) {
|
|
272
274
|
return { error: 'Invalid source, should be list or show' };
|
|
@@ -286,7 +288,7 @@ export default class AdminForthRestAPI {
|
|
|
286
288
|
if (!allowed) {
|
|
287
289
|
return { error };
|
|
288
290
|
}
|
|
289
|
-
for (const hook of listify((
|
|
291
|
+
for (const hook of listify((_u = (_t = resource.hooks) === null || _t === void 0 ? void 0 : _t[source]) === null || _u === void 0 ? void 0 : _u.beforeDatasourceRequest)) {
|
|
290
292
|
const resp = yield hook({ resource, query: body, adminUser });
|
|
291
293
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
292
294
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -365,7 +367,7 @@ export default class AdminForthRestAPI {
|
|
|
365
367
|
item._label = resource.recordLabel(item);
|
|
366
368
|
});
|
|
367
369
|
// only after adminforth made all post processing, give user ability to edit it
|
|
368
|
-
for (const hook of listify((
|
|
370
|
+
for (const hook of listify((_w = (_v = resource.hooks) === null || _v === void 0 ? void 0 : _v[source]) === null || _w === void 0 ? void 0 : _w.afterDatasourceResponse)) {
|
|
369
371
|
const resp = yield hook({ resource, response: data.data, adminUser });
|
|
370
372
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
371
373
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -380,8 +382,8 @@ export default class AdminForthRestAPI {
|
|
|
380
382
|
server.endpoint({
|
|
381
383
|
method: 'POST',
|
|
382
384
|
path: '/get_resource_foreign_data',
|
|
383
|
-
handler: (
|
|
384
|
-
var
|
|
385
|
+
handler: (_x) => __awaiter(this, [_x], void 0, function* ({ body, adminUser }) {
|
|
386
|
+
var _y, _z, _0, _1;
|
|
385
387
|
const { resourceId, column } = body;
|
|
386
388
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
387
389
|
return { error: 'Database discovery not started' };
|
|
@@ -402,7 +404,7 @@ export default class AdminForthRestAPI {
|
|
|
402
404
|
}
|
|
403
405
|
const targetResourceId = columnConfig.foreignResource.resourceId;
|
|
404
406
|
const targetResource = this.adminforth.config.resources.find((res) => res.resourceId == targetResourceId);
|
|
405
|
-
for (const hook of listify((
|
|
407
|
+
for (const hook of listify((_z = (_y = columnConfig.foreignResource.hooks) === null || _y === void 0 ? void 0 : _y.dropdownList) === null || _z === void 0 ? void 0 : _z.beforeDatasourceRequest)) {
|
|
406
408
|
const resp = yield hook({ query: body, adminUser, resource: targetResource });
|
|
407
409
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
408
410
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -431,7 +433,7 @@ export default class AdminForthRestAPI {
|
|
|
431
433
|
const response = {
|
|
432
434
|
items
|
|
433
435
|
};
|
|
434
|
-
for (const hook of listify((
|
|
436
|
+
for (const hook of listify((_1 = (_0 = columnConfig.foreignResource.hooks) === null || _0 === void 0 ? void 0 : _0.dropdownList) === null || _1 === void 0 ? void 0 : _1.afterDatasourceResponse)) {
|
|
435
437
|
const resp = yield hook({ response, adminUser, resource: targetResource });
|
|
436
438
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
437
439
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -446,7 +448,7 @@ export default class AdminForthRestAPI {
|
|
|
446
448
|
server.endpoint({
|
|
447
449
|
method: 'POST',
|
|
448
450
|
path: '/get_min_max_for_columns',
|
|
449
|
-
handler: (
|
|
451
|
+
handler: (_2) => __awaiter(this, [_2], void 0, function* ({ body }) {
|
|
450
452
|
const { resourceId } = body;
|
|
451
453
|
if (!this.adminforth.statuses.dbDiscover) {
|
|
452
454
|
return { error: 'Database discovery not started' };
|
|
@@ -475,7 +477,7 @@ export default class AdminForthRestAPI {
|
|
|
475
477
|
server.endpoint({
|
|
476
478
|
method: 'POST',
|
|
477
479
|
path: '/create_record',
|
|
478
|
-
handler: (
|
|
480
|
+
handler: (_3) => __awaiter(this, [_3], void 0, function* ({ body, adminUser }) {
|
|
479
481
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
480
482
|
if (!resource) {
|
|
481
483
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -499,8 +501,8 @@ export default class AdminForthRestAPI {
|
|
|
499
501
|
server.endpoint({
|
|
500
502
|
method: 'POST',
|
|
501
503
|
path: '/update_record',
|
|
502
|
-
handler: (
|
|
503
|
-
var
|
|
504
|
+
handler: (_4) => __awaiter(this, [_4], void 0, function* ({ body, adminUser }) {
|
|
505
|
+
var _5, _6, _7, _8;
|
|
504
506
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
505
507
|
if (!resource) {
|
|
506
508
|
return { error: `Resource '${body['resourceId']}' not found` };
|
|
@@ -519,7 +521,7 @@ export default class AdminForthRestAPI {
|
|
|
519
521
|
return { error };
|
|
520
522
|
}
|
|
521
523
|
// execute hook if needed
|
|
522
|
-
for (const hook of listify((
|
|
524
|
+
for (const hook of listify((_6 = (_5 = resource.hooks) === null || _5 === void 0 ? void 0 : _5.edit) === null || _6 === void 0 ? void 0 : _6.beforeSave)) {
|
|
523
525
|
const resp = yield hook({ resource, record, adminUser });
|
|
524
526
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
525
527
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -546,7 +548,7 @@ export default class AdminForthRestAPI {
|
|
|
546
548
|
yield connector.updateRecord({ resource, recordId, newValues });
|
|
547
549
|
}
|
|
548
550
|
// execute hook if needed
|
|
549
|
-
for (const hook of listify((
|
|
551
|
+
for (const hook of listify((_8 = (_7 = resource.hooks) === null || _7 === void 0 ? void 0 : _7.edit) === null || _8 === void 0 ? void 0 : _8.afterSave)) {
|
|
550
552
|
const resp = yield hook({ resource, record, adminUser, oldRecord });
|
|
551
553
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
552
554
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -563,8 +565,8 @@ export default class AdminForthRestAPI {
|
|
|
563
565
|
server.endpoint({
|
|
564
566
|
method: 'POST',
|
|
565
567
|
path: '/delete_record',
|
|
566
|
-
handler: (
|
|
567
|
-
var
|
|
568
|
+
handler: (_9) => __awaiter(this, [_9], void 0, function* ({ body, adminUser }) {
|
|
569
|
+
var _10, _11, _12, _13;
|
|
568
570
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == body['resourceId']);
|
|
569
571
|
const record = yield this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, body['primaryKey']);
|
|
570
572
|
if (!resource) {
|
|
@@ -582,7 +584,7 @@ export default class AdminForthRestAPI {
|
|
|
582
584
|
return { error };
|
|
583
585
|
}
|
|
584
586
|
// execute hook if needed
|
|
585
|
-
for (const hook of listify((
|
|
587
|
+
for (const hook of listify((_11 = (_10 = resource.hooks) === null || _10 === void 0 ? void 0 : _10.delete) === null || _11 === void 0 ? void 0 : _11.beforeSave)) {
|
|
586
588
|
const resp = yield hook({ resource, record, adminUser });
|
|
587
589
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
588
590
|
throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -594,7 +596,7 @@ export default class AdminForthRestAPI {
|
|
|
594
596
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
595
597
|
yield connector.deleteRecord({ resource, recordId: body['primaryKey'] });
|
|
596
598
|
// execute hook if needed
|
|
597
|
-
for (const hook of listify((
|
|
599
|
+
for (const hook of listify((_13 = (_12 = resource.hooks) === null || _12 === void 0 ? void 0 : _12.delete) === null || _13 === void 0 ? void 0 : _13.afterSave)) {
|
|
598
600
|
const resp = yield hook({ resource, record, adminUser });
|
|
599
601
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
600
602
|
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
@@ -611,7 +613,7 @@ export default class AdminForthRestAPI {
|
|
|
611
613
|
server.endpoint({
|
|
612
614
|
method: 'POST',
|
|
613
615
|
path: '/start_bulk_action',
|
|
614
|
-
handler: (
|
|
616
|
+
handler: (_14) => __awaiter(this, [_14], void 0, function* ({ body, adminUser }) {
|
|
615
617
|
const { resourceId, actionId, recordIds } = body;
|
|
616
618
|
const resource = this.adminforth.config.resources.find((res) => res.resourceId == resourceId);
|
|
617
619
|
if (!resource) {
|
package/modules/restApi.ts
CHANGED
|
@@ -207,6 +207,8 @@ export default class AdminForthRestAPI {
|
|
|
207
207
|
newMenu.push(newMenuItem)
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
const announcementBadge = this.adminforth.config.customization.announcementBadge?.(adminUser);
|
|
211
|
+
|
|
210
212
|
return {
|
|
211
213
|
user: userData,
|
|
212
214
|
resources: this.adminforth.config.resources.map((res) => ({
|
|
@@ -223,6 +225,7 @@ export default class AdminForthRestAPI {
|
|
|
223
225
|
usernameField: this.adminforth.config.auth.usernameField,
|
|
224
226
|
title: this.adminforth.config.customization?.title,
|
|
225
227
|
emptyFieldPlaceholder: this.adminforth.config.customization?.emptyFieldPlaceholder,
|
|
228
|
+
announcementBadge,
|
|
226
229
|
},
|
|
227
230
|
adminUser,
|
|
228
231
|
version: ADMINFORTH_VERSION,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adminforth",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.77",
|
|
4
4
|
"description": "OpenSource Vue3 powered forth-generation admin panel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"rollout": "tsc && npm version patch && npm publish && npm run rollout-doc",
|
|
12
12
|
"rollout-doc": "cd documentation && npm run build && npm run deploy",
|
|
13
13
|
"docs": "typedoc",
|
|
14
|
-
"postinstall": "cd spa/src && ln -sf ../../types types"
|
|
14
|
+
"postinstall": "cd ./spa/src/ && test ! -d ./types && ln -sf ../../types ./types || echo 'types linked'"
|
|
15
15
|
},
|
|
16
16
|
"author": "devforth.io",
|
|
17
17
|
"license": "ISC",
|
package/spa/src/App.vue
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<div class="flex items-center justify-between">
|
|
9
9
|
<div class="flex items-center justify-start rtl:justify-end">
|
|
10
10
|
<button @click="sideBarOpen = !sideBarOpen"
|
|
11
|
-
|
|
11
|
+
type="button" class="inline-flex items-center p-2 text-sm rounded-lg sm:hidden hover:bg-lightSidebarItemHover focus:outline-none focus:ring-2 focus:ring-lightSidebarDevider dark:text-darkSidebarIcons dark:hover:bg-darkSidebarHover dark:focus:ring-lightSidebarDevider">
|
|
12
12
|
<span class="sr-only">Open sidebar</span>
|
|
13
13
|
<svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
14
14
|
<path clip-rule="evenodd" fill-rule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"></path>
|
|
@@ -73,38 +73,66 @@
|
|
|
73
73
|
</span>
|
|
74
74
|
</div>
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
<ul class="space-y-2 font-medium">
|
|
77
|
+
<template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
|
|
78
|
+
<div v-if="item.type === 'divider'" class="border-t border-lightSidebarDevider dark:border-darkSidebarDevider"></div>
|
|
79
|
+
<div v-else-if="item.type === 'gap'" class="flex items-center justify-center h-8"></div>
|
|
80
|
+
<div v-else-if="item.type === 'heading'" class="flex items-center justify-left pl-2 h-8 text-lightSidebarHeading dark:text-darkSidebarHeading
|
|
81
|
+
">{{ item.label }}</div>
|
|
82
|
+
<li v-else-if="item.children" class=" ">
|
|
83
|
+
<button @click="clickOnMenuItem(i)" type="button" class="flex items-center w-full p-2 text-base text-lightSidebarText rounded-default transition duration-75 group hover:bg-lightSidebarItemHover hover:text-lightSidebarTextHover dark:text-darkSidebarText dark:hover:bg-darkSidebarHover dark:hover:text-darkSidebarTextHover"
|
|
84
|
+
:aria-controls="`dropdown-example${i}`"
|
|
85
|
+
:data-collapse-toggle="`dropdown-example${i}`"
|
|
86
|
+
>
|
|
87
|
+
<component v-if="item.icon" :is="getIcon(item.icon)" class="w-5 h-5 text-lightSidebarIcons group-hover:text-lightSidebarIconsHover transition duration-75 dark:group-hover:text-darkSidebarIconsHover dark:text-darkSidebarIcons" ></component>
|
|
88
|
+
|
|
89
|
+
<span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">{{ item.label }}</span>
|
|
90
|
+
<svg :class="{'rotate-180': opened.includes(i) }" class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
|
91
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
|
92
|
+
</svg>
|
|
93
|
+
</button>
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
<ul :id="`dropdown-example${i}`" role="none" class="pt-1 space-y-1" :class="{ 'hidden': !opened.includes(i) }">
|
|
96
|
+
<template v-for="(child, j) in item.children" :key="`menu-${i}-${j}`">
|
|
97
|
+
<li>
|
|
98
|
+
<MenuLink :item="child" isChild="true" />
|
|
99
|
+
</li>
|
|
100
|
+
</template>
|
|
101
|
+
</ul>
|
|
102
|
+
</li>
|
|
103
|
+
<li v-else>
|
|
104
|
+
<MenuLink :item="item" />
|
|
105
|
+
</li>
|
|
106
|
+
</template>
|
|
107
|
+
</ul>
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
<div id="dropdown-cta" class="p-4 mt-6 rounded-lg bg-blue-50 dark:bg-blue-900" role="alert"
|
|
111
|
+
v-if="ctaBadge"
|
|
112
|
+
>
|
|
113
|
+
<div class="flex items-center mb-3">
|
|
114
|
+
<span class="bg-blue-200 text-blue-800 text-sm font-semibold me-2 px-2.5 py-0.5 rounded dark:bg-blue-200 dark:text-blue-800"
|
|
115
|
+
v-if="ctaBadge.title"
|
|
116
|
+
>
|
|
117
|
+
{{ctaBadge.title}}
|
|
118
|
+
</span>
|
|
119
|
+
<button type="button"
|
|
120
|
+
class="ms-auto -mx-1.5 -my-1.5 bg-blue-50 inline-flex justify-center items-center w-6 h-6 text-blue-900 rounded-lg focus:ring-2 focus:ring-blue-400 p-1 hover:bg-blue-200 dark:bg-blue-900 dark:text-blue-400 dark:hover:bg-blue-800"
|
|
121
|
+
data-dismiss-target="#dropdown-cta" aria-label="Close"
|
|
122
|
+
v-if="ctaBadge.closable" @click="closeCTA"
|
|
123
|
+
>
|
|
124
|
+
<span class="sr-only">Close</span>
|
|
125
|
+
<svg class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
126
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
127
|
+
</svg>
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
<p class="mb-3 text-sm fill-blue-800 dark:fill-blue-400 text-blue-800 dark:text-blue-400" v-if="ctaBadge.html" v-html="ctaBadge.html"></p>
|
|
131
|
+
<p class="text-sm text-blue-800 dark:text-blue-400" v-else>
|
|
132
|
+
{{ ctaBadge.text }}
|
|
133
|
+
</p>
|
|
134
|
+
<!-- <a class="text-sm text-blue-800 underline font-medium hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300" href="#">Turn new navigation off</a> -->
|
|
135
|
+
</div>
|
|
108
136
|
</div>
|
|
109
137
|
</aside>
|
|
110
138
|
|
|
@@ -311,4 +339,18 @@ onBeforeMount(()=>{
|
|
|
311
339
|
document.documentElement.classList.toggle('dark', theme.value === 'dark');
|
|
312
340
|
})
|
|
313
341
|
|
|
342
|
+
|
|
343
|
+
const ctaBadge = computed(() => {
|
|
344
|
+
const badge = coreStore.config?.announcementBadge;
|
|
345
|
+
const hash = badge.closable ? JSON.stringify(badge).split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0) : '';
|
|
346
|
+
if (badge.closable && window.localStorage.getItem(`ctaBadge-${hash}`)) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
return {...badge, hash};
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
function closeCTA() {
|
|
353
|
+
const hash = ctaBadge.value.hash;
|
|
354
|
+
window.localStorage.setItem(`ctaBadge-${hash}`, '1');
|
|
355
|
+
}
|
|
314
356
|
</script>
|
package/spa/src/router/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
-
import ResourceParent from '@/views/ResourceParent.vue'
|
|
3
|
-
import {
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router';
|
|
2
|
+
import ResourceParent from '@/views/ResourceParent.vue';
|
|
3
|
+
import { useFiltersStore } from '@/stores/filters';
|
|
4
4
|
/* IMPORTANT:ADMINFORTH ROUTES IMPORTS */
|
|
5
5
|
|
|
6
6
|
const router = createRouter({
|
|
@@ -51,13 +51,17 @@ const router = createRouter({
|
|
|
51
51
|
|
|
52
52
|
},
|
|
53
53
|
]
|
|
54
|
-
},
|
|
54
|
+
},
|
|
55
55
|
/* IMPORTANT:ADMINFORTH ROUTES */
|
|
56
56
|
]
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
router.beforeEach((to, from, next) => {
|
|
60
|
+
const filterStore = useFiltersStore();
|
|
61
|
+
if (to.path.startsWith('/resource/')) {
|
|
62
|
+
filterStore.clearFilters();
|
|
63
|
+
}
|
|
64
|
+
next()
|
|
65
|
+
})
|
|
62
66
|
|
|
63
67
|
export default router
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
import { defineStore } from 'pinia'
|
|
3
|
-
import { callAdminForthApi } from '@/utils';
|
|
1
|
+
import { ref, type Ref } from 'vue';
|
|
2
|
+
import { defineStore } from 'pinia';
|
|
4
3
|
|
|
5
4
|
export const useFiltersStore = defineStore('filters', () => {
|
|
6
|
-
const filters = ref([]);
|
|
5
|
+
const filters: Ref<any[]> = ref([]);
|
|
7
6
|
const setFilter = (filter: any) => {
|
|
8
7
|
filters.value = [...filters.value, filter];
|
|
9
8
|
}
|
|
@@ -16,7 +15,5 @@ export const useFiltersStore = defineStore('filters', () => {
|
|
|
16
15
|
const clearFilters = () => {
|
|
17
16
|
filters.value = [];
|
|
18
17
|
}
|
|
19
|
-
return {setFilter, getFilters,clearFilters, filters,setFilters}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
return {setFilter, getFilters, clearFilters, filters, setFilters}
|
|
19
|
+
})
|
|
@@ -798,7 +798,9 @@ export type AdminForthResource = {
|
|
|
798
798
|
*/
|
|
799
799
|
columns: Array<AdminForthResourceColumn>,
|
|
800
800
|
|
|
801
|
-
|
|
801
|
+
/**
|
|
802
|
+
* Internal array of columns which are not virtual. You should not edit it.
|
|
803
|
+
*/
|
|
802
804
|
dataSourceColumns?: Array<AdminForthResourceColumn>, // TODO, mark as private
|
|
803
805
|
|
|
804
806
|
/**
|
|
@@ -818,25 +820,79 @@ export type AdminForthResource = {
|
|
|
818
820
|
*
|
|
819
821
|
*/
|
|
820
822
|
plugins?: Array<IAdminForthPlugin>,
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Hooks allow you to change the data on different stages of resource lifecycle.
|
|
826
|
+
* Hooks are functions which will be called on backend side (only backend side).
|
|
827
|
+
*/
|
|
821
828
|
hooks?: {
|
|
822
829
|
show?: {
|
|
830
|
+
/**
|
|
831
|
+
* Typical usecases:
|
|
832
|
+
* - request additional data from database before returning to frontend for soft-join
|
|
833
|
+
*/
|
|
823
834
|
beforeDatasourceRequest?: BeforeDataSourceRequestFunction | Array<BeforeDataSourceRequestFunction>,
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Typical usecases:
|
|
838
|
+
* - Transform value for some field for record returned from database before returning to frontend (minimize, sanitize, etc)
|
|
839
|
+
* - If some-why you can't use `backendOnly` you can cleanup sensitive fields here
|
|
840
|
+
* - Attach additional data to record before returning to frontend
|
|
841
|
+
*/
|
|
824
842
|
afterDatasourceResponse?: AfterDataSourceResponseFunction | Array<AfterDataSourceResponseFunction>,
|
|
825
843
|
},
|
|
826
844
|
list?: {
|
|
845
|
+
/**
|
|
846
|
+
* Typical usecases:
|
|
847
|
+
* - add additional filters in addition to what user selected before fetching data from database.
|
|
848
|
+
* - same as hooks.show.beforeDatasourceRequest
|
|
849
|
+
*/
|
|
827
850
|
beforeDatasourceRequest?: BeforeDataSourceRequestFunction | Array<BeforeDataSourceRequestFunction>,
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Typical usecases:
|
|
854
|
+
* - Same as hooks.show.afterDatasourceResponse but applied for each record in list
|
|
855
|
+
*/
|
|
828
856
|
afterDatasourceResponse?: AfterDataSourceResponseFunction | Array<AfterDataSourceResponseFunction>,
|
|
829
857
|
},
|
|
830
858
|
create?: {
|
|
859
|
+
/**
|
|
860
|
+
* Typical usecases:
|
|
861
|
+
* - Validate record before saving to database and interrupt execution if validation failed (`allowedActions.create` should be preferred in most cases)
|
|
862
|
+
* - fill-in adminUser as creator of record
|
|
863
|
+
* - Attach additional data to record before saving to database (mostly fillOnCreate should be used instead)
|
|
864
|
+
*/
|
|
831
865
|
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Typical usecases:
|
|
869
|
+
* - Initiate some trigger after record saved to database (e.g sync to another datasource)
|
|
870
|
+
*/
|
|
832
871
|
afterSave?: AfterSaveFunction | Array<AfterSaveFunction>,
|
|
833
872
|
},
|
|
834
873
|
edit?: {
|
|
874
|
+
/**
|
|
875
|
+
* Typical usecases:
|
|
876
|
+
* - Same as hooks.create.beforeSave but for edit page
|
|
877
|
+
*/
|
|
835
878
|
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Typical usecases:
|
|
882
|
+
* - Same as hooks.create.afterSave but for edit page
|
|
883
|
+
*/
|
|
836
884
|
afterSave?: AfterSaveFunction | Array<AfterSaveFunction>,
|
|
837
885
|
},
|
|
838
886
|
delete?: {
|
|
887
|
+
/**
|
|
888
|
+
* Typical usecases:
|
|
889
|
+
* - Validate that record can be deleted and interrupt execution if validation failed (`allowedActions.delete` should be preferred in most cases)
|
|
890
|
+
*/
|
|
839
891
|
beforeSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
892
|
+
/**
|
|
893
|
+
* Typical usecases:
|
|
894
|
+
* - Initiate some trigger after record deleted from database (e.g sync to another datasource)
|
|
895
|
+
*/
|
|
840
896
|
afterSave?: BeforeSaveFunction | Array<BeforeSaveFunction>,
|
|
841
897
|
},
|
|
842
898
|
},
|
|
@@ -1050,7 +1106,6 @@ export type AdminForthConfig = {
|
|
|
1050
1106
|
* Function or functions which will be called before user try to login.
|
|
1051
1107
|
* Each function will resive User object as an argument
|
|
1052
1108
|
*/
|
|
1053
|
-
|
|
1054
1109
|
beforeLoginConfirmation?: BeforeLoginConfirmationFunction | Array<BeforeLoginConfirmationFunction>,
|
|
1055
1110
|
|
|
1056
1111
|
/**
|
|
@@ -1205,14 +1260,21 @@ export type AdminForthConfig = {
|
|
|
1205
1260
|
* Object to redefine default styles for AdminForth components. Use this file as reference for all possible adjustments https://github.com/devforth/adminforth/blob/main/adminforth/modules/styles.ts
|
|
1206
1261
|
*/
|
|
1207
1262
|
styles?: Object,
|
|
1263
|
+
|
|
1208
1264
|
/**
|
|
1209
1265
|
* Description of custom pages which will let register custom pages for custom routes in AdminForth.
|
|
1210
1266
|
*/
|
|
1211
|
-
|
|
1212
1267
|
customPages?: Array<{
|
|
1213
1268
|
path: string,
|
|
1214
1269
|
component: AdminForthComponentDeclaration,
|
|
1215
1270
|
}>,
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Function to return custom badge in side bar for users. Can return text or html
|
|
1274
|
+
* If function is not passed or returns null, badge will not be shown.
|
|
1275
|
+
* Execution is done on admin app load.
|
|
1276
|
+
*/
|
|
1277
|
+
announcementBadge?: (user: AdminUser) => { text?: string, html?: string, closable?: boolean, title?: string } | null,
|
|
1216
1278
|
}
|
|
1217
1279
|
|
|
1218
1280
|
/**
|
|
@@ -1224,7 +1286,8 @@ export type AdminForthConfig = {
|
|
|
1224
1286
|
*
|
|
1225
1287
|
*/
|
|
1226
1288
|
baseUrl?: string,
|
|
1227
|
-
|
|
1289
|
+
|
|
1290
|
+
|
|
1228
1291
|
deleteConfirmation?: boolean,
|
|
1229
1292
|
|
|
1230
1293
|
|