feat: fetch frontend config in server side rendering

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-04-04 17:27:20 +02:00
parent 312d1adf6f
commit 24f1b2a361
41 changed files with 270 additions and 220 deletions

View file

@ -5,9 +5,11 @@
*/
import '../../global-styles/dark.scss'
import '../../global-styles/index.scss'
import type { FrontendConfig } from '../api/config/types'
import { ApplicationLoader } from '../components/application-loader/application-loader'
import { BaseUrlContextProvider } from '../components/common/base-url/base-url-context-provider'
import type { BaseUrls } from '../components/common/base-url/base-url-context-provider'
import { BaseUrlContextProvider } from '../components/common/base-url/base-url-context-provider'
import { FrontendConfigContextProvider } from '../components/common/frontend-config-context/frontend-config-context-provider'
import { ErrorBoundary } from '../components/error-boundary/error-boundary'
import { BaseHead } from '../components/layout/base-head'
import { UiNotificationBoundary } from '../components/notifications/ui-notification-boundary'
@ -16,6 +18,8 @@ import { BaseUrlFromEnvExtractor } from '../utils/base-url-from-env-extractor'
import { configureLuxon } from '../utils/configure-luxon'
import { determineCurrentOrigin } from '../utils/determine-current-origin'
import { ExpectedOriginBoundary } from '../utils/expected-origin-boundary'
import { FrontendConfigFetcher } from '../utils/frontend-config-fetcher'
import { isTestMode } from '../utils/test-modes'
import type { AppContext, AppInitialProps, AppProps } from 'next/app'
import React from 'react'
@ -23,6 +27,7 @@ configureLuxon()
interface AppPageProps {
baseUrls: BaseUrls | undefined
frontendConfig: FrontendConfig | undefined
currentOrigin: string | undefined
}
@ -33,31 +38,36 @@ interface AppPageProps {
function HedgeDocApp({ Component, pageProps }: AppProps<AppPageProps>) {
return (
<BaseUrlContextProvider baseUrls={pageProps.baseUrls}>
<ExpectedOriginBoundary currentOrigin={pageProps.currentOrigin}>
<StoreProvider>
<BaseHead />
<ApplicationLoader>
<ErrorBoundary>
<UiNotificationBoundary>
<Component {...pageProps} />
</UiNotificationBoundary>
</ErrorBoundary>
</ApplicationLoader>
</StoreProvider>
</ExpectedOriginBoundary>
<FrontendConfigContextProvider config={pageProps.frontendConfig}>
<ExpectedOriginBoundary currentOrigin={pageProps.currentOrigin}>
<StoreProvider>
<BaseHead />
<ApplicationLoader>
<ErrorBoundary>
<UiNotificationBoundary>
<Component {...pageProps} />
</UiNotificationBoundary>
</ErrorBoundary>
</ApplicationLoader>
</StoreProvider>
</ExpectedOriginBoundary>
</FrontendConfigContextProvider>
</BaseUrlContextProvider>
)
}
const baseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor()
const frontendConfigFetcher = new FrontendConfigFetcher()
HedgeDocApp.getInitialProps = ({ ctx }: AppContext): AppInitialProps<AppPageProps> => {
HedgeDocApp.getInitialProps = async ({ ctx }: AppContext): Promise<AppInitialProps<AppPageProps>> => {
const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls().orElse(undefined)
const frontendConfig = isTestMode ? undefined : await frontendConfigFetcher.fetch(baseUrls) //some tests mock the frontend config. Therefore it needs to be fetched in the browser.
const currentOrigin = determineCurrentOrigin(ctx)
return {
pageProps: {
baseUrls,
frontendConfig,
currentOrigin
}
}

View file

@ -1,15 +1,15 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { Config } from '../../../api/config/types'
import type { FrontendConfig } from '../../../api/config/types'
import { AuthProviderType } from '../../../api/config/types'
import { HttpMethod, respondToMatchingRequest } from '../../../handler-utils/respond-to-matching-request'
import type { NextApiRequest, NextApiResponse } from 'next'
const handler = (req: NextApiRequest, res: NextApiResponse) => {
respondToMatchingRequest<Config>(HttpMethod.GET, req, res, {
respondToMatchingRequest<FrontendConfig>(HttpMethod.GET, req, res, {
allowAnonymous: true,
allowRegister: true,
authProviders: [

View file

@ -1,10 +1,11 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { AuthProviderWithCustomName } from '../api/config/types'
import { AuthProviderType } from '../api/config/types'
import { useFrontendConfig } from '../components/common/frontend-config-context/use-frontend-config'
import { RedirectBack } from '../components/common/redirect-back'
import { ShowIf } from '../components/common/show-if/show-if'
import { LandingLayout } from '../components/landing-layout/landing-layout'
@ -23,7 +24,7 @@ import { Trans, useTranslation } from 'react-i18next'
*/
export const LoginPage: React.FC = () => {
useTranslation()
const authProviders = useApplicationState((state) => state.config.authProviders)
const authProviders = useFrontendConfig().authProviders
const userLoggedIn = useApplicationState((state) => !!state.user)
const ldapProviders = useMemo(() => {

View file

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@ -9,6 +9,7 @@ import { DisplayNameField } from '../components/common/fields/display-name-field
import { NewPasswordField } from '../components/common/fields/new-password-field'
import { PasswordAgainField } from '../components/common/fields/password-again-field'
import { UsernameField } from '../components/common/fields/username-field'
import { useFrontendConfig } from '../components/common/frontend-config-context/use-frontend-config'
import { Redirect } from '../components/common/redirect'
import { LandingLayout } from '../components/landing-layout/landing-layout'
import { fetchAndSetUser } from '../components/login-page/auth/utils'
@ -30,7 +31,7 @@ import { Trans, useTranslation } from 'react-i18next'
export const RegisterPage: NextPage = () => {
useTranslation()
const router = useRouter()
const allowRegister = useApplicationState((state) => state.config.allowRegister)
const allowRegister = useFrontendConfig().allowRegister
const userExists = useApplicationState((state) => !!state.user)
const [username, setUsername] = useState('')