mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-02 10:18:42 +00:00
Load notes into editor
This commit is contained in:
@@ -840,6 +840,10 @@ class NoteFilter(FilterSet):
|
|||||||
class NoteMixin:
|
class NoteMixin:
|
||||||
"""Mixin class for the Note views."""
|
"""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()
|
queryset = common.models.Note.objects.all()
|
||||||
serializer_class = common.serializers.NoteSerializer
|
serializer_class = common.serializers.NoteSerializer
|
||||||
permission_classes = [IsAuthenticatedOrReadScope]
|
permission_classes = [IsAuthenticatedOrReadScope]
|
||||||
|
|||||||
@@ -2921,10 +2921,6 @@ class Note(
|
|||||||
created: Date/time that the note was created
|
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:
|
class Meta:
|
||||||
"""Meta options for Note model."""
|
"""Meta options for Note model."""
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ import {
|
|||||||
Tabs,
|
Tabs,
|
||||||
Text
|
Text
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconCirclePlus, IconInfoCircle } from '@tabler/icons-react';
|
import {
|
||||||
|
IconCirclePlus,
|
||||||
|
IconInfoCircle,
|
||||||
|
IconUpload
|
||||||
|
} from '@tabler/icons-react';
|
||||||
import { useNoteFields } from '../../forms/CommonForms';
|
import { useNoteFields } from '../../forms/CommonForms';
|
||||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
@@ -47,6 +51,8 @@ export default function NotesEditor({
|
|||||||
const api = useApi();
|
const api = useApi();
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
|
||||||
|
const editor = useCreateBlockNote();
|
||||||
|
|
||||||
// The ID of the selected note
|
// The ID of the selected note
|
||||||
const [selectedNote, setSelectedNote] = useState<number | undefined>(
|
const [selectedNote, setSelectedNote] = useState<number | undefined>(
|
||||||
undefined
|
undefined
|
||||||
@@ -71,6 +77,20 @@ export default function NotesEditor({
|
|||||||
enabled: !!modelId && !!modelType
|
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
|
// Adjust the note selection
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If the currently selected note is not in the list of available notes, then we need to adjust the selection
|
// 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;
|
return notesQuery.data && notesQuery.data.length > 0;
|
||||||
}, [notesQuery.data]);
|
}, [notesQuery.data]);
|
||||||
|
|
||||||
const editor = useCreateBlockNote();
|
|
||||||
|
|
||||||
const noteFields = useNoteFields({ modelType: modelType, modelId: modelId });
|
const noteFields = useNoteFields({ modelType: modelType, modelId: modelId });
|
||||||
|
|
||||||
const createNote = useCreateApiFormModal({
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
{createNote.modal}
|
{createNote.modal}
|
||||||
@@ -126,7 +185,6 @@ export default function NotesEditor({
|
|||||||
<Stack gap='xs'>
|
<Stack gap='xs'>
|
||||||
<BlockNoteView
|
<BlockNoteView
|
||||||
editor={editor}
|
editor={editor}
|
||||||
content={''}
|
|
||||||
editable={canEdit}
|
editable={canEdit}
|
||||||
style={{ minHeight: '400px' }}
|
style={{ minHeight: '400px' }}
|
||||||
/>
|
/>
|
||||||
@@ -140,6 +198,9 @@ export default function NotesEditor({
|
|||||||
</Box>
|
</Box>
|
||||||
<Paper p='sm' shadow='sm' withBorder ml='md' style={{ width: '200px' }}>
|
<Paper p='sm' shadow='sm' withBorder ml='md' style={{ width: '200px' }}>
|
||||||
<Stack gap='xs'>
|
<Stack gap='xs'>
|
||||||
|
<Button leftSection={<IconUpload />} onClick={saveNote}>
|
||||||
|
{t`Save`}
|
||||||
|
</Button>
|
||||||
<Button leftSection={<IconCirclePlus />} onClick={createNote.open}>
|
<Button leftSection={<IconCirclePlus />} onClick={createNote.open}>
|
||||||
{t`Add Note`}
|
{t`Add Note`}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user