adminforth 1.0.82 → 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 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, _k;
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 ((_d = this.adminforth.config.customization) === null || _d === void 0 ? void 0 : _d.vueUsesFile) {
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 ((_e = this.adminforth.config.customization) === null || _e === void 0 ? void 0 : _e.vueUsesFile) {
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 ((_f = this.adminforth.config) === null || _f === void 0 ? void 0 : _f.styles) {
287
- const tailwindStyles = (_g = this.adminforth.config) === null || _g === void 0 ? void 0 : _g.styles;
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 = (_h = childrenHomePageMenuItem === null || childrenHomePageMenuItem === void 0 ? void 0 : childrenHomePageMenuItem.children) === null || _h === void 0 ? void 0 : _h.find((mi) => mi.homepage);
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 = ((_j = this.adminforth.config.menu.filter((mi) => mi.path)[0]) === null || _j === void 0 ? void 0 : _j.path) || `/resource/${(_k = this.adminforth.config.menu.filter((mi) => mi.children)[0]) === null || _k === void 0 ? void 0 : _k.resourceId}`;
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.devforth.io',
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: {
@@ -114,6 +114,10 @@ const config: Config = {
114
114
  label: 'Tutorial',
115
115
  to: '/docs/Getting%20Started',
116
116
  },
117
+ {
118
+ label: 'API',
119
+ to: '/docs/api',
120
+ },
117
121
  ],
118
122
  },
119
123
  // {
@@ -158,7 +162,7 @@ const config: Config = {
158
162
  copyright: `Copyright © ${new Date().getFullYear()} Devforth sp. z o.o.`,
159
163
  },
160
164
  prism: {
161
- theme: prismThemes.vsLight,
165
+ theme: prismThemes.okaidia,
162
166
  darkTheme: prismThemes.dracula,
163
167
  },
164
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
@@ -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,13 +1,13 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.0.82",
3
+ "version": "1.0.84",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "test": "echo \"Error: no test specified\" && exit 1",
9
9
  "build": "tsc",
10
- "rollout": "tsc && cp -r spa dist/spa && npm version patch && npm publish && cd documentation && npm run deploy",
10
+ "rollout": "tsc && cp -r spa dist/spa && npm version patch && npm publish && cd documentation && npm run build && npm run deploy",
11
11
  "docs": "typedoc"
12
12
  },
13
13
  "author": "devforth.io",
@@ -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?: 'heading' | 'group' | 'resource' | 'page' | 'gap' | 'divider',
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,
File without changes