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

@ -1,8 +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 type { FrontendConfig } from '../../api/config/types'
import type { CheatsheetExtension } from '../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { Linter } from '../../components/editor-page/editor-pane/linter/linter'
import type { MarkdownRendererExtension } from '../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
@ -11,9 +12,14 @@ import type { EventEmitter2 } from 'eventemitter2'
import type React from 'react'
import { Fragment } from 'react'
export interface MarkdownRendererExtensionOptions {
frontendConfig: FrontendConfig
eventEmitter?: EventEmitter2
}
export abstract class AppExtension {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public buildMarkdownRendererExtensions(eventEmitter?: EventEmitter2): MarkdownRendererExtension[] {
public buildMarkdownRendererExtensions(options: MarkdownRendererExtensionOptions): MarkdownRendererExtension[] {
return []
}

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 {
codeFenceRegex
} from '../../../components/editor-page/editor-pane/autocompletions/basic-completion'
import type { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import type { MarkdownRendererExtensionOptions } from '../../base/app-extension'
import { AppExtension } from '../../base/app-extension'
import { PlantumlMarkdownExtension } from './plantuml-markdown-extension'
import type { CompletionSource } from '@codemirror/autocomplete'
@ -19,8 +20,8 @@ import type { CompletionSource } from '@codemirror/autocomplete'
* @see https://plantuml.com
*/
export class PlantumlAppExtension extends AppExtension {
buildMarkdownRendererExtensions(): MarkdownRendererExtension[] {
return [new PlantumlMarkdownExtension()]
buildMarkdownRendererExtensions(options: MarkdownRendererExtensionOptions): MarkdownRendererExtension[] {
return [new PlantumlMarkdownExtension(options.frontendConfig.plantumlServer)]
}
buildCheatsheetExtensions(): CheatsheetExtension[] {

View file

@ -5,30 +5,17 @@
*/
import { mockI18n } from '../../../components/markdown-renderer/test-utils/mock-i18n'
import { TestMarkdownRenderer } from '../../../components/markdown-renderer/test-utils/test-markdown-renderer'
import * as reduxModule from '../../../redux'
import type { ApplicationState } from '../../../redux/application-state'
import { PlantumlMarkdownExtension } from './plantuml-markdown-extension'
import { render } from '@testing-library/react'
import React from 'react'
import { Mock } from 'ts-mockery'
jest.mock('../../../redux')
describe('PlantUML markdown extensions', () => {
beforeAll(() => mockI18n())
it('renders a plantuml codeblock', () => {
jest.spyOn(reduxModule, 'getGlobalState').mockReturnValue(
Mock.of<ApplicationState>({
config: {
plantumlServer: 'https://example.org'
}
})
)
const view = render(
<TestMarkdownRenderer
extensions={[new PlantumlMarkdownExtension()]}
extensions={[new PlantumlMarkdownExtension('https://example.org')]}
content={'```plantuml\nclass Example\n```'}
/>
)
@ -36,17 +23,9 @@ describe('PlantUML markdown extensions', () => {
})
it('renders an error if no server is defined', () => {
jest.spyOn(reduxModule, 'getGlobalState').mockReturnValue(
Mock.of<ApplicationState>({
config: {
plantumlServer: undefined
}
})
)
const view = render(
<TestMarkdownRenderer
extensions={[new PlantumlMarkdownExtension()]}
extensions={[new PlantumlMarkdownExtension(undefined)]}
content={'```plantuml\nclass Example\n```'}
/>
)

View file

@ -1,11 +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 { MarkdownRendererExtension } from '../../../components/markdown-renderer/extensions/base/markdown-renderer-extension'
import type { ComponentReplacer } from '../../../components/markdown-renderer/replace-components/component-replacer'
import { getGlobalState } from '../../../redux'
import { PlantumlNotConfiguredComponentReplacer } from './plantuml-not-configured-component-replacer'
import { Optional } from '@mrdrogdrog/optional'
import type MarkdownIt from 'markdown-it'
@ -20,6 +19,10 @@ import type Token from 'markdown-it/lib/token'
* @see https://plantuml.com
*/
export class PlantumlMarkdownExtension extends MarkdownRendererExtension {
constructor(private plantumlServerUrl: string | undefined) {
super()
}
private plantumlError(markdownIt: MarkdownIt): void {
const defaultRenderer: Renderer.RenderRule = markdownIt.renderer.rules.fence || (() => '')
markdownIt.renderer.rules.fence = (tokens: Token[], idx: number, options: Options, env, slf: Renderer) => {
@ -30,7 +33,7 @@ export class PlantumlMarkdownExtension extends MarkdownRendererExtension {
}
public configureMarkdownIt(markdownIt: MarkdownIt): void {
Optional.ofNullable(getGlobalState().config.plantumlServer)
Optional.ofNullable(this.plantumlServerUrl)
.map((plantumlServer) =>
plantuml(markdownIt, {
openMarker: '```plantuml',

View file

@ -1,14 +1,14 @@
/*
* 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 { CheatsheetExtension } from '../../../components/editor-page/cheatsheet/cheatsheet-extension'
import type { MarkdownRendererExtensionOptions } from '../../base/app-extension'
import { AppExtension } from '../../base/app-extension'
import { SetCheckboxInCheatsheet } from './set-checkbox-in-cheatsheet'
import { SetCheckboxInEditor } from './set-checkbox-in-editor'
import { TaskListMarkdownExtension } from './task-list-markdown-extension'
import type { EventEmitter2 } from 'eventemitter2'
import type React from 'react'
/**
@ -17,8 +17,8 @@ import type React from 'react'
export class TaskListCheckboxAppExtension extends AppExtension {
public static readonly EVENT_NAME = 'TaskListCheckbox'
buildMarkdownRendererExtensions(eventEmitter: EventEmitter2): TaskListMarkdownExtension[] {
return [new TaskListMarkdownExtension(eventEmitter)]
buildMarkdownRendererExtensions(options: MarkdownRendererExtensionOptions): TaskListMarkdownExtension[] {
return [new TaskListMarkdownExtension(options.eventEmitter)]
}
buildEditorExtensionComponent(): React.FC {