diff --git a/src/frontend/package.json b/src/frontend/package.json
index 7dca970377..00c73b5e8c 100644
--- a/src/frontend/package.json
+++ b/src/frontend/package.json
@@ -83,6 +83,7 @@
"@tiptap/core": "^3.23.6",
"@tiptap/extension-image": "^3.23.6",
"@tiptap/extension-link": "^3.23.6",
+ "@tiptap/extension-table": "^3.23.6",
"@tiptap/pm": "^3.23.6",
"@tiptap/react": "^3.23.6",
"@tiptap/starter-kit": "^3.23.6",
diff --git a/src/frontend/src/components/editors/NotesEditor.tsx b/src/frontend/src/components/editors/NotesEditor.tsx
index a39fb8ddb2..ada6cab3fa 100644
--- a/src/frontend/src/components/editors/NotesEditor.tsx
+++ b/src/frontend/src/components/editors/NotesEditor.tsx
@@ -4,7 +4,8 @@ import '@mantine/tiptap/styles.css';
import { useHotkeys } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { useQuery } from '@tanstack/react-query';
-import { useEditor } from '@tiptap/react';
+import { TableKit } from '@tiptap/extension-table';
+import { useEditor, useEditorState } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import DOMPurify from 'dompurify';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -35,12 +36,22 @@ import {
Tooltip
} from '@mantine/core';
import {
+ IconArrowMerge,
IconCirclePlus,
+ IconColumnInsertLeft,
+ IconColumnInsertRight,
+ IconColumnRemove,
IconDeviceFloppy,
IconInfoCircle,
IconPhoto,
IconReload,
- IconStar
+ IconRowInsertBottom,
+ IconRowInsertTop,
+ IconRowRemove,
+ IconStar,
+ IconTableOff,
+ IconTablePlus,
+ IconTableRow
} from '@tabler/icons-react';
import { useShallow } from 'zustand/react/shallow';
import { formatDate } from '../../defaults/formatters';
@@ -150,6 +161,9 @@ export default function NotesEditor({
const src = await uploadFileRef.current(file);
return { src, 'data-keep-ratio': true };
}
+ }),
+ TableKit.configure({
+ table: { resizable: true, renderWrapper: true, cellMinWidth: 50 }
})
],
content: '',
@@ -233,6 +247,11 @@ export default function NotesEditor({
[user, modelType, notesQuery]
);
+ const isInTable = useEditorState({
+ editor,
+ selector: ({ editor: e }) => e?.isActive('table') ?? false
+ });
+
// Sync editor editable state when permissions change
useEffect(() => {
editor?.setEditable(canEdit);
@@ -466,6 +485,118 @@ export default function NotesEditor({
)}
+
+
+ editor
+ ?.chain()
+ .focus()
+ .insertTable({
+ rows: 3,
+ cols: 3,
+ withHeaderRow: true
+ })
+ .run()
+ }
+ aria-label={t`Insert table`}
+ title={t`Insert table`}
+ >
+
+
+
+
+ )}
+ {canEdit && isInTable && (
+
+
+
+ editor?.chain().focus().addColumnBefore().run()
+ }
+ aria-label={t`Add column before`}
+ title={t`Add column before`}
+ >
+
+
+
+ editor?.chain().focus().addColumnAfter().run()
+ }
+ aria-label={t`Add column after`}
+ title={t`Add column after`}
+ >
+
+
+
+ editor?.chain().focus().deleteColumn().run()
+ }
+ aria-label={t`Delete column`}
+ title={t`Delete column`}
+ >
+
+
+
+
+
+ editor?.chain().focus().addRowBefore().run()
+ }
+ aria-label={t`Add row before`}
+ title={t`Add row before`}
+ >
+
+
+
+ editor?.chain().focus().addRowAfter().run()
+ }
+ aria-label={t`Add row after`}
+ title={t`Add row after`}
+ >
+
+
+
+ editor?.chain().focus().deleteRow().run()
+ }
+ aria-label={t`Delete row`}
+ title={t`Delete row`}
+ >
+
+
+
+
+
+ editor?.chain().focus().mergeOrSplit().run()
+ }
+ aria-label={t`Merge or split cells`}
+ title={t`Merge or split cells`}
+ >
+
+
+
+ editor?.chain().focus().toggleHeaderRow().run()
+ }
+ aria-label={t`Toggle header row`}
+ title={t`Toggle header row`}
+ >
+
+
+
+
+
+ editor?.chain().focus().deleteTable().run()
+ }
+ aria-label={t`Delete table`}
+ title={t`Delete table`}
+ >
+
+
+
)}
diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock
index f091761fe7..c631338144 100644
--- a/src/frontend/yarn.lock
+++ b/src/frontend/yarn.lock
@@ -2110,6 +2110,11 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.6.tgz#b68e8df11c8c24c82d8c292ff94bc962f3cec871"
integrity sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==
+"@tiptap/extension-table@^3.23.6":
+ version "3.23.6"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-3.23.6.tgz#757a4d14f472fd4735ff5bab35da72402b0bced4"
+ integrity sha512-XbhZXjhsS6AP7ThoZxjAnNs+NiR81YRori25l6E+ORqB7quiPkIXOAi5h4AIpkn/CYIqze6ere11lWsYpDjtaQ==
+
"@tiptap/extension-text@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.4.tgz#1ab44d78d34c746f97100ff34cc28e0914231eaa"