adminforth 2.0.7-next.2 → 2.1.0-next.1
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/commands/createCustomComponent/configUpdater.js +135 -74
- package/commands/createCustomComponent/main.js +12 -2
- package/commands/createCustomComponent/templates/customCrud/afterBreadcrumbs.vue.hbs +9 -1
- package/commands/createCustomComponent/templates/customCrud/beforeBreadcrumbs.vue.hbs +9 -1
- package/commands/createCustomComponent/templates/customCrud/bottom.vue.hbs +27 -50
- package/commands/createCustomComponent/templates/customCrud/threeDotsDropdownItems.vue.hbs +10 -21
- package/commands/createCustomComponent/templates/customFields/list.vue.hbs +16 -10
- package/commands/createCustomComponent/templates/customFields/show.vue.hbs +16 -10
- package/commands/createCustomComponent/templates/global/everyPageBottom.vue.hbs +10 -4
- package/commands/createCustomComponent/templates/global/header.vue.hbs +10 -4
- package/commands/createCustomComponent/templates/global/sidebar.vue.hbs +10 -4
- package/commands/createCustomComponent/templates/global/userMenu.vue.hbs +10 -4
- package/commands/createCustomComponent/templates/login/afterLogin.vue.hbs +10 -4
- package/dist/spa/src/App.vue +6 -0
- package/package.json +1 -1
|
@@ -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(
|
|
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
|
-
|
|
224
|
+
parser: typescriptParser,
|
|
215
225
|
});
|
|
216
|
-
|
|
226
|
+
|
|
217
227
|
let updated = false;
|
|
218
|
-
|
|
228
|
+
let injectionLine = null;
|
|
229
|
+
|
|
219
230
|
recast.visit(ast, {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
462
|
-
|
|
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(
|
|
465
|
-
|
|
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(
|
|
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="
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
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
|
|
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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
{{
|
|
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
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
3
|
+
Page Bottom Text
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
-
|
|
9
|
-
|
|
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>
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="text-center text-gray-500 text-sm mt-4">
|
|
3
|
-
|
|
3
|
+
Header Text
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
-
|
|
9
|
-
|
|
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>
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="display-flex justify-center text-lightSidebarIcons text-center dark:text-darkSidebarIcons">
|
|
3
|
-
|
|
3
|
+
Sidebar Text
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
-
|
|
9
|
-
|
|
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>
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="text-center text-gray-500 text-sm mt-4">
|
|
3
|
-
|
|
3
|
+
User Menu Text
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
-
|
|
9
|
-
|
|
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>
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="text-center text-gray-500 text-sm mt-4">
|
|
3
|
-
|
|
3
|
+
Login Page Text
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
-
|
|
9
|
-
|
|
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>
|
|
12
18
|
|
package/dist/spa/src/App.vue
CHANGED
|
@@ -429,6 +429,12 @@ function closeCTA() {
|
|
|
429
429
|
}
|
|
430
430
|
const hash = ctaBadge.value.hash;
|
|
431
431
|
window.localStorage.setItem(`ctaBadge-${hash}`, '1');
|
|
432
|
+
nextTick( async() => {
|
|
433
|
+
loadMenu();
|
|
434
|
+
await coreStore.fetchMenuBadges();
|
|
435
|
+
adminforth.menu.refreshMenuBadges();
|
|
436
|
+
})
|
|
437
|
+
|
|
432
438
|
}
|
|
433
439
|
|
|
434
440
|
|