mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-18 17:25:16 -04:00
Use precalculated diff in revision viewer (#2179)
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
f55b590777
commit
649ebe48f1
8 changed files with 530 additions and 89 deletions
|
@ -3,74 +3,58 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import React from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer'
|
||||
import { useAsync } from 'react-use'
|
||||
import type { RevisionDetails, RevisionMetadata } from '../../../../api/revisions/types'
|
||||
import { getRevision } from '../../../../api/revisions'
|
||||
import { useApplicationState } from '../../../../hooks/common/use-application-state'
|
||||
import { useNoteMarkdownContent } from '../../../../hooks/common/use-note-markdown-content'
|
||||
import { useIsDarkModeActivated } from '../../../../hooks/common/use-is-dark-mode-activated'
|
||||
import type { AsyncState } from 'react-use/lib/useAsyncFn'
|
||||
import { AsyncLoadingBoundary } from '../../../common/async-loading-boundary'
|
||||
import { applyPatch, parsePatch } from 'diff'
|
||||
import { invertUnifiedPatch } from './invert-unified-patch'
|
||||
import { Optional } from '@mrdrogdrog/optional'
|
||||
|
||||
export interface RevisionViewerProps {
|
||||
selectedRevisionId?: number
|
||||
allRevisions?: RevisionMetadata[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the diff viewer for a given revision and its previous one.
|
||||
*
|
||||
* @param selectedRevisionId The id of the currently selected revision.
|
||||
* @param allRevisions List of metadata for all available revisions.
|
||||
*/
|
||||
export const RevisionViewer: React.FC<RevisionViewerProps> = ({ selectedRevisionId, allRevisions }) => {
|
||||
export const RevisionViewer: React.FC<RevisionViewerProps> = ({ selectedRevisionId }) => {
|
||||
const noteIdentifier = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const markdownContent = useNoteMarkdownContent()
|
||||
const darkModeEnabled = useIsDarkModeActivated()
|
||||
|
||||
const previousRevisionContent = useAsync(async () => {
|
||||
if (!allRevisions || selectedRevisionId === undefined) {
|
||||
return Promise.reject()
|
||||
const { value, error, loading } = useAsync(async () => {
|
||||
if (selectedRevisionId === undefined) {
|
||||
throw new Error('No revision selected')
|
||||
} else {
|
||||
return await getRevision(noteIdentifier, selectedRevisionId)
|
||||
}
|
||||
const revisionIds = allRevisions.map((revisionMetadata) => revisionMetadata.id)
|
||||
const largestId = Math.max(...revisionIds)
|
||||
if (selectedRevisionId === largestId) {
|
||||
return Promise.resolve(markdownContent)
|
||||
}
|
||||
const nextSmallerId = revisionIds
|
||||
.sort()
|
||||
.reverse()
|
||||
.find((id) => id < selectedRevisionId)
|
||||
if (!nextSmallerId) {
|
||||
return Promise.resolve('')
|
||||
}
|
||||
const revision = await getRevision(noteIdentifier, nextSmallerId)
|
||||
return revision.content
|
||||
}, [selectedRevisionId, allRevisions])
|
||||
|
||||
const selectedRevision = useAsync(() => {
|
||||
if (!allRevisions || selectedRevisionId === undefined) {
|
||||
return Promise.reject()
|
||||
}
|
||||
return getRevision(noteIdentifier, selectedRevisionId)
|
||||
}, [selectedRevisionId, noteIdentifier])
|
||||
|
||||
if (selectedRevisionId === undefined || !allRevisions) {
|
||||
const previousRevisionContent = useMemo(() => {
|
||||
return Optional.ofNullable(value)
|
||||
.flatMap((revision) =>
|
||||
Optional.ofNullable(parsePatch(revision.patch)[0])
|
||||
.map((patch) => invertUnifiedPatch(patch))
|
||||
.map((patch) => applyPatch(revision.content, patch))
|
||||
)
|
||||
.orElse('')
|
||||
}, [value])
|
||||
|
||||
if (selectedRevisionId === undefined) {
|
||||
return null
|
||||
}
|
||||
|
||||
// TODO Rework the revision viewer to use pre-calculated diffs
|
||||
// see https://github.com/hedgedoc/react-client/issues/1989
|
||||
|
||||
return (
|
||||
<AsyncLoadingBoundary
|
||||
loading={selectedRevision.loading || previousRevisionContent.loading}
|
||||
componentName={'RevisionViewer'}
|
||||
error={selectedRevision.error || previousRevisionContent.error}>
|
||||
<AsyncLoadingBoundary loading={loading} componentName={'RevisionViewer'} error={error}>
|
||||
<ReactDiffViewer
|
||||
oldValue={previousRevisionContent.value ?? ''}
|
||||
newValue={(selectedRevision as AsyncState<RevisionDetails>).value?.content}
|
||||
oldValue={previousRevisionContent ?? ''}
|
||||
newValue={value?.content ?? ''}
|
||||
splitView={false}
|
||||
compareMethod={DiffMethod.WORDS}
|
||||
useDarkTheme={darkModeEnabled}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue