mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-12 22:26:08 -04:00
feat: fetch frontend config in server side rendering
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
312d1adf6f
commit
24f1b2a361
41 changed files with 270 additions and 220 deletions
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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 React, { createContext, useState } from 'react'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { createContext, useState } from 'react'
|
||||
|
||||
export interface BaseUrls {
|
||||
renderer: string
|
||||
|
@ -28,9 +28,8 @@ export const BaseUrlContextProvider: React.FC<PropsWithChildren<BaseUrlContextPr
|
|||
children
|
||||
}) => {
|
||||
const [baseUrlState] = useState<undefined | BaseUrls>(() => baseUrls)
|
||||
|
||||
return baseUrlState === undefined ? (
|
||||
<div className={'text-white'}>HedgeDoc is not configured correctly! Please check the server log.</div>
|
||||
<span className={'text-white bg-dark'}>HedgeDoc is not configured correctly! Please check the server log.</span>
|
||||
) : (
|
||||
<baseUrlContext.Provider value={baseUrlState}>{children}</baseUrlContext.Provider>
|
||||
)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* 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 { useApplicationState } from '../../../hooks/common/use-application-state'
|
||||
import { useFrontendConfig } from '../frontend-config-context/use-frontend-config'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import styles from './branding.module.scss'
|
||||
import React, { useMemo } from 'react'
|
||||
|
@ -21,7 +21,7 @@ export interface BrandingProps {
|
|||
* @param delimiter If the delimiter between the HedgeDoc logo and the branding should be shown.
|
||||
*/
|
||||
export const Branding: React.FC<BrandingProps> = ({ inline = false, delimiter = true }) => {
|
||||
const branding = useApplicationState((state) => state.config.branding)
|
||||
const branding = useFrontendConfig().branding
|
||||
const showBranding = !!branding.name || !!branding.logo
|
||||
|
||||
const brandingDom = useMemo(() => {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { FrontendConfig } from '../../../api/config/types'
|
||||
import { createContext } from 'react'
|
||||
|
||||
export const frontendConfigContext = createContext<FrontendConfig | undefined>(undefined)
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { getConfig } from '../../../api/config'
|
||||
import type { FrontendConfig } from '../../../api/config/types'
|
||||
import { useBaseUrl } from '../../../hooks/common/use-base-url'
|
||||
import { Logger } from '../../../utils/logger'
|
||||
import { frontendConfigContext } from './context'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
const logger = new Logger('FrontendConfigContextProvider')
|
||||
|
||||
interface FrontendConfigContextProviderProps extends PropsWithChildren {
|
||||
config?: FrontendConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the given frontend configuration in a context or renders an error message otherwise.
|
||||
*
|
||||
* @param config the frontend config to provoide
|
||||
* @param children the react elements to show if the config is valid
|
||||
*/
|
||||
export const FrontendConfigContextProvider: React.FC<FrontendConfigContextProviderProps> = ({ config, children }) => {
|
||||
const [configState, setConfigState] = useState<undefined | FrontendConfig>(() => config)
|
||||
|
||||
const baseUrl = useBaseUrl()
|
||||
|
||||
useEffect(() => {
|
||||
if (config === undefined && configState === undefined) {
|
||||
logger.debug('Fetching Config client side')
|
||||
getConfig(baseUrl)
|
||||
.then((config) => setConfigState(config))
|
||||
.catch((error) => logger.error(error))
|
||||
}
|
||||
}, [baseUrl, config, configState])
|
||||
|
||||
return configState === undefined ? (
|
||||
<span className={'text-white bg-dark'}>No frontend config received! Please check the server log.</span>
|
||||
) : (
|
||||
<frontendConfigContext.Provider value={configState}>{children}</frontendConfigContext.Provider>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { FrontendConfig } from '../../../api/config/types'
|
||||
import { frontendConfigContext } from './context'
|
||||
import { Optional } from '@mrdrogdrog/optional'
|
||||
import { useContext } from 'react'
|
||||
|
||||
/**
|
||||
* Retrieves the current frontend config from the next react context.
|
||||
*/
|
||||
export const useFrontendConfig = (): FrontendConfig => {
|
||||
return Optional.ofNullable(useContext(frontendConfigContext)).orElseThrow(
|
||||
() => new Error('No frontend config context found. Did you forget to use the provider component?')
|
||||
)
|
||||
}
|
|
@ -22,7 +22,7 @@ jest.mock('../../../hooks/common/use-base-url')
|
|||
|
||||
describe('motd modal', () => {
|
||||
beforeAll(async () => {
|
||||
jest.spyOn(UseBaseUrlModule, 'useBaseUrl').mockImplementation(() => 'https://example.org')
|
||||
jest.spyOn(UseBaseUrlModule, 'useBaseUrl').mockImplementation(() => new URL('https://example.org'))
|
||||
await mockI18n()
|
||||
})
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue