mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 15:14:56 -04:00
The History PR: III - Editor integration (#1158)
* Update history on editor load and title change Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Add pinning to history from sidebar Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Add CHANGELOG entry Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Only update local history entries Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Update property names to match backend ones Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Show error notification on failure Signed-off-by: Erik Michelson <github@erik.michelson.eu> * Apply requested changes from review - rename use hook to reflect the situation that only local entries will be updated - extract the update ready check from the hook - rename vars to make comparison more clear Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
726b084509
commit
3887de4309
5 changed files with 85 additions and 6 deletions
|
@ -72,6 +72,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- The intro page content can be changed by editing `public/intro.md`.
|
- The intro page content can be changed by editing `public/intro.md`.
|
||||||
- When pasting tables (e.g. from LibreOffice Calc or MS Excel) they get reformatted to markdown tables.
|
- When pasting tables (e.g. from LibreOffice Calc or MS Excel) they get reformatted to markdown tables.
|
||||||
- The history page supports URL parameters that allow bookmarking of a specific search of tags filter.
|
- The history page supports URL parameters that allow bookmarking of a specific search of tags filter.
|
||||||
|
- Users can change the pinning state of a note directly from the editor.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import { useEditorModeFromUrl } from './hooks/useEditorModeFromUrl'
|
||||||
import { UiNotifications } from '../notifications/ui-notifications'
|
import { UiNotifications } from '../notifications/ui-notifications'
|
||||||
import { useNotificationTest } from './use-notification-test'
|
import { useNotificationTest } from './use-notification-test'
|
||||||
import { IframeCommunicatorContextProvider } from './render-context/iframe-communicator-context-provider'
|
import { IframeCommunicatorContextProvider } from './render-context/iframe-communicator-context-provider'
|
||||||
|
import { useUpdateLocalHistoryEntry } from './hooks/useUpdateLocalHistoryEntry'
|
||||||
|
|
||||||
export interface EditorPagePathParams {
|
export interface EditorPagePathParams {
|
||||||
id: string
|
id: string
|
||||||
|
@ -77,6 +78,8 @@ export const EditorPage: React.FC = () => {
|
||||||
|
|
||||||
const [error, loading] = useLoadNoteFromServer()
|
const [error, loading] = useLoadNoteFromServer()
|
||||||
|
|
||||||
|
useUpdateLocalHistoryEntry(!error && !loading)
|
||||||
|
|
||||||
const setRendererToScrollSource = useCallback(() => {
|
const setRendererToScrollSource = useCallback(() => {
|
||||||
scrollSource.current = ScrollSource.RENDERER
|
scrollSource.current = ScrollSource.RENDERER
|
||||||
}, [])
|
}, [])
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import equal from 'fast-deep-equal'
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState, store } from '../../../redux'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
import { EditorPagePathParams } from '../editor-page'
|
||||||
|
import { HistoryEntry, HistoryEntryOrigin } from '../../../redux/history/types'
|
||||||
|
import { updateLocalHistoryEntry } from '../../../redux/history/methods'
|
||||||
|
|
||||||
|
export const useUpdateLocalHistoryEntry = (updateReady: boolean): void => {
|
||||||
|
const { id } = useParams<EditorPagePathParams>()
|
||||||
|
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||||
|
const currentNoteTitle = useSelector((state: ApplicationState) => state.noteDetails.noteTitle)
|
||||||
|
const currentNoteTags = useSelector((state: ApplicationState) => state.noteDetails.frontmatter.tags)
|
||||||
|
|
||||||
|
const lastNoteTitle = useRef('')
|
||||||
|
const lastNoteTags = useRef<string[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!updateReady || userExists) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentNoteTitle === lastNoteTitle.current && equal(currentNoteTags, lastNoteTags.current)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const history = store.getState().history
|
||||||
|
const entry: HistoryEntry = history.find(entry => entry.identifier === id) ?? {
|
||||||
|
identifier: id,
|
||||||
|
title: '',
|
||||||
|
pinStatus: false,
|
||||||
|
lastVisited: '',
|
||||||
|
tags: [],
|
||||||
|
origin: HistoryEntryOrigin.LOCAL
|
||||||
|
}
|
||||||
|
if (entry.origin === HistoryEntryOrigin.REMOTE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
entry.title = currentNoteTitle
|
||||||
|
entry.tags = currentNoteTags
|
||||||
|
entry.lastVisited = new Date().toISOString()
|
||||||
|
updateLocalHistoryEntry(id, entry)
|
||||||
|
lastNoteTitle.current = currentNoteTitle
|
||||||
|
lastNoteTags.current = currentNoteTags
|
||||||
|
}, [updateReady, id, userExists, currentNoteTitle, currentNoteTags])
|
||||||
|
}
|
|
@ -4,20 +4,40 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { SidebarButton } from './sidebar-button'
|
import { SidebarButton } from './sidebar-button'
|
||||||
import { SpecificSidebarEntryProps } from './types'
|
import { SpecificSidebarEntryProps } from './types'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
import { EditorPagePathParams } from '../editor-page'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../../redux'
|
||||||
|
import { toggleHistoryEntryPinning } from '../../../redux/history/methods'
|
||||||
|
import { showErrorNotification } from '../../../redux/ui-notifications/methods'
|
||||||
|
|
||||||
export const PinNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ className, hide }) => {
|
export const PinNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ className, hide }) => {
|
||||||
useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { id } = useParams<EditorPagePathParams>()
|
||||||
|
const history = useSelector((state: ApplicationState) => state.history)
|
||||||
|
|
||||||
const isPinned = true
|
const isPinned = useMemo(() => {
|
||||||
const i18nKey = isPinned ? 'editor.documentBar.pinNoteToHistory' : 'editor.documentBar.pinnedToHistory'
|
const entry = history.find(entry => entry.identifier === id)
|
||||||
|
if (!entry) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return entry.pinStatus
|
||||||
|
}, [id, history])
|
||||||
|
|
||||||
|
const onPinClicked = useCallback(() => {
|
||||||
|
toggleHistoryEntryPinning(id).catch(
|
||||||
|
showErrorNotification(t('landing.history.error.updateEntry.text'))
|
||||||
|
)
|
||||||
|
}, [id, t])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarButton icon={ 'thumb-tack' } className={ className } hide={ hide }>
|
<SidebarButton icon={ 'thumb-tack' } hide={ hide } onClick={ onPinClicked }
|
||||||
<Trans i18nKey={ i18nKey }/>
|
className={ `${ className ?? '' } ${ isPinned ? 'icon-highlighted' : '' }` }>
|
||||||
|
<Trans i18nKey={ isPinned ? 'editor.documentBar.pinnedToHistory' : 'editor.documentBar.pinNoteToHistory' }/>
|
||||||
</SidebarButton>
|
</SidebarButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
background: $entry-hover-bg;
|
background: $entry-hover-bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-highlighted > .sidebar-icon {
|
||||||
|
color: $orange
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue