adminforth 1.0.83 → 1.0.84
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 +19 -0
- package/dist/modules/codeInjector.js +17 -8
- package/dist/spa/spa/src/views/CreateView.vue +23 -0
- package/dist/spa/spa/src/views/EditView.vue +24 -0
- package/dist/spa/spa/src/views/ListView.vue +26 -2
- package/dist/spa/spa/src/views/ShowView.vue +23 -0
- package/dist/types/AdminForthConfig.js +46 -0
- package/documentation/docusaurus.config.ts +3 -3
- package/documentation/static/CNAME +1 -0
- package/index.ts +21 -0
- package/modules/codeInjector.ts +11 -2
- package/package.json +1 -1
- package/spa/src/views/CreateView.vue +23 -0
- package/spa/src/views/EditView.vue +24 -0
- package/spa/src/views/ListView.vue +26 -2
- package/spa/src/views/ShowView.vue +23 -0
- package/types/AdminForthConfig.ts +158 -1
- package/documentation/static/img/docusaurus-social-card.jpg +0 -0
- package/documentation/static/img/tail.png:Zone.Identifier +0 -0
package/dist/index.js
CHANGED
|
@@ -204,6 +204,25 @@ class AdminForth {
|
|
|
204
204
|
return Object.assign(action, { id: uuid() });
|
|
205
205
|
});
|
|
206
206
|
bulkActions = newBulkActions;
|
|
207
|
+
// if pageInjection is a string, make array with one element. Also check file exists
|
|
208
|
+
const possibleInjections = ['beforeBreadcrumbs', 'afterBreadcrumbs', 'bottom'];
|
|
209
|
+
if (res.options.pageInjections) {
|
|
210
|
+
Object.entries(res.options.pageInjections).map(([key, value]) => {
|
|
211
|
+
Object.entries(value).map(([injection, target]) => {
|
|
212
|
+
if (possibleInjections.includes(injection)) {
|
|
213
|
+
if (typeof target === 'string') {
|
|
214
|
+
res.options.pageInjections[key][injection] = [target];
|
|
215
|
+
}
|
|
216
|
+
res.options.pageInjections[key][injection].forEach((target) => {
|
|
217
|
+
errors.push(...this.checkCustomFileExists(target));
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
errors.push(`Resource "${res.resourceId}" has invalid pageInjection key "${injection}", Supported keys are ${possibleInjections.join(', ')}`);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
207
226
|
}
|
|
208
227
|
//add default allowedActions to resources
|
|
209
228
|
if (res.options.allowedActions) {
|
|
@@ -94,7 +94,7 @@ class CodeInjector {
|
|
|
94
94
|
}
|
|
95
95
|
prepareSources(_a) {
|
|
96
96
|
return __awaiter(this, arguments, void 0, function* ({ filesUpdated, verbose = false }) {
|
|
97
|
-
var _b, _c, _d, _e, _f, _g, _h, _j
|
|
97
|
+
var _b, _c, _d, _e, _f, _g, _h, _j;
|
|
98
98
|
// check SPA_TMP_PATH exists and create if not
|
|
99
99
|
try {
|
|
100
100
|
yield fs.promises.access(CodeInjector.SPA_TMP_PATH, fs.constants.F_OK);
|
|
@@ -233,9 +233,9 @@ class CodeInjector {
|
|
|
233
233
|
return `import { ${PascalIconName} } from '@iconify-prerendered/vue-${collection}';`;
|
|
234
234
|
}).join('\n');
|
|
235
235
|
// for each custom component generate import statement
|
|
236
|
-
const customComponentsDir = (_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.customComponentsDir;
|
|
237
236
|
const customResourceComponents = [];
|
|
238
237
|
this.adminforth.config.resources.forEach((resource) => {
|
|
238
|
+
var _a;
|
|
239
239
|
resource.columns.forEach((field) => {
|
|
240
240
|
if (field.component) {
|
|
241
241
|
Object.values(field.component).forEach((filePath) => {
|
|
@@ -245,6 +245,15 @@ class CodeInjector {
|
|
|
245
245
|
});
|
|
246
246
|
}
|
|
247
247
|
});
|
|
248
|
+
(Object.values(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.pageInjections) || {})).forEach((injection) => {
|
|
249
|
+
Object.values(injection).forEach((filePathes) => {
|
|
250
|
+
filePathes.forEach((filePath) => {
|
|
251
|
+
if (!customResourceComponents.includes(filePath)) {
|
|
252
|
+
customResourceComponents.push(filePath);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
248
257
|
});
|
|
249
258
|
customResourceComponents.forEach((filePath) => {
|
|
250
259
|
const componentName = getComponentNameFromPath(filePath);
|
|
@@ -270,7 +279,7 @@ class CodeInjector {
|
|
|
270
279
|
}
|
|
271
280
|
let imports = iconImports + '\n';
|
|
272
281
|
imports += customComponentsImports + '\n';
|
|
273
|
-
if ((
|
|
282
|
+
if ((_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.vueUsesFile) {
|
|
274
283
|
imports += `import addCustomUses from '${this.adminforth.config.customization.vueUsesFile}';\n`;
|
|
275
284
|
}
|
|
276
285
|
// inject that code into spa_tmp/src/App.vue
|
|
@@ -278,13 +287,13 @@ class CodeInjector {
|
|
|
278
287
|
let appVueContent = yield fs.promises.readFile(appVuePath, 'utf-8');
|
|
279
288
|
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH IMPORTS */', imports);
|
|
280
289
|
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH COMPONENT REGISTRATIONS */', iconComponents + '\n' + customComponentsComponents + '\n');
|
|
281
|
-
if ((
|
|
290
|
+
if ((_d = this.adminforth.config.customization) === null || _d === void 0 ? void 0 : _d.vueUsesFile) {
|
|
282
291
|
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH CUSTOM USES */', 'addCustomUses(app);');
|
|
283
292
|
}
|
|
284
293
|
yield fs.promises.writeFile(appVuePath, appVueContent);
|
|
285
294
|
// generate tailwind extend styles
|
|
286
|
-
if ((
|
|
287
|
-
const tailwindStyles = (
|
|
295
|
+
if ((_e = this.adminforth.config) === null || _e === void 0 ? void 0 : _e.styles) {
|
|
296
|
+
const tailwindStyles = (_f = this.adminforth.config) === null || _f === void 0 ? void 0 : _f.styles;
|
|
288
297
|
const stylesText = JSON.stringify(tailwindStyles, null, 2).slice(1, -1);
|
|
289
298
|
let tailwindConfigPath = path.join(CodeInjector.SPA_TMP_PATH, 'tailwind.config.js');
|
|
290
299
|
let tailwindConfigContent = yield fs.promises.readFile(tailwindConfigPath, 'utf-8');
|
|
@@ -308,10 +317,10 @@ class CodeInjector {
|
|
|
308
317
|
/* generate custom routes */
|
|
309
318
|
const homepageMenuItem = this.adminforth.config.menu.find((mi) => mi.homepage);
|
|
310
319
|
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)); });
|
|
311
|
-
let childrenHomepage = (
|
|
320
|
+
let childrenHomepage = (_g = childrenHomePageMenuItem === null || childrenHomePageMenuItem === void 0 ? void 0 : childrenHomePageMenuItem.children) === null || _g === void 0 ? void 0 : _g.find((mi) => mi.homepage);
|
|
312
321
|
let homePagePath = (homepageMenuItem === null || homepageMenuItem === void 0 ? void 0 : homepageMenuItem.path) || `/resource/${childrenHomepage === null || childrenHomepage === void 0 ? void 0 : childrenHomepage.resourceId}`;
|
|
313
322
|
if (!homePagePath) {
|
|
314
|
-
homePagePath = ((
|
|
323
|
+
homePagePath = ((_h = this.adminforth.config.menu.filter((mi) => mi.path)[0]) === null || _h === void 0 ? void 0 : _h.path) || `/resource/${(_j = this.adminforth.config.menu.filter((mi) => mi.children)[0]) === null || _j === void 0 ? void 0 : _j.resourceId}`;
|
|
315
324
|
}
|
|
316
325
|
routes += `{
|
|
317
326
|
path: '/',
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
3
|
|
|
4
|
+
<component
|
|
5
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.beforeBreadcrumbs || []"
|
|
6
|
+
:is="getCustomComponent(c)"
|
|
7
|
+
:record="coreStore.record"
|
|
8
|
+
:columns="coreStore.resourceColumns"
|
|
9
|
+
:adminUser="coreStore.adminUser"
|
|
10
|
+
/>
|
|
11
|
+
|
|
4
12
|
<BreadcrumbsWithButtons>
|
|
5
13
|
<!-- save and cancle -->
|
|
6
14
|
<button @click="$router.back()"
|
|
@@ -22,6 +30,14 @@
|
|
|
22
30
|
|
|
23
31
|
</BreadcrumbsWithButtons>
|
|
24
32
|
|
|
33
|
+
<component
|
|
34
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.afterBreadcrumbs || []"
|
|
35
|
+
:is="getCustomComponent(c)"
|
|
36
|
+
:record="coreStore.record"
|
|
37
|
+
:columns="coreStore.resourceColumns"
|
|
38
|
+
:adminUser="coreStore.adminUser"
|
|
39
|
+
/>
|
|
40
|
+
|
|
25
41
|
<SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
|
|
26
42
|
|
|
27
43
|
|
|
@@ -36,6 +52,13 @@
|
|
|
36
52
|
>
|
|
37
53
|
</ResourceForm>
|
|
38
54
|
|
|
55
|
+
<component
|
|
56
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.bottom || []"
|
|
57
|
+
:is="getCustomComponent(c)"
|
|
58
|
+
:record="coreStore.record"
|
|
59
|
+
:columns="coreStore.resourceColumns"
|
|
60
|
+
:adminUser="coreStore.adminUser"
|
|
61
|
+
/>
|
|
39
62
|
|
|
40
63
|
</div>
|
|
41
64
|
</template>
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
+
<component
|
|
4
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.beforeBreadcrumbs || []"
|
|
5
|
+
:is="getCustomComponent(c)"
|
|
6
|
+
:record="coreStore.record"
|
|
7
|
+
:columns="coreStore.resourceColumns"
|
|
8
|
+
:adminUser="coreStore.adminUser"
|
|
9
|
+
/>
|
|
3
10
|
|
|
4
11
|
<BreadcrumbsWithButtons>
|
|
5
12
|
<!-- save and cancle -->
|
|
@@ -19,6 +26,14 @@
|
|
|
19
26
|
|
|
20
27
|
</BreadcrumbsWithButtons>
|
|
21
28
|
|
|
29
|
+
<component
|
|
30
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.afterBreadcrumbs || []"
|
|
31
|
+
:is="getCustomComponent(c)"
|
|
32
|
+
:record="coreStore.record"
|
|
33
|
+
:columns="coreStore.resourceColumns"
|
|
34
|
+
:adminUser="coreStore.adminUser"
|
|
35
|
+
/>
|
|
36
|
+
|
|
22
37
|
<SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
|
|
23
38
|
|
|
24
39
|
<ResourceForm
|
|
@@ -31,6 +46,15 @@
|
|
|
31
46
|
:customComponentsPerColumn="editComponentsPerColumn"
|
|
32
47
|
>
|
|
33
48
|
</ResourceForm>
|
|
49
|
+
|
|
50
|
+
<component
|
|
51
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.bottom || []"
|
|
52
|
+
:is="getCustomComponent(c)"
|
|
53
|
+
:record="coreStore.record"
|
|
54
|
+
:columns="coreStore.resourceColumns"
|
|
55
|
+
:adminUser="coreStore.adminUser"
|
|
56
|
+
/>
|
|
57
|
+
|
|
34
58
|
</div>
|
|
35
59
|
</template>
|
|
36
60
|
|
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
/>
|
|
10
10
|
</Teleport>
|
|
11
11
|
|
|
12
|
+
<component
|
|
13
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.beforeBreadcrumbs || []"
|
|
14
|
+
:is="getCustomComponent(c)"
|
|
15
|
+
:record="coreStore.record"
|
|
16
|
+
:columns="coreStore.resourceColumns"
|
|
17
|
+
:adminUser="coreStore.adminUser"
|
|
18
|
+
/>
|
|
19
|
+
|
|
12
20
|
<BreadcrumbsWithButtons>
|
|
13
21
|
<button
|
|
14
22
|
@click="()=>{checkboxes = []}"
|
|
@@ -64,6 +72,14 @@
|
|
|
64
72
|
</button>
|
|
65
73
|
</BreadcrumbsWithButtons>
|
|
66
74
|
|
|
75
|
+
<component
|
|
76
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.afterBreadcrumbs || []"
|
|
77
|
+
:is="getCustomComponent(c)"
|
|
78
|
+
:record="coreStore.record"
|
|
79
|
+
:columns="coreStore.resourceColumns"
|
|
80
|
+
:adminUser="coreStore.adminUser"
|
|
81
|
+
/>
|
|
82
|
+
|
|
67
83
|
<!-- table -->
|
|
68
84
|
<div class="relative overflow-x-auto shadow-list-table-shadow dark:shadow-black overflow-y-hidden rounded-default">
|
|
69
85
|
|
|
@@ -260,8 +276,7 @@
|
|
|
260
276
|
</div>
|
|
261
277
|
<!-- pagination -->
|
|
262
278
|
<div class="flex flex-col items-center mt-4 xs:flex-row xs:justify-between xs:items-center"
|
|
263
|
-
v-if="rows && totalRows >= pageSize && totalRows > 0"
|
|
264
|
-
>
|
|
279
|
+
v-if="rows && totalRows >= pageSize && totalRows > 0">
|
|
265
280
|
<!-- Help text -->
|
|
266
281
|
<span class="text-sm text-gray-700 dark:text-gray-400">
|
|
267
282
|
Showing <span class="font-semibold text-gray-900 dark:text-white">
|
|
@@ -313,6 +328,15 @@
|
|
|
313
328
|
</button>
|
|
314
329
|
</div>
|
|
315
330
|
</div>
|
|
331
|
+
|
|
332
|
+
<component
|
|
333
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.bottom || []"
|
|
334
|
+
:is="getCustomComponent(c)"
|
|
335
|
+
:record="coreStore.record"
|
|
336
|
+
:columns="coreStore.resourceColumns"
|
|
337
|
+
:adminUser="coreStore.adminUser"
|
|
338
|
+
/>
|
|
339
|
+
|
|
316
340
|
</div>
|
|
317
341
|
</template>
|
|
318
342
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
+
<component
|
|
4
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.beforeBreadcrumbs || []"
|
|
5
|
+
:is="getCustomComponent(c)"
|
|
6
|
+
:record="coreStore.record"
|
|
7
|
+
:columns="coreStore.resourceColumns"
|
|
8
|
+
:adminUser="coreStore.adminUser"
|
|
9
|
+
/>
|
|
3
10
|
<BreadcrumbsWithButtons>
|
|
4
11
|
<RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
5
12
|
class="flex items-center py-1 px-3 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
@@ -16,6 +23,14 @@
|
|
|
16
23
|
</button>
|
|
17
24
|
</BreadcrumbsWithButtons>
|
|
18
25
|
|
|
26
|
+
<component
|
|
27
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
28
|
+
:is="getCustomComponent(c)"
|
|
29
|
+
:record="coreStore.record"
|
|
30
|
+
:columns="coreStore.resourceColumns"
|
|
31
|
+
:adminUser="coreStore.adminUser"
|
|
32
|
+
/>
|
|
33
|
+
|
|
19
34
|
<div v-if="loading" role="status" class="max-w-sm animate-pulse">
|
|
20
35
|
<div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4"></div>
|
|
21
36
|
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
|
|
@@ -70,6 +85,14 @@
|
|
|
70
85
|
</tr>
|
|
71
86
|
</tbody>
|
|
72
87
|
</table>
|
|
88
|
+
|
|
89
|
+
<component
|
|
90
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
91
|
+
:is="getCustomComponent(c)"
|
|
92
|
+
:record="coreStore.record"
|
|
93
|
+
:columns="coreStore.resourceColumns"
|
|
94
|
+
:adminUser="coreStore.adminUser"
|
|
95
|
+
/>
|
|
73
96
|
</div>
|
|
74
97
|
|
|
75
98
|
|
|
@@ -1,3 +1,49 @@
|
|
|
1
|
+
export var AdminForthMenuType;
|
|
2
|
+
(function (AdminForthMenuType) {
|
|
3
|
+
/**
|
|
4
|
+
* HEADING is just a label in the menu.
|
|
5
|
+
* Respect `label` and `icon` property in @AdminForthConfigMenuItem
|
|
6
|
+
*/
|
|
7
|
+
AdminForthMenuType["HEADING"] = "heading";
|
|
8
|
+
/**
|
|
9
|
+
* GROUP is a group of menu items.
|
|
10
|
+
* Respects `label`, `icon` and `children` properties in @AdminForthConfigMenuItem
|
|
11
|
+
* use @AdminForthMenuType.open to set if group is open by default
|
|
12
|
+
*/
|
|
13
|
+
AdminForthMenuType["GROUP"] = "group";
|
|
14
|
+
/**
|
|
15
|
+
* RESOURCE is a link to a resource.
|
|
16
|
+
* Respects `label`, `icon`, `resourceId`, `homepage`, `isStaticRoute` properties in @AdminForthConfigMenuItem
|
|
17
|
+
*/
|
|
18
|
+
AdminForthMenuType["RESOURCE"] = "resource";
|
|
19
|
+
/**
|
|
20
|
+
* PAGE is a link to a custom page.
|
|
21
|
+
* Respects `label`, `icon`, `path`, `component`, `homepage`, `isStaticRoute`, properties in @AdminForthConfigMenuItem
|
|
22
|
+
*
|
|
23
|
+
* Example:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* {
|
|
27
|
+
* type: AdminForthMenuType.PAGE,
|
|
28
|
+
* label: 'Custom Page',
|
|
29
|
+
* icon: 'home',
|
|
30
|
+
* path: '/dash',
|
|
31
|
+
* component: '@@/Dashboard.vue',
|
|
32
|
+
* homepage: true,
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
AdminForthMenuType["PAGE"] = "page";
|
|
38
|
+
/**
|
|
39
|
+
* GAP ads some space between menu items.
|
|
40
|
+
*/
|
|
41
|
+
AdminForthMenuType["GAP"] = "gap";
|
|
42
|
+
/**
|
|
43
|
+
* DIVIDER is a divider between menu items.
|
|
44
|
+
*/
|
|
45
|
+
AdminForthMenuType["DIVIDER"] = "divider";
|
|
46
|
+
})(AdminForthMenuType || (AdminForthMenuType = {}));
|
|
1
47
|
export var AdminForthDataTypes;
|
|
2
48
|
(function (AdminForthDataTypes) {
|
|
3
49
|
AdminForthDataTypes["STRING"] = "string";
|
|
@@ -8,7 +8,7 @@ const config: Config = {
|
|
|
8
8
|
favicon: 'img/favicon.png',
|
|
9
9
|
|
|
10
10
|
// Set the production url of your site here
|
|
11
|
-
url: 'https://adminforth.
|
|
11
|
+
url: 'https://adminforth.dev',
|
|
12
12
|
// Set the /<baseUrl>/ pathname under which your site is served
|
|
13
13
|
// For GitHub pages deployment, it is often '/<projectName>/'
|
|
14
14
|
baseUrl: '/',
|
|
@@ -76,7 +76,7 @@ const config: Config = {
|
|
|
76
76
|
|
|
77
77
|
themeConfig: {
|
|
78
78
|
// Replace with your project's social card
|
|
79
|
-
image: 'img/docusaurus-social-card.jpg',
|
|
79
|
+
// image: 'img/docusaurus-social-card.jpg',
|
|
80
80
|
navbar: {
|
|
81
81
|
title: 'AdminForth',
|
|
82
82
|
logo: {
|
|
@@ -162,7 +162,7 @@ const config: Config = {
|
|
|
162
162
|
copyright: `Copyright © ${new Date().getFullYear()} Devforth sp. z o.o.`,
|
|
163
163
|
},
|
|
164
164
|
prism: {
|
|
165
|
-
theme: prismThemes.
|
|
165
|
+
theme: prismThemes.okaidia,
|
|
166
166
|
darkTheme: prismThemes.dracula,
|
|
167
167
|
},
|
|
168
168
|
} satisfies Preset.ThemeConfig,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
adminforth.dev
|
package/index.ts
CHANGED
|
@@ -243,6 +243,27 @@ class AdminForth implements AdminForthClass {
|
|
|
243
243
|
return Object.assign(action, {id: uuid()});
|
|
244
244
|
});
|
|
245
245
|
bulkActions = newBulkActions;
|
|
246
|
+
|
|
247
|
+
// if pageInjection is a string, make array with one element. Also check file exists
|
|
248
|
+
const possibleInjections = ['beforeBreadcrumbs', 'afterBreadcrumbs', 'bottom'];
|
|
249
|
+
if(res.options.pageInjections) {
|
|
250
|
+
Object.entries(res.options.pageInjections).map(([key, value]) => {
|
|
251
|
+
Object.entries(value).map(([injection, target]) => {
|
|
252
|
+
if (possibleInjections.includes(injection)) {
|
|
253
|
+
if (typeof target === 'string') {
|
|
254
|
+
res.options.pageInjections[key][injection] = [target];
|
|
255
|
+
}
|
|
256
|
+
res.options.pageInjections[key][injection].forEach((target) => {
|
|
257
|
+
errors.push(...this.checkCustomFileExists(target));
|
|
258
|
+
});
|
|
259
|
+
} else {
|
|
260
|
+
errors.push(`Resource "${res.resourceId}" has invalid pageInjection key "${injection}", Supported keys are ${possibleInjections.join(', ')}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
246
267
|
}
|
|
247
268
|
|
|
248
269
|
//add default allowedActions to resources
|
package/modules/codeInjector.ts
CHANGED
|
@@ -260,8 +260,6 @@ class CodeInjector {
|
|
|
260
260
|
}).join('\n');
|
|
261
261
|
|
|
262
262
|
// for each custom component generate import statement
|
|
263
|
-
const customComponentsDir = this.adminforth.config.customization?.customComponentsDir;
|
|
264
|
-
|
|
265
263
|
const customResourceComponents = [];
|
|
266
264
|
this.adminforth.config.resources.forEach((resource) => {
|
|
267
265
|
resource.columns.forEach((field) => {
|
|
@@ -273,6 +271,17 @@ class CodeInjector {
|
|
|
273
271
|
});
|
|
274
272
|
}
|
|
275
273
|
});
|
|
274
|
+
(Object.values(resource.options?.pageInjections || {})).forEach((injection) => {
|
|
275
|
+
Object.values(injection).forEach((filePathes: string[]) => {
|
|
276
|
+
filePathes.forEach((filePath) => {
|
|
277
|
+
if (!customResourceComponents.includes(filePath)) {
|
|
278
|
+
customResourceComponents.push(filePath);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
|
|
276
285
|
});
|
|
277
286
|
|
|
278
287
|
customResourceComponents.forEach((filePath) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
3
|
|
|
4
|
+
<component
|
|
5
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.beforeBreadcrumbs || []"
|
|
6
|
+
:is="getCustomComponent(c)"
|
|
7
|
+
:record="coreStore.record"
|
|
8
|
+
:columns="coreStore.resourceColumns"
|
|
9
|
+
:adminUser="coreStore.adminUser"
|
|
10
|
+
/>
|
|
11
|
+
|
|
4
12
|
<BreadcrumbsWithButtons>
|
|
5
13
|
<!-- save and cancle -->
|
|
6
14
|
<button @click="$router.back()"
|
|
@@ -22,6 +30,14 @@
|
|
|
22
30
|
|
|
23
31
|
</BreadcrumbsWithButtons>
|
|
24
32
|
|
|
33
|
+
<component
|
|
34
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.afterBreadcrumbs || []"
|
|
35
|
+
:is="getCustomComponent(c)"
|
|
36
|
+
:record="coreStore.record"
|
|
37
|
+
:columns="coreStore.resourceColumns"
|
|
38
|
+
:adminUser="coreStore.adminUser"
|
|
39
|
+
/>
|
|
40
|
+
|
|
25
41
|
<SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
|
|
26
42
|
|
|
27
43
|
|
|
@@ -36,6 +52,13 @@
|
|
|
36
52
|
>
|
|
37
53
|
</ResourceForm>
|
|
38
54
|
|
|
55
|
+
<component
|
|
56
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.bottom || []"
|
|
57
|
+
:is="getCustomComponent(c)"
|
|
58
|
+
:record="coreStore.record"
|
|
59
|
+
:columns="coreStore.resourceColumns"
|
|
60
|
+
:adminUser="coreStore.adminUser"
|
|
61
|
+
/>
|
|
39
62
|
|
|
40
63
|
</div>
|
|
41
64
|
</template>
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
+
<component
|
|
4
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.beforeBreadcrumbs || []"
|
|
5
|
+
:is="getCustomComponent(c)"
|
|
6
|
+
:record="coreStore.record"
|
|
7
|
+
:columns="coreStore.resourceColumns"
|
|
8
|
+
:adminUser="coreStore.adminUser"
|
|
9
|
+
/>
|
|
3
10
|
|
|
4
11
|
<BreadcrumbsWithButtons>
|
|
5
12
|
<!-- save and cancle -->
|
|
@@ -19,6 +26,14 @@
|
|
|
19
26
|
|
|
20
27
|
</BreadcrumbsWithButtons>
|
|
21
28
|
|
|
29
|
+
<component
|
|
30
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.afterBreadcrumbs || []"
|
|
31
|
+
:is="getCustomComponent(c)"
|
|
32
|
+
:record="coreStore.record"
|
|
33
|
+
:columns="coreStore.resourceColumns"
|
|
34
|
+
:adminUser="coreStore.adminUser"
|
|
35
|
+
/>
|
|
36
|
+
|
|
22
37
|
<SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
|
|
23
38
|
|
|
24
39
|
<ResourceForm
|
|
@@ -31,6 +46,15 @@
|
|
|
31
46
|
:customComponentsPerColumn="editComponentsPerColumn"
|
|
32
47
|
>
|
|
33
48
|
</ResourceForm>
|
|
49
|
+
|
|
50
|
+
<component
|
|
51
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.bottom || []"
|
|
52
|
+
:is="getCustomComponent(c)"
|
|
53
|
+
:record="coreStore.record"
|
|
54
|
+
:columns="coreStore.resourceColumns"
|
|
55
|
+
:adminUser="coreStore.adminUser"
|
|
56
|
+
/>
|
|
57
|
+
|
|
34
58
|
</div>
|
|
35
59
|
</template>
|
|
36
60
|
|
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
/>
|
|
10
10
|
</Teleport>
|
|
11
11
|
|
|
12
|
+
<component
|
|
13
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.beforeBreadcrumbs || []"
|
|
14
|
+
:is="getCustomComponent(c)"
|
|
15
|
+
:record="coreStore.record"
|
|
16
|
+
:columns="coreStore.resourceColumns"
|
|
17
|
+
:adminUser="coreStore.adminUser"
|
|
18
|
+
/>
|
|
19
|
+
|
|
12
20
|
<BreadcrumbsWithButtons>
|
|
13
21
|
<button
|
|
14
22
|
@click="()=>{checkboxes = []}"
|
|
@@ -64,6 +72,14 @@
|
|
|
64
72
|
</button>
|
|
65
73
|
</BreadcrumbsWithButtons>
|
|
66
74
|
|
|
75
|
+
<component
|
|
76
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.afterBreadcrumbs || []"
|
|
77
|
+
:is="getCustomComponent(c)"
|
|
78
|
+
:record="coreStore.record"
|
|
79
|
+
:columns="coreStore.resourceColumns"
|
|
80
|
+
:adminUser="coreStore.adminUser"
|
|
81
|
+
/>
|
|
82
|
+
|
|
67
83
|
<!-- table -->
|
|
68
84
|
<div class="relative overflow-x-auto shadow-list-table-shadow dark:shadow-black overflow-y-hidden rounded-default">
|
|
69
85
|
|
|
@@ -260,8 +276,7 @@
|
|
|
260
276
|
</div>
|
|
261
277
|
<!-- pagination -->
|
|
262
278
|
<div class="flex flex-col items-center mt-4 xs:flex-row xs:justify-between xs:items-center"
|
|
263
|
-
v-if="rows && totalRows >= pageSize && totalRows > 0"
|
|
264
|
-
>
|
|
279
|
+
v-if="rows && totalRows >= pageSize && totalRows > 0">
|
|
265
280
|
<!-- Help text -->
|
|
266
281
|
<span class="text-sm text-gray-700 dark:text-gray-400">
|
|
267
282
|
Showing <span class="font-semibold text-gray-900 dark:text-white">
|
|
@@ -313,6 +328,15 @@
|
|
|
313
328
|
</button>
|
|
314
329
|
</div>
|
|
315
330
|
</div>
|
|
331
|
+
|
|
332
|
+
<component
|
|
333
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.list?.bottom || []"
|
|
334
|
+
:is="getCustomComponent(c)"
|
|
335
|
+
:record="coreStore.record"
|
|
336
|
+
:columns="coreStore.resourceColumns"
|
|
337
|
+
:adminUser="coreStore.adminUser"
|
|
338
|
+
/>
|
|
339
|
+
|
|
316
340
|
</div>
|
|
317
341
|
</template>
|
|
318
342
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
+
<component
|
|
4
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.beforeBreadcrumbs || []"
|
|
5
|
+
:is="getCustomComponent(c)"
|
|
6
|
+
:record="coreStore.record"
|
|
7
|
+
:columns="coreStore.resourceColumns"
|
|
8
|
+
:adminUser="coreStore.adminUser"
|
|
9
|
+
/>
|
|
3
10
|
<BreadcrumbsWithButtons>
|
|
4
11
|
<RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
5
12
|
class="flex items-center py-1 px-3 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
@@ -16,6 +23,14 @@
|
|
|
16
23
|
</button>
|
|
17
24
|
</BreadcrumbsWithButtons>
|
|
18
25
|
|
|
26
|
+
<component
|
|
27
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
28
|
+
:is="getCustomComponent(c)"
|
|
29
|
+
:record="coreStore.record"
|
|
30
|
+
:columns="coreStore.resourceColumns"
|
|
31
|
+
:adminUser="coreStore.adminUser"
|
|
32
|
+
/>
|
|
33
|
+
|
|
19
34
|
<div v-if="loading" role="status" class="max-w-sm animate-pulse">
|
|
20
35
|
<div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4"></div>
|
|
21
36
|
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
|
|
@@ -70,6 +85,14 @@
|
|
|
70
85
|
</tr>
|
|
71
86
|
</tbody>
|
|
72
87
|
</table>
|
|
88
|
+
|
|
89
|
+
<component
|
|
90
|
+
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
91
|
+
:is="getCustomComponent(c)"
|
|
92
|
+
:record="coreStore.record"
|
|
93
|
+
:columns="coreStore.resourceColumns"
|
|
94
|
+
:adminUser="coreStore.adminUser"
|
|
95
|
+
/>
|
|
73
96
|
</div>
|
|
74
97
|
|
|
75
98
|
|
|
@@ -19,17 +19,130 @@ export interface AdminForthPluginType {
|
|
|
19
19
|
componentPath(componentFile: string): string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
export enum AdminForthMenuType {
|
|
23
|
+
/**
|
|
24
|
+
* HEADING is just a label in the menu.
|
|
25
|
+
* Respect `label` and `icon` property in @AdminForthConfigMenuItem
|
|
26
|
+
*/
|
|
27
|
+
HEADING = 'heading',
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* GROUP is a group of menu items.
|
|
31
|
+
* Respects `label`, `icon` and `children` properties in @AdminForthConfigMenuItem
|
|
32
|
+
* use @AdminForthMenuType.open to set if group is open by default
|
|
33
|
+
*/
|
|
34
|
+
GROUP = 'group',
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* RESOURCE is a link to a resource.
|
|
38
|
+
* Respects `label`, `icon`, `resourceId`, `homepage`, `isStaticRoute` properties in @AdminForthConfigMenuItem
|
|
39
|
+
*/
|
|
40
|
+
RESOURCE = 'resource',
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* PAGE is a link to a custom page.
|
|
44
|
+
* Respects `label`, `icon`, `path`, `component`, `homepage`, `isStaticRoute`, properties in @AdminForthConfigMenuItem
|
|
45
|
+
*
|
|
46
|
+
* Example:
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* {
|
|
50
|
+
* type: AdminForthMenuType.PAGE,
|
|
51
|
+
* label: 'Custom Page',
|
|
52
|
+
* icon: 'home',
|
|
53
|
+
* path: '/dash',
|
|
54
|
+
* component: '@@/Dashboard.vue',
|
|
55
|
+
* homepage: true,
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
PAGE = 'page',
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* GAP ads some space between menu items.
|
|
64
|
+
*/
|
|
65
|
+
GAP = 'gap',
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* DIVIDER is a divider between menu items.
|
|
69
|
+
*/
|
|
70
|
+
DIVIDER = 'divider',
|
|
71
|
+
}
|
|
72
|
+
|
|
22
73
|
export type AdminForthConfigMenuItem = {
|
|
23
|
-
type?:
|
|
74
|
+
type?: AdminForthMenuType,
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Label for menu item which will be displayed in the admin panel.
|
|
78
|
+
*/
|
|
24
79
|
label?: string,
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Icon for menu item which will be displayed in the admin panel.
|
|
83
|
+
* Supports iconify icons in format `<icon set name>:<icon name>`
|
|
84
|
+
* Browse available icons here: https://icon-sets.iconify.design/
|
|
85
|
+
*
|
|
86
|
+
* Example:
|
|
87
|
+
*
|
|
88
|
+
* ```ts
|
|
89
|
+
* icon: 'flowbite:brain-solid',
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
*/
|
|
25
93
|
icon?: string,
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Path to custom component which will be displayed in the admin panel.
|
|
97
|
+
*
|
|
98
|
+
*/
|
|
26
99
|
path?: string,
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Component to be used for this menu item. Component should be placed in custom folder and referenced with `@@/` prefix.
|
|
103
|
+
* Supported for AdminForthMenuType.PAGE only!
|
|
104
|
+
* Example:
|
|
105
|
+
*
|
|
106
|
+
* ```ts
|
|
107
|
+
* component: '@@/Dashboard.vue',
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
*/
|
|
27
111
|
component?: string,
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resource ID which will be used to fetch data from.
|
|
115
|
+
* Supported for AdminForthMenuType.RESOURCE only!
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
28
118
|
resourceId?: string,
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* If true, group will be open by default after user login to the admin panel.
|
|
122
|
+
* Also will be used to redirect from root path.
|
|
123
|
+
*/
|
|
29
124
|
homepage?: boolean,
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Where Group is open by default
|
|
128
|
+
* Supported for AdminForthMenuType.GROUP only!
|
|
129
|
+
*
|
|
130
|
+
* */
|
|
30
131
|
open?: boolean,
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Children menu items which will be displayed in this group.
|
|
135
|
+
* Supported for AdminForthMenuType.GROUP only!
|
|
136
|
+
*/
|
|
31
137
|
children?: Array<AdminForthConfigMenuItem>,
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* By default all pages are imported dynamically with lazy import().
|
|
141
|
+
* If you wish to import page statically, set this option to true.
|
|
142
|
+
* Homepage will be imported statically by default. but you can override it with this option.
|
|
143
|
+
*/
|
|
32
144
|
isStaticRoute?: boolean,
|
|
145
|
+
|
|
33
146
|
meta?: {
|
|
34
147
|
title?: string,
|
|
35
148
|
},
|
|
@@ -148,7 +261,50 @@ export type AdminForthResource = {
|
|
|
148
261
|
id?: string,
|
|
149
262
|
}>,
|
|
150
263
|
allowedActions?: AllowedActions,
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Page size for list view
|
|
267
|
+
*/
|
|
151
268
|
listPageSize?: number,
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Custom components which can be injected into AdminForth CRUD pages.
|
|
272
|
+
* Each injection is a path to a custom component which will be displayed in the admin panel.
|
|
273
|
+
* Can be also array to render multiple injections one after another.
|
|
274
|
+
*
|
|
275
|
+
* Example:
|
|
276
|
+
*
|
|
277
|
+
* ```ts
|
|
278
|
+
* pageInjections: {
|
|
279
|
+
* list: {
|
|
280
|
+
* beforeBreadcrumbs: '@@/Announcement.vue',
|
|
281
|
+
* }
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
*/
|
|
286
|
+
pageInjections?: {
|
|
287
|
+
list?: {
|
|
288
|
+
beforeBreadcrumbs?: string | Array<string>,
|
|
289
|
+
afterBreadcrumbs?: string | Array<string>,
|
|
290
|
+
bottom?: string | Array<string>,
|
|
291
|
+
},
|
|
292
|
+
show?: {
|
|
293
|
+
beforeBreadcrumbs?: string | Array<string>,
|
|
294
|
+
afterBreadcrumbs?: string | Array<string>,
|
|
295
|
+
bottom?: string | Array<string>,
|
|
296
|
+
},
|
|
297
|
+
edit?: {
|
|
298
|
+
beforeBreadcrumbs?: string | Array<string>,
|
|
299
|
+
afterBreadcrumbs?: string | Array<string>,
|
|
300
|
+
bottom?: string | Array<string>,
|
|
301
|
+
},
|
|
302
|
+
create?: {
|
|
303
|
+
beforeBreadcrumbs?: string | Array<string>,
|
|
304
|
+
afterBreadcrumbs?: string | Array<string>,
|
|
305
|
+
bottom?: string | Array<string>,
|
|
306
|
+
},
|
|
307
|
+
}
|
|
152
308
|
},
|
|
153
309
|
}
|
|
154
310
|
|
|
@@ -301,6 +457,7 @@ export type AdminForthConfig = {
|
|
|
301
457
|
* component: {
|
|
302
458
|
* show: '@@/comp/my.vue',
|
|
303
459
|
* }
|
|
460
|
+
* ```
|
|
304
461
|
*
|
|
305
462
|
*/
|
|
306
463
|
customComponentsDir?: string,
|
|
Binary file
|
|
File without changes
|