diff --git a/apps/backend/src/plugins/welcome/config.json b/apps/backend/src/plugins/welcome/config.json index 93919c58c..b79a6c89b 100644 --- a/apps/backend/src/plugins/welcome/config.json +++ b/apps/backend/src/plugins/welcome/config.json @@ -7,6 +7,5 @@ "code": "welcome", "author": "VitNode", "author_url": "https://vitnode.com/", - "support_url": "https://github.com/VitNode/vitnode/issues", - "allow_default": true -} \ No newline at end of file + "support_url": "https://github.com/VitNode/vitnode/issues" +} diff --git a/apps/frontend/src/app/[locale]/(main)/(layout)/page.tsx b/apps/frontend/src/app/[locale]/(main)/(layout)/page.tsx index fe3030911..0cfb0b4f8 100644 --- a/apps/frontend/src/app/[locale]/(main)/(layout)/page.tsx +++ b/apps/frontend/src/app/[locale]/(main)/(layout)/page.tsx @@ -1,21 +1,9 @@ -// ! DO NOT TOUCH THIS FILE!!! -// ! If you remove this then default page plugin will not work +import DefaultPage from '@/plugins/welcome/templates/default-page'; import React from 'react'; -import { getMiddlewareData } from 'vitnode-frontend/api/get-middleware-data'; import { generateMetadataDefaultPage } from 'vitnode-frontend/views/theme/views/default-page'; export const generateMetadata = generateMetadataDefaultPage; -export default async function Page() { - const { plugin_code_default } = await getMiddlewareData(); - - const PageFromTheme = React.lazy(async () => - import(`@/plugins/${plugin_code_default}/templates/default-page`).then( - module => ({ - default: module.default, - }), - ), - ); - - return ; +export default function Page() { + return ; } diff --git a/docs/dev/i18n/namespaces.mdx b/docs/dev/i18n/namespaces.mdx index 1b31c81f3..bd7050561 100644 --- a/docs/dev/i18n/namespaces.mdx +++ b/docs/dev/i18n/namespaces.mdx @@ -66,15 +66,3 @@ Provide the list of namespaces that you want to get access to the translation st You don't need to include the `core.global` namespace in the `namespaces` prop. It's already included by default. - -### Default page - -VitNode has plugin system with option to set plugin as default. That means default plugin will be loaded on the home page. - -To set default page make sure your have `default-page.tsx` inside `templates` folder plugin with `export default` function. - -```tsx title="apps/frontend/src/plugins/{your_plugin}/templates/default-page.tsx" -export default function Page() { - return
Hello World
; -} -``` diff --git a/docs/dev/permissions-admin.mdx b/docs/dev/permissions-admin.mdx index 8832439b6..629d32efd 100644 --- a/docs/dev/permissions-admin.mdx +++ b/docs/dev/permissions-admin.mdx @@ -58,7 +58,6 @@ Edit the `permissions_admin` in the `config.json` file from your plugin. "author": "VitNode", "author_url": "https://vitnode.com/", "support_url": "https://github.com/VitNode/vitnode/issues", - "allow_default": true, // [!code ++] "permissions_admin": [ // [!code ++] diff --git a/packages/backend/scripts/update-plugins.ts b/packages/backend/scripts/update-plugins.ts index 86ea646b6..b707afa15 100644 --- a/packages/backend/scripts/update-plugins.ts +++ b/packages/backend/scripts/update-plugins.ts @@ -14,10 +14,6 @@ export const updatePlugins = async ({ db: NodePgDatabase; pluginsPath: string; }) => { - let isDefaultIndex: null | number = null; - const defaultPlugin = await db.query.core_plugins.findFirst({ - where: (table, { eq }) => eq(table.default, true), - }); const plugins = (await readdir(pluginsPath)).filter( plugin => !['core', 'plugins.module.ts'].includes(plugin), ); @@ -30,58 +26,53 @@ export const updatePlugins = async ({ }, }); - for (const [index, code] of plugins.entries()) { - const pluginPath = join(pluginsPath, code); - const configPath = join(pluginPath, 'config.json'); - if (!existsSync(configPath)) { - continue; - } - - const config = JSON.parse( - await readFile(join(pluginPath, 'config.json'), 'utf8'), - ); + await Promise.all( + plugins.map(async code => { + const pluginPath = join(pluginsPath, code); + const configPath = join(pluginPath, 'config.json'); + if (!existsSync(configPath)) { + return; + } - if (config.allow_default && isDefaultIndex === null) { - isDefaultIndex = index; - } + const config = JSON.parse( + await readFile(join(pluginPath, 'config.json'), 'utf8'), + ); - const plugin = pluginsFromDatabase.find( - plugin => plugin.code === config.code, - ); + const plugin = pluginsFromDatabase.find( + plugin => plugin.code === config.code, + ); - if (plugin) { - await tx - .update(core_plugins) - .set({ - name: config.name, - description: config.description, - support_url: config.support_url, - author: config.author, - author_url: config.author_url, - allow_default: config.allow_default, - version: config.version, - version_code: config.version_code, - }) - .where(eq(core_plugins.id, plugin.id)); - } else { - await tx.insert(core_plugins).values([ - { - name: config.name, - description: config.description, - code: config.code, - support_url: config.support_url, - author: config.author, - author_url: config.author_url, - allow_default: config.allow_default, - version: config.version, - version_code: config.version_code, - default: isDefaultIndex === index && !defaultPlugin, - }, - ]); - } + if (plugin) { + await tx + .update(core_plugins) + .set({ + name: config.name, + description: config.description, + support_url: config.support_url, + author: config.author, + author_url: config.author_url, + version: config.version, + version_code: config.version_code, + }) + .where(eq(core_plugins.id, plugin.id)); + } else { + await tx.insert(core_plugins).values([ + { + name: config.name, + description: config.description, + code: config.code, + support_url: config.support_url, + author: config.author, + author_url: config.author_url, + version: config.version, + version_code: config.version_code, + }, + ]); + } - await tx.execute(sql`commit`); - } + await tx.execute(sql`commit`); + }), + ); // Remove plugins that are not in the plugins folder const pluginsToDelete = pluginsFromDatabase.filter( diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index 581984284..a079498f9 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -46,13 +46,6 @@ 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', diff --git a/packages/backend/src/core/admin/plugins/services/create.service.ts b/packages/backend/src/core/admin/plugins/services/create.service.ts index 6ddf2be72..434080d89 100644 --- a/packages/backend/src/core/admin/plugins/services/create.service.ts +++ b/packages/backend/src/core/admin/plugins/services/create.service.ts @@ -38,7 +38,6 @@ export class CreatePluginsAdminService { $schema: 'https://api.vitnode.com/public/vitnode/plugin.schema.json', code, ...rest, - allow_default: true, nav: [], version: '0.0.1', version_code: 1, diff --git a/packages/backend/src/core/admin/plugins/services/delete.service.ts b/packages/backend/src/core/admin/plugins/services/delete.service.ts index 2167fb9f1..8225c84da 100644 --- a/packages/backend/src/core/admin/plugins/services/delete.service.ts +++ b/packages/backend/src/core/admin/plugins/services/delete.service.ts @@ -9,7 +9,7 @@ import { Injectable, NotFoundException, } from '@nestjs/common'; -import { eq } from 'drizzle-orm'; +import { count, eq } from 'drizzle-orm'; import { existsSync } from 'fs'; import { rm } from 'fs/promises'; import { join } from 'path'; @@ -35,7 +35,6 @@ export class DeletePluginsAdminService { where: (table, { eq }) => eq(table.id, id), columns: { code: true, - default: true, }, }); @@ -43,8 +42,14 @@ export class DeletePluginsAdminService { throw new NotFoundException(); } - if (plugin.default) { - throw new BadRequestException('DEFAULT_PLUGIN_CANNOT_BE_DELETED'); + const [pluginCount] = await this.databaseService.db + .select({ + count: count(), + }) + .from(core_plugins); + + if (pluginCount.count === 1) { + throw new BadRequestException('Cannot delete the last plugin'); } await this.changeFilesHelper.changeFiles({ diff --git a/packages/backend/src/core/admin/plugins/services/edit.service.ts b/packages/backend/src/core/admin/plugins/services/edit.service.ts index 56f0801cb..db4056a42 100644 --- a/packages/backend/src/core/admin/plugins/services/edit.service.ts +++ b/packages/backend/src/core/admin/plugins/services/edit.service.ts @@ -6,7 +6,7 @@ import { Injectable, NotFoundException, } from '@nestjs/common'; -import { eq, ne } from 'drizzle-orm'; +import { eq } from 'drizzle-orm'; import { readFile, writeFile } from 'fs/promises'; import { ConfigPlugin, @@ -20,7 +20,7 @@ export class EditPluginsAdminService { async edit({ code, - body: { default: isDefault = false, ...rest }, + body, }: { body: EditPluginsAdminBody; code: string; @@ -37,26 +37,9 @@ export class EditPluginsAdminService { throw new BadRequestException('PLUGIN_CODE_MISMATCH'); } - if (isDefault) { - if (!plugin.enabled) { - throw new BadRequestException('PLUGIN_NOT_ENABLED'); - } - - // Set all other plugins to default: false - await this.databaseService.db - .update(core_plugins) - .set({ - default: false, - }) - .where(ne(core_plugins.code, code)); - } - const [updatePlugin] = await this.databaseService.db .update(core_plugins) - .set({ - ...rest, - default: isDefault, - }) + .set(body) .where(eq(core_plugins.code, code)) .returning(); @@ -66,11 +49,11 @@ export class EditPluginsAdminService { await readFile(path, 'utf8'), ); - config.name = rest.name; - config.description = rest.description; - config.author = rest.author; - config.author_url = rest.author_url; - config.support_url = rest.support_url; + config.name = body.name; + config.description = body.description; + config.author = body.author; + config.author_url = body.author_url; + config.support_url = body.support_url; await writeFile(path, JSON.stringify(config, null, 2)); 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 189969230..516824eeb 100644 --- a/packages/backend/src/core/admin/plugins/services/export.service.ts +++ b/packages/backend/src/core/admin/plugins/services/export.service.ts @@ -42,9 +42,6 @@ export class ExportPluginsAdminService { const configJSON: ConfigPlugin = JSON.parse( await readFile(pathInfoJSON, 'utf8'), ); - const allow_default = existsSync( - ABSOLUTE_PATHS.plugin({ code }).frontend.default_page, - ); if ( (!version && !configJSON.version) || @@ -66,32 +63,19 @@ export class ExportPluginsAdminService { }); } - 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)); - } 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, + updated_at: new Date(), + }) + .where(eq(core_plugins.code, code)); // Prepare the export const tempFolderName = removeSpecialCharacters( diff --git a/packages/backend/src/core/middleware/services/show.service.ts b/packages/backend/src/core/middleware/services/show.service.ts index 205c5f4dc..9c20b9211 100644 --- a/packages/backend/src/core/middleware/services/show.service.ts +++ b/packages/backend/src/core/middleware/services/show.service.ts @@ -60,7 +60,6 @@ export class ShowMiddlewareService { this.databaseService.db.query.core_plugins.findMany({ columns: { code: true, - default: true, }, }), this.databaseService.db.query.core_languages.findMany({ @@ -76,10 +75,6 @@ export class ShowMiddlewareService { }), ]); - const plugin_code_default = plugins.find(plugin => plugin.default)?.code; - if (!plugin_code_default) { - throw new InternalServerErrorException('Plugin not found'); - } const manifest = await this.getManifests({ langCodes: langs.map(lang => lang.code), }); @@ -124,7 +119,6 @@ export class ShowMiddlewareService { editor: { sticky: configFromDb.editor_sticky ?? false, }, - plugin_code_default, site_description: manifest.map(item => ({ language_code: item.lang, value: item.description, diff --git a/packages/backend/src/database/schema/plugins.ts b/packages/backend/src/database/schema/plugins.ts index a2d822417..ddd122620 100644 --- a/packages/backend/src/database/schema/plugins.ts +++ b/packages/backend/src/database/schema/plugins.ts @@ -15,8 +15,6 @@ export const core_plugins = pgTable( support_url: t.varchar({ length: 255 }).notNull(), author: t.varchar({ length: 100 }).notNull(), author_url: t.varchar({ length: 255 }), - default: t.boolean().notNull().default(false), - allow_default: t.boolean().notNull().default(true), }), t => [ index('core_plugins_code_idx').on(t.code), diff --git a/packages/create-vitnode-app/templates/basic/apps/backend/src/plugins/welcome/config.json b/packages/create-vitnode-app/templates/basic/apps/backend/src/plugins/welcome/config.json index edfcb7c02..d508d4b44 100644 --- a/packages/create-vitnode-app/templates/basic/apps/backend/src/plugins/welcome/config.json +++ b/packages/create-vitnode-app/templates/basic/apps/backend/src/plugins/welcome/config.json @@ -1,4 +1,5 @@ { + "$schema": "https://api.vitnode.com/public/vitnode/plugin.schema.json", "name": "Welcome", "description": "Basic plugin with default page.", "version": "1.0.0", @@ -7,6 +8,5 @@ "author": "VitNode", "author_url": "https://vitnode.com/", "support_url": "https://github.com/VitNode/vitnode/issues", - "allow_default": true, "nav": [] -} \ No newline at end of file +} diff --git a/packages/frontend/src/views/admin/views/core/plugins/actions/create/hooks/use-create-edit-plugin-admin.ts b/packages/frontend/src/views/admin/views/core/plugins/actions/create/hooks/use-create-edit-plugin-admin.ts index 78bf7e2c4..4ea699d3c 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/actions/create/hooks/use-create-edit-plugin-admin.ts +++ b/packages/frontend/src/views/admin/views/core/plugins/actions/create/hooks/use-create-edit-plugin-admin.ts @@ -62,11 +62,7 @@ export const useCreateEditPluginAdmin = ({ ) => { try { if (data) { - await mutationEditApi({ - ...values, - default: data.default, - }); - + await mutationEditApi(values); toast.error(t('edit.success'), { description: values.name, }); 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 19279e68c..f7fdf84be 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 @@ -1,12 +1,10 @@ import { DateFormat } from '@/components/date-format'; -import { Badge } from '@/components/ui/badge'; import { Card } from '@/components/ui/card'; import { HeaderContent } from '@/components/ui/header-content'; import { CONFIG } from '@/helpers/config-with-env'; import { redirect } from '@/navigation'; import { ExternalLink } from 'lucide-react'; import { Metadata } from 'next'; -import { getTranslations } from 'next-intl/server'; import React from 'react'; import { getPluginDataAdmin } from '../query-api'; @@ -32,22 +30,15 @@ export async function generateMetadataDevPluginAdminLayout({ export const DevPluginAdminLayout = async ({ code, children }: Props) => { if (!CONFIG.node_development) await redirect('/admin'); - const [ - { - author, - author_url, - default: isDefault, - description, - name, - updated_at, - version, - version_code, - }, - t, - ] = await Promise.all([ - getPluginDataAdmin(code), - getTranslations('core.global'), - ]); + const { + author, + author_url, + description, + name, + updated_at, + version, + version_code, + } = await getPluginDataAdmin(code); return ( { )} } - h1={ -
- {name} - {isDefault && {t('default')}} -
- } + h1={name} > {CONFIG.node_development && } diff --git a/packages/frontend/src/views/admin/views/core/plugins/plugins-admin-view.tsx b/packages/frontend/src/views/admin/views/core/plugins/plugins-admin-view.tsx index 54f8c614d..222258d9f 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/plugins-admin-view.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/plugins-admin-view.tsx @@ -1,5 +1,4 @@ import { fetcher } from '@/api/fetcher'; -import { getSessionAdminData } from '@/api/get-session-admin-data'; import { HeaderContent } from '@/components/ui/header-content'; import { CONFIG } from '@/helpers/config-with-env'; import { @@ -44,10 +43,9 @@ export const PluginsAdminView = async ({ searchParams, sortEnum: ShowPluginsAdminSortEnum, }); - const [t, data, { restart_server }] = await Promise.all([ + const [t, data] = await Promise.all([ getTranslations('admin.core.plugins'), getData(variables), - getSessionAdminData(), ]); return ( @@ -57,10 +55,7 @@ export const PluginsAdminView = async ({ - + ); }; diff --git a/packages/frontend/src/views/admin/views/core/plugins/table/actions/actions.tsx b/packages/frontend/src/views/admin/views/core/plugins/table/actions/actions.tsx index e7710c5bd..5711cb23e 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/table/actions/actions.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/table/actions/actions.tsx @@ -14,14 +14,13 @@ import React from 'react'; import { ShowPluginAdmin } from 'vitnode-shared/admin/plugins.dto'; import { DeletePluginActionsAdmin } from './delete/delete'; -import { SetDefaultPluginActionsAdmin } from './set-default/set-default'; import { UploadPluginActionsAdmin } from './upload'; export const ActionsItemPluginsAdmin = ({ - isRestartServerRequired, + countPlugins, ...props }: ShowPluginAdmin & { - isRestartServerRequired: boolean; + countPlugins: number; }) => { const t = useTranslations('admin.core.plugins'); const tCore = useTranslations('core.global'); @@ -32,13 +31,6 @@ export const ActionsItemPluginsAdmin = ({ return ( <> - {!props.default && - props.enabled && - !isRestartServerRequired && - (props.allow_default || CONFIG.node_development) && ( - - )} - - - ); -}; diff --git a/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/hooks/use-set-default-admin.ts b/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/hooks/use-set-default-admin.ts deleted file mode 100644 index fbc610866..000000000 --- a/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/hooks/use-set-default-admin.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { useTranslations } from 'next-intl'; -import { toast } from 'sonner'; -import { ShowPluginAdmin } from 'vitnode-shared/admin/plugins.dto'; - -import { mutationEditApi } from '../../../../actions/create/hooks/mutation-edit-api'; - -export const useSetDefaultPluginAdmin = (data: ShowPluginAdmin) => { - const tCore = useTranslations('core.global.errors'); - - const onSubmit = async () => { - try { - await mutationEditApi({ - ...data, - description: data.description ?? '', - author_url: data.author_url ?? '', - default: true, - }); - } catch (_) { - toast.error(tCore('title'), { - description: tCore('internal_server_error'), - }); - - return; - } - }; - - return { - onSubmit, - }; -}; diff --git a/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/set-default.tsx b/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/set-default.tsx deleted file mode 100644 index 6d248d1f4..000000000 --- a/packages/frontend/src/views/admin/views/core/plugins/table/actions/set-default/set-default.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { ShowPluginAdmin } from 'vitnode-shared/admin/plugins.dto'; - -import { ButtonSetDefaultPluginActionsAdmin } from './button'; -import { useSetDefaultPluginAdmin } from './hooks/use-set-default-admin'; - -export const SetDefaultPluginActionsAdmin = (props: ShowPluginAdmin) => { - const { onSubmit } = useSetDefaultPluginAdmin(props); - - return ( -
- - - ); -}; diff --git a/packages/frontend/src/views/admin/views/core/plugins/table/content.tsx b/packages/frontend/src/views/admin/views/core/plugins/table/content.tsx index d53f1a30b..3849de6d4 100644 --- a/packages/frontend/src/views/admin/views/core/plugins/table/content.tsx +++ b/packages/frontend/src/views/admin/views/core/plugins/table/content.tsx @@ -1,7 +1,6 @@ 'use client'; import { DateFormat } from '@/components/date-format'; -import { Badge } from '@/components/ui/badge'; import { DataTable } from '@/components/ui/data-table'; import { ExternalLink } from 'lucide-react'; import { useTranslations } from 'next-intl'; @@ -13,12 +12,8 @@ import { ActionsItemPluginsAdmin } from './actions/actions'; export const ContentPluginsCoreAdmin = ({ edges, page_info, - isRestartServerRequired, -}: ShowPluginsAdminObj & { - isRestartServerRequired: boolean; -}) => { +}: ShowPluginsAdminObj) => { const t = useTranslations('admin.core.plugins'); - const tCore = useTranslations('core.global'); return ( { return ( <> -
- {row.name} - {row.default && {tCore('default')}} -
+ {row.name} {row.description && (

{row.description} @@ -91,7 +83,7 @@ export const ContentPluginsCoreAdmin = ({ cell: ({ row }) => { return ( ); diff --git a/packages/shared/src/admin/plugin.dto.ts b/packages/shared/src/admin/plugin.dto.ts index f74c33787..0e38961e9 100644 --- a/packages/shared/src/admin/plugin.dto.ts +++ b/packages/shared/src/admin/plugin.dto.ts @@ -12,7 +12,6 @@ import { import { TransformString } from '../utils/text-language'; export interface ConfigPlugin extends CreatePluginsAdminBody { - allow_default: boolean; nav?: { children?: { code: string; diff --git a/packages/shared/src/admin/plugins.dto.ts b/packages/shared/src/admin/plugins.dto.ts index 2e5f56cde..db104da04 100644 --- a/packages/shared/src/admin/plugins.dto.ts +++ b/packages/shared/src/admin/plugins.dto.ts @@ -58,9 +58,6 @@ export class CreatePluginsAdminBody { } export class ShowPluginAdmin { - @ApiProperty() - allow_default: boolean; - @ApiProperty() author: string; @@ -73,9 +70,6 @@ export class ShowPluginAdmin { @ApiProperty() created_at: Date; - @ApiProperty() - default: boolean; - @ApiPropertyOptional() description: null | string; diff --git a/packages/shared/src/middleware.dto.ts b/packages/shared/src/middleware.dto.ts index 7cc0b86e8..74c918e83 100644 --- a/packages/shared/src/middleware.dto.ts +++ b/packages/shared/src/middleware.dto.ts @@ -146,9 +146,6 @@ export class ShowMiddlewareObj extends MainSettingsAdminBody { @ApiProperty({ type: [ShowNavStyles] }) nav: ShowNavStyles[]; - @ApiProperty() - plugin_code_default: string; - @ApiProperty({ example: ['core', 'admin'] }) plugins: string[];