Load notes into editor

This commit is contained in:
Oliver Walters 2026-05-21 09:59:47 +00:00
parent 9e8764d28a
commit df340e363c
3 changed files with 69 additions and 8 deletions

View File

@ -840,6 +840,10 @@ class NoteFilter(FilterSet):
class NoteMixin:
"""Mixin class for the Note views."""
# Ignore default sanitizing of the 'content' field
# Note: This is handled explicitly in the 'save' method of the Note model
SAFE_FIELDS = ['content']
queryset = common.models.Note.objects.all()
serializer_class = common.serializers.NoteSerializer
permission_classes = [IsAuthenticatedOrReadScope]

View File

@ -2921,10 +2921,6 @@ class Note(
created: Date/time that the note was created
"""
# Ignore default sanitizing of the 'content' field
# Note: This is handled explicitly in the 'save' method
SAFE_FIELDS = ['content']
class Meta:
"""Meta options for Note model."""

View File

@ -28,7 +28,11 @@ import {
Tabs,
Text
} from '@mantine/core';
import { IconCirclePlus, IconInfoCircle } from '@tabler/icons-react';
import {
IconCirclePlus,
IconInfoCircle,
IconUpload
} from '@tabler/icons-react';
import { useNoteFields } from '../../forms/CommonForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useUserState } from '../../states/UserState';
@ -47,6 +51,8 @@ export default function NotesEditor({
const api = useApi();
const user = useUserState();
const editor = useCreateBlockNote();
// The ID of the selected note
const [selectedNote, setSelectedNote] = useState<number | undefined>(
undefined
@ -71,6 +77,20 @@ export default function NotesEditor({
enabled: !!modelId && !!modelType
});
useEffect(() => {
const note = notesQuery.data?.find((note: any) => note.pk === selectedNote);
if (note) {
const blocks = editor.tryParseHTMLToBlocks(note.content ?? '');
if (blocks) {
editor.replaceBlocks(editor.document, blocks);
}
} else {
editor.replaceBlocks(editor.document, []);
}
}, [editor, selectedNote, notesQuery.data]);
// Adjust the note selection
useEffect(() => {
// If the currently selected note is not in the list of available notes, then we need to adjust the selection
@ -98,8 +118,6 @@ export default function NotesEditor({
return notesQuery.data && notesQuery.data.length > 0;
}, [notesQuery.data]);
const editor = useCreateBlockNote();
const noteFields = useNoteFields({ modelType: modelType, modelId: modelId });
const createNote = useCreateApiFormModal({
@ -116,6 +134,47 @@ export default function NotesEditor({
}
});
const saveNote = useCallback(() => {
// if (!selectedNote) {
// return;
// }
const blocks = editor.document;
const html = editor.blocksToHTMLLossy(blocks);
// TODO: Sanitize the HTML content before sending to the server (or ensure it's sanitized on the back-end)
if (selectedNote) {
const url = apiUrl(ApiEndpoints.note_list, selectedNote);
notifications.hide('note-update-status');
api
.patch(url, { content: html })
.then(() => {
notifications.show({
title: t`Success`,
message: t`Note updated`,
color: 'green',
id: 'note-update-status',
autoClose: 2000
});
})
.catch((error) => {
notifications.show({
title: t`Error`,
message: t`Failed to update note: ${error.message}`,
color: 'red',
id: 'note-update-status',
autoClose: 2000
});
})
.finally(() => {
notesQuery.refetch();
});
}
}, [selectedNote, editor]);
return (
<>
{createNote.modal}
@ -126,7 +185,6 @@ export default function NotesEditor({
<Stack gap='xs'>
<BlockNoteView
editor={editor}
content={''}
editable={canEdit}
style={{ minHeight: '400px' }}
/>
@ -140,6 +198,9 @@ export default function NotesEditor({
</Box>
<Paper p='sm' shadow='sm' withBorder ml='md' style={{ width: '200px' }}>
<Stack gap='xs'>
<Button leftSection={<IconUpload />} onClick={saveNote}>
{t`Save`}
</Button>
<Button leftSection={<IconCirclePlus />} onClick={createNote.open}>
{t`Add Note`}
</Button>