diff --git a/backend/src/admin/core/sessions/authorization/dto/authorization.obj.ts b/backend/src/admin/core/sessions/authorization/dto/authorization.obj.ts index 98aa7d819..480bd26a5 100644 --- a/backend/src/admin/core/sessions/authorization/dto/authorization.obj.ts +++ b/backend/src/admin/core/sessions/authorization/dto/authorization.obj.ts @@ -2,7 +2,7 @@ import { Field, ObjectType } from "@nestjs/graphql"; import { AuthorizationCurrentUserObj } from "@/src/core/sessions/authorization/dto/authorization.obj"; @ObjectType() -class RebuildRequiredObj { +export class RebuildRequiredObj { @Field(() => Boolean) themes: boolean; diff --git a/backend/src/core/sessions/authorization/authorization.service.ts b/backend/src/core/sessions/authorization/authorization.service.ts index 16e2c948e..3487028a3 100644 --- a/backend/src/core/sessions/authorization/authorization.service.ts +++ b/backend/src/core/sessions/authorization/authorization.service.ts @@ -6,6 +6,7 @@ import { AuthorizationCoreSessionsObj } from "./dto/authorization.obj"; import { Ctx } from "@/types/context.type"; import { DatabaseService } from "@/database/database.service"; +import { getConfigFile } from "@/functions/config/get-config-file"; @Injectable() export class AuthorizationCoreSessionsService { @@ -69,6 +70,7 @@ export class AuthorizationCoreSessionsService { res }: Ctx): Promise { const theme_id = await this.getThemeId({ req }); + const config = await getConfigFile(); try { const currentUser = await this.service.authorization({ req, res }); @@ -98,12 +100,14 @@ export class AuthorizationCoreSessionsService { }), avatar_color: user.avatar_color }, - theme_id + theme_id, + rebuild_required: config.rebuild_required }; } catch (error) { return { user: null, - theme_id + theme_id, + rebuild_required: config.rebuild_required }; } } diff --git a/backend/src/core/sessions/authorization/dto/authorization.obj.ts b/backend/src/core/sessions/authorization/dto/authorization.obj.ts index fa5a4d8ef..d1a2ba6c1 100644 --- a/backend/src/core/sessions/authorization/dto/authorization.obj.ts +++ b/backend/src/core/sessions/authorization/dto/authorization.obj.ts @@ -1,6 +1,7 @@ import { Field, Int, ObjectType } from "@nestjs/graphql"; import { User } from "@/utils/decorators/user.decorator"; +import { RebuildRequiredObj } from "@/src/admin/core/sessions/authorization/dto/authorization.obj"; @ObjectType() export class AuthorizationCurrentUserObj extends User { @@ -23,4 +24,7 @@ export class AuthorizationCoreSessionsObj { @Field(() => Int, { nullable: true }) theme_id: number | null; + + @Field(() => RebuildRequiredObj) + rebuild_required: RebuildRequiredObj; } diff --git a/backend/src/schema.gql b/backend/src/schema.gql index 7ede58c76..2044aa69d 100644 --- a/backend/src/schema.gql +++ b/backend/src/schema.gql @@ -8,6 +8,7 @@ type AuthorizationAdminSessionsObj { } type AuthorizationCoreSessionsObj { + rebuild_required: RebuildRequiredObj! theme_id: Int user: AuthorizationCurrentUserObj } diff --git a/frontend/admin/core/layout/header/header-admin.tsx b/frontend/admin/core/layout/header/header-admin.tsx index 2ba32914b..4b0ec9e06 100644 --- a/frontend/admin/core/layout/header/header-admin.tsx +++ b/frontend/admin/core/layout/header/header-admin.tsx @@ -1,6 +1,6 @@ -import { LanguageSwitcher } from "@/components/switchers/language-switcher"; import { UserBarAdmin } from "./user-bar/user-bar-admin"; import { DarkLightModeSwitcher } from "@/components/switchers/dark-light-mode-switcher"; +import { LangSwitcherHeaderAdmin } from "./lang-switcher"; export const HeaderAdmin = () => { return ( @@ -16,7 +16,7 @@ export const HeaderAdmin = () => { )}
- +
diff --git a/frontend/admin/core/layout/header/lang-switcher.tsx b/frontend/admin/core/layout/header/lang-switcher.tsx new file mode 100644 index 000000000..238ee43fe --- /dev/null +++ b/frontend/admin/core/layout/header/lang-switcher.tsx @@ -0,0 +1,15 @@ +"use client"; + +import { LanguageSwitcher } from "@/components/switchers/language-switcher"; + +import { useSessionAdmin } from "../../hooks/use-session-admin"; + +export const LangSwitcherHeaderAdmin = () => { + const { rebuild_required } = useSessionAdmin(); + + if (rebuild_required.langs && process.env.NODE_ENV !== "development") { + return null; + } + + return ; +}; diff --git a/frontend/app/[locale]/(apps)/(main)/session-provider.tsx b/frontend/app/[locale]/(apps)/(main)/session-provider.tsx index 5647b9609..53704018a 100644 --- a/frontend/app/[locale]/(apps)/(main)/session-provider.tsx +++ b/frontend/app/[locale]/(apps)/(main)/session-provider.tsx @@ -16,7 +16,8 @@ export const SessionProvider = ({ children, data }: Props) => { value={{ session: data?.core_sessions__authorization.user, theme_id: data?.core_sessions__authorization.theme_id ?? null, - nav: data?.core_nav__show.edges ?? [] + nav: data?.core_nav__show.edges ?? [], + rebuild_required: data?.core_sessions__authorization.rebuild_required }} > {children} diff --git a/frontend/components/switchers/language-switcher.tsx b/frontend/components/switchers/language-switcher.tsx index 314596768..1bad35161 100644 --- a/frontend/components/switchers/language-switcher.tsx +++ b/frontend/components/switchers/language-switcher.tsx @@ -13,6 +13,7 @@ import { import { Button } from "@/components/ui/button"; import { usePathname, useRouter } from "@/i18n"; import { useGlobals } from "@/hooks/core/use-globals"; +import { useSession } from "@/hooks/core/use-session"; export const LanguageSwitcher = () => { const t = useTranslations("core"); @@ -21,8 +22,14 @@ export const LanguageSwitcher = () => { const { replace } = useRouter(); const pathname = usePathname(); const enableLocales = languages.filter(lang => lang.enabled); + const { rebuild_required } = useSession(); - if (enableLocales.length <= 1) return null; + if ( + enableLocales.length <= 1 || + (rebuild_required && process.env.NODE_ENV !== "development") + ) { + return null; + } return ( diff --git a/frontend/components/switchers/theme/theme-switcher.tsx b/frontend/components/switchers/theme/theme-switcher.tsx index ee53a4d56..e903be52b 100644 --- a/frontend/components/switchers/theme/theme-switcher.tsx +++ b/frontend/components/switchers/theme/theme-switcher.tsx @@ -18,9 +18,9 @@ import { mutationApi } from "./mutation-api"; export const ThemeSwitcher = () => { const t = useTranslations("core"); const { themes } = useGlobals(); - const { theme_id } = useSession(); + const { rebuild_required, theme_id } = useSession(); - if (themes.length <= 1) return null; + if (themes.length <= 1 || rebuild_required.themes) return null; return ( diff --git a/frontend/graphql/hooks.ts b/frontend/graphql/hooks.ts index d3b405d85..9b1bb54a4 100644 --- a/frontend/graphql/hooks.ts +++ b/frontend/graphql/hooks.ts @@ -24,6 +24,7 @@ export type AuthorizationAdminSessionsObj = { export type AuthorizationCoreSessionsObj = { __typename?: 'AuthorizationCoreSessionsObj'; + rebuild_required: RebuildRequiredObj; theme_id?: Maybe; user?: Maybe; }; @@ -1422,7 +1423,7 @@ export type Core_Members__ProfilesQuery = { __typename?: 'Query', core_members__ export type Core_Sessions__AuthorizationQueryVariables = Exact<{ [key: string]: never; }>; -export type Core_Sessions__AuthorizationQuery = { __typename?: 'Query', core_sessions__authorization: { __typename?: 'AuthorizationCoreSessionsObj', theme_id?: number | null, user?: { __typename?: 'AuthorizationCurrentUserObj', email: string, id: number, name_seo: string, is_admin: boolean, is_mod: boolean, name: string, newsletter: boolean, avatar_color: string, avatar?: { __typename?: 'AvatarUser', id: number, dir_folder: string, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } } | null }, core_languages__show: { __typename?: 'ShowCoreLanguagesObj', edges: Array<{ __typename?: 'ShowCoreLanguages', code: string }> }, core_nav__show: { __typename?: 'ShowCoreNavObj', edges: Array<{ __typename?: 'ShowCoreNav', id: number, href: string, external: boolean, position: number, children: Array<{ __typename?: 'ShowCoreNavItem', id: number, position: number, external: boolean, href: string, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }> } }; +export type Core_Sessions__AuthorizationQuery = { __typename?: 'Query', core_sessions__authorization: { __typename?: 'AuthorizationCoreSessionsObj', theme_id?: number | null, user?: { __typename?: 'AuthorizationCurrentUserObj', email: string, id: number, name_seo: string, is_admin: boolean, is_mod: boolean, name: string, newsletter: boolean, avatar_color: string, avatar?: { __typename?: 'AvatarUser', id: number, dir_folder: string, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } } | null, rebuild_required: { __typename?: 'RebuildRequiredObj', themes: boolean, langs: boolean, plugins: boolean } }, core_languages__show: { __typename?: 'ShowCoreLanguagesObj', edges: Array<{ __typename?: 'ShowCoreLanguages', code: string }> }, core_nav__show: { __typename?: 'ShowCoreNavObj', edges: Array<{ __typename?: 'ShowCoreNav', id: number, href: string, external: boolean, position: number, children: Array<{ __typename?: 'ShowCoreNavItem', id: number, position: number, external: boolean, href: string, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }> } }; export type Forum_Forums__ShowQueryVariables = Exact<{ [key: string]: never; }>; @@ -2349,6 +2350,11 @@ export const Core_Sessions__Authorization = gql` } } theme_id + rebuild_required { + themes + langs + plugins + } } core_languages__show { edges { diff --git a/frontend/graphql/queries/core/sessions/core_sessions__authorization.gql b/frontend/graphql/queries/core/sessions/core_sessions__authorization.gql index ef27bc2da..2db13ec52 100644 --- a/frontend/graphql/queries/core/sessions/core_sessions__authorization.gql +++ b/frontend/graphql/queries/core/sessions/core_sessions__authorization.gql @@ -23,6 +23,11 @@ query Core_sessions__authorization { } } theme_id + rebuild_required { + themes + langs + plugins + } } core_languages__show { edges { diff --git a/frontend/hooks/core/use-session.ts b/frontend/hooks/core/use-session.ts index d750f96ee..292a03b77 100644 --- a/frontend/hooks/core/use-session.ts +++ b/frontend/hooks/core/use-session.ts @@ -1,9 +1,14 @@ import { createContext, useContext } from "react"; -import type { AuthorizationCurrentUserObj, ShowCoreNav } from "@/graphql/hooks"; +import type { + AuthorizationCurrentUserObj, + RebuildRequiredObj, + ShowCoreNav +} from "@/graphql/hooks"; interface Args { nav: ShowCoreNav[]; + rebuild_required: RebuildRequiredObj; session: Omit | undefined | null; theme_id: number | null; } @@ -11,7 +16,12 @@ interface Args { export const SessionContext = createContext({ session: null, theme_id: null, - nav: [] + nav: [], + rebuild_required: { + themes: false, + langs: false, + plugins: false + } }); export const useSession = () => useContext(SessionContext); diff --git a/package.json b/package.json index 965844ee0..cb41650da 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "prepare": "npx husky install", "config:init": "cd backend && pnpm config:init && cd ..", "config:finish": "cd backend && pnpm config:finish && cd ..", - "backend:build": "cd backend && pnpm build && cd ..", + "backend:build": "cd backend && pnpm build && cd .. pnpm config:finish", "backend:start": "cd backend && pnpm start", "backend:dev": "cd backend && pnpm dev", "frontend:build": "cd frontend && pnpm build && cd ..",