fix: convert realtime connection dialog into alert

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-03-25 14:30:18 +01:00
parent 925bb85d2f
commit b4f73c0f49
6 changed files with 77 additions and 42 deletions

View file

@ -600,7 +600,7 @@
} }
}, },
"realtime": { "realtime": {
"reconnect": "Reconnecting to HedgeDoc…" "connecting": "Connecting to realtime collaboration server…"
}, },
"settings": { "settings": {
"title": "Settings", "title": "Settings",

View file

@ -17,10 +17,10 @@ import { EditorPane } from './editor-pane/editor-pane'
import { useComponentsFromAppExtensions } from './editor-pane/hooks/use-components-from-app-extensions' import { useComponentsFromAppExtensions } from './editor-pane/hooks/use-components-from-app-extensions'
import { HeadMetaProperties } from './head-meta-properties/head-meta-properties' import { HeadMetaProperties } from './head-meta-properties/head-meta-properties'
import { useUpdateLocalHistoryEntry } from './hooks/use-update-local-history-entry' import { useUpdateLocalHistoryEntry } from './hooks/use-update-local-history-entry'
import { RealtimeConnectionAlert } from './realtime-connection-alert/realtime-connection-alert'
import { Sidebar } from './sidebar/sidebar' import { Sidebar } from './sidebar/sidebar'
import { Splitter } from './splitter/splitter' import { Splitter } from './splitter/splitter'
import type { DualScrollState, ScrollState } from './synced-scroll/scroll-props' import type { DualScrollState, ScrollState } from './synced-scroll/scroll-props'
import { RealtimeConnectionModal } from './websocket-connection-modal/realtime-connection-modal'
import equal from 'fast-deep-equal' import equal from 'fast-deep-equal'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -129,9 +129,9 @@ export const EditorPageContent: React.FC = () => {
<CommunicatorImageLightbox /> <CommunicatorImageLightbox />
<HeadMetaProperties /> <HeadMetaProperties />
<MotdModal /> <MotdModal />
<RealtimeConnectionModal />
<div className={'d-flex flex-column vh-100'}> <div className={'d-flex flex-column vh-100'}>
<AppBar mode={AppBarMode.EDITOR} /> <AppBar mode={AppBarMode.EDITOR} />
<RealtimeConnectionAlert />
<div className={'flex-fill d-flex h-100 w-100 overflow-hidden flex-row'}> <div className={'flex-fill d-flex h-100 w-100 overflow-hidden flex-row'}>
<Splitter <Splitter
left={leftPane} left={leftPane}

View file

@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`realtime connection alert will show if not synced 1`] = `
<div>
<div
class="fade m-0 rounded-0 alert alert-warning show"
role="alert"
>
realtime.connecting
BootstrapIconMock_ArrowRepeat
</div>
</div>
`;
exports[`realtime connection alert won't show if synced 1`] = `<div />`;

View file

@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import * as UseApplicationStateModule from '../../../hooks/common/use-application-state'
import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
import { RealtimeConnectionAlert } from './realtime-connection-alert'
import { render } from '@testing-library/react'
jest.mock('../../../hooks/common/use-application-state')
describe('realtime connection alert', () => {
beforeAll(mockI18n)
it("won't show if synced", () => {
jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation(() => true)
const view = render(<RealtimeConnectionAlert />)
expect(view.container).toMatchSnapshot()
})
it('will show if not synced', () => {
jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation(() => false)
const view = render(<RealtimeConnectionAlert />)
expect(view.container).toMatchSnapshot()
})
})

View file

@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useApplicationState } from '../../../hooks/common/use-application-state'
import { UiIcon } from '../../common/icons/ui-icon'
import React, { Fragment } from 'react'
import { Alert } from 'react-bootstrap'
import { ArrowRepeat as IconArrowRepeat } from 'react-bootstrap-icons'
import { Trans, useTranslation } from 'react-i18next'
/**
* Modal with a spinner that is only shown while reconnecting to the realtime backend
*/
export const RealtimeConnectionAlert: React.FC = () => {
const isSynced = useApplicationState((state) => state.realtimeStatus.isSynced)
useTranslation()
if (isSynced) {
return <Fragment />
}
return (
<Alert variant={'warning'} className={'m-0 rounded-0'}>
<Trans i18nKey={'realtime.connecting'}></Trans>
<UiIcon icon={IconArrowRepeat} spin={true} className={'ms-2 mb-1'} />
</Alert>
)
}

View file

@ -1,39 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useApplicationState } from '../../../hooks/common/use-application-state'
import { WaitSpinner } from '../../common/wait-spinner/wait-spinner'
import React from 'react'
import { Col, Container, Modal, Row } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
/**
* Modal with a spinner that is only shown while reconnecting to the realtime backend
*/
export const RealtimeConnectionModal: React.FC = () => {
const isConnected = useApplicationState((state) => state.realtimeStatus.isSynced)
useTranslation()
return (
<Modal show={!isConnected}>
<Modal.Body>
<Container className={'text-center'}>
<Row className={'mb-4'}>
<Col xs={12}>
<WaitSpinner size={5}></WaitSpinner>
</Col>
</Row>
<Row>
<Col xs={12}>
<span>
<Trans i18nKey={'realtime.reconnect'}></Trans>
</span>
</Col>
</Row>
</Container>
</Modal.Body>
</Modal>
)
}