|
@@ -10,6 +10,7 @@ import { useTranslation } from 'next-i18next';
|
|
|
import dynamic from 'next/dynamic';
|
|
import dynamic from 'next/dynamic';
|
|
|
import { HtmlElementNode } from 'rehype-toc';
|
|
import { HtmlElementNode } from 'rehype-toc';
|
|
|
|
|
|
|
|
|
|
+import MarkdownTable from '~/client/models/MarkdownTable';
|
|
|
import { useSaveOrUpdate } from '~/client/services/page-operation';
|
|
import { useSaveOrUpdate } from '~/client/services/page-operation';
|
|
|
import { toastSuccess, toastError } from '~/client/util/apiNotification';
|
|
import { toastSuccess, toastError } from '~/client/util/apiNotification';
|
|
|
import { OptionsToSave } from '~/interfaces/page-operation';
|
|
import { OptionsToSave } from '~/interfaces/page-operation';
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
useIsGuestUser, useShareLinkId,
|
|
useIsGuestUser, useShareLinkId,
|
|
|
} from '~/stores/context';
|
|
} from '~/stores/context';
|
|
|
import { useEditingMarkdown } from '~/stores/editor';
|
|
import { useEditingMarkdown } from '~/stores/editor';
|
|
|
-import { useDrawioModal } from '~/stores/modal';
|
|
|
|
|
|
|
+import { useDrawioModal, useHandsontableModal } from '~/stores/modal';
|
|
|
import { useSWRxCurrentPage, useSWRxTagsInfo } from '~/stores/page';
|
|
import { useSWRxCurrentPage, useSWRxTagsInfo } from '~/stores/page';
|
|
|
import { useViewOptions } from '~/stores/renderer';
|
|
import { useViewOptions } from '~/stores/renderer';
|
|
|
import {
|
|
import {
|
|
@@ -28,6 +29,9 @@ import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
|
|
import RevisionRenderer from './Page/RevisionRenderer';
|
|
import RevisionRenderer from './Page/RevisionRenderer';
|
|
|
import mdu from './PageEditor/MarkdownDrawioUtil';
|
|
import mdu from './PageEditor/MarkdownDrawioUtil';
|
|
|
|
|
+import mtu from './PageEditor/MarkdownTableUtil';
|
|
|
|
|
+
|
|
|
|
|
+import styles from './Page.module.scss';
|
|
|
|
|
|
|
|
|
|
|
|
|
declare global {
|
|
declare global {
|
|
@@ -62,6 +66,7 @@ export const Page = (props) => {
|
|
|
const { data: rendererOptions } = useViewOptions(storeTocNodeHandler);
|
|
const { data: rendererOptions } = useViewOptions(storeTocNodeHandler);
|
|
|
const { mutate: mutateCurrentPageTocNode } = useCurrentPageTocNode();
|
|
const { mutate: mutateCurrentPageTocNode } = useCurrentPageTocNode();
|
|
|
const { open: openDrawioModal } = useDrawioModal();
|
|
const { open: openDrawioModal } = useDrawioModal();
|
|
|
|
|
+ const { open: openHandsontableModal } = useHandsontableModal();
|
|
|
|
|
|
|
|
const saveOrUpdate = useSaveOrUpdate();
|
|
const saveOrUpdate = useSaveOrUpdate();
|
|
|
|
|
|
|
@@ -72,6 +77,7 @@ export const Page = (props) => {
|
|
|
}, [mutateCurrentPageTocNode, tocRef.current]); // include tocRef.current to call mutateCurrentPageTocNode when tocRef.current changes
|
|
}, [mutateCurrentPageTocNode, tocRef.current]); // include tocRef.current to call mutateCurrentPageTocNode when tocRef.current changes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ // TODO: refactor commonize saveByDrawioModal and saveByHandsontableModal
|
|
|
const saveByDrawioModal = useCallback(async(drawioMxFile: string, bol: number, eol: number) => {
|
|
const saveByDrawioModal = useCallback(async(drawioMxFile: string, bol: number, eol: number) => {
|
|
|
if (currentPage == null || tagsInfo == null) {
|
|
if (currentPage == null || tagsInfo == null) {
|
|
|
return;
|
|
return;
|
|
@@ -131,6 +137,61 @@ export const Page = (props) => {
|
|
|
};
|
|
};
|
|
|
}, [openDrawioModal, saveByDrawioModal, shareLinkId]);
|
|
}, [openDrawioModal, saveByDrawioModal, shareLinkId]);
|
|
|
|
|
|
|
|
|
|
+ const saveByHandsontableModal = useCallback(async(table: MarkdownTable, bol: number, eol: number) => {
|
|
|
|
|
+ if (currentPage == null || tagsInfo == null || shareLinkId != null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const currentMarkdown = currentPage.revision.body;
|
|
|
|
|
+ const optionsToSave: OptionsToSave = {
|
|
|
|
|
+ isSlackEnabled: false,
|
|
|
|
|
+ slackChannels: '',
|
|
|
|
|
+ grant: currentPage.grant,
|
|
|
|
|
+ grantUserGroupId: currentPage.grantedGroup?._id,
|
|
|
|
|
+ grantUserGroupName: currentPage.grantedGroup?.name,
|
|
|
|
|
+ pageTags: tagsInfo.tags,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const newMarkdown = mtu.replaceMarkdownTableInMarkdown(table, currentMarkdown, bol, eol);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const currentRevisionId = currentPage.revision._id;
|
|
|
|
|
+ await saveOrUpdate(
|
|
|
|
|
+ newMarkdown,
|
|
|
|
|
+ { pageId: currentPage._id, path: currentPage.path, revisionId: currentRevisionId },
|
|
|
|
|
+ optionsToSave,
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ toastSuccess(t('toaster.save_succeeded'));
|
|
|
|
|
+
|
|
|
|
|
+ // rerender
|
|
|
|
|
+ mutateCurrentPage();
|
|
|
|
|
+ mutateEditingMarkdown(newMarkdown);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ logger.error('failed to save', error);
|
|
|
|
|
+ toastError(error);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [currentPage, mutateCurrentPage, mutateEditingMarkdown, saveOrUpdate, shareLinkId, t, tagsInfo]);
|
|
|
|
|
+
|
|
|
|
|
+ // set handler to open HandsonTableModal
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (currentPage == null || shareLinkId != null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handler = (bol: number, eol: number) => {
|
|
|
|
|
+ const markdown = currentPage.revision.body;
|
|
|
|
|
+ const currentMarkdownTable = mtu.getMarkdownTableFromLine(markdown, bol, eol);
|
|
|
|
|
+ openHandsontableModal(currentMarkdownTable, undefined, false, table => saveByHandsontableModal(table, bol, eol));
|
|
|
|
|
+ };
|
|
|
|
|
+ globalEmitter.on('launchHandsonTableModal', handler);
|
|
|
|
|
+
|
|
|
|
|
+ return function cleanup() {
|
|
|
|
|
+ globalEmitter.removeListener('launchHandsonTableModal', handler);
|
|
|
|
|
+ };
|
|
|
|
|
+ }, [currentPage, openHandsontableModal, saveByHandsontableModal, shareLinkId]);
|
|
|
|
|
+
|
|
|
if (currentPage == null || isGuestUser == null || rendererOptions == null) {
|
|
if (currentPage == null || isGuestUser == null || rendererOptions == null) {
|
|
|
const entries = Object.entries({
|
|
const entries = Object.entries({
|
|
|
currentPage, isGuestUser, rendererOptions,
|
|
currentPage, isGuestUser, rendererOptions,
|
|
@@ -145,7 +206,7 @@ export const Page = (props) => {
|
|
|
const { _id: revisionId, body: markdown } = currentPage.revision;
|
|
const { _id: revisionId, body: markdown } = currentPage.revision;
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <div className={`mb-5 ${isMobile ? 'page-mobile' : ''}`}>
|
|
|
|
|
|
|
+ <div className={`mb-5 ${isMobile ? `page-mobile ${styles['page-mobile']}` : ''}`}>
|
|
|
|
|
|
|
|
{ revisionId != null && (
|
|
{ revisionId != null && (
|
|
|
<RevisionRenderer rendererOptions={rendererOptions} markdown={markdown} />
|
|
<RevisionRenderer rendererOptions={rendererOptions} markdown={markdown} />
|