adminforth 2.0.7-next.3 → 2.1.0-next.10

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.
Files changed (51) hide show
  1. package/commands/bundle.js +1 -1
  2. package/commands/cli.js +4 -0
  3. package/commands/createApp/templates/Dockerfile.hbs +1 -1
  4. package/commands/createCustomComponent/configUpdater.js +135 -74
  5. package/commands/createCustomComponent/main.js +12 -2
  6. package/commands/createCustomComponent/templates/customCrud/afterBreadcrumbs.vue.hbs +9 -1
  7. package/commands/createCustomComponent/templates/customCrud/beforeBreadcrumbs.vue.hbs +9 -1
  8. package/commands/createCustomComponent/templates/customCrud/bottom.vue.hbs +27 -50
  9. package/commands/createCustomComponent/templates/customCrud/threeDotsDropdownItems.vue.hbs +10 -21
  10. package/commands/createCustomComponent/templates/customFields/list.vue.hbs +16 -10
  11. package/commands/createCustomComponent/templates/customFields/show.vue.hbs +16 -10
  12. package/commands/createCustomComponent/templates/global/everyPageBottom.vue.hbs +10 -4
  13. package/commands/createCustomComponent/templates/global/header.vue.hbs +10 -4
  14. package/commands/createCustomComponent/templates/global/sidebar.vue.hbs +10 -4
  15. package/commands/createCustomComponent/templates/global/userMenu.vue.hbs +10 -4
  16. package/commands/createCustomComponent/templates/login/afterLogin.vue.hbs +10 -4
  17. package/commands/createResource/generateResourceFile.js +47 -0
  18. package/commands/createResource/injectResourceIntoIndex.js +113 -0
  19. package/commands/createResource/main.js +53 -0
  20. package/commands/createResource/templates/resource.ts.hbs +19 -0
  21. package/commands/utils.js +26 -0
  22. package/dist/dataConnectors/baseConnector.d.ts +2 -0
  23. package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
  24. package/dist/dataConnectors/baseConnector.js +6 -0
  25. package/dist/dataConnectors/baseConnector.js.map +1 -1
  26. package/dist/dataConnectors/sqlite.d.ts +2 -0
  27. package/dist/dataConnectors/sqlite.d.ts.map +1 -1
  28. package/dist/dataConnectors/sqlite.js +10 -0
  29. package/dist/dataConnectors/sqlite.js.map +1 -1
  30. package/dist/index.d.ts +7 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +57 -3
  33. package/dist/index.js.map +1 -1
  34. package/dist/modules/codeInjector.js +1 -1
  35. package/dist/modules/codeInjector.js.map +1 -1
  36. package/dist/modules/filtersTools.d.ts +13 -0
  37. package/dist/modules/filtersTools.d.ts.map +1 -0
  38. package/dist/modules/filtersTools.js +32 -0
  39. package/dist/modules/filtersTools.js.map +1 -0
  40. package/dist/modules/restApi.d.ts.map +1 -1
  41. package/dist/modules/restApi.js +7 -0
  42. package/dist/modules/restApi.js.map +1 -1
  43. package/dist/spa/src/components/MenuLink.vue +5 -4
  44. package/dist/spa/src/stores/core.ts +3 -1
  45. package/dist/spa/src/types/Back.ts +33 -4
  46. package/dist/spa/src/views/EditView.vue +10 -1
  47. package/dist/types/Back.d.ts +10 -2
  48. package/dist/types/Back.d.ts.map +1 -1
  49. package/dist/types/Back.js +17 -5
  50. package/dist/types/Back.js.map +1 -1
  51. package/package.json +1 -1
@@ -16,7 +16,7 @@ async function bundle() {
16
16
  `);
17
17
 
18
18
  } catch (e) {
19
- console.log(`Running file ${file} failed`, e);
19
+ console.log(`Running budndle failed`, e);
20
20
  }
21
21
  }
22
22
 
package/commands/cli.js CHANGED
@@ -8,6 +8,7 @@ import createApp from "./createApp/main.js";
8
8
  import generateModels from "./generateModels.js";
9
9
  import createPlugin from "./createPlugin/main.js";
10
10
  import createComponent from "./createCustomComponent/main.js";
11
+ import createResource from "./createResource/main.js";
11
12
  import chalk from "chalk";
12
13
  import path from "path";
13
14
  import fs from "fs";
@@ -58,6 +59,9 @@ switch (command) {
58
59
  case "component":
59
60
  createComponent(args);
60
61
  break;
62
+ case "resource":
63
+ createResource(args);
64
+ break;
61
65
  case "help":
62
66
  case "--help":
63
67
  case "-h":
@@ -3,5 +3,5 @@ WORKDIR /code/
3
3
  ADD package.json package-lock.json /code/
4
4
  RUN npm ci
5
5
  ADD . /code/
6
- RUN --mount=type=cache,target=/tmp npx adminforth bundle
6
+ RUN npx adminforth bundle
7
7
  CMD ["sh", "-c", "npm run migrate:prod && npm run prod"]
@@ -26,7 +26,6 @@ async function findResourceFilePath(resourceId) {
26
26
  throw new Error(`Failed to read resources directory ${resourcesDir}: ${error.message}`);
27
27
  }
28
28
 
29
- console.log(chalk.dim(`Found .ts files to scan: ${tsFiles.join(', ') || 'None'}`));
30
29
 
31
30
  for (const file of tsFiles) {
32
31
  const filePath = path.resolve(resourcesDir, file);
@@ -94,6 +93,7 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
94
93
  console.log(chalk.dim(`Attempting to update resource config: ${filePath}`));
95
94
 
96
95
  let content;
96
+ let injectionLine = null;
97
97
  try {
98
98
  content = await fs.readFile(filePath, 'utf-8');
99
99
  } catch (error) {
@@ -176,11 +176,16 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
176
176
  const newComponentValue = b.stringLiteral(componentPathForConfig);
177
177
 
178
178
  if (fieldTypeProperty) {
179
+ injectionLine = fieldTypeProperty.loc?.start.line ?? null;
179
180
  fieldTypeProperty.value = newComponentValue;
180
181
  console.log(chalk.dim(`Updated '${fieldType}' component path in column '${columnName}'.`));
181
182
  } else {
182
183
  fieldTypeProperty = b.objectProperty(b.identifier(fieldType), newComponentValue);
183
184
  componentsObject.properties.push(fieldTypeProperty);
185
+ fieldTypeProperty = componentsObject.properties.find(p =>
186
+ n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === fieldType
187
+ );
188
+ injectionLine = fieldTypeProperty.loc?.start.line ?? null;
184
189
  console.log(chalk.dim(`Added '${fieldType}' component path to column '${columnName}'.`));
185
190
  }
186
191
 
@@ -197,7 +202,12 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
197
202
  const outputCode = recast.print(ast).code;
198
203
 
199
204
  await fs.writeFile(filePath, outputCode, 'utf-8');
200
- console.log(chalk.dim(`Successfully updated resource configuration file (preserving formatting): ${filePath}`));
205
+ console.log(
206
+ chalk.green(
207
+ `✅ Successfully updated CRUD injection in resource file: ${filePath}` +
208
+ (injectionLine !== null ? `:${injectionLine}` : '')
209
+ )
210
+ );
201
211
 
202
212
  } catch (error) {
203
213
  console.error(chalk.red(`❌ Error processing resource file: ${filePath}`));
@@ -211,78 +221,106 @@ export async function injectLoginComponent(indexFilePath, componentPath) {
211
221
  console.log(chalk.dim(`Reading file: ${indexFilePath}`));
212
222
  const content = await fs.readFile(indexFilePath, 'utf-8');
213
223
  const ast = recast.parse(content, {
214
- parser: typescriptParser,
224
+ parser: typescriptParser,
215
225
  });
216
-
226
+
217
227
  let updated = false;
218
-
228
+ let injectionLine = null;
229
+
219
230
  recast.visit(ast, {
220
- visitNewExpression(path) {
221
- if (
222
- n.Identifier.check(path.node.callee) &&
223
- path.node.callee.name === 'AdminForth' &&
224
- path.node.arguments.length > 0 &&
225
- n.ObjectExpression.check(path.node.arguments[0])
226
- ) {
227
- const configObject = path.node.arguments[0];
228
-
229
- let customizationProp = configObject.properties.find(
230
- p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === 'customization'
231
- );
232
-
233
- if (!customizationProp) {
234
- const customizationObj = b.objectExpression([]);
235
- customizationProp = b.objectProperty(b.identifier('customization'), customizationObj);
236
- configObject.properties.push(customizationProp);
237
- console.log(chalk.dim(`Added missing 'customization' property.`));
238
- }
239
-
240
- const customizationValue = customizationProp.value;
241
- if (!n.ObjectExpression.check(customizationValue)) return false;
242
-
243
- let loginPageInjections = customizationValue.properties.find(
244
- p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === 'loginPageInjections'
245
- );
246
-
247
- if (!loginPageInjections) {
248
- const injectionsObj = b.objectExpression([]);
249
- loginPageInjections = b.objectProperty(b.identifier('loginPageInjections'), injectionsObj);
250
- customizationValue.properties.push(loginPageInjections);
251
- console.log(chalk.dim(`Added missing 'loginPageInjections'.`));
252
- }
253
-
254
- const injectionsValue = loginPageInjections.value;
255
- if (!n.ObjectExpression.check(injectionsValue)) return false;
256
-
257
- let underInputsProp = injectionsValue.properties.find(
258
- p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === 'underInputs'
259
- );
260
-
261
- if (underInputsProp) {
262
- underInputsProp.value = b.stringLiteral(componentPath);
263
- console.log(chalk.dim(`Updated 'underInputs' to ${componentPath}`));
264
- } else {
265
- injectionsValue.properties.push(
266
- b.objectProperty(b.identifier('underInputs'), b.stringLiteral(componentPath))
267
- );
268
- console.log(chalk.dim(`Added 'underInputs': ${componentPath}`));
269
- }
270
-
271
- updated = true;
272
- this.abort();
231
+ visitNewExpression(path) {
232
+ if (
233
+ n.Identifier.check(path.node.callee) &&
234
+ path.node.callee.name === 'AdminForth' &&
235
+ path.node.arguments.length > 0 &&
236
+ n.ObjectExpression.check(path.node.arguments[0])
237
+ ) {
238
+ const configObject = path.node.arguments[0];
239
+
240
+ const getOrCreateProp = (obj, name) => {
241
+ let prop = obj.properties.find(
242
+ p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === name
243
+ );
244
+ if (!prop) {
245
+ const newObj = b.objectExpression([]);
246
+ prop = b.objectProperty(b.identifier(name), newObj);
247
+ obj.properties.push(prop);
248
+ console.log(chalk.dim(`Added missing '${name}' property.`));
273
249
  }
274
- return false;
250
+ return prop.value;
251
+ };
252
+
253
+ const customization = getOrCreateProp(configObject, 'customization');
254
+ if (!n.ObjectExpression.check(customization)) return false;
255
+
256
+ const loginPageInjections = getOrCreateProp(customization, 'loginPageInjections');
257
+ if (!n.ObjectExpression.check(loginPageInjections)) return false;
258
+
259
+ let underInputsProp = loginPageInjections.properties.find(
260
+ p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === 'underInputs'
261
+ );
262
+
263
+ if (underInputsProp) {
264
+ const currentVal = underInputsProp.value;
265
+ injectionLine = underInputsProp.loc?.start.line ?? null;
266
+ if (n.StringLiteral.check(currentVal)) {
267
+ if (currentVal.value !== componentPath) {
268
+ underInputsProp.value = b.arrayExpression([
269
+ b.stringLiteral(currentVal.value),
270
+ b.stringLiteral(componentPath),
271
+ ]);
272
+ console.log(chalk.dim(`Converted 'underInputs' to array with existing + new path.`));
273
+ } else {
274
+ console.log(chalk.dim(`Component path already present as string. Skipping.`));
275
+ }
276
+ } else if (n.ArrayExpression.check(currentVal)) {
277
+ const exists = currentVal.elements.some(
278
+ el => n.StringLiteral.check(el) && el.value === componentPath
279
+ );
280
+ if (!exists) {
281
+ currentVal.elements.push(b.stringLiteral(componentPath));
282
+ console.log(chalk.dim(`Appended new component path to existing 'underInputs' array.`));
283
+ } else {
284
+ console.log(chalk.dim(`Component path already present in array. Skipping.`));
285
+ }
286
+ } else {
287
+ console.warn(chalk.yellow(`⚠️ 'underInputs' is not a string or array. Skipping.`));
288
+ return false;
289
+ }
290
+ } else {
291
+ const newProperty = b.objectProperty(
292
+ b.identifier('underInputs'),
293
+ b.stringLiteral(componentPath)
294
+ );
295
+
296
+ if (newProperty.loc) {
297
+ console.log(chalk.dim(`Adding 'underInputs' at line: ${newProperty.loc.start.line}`));
298
+ }
299
+
300
+ loginPageInjections.properties.push(newProperty);
301
+ console.log(chalk.dim(`Added 'underInputs': ${componentPath}`));
302
+ }
303
+
304
+ updated = true;
305
+ this.abort();
275
306
  }
307
+ return false;
308
+ }
276
309
  });
277
-
310
+
278
311
  if (!updated) {
279
- throw new Error(`Could not find AdminForth configuration in file: ${indexFilePath}`);
312
+ throw new Error(`Could not find AdminForth configuration in file: ${indexFilePath}`);
280
313
  }
281
-
314
+
282
315
  const outputCode = recast.print(ast).code;
283
316
  await fs.writeFile(indexFilePath, outputCode, 'utf-8');
284
- console.log(chalk.green(`✅ Successfully updated login injection in: ${indexFilePath}`));
285
- }
317
+ console.log(
318
+ chalk.green(
319
+ `✅ Successfully updated CRUD injection in resource file: ${indexFilePath}` +
320
+ (injectionLine !== null ? `:${injectionLine}` : '')
321
+ )
322
+ );
323
+ }
286
324
 
287
325
 
288
326
  export async function injectGlobalComponent(indexFilePath, injectionType, componentPath) {
@@ -293,7 +331,7 @@ export async function injectGlobalComponent(indexFilePath, injectionType, compon
293
331
  });
294
332
 
295
333
  let updated = false;
296
-
334
+ let injectionLine = null;
297
335
  console.log(JSON.stringify(injectionType));
298
336
  recast.visit(ast, {
299
337
  visitNewExpression(path) {
@@ -315,7 +353,7 @@ export async function injectGlobalComponent(indexFilePath, injectionType, compon
315
353
  configObject.properties.push(customizationProp);
316
354
  console.log(chalk.dim(`Added missing 'customization' property.`));
317
355
  }
318
-
356
+
319
357
  const customizationValue = customizationProp.value;
320
358
  if (!n.ObjectExpression.check(customizationValue)) return false;
321
359
 
@@ -338,7 +376,7 @@ export async function injectGlobalComponent(indexFilePath, injectionType, compon
338
376
  );
339
377
  if (injectionProp) {
340
378
  const currentValue = injectionProp.value;
341
-
379
+ injectionLine = injectionProp.loc?.start.line ?? null;
342
380
  if (n.ArrayExpression.check(currentValue)) {
343
381
  currentValue.elements.push(b.stringLiteral(componentPath));
344
382
  console.log(chalk.dim(`Added '${componentPath}' to existing array in '${injectionType}'`));
@@ -374,7 +412,12 @@ export async function injectGlobalComponent(indexFilePath, injectionType, compon
374
412
 
375
413
  const outputCode = recast.print(ast).code;
376
414
  await fs.writeFile(indexFilePath, outputCode, 'utf-8');
377
- console.log(chalk.green(`✅ Successfully updated global injection '${injectionType}' in: ${indexFilePath}`));
415
+ console.log(
416
+ chalk.green(
417
+ `✅ Successfully updated CRUD injection in resource file: ${indexFilePath}` +
418
+ (injectionLine !== null ? `:${injectionLine}` : '')
419
+ )
420
+ );
378
421
  }
379
422
 
380
423
  export async function updateCrudInjectionConfig(resourceId, crudType, injectionPosition, componentPathForConfig, isThin) {
@@ -382,6 +425,7 @@ export async function updateCrudInjectionConfig(resourceId, crudType, injectionP
382
425
  console.log(chalk.dim(`Attempting to update resource CRUD injection: ${filePath}`));
383
426
 
384
427
  let content;
428
+ let injectionLine = null;
385
429
  try {
386
430
  content = await fs.readFile(filePath, 'utf-8');
387
431
  } catch (error) {
@@ -439,7 +483,7 @@ export async function updateCrudInjectionConfig(resourceId, crudType, injectionP
439
483
  );
440
484
  pageInjections.properties.push(crudProp);
441
485
  }
442
-
486
+ injectionLine = crudProp.loc?.start.line ?? null;
443
487
  const crudValue = crudProp.value;
444
488
  if (!n.ObjectExpression.check(crudValue)) return false;
445
489
 
@@ -458,11 +502,23 @@ export async function updateCrudInjectionConfig(resourceId, crudType, injectionP
458
502
  ]);
459
503
 
460
504
  if (injectionProp) {
461
- injectionProp.value = newInjectionObject;
462
- console.log(chalk.dim(`Updated '${injectionPosition}' injection for '${crudType}'.`));
505
+ if (n.ArrayExpression.check(injectionProp.value)) {
506
+ injectionProp.value.elements.push(newInjectionObject);
507
+ console.log(chalk.dim(`Appended new injection to array at '${injectionPosition}' for '${crudType}'.`));
508
+ }
509
+ else if (n.ObjectExpression.check(injectionProp.value)) {
510
+ injectionProp.value = b.arrayExpression([injectionProp.value, newInjectionObject]);
511
+ console.log(chalk.dim(`Converted to array and added new injection at '${injectionPosition}' for '${crudType}'.`));
512
+ }
513
+ else {
514
+ injectionProp.value = b.arrayExpression([newInjectionObject]);
515
+ console.log(chalk.yellow(`⚠️ Replaced invalid injection at '${injectionPosition}' with array.`));
516
+ }
463
517
  } else {
464
- crudValue.properties.push(b.objectProperty(b.identifier(injectionPosition), newInjectionObject));
465
- console.log(chalk.dim(`Added '${injectionPosition}' injection for '${crudType}'.`));
518
+ crudValue.properties.push(
519
+ b.objectProperty(b.identifier(injectionPosition), b.arrayExpression([newInjectionObject]))
520
+ );
521
+ console.log(chalk.dim(`Added new array of injections at '${injectionPosition}' for '${crudType}'.`));
466
522
  }
467
523
 
468
524
  updateApplied = true;
@@ -477,7 +533,12 @@ export async function updateCrudInjectionConfig(resourceId, crudType, injectionP
477
533
 
478
534
  const outputCode = recast.print(ast).code;
479
535
  await fs.writeFile(filePath, outputCode, 'utf-8');
480
- console.log(chalk.dim(`✅ Successfully updated CRUD injection in resource file: ${filePath}`));
536
+ console.log(
537
+ chalk.green(
538
+ `✅ Successfully updated CRUD injection in resource file: ${filePath}` +
539
+ (injectionLine !== null ? `:${injectionLine}` : '')
540
+ )
541
+ );
481
542
 
482
543
  } catch (error) {
483
544
  console.error(chalk.red(`❌ Error processing resource file: ${filePath}`));
@@ -170,6 +170,14 @@ async function handleCrudPageInjectionCreation(config, resources) {
170
170
  });
171
171
  if (injectionPosition === '__BACK__') return handleCrudPageInjectionCreation(config, resources);
172
172
 
173
+ const additionalName = await input({
174
+ message: 'Enter additional name (optional, e.g., "CustomExport"):',
175
+ validate: (value) => {
176
+ if (!value) return true;
177
+ return /^[A-Za-z0-9_-]+$/.test(value) || 'Only alphanumeric characters, hyphens or underscores are allowed.';
178
+ },
179
+ });
180
+
173
181
  const isThin = await select({
174
182
  message: 'Will this component be thin enough to fit on the same page with list (so list will still shrink)?',
175
183
  choices: [
@@ -177,9 +185,11 @@ async function handleCrudPageInjectionCreation(config, resources) {
177
185
  { name: 'No', value: false },
178
186
  ],
179
187
  });
180
-
188
+ const formattedAdditionalName = additionalName
189
+ ? additionalName[0].toUpperCase() + additionalName.slice(1)
190
+ : '';
181
191
  const safeResourceLabel = sanitizeLabel(selectedResource.label)
182
- const componentFileName = `${safeResourceLabel}${crudType.charAt(0).toUpperCase() + crudType.slice(1)}${injectionPosition.charAt(0).toUpperCase() + injectionPosition.slice(1)}.vue`;
192
+ const componentFileName = `${safeResourceLabel}${crudType.charAt(0).toUpperCase() + crudType.slice(1)}${injectionPosition.charAt(0).toUpperCase() + injectionPosition.slice(1) + formattedAdditionalName}.vue`;
183
193
  const componentPathForConfig = `@@/${componentFileName}`;
184
194
 
185
195
  try {
@@ -5,7 +5,7 @@
5
5
  @click="handleClick"
6
6
  class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-800"
7
7
  >
8
- Example
8
+ \{{ $t('Example') }}
9
9
  </button>
10
10
  </div>
11
11
  </template>
@@ -14,9 +14,17 @@
14
14
  import { onMounted } from 'vue';
15
15
  import { useI18n } from 'vue-i18n';
16
16
  import adminforth from '@/adminforth';
17
+ import { AdminForthResourceCommon, AdminUser } from "@/types/Common";
17
18
 
18
19
  const { t } = useI18n();
19
20
 
21
+ const props = defineProps<{
22
+ record: any
23
+ resource: AdminForthResourceCommon
24
+ adminUser: AdminUser
25
+ meta?: any
26
+ }>();
27
+
20
28
  onMounted(() => {
21
29
  // Logic on mount if needed
22
30
  });
@@ -5,7 +5,7 @@
5
5
  @click="handleClick"
6
6
  class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-800"
7
7
  >
8
- Example
8
+ \{{ $t('Example') }}
9
9
  </button>
10
10
  </div>
11
11
  </template>
@@ -14,9 +14,17 @@
14
14
  import { onMounted } from 'vue';
15
15
  import { useI18n } from 'vue-i18n';
16
16
  import adminforth from '@/adminforth';
17
+ import { AdminForthResourceCommon, AdminUser } from "@/types/Common";
17
18
 
18
19
  const { t } = useI18n();
19
20
 
21
+ const props = defineProps<{
22
+ record: any
23
+ resource: AdminForthResourceCommon
24
+ adminUser: AdminUser
25
+ meta?: any
26
+ }>();
27
+
20
28
  onMounted(() => {
21
29
  // Logic on mount if needed
22
30
  });
@@ -1,61 +1,38 @@
1
1
  <template>
2
- <div class="overflow-auto p-4">
3
- <table class="min-w-full text-sm text-left text-gray-500 dark:text-gray-400">
4
- <thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
5
- <tr>
6
- <th scope="col" class="px-6 py-3" v-for="header in headers" :key="header">
7
- {{ header }}
8
- </th>
9
- </tr>
10
- </thead>
11
- <tbody>
12
- <tr
13
- v-for="row in rows"
14
- :key="row.id"
15
- class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600"
16
- >
17
- <td class="px-6 py-4" v-for="cell in row.cells" :key="cell">
18
- {{ cell }}
19
- </td>
20
- </tr>
21
- </tbody>
22
- </table>
2
+ <div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600">
3
+ <button
4
+ type="button"
5
+ @click="handleClick"
6
+ class="text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-800"
7
+ >
8
+ {{ $t('Example') }}
9
+ </button>
23
10
  </div>
24
11
  </template>
25
12
 
26
13
  <script setup lang="ts">
27
- import { onMounted, ref } from 'vue';
14
+ import { onMounted } from 'vue';
15
+ import { useI18n } from 'vue-i18n';
16
+ import adminforth from '@/adminforth';
17
+ import { AdminForthResourceCommon, AdminUser } from "@/types/Common";
28
18
 
29
- const headers = [
30
- 'ID',
31
- 'Name',
32
- 'Email',
33
- 'Phone',
34
- 'Address',
35
- 'City',
36
- 'Country',
37
- 'Company',
38
- 'Position',
39
- 'Status',
40
- ];
19
+ const { t } = useI18n();
41
20
 
42
- const rows = Array.from({ length: 50 }, (_, i) => ({
43
- id: i + 1,
44
- cells: [
45
- i + 1,
46
- `Name ${i + 1}`,
47
- `user${i + 1}@example.com`,
48
- `+1-555-010${i.toString().padStart(2, '0')}`,
49
- `Address ${i + 1}`,
50
- `City ${i + 1}`,
51
- `Country ${i + 1}`,
52
- `Company ${i + 1}`,
53
- `Position ${i + 1}`,
54
- i % 2 === 0 ? 'Active' : 'Inactive',
55
- ],
56
- }));
21
+ const props = defineProps<{
22
+ record: any
23
+ resource: AdminForthResourceCommon
24
+ adminUser: AdminUser
25
+ meta?: any
26
+ }>();
57
27
 
58
28
  onMounted(() => {
59
- console.log('Table mounted. Rows:', rows.length);
29
+ // Logic on mount if needed
60
30
  });
31
+
32
+ function handleClick() {
33
+ adminforth.alert({
34
+ message: t('Confirmed'),
35
+ variant: 'success',
36
+ });
37
+ }
61
38
  </script>
@@ -4,9 +4,8 @@
4
4
  v-for="item in menuItems"
5
5
  :key="item.label"
6
6
  @click="item.action"
7
- class="w-full text-left text-sm px-4 py-2 rounded hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"
8
7
  >
9
- {{ t(item.label) }}
8
+ \{{ item.label }}
10
9
  </button>
11
10
  </div>
12
11
  </template>
@@ -15,9 +14,17 @@
15
14
  import { useI18n } from 'vue-i18n';
16
15
  import adminforth from '@/adminforth';
17
16
  import { onMounted } from 'vue';
17
+ import { AdminForthResourceCommon, AdminUser } from "@/types/Common";
18
18
 
19
19
  const { t } = useI18n();
20
20
 
21
+ const props = defineProps<{
22
+ record: any
23
+ resource: AdminForthResourceCommon
24
+ adminUser: AdminUser
25
+ meta?: any
26
+ }>();
27
+
21
28
  const menuItems = [
22
29
  {
23
30
  label: 'Show Success Alert',
@@ -27,25 +34,7 @@ const menuItems = [
27
34
  variant: 'success',
28
35
  });
29
36
  },
30
- },
31
- {
32
- label: 'Show Warning Alert',
33
- action: () => {
34
- adminforth.alert({
35
- message: t('Warning Alert'),
36
- variant: 'warning',
37
- });
38
- },
39
- },
40
- {
41
- label: 'Show Error Alert',
42
- action: () => {
43
- adminforth.alert({
44
- message: t('Error Alert'),
45
- variant: 'danger',
46
- });
47
- },
48
- },
37
+ }
49
38
  ];
50
39
 
51
40
  onMounted(() => {
@@ -1,18 +1,24 @@
1
1
  <template>
2
- <div v-if='record[column.name]'
2
+ <div
3
3
  class="text-red-500"
4
- >\{{ record[column.name] }}</div>
4
+ >\{{ record[props.column.name] }}</div>
5
5
  </template>
6
6
 
7
- <script setup>
7
+ <script setup lang="ts">
8
8
 
9
- defineProps({
10
- record: Object,
11
- resource: Object,
12
- adminUser: Object,
13
- meta: Object,
14
- column: Object
15
- });
9
+ import type {
10
+ AdminForthResourceColumnCommon,
11
+ AdminForthResourceCommon,
12
+ AdminUser,
13
+ } from "@/types/Common";
14
+
15
+ const props = defineProps<{
16
+ column: AdminForthResourceColumnCommon;
17
+ record: any;
18
+ meta: any;
19
+ resource: AdminForthResourceCommon;
20
+ adminUser: AdminUser;
21
+ }>();
16
22
 
17
23
  </script>
18
24
 
@@ -1,17 +1,23 @@
1
1
  <template>
2
- <div v-if='record[column.name]'
2
+ <div
3
3
  class="text-red-500"
4
- >\{{ record[column.name] }}</div>
4
+ >\{{ record[props.column.name] }}</div>
5
5
  </template>
6
6
 
7
- <script setup>
7
+ <script setup lang="ts">
8
8
 
9
- defineProps({
10
- record: Object,
11
- resource: Object,
12
- adminUser: Object,
13
- meta: Object,
14
- column: Object
15
- });
9
+ import type {
10
+ AdminForthResourceColumnCommon,
11
+ AdminForthResourceCommon,
12
+ AdminUser,
13
+ } from "@/types/Common";
14
+
15
+ const props = defineProps<{
16
+ column: AdminForthResourceColumnCommon;
17
+ record: any;
18
+ meta: any;
19
+ resource: AdminForthResourceCommon;
20
+ adminUser: AdminUser;
21
+ }>();
16
22
 
17
23
  </script>
@@ -1,11 +1,17 @@
1
1
  <template>
2
2
  <div class="flex items-center justify-center text-gray-900 dark:text-gray-400 p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600">
3
- {{reason}}
3
+ Page Bottom Text
4
4
  </div>
5
5
  </template>
6
6
 
7
7
  <script setup>
8
- defineProps({
9
- reason: String
10
- });
8
+ import { onMounted } from 'vue';
9
+
10
+ const props = defineProps<{
11
+ reason: String
12
+ }>();
13
+
14
+ onMounted(() => {
15
+ // Logic on mount if needed
16
+ });
11
17
  </script>