adminforth 1.17.0 → 1.19.0

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.
@@ -96,7 +96,7 @@ function generateDbUrlForPrisma(connectionString) {
96
96
  return connectionString.toString();
97
97
  }
98
98
 
99
- function initialChecks() {
99
+ function initialChecks(options) {
100
100
  return [
101
101
  {
102
102
  title: '👀 Checking Node.js version...',
@@ -104,21 +104,25 @@ function initialChecks() {
104
104
  },
105
105
  {
106
106
  title: '👀 Validating current working directory...',
107
- task: () => checkForExistingPackageJson()
107
+ task: () => checkForExistingPackageJson(options)
108
108
  }
109
109
  ]
110
110
  }
111
111
 
112
- function checkForExistingPackageJson() {
113
- if (fs.existsSync(path.join(process.cwd(), 'package.json'))) {
112
+ function checkForExistingPackageJson(options) {
113
+ const projectDir = path.join(process.cwd(), options.appName);
114
+ if (fs.existsSync(projectDir)) {
114
115
  throw new Error(
115
- `A package.json already exists in this directory.\n` +
116
- `Please remove it or use an empty directory.`
116
+ `Directory "${options.appName}" already exists.\n` +
117
+ `Please remove it or use a different name.`
117
118
  );
118
119
  }
119
120
  }
120
121
 
121
122
  async function scaffoldProject(ctx, options, cwd) {
123
+ const projectDir = path.join(cwd, options.appName);
124
+ await fse.ensureDir(projectDir);
125
+
122
126
  const connectionString = parseConnectionString(options.db);
123
127
  const provider = detectDbProvider(connectionString.protocol);
124
128
  const prismaDbUrl = generateDbUrlForPrisma(connectionString);
@@ -130,9 +134,9 @@ async function scaffoldProject(ctx, options, cwd) {
130
134
  const dirname = path.dirname(filename);
131
135
 
132
136
  // Prepare directories
133
- ctx.customDir = path.join(cwd, 'custom');
137
+ ctx.customDir = path.join(projectDir, 'custom');
134
138
  await fse.ensureDir(ctx.customDir);
135
- await fse.ensureDir(path.join(cwd, 'resources'));
139
+ await fse.ensureDir(path.join(projectDir, 'resources'));
136
140
 
137
141
  // Copy static assets to `custom/assets`
138
142
  const sourceAssetsDir = path.join(dirname, 'assets');
@@ -141,13 +145,14 @@ async function scaffoldProject(ctx, options, cwd) {
141
145
  await fse.copy(sourceAssetsDir, targetAssetsDir);
142
146
 
143
147
  // Write templated files
144
- writeTemplateFiles(dirname, cwd, {
148
+ writeTemplateFiles(dirname, projectDir, {
145
149
  dbUrl: connectionString.toString(),
146
150
  prismaDbUrl,
147
151
  appName,
148
152
  provider,
149
153
  });
150
154
 
155
+ return projectDir; // Return the new directory path
151
156
  }
152
157
 
153
158
  async function writeTemplateFiles(dirname, cwd, options) {
@@ -236,14 +241,18 @@ async function installDependencies(ctx, cwd) {
236
241
  const customDir = ctx.customDir;
237
242
 
238
243
  await Promise.all([
239
- await execa('npm', ['install', '--no-package-lock'], { cwd }),
244
+ await execa('npm', ['install'], { cwd }),
240
245
  await execa('npm', ['install'], { cwd: customDir }),
241
246
  ]);
242
247
  }
243
248
 
244
- function generateFinalInstructions(skipPrismaSetup) {
249
+ function generateFinalInstructions(skipPrismaSetup, options) {
245
250
  let instruction = '⏭️ Run the following commands to get started:\n';
246
251
  if (!skipPrismaSetup)
252
+ instruction += `
253
+ ${chalk.dim('// Go to the project directory')}
254
+ ${chalk.cyan(`$ cd ${options.appName}`)}\n`;
255
+
247
256
  instruction += `
248
257
  ${chalk.dim('// Generate and apply initial migration')}
249
258
  ${chalk.cyan('$ npm run makemigration -- --name init')}\n`;
@@ -272,33 +281,35 @@ export function prepareWorkflow(options) {
272
281
  title: '🔍 Initial checks...',
273
282
  task: (_, task) =>
274
283
  task.newListr(
275
- initialChecks(),
284
+ initialChecks(options),
276
285
  { concurrent: true },
277
286
  )
278
287
  },
279
288
  {
280
289
  title: '🚀 Scaffolding your project...',
281
- task: async (ctx) => scaffoldProject(ctx, options, cwd)
290
+ task: async (ctx) => {
291
+ ctx.projectDir = await scaffoldProject(ctx, options, cwd);
292
+ }
282
293
  },
283
294
  {
284
295
  title: '📦 Installing dependencies...',
285
- task: async (ctx) => installDependencies(ctx, cwd)
296
+ task: async (ctx) => installDependencies(ctx, ctx.projectDir)
286
297
  },
287
298
  {
288
299
  title: '📝 Preparing final instructions...',
289
300
  task: (ctx) => {
290
- console.log(chalk.green(`✅ Successfully created your new Adminforth project!\n`));
291
- console.log(generateFinalInstructions(ctx.skipPrismaSetup));
301
+ console.log(chalk.green(`✅ Successfully created your new Adminforth project in ${ctx.projectDir}!\n`));
302
+ console.log(generateFinalInstructions(ctx.skipPrismaSetup, options));
292
303
  console.log('\n\n');
304
+ }
293
305
  }
294
- }],
306
+ ],
295
307
  {
296
308
  rendererOptions: {collapseSubtasks: false},
297
309
  concurrent: false,
298
310
  exitOnError: true,
299
311
  collectErrors: true,
300
- }
301
- );
312
+ });
302
313
 
303
314
  return tasks;
304
315
  }
@@ -3,7 +3,7 @@ import type { IAdminForth, IHttpServer, AdminForthResourcePages, AdminForthResou
3
3
  import type { PluginOptions } from './types.js';
4
4
 
5
5
 
6
- export default class ChatGptPlugin extends AdminForthPlugin {
6
+ export default class {{pluginName}} extends AdminForthPlugin {
7
7
  options: PluginOptions;
8
8
 
9
9
  constructor(options: PluginOptions) {
@@ -1,5 +1,6 @@
1
1
  <template>
2
- <div class="flex items-center justify-center w-full"
2
+ <!-- tag form used to reset the input (method .reset() in claer() function) -->
3
+ <form class="flex items-center justify-center w-full"
3
4
  @dragover.prevent="dragging = true"
4
5
  @dragleave.prevent="dragging = false"
5
6
  @drop.prevent="dragging = false; doEmit($event.dataTransfer.files)"
@@ -43,12 +44,12 @@
43
44
  :multiple="props.multiple || false"
44
45
  />
45
46
  </label>
46
- </div>
47
+ </form>
47
48
  </template>
48
49
 
49
50
  <script setup lang="ts">
50
51
  import { humanifySize } from '@/utils';
51
- import { ref, type Ref } from 'vue';
52
+ import { ref, defineExpose, type Ref } from 'vue';
52
53
  import { IconFileSolid } from '@iconify-prerendered/vue-flowbite';
53
54
  import { watch } from 'vue';
54
55
  import adminforth from '@/adminforth';
@@ -125,4 +126,14 @@ function doEmit(filesIn: FileList) {
125
126
 
126
127
  const dragging = ref(false);
127
128
 
129
+ function clear() {
130
+ selectedFiles.value = [];
131
+ emit('update:modelValue', []);
132
+ const form = document.getElementById(id)?.closest('form');
133
+ form?.reset();
134
+ }
135
+
136
+ defineExpose({
137
+ clear,
138
+ });
128
139
  </script>
@@ -16,7 +16,9 @@ import { computed, ref, onMounted, nextTick } from 'vue';
16
16
  import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
17
17
  import Tooltip from '@/afcl/Tooltip.vue';
18
18
  import adminforth from '@/adminforth';
19
+ import { useI18n } from 'vue-i18n';
19
20
 
21
+ const { t } = useI18n();
20
22
  const visualValue = computed(() => {
21
23
  // if lenght is more then 8, show only first 4 and last 4 characters, ... in the middle
22
24
  const val = props.record[props.column.name];
@@ -33,7 +35,7 @@ const id = ref();
33
35
  function copyToCB() {
34
36
  navigator.clipboard.writeText(props.record[props.column.name]);
35
37
  adminforth.alert({
36
- message: 'ID copied to clipboard',
38
+ message: t('ID copied to clipboard'),
37
39
  variant: 'success',
38
40
  })
39
41
  }
@@ -16,7 +16,9 @@ import { computed, ref, onMounted, nextTick } from 'vue';
16
16
  import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
17
17
  import Tooltip from '@/afcl/Tooltip.vue';
18
18
  import adminforth from '@/adminforth';
19
+ import { useI18n } from 'vue-i18n';
19
20
 
21
+ const { t } = useI18n();
20
22
  const visualValue = computed(() => {
21
23
  // if lenght is more then 8, show only first 4 and last 4 characters, ... in the middle
22
24
  const val = props.record[props.column.name];
@@ -33,7 +35,7 @@ const id = ref();
33
35
  function copyToCB() {
34
36
  navigator.clipboard.writeText(props.record[props.column.name]);
35
37
  adminforth.alert({
36
- message: 'ID copied to clipboard',
38
+ message: t('ID copied to clipboard'),
37
39
  variant: 'success',
38
40
  })
39
41
  }
@@ -28,6 +28,21 @@ export interface CompletionAdapter {
28
28
  }>;
29
29
  }
30
30
 
31
+ export interface ImageGenerationAdapter {
32
+
33
+ validate(): void;
34
+
35
+ generate(
36
+ prompt: string,
37
+ inputFiles: string[],
38
+ ): Promise<{
39
+ imageURL?: string;
40
+ error?: string;
41
+ }>;
42
+ }
43
+
44
+
45
+
31
46
  export interface OAuth2Adapter {
32
47
  getAuthUrl(): string;
33
48
  getTokenFromCode(code: string, redirect_uri: string): Promise<{ email: string }>;
@@ -386,7 +386,7 @@ export interface IAdminForth {
386
386
  * Example:
387
387
  *
388
388
  * ```ts
389
- * const i18nPlugin = adminforth.getPluginByClassName<I18nPlugin>('I18nPlugin');
389
+ * const i18nPlugin = adminforth.getPluginByClassName\<I18nPlugin\>('I18nPlugin');
390
390
  * ```
391
391
  *
392
392
  */
@@ -81,7 +81,9 @@ import { useRoute, useRouter } from 'vue-router';
81
81
  import { showErrorTost } from '@/composables/useFrontendApi';
82
82
  import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
83
83
  import adminforth from '@/adminforth';
84
+ import { useI18n } from 'vue-i18n';
84
85
 
86
+ const { t } = useI18n();
85
87
  const coreStore = useCoreStore();
86
88
 
87
89
  const isValid = ref(false);
@@ -170,7 +172,7 @@ async function saveRecord() {
170
172
  showErrorTost(resp.error);
171
173
  } else {
172
174
  adminforth.alert({
173
- message: 'Record updated successfully',
175
+ message: t('Record updated successfully'),
174
176
  variant: 'success',
175
177
  timeout: 400000
176
178
  });
@@ -331,7 +331,7 @@ async function init() {
331
331
  await coreStore.fetchResourceFull({
332
332
  resourceId: route.params.resourceId
333
333
  });
334
-
334
+ isPageLoaded.value = true;
335
335
  // !!! clear filters should be in same tick with sort assignment so that watch can catch it as one change
336
336
 
337
337
  // try to init filters from query params
@@ -446,8 +446,4 @@ watch([sort], async () => {
446
446
  setQuery({ sort: SortQuerySerializer.serialize(sort.value) });
447
447
  });
448
448
 
449
- watch(() => coreStore.resource, () => {
450
- isPageLoaded.value = true;
451
- });
452
-
453
449
  </script>
@@ -13,6 +13,13 @@ export interface CompletionAdapter {
13
13
  error?: string;
14
14
  }>;
15
15
  }
16
+ export interface ImageGenerationAdapter {
17
+ validate(): void;
18
+ generate(prompt: string, inputFiles: string[]): Promise<{
19
+ imageURL?: string;
20
+ error?: string;
21
+ }>;
22
+ }
16
23
  export interface OAuth2Adapter {
17
24
  getAuthUrl(): string;
18
25
  getTokenFromCode(code: string, redirect_uri: string): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"Adapters.d.ts","sourceRoot":"","sources":["../../types/Adapters.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,EAAE,CAAC,EAAE,OAAO,CAAC;KACd,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAEhC,QAAQ,IAAI,IAAI,CAAC;IAEjB,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,IAAI,MAAM,CAAC;IACrB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,OAAO,IAAI,MAAM,CAAC;IAClB,aAAa,CAAC,IAAI,MAAM,CAAC;IACzB,OAAO,CAAC,IAAI,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"Adapters.d.ts","sourceRoot":"","sources":["../../types/Adapters.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,EAAE,CAAC,EAAE,OAAO,CAAC;KACd,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAEhC,QAAQ,IAAI,IAAI,CAAC;IAEjB,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,sBAAsB;IAErC,QAAQ,IAAI,IAAI,CAAC;IAEjB,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC;QACT,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAID,MAAM,WAAW,aAAa;IAC5B,UAAU,IAAI,MAAM,CAAC;IACrB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,OAAO,IAAI,MAAM,CAAC;IAClB,aAAa,CAAC,IAAI,MAAM,CAAC;IACzB,OAAO,CAAC,IAAI,MAAM,CAAC;CACpB"}
@@ -367,7 +367,7 @@ export interface IAdminForth {
367
367
  * Example:
368
368
  *
369
369
  * ```ts
370
- * const i18nPlugin = adminforth.getPluginByClassName<I18nPlugin>('I18nPlugin');
370
+ * const i18nPlugin = adminforth.getPluginByClassName\<I18nPlugin\>('I18nPlugin');
371
371
  * ```
372
372
  *
373
373
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.17.0",
3
+ "version": "1.19.0",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",