From ba96f073740a84140c3b63f1332a444323ae1077 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Thu, 6 Oct 2022 21:56:52 +0200 Subject: [PATCH] feat(motd): use iframe renderer for motd Signed-off-by: Tilman Vatteroth --- cypress/e2e/motd.spec.ts | 2 +- cypress/support/get-iframe-content.ts | 10 +++- .../__snapshots__/motd-modal.test.tsx.snap | 53 +++--------------- .../common/motd-modal/motd-modal.test.tsx | 22 ++++---- .../common/motd-modal/motd-modal.tsx | 21 +++++-- .../common/motd-modal/motd-renderer.tsx | 55 ------------------- .../render-page/iframe-markdown-renderer.tsx | 1 + .../rendering-message.ts | 3 +- 8 files changed, 47 insertions(+), 120 deletions(-) delete mode 100644 src/components/common/motd-modal/motd-renderer.tsx diff --git a/cypress/e2e/motd.spec.ts b/cypress/e2e/motd.spec.ts index 3799ab9cb..e3ba8dcae 100644 --- a/cypress/e2e/motd.spec.ts +++ b/cypress/e2e/motd.spec.ts @@ -23,7 +23,7 @@ describe('Motd', () => { headers: { 'Last-Modified': MOCK_LAST_MODIFIED } }) cy.visitHome() - cy.getByCypressId('motd-modal').find('.markdown-body').should('contain.html', motdMockHtml) + cy.getMotdBody().should('contain.html', motdMockHtml) cy.getByCypressId('motd-dismiss') .click() .then(() => { diff --git a/cypress/support/get-iframe-content.ts b/cypress/support/get-iframe-content.ts index 30b75e707..d8838c617 100644 --- a/cypress/support/get-iframe-content.ts +++ b/cypress/support/get-iframe-content.ts @@ -7,12 +7,16 @@ import { RendererType } from '../../src/components/render-page/window-post-message-communicator/rendering-message' declare namespace Cypress { - interface Chainable { + interface Chainable { getIframeBody(rendererType?: RendererType): Chainable getReveal(): Chainable getMarkdownBody(): Chainable + + getIntroBody(): Chainable + + getMotdBody(): Chainable } } @@ -39,3 +43,7 @@ Cypress.Commands.add('getMarkdownBody', () => { Cypress.Commands.add('getIntroBody', () => { return cy.getIframeBody(RendererType.INTRO).findByCypressId('markdown-body') }) + +Cypress.Commands.add('getMotdBody', () => { + return cy.getIframeBody(RendererType.MOTD).findByCypressId('markdown-body') +}) diff --git a/src/components/common/motd-modal/__snapshots__/motd-modal.test.tsx.snap b/src/components/common/motd-modal/__snapshots__/motd-modal.test.tsx.snap index d339358b7..ae11f42d9 100644 --- a/src/components/common/motd-modal/__snapshots__/motd-modal.test.tsx.snap +++ b/src/components/common/motd-modal/__snapshots__/motd-modal.test.tsx.snap @@ -1,40 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`motd modal doesn't allow html in the motd 1`] = ` -
- - This is a mock implementation of a Modal: - - - - - -
-`; - exports[`motd modal doesn't render a modal if no motd has been fetched 1`] = `
- This is a mock implementation of a Modal: + This is a mock implementation of a Modal: diff --git a/src/components/common/motd-modal/motd-modal.test.tsx b/src/components/common/motd-modal/motd-modal.test.tsx index 9c18fcfdb..1115cf85f 100644 --- a/src/components/common/motd-modal/motd-modal.test.tsx +++ b/src/components/common/motd-modal/motd-modal.test.tsx @@ -12,9 +12,12 @@ import type { PropsWithChildren } from 'react' import React from 'react' import type { CommonModalProps } from '../modals/common-modal' import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n' +import * as RenderIframeModule from '../../editor-page/renderer-pane/render-iframe' +import { testId } from '../../../utils/test-id' jest.mock('./fetch-motd') jest.mock('../modals/common-modal') +jest.mock('../../editor-page/renderer-pane/render-iframe') describe('motd modal', () => { beforeAll(mockI18n) @@ -28,11 +31,17 @@ describe('motd modal', () => { jest.spyOn(CommonModalModule, 'CommonModal').mockImplementation((({ children, show }) => { return ( - This is a mock implementation of a Modal: - {show ? {children} : 'Modal is invisible'} + This is a mock implementation of a Modal: {show ? {children} : 'Modal is invisible'} ) }) as React.FC>) + jest.spyOn(RenderIframeModule, 'RenderIframe').mockImplementation((props) => { + return ( + + This is a mock implementation of a iframe renderer. Props: {JSON.stringify(props)} + + ) + }) }) it('renders a modal if a motd was fetched and can dismiss it', async () => { @@ -61,13 +70,4 @@ describe('motd modal', () => { await screen.findByTestId('loaded not visible') expect(view.container).toMatchSnapshot() }) - - it("doesn't allow html in the motd", async () => { - jest.spyOn(fetchMotdModule, 'fetchMotd').mockImplementation(() => { - return Promise.resolve({ motdText: '', lastModified: 'yesterday' }) - }) - const view = render() - await screen.findByTestId('motd-renderer') - expect(view.container).toMatchSnapshot() - }) }) diff --git a/src/components/common/motd-modal/motd-modal.tsx b/src/components/common/motd-modal/motd-modal.tsx index 287b17d10..bc21ed60c 100644 --- a/src/components/common/motd-modal/motd-modal.tsx +++ b/src/components/common/motd-modal/motd-modal.tsx @@ -4,7 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import React, { Suspense, useCallback, useEffect, useState } from 'react' +import React, { Suspense, useCallback, useMemo, useEffect, useState } from 'react' import { Button, Modal } from 'react-bootstrap' import { CommonModal } from '../modals/common-modal' import { Trans, useTranslation } from 'react-i18next' @@ -13,9 +13,11 @@ import { fetchMotd, MOTD_LOCAL_STORAGE_KEY } from './fetch-motd' import { useAsync } from 'react-use' import { Logger } from '../../../utils/logger' import { testId } from '../../../utils/test-id' +import { RenderIframe } from '../../editor-page/renderer-pane/render-iframe' +import { RendererType } from '../../render-page/window-post-message-communicator/rendering-message' +import { EditorToRendererCommunicatorContextProvider } from '../../editor-page/render-context/editor-to-renderer-communicator-context-provider' import { cypressId } from '../../../utils/cypress-attribute' -const MotdRenderer = React.lazy(() => import('./motd-renderer')) const logger = new Logger('Motd') /** @@ -29,6 +31,8 @@ export const MotdModal: React.FC = () => { const { error, loading, value } = useAsync(fetchMotd) const [dismissed, setDismissed] = useState(false) + const lines = useMemo(() => value?.motdText.split('\n'), [value?.motdText]) + const dismiss = useCallback(() => { if (value?.lastModified) { window.localStorage.setItem(MOTD_LOCAL_STORAGE_KEY, value.lastModified) @@ -47,10 +51,17 @@ export const MotdModal: React.FC = () => { } return ( - - + + }> - + + + diff --git a/src/components/common/motd-modal/motd-renderer.tsx b/src/components/common/motd-modal/motd-renderer.tsx deleted file mode 100644 index c1d8459c8..000000000 --- a/src/components/common/motd-modal/motd-renderer.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import React, { useMemo } from 'react' -import { GenericSyntaxMarkdownExtension } from '../../markdown-renderer/markdown-extension/generic-syntax-markdown-extension' -import { useConvertMarkdownToReactDom } from '../../markdown-renderer/hooks/use-convert-markdown-to-react-dom' -import { LinkifyFixMarkdownExtension } from '../../markdown-renderer/markdown-extension/linkify-fix-markdown-extension' -import { EmojiMarkdownExtension } from '../../markdown-renderer/markdown-extension/emoji/emoji-markdown-extension' -import { DebuggerMarkdownExtension } from '../../markdown-renderer/markdown-extension/debugger-markdown-extension' -import { ProxyImageMarkdownExtension } from '../../markdown-renderer/markdown-extension/image/proxy-image-markdown-extension' -import { YoutubeMarkdownExtension } from '../../markdown-renderer/markdown-extension/youtube/youtube-markdown-extension' -import { AlertMarkdownExtension } from '../../markdown-renderer/markdown-extension/alert-markdown-extension' -import { SpoilerMarkdownExtension } from '../../markdown-renderer/markdown-extension/spoiler-markdown-extension' -import { BlockquoteExtraTagMarkdownExtension } from '../../markdown-renderer/markdown-extension/blockquote/blockquote-extra-tag-markdown-extension' -import { VimeoMarkdownExtension } from '../../markdown-renderer/markdown-extension/vimeo/vimeo-markdown-extension' -import { testId } from '../../../utils/test-id' - -export interface MotdRendererProps { - content: string -} - -/** - * Reads the motd from the global application state and renders it as markdown with a subset of the usual features and without HTML support. - */ -export const MotdRenderer: React.FC = ({ content }) => { - const extensions = useMemo( - () => [ - new YoutubeMarkdownExtension(), - new VimeoMarkdownExtension(), - new ProxyImageMarkdownExtension(), - new BlockquoteExtraTagMarkdownExtension(), - new AlertMarkdownExtension(), - new SpoilerMarkdownExtension(), - new GenericSyntaxMarkdownExtension(), - new LinkifyFixMarkdownExtension(), - new EmojiMarkdownExtension(), - new DebuggerMarkdownExtension() - ], - [] - ) - - const lines = useMemo(() => content.split('\n'), [content]) - const dom = useConvertMarkdownToReactDom(lines, extensions, true, false) - - return ( -
- {dom} -
- ) -} - -export default MotdRenderer diff --git a/src/components/render-page/iframe-markdown-renderer.tsx b/src/components/render-page/iframe-markdown-renderer.tsx index ad24506d0..5f84df853 100644 --- a/src/components/render-page/iframe-markdown-renderer.tsx +++ b/src/components/render-page/iframe-markdown-renderer.tsx @@ -159,6 +159,7 @@ export const IframeMarkdownRenderer: React.FC = () => { slideOptions={slideOptions} /> ) + case RendererType.MOTD: case RendererType.INTRO: return (