From 1c73e99b0af3c03e661008aaf6a443c7908b8b14 Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Sun, 15 Sep 2024 20:39:00 +0200 Subject: [PATCH] enhancement(note-deletion): allow to keep uploads This adds support for keeping the uploads attached to a note when deleting the same note. This is done by a simple checkbox that can be clicked in the DeletionModal. To do this, some parts of the note deletion had to be refactored, especially in the case of the history page. Both the note deletion and history removal methods used the same modal, which isn't applicable now anymore. Additionally, there was a bug that the modal checked for ownership in the frontend before allowing the note deletion. However, in the context of the history page, the ownership couldn't be evaluated since the backend API didn't include that information. This is now fixed as well. Signed-off-by: Erik Michelson --- backend/src/history/history-entry.dto.ts | 18 ++++- backend/src/history/history.service.ts | 2 + frontend/locales/en.json | 4 +- frontend/src/api/history/types.ts | 1 + frontend/src/api/notes/index.ts | 7 +- .../common/modals/deletion-modal.tsx | 3 + .../hooks/use-update-local-history-entry.ts | 8 +- .../delete-note-modal.tsx | 53 +++++++------ .../delete-note-sidebar-entry.tsx | 21 +++--- .../entry-menu/delete-note-item.tsx | 33 +++++--- .../dropdown-item-with-deletion-modal.tsx | 75 ------------------- .../history-page/entry-menu/entry-menu.tsx | 12 ++- .../entry-menu/remove-note-entry-item.tsx | 43 +++++++---- .../history-card/history-card.tsx | 10 ++- .../history-content/history-content.tsx | 6 +- .../history-table/history-table-row.tsx | 10 ++- frontend/src/pages/api/private/me/history.ts | 12 ++- frontend/src/redux/history/methods.ts | 3 +- 18 files changed, 163 insertions(+), 158 deletions(-) delete mode 100644 frontend/src/components/history-page/entry-menu/dropdown-item-with-deletion-modal.tsx diff --git a/backend/src/history/history-entry.dto.ts b/backend/src/history/history-entry.dto.ts index eaf2e1b5a..c5ae719fa 100644 --- a/backend/src/history/history-entry.dto.ts +++ b/backend/src/history/history-entry.dto.ts @@ -5,7 +5,13 @@ */ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; -import { IsArray, IsBoolean, IsDate, IsString } from 'class-validator'; +import { + IsArray, + IsBoolean, + IsDate, + IsOptional, + IsString, +} from 'class-validator'; import { BaseDto } from '../utils/base.dto.'; @@ -26,6 +32,16 @@ export class HistoryEntryDto extends BaseDto { @ApiProperty() title: string; + /** + * The username of the owner of the note + * Might be null for anonymous notes + * @example "alice" + */ + @IsOptional() + @IsString() + @ApiProperty() + owner: string | null; + /** * Datestring of the last time this note was updated * @example "2020-12-01 12:23:34" diff --git a/backend/src/history/history.service.ts b/backend/src/history/history.service.ts index 57928333c..93356e807 100644 --- a/backend/src/history/history.service.ts +++ b/backend/src/history/history.service.ts @@ -180,6 +180,7 @@ export class HistoryService { */ async toHistoryEntryDto(entry: HistoryEntry): Promise { const note = await entry.note; + const owner = await note.owner; const revision = await this.revisionsService.getLatestRevision(note); return { identifier: await getIdentifier(entry), @@ -187,6 +188,7 @@ export class HistoryService { tags: (await revision.tags).map((tag) => tag.name), title: revision.title ?? '', pinStatus: entry.pinStatus, + owner: owner ? owner.username : null, }; } } diff --git a/frontend/locales/en.json b/frontend/locales/en.json index b77d8a8ad..3bf141350 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -445,7 +445,9 @@ "title": "Delete note", "question": "Do you really want to delete this note?", "warning": "All users will lose their connection. This process is irreversible.", - "button": "Delete note" + "deleteButton": "Delete note and uploads", + "deleteButtonKeepMedia": "Delete note but keep uploads", + "keepMedia": "Keep uploads?" }, "permissions": { "title": "Permissions", diff --git a/frontend/src/api/history/types.ts b/frontend/src/api/history/types.ts index 9b8f0e2f1..9b1d972e3 100644 --- a/frontend/src/api/history/types.ts +++ b/frontend/src/api/history/types.ts @@ -17,6 +17,7 @@ export interface HistoryEntryPutDto { export interface HistoryEntry { identifier: string title: string + owner: string | null lastVisitedAt: string tags: string[] pinStatus: boolean diff --git a/frontend/src/api/notes/index.ts b/frontend/src/api/notes/index.ts index e49f80264..8f1dcab3a 100644 --- a/frontend/src/api/notes/index.ts +++ b/frontend/src/api/notes/index.ts @@ -79,14 +79,13 @@ export const createNoteWithPrimaryAlias = async (markdown: string, primaryAlias: * Deletes the specified note. * * @param noteIdOrAlias The id or alias of the note to delete. + * @param keepMedia Whether to keep the uploaded media associated with the note. * @throws {Error} when the api request wasn't successful. */ -export const deleteNote = async (noteIdOrAlias: string): Promise => { +export const deleteNote = async (noteIdOrAlias: string, keepMedia: boolean): Promise => { await new DeleteApiRequestBuilder('notes/' + noteIdOrAlias) .withJsonBody({ - keepMedia: false - // TODO Ask whether the user wants to keep the media uploaded to the note. - // https://github.com/hedgedoc/hedgedoc/issues/2928 + keepMedia }) .sendRequest() } diff --git a/frontend/src/components/common/modals/deletion-modal.tsx b/frontend/src/components/common/modals/deletion-modal.tsx index 96900c99a..43efffc2d 100644 --- a/frontend/src/components/common/modals/deletion-modal.tsx +++ b/frontend/src/components/common/modals/deletion-modal.tsx @@ -15,6 +15,7 @@ export interface DeletionModalProps extends CommonModalProps { onConfirm: () => void deletionButtonI18nKey: string disabled?: boolean + footerContent?: React.ReactNode } /** @@ -39,6 +40,7 @@ export const DeletionModal: React.FC> = ({ titleIcon, children, disabled = false, + footerContent, ...props }) => { useTranslation() @@ -52,6 +54,7 @@ export const DeletionModal: React.FC> = ({ {...props}> {children} + {footerContent} diff --git a/frontend/src/components/editor-page/hooks/use-update-local-history-entry.ts b/frontend/src/components/editor-page/hooks/use-update-local-history-entry.ts index 55fc596a5..d4b2e7270 100644 --- a/frontend/src/components/editor-page/hooks/use-update-local-history-entry.ts +++ b/frontend/src/components/editor-page/hooks/use-update-local-history-entry.ts @@ -20,7 +20,7 @@ export const useUpdateLocalHistoryEntry = (): void => { const userExists = useApplicationState((state) => !!state.user) const currentNoteTitle = useApplicationState((state) => state.noteDetails?.title ?? '') const currentNoteTags = useApplicationState((state) => state.noteDetails?.frontmatter.tags ?? []) - + const currentNoteOwner = useApplicationState((state) => state.noteDetails?.permissions.owner) const lastNoteTitle = useRef('') const lastNoteTags = useRef([]) @@ -38,7 +38,8 @@ export const useUpdateLocalHistoryEntry = (): void => { pinStatus: false, lastVisitedAt: '', tags: [], - origin: HistoryEntryOrigin.LOCAL + origin: HistoryEntryOrigin.LOCAL, + owner: null } if (entry.origin === HistoryEntryOrigin.REMOTE) { return @@ -46,9 +47,10 @@ export const useUpdateLocalHistoryEntry = (): void => { const updatedEntry = { ...entry } updatedEntry.title = currentNoteTitle updatedEntry.tags = currentNoteTags + updatedEntry.owner = currentNoteOwner updatedEntry.lastVisitedAt = new Date().toISOString() updateLocalHistoryEntry(id, updatedEntry) lastNoteTitle.current = currentNoteTitle lastNoteTags.current = currentNoteTags - }, [id, userExists, currentNoteTitle, currentNoteTags]) + }, [id, userExists, currentNoteTitle, currentNoteTags, currentNoteOwner]) } diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal.tsx index b08219025..e4c26ec69 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal.tsx @@ -7,20 +7,14 @@ import { useNoteTitle } from '../../../../../hooks/common/use-note-title' import { cypressId } from '../../../../../utils/cypress-attribute' import type { ModalVisibilityProps } from '../../../../common/modals/common-modal' import { DeletionModal } from '../../../../common/modals/deletion-modal' -import React from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { Trans } from 'react-i18next' import { useIsOwner } from '../../../../../hooks/common/use-is-owner' -export interface DeleteHistoryNoteModalProps { - modalTitleI18nKey?: string - modalQuestionI18nKey?: string - modalWarningI18nKey?: string - modalButtonI18nKey?: string -} - export interface DeleteNoteModalProps extends ModalVisibilityProps { optionalNoteTitle?: string - onConfirm: () => void + onConfirm: (keepMedia: boolean) => void + overrideIsOwner?: boolean } /** @@ -31,40 +25,53 @@ export interface DeleteNoteModalProps extends ModalVisibilityProps { * @param onHide A callback that fires if the modal should be hidden without confirmation * @param onConfirm A callback that fires if the user confirmed the request * @param modalTitleI18nKey optional i18nKey for the title - * @param modalQuestionI18nKey optional i18nKey for the question - * @param modalWarningI18nKey optional i18nKey for the warning - * @param modalButtonI18nKey optional i18nKey for the button */ -export const DeleteNoteModal: React.FC = ({ +export const DeleteNoteModal: React.FC = ({ optionalNoteTitle, show, onHide, onConfirm, - modalTitleI18nKey, - modalQuestionI18nKey, - modalWarningI18nKey, - modalButtonI18nKey + overrideIsOwner }) => { + const [keepMedia, setKeepMedia] = useState(false) const noteTitle = useNoteTitle() - const isOwner = useIsOwner() + const isOwnerOfCurrentEditedNote = useIsOwner() + + const deletionButtonI18nKey = useMemo(() => { + return keepMedia ? 'editor.modal.deleteNote.deleteButtonKeepMedia' : 'editor.modal.deleteNote.deleteButton' + }, [keepMedia]) + + const handleConfirm = useCallback(() => { + onConfirm(keepMedia) + }, [onConfirm, keepMedia]) + + const isOwner = overrideIsOwner ?? isOwnerOfCurrentEditedNote return ( + titleI18nKey={'editor.modal.deleteNote.title'} + footerContent={ + + }>
- +
  • {optionalNoteTitle ?? noteTitle}
- +
) diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-sidebar-entry.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-sidebar-entry.tsx index e877fab02..8cc534bb1 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-sidebar-entry.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-sidebar-entry.tsx @@ -32,15 +32,18 @@ export const DeleteNoteSidebarEntry: React.FC { - if (noteId === undefined) { - return - } - deleteNote(noteId) - .then(() => router.push('/history')) - .catch(showErrorNotification('landing.history.error.deleteNote.text')) - .finally(closeModal) - }, [closeModal, noteId, router, showErrorNotification]) + const deleteNoteAndCloseDialog = useCallback( + (keepMedia: boolean) => { + if (noteId === undefined) { + return + } + deleteNote(noteId, keepMedia) + .then(() => router.push('/history')) + .catch(showErrorNotification('landing.history.error.deleteNote.text')) + .finally(closeModal) + }, + [closeModal, noteId, router, showErrorNotification] + ) if (!userIsOwner) { return null diff --git a/frontend/src/components/history-page/entry-menu/delete-note-item.tsx b/frontend/src/components/history-page/entry-menu/delete-note-item.tsx index 7f67d68ee..9e4d70210 100644 --- a/frontend/src/components/history-page/entry-menu/delete-note-item.tsx +++ b/frontend/src/components/history-page/entry-menu/delete-note-item.tsx @@ -3,13 +3,18 @@ * * SPDX-License-Identifier: AGPL-3.0-only */ -import { DropdownItemWithDeletionModal } from './dropdown-item-with-deletion-modal' -import React from 'react' +import React, { Fragment } from 'react' import { Trash as IconTrash } from 'react-bootstrap-icons' +import { Dropdown } from 'react-bootstrap' +import { UiIcon } from '../../common/icons/ui-icon' +import { Trans } from 'react-i18next' +import { DeleteNoteModal } from '../../editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal' +import { useBooleanState } from '../../../hooks/common/use-boolean-state' export interface DeleteNoteItemProps { - onConfirm: () => void + onConfirm: (keepMedia: boolean) => void noteTitle: string + isOwner: boolean } /** @@ -18,13 +23,21 @@ export interface DeleteNoteItemProps { * @param noteTitle The title of the note to delete to show it in the deletion confirmation modal * @param onConfirm The callback that is fired when the deletion is confirmed */ -export const DeleteNoteItem: React.FC = ({ noteTitle, onConfirm }) => { +export const DeleteNoteItem: React.FC = ({ noteTitle, onConfirm, isOwner }) => { + const [isModalVisible, showModal, hideModal] = useBooleanState() return ( - + + + + + + + ) } diff --git a/frontend/src/components/history-page/entry-menu/dropdown-item-with-deletion-modal.tsx b/frontend/src/components/history-page/entry-menu/dropdown-item-with-deletion-modal.tsx deleted file mode 100644 index 8299d75b8..000000000 --- a/frontend/src/components/history-page/entry-menu/dropdown-item-with-deletion-modal.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ -import { useBooleanState } from '../../../hooks/common/use-boolean-state' -import { UiIcon } from '../../common/icons/ui-icon' -import type { DeleteHistoryNoteModalProps } from '../../editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal' -import { DeleteNoteModal } from '../../editor-page/sidebar/specific-sidebar-entries/delete-note-sidebar-entry/delete-note-modal' -import React, { Fragment, useCallback } from 'react' -import { Dropdown } from 'react-bootstrap' -import type { Icon } from 'react-bootstrap-icons' -import { Trans, useTranslation } from 'react-i18next' - -export interface DropdownItemWithDeletionModalProps { - onConfirm: () => void - itemI18nKey: string - modalIcon: Icon - noteTitle: string - className?: string -} - -/** - * Renders a dropdown item and the corresponding deletion modal. - * - * @param onConfirm A callback that fires if the user confirmed the request - * @param noteTitle The note title to be displayed - * @param modalTitleI18nKey The i18nKey for title to be shown in the modal - * @param modalButtonI18nKey The i18nKey for button to be shown in the modal - * @param itemI18nKey The i18nKey for the dropdown item - * @param modalIcon The icon for the dropdown item - * @param modalQuestionI18nKey The i18nKey for question to be shown in the modal - * @param modalWarningI18nKey The i18nKey for warning to be shown in the modal - * @param className Additional classes given to the dropdown item - */ -export const DropdownItemWithDeletionModal: React.FC< - DropdownItemWithDeletionModalProps & DeleteHistoryNoteModalProps -> = ({ - onConfirm, - noteTitle, - modalTitleI18nKey, - modalButtonI18nKey, - itemI18nKey, - modalIcon, - modalQuestionI18nKey, - modalWarningI18nKey, - className -}) => { - useTranslation() - const [modalVisibility, showModal, closeModal] = useBooleanState() - - const handleConfirm = useCallback(() => { - closeModal() - onConfirm() - }, [closeModal, onConfirm]) - - return ( - - - - - - - - ) -} diff --git a/frontend/src/components/history-page/entry-menu/entry-menu.tsx b/frontend/src/components/history-page/entry-menu/entry-menu.tsx index f591e3f2a..b4d7567e9 100644 --- a/frontend/src/components/history-page/entry-menu/entry-menu.tsx +++ b/frontend/src/components/history-page/entry-menu/entry-menu.tsx @@ -14,13 +14,15 @@ import { Dropdown } from 'react-bootstrap' import { Cloud as IconCloud, Laptop as IconLaptop, ThreeDots as IconThreeDots } from 'react-bootstrap-icons' import { Trans, useTranslation } from 'react-i18next' import { useIsLoggedIn } from '../../../hooks/common/use-is-logged-in' +import { useApplicationState } from '../../../hooks/common/use-application-state' export interface EntryMenuProps { id: string title: string origin: HistoryEntryOrigin + noteOwner: string | null onRemoveFromHistory: () => void - onDeleteNote: () => void + onDeleteNote: (keepMedia: boolean) => void className?: string } @@ -30,6 +32,7 @@ export interface EntryMenuProps { * @param id The unique identifier of the history entry. * @param title The title of the note of the history entry. * @param origin The origin of the entry. Must be either {@link HistoryEntryOrigin.LOCAL} or {@link HistoryEntryOrigin.REMOTE}. + * @param noteOwner The username of the note owner. * @param onRemoveFromHistory Callback that is fired when the entry should be removed from the history. * @param onDeleteNote Callback that is fired when the note should be deleted. * @param className Additional CSS classes to add to the dropdown. @@ -38,12 +41,14 @@ export const EntryMenu: React.FC = ({ id, title, origin, + noteOwner, onRemoveFromHistory, onDeleteNote, className }) => { useTranslation() const userExists = useIsLoggedIn() + const currentUsername = useApplicationState((state) => state.user?.username) return ( @@ -75,11 +80,10 @@ export const EntryMenu: React.FC = ({ - {/* TODO Check permissions (ownership) before showing option for delete (https://github.com/hedgedoc/hedgedoc/issues/5036)*/} - {userExists && ( + {userExists && currentUsername === noteOwner && ( <> - + )} diff --git a/frontend/src/components/history-page/entry-menu/remove-note-entry-item.tsx b/frontend/src/components/history-page/entry-menu/remove-note-entry-item.tsx index d47bfa848..a1898bf2d 100644 --- a/frontend/src/components/history-page/entry-menu/remove-note-entry-item.tsx +++ b/frontend/src/components/history-page/entry-menu/remove-note-entry-item.tsx @@ -3,10 +3,13 @@ * * SPDX-License-Identifier: AGPL-3.0-only */ -import { cypressId } from '../../../utils/cypress-attribute' -import { DropdownItemWithDeletionModal } from './dropdown-item-with-deletion-modal' -import React from 'react' +import React, { Fragment } from 'react' import { Archive as IconArchive } from 'react-bootstrap-icons' +import { useBooleanState } from '../../../hooks/common/use-boolean-state' +import { Dropdown } from 'react-bootstrap' +import { UiIcon } from '../../common/icons/ui-icon' +import { Trans } from 'react-i18next' +import { DeletionModal } from '../../common/modals/deletion-modal' export interface RemoveNoteEntryItemProps { onConfirm: () => void @@ -20,17 +23,29 @@ export interface RemoveNoteEntryItemProps { * @param onConfirm The callback to delete the note */ export const RemoveNoteEntryItem: React.FC = ({ noteTitle, onConfirm }) => { + const [isModalVisible, showModal, hideModal] = useBooleanState() return ( - + + + + + + +
+ +
+
    +
  • {noteTitle}
  • +
+
+ +
+
+
) } diff --git a/frontend/src/components/history-page/history-card/history-card.tsx b/frontend/src/components/history-page/history-card/history-card.tsx index e8569ed13..d04c3589e 100644 --- a/frontend/src/components/history-page/history-card/history-card.tsx +++ b/frontend/src/components/history-page/history-card/history-card.tsx @@ -36,9 +36,12 @@ export const HistoryCard: React.FC = ( onRemoveEntryClick(entry.identifier) }, [onRemoveEntryClick, entry.identifier]) - const onDeleteNote = useCallback(() => { - onDeleteNoteClick(entry.identifier) - }, [onDeleteNoteClick, entry.identifier]) + const onDeleteNote = useCallback( + (keepMedia: boolean) => { + onDeleteNoteClick(entry.identifier, keepMedia) + }, + [onDeleteNoteClick, entry.identifier] + ) const onPinEntry = useCallback(() => { onPinClick(entry.identifier) @@ -93,6 +96,7 @@ export const HistoryCard: React.FC = ( origin={entry.origin} onRemoveFromHistory={onRemoveEntry} onDeleteNote={onDeleteNote} + noteOwner={entry.owner} /> diff --git a/frontend/src/components/history-page/history-content/history-content.tsx b/frontend/src/components/history-page/history-content/history-content.tsx index f1bd332bc..236e116de 100644 --- a/frontend/src/components/history-page/history-content/history-content.tsx +++ b/frontend/src/components/history-page/history-content/history-content.tsx @@ -23,7 +23,7 @@ type OnEntryClick = (entryId: string) => void export interface HistoryEventHandlers { onPinClick: OnEntryClick onRemoveEntryClick: OnEntryClick - onDeleteNoteClick: OnEntryClick + onDeleteNoteClick: (entryId: string, keepMedia: boolean) => void } export interface HistoryEntryProps { @@ -61,8 +61,8 @@ export const HistoryContent: React.FC = () => { ) const onDeleteClick = useCallback( - (noteId: string) => { - deleteNote(noteId) + (noteId: string, keepMedia: boolean) => { + deleteNote(noteId, keepMedia) .then(() => removeHistoryEntry(noteId)) .catch(showErrorNotification('landing.history.error.deleteNote.text')) }, diff --git a/frontend/src/components/history-page/history-table/history-table-row.tsx b/frontend/src/components/history-page/history-table/history-table-row.tsx index 1693bffa1..6c816697f 100644 --- a/frontend/src/components/history-page/history-table/history-table-row.tsx +++ b/frontend/src/components/history-page/history-table/history-table-row.tsx @@ -37,9 +37,12 @@ export const HistoryTableRow: React.FC onRemoveEntryClick(entry.identifier) }, [onRemoveEntryClick, entry.identifier]) - const onDeleteNote = useCallback(() => { - onDeleteNoteClick(entry.identifier) - }, [onDeleteNoteClick, entry.identifier]) + const onDeleteNote = useCallback( + (keepMedia: boolean) => { + onDeleteNoteClick(entry.identifier, keepMedia) + }, + [onDeleteNoteClick, entry.identifier] + ) return ( @@ -63,6 +66,7 @@ export const HistoryTableRow: React.FC id={entry.identifier} title={entryTitle} origin={entry.origin} + noteOwner={entry.owner} onRemoveFromHistory={onEntryRemove} onDeleteNote={onDeleteNote} /> diff --git a/frontend/src/pages/api/private/me/history.ts b/frontend/src/pages/api/private/me/history.ts index 631690a3a..f9b83b76c 100644 --- a/frontend/src/pages/api/private/me/history.ts +++ b/frontend/src/pages/api/private/me/history.ts @@ -14,28 +14,32 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => { title: 'Slide example', lastVisitedAt: '2020-05-30T15:20:36.088Z', pinStatus: true, - tags: ['features', 'cool', 'updated'] + tags: ['features', 'cool', 'updated'], + owner: null }, { identifier: 'features', title: 'Features', lastVisitedAt: '2020-05-31T15:20:36.088Z', pinStatus: true, - tags: ['features', 'cool', 'updated'] + tags: ['features', 'cool', 'updated'], + owner: null }, { identifier: 'ODakLc2MQkyyFc_Xmb53sg', title: 'Non existent', lastVisitedAt: '2020-05-25T19:48:14.025Z', pinStatus: false, - tags: [] + tags: [], + owner: null }, { identifier: 'l8JuWxApTR6Fqa0LCrpnLg', title: 'Non existent', lastVisitedAt: '2020-05-24T16:04:36.433Z', pinStatus: false, - tags: ['agenda', 'HedgeDoc community', 'community call'] + tags: ['agenda', 'HedgeDoc community', 'community call'], + owner: 'test' } ]) } diff --git a/frontend/src/redux/history/methods.ts b/frontend/src/redux/history/methods.ts index 013b4fa73..2c8a3ac2a 100644 --- a/frontend/src/redux/history/methods.ts +++ b/frontend/src/redux/history/methods.ts @@ -151,7 +151,8 @@ export const convertV1History = (oldHistory: V1HistoryEntry[]): HistoryEntryWith tags: entry.tags, lastVisitedAt: DateTime.fromMillis(entry.time).toISO(), pinStatus: entry.pinned, - origin: HistoryEntryOrigin.LOCAL + origin: HistoryEntryOrigin.LOCAL, + owner: null })) }