From 89ad46598890317105c8a3aac5abbd36bfda0703 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 8 Dec 2024 22:43:51 +0100 Subject: [PATCH 1/2] feat(backend): Add export plugin API --- packages/backend/package.json | 1 + packages/backend/src/app.module.ts | 8 + .../admin/languages/languages.controller.ts | 14 +- .../core/admin/plugins/plugins.controller.ts | 26 ++- .../src/core/admin/plugins/plugins.module.ts | 2 + .../admin/plugins/services/export.service.ts | 174 ++++++++++++++++++ packages/backend/src/guards/dev.guard.ts | 14 ++ .../helpers/create-packages-json.ts | 1 + packages/shared/src/admin/plugins.dto.ts | 13 ++ pnpm-lock.yaml | 60 ++++++ 10 files changed, 311 insertions(+), 2 deletions(-) create mode 100644 packages/backend/src/core/admin/plugins/services/export.service.ts create mode 100644 packages/backend/src/guards/dev.guard.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index 631f6cde9..11f9c8541 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -118,6 +118,7 @@ "pg": "^8.13.1", "rxjs": "^7.8.1", "sharp": "^0.33.5", + "tar": "^7.4.3", "ua-parser-js": "^2.0.0", "vitnode-shared": "workspace:*" } diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index c9e048ed4..f215ab622 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -43,6 +43,13 @@ export const ABSOLUTE_PATHS = { plugin: join(internalPaths.frontend, 'plugins', code), templates: join(internalPaths.frontend, 'plugins', code, 'templates'), languages: join(internalPaths.frontend, 'plugins', code, 'langs'), + default_page: join( + internalPaths.frontend, + 'plugins', + code, + 'templates', + 'default-page.tsx', + ), admin_pages_auth: join( internalPaths.frontend, 'app', @@ -76,6 +83,7 @@ export const ABSOLUTE_PATHS = { '(layout)', code, ), + pages_root: join(internalPaths.frontend, 'src', 'app', code), }, }), }; diff --git a/packages/backend/src/core/admin/languages/languages.controller.ts b/packages/backend/src/core/admin/languages/languages.controller.ts index 1834799e0..6ea8d3218 100644 --- a/packages/backend/src/core/admin/languages/languages.controller.ts +++ b/packages/backend/src/core/admin/languages/languages.controller.ts @@ -1,5 +1,15 @@ +import { OnlyForDevelopment } from '@/guards/dev.guard'; import { Controllers } from '@/helpers/controller.decorator'; -import { Body, Delete, Get, Param, Post, Put, Query } from '@nestjs/common'; +import { + Body, + Delete, + Get, + Param, + Post, + Put, + Query, + UseGuards, +} from '@nestjs/common'; import { ApiCreatedResponse, ApiOkResponse } from '@nestjs/swagger'; import { CreateLanguagesAdminBody, @@ -32,6 +42,7 @@ export class LanguagesAdminController { description: 'Create language', }) @Post() + @UseGuards(OnlyForDevelopment) async createLang( @Body() body: CreateLanguagesAdminBody, ): Promise { @@ -42,6 +53,7 @@ export class LanguagesAdminController { description: 'Delete language', }) @Delete(':id') + @UseGuards(OnlyForDevelopment) async deleteLang(@Param('id') id: string) { await this.deleteService.delete(+id); } diff --git a/packages/backend/src/core/admin/plugins/plugins.controller.ts b/packages/backend/src/core/admin/plugins/plugins.controller.ts index 5421d5686..540999560 100644 --- a/packages/backend/src/core/admin/plugins/plugins.controller.ts +++ b/packages/backend/src/core/admin/plugins/plugins.controller.ts @@ -1,9 +1,21 @@ +import type { Response } from 'express'; + import { Controllers } from '@/helpers/controller.decorator'; -import { Body, Delete, Get, Param, Post, Put, Query } from '@nestjs/common'; +import { + Body, + Delete, + Get, + Param, + Post, + Put, + Query, + Res, +} from '@nestjs/common'; import { ApiCreatedResponse, ApiOkResponse } from '@nestjs/swagger'; import { EditPluginsAdminBody } from 'vitnode-shared/admin/plugin.dto'; import { CreatePluginsAdminBody, + ExportPluginsAdminBody, ShowPluginAdmin, ShowPluginsAdminObj, ShowPluginsAdminQuery, @@ -12,6 +24,7 @@ import { import { CreatePluginsAdminService } from './services/create.service'; import { DeletePluginsAdminService } from './services/delete.service'; import { EditPluginsAdminService } from './services/edit.service'; +import { ExportPluginsAdminService } from './services/export.service'; import { ItemPluginsAdminService } from './services/item.service'; import { ShowPluginsAdminService } from './services/show.service'; @@ -23,6 +36,7 @@ export class PluginsAdminController { private readonly deleteService: DeletePluginsAdminService, private readonly itemService: ItemPluginsAdminService, private readonly editService: EditPluginsAdminService, + private readonly exportService: ExportPluginsAdminService, ) {} @ApiCreatedResponse({ description: 'Plugin created', type: ShowPluginAdmin }) @@ -51,6 +65,16 @@ export class PluginsAdminController { return await this.editService.edit({ code, body }); } + @ApiOkResponse({ description: 'Plugin exported' }) + @Post('export/:code') + async exportPlugin( + @Param('code') code: string, + @Body() body: ExportPluginsAdminBody, + @Res() res: Response, + ): Promise { + await this.exportService.export({ code, body, res }); + } + @ApiOkResponse({ type: ShowPluginAdmin, description: 'Plugin details' }) @Get(':code') async itemPlugin(@Param('code') code: string): Promise { diff --git a/packages/backend/src/core/admin/plugins/plugins.module.ts b/packages/backend/src/core/admin/plugins/plugins.module.ts index a807d7d46..a3570a967 100644 --- a/packages/backend/src/core/admin/plugins/plugins.module.ts +++ b/packages/backend/src/core/admin/plugins/plugins.module.ts @@ -8,6 +8,7 @@ import { PluginsAdminController } from './plugins.controller'; import { CreatePluginsAdminService } from './services/create.service'; import { DeletePluginsAdminService } from './services/delete.service'; import { EditPluginsAdminService } from './services/edit.service'; +import { ExportPluginsAdminService } from './services/export.service'; import { ItemPluginsAdminService } from './services/item.service'; import { ShowPluginsAdminService } from './services/show.service'; @@ -20,6 +21,7 @@ import { ShowPluginsAdminService } from './services/show.service'; DeletePluginsAdminService, ItemPluginsAdminService, EditPluginsAdminService, + ExportPluginsAdminService, ], controllers: [PluginsAdminController], imports: [NavPluginsAdminModule, PermissionsAdminPluginsAdminModule], diff --git a/packages/backend/src/core/admin/plugins/services/export.service.ts b/packages/backend/src/core/admin/plugins/services/export.service.ts new file mode 100644 index 000000000..65e403c60 --- /dev/null +++ b/packages/backend/src/core/admin/plugins/services/export.service.ts @@ -0,0 +1,174 @@ +import type { Response } from 'express'; + +import { ABSOLUTE_PATHS } from '@/app.module'; +import { core_plugins } from '@/database/schema/plugins'; +import { currentUnixDate, removeSpecialCharacters } from '@/functions'; +import { generateRandomString } from '@/functions/generate-random-string'; +import { InternalDatabaseService } from '@/utils/database/internal_database.service'; +import { Injectable } from '@nestjs/common'; +import { eq } from 'drizzle-orm'; +import { createReadStream, existsSync } from 'fs'; +import { cp, mkdir, readFile, rm, writeFile } from 'fs/promises'; +import { join } from 'path'; +import * as tar from 'tar'; +import { ConfigPlugin } from 'vitnode-shared/admin/plugin.dto'; +import { ExportPluginsAdminBody } from 'vitnode-shared/admin/plugins.dto'; + +@Injectable() +export class ExportPluginsAdminService { + constructor(private readonly databaseService: InternalDatabaseService) {} + + private readonly tempPath = join(ABSOLUTE_PATHS.uploads.temp, 'plugins'); + + async export({ + code, + body: { version, version_code }, + res, + }: { + body: ExportPluginsAdminBody; + code: string; + res: Response; + }) { + const plugin = await this.databaseService.db.query.core_plugins.findFirst({ + where: (table, { eq }) => eq(table.code, code), + }); + + if (!plugin) { + return res.status(404).json({ message: 'Plugin not found' }); + } + + // Update config.json + const pathInfoJSON = ABSOLUTE_PATHS.plugin({ code }).config; + const configJSON: ConfigPlugin = JSON.parse( + await readFile(pathInfoJSON, 'utf8'), + ); + const allow_default = existsSync( + ABSOLUTE_PATHS.plugin({ code }).frontend.default_page, + ); + + if ( + (!version && !configJSON.version) || + (!version_code && !configJSON.version_code) + ) { + return res.status(400).json({ + message: 'Version and version_code are required', + }); + } + + configJSON.allow_default = allow_default; + configJSON.version = version ?? configJSON.version; + configJSON.version_code = version_code ?? configJSON.version_code; + + await writeFile(pathInfoJSON, JSON.stringify(configJSON, null, 2), 'utf8'); + + // Update only allow_default + if (!version || !version_code) { + await this.databaseService.db + .update(core_plugins) + .set({ + allow_default, + updated_at: new Date(), + }) + .where(eq(core_plugins.code, code)); + + return; + } + + await this.databaseService.db + .update(core_plugins) + .set({ + version, + version_code, + allow_default, + updated_at: new Date(), + }) + .where(eq(core_plugins.code, code)); + + // Prepare the export + const tempFolderName = removeSpecialCharacters( + `${code}-${version}-${generateRandomString(5)}-${currentUnixDate()}`, + ); + const tempPath = join(this.tempPath, tempFolderName); + await mkdir(tempPath, { recursive: true }); + + // Create folders for backend, frontend + const backendPath = join(tempPath, 'backend'); + const frontendPath = join(tempPath, 'frontend'); + await Promise.all([ + mkdir(backendPath, { recursive: true }), + mkdir(frontendPath, { recursive: true }), + ]); + + // Copy backend files + const backendSource = ABSOLUTE_PATHS.plugin({ code }).root; + if (!existsSync(backendSource)) { + return res.status(500).json({ message: 'Backend source does not exist' }); + } + await cp(backendSource, backendPath, { recursive: true }); + + // Copy frontend files + const frontendPaths = [ + 'admin_pages_auth', + 'admin_pages', + 'pages', + 'pages_main', + 'pages_main_layout', + 'pages_root', + 'plugin', + ] as const; + await Promise.all( + frontendPaths.map(async path => { + const source = ABSOLUTE_PATHS.plugin({ code }).frontend[path]; + if (!existsSync(source)) { + if (path === 'plugin') { + return res + .status(500) + .json({ message: 'Frontend source does not exist' }); + } + + return; + } + + await cp(source, join(frontendPath, path), { recursive: true }); + }), + ); + + // Copy shared files + const sharedSource = ABSOLUTE_PATHS.plugin({ code }).shared; + if (!existsSync(sharedSource)) return; + const sharedPath = join(tempPath, 'shared'); + await mkdir(sharedPath, { recursive: true }); + await cp(sharedSource, sharedPath, { recursive: true }); + + // Create tar + const file = join(ABSOLUTE_PATHS.uploads.temp, `${tempFolderName}.tgz`); + + try { + await tar.create( + { + gzip: true, + file, + cwd: tempPath, + }, + ['.'], + ); + } catch (_) { + return res.status(500).json({ message: 'Error creating tar' }); + } + + // Delete temp folder + await rm(tempPath, { recursive: true }); + + res.setHeader('Content-Type', 'application/octet-stream'); + res.setHeader( + 'Content-Disposition', + `attachment; filename=${tempFolderName}.tgz`, + ); + + const stream = createReadStream(file); + stream.pipe(res); + stream.on('end', async () => { + await rm(file); + }); + } +} diff --git a/packages/backend/src/guards/dev.guard.ts b/packages/backend/src/guards/dev.guard.ts new file mode 100644 index 000000000..d4801c3fb --- /dev/null +++ b/packages/backend/src/guards/dev.guard.ts @@ -0,0 +1,14 @@ +import { CanActivate, ForbiddenException, Injectable } from '@nestjs/common'; + +@Injectable() +export class OnlyForDevelopment implements CanActivate { + canActivate(): boolean { + if (process.env.NODE_ENV !== 'development') { + throw new ForbiddenException( + 'This route is only available in development mode', + ); + } + + return true; + } +} diff --git a/packages/create-vitnode-app/helpers/create-packages-json.ts b/packages/create-vitnode-app/helpers/create-packages-json.ts index b8e67c755..05e80ba42 100644 --- a/packages/create-vitnode-app/helpers/create-packages-json.ts +++ b/packages/create-vitnode-app/helpers/create-packages-json.ts @@ -145,6 +145,7 @@ export const createPackagesJSON = ({ '@nestjs/core': '^10.4.13', '@nestjs/platform-express': '^10.4.13', '@nestjs/schedule': '^4.1.1', + '@nestjs/swagger': '^8.1.0', '@react-email/components': '^0.0.29', 'class-transformer': '^0.5.1', 'class-validator': '^0.14.1', diff --git a/packages/shared/src/admin/plugins.dto.ts b/packages/shared/src/admin/plugins.dto.ts index 454bffbb2..1cdf8acb6 100644 --- a/packages/shared/src/admin/plugins.dto.ts +++ b/packages/shared/src/admin/plugins.dto.ts @@ -2,6 +2,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; import { IsEnum, + IsNumber, IsOptional, IsString, Matches, @@ -123,3 +124,15 @@ export class ShowPluginsAdminQuery extends PaginationQuery { @IsOptional() sortDirection?: SortDirectionEnum; } + +export class ExportPluginsAdminBody { + @ApiPropertyOptional({ example: '1.0.0' }) + @IsOptional() + @IsString() + version?: string; + + @ApiPropertyOptional({ example: 1 }) + @IsNumber() + @IsOptional() + version_code?: number; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86177cee9..165558b53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -251,6 +251,9 @@ importers: sharp: specifier: ^0.33.5 version: 0.33.5 + tar: + specifier: ^7.4.3 + version: 7.4.3 ua-parser-js: specifier: ^2.0.0 version: 2.0.0 @@ -1702,6 +1705,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -3682,6 +3689,10 @@ packages: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -5319,10 +5330,19 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + minizlib@3.0.1: + resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + engines: {node: '>= 18'} + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} @@ -6144,6 +6164,10 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + rollup@4.28.0: resolution: {integrity: sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -6481,6 +6505,10 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -6916,6 +6944,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -7752,6 +7784,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -9799,6 +9835,8 @@ snapshots: dependencies: readdirp: 4.0.2 + chownr@3.0.0: {} + chrome-trace-event@1.0.4: {} class-transformer@0.5.1: {} @@ -11496,10 +11534,17 @@ snapshots: minipass@7.1.2: {} + minizlib@3.0.1: + dependencies: + minipass: 7.1.2 + rimraf: 5.0.10 + mkdirp@0.5.6: dependencies: minimist: 1.2.8 + mkdirp@3.0.1: {} + mrmime@2.0.0: {} ms@2.0.0: {} @@ -12287,6 +12332,10 @@ snapshots: reusify@1.0.4: {} + rimraf@5.0.10: + dependencies: + glob: 10.4.5 + rollup@4.28.0: dependencies: '@types/estree': 1.0.6 @@ -12727,6 +12776,15 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.21.0 + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.1 + mkdirp: 3.0.1 + yallist: 5.0.0 + terser-webpack-plugin@5.3.10(@swc/core@1.10.0(@swc/helpers@0.5.13))(webpack@5.96.1(@swc/core@1.10.0(@swc/helpers@0.5.13))): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -13205,6 +13263,8 @@ snapshots: yallist@3.1.1: {} + yallist@5.0.0: {} + yaml@1.10.2: {} yaml@2.6.1: {} From 6a054017127d9217a158a56de2f1d5bf5f8dcec6 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Mon, 9 Dec 2024 10:59:13 +0100 Subject: [PATCH 2/2] feat: Add export plugin button in dev mode in AdminCP --- apps/frontend/src/plugins/admin/langs/en.json | 30 ++-- .../core/admin/plugins/nav/nav.controller.ts | 1 + .../permissions-admin.controller.ts | 1 + .../core/admin/plugins/plugins.controller.ts | 7 +- .../admin/plugins/services/export.service.ts | 44 +++--- .../src/helpers/controller.decorator.ts | 7 + packages/backend/src/main.ts | 1 + packages/frontend/src/api/fetcher-client.ts | 4 + .../data-table/toolbar/filter/filter.tsx | 4 +- .../frontend/src/components/editor/editor.tsx | 4 +- .../src/components/ui/alert-dialog.tsx | 4 +- .../frontend/src/components/ui/carousel.tsx | 4 +- packages/frontend/src/components/ui/chart.tsx | 4 +- .../frontend/src/components/ui/dialog.tsx | 4 +- packages/frontend/src/components/ui/form.tsx | 8 +- packages/frontend/src/components/ui/sheet.tsx | 4 +- .../frontend/src/components/ui/sidebar.tsx | 4 +- .../src/components/ui/toggle-group.tsx | 4 +- .../src/views/admin/layout/wrapper.tsx | 4 +- .../core/plugins/actions/create/create.tsx | 2 +- .../core/plugins/dev/hooks/use-dev-plugin.ts | 16 +- .../plugins/dev/layout/export/content.tsx | 143 ++++++++++++++++++ .../core/plugins/dev/layout/export/export.tsx | 47 ++++++ .../views/core/plugins/dev/layout/layout.tsx | 12 +- .../views/core/plugins/dev/layout/wrapper.tsx | 11 +- .../views/core/plugins/dev/nav/content.tsx | 4 +- .../hooks/use-create-nav-plugin-admin.ts | 8 +- .../hooks/use-delete-nav-plugin-admin.ts | 2 +- .../views/core/plugins/dev/nav/item/item.tsx | 6 +- ...eate-edit-permission-admin-plugin-admin.ts | 6 +- ...se-delete-permission-admin-plugin-admin.ts | 4 +- .../dev/permissions-admin/item/item.tsx | 6 +- .../admin/views/core/plugins/dev/tabs.tsx | 14 +- .../core/styles/theme-editor/wrapper.tsx | 6 +- .../src/views/layout/auth/wrapper.tsx | 4 +- .../frontend/src/views/layout/providers.tsx | 4 +- .../theme/views/auth/sign/up/wrapper.tsx | 4 +- packages/shared/src/admin/plugins.dto.ts | 2 +- 38 files changed, 340 insertions(+), 104 deletions(-) create mode 100644 packages/frontend/src/views/admin/views/core/plugins/dev/layout/export/content.tsx create mode 100644 packages/frontend/src/views/admin/views/core/plugins/dev/layout/export/export.tsx diff --git a/apps/frontend/src/plugins/admin/langs/en.json b/apps/frontend/src/plugins/admin/langs/en.json index 46ddc1b77..7dc29fa0f 100644 --- a/apps/frontend/src/plugins/admin/langs/en.json +++ b/apps/frontend/src/plugins/admin/langs/en.json @@ -299,9 +299,7 @@ "desc": "We're detected changes in the plugin system. To apply these changes, you need to restart the server." }, "dev": { - "overview": { - "title": "Overview" - }, + "overview": "Overview", "nav": { "title": "Navigation in AdminCP", "lang_key": "Lang Key: ", @@ -363,6 +361,18 @@ "desc": "If you delete this permission, all children will be deleted too." } } + }, + "export": { + "title": "Export Plugin", + "desc": "Choose version to export.", + "type": { + "rebuild": "Rebuild current version - {version}", + "new_version": "Create new version" + }, + "version": "Version", + "version_code": "Version Code", + "success": "Plugin has been exported.", + "submit": "Export" } }, "create": { @@ -411,20 +421,6 @@ "submit": "Yes, delete plugin", "desc": "This action will delete plugin created by and all data associated with it.", "info": "After the process is complete, you need to restart the server to apply the changes." - }, - "download": { - "title": "Download Plugin", - "type": { - "rebuild": "Rebuild current version - {version}", - "new_version": "Create new version" - }, - "version": { - "label": "Version" - }, - "version_code": { - "label": "Version Code" - }, - "submit": "Download" } }, "styles": { diff --git a/packages/backend/src/core/admin/plugins/nav/nav.controller.ts b/packages/backend/src/core/admin/plugins/nav/nav.controller.ts index f31822ae5..8f2eb159f 100644 --- a/packages/backend/src/core/admin/plugins/nav/nav.controller.ts +++ b/packages/backend/src/core/admin/plugins/nav/nav.controller.ts @@ -19,6 +19,7 @@ import { ShowNavPluginsAdminService } from './services/show.service'; plugin_code: 'plugins', isAdmin: true, route: 'nav', + isDev: true, }) export class NavPluginsAdminController { constructor( diff --git a/packages/backend/src/core/admin/plugins/permissions-admin/permissions-admin.controller.ts b/packages/backend/src/core/admin/plugins/permissions-admin/permissions-admin.controller.ts index 98ff14a21..ae0d4338f 100644 --- a/packages/backend/src/core/admin/plugins/permissions-admin/permissions-admin.controller.ts +++ b/packages/backend/src/core/admin/plugins/permissions-admin/permissions-admin.controller.ts @@ -17,6 +17,7 @@ import { ShowPermissionsAdminPluginsAdminService } from './services/show.service plugin_code: 'plugins', isAdmin: true, route: 'permissions-admin', + isDev: true, }) export class PermissionsAdminPluginsAdminController { constructor( diff --git a/packages/backend/src/core/admin/plugins/plugins.controller.ts b/packages/backend/src/core/admin/plugins/plugins.controller.ts index 540999560..bed52506e 100644 --- a/packages/backend/src/core/admin/plugins/plugins.controller.ts +++ b/packages/backend/src/core/admin/plugins/plugins.controller.ts @@ -1,5 +1,6 @@ import type { Response } from 'express'; +import { OnlyForDevelopment } from '@/guards/dev.guard'; import { Controllers } from '@/helpers/controller.decorator'; import { Body, @@ -10,6 +11,7 @@ import { Put, Query, Res, + UseGuards, } from '@nestjs/common'; import { ApiCreatedResponse, ApiOkResponse } from '@nestjs/swagger'; import { EditPluginsAdminBody } from 'vitnode-shared/admin/plugin.dto'; @@ -41,6 +43,7 @@ export class PluginsAdminController { @ApiCreatedResponse({ description: 'Plugin created', type: ShowPluginAdmin }) @Post() + @UseGuards(OnlyForDevelopment) async createPlugin( @Body() body: CreatePluginsAdminBody, ): Promise { @@ -49,6 +52,7 @@ export class PluginsAdminController { @ApiOkResponse({ description: 'Plugin deleted' }) @Delete(':id') + @UseGuards(OnlyForDevelopment) async deletePlugin(@Param('id') id: string): Promise { await this.deleteService.delete(+id); } @@ -66,7 +70,8 @@ export class PluginsAdminController { } @ApiOkResponse({ description: 'Plugin exported' }) - @Post('export/:code') + @Post(':code/export') + @UseGuards(OnlyForDevelopment) async exportPlugin( @Param('code') code: string, @Body() body: ExportPluginsAdminBody, diff --git a/packages/backend/src/core/admin/plugins/services/export.service.ts b/packages/backend/src/core/admin/plugins/services/export.service.ts index 65e403c60..8ac2e2dcd 100644 --- a/packages/backend/src/core/admin/plugins/services/export.service.ts +++ b/packages/backend/src/core/admin/plugins/services/export.service.ts @@ -55,6 +55,17 @@ export class ExportPluginsAdminService { }); } + // Check if version_code is greater than the current version_code + if ( + version_code && + configJSON.version_code && + version_code <= configJSON.version_code + ) { + return res.status(400).json({ + message: 'Version code must be greater than the current version code', + }); + } + configJSON.allow_default = allow_default; configJSON.version = version ?? configJSON.version; configJSON.version_code = version_code ?? configJSON.version_code; @@ -70,23 +81,21 @@ export class ExportPluginsAdminService { updated_at: new Date(), }) .where(eq(core_plugins.code, code)); - - return; + } else { + await this.databaseService.db + .update(core_plugins) + .set({ + version, + version_code, + allow_default, + updated_at: new Date(), + }) + .where(eq(core_plugins.code, code)); } - await this.databaseService.db - .update(core_plugins) - .set({ - version, - version_code, - allow_default, - updated_at: new Date(), - }) - .where(eq(core_plugins.code, code)); - // Prepare the export const tempFolderName = removeSpecialCharacters( - `${code}-${version}-${generateRandomString(5)}-${currentUnixDate()}`, + `${code}-${version ?? plugin.version}-${generateRandomString(5)}-${currentUnixDate()}`, ); const tempPath = join(this.tempPath, tempFolderName); await mkdir(tempPath, { recursive: true }); @@ -135,10 +144,11 @@ export class ExportPluginsAdminService { // Copy shared files const sharedSource = ABSOLUTE_PATHS.plugin({ code }).shared; - if (!existsSync(sharedSource)) return; - const sharedPath = join(tempPath, 'shared'); - await mkdir(sharedPath, { recursive: true }); - await cp(sharedSource, sharedPath, { recursive: true }); + if (existsSync(sharedSource)) { + const sharedPath = join(tempPath, 'shared'); + await mkdir(sharedPath, { recursive: true }); + await cp(sharedSource, sharedPath, { recursive: true }); + } // Create tar const file = join(ABSOLUTE_PATHS.uploads.temp, `${tempFolderName}.tgz`); diff --git a/packages/backend/src/helpers/controller.decorator.ts b/packages/backend/src/helpers/controller.decorator.ts index 08537b675..ac78788ab 100644 --- a/packages/backend/src/helpers/controller.decorator.ts +++ b/packages/backend/src/helpers/controller.decorator.ts @@ -1,9 +1,11 @@ import { AdminAuthGuard } from '@/guards/admin-auth.guard'; import { AuthGuard } from '@/guards/auth.guard'; +import { OnlyForDevelopment } from '@/guards/dev.guard'; import { applyDecorators, Controller, UseGuards } from '@nestjs/common'; import { ApiSecurity, ApiTags } from '@nestjs/swagger'; interface Args { + isDev?: boolean; plugin_code: string; plugin_name: string; route?: string; @@ -30,9 +32,14 @@ export function Controllers({ isAdmin, isProtect, route, + isDev, }: ArgsWithAdmin | ArgsWithout | ArgsWithProtect) { const decorators = [Controller(`${plugin_code}${route ? `/${route}` : ''}`)]; + if (isDev) { + decorators.push(UseGuards(OnlyForDevelopment)); + } + if (isAdmin) { decorators.push( ApiTags(`Admin - ${plugin_name}`), diff --git a/packages/backend/src/main.ts b/packages/backend/src/main.ts index 971be240a..c2903cfaf 100644 --- a/packages/backend/src/main.ts +++ b/packages/backend/src/main.ts @@ -22,6 +22,7 @@ export const nestjsMainApp = async (app: INestApplication, options?: Args) => { app.enableCors({ ...options?.cors, credentials: true, + exposedHeaders: ['Content-Disposition'], origin: [ process.env.NEXT_PUBLIC_FRONTEND_URL ?? 'http://localhost:3000', ...(options?.cors?.origin ?? []), diff --git a/packages/frontend/src/api/fetcher-client.ts b/packages/frontend/src/api/fetcher-client.ts index de51d2bca..236b5bcbc 100644 --- a/packages/frontend/src/api/fetcher-client.ts +++ b/packages/frontend/src/api/fetcher-client.ts @@ -40,6 +40,10 @@ export async function fetcherClient< : null, }); + if (res.headers.get('Content-Disposition')) { + return { res, data: {} as TData }; + } + let data = {} as TData; try { data = await res.json(); diff --git a/packages/frontend/src/components/data-table/toolbar/filter/filter.tsx b/packages/frontend/src/components/data-table/toolbar/filter/filter.tsx index 68971470a..0623f28b6 100644 --- a/packages/frontend/src/components/data-table/toolbar/filter/filter.tsx +++ b/packages/frontend/src/components/data-table/toolbar/filter/filter.tsx @@ -52,11 +52,11 @@ export function FilterToolbarDataTable({ - + }> {children} - + ); diff --git a/packages/frontend/src/components/editor/editor.tsx b/packages/frontend/src/components/editor/editor.tsx index 97644c33f..0eaa489bb 100644 --- a/packages/frontend/src/components/editor/editor.tsx +++ b/packages/frontend/src/components/editor/editor.tsx @@ -234,7 +234,7 @@ export const Editor = ({ if (!editor) return null; return ( - - + ); }; diff --git a/packages/frontend/src/components/ui/alert-dialog.tsx b/packages/frontend/src/components/ui/alert-dialog.tsx index 221eaad07..42d907e47 100644 --- a/packages/frontend/src/components/ui/alert-dialog.tsx +++ b/packages/frontend/src/components/ui/alert-dialog.tsx @@ -27,7 +27,7 @@ const AlertDialog = ({ const [open, setOpen] = React.useState(false); return ( - {children} - + ); }; diff --git a/packages/frontend/src/components/ui/carousel.tsx b/packages/frontend/src/components/ui/carousel.tsx index 90b54e3fc..45fa6c287 100644 --- a/packages/frontend/src/components/ui/carousel.tsx +++ b/packages/frontend/src/components/ui/carousel.tsx @@ -102,7 +102,7 @@ function Carousel({ }, [api, onSelect]); return ( - {children} - + ); } diff --git a/packages/frontend/src/components/ui/chart.tsx b/packages/frontend/src/components/ui/chart.tsx index b85d7b105..2a4551167 100644 --- a/packages/frontend/src/components/ui/chart.tsx +++ b/packages/frontend/src/components/ui/chart.tsx @@ -50,7 +50,7 @@ const ChartContainer = ({ const chartId = `chart-${id ?? uniqueId.replace(/:/g, '')}`; return ( - +
-
+ ); }; diff --git a/packages/frontend/src/components/ui/dialog.tsx b/packages/frontend/src/components/ui/dialog.tsx index 6e2a7e821..f6be07d45 100644 --- a/packages/frontend/src/components/ui/dialog.tsx +++ b/packages/frontend/src/components/ui/dialog.tsx @@ -31,7 +31,7 @@ const Dialog = ({ const [isDirty, setIsDirty] = React.useState(false); return ( - { @@ -50,7 +50,7 @@ const Dialog = ({ > {children} - + ); }; diff --git a/packages/frontend/src/components/ui/form.tsx b/packages/frontend/src/components/ui/form.tsx index d8d429744..f14c278bc 100644 --- a/packages/frontend/src/components/ui/form.tsx +++ b/packages/frontend/src/components/ui/form.tsx @@ -67,9 +67,9 @@ const FormField = < ...props }: ControllerProps) => { return ( - + - + ); }; @@ -111,9 +111,9 @@ const FormItem = ({ const id = React.useId(); return ( - +
- + ); }; diff --git a/packages/frontend/src/components/ui/sheet.tsx b/packages/frontend/src/components/ui/sheet.tsx index e80672912..9cb8ddd02 100644 --- a/packages/frontend/src/components/ui/sheet.tsx +++ b/packages/frontend/src/components/ui/sheet.tsx @@ -28,7 +28,7 @@ const Sheet = ({ const [open, setOpen] = React.useState(false); return ( - {children} - + ); }; diff --git a/packages/frontend/src/components/ui/sidebar.tsx b/packages/frontend/src/components/ui/sidebar.tsx index 495115e10..db5492da0 100644 --- a/packages/frontend/src/components/ui/sidebar.tsx +++ b/packages/frontend/src/components/ui/sidebar.tsx @@ -129,7 +129,7 @@ const SidebarProvider = ({ ); return ( - +
- + ); }; diff --git a/packages/frontend/src/components/ui/toggle-group.tsx b/packages/frontend/src/components/ui/toggle-group.tsx index 658c4d6fe..1a0601eba 100644 --- a/packages/frontend/src/components/ui/toggle-group.tsx +++ b/packages/frontend/src/components/ui/toggle-group.tsx @@ -26,9 +26,9 @@ const ToggleGroup = ({ className={cn('flex items-center justify-center gap-1', className)} {...props} > - + {children} - + ); diff --git a/packages/frontend/src/views/admin/layout/wrapper.tsx b/packages/frontend/src/views/admin/layout/wrapper.tsx index 0a5f1a0a4..7db2d2417 100644 --- a/packages/frontend/src/views/admin/layout/wrapper.tsx +++ b/packages/frontend/src/views/admin/layout/wrapper.tsx @@ -30,8 +30,8 @@ export const WrapperAdminLayout = ({ }; return ( - + {children} - + ); }; diff --git a/packages/frontend/src/views/admin/views/core/plugins/actions/create/create.tsx b/packages/frontend/src/views/admin/views/core/plugins/actions/create/create.tsx index 8637f117f..50b545e8f 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/actions/create/create.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/actions/create/create.tsx @@ -28,7 +28,7 @@ export const CreateActionPluginAdmin = () => { return ( } + /> + ); +}; diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/layout/export/export.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/export/export.tsx new file mode 100644 index 000000000..24be1aa40 --- /dev/null +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/export/export.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { Loader } from '@/components/ui/loader'; +import { DownloadIcon } from 'lucide-react'; +import { useTranslations } from 'next-intl'; +import React from 'react'; + +const Content = React.lazy(async () => + import('./content').then(module => ({ + default: module.ContentExportActionDevPluginAdmin, + })), +); + +export const ExportActionDevPluginAdmin = () => { + const t = useTranslations('admin.core.plugins.dev.export'); + + return ( + + + + + + + + {t('title')} + {t('desc')} + + + }> + + + + + ); +}; diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/layout/layout.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/layout.tsx index d1e3702e3..19279e68c 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/layout/layout.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/layout.tsx @@ -11,6 +11,7 @@ import React from 'react'; import { getPluginDataAdmin } from '../query-api'; import { TabsDevPluginAdmin } from '../tabs'; +import { ExportActionDevPluginAdmin } from './export/export'; import { WrapperDevPluginAdminLayout } from './wrapper'; interface Props { @@ -49,7 +50,14 @@ export const DevPluginAdminLayout = async ({ code, children }: Props) => { ]); return ( - + @@ -85,7 +93,7 @@ export const DevPluginAdminLayout = async ({ code, children }: Props) => {
} > - {/* */} + {CONFIG.node_development && } diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/layout/wrapper.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/wrapper.tsx index 6d116c8b6..bd3d75950 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/layout/wrapper.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/layout/wrapper.tsx @@ -1,16 +1,19 @@ 'use client'; -import { DevPluginAdminContext } from '../hooks/use-dev-plugin'; +import { + DevPluginAdminContext, + DevPluginAdminContextArgs, +} from '../hooks/use-dev-plugin'; export const WrapperDevPluginAdminLayout = ({ children, - pluginCode, + data, }: { children: React.ReactNode; - pluginCode: string; + data: DevPluginAdminContextArgs; }) => { return ( - + {children} ); diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/content.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/content.tsx index 23bb9b630..d958d0baf 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/content.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/content.tsx @@ -19,7 +19,7 @@ export const ContentNavDevPluginAdmin = ({ textsAndIcons: TextAndIconsAsideAdmin[]; }) => { const t = useTranslations('core.global.errors'); - const { pluginCode } = useDevPluginAdmin(); + const { code } = useDevPluginAdmin(); return ( , form: UseFormReturn>, ) => { - if (!pluginCode) return; - try { if (data) { await editMutationApi({ ...values, previous_code: data.code, - plugin_code: pluginCode, + plugin_code: code, parent_code: values.parent_code === 'null' ? undefined : values.parent_code, keywords: (values.keywords ?? []).map(keyword => keyword.value), @@ -65,7 +63,7 @@ export const useCreateNavPluginAdmin = ({ } else { await createMutationApi({ ...values, - plugin_code: pluginCode, + plugin_code: code, parent_code: values.parent_code === 'null' ? undefined : values.parent_code, keywords: (values.keywords ?? []).map(keyword => keyword.value), diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/actions/delete/hooks/use-delete-nav-plugin-admin.ts b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/actions/delete/hooks/use-delete-nav-plugin-admin.ts index 94e7dcf57..96149923a 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/actions/delete/hooks/use-delete-nav-plugin-admin.ts +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/actions/delete/hooks/use-delete-nav-plugin-admin.ts @@ -13,7 +13,7 @@ export const useDeleteNavPluginAdmin = ({ const t = useTranslations('admin.core.plugins.dev.nav.delete'); const tCore = useTranslations('core.global.errors'); const { setOpen } = useAlertDialog(); - const { pluginCode } = useDevPluginAdmin(); + const { code: pluginCode } = useDevPluginAdmin(); const onSubmit = async () => { try { diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/item.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/item.tsx index 8ec9b8c47..cadc52b36 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/item.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/nav/item/item.tsx @@ -16,7 +16,7 @@ export const ItemContentNavDevPluginAdmin = ({ parentId?: string; textsAndIcons: TextAndIconsAsideAdmin[]; }) => { - const { pluginCode } = useDevPluginAdmin(); + const { code } = useDevPluginAdmin(); const tAdmin = useTranslations('admin.core.plugins.dev.nav'); const langKey = parentId ? `${parentId}_${data.code}` : data.code; const textAndIcon = textsAndIcons.find(item => item.id === langKey); @@ -32,14 +32,14 @@ export const ItemContentNavDevPluginAdmin = ({

{tAdmin.rich('lang_key', { key: () => ( - {`admin_${pluginCode}.nav.${langKey}`} + {`admin_${code}.nav.${langKey}`} ), })}

{tAdmin.rich('link_url_with_link', { link: () => ( - {`/admin/${pluginCode}/${parentId ? `${parentId}/` : ''}${data.code}`} + {`/admin/${code}/${parentId ? `${parentId}/` : ''}${data.code}`} ), })}

diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/create-edit/hooks/use-create-edit-permission-admin-plugin-admin.ts b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/create-edit/hooks/use-create-edit-permission-admin-plugin-admin.ts index 43e4f6440..e20c69fa1 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/create-edit/hooks/use-create-edit-permission-admin-plugin-admin.ts +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/create-edit/hooks/use-create-edit-permission-admin-plugin-admin.ts @@ -18,7 +18,7 @@ export const useCreateEditPermissionAdminPluginAdmin = ({ dataWithI18n: PermissionsAdminWithI18n[]; parentId: string | undefined; }) => { - const { pluginCode } = useDevPluginAdmin(); + const { code } = useDevPluginAdmin(); const t = useTranslations( 'admin.core.plugins.dev.permissions-admin.create_edit', ); @@ -44,14 +44,14 @@ export const useCreateEditPermissionAdminPluginAdmin = ({ await editMutationApi({ ...values, parent_id: values.parent_id === 'null' ? undefined : values.parent_id, - plugin_code: pluginCode, + plugin_code: code, old_id: data.id, }); } else { await createMutationApi({ ...values, parent_id: values.parent_id === 'null' ? undefined : values.parent_id, - plugin_code: pluginCode, + plugin_code: code, }); } diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/actions/delete/hooks/use-delete-permission-admin-plugin-admin.ts b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/actions/delete/hooks/use-delete-permission-admin-plugin-admin.ts index b464867b5..61bed2ee6 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/actions/delete/hooks/use-delete-permission-admin-plugin-admin.ts +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/actions/delete/hooks/use-delete-permission-admin-plugin-admin.ts @@ -15,12 +15,12 @@ export const useDeletePermissionAdminPluginAdmin = ({ const t = useTranslations('admin.core.plugins.dev.permissions-admin.delete'); const tCore = useTranslations('core.global.errors'); const { setOpen } = useAlertDialog(); - const { pluginCode } = useDevPluginAdmin(); + const { code } = useDevPluginAdmin(); const onSubmit = async () => { try { await mutationApi({ - plugin_code: Array.isArray(pluginCode) ? pluginCode[0] : pluginCode, + plugin_code: code, id, parent_id: parentId, }); diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/item.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/item.tsx index 67883cdaa..938adafd7 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/item.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/permissions-admin/item/item.tsx @@ -16,7 +16,7 @@ export const ItemPermissionsAdminDevPluginAdmin = ({ parentId: string | undefined; }) => { const t = useTranslations('admin.core.plugins.dev.permissions-admin'); - const { pluginCode } = useDevPluginAdmin(); + const { code } = useDevPluginAdmin(); return (
@@ -28,7 +28,7 @@ export const ItemPermissionsAdminDevPluginAdmin = ({

{t.rich('lang_key', { key: () => ( - {`admin_${pluginCode}.admin_permissions.${id}`} + {`admin_${code}.admin_permissions.${id}`} ), })}

@@ -37,7 +37,7 @@ export const ItemPermissionsAdminDevPluginAdmin = ({ {t.rich('page_permission', { page: () => ( - {`/admin/${pluginCode}/${id.replace('can_manage_', '').split('_').join('/')}`} + {`/admin/${code}/${id.replace('can_manage_', '').split('_').join('/')}`} ), })} diff --git a/packages/frontend/src/views/admin/views/core/plugins/dev/tabs.tsx b/packages/frontend/src/views/admin/views/core/plugins/dev/tabs.tsx index 13d7489a3..aebc5b243 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/dev/tabs.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/dev/tabs.tsx @@ -14,12 +14,20 @@ export const TabsDevPluginAdmin = ({ code }: { code: string }) => { active={pathname === `/admin/core/plugins/${code}/dev`} href={`/admin/core/plugins/${code}/dev`} > - {t('overview.title')} + {t('overview')} - + {t('nav.title')} - + {t('permissions-admin.title')} diff --git a/packages/frontend/src/views/admin/views/core/styles/theme-editor/wrapper.tsx b/packages/frontend/src/views/admin/views/core/styles/theme-editor/wrapper.tsx index f63581627..cf2042afd 100644 --- a/packages/frontend/src/views/admin/views/core/styles/theme-editor/wrapper.tsx +++ b/packages/frontend/src/views/admin/views/core/styles/theme-editor/wrapper.tsx @@ -217,10 +217,8 @@ export const WrapperThemeEditorAdmin = ({ }; return ( - + {children} - + ); }; diff --git a/packages/frontend/src/views/layout/auth/wrapper.tsx b/packages/frontend/src/views/layout/auth/wrapper.tsx index bd6524b2e..b7e388731 100644 --- a/packages/frontend/src/views/layout/auth/wrapper.tsx +++ b/packages/frontend/src/views/layout/auth/wrapper.tsx @@ -10,7 +10,5 @@ export const WrapperAuthLayout = ({ children: React.ReactNode; data: ShowAuthObj; }) => { - return ( - {children} - ); + return {children}; }; diff --git a/packages/frontend/src/views/layout/providers.tsx b/packages/frontend/src/views/layout/providers.tsx index 6b77b80ba..f81d1041d 100644 --- a/packages/frontend/src/views/layout/providers.tsx +++ b/packages/frontend/src/views/layout/providers.tsx @@ -37,9 +37,9 @@ export const RootProviders = ({ /> {middlewareData ? ( - + {children} - + ) : ( children )} diff --git a/packages/frontend/src/views/theme/views/auth/sign/up/wrapper.tsx b/packages/frontend/src/views/theme/views/auth/sign/up/wrapper.tsx index 9b115bb03..8e4b1117c 100644 --- a/packages/frontend/src/views/theme/views/auth/sign/up/wrapper.tsx +++ b/packages/frontend/src/views/theme/views/auth/sign/up/wrapper.tsx @@ -20,9 +20,7 @@ export const SignUpWrapper = ({ if (!emailSuccess) { return ( - - {children} - + {children} ); } diff --git a/packages/shared/src/admin/plugins.dto.ts b/packages/shared/src/admin/plugins.dto.ts index 1cdf8acb6..1923c6a6c 100644 --- a/packages/shared/src/admin/plugins.dto.ts +++ b/packages/shared/src/admin/plugins.dto.ts @@ -126,7 +126,7 @@ export class ShowPluginsAdminQuery extends PaginationQuery { } export class ExportPluginsAdminBody { - @ApiPropertyOptional({ example: '1.0.0' }) + @ApiPropertyOptional({ example: '0.0.1' }) @IsOptional() @IsString() version?: string;