From 241cb94b5c920e3b274ed612506e628fdf5bfa1b Mon Sep 17 00:00:00 2001 From: lixiaoshu Date: Fri, 23 May 2025 09:34:49 +0800 Subject: [PATCH] feat: migrate the code of the Mr module and fix lint and add dependencies --- moon/apps/web/components/MrView/MRComment.tsx | 61 +++ .../components/MrView/catalyst/heading.tsx | 27 ++ .../web/components/MrView/files-changed.tsx | 14 + moon/apps/web/components/MrView/index.tsx | 144 +++++++ .../MrView/rich-editor/ExampleTheme.ts | 44 ++ .../MrView/rich-editor/LexicalContent.tsx | 46 ++ .../MrView/rich-editor/RichEditor.tsx | 84 ++++ .../MrView/rich-editor/icons/LICENSE.md | 5 + .../rich-editor/icons/arrow-clockwise.svg | 4 + .../icons/arrow-counterclockwise.svg | 4 + .../MrView/rich-editor/icons/journal-text.svg | 5 + .../MrView/rich-editor/icons/justify.svg | 3 + .../MrView/rich-editor/icons/text-center.svg | 3 + .../MrView/rich-editor/icons/text-left.svg | 3 + .../rich-editor/icons/text-paragraph.svg | 3 + .../MrView/rich-editor/icons/text-right.svg | 3 + .../MrView/rich-editor/icons/type-bold.svg | 3 + .../MrView/rich-editor/icons/type-italic.svg | 3 + .../rich-editor/icons/type-strikethrough.svg | 3 + .../rich-editor/icons/type-underline.svg | 3 + .../rich-editor/plugins/ToolbarPlugin.tsx | 173 ++++++++ .../rich-editor/plugins/TreeViewPlugin.tsx | 26 ++ .../components/MrView/rich-editor/styles.css | 396 ++++++++++++++++++ .../Sidebar/SiderbarMergeRequest.tsx | 22 + moon/apps/web/components/Sidebar/index.tsx | 2 + moon/apps/web/package.json | 5 + moon/apps/web/pages/[org]/mr/[id].tsx | 283 +++++++++++++ moon/apps/web/pages/[org]/mr/index.tsx | 29 ++ moon/pnpm-lock.yaml | 360 +++++++++++++++- moon/pnpm-workspace.yaml | 7 +- 30 files changed, 1744 insertions(+), 24 deletions(-) create mode 100644 moon/apps/web/components/MrView/MRComment.tsx create mode 100644 moon/apps/web/components/MrView/catalyst/heading.tsx create mode 100644 moon/apps/web/components/MrView/files-changed.tsx create mode 100644 moon/apps/web/components/MrView/index.tsx create mode 100644 moon/apps/web/components/MrView/rich-editor/ExampleTheme.ts create mode 100644 moon/apps/web/components/MrView/rich-editor/LexicalContent.tsx create mode 100644 moon/apps/web/components/MrView/rich-editor/RichEditor.tsx create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/LICENSE.md create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/arrow-clockwise.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/arrow-counterclockwise.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/journal-text.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/justify.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/text-center.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/text-left.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/text-paragraph.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/text-right.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/type-bold.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/type-italic.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/type-strikethrough.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/icons/type-underline.svg create mode 100644 moon/apps/web/components/MrView/rich-editor/plugins/ToolbarPlugin.tsx create mode 100644 moon/apps/web/components/MrView/rich-editor/plugins/TreeViewPlugin.tsx create mode 100644 moon/apps/web/components/MrView/rich-editor/styles.css create mode 100644 moon/apps/web/components/Sidebar/SiderbarMergeRequest.tsx create mode 100644 moon/apps/web/pages/[org]/mr/[id].tsx create mode 100644 moon/apps/web/pages/[org]/mr/index.tsx diff --git a/moon/apps/web/components/MrView/MRComment.tsx b/moon/apps/web/components/MrView/MRComment.tsx new file mode 100644 index 000000000..c8e5acdb6 --- /dev/null +++ b/moon/apps/web/components/MrView/MRComment.tsx @@ -0,0 +1,61 @@ +import { Card, Dropdown } from 'antd/lib'; +import type { MenuProps } from 'antd'; +// import { MoreOutlined } from '@ant-design/icons'; +import { NotePlusIcon} from '@gitmono/ui/Icons' +import { formatDistance, fromUnixTime } from 'date-fns'; +import LexicalContent from './rich-editor/LexicalContent'; + +const Comment = ({ conv, fetchDetail }:any) => { + + const delete_comment = async () => { + await fetch(`/api/mr/comment/${conv.id}/delete`, { + method: 'POST', + }); + }; + const handleMenuClick: MenuProps['onClick'] = ({ key }) => { + if (key === '3') { + delete_comment() + fetchDetail() + } + }; + + const items: MenuProps['items'] = [ + { + label: 'Edit', + key: '1', + disabled: true + }, + { + label: 'Hide', + key: '2', + disabled: true + }, + { + type: 'divider', + }, + { + label: 'Delete', + key: '3', + danger: true, + } + ]; + const menuProps = { + items, + onClick: handleMenuClick, + }; + + const time = formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }); + + return ( + + + + }> + + + ) + +} + +export default Comment; \ No newline at end of file diff --git a/moon/apps/web/components/MrView/catalyst/heading.tsx b/moon/apps/web/components/MrView/catalyst/heading.tsx new file mode 100644 index 000000000..5ccc9d134 --- /dev/null +++ b/moon/apps/web/components/MrView/catalyst/heading.tsx @@ -0,0 +1,27 @@ +import clsx from 'clsx' + +type HeadingProps = { level?: 1 | 2 | 3 | 4 | 5 | 6 } & React.ComponentPropsWithoutRef< + 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' +> + +export function Heading({ className, level = 1, ...props }: HeadingProps) { + let Element: `h${typeof level}` = `h${level}` + + return ( + + ) +} + +export function Subheading({ className, level = 2, ...props }: HeadingProps) { + let Element: `h${typeof level}` = `h${level}` + + return ( + + ) +} diff --git a/moon/apps/web/components/MrView/files-changed.tsx b/moon/apps/web/components/MrView/files-changed.tsx new file mode 100644 index 000000000..bc82937c6 --- /dev/null +++ b/moon/apps/web/components/MrView/files-changed.tsx @@ -0,0 +1,14 @@ +'use client' + +import React from 'react'; + +export default function FilesChanged({ outputHtml }: { outputHtml: Readonly }) { + return ( +
+
+
+ ) +} \ No newline at end of file diff --git a/moon/apps/web/components/MrView/index.tsx b/moon/apps/web/components/MrView/index.tsx new file mode 100644 index 000000000..66e431e24 --- /dev/null +++ b/moon/apps/web/components/MrView/index.tsx @@ -0,0 +1,144 @@ +'use client' + +import React, { useCallback, useEffect, useState } from 'react'; +import { List, PaginationProps, Tag, Tabs, TabsProps } from 'antd'; +import { formatDistance, fromUnixTime } from 'date-fns'; +// import { MergeOutlined, PullRequestOutlined, CloseCircleOutlined } from '@ant-design/icons'; +import { ChevronSelectIcon,AlarmIcon,ClockIcon} from '@gitmono/ui/Icons' +import { Link } from '@gitmono/ui/Link' +import { Heading } from './catalyst/heading'; + +interface MrInfoItem { + link: string, + title: string, + status: string, + open_timestamp: number, + merge_timestamp: number | null, + updated_at: number, +} + +export default function MrView() { + const [mrList, setMrList] = useState([]); + const [numTotal, setNumTotal] = useState(0); + const [pageSize] = useState(10); + const [status, setStatus] = useState('open') + + const fetchData = useCallback(async (page: number, per_page: number) => { + try { + const res = await fetch(`/api/mr/list`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + pagination: { + page: page, + per_page: per_page + }, + additional: { + status: status + } + }), + }); + const response = await res.json(); + const data = response.data.data; + + setMrList(data.items); + setNumTotal(data.total) + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error fetching data:', error); + } + }, [status]); + + useEffect(() => { + fetchData(1, pageSize); + }, [pageSize, status, fetchData]); + + const getStatusTag = (status: string) => { + switch (status) { + case 'open': + return open; + case 'merged': + return merged; + case 'closed': + return closed; + } + }; + + const getStatusIcon = (status: string) => { + switch (status) { + case 'open': + return ; + case 'closed': + return ; + case 'merged': + return ; + } + }; + + const getDescription = (item: MrInfoItem) => { + switch (item.status) { + case 'open': + return `MergeRequest opened by Admin ${formatDistance(fromUnixTime(item.open_timestamp), new Date(), { addSuffix: true })} `; + case 'merged': + if (item.merge_timestamp !== null) { + return `MergeRequest merged by Admin ${formatDistance(fromUnixTime(item.merge_timestamp), new Date(), { addSuffix: true })}`; + } else { + return ""; + } + case 'closed': + return (`MR ${item.link} closed by Admin ${formatDistance(fromUnixTime(item.updated_at), new Date(), { addSuffix: true })}`) + } + } + + const onChange: PaginationProps['onChange'] = (current, pageSize) => { + fetchData(current, pageSize); + }; + + const tabsChange = (activeKey: string) => { + if (activeKey === '1') { + setStatus("open"); + } else { + setStatus("closed"); + } + } + + const tab_items: TabsProps['items'] = [ + { + key: '1', + label: 'Open', + }, + { + key: '2', + label: 'Closed', + } + ]; + + + + return ( +
+ Merge Request +
+ + + ( + + {`${item.title}`} {getStatusTag(item.status)}} + description={getDescription(item)} + /> + + )} + /> +
+ ) +} \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/ExampleTheme.ts b/moon/apps/web/components/MrView/rich-editor/ExampleTheme.ts new file mode 100644 index 000000000..7b5f09c72 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/ExampleTheme.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +const theme = { + code: 'editor-code', + heading: { + h1: 'editor-heading-h1', + h2: 'editor-heading-h2', + h3: 'editor-heading-h3', + h4: 'editor-heading-h4', + h5: 'editor-heading-h5', + }, + image: 'editor-image', + link: 'editor-link', + list: { + listitem: 'editor-listitem', + nested: { + listitem: 'editor-nested-listitem', + }, + ol: 'editor-list-ol', + ul: 'editor-list-ul', + }, + ltr: 'ltr', + paragraph: 'editor-paragraph', + placeholder: 'editor-placeholder', + quote: 'editor-quote', + rtl: 'rtl', + text: { + bold: 'editor-text-bold', + code: 'editor-text-code', + hashtag: 'editor-text-hashtag', + italic: 'editor-text-italic', + overflowed: 'editor-text-overflowed', + strikethrough: 'editor-text-strikethrough', + underline: 'editor-text-underline', + underlineStrikethrough: 'editor-text-underlineStrikethrough', + }, +}; + +export default theme; \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/LexicalContent.tsx b/moon/apps/web/components/MrView/rich-editor/LexicalContent.tsx new file mode 100644 index 000000000..94521e665 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/LexicalContent.tsx @@ -0,0 +1,46 @@ +import { LexicalComposer } from '@lexical/react/LexicalComposer'; +import ExampleTheme from './ExampleTheme'; +import { ContentEditable } from '@lexical/react/LexicalContentEditable'; +import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; +import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'; + +const LexicalContent = ({ lexicalJson }: { lexicalJson: string }) => { + const editorConfig = { + namespace: '', + nodes: [], + onError(error: Error) { + throw error; + }, + theme: ExampleTheme, + editable: false, + editorState: lexicalJson, + }; + + const placeholder = 'No description provided.'; + + return ( + +
+
+ {placeholder}
+ } + /> + } + ErrorBoundary={LexicalErrorBoundary} + /> +
+
+ + ); +}; + + + +export default LexicalContent; \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/RichEditor.tsx b/moon/apps/web/components/MrView/rich-editor/RichEditor.tsx new file mode 100644 index 000000000..a1bf83733 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/RichEditor.tsx @@ -0,0 +1,84 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin'; +import { LexicalComposer } from '@lexical/react/LexicalComposer'; +import { ContentEditable } from '@lexical/react/LexicalContentEditable'; +import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'; +import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'; +import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; + +import ExampleTheme from './ExampleTheme'; +import ToolbarPlugin from './plugins/ToolbarPlugin'; +// import TreeViewPlugin from './plugins/TreeViewPlugin'; + +import './styles.css'; +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { useEffect} from 'react'; + +const placeholder = 'Add your comment here...'; + +const editorConfig = { + namespace: '', + nodes: [], + // Handling of errors during update + onError(error: Error) { + throw error; + }, + // The editor theme + theme: ExampleTheme, +}; + +function OnChangePlugin({ onChange }:any) { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + return editor.registerUpdateListener(({ editorState }:any) => { + onChange(editorState); + }); + }, [editor, onChange]); + return null; +} + + +export default function RichEditor({ setEditorState }:any) { + + function onChange(editorState:any) { + // Call toJSON on the EditorState object, which produces a serialization safe string + const editorStateJSON = editorState.toJSON(); + // However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify + + setEditorState(JSON.stringify(editorStateJSON)); + } + + return ( + +
+ +
+ {placeholder}
+ } + /> + } + ErrorBoundary={LexicalErrorBoundary} + /> + + + {/* */} +
+ + + +
+ ); +} diff --git a/moon/apps/web/components/MrView/rich-editor/icons/LICENSE.md b/moon/apps/web/components/MrView/rich-editor/icons/LICENSE.md new file mode 100644 index 000000000..ce74f6abe --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/LICENSE.md @@ -0,0 +1,5 @@ +Bootstrap Icons +https://icons.getbootstrap.com + +Licensed under MIT license +https://github.com/twbs/icons/blob/main/LICENSE.md diff --git a/moon/apps/web/components/MrView/rich-editor/icons/arrow-clockwise.svg b/moon/apps/web/components/MrView/rich-editor/icons/arrow-clockwise.svg new file mode 100644 index 000000000..b072eb097 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/arrow-clockwise.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/arrow-counterclockwise.svg b/moon/apps/web/components/MrView/rich-editor/icons/arrow-counterclockwise.svg new file mode 100644 index 000000000..b0b23b9bb --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/arrow-counterclockwise.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/journal-text.svg b/moon/apps/web/components/MrView/rich-editor/icons/journal-text.svg new file mode 100644 index 000000000..9b66f43aa --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/journal-text.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/justify.svg b/moon/apps/web/components/MrView/rich-editor/icons/justify.svg new file mode 100644 index 000000000..009bd7214 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/justify.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/text-center.svg b/moon/apps/web/components/MrView/rich-editor/icons/text-center.svg new file mode 100644 index 000000000..2887a99f2 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/text-center.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/text-left.svg b/moon/apps/web/components/MrView/rich-editor/icons/text-left.svg new file mode 100644 index 000000000..045261164 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/text-left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/text-paragraph.svg b/moon/apps/web/components/MrView/rich-editor/icons/text-paragraph.svg new file mode 100644 index 000000000..9779beabf --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/text-paragraph.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/text-right.svg b/moon/apps/web/components/MrView/rich-editor/icons/text-right.svg new file mode 100644 index 000000000..34686b0f1 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/text-right.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/type-bold.svg b/moon/apps/web/components/MrView/rich-editor/icons/type-bold.svg new file mode 100644 index 000000000..276d133c2 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/type-bold.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/type-italic.svg b/moon/apps/web/components/MrView/rich-editor/icons/type-italic.svg new file mode 100644 index 000000000..3ac6b09f0 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/type-italic.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/type-strikethrough.svg b/moon/apps/web/components/MrView/rich-editor/icons/type-strikethrough.svg new file mode 100644 index 000000000..1c940e42a --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/type-strikethrough.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/icons/type-underline.svg b/moon/apps/web/components/MrView/rich-editor/icons/type-underline.svg new file mode 100644 index 000000000..c299b8bf2 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/icons/type-underline.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/moon/apps/web/components/MrView/rich-editor/plugins/ToolbarPlugin.tsx b/moon/apps/web/components/MrView/rich-editor/plugins/ToolbarPlugin.tsx new file mode 100644 index 000000000..0fc981c27 --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/plugins/ToolbarPlugin.tsx @@ -0,0 +1,173 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; +import {mergeRegister} from '@lexical/utils'; +import { + $getSelection, + $isRangeSelection, + CAN_REDO_COMMAND, + CAN_UNDO_COMMAND, + FORMAT_ELEMENT_COMMAND, + FORMAT_TEXT_COMMAND, + REDO_COMMAND, + SELECTION_CHANGE_COMMAND, + UNDO_COMMAND, +} from 'lexical'; +import {useCallback, useEffect, useRef, useState} from 'react'; + +const LowPriority = 1; + +function Divider() { + return
; +} + +export default function ToolbarPlugin() { + const [editor] = useLexicalComposerContext(); + const toolbarRef = useRef(null); + const [canUndo, setCanUndo] = useState(false); + const [canRedo, setCanRedo] = useState(false); + const [isBold, setIsBold] = useState(false); + const [isItalic, setIsItalic] = useState(false); + const [isUnderline, setIsUnderline] = useState(false); + const [isStrikethrough, setIsStrikethrough] = useState(false); + + const $updateToolbar = useCallback(() => { + const selection = $getSelection(); + + if ($isRangeSelection(selection)) { + // Update text format + setIsBold(selection.hasFormat('bold')); + setIsItalic(selection.hasFormat('italic')); + setIsUnderline(selection.hasFormat('underline')); + setIsStrikethrough(selection.hasFormat('strikethrough')); + } + }, []); + + useEffect(() => { + return mergeRegister( + editor.registerUpdateListener(({editorState}:any) => { + editorState.read(() => { + $updateToolbar(); + }); + }), + editor.registerCommand( + SELECTION_CHANGE_COMMAND, + (_payload: any, _newEditor: any) => { + $updateToolbar(); + return false; + }, + LowPriority, + ), + editor.registerCommand( + CAN_UNDO_COMMAND, + (payload: boolean | ((prevState: boolean) => boolean)) => { + setCanUndo(payload); + return false; + }, + LowPriority, + ), + editor.registerCommand( + CAN_REDO_COMMAND, + (payload: boolean | ((prevState: boolean) => boolean)) => { + setCanRedo(payload); + return false; + }, + LowPriority, + ), + ); + }, [editor, $updateToolbar]); + + return ( +
+ + + + + + + + + + + + {' '} +
+ ); +} diff --git a/moon/apps/web/components/MrView/rich-editor/plugins/TreeViewPlugin.tsx b/moon/apps/web/components/MrView/rich-editor/plugins/TreeViewPlugin.tsx new file mode 100644 index 000000000..b3ef1f59c --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/plugins/TreeViewPlugin.tsx @@ -0,0 +1,26 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; +import {TreeView} from '@lexical/react/LexicalTreeView'; + +export default function TreeViewPlugin(): JSX.Element { + const [editor] = useLexicalComposerContext(); + + return ( + + ); +} diff --git a/moon/apps/web/components/MrView/rich-editor/styles.css b/moon/apps/web/components/MrView/rich-editor/styles.css new file mode 100644 index 000000000..75e5dba2d --- /dev/null +++ b/moon/apps/web/components/MrView/rich-editor/styles.css @@ -0,0 +1,396 @@ + +.editor-container { + margin: 20px auto 20px auto; + border-radius: 10px; + border: 1px solid #d1d9e0; + color: #000; + position: relative; + line-height: 20px; + font-weight: 400; + text-align: left; + border-top-left-radius: 10px; + border-top-right-radius: 10px; +} + +.editor-inner { + position: relative; +} + +.editor-input { + min-height: 150px; + resize: none; + font-size: 15px; + caret-color: rgb(5, 5, 5); + position: relative; + tab-size: 1; + outline: 0; + padding: 15px 10px; + caret-color: #444; +} + +.editor-placeholder { + color: #999; + overflow: hidden; + position: absolute; + text-overflow: ellipsis; + top: 15px; + left: 10px; + font-size: 15px; + user-select: none; + display: inline-block; + pointer-events: none; +} + +.editor-text-bold { + font-weight: bold; +} + +.editor-text-italic { + font-style: italic; +} + +.editor-text-underline { + text-decoration: underline; +} + +.editor-text-strikethrough { + text-decoration: line-through; +} + +.editor-text-underlineStrikethrough { + text-decoration: underline line-through; +} + +.editor-text-code { + background-color: rgb(240, 242, 245); + padding: 1px 0.25rem; + font-family: Menlo, Consolas, Monaco, monospace; + font-size: 94%; +} + +.editor-link { + color: rgb(33, 111, 219); + text-decoration: none; +} + +.tree-view-output { + display: block; + background: #222; + color: #fff; + padding: 5px; + font-size: 12px; + white-space: pre-wrap; + margin: 1px auto 10px auto; + max-height: 250px; + position: relative; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + overflow: auto; + line-height: 14px; +} + +.editor-code { + background-color: rgb(240, 242, 245); + font-family: Menlo, Consolas, Monaco, monospace; + display: block; + padding: 8px 8px 8px 52px; + line-height: 1.53; + font-size: 13px; + margin: 0; + margin-top: 8px; + margin-bottom: 8px; + tab-size: 2; + /* white-space: pre; */ + overflow-x: auto; + position: relative; +} + +.editor-code:before { + content: attr(data-gutter); + position: absolute; + background-color: #eee; + left: 0; + top: 0; + border-right: 1px solid #ccc; + padding: 8px; + color: #777; + white-space: pre-wrap; + text-align: right; + min-width: 25px; +} +.editor-code:after { + content: attr(data-highlight-language); + top: 0; + right: 3px; + padding: 3px; + font-size: 10px; + text-transform: uppercase; + position: absolute; + color: rgba(0, 0, 0, 0.5); +} + +.editor-tokenComment { + color: slategray; +} + +.editor-tokenPunctuation { + color: #999; +} + +.editor-tokenProperty { + color: #905; +} + +.editor-tokenSelector { + color: #690; +} + +.editor-tokenOperator { + color: #9a6e3a; +} + +.editor-tokenAttr { + color: #07a; +} + +.editor-tokenVariable { + color: #e90; +} + +.editor-tokenFunction { + color: #dd4a68; +} + +.editor-paragraph { + margin: 0; + margin-bottom: 8px; + position: relative; +} + +.editor-paragraph:last-child { + margin-bottom: 0; +} + +.editor-heading-h1 { + font-size: 24px; + color: rgb(5, 5, 5); + font-weight: 400; + margin: 0; + margin-bottom: 12px; + padding: 0; +} + +.editor-heading-h2 { + font-size: 15px; + color: rgb(101, 103, 107); + font-weight: 700; + margin: 0; + margin-top: 10px; + padding: 0; + text-transform: uppercase; +} + +.editor-quote { + margin: 0; + margin-left: 20px; + font-size: 15px; + color: rgb(101, 103, 107); + border-left-color: rgb(206, 208, 212); + border-left-width: 4px; + border-left-style: solid; + padding-left: 16px; +} + +.editor-list-ol { + padding: 0; + margin: 0; + margin-left: 16px; +} + +.editor-list-ul { + padding: 0; + margin: 0; + margin-left: 16px; +} + +.editor-listitem { + margin: 8px 32px 8px 32px; +} + +.editor-nested-listitem { + list-style-type: none; +} + +pre::-webkit-scrollbar { + background: transparent; + width: 10px; +} + +pre::-webkit-scrollbar-thumb { + background: #999; +} + +.debug-timetravel-panel { + overflow: hidden; + padding: 0 0 10px 0; + margin: auto; + display: flex; +} + +.debug-timetravel-panel-slider { + padding: 0; + flex: 8; +} + +.debug-timetravel-panel-button { + padding: 0; + border: 0; + background: none; + flex: 1; + color: #fff; + font-size: 12px; +} + +.debug-timetravel-panel-button:hover { + text-decoration: underline; +} + +.debug-timetravel-button { + border: 0; + padding: 0; + font-size: 12px; + top: 10px; + right: 15px; + position: absolute; + background: none; + color: #fff; +} + +.debug-timetravel-button:hover { + text-decoration: underline; +} + +.toolbar { + display: flex; + margin-bottom: 1px; + background: #fff; + padding: 4px; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + vertical-align: middle; +} + +.toolbar button.toolbar-item { + border: 0; + display: flex; + background: none; + border-radius: 10px; + padding: 8px; + cursor: pointer; + vertical-align: middle; +} + +.toolbar button.toolbar-item:disabled { + cursor: not-allowed; +} + +.toolbar button.toolbar-item.spaced { + margin-right: 2px; +} + +.toolbar button.toolbar-item i.format { + background-size: contain; + display: inline-block; + height: 18px; + width: 18px; + margin-top: 2px; + vertical-align: -0.25em; + display: flex; + opacity: 0.6; +} + +.toolbar button.toolbar-item:disabled i.format { + opacity: 0.2; +} + +.toolbar button.toolbar-item.active { + background-color: rgba(223, 232, 250, 0.3); +} + +.toolbar button.toolbar-item.active i { + opacity: 1; +} + +.toolbar .toolbar-item:hover:not([disabled]) { + background-color: #eee; +} + +.toolbar .divider { + width: 1px; + background-color: #eee; + margin: 0 4px; +} + +.toolbar .toolbar-item .text { + display: flex; + line-height: 20px; + width: 200px; + vertical-align: middle; + font-size: 14px; + color: #777; + text-overflow: ellipsis; + width: 70px; + overflow: hidden; + height: 20px; + text-align: left; +} + +.toolbar .toolbar-item .icon { + display: flex; + width: 20px; + height: 20px; + user-select: none; + margin-right: 8px; + line-height: 16px; + background-size: contain; +} + +i.undo { + background-image: url(icons/arrow-counterclockwise.svg); +} + +i.redo { + background-image: url(icons/arrow-clockwise.svg); +} + +i.bold { + background-image: url(icons/type-bold.svg); +} + +i.italic { + background-image: url(icons/type-italic.svg); +} + +i.underline { + background-image: url(icons/type-underline.svg); +} + +i.strikethrough { + background-image: url(icons/type-strikethrough.svg); +} + +i.left-align { + background-image: url(icons/text-left.svg); +} + +i.center-align { + background-image: url(icons/text-center.svg); +} + +i.right-align { + background-image: url(icons/text-right.svg); +} + +i.justify-align { + background-image: url(icons/justify.svg); +} diff --git a/moon/apps/web/components/Sidebar/SiderbarMergeRequest.tsx b/moon/apps/web/components/Sidebar/SiderbarMergeRequest.tsx new file mode 100644 index 000000000..2e24fffd4 --- /dev/null +++ b/moon/apps/web/components/Sidebar/SiderbarMergeRequest.tsx @@ -0,0 +1,22 @@ +import router from 'next/router' + +import { SidebarLink } from './SidebarLink' +import { useScope } from '@/contexts/scope' +import { GitCommitIcon} from '@gitmono/ui/Icons' + +export function SiderbarMergeRequest() { + const { scope } = useScope() + + return ( + <> + } + /> + + ) +} + diff --git a/moon/apps/web/components/Sidebar/index.tsx b/moon/apps/web/components/Sidebar/index.tsx index 598e4416d..5245f8053 100644 --- a/moon/apps/web/components/Sidebar/index.tsx +++ b/moon/apps/web/components/Sidebar/index.tsx @@ -39,6 +39,7 @@ import { RecentlyViewedPopover } from './RecentlyViewed/RecentlyViewedPopover' import { SidebarGroup } from './SidebarGroup' import { SidebarInbox } from './SidebarInbox' import { SidebarTest } from './SidebarTest' +import { SiderbarMergeRequest } from './SiderbarMergeRequest' export function SidebarContainer() { const { scope } = useScope() @@ -165,6 +166,7 @@ function SidebarContent() { + diff --git a/moon/apps/web/package.json b/moon/apps/web/package.json index 0cea9c046..0a3232bb3 100644 --- a/moon/apps/web/package.json +++ b/moon/apps/web/package.json @@ -26,6 +26,8 @@ "@heroicons/react": "catalog:", "@hocuspocus/provider": "catalog:", "@hookform/resolvers": "catalog:", + "@lexical/react": "catalog:", + "@lexical/utils": "catalog:", "@next/bundle-analyzer": "catalog:", "@octokit/auth-app": "catalog:", "@octokit/core": "catalog:", @@ -50,11 +52,13 @@ "@vercel/og": "catalog:", "@vercel/speed-insights": "catalog:", "antd": "catalog:", + "clsx": "catalog:", "cookies-next": "catalog:", "d3-selection": "catalog:", "d3-zoom": "catalog:", "date-fns": "catalog:", "deepmerge": "catalog:", + "diff2html": "catalog:", "fast-deep-equal": "catalog:", "framer-motion": "catalog:", "github-markdown-css": "catalog:", @@ -63,6 +67,7 @@ "jotai-scope": "catalog:", "js-base64": "catalog:", "jszip": "catalog:", + "lexical": "catalog:", "linkify-react": "catalog:", "linkifyjs": "catalog:", "lottie-web": "catalog:", diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx new file mode 100644 index 000000000..751fb476a --- /dev/null +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -0,0 +1,283 @@ +'use client' + +import React, { useCallback, useEffect, useState } from 'react'; +import { Card, Tabs, TabsProps,Timeline,} from 'antd'; +// import { CommentOutlined, MergeOutlined, CloseCircleOutlined, PullRequestOutlined } from '@ant-design/icons'; +import { ChevronRightCircleIcon, ChevronSelectIcon,AlarmIcon,ClockIcon} from '@gitmono/ui/Icons' +import { formatDistance, fromUnixTime } from 'date-fns'; +import RichEditor from '@/components/MrView/rich-editor/RichEditor'; +import MRComment from '@/components/MrView/MRComment'; +import { useParams, useRouter } from 'next/navigation'; +import * as Diff2Html from 'diff2html'; +import 'diff2html/bundles/css/diff2html.min.css'; +import FilesChanged from '@/components/MrView/files-changed'; +import { Button } from '@gitmono/ui'; +// import { ReloadIcon } from '@radix-ui/react-icons'; +import {DownloadIcon } from '@gitmono/ui' +import { cn } from '@gitmono/ui/utils'; +import AuthAppProviders from '@/components/Providers/AuthAppProviders'; +import { AppLayout } from '@/components/Layout/AppLayout'; +import { PageWithLayout } from '@/utils/types'; + +interface MRDetail { + status: string, + conversations: Conversation[], + title: string, +} +interface Conversation { + id: number, + user_id: number, + conv_type: string, + comment: string, + created_at: number, +} + +const MRDetailPage:PageWithLayout = () =>{ + // const { id } = React.use(params) + const router = useRouter(); + const params = useParams(); + + const id = params?.id as string; + + const [editorState, setEditorState] = useState(""); + const [login, setLogin] = useState(false); + const [mrDetail, setMrDetail] = useState( + { + status: "", + conversations: [], + title: "", + } + ); + const [filedata, setFileData] = useState([]); + const [loadings, setLoadings] = useState([]); + const [outputHtml, setOutputHtml] = useState(''); + + const checkLogin = async () => { + const res = await fetch(`/api/auth`); + + setLogin(res.ok); + }; + + const fetchDetail = useCallback(async () => { + const detail = await fetch(`/api/mr/${id}/detail`); + const detail_json = await detail.json(); + + setMrDetail(detail_json.data.data); + }, [id]); + + const fetchFileList = useCallback(async () => { + set_to_loading(2) + try { + const res = await fetch(`/api/mr/${id}/files`); + const result = await res.json(); + + setFileData(result.data.data); + } finally { + cancel_loading(2) + } + }, [id]); + + const get_diff_content = useCallback(async () => { + const detail = await fetch(`/api/mr/${id}/files-changed`); + const res = await detail.json(); + const diff = Diff2Html.html(res.data.data.content, { drawFileList: true, matching: 'lines' }) + + setOutputHtml(diff); + }, [id]) + + useEffect(() => { + fetchDetail() + fetchFileList(); + checkLogin(); + + }, [id, fetchDetail, fetchFileList]); + + useEffect(()=>{ + // eslint-disable-next-line no-console + console.log(filedata); + },[filedata]) + + const set_to_loading = (index: number) => { + setLoadings((prevLoadings) => { + const newLoadings = [...prevLoadings]; + + newLoadings[index] = true; + return newLoadings; + }); + } + + const cancel_loading = (index: number) => { + setLoadings((prevLoadings) => { + const newLoadings = [...prevLoadings]; + + newLoadings[index] = false; + return newLoadings; + }); + } + + async function approve_mr() { + set_to_loading(1); + const res = await fetch(`/api/mr/${id}/merge`, { + method: 'POST', + }); + + if (res) { + cancel_loading(1); + router.push( + "/mr" + ); + } + }; + + async function close_mr() { + set_to_loading(3); + const res = await fetch(`/api/mr/${id}/close`, { + method: 'POST', + }); + + if (res) { + cancel_loading(3); + router.push( + "/mr" + ); + } + }; + + async function reopen_mr() { + set_to_loading(3); + const res = await fetch(`/api/mr/${id}/reopen`, { + method: 'POST', + }); + + if (res) { + cancel_loading(3); + router.push( + "/mr" + ); + } + }; + + + async function save_comment(comment:any) { + set_to_loading(3); + const res = await fetch(`/api/mr/${id}/comment`, { + method: 'POST', + body: comment, + }); + + if (res) { + setEditorState(""); + fetchDetail(); + cancel_loading(3); + } + } + + let conv_items = mrDetail?.conversations.map(conv => { + let icon; + let children; + + switch (conv.conv_type) { + case "Comment": icon = ; children = ; break + case "Merged": icon = ; children = "Merged via the queue into main " + formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }); break; + case "Closed": icon = ; children = conv.comment; break; + case "Reopen": icon = ; children = conv.comment; break; + }; + + const element = { + dot: icon, + // color: 'red', + children: children + } + + return element + }); + + const onTabsChange = (key: string) => { + // eslint-disable-next-line no-console + console.log(key); + if (key === '2') { + get_diff_content() + } + }; + + const buttonClasses= 'cursor-pointer'; + + const tab_items: TabsProps['items'] = [ + { + key: '1', + label: 'Conversation', + children: +
+ +

Add a comment

+ +
+ {mrDetail && mrDetail.status === "open" && + + } + {mrDetail && mrDetail.status === "closed" && + + } + +
+
+ }, + { + key: '2', + label: 'Files Changed', + children: + } + ]; + + return ( + + {mrDetail && mrDetail.status === "open" && + + } + + + ) +} + + +MRDetailPage.getProviders = (page, pageProps) => { + return ( + + {page} + + ) +} + +export default MRDetailPage diff --git a/moon/apps/web/pages/[org]/mr/index.tsx b/moon/apps/web/pages/[org]/mr/index.tsx new file mode 100644 index 000000000..c09e8f8a6 --- /dev/null +++ b/moon/apps/web/pages/[org]/mr/index.tsx @@ -0,0 +1,29 @@ +import Head from 'next/head' + +import { AppLayout } from '@/components/Layout/AppLayout' +import { AuthAppProviders } from '@/components/Providers/AuthAppProviders' +import { PageWithLayout } from '@/utils/types' +import MrView from '@/components/MrView' + +const OrganizationMrPage: PageWithLayout = () => { + + return ( + <> + + Mr + + + + + ) +} + +OrganizationMrPage.getProviders = (page, pageProps) => { + return ( + + {page} + + ) +} + +export default OrganizationMrPage diff --git a/moon/pnpm-lock.yaml b/moon/pnpm-lock.yaml index e95c502cc..921c683fa 100644 --- a/moon/pnpm-lock.yaml +++ b/moon/pnpm-lock.yaml @@ -30,6 +30,12 @@ catalogs: '@ianvs/prettier-plugin-sort-imports': specifier: ^4.2.1 version: 4.2.1 + '@lexical/react': + specifier: ^0.31.2 + version: 0.31.2 + '@lexical/utils': + specifier: ^0.31.2 + version: 0.31.2 '@next/bundle-analyzer': specifier: ^14.2.5 version: 14.2.5 @@ -307,8 +313,8 @@ catalogs: specifier: ^0.7.0 version: 0.7.0 clsx: - specifier: ^1.2.1 - version: 1.2.1 + specifier: ^2.1.1 + version: 2.1.1 cookies-next: specifier: ^2.1.1 version: 2.1.1 @@ -327,6 +333,9 @@ catalogs: diff: specifier: ^5.1.0 version: 5.1.0 + diff2html: + specifier: ^3.4.51 + version: 3.4.51 eslint: specifier: ^8.57.0 version: 8.57.0 @@ -375,6 +384,9 @@ catalogs: jszip: specifier: ^3.10.1 version: 3.10.1 + lexical: + specifier: ^0.31.2 + version: 0.31.2 linkify-react: specifier: ^4.1.3 version: 4.1.3 @@ -679,6 +691,12 @@ importers: '@hookform/resolvers': specifier: 'catalog:' version: 3.3.1(react-hook-form@7.46.1(react@18.2.0)) + '@lexical/react': + specifier: 'catalog:' + version: 0.31.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(yjs@13.6.8) + '@lexical/utils': + specifier: 'catalog:' + version: 0.31.2 '@next/bundle-analyzer': specifier: 'catalog:' version: 14.2.5 @@ -751,6 +769,9 @@ importers: antd: specifier: 'catalog:' version: 5.25.1(date-fns@3.6.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + clsx: + specifier: 'catalog:' + version: 2.1.1 cookies-next: specifier: 'catalog:' version: 2.1.1 @@ -766,6 +787,9 @@ importers: deepmerge: specifier: 'catalog:' version: 4.3.1 + diff2html: + specifier: 'catalog:' + version: 3.4.51 fast-deep-equal: specifier: 'catalog:' version: 3.1.3 @@ -790,6 +814,9 @@ importers: jszip: specifier: 'catalog:' version: 3.10.1 + lexical: + specifier: 'catalog:' + version: 0.31.2 linkify-react: specifier: 'catalog:' version: 4.1.3(linkifyjs@4.1.3)(react@18.2.0) @@ -1354,7 +1381,7 @@ importers: version: 0.7.0 clsx: specifier: 'catalog:' - version: 1.2.1 + version: 2.1.1 date-fns: specifier: 'catalog:' version: 3.6.0 @@ -2751,6 +2778,77 @@ packages: resolution: {integrity: sha512-ID5Br2OshdhyD4G0g1dm7915Ol2ee6RmCPMDSEh7QFtkbHrtzkgJfYS60na6tGWRBqViAMrCByBfD6uSinjAgg==} engines: {node: '>= 16'} + '@lexical/clipboard@0.31.2': + resolution: {integrity: sha512-cedna5jXfNzbmGl0nLOiLoQoE42i3NfCU6wtugO/auWTLbv1/gD9g0egLg2lAUod+BApaCgdTU4tV2bqww2GWQ==} + + '@lexical/code@0.31.2': + resolution: {integrity: sha512-pix3n43zJzzkOgiUV0aTkWL4syItiHrP7YkdenkXgauVMAqZq3IvmK1hSQYKeDsVw/3N8mU26oRp0g5kPDV1rA==} + + '@lexical/devtools-core@0.31.2': + resolution: {integrity: sha512-Ae5jJzeo6+3DVEWj9n6h+Vz8R4eL+Z7egGHOAwSa3E65PVp8WNlAoM+Z0rNNpvmbFglWD7d9pSPHcK/G5B7Bfw==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.31.2': + resolution: {integrity: sha512-exFqbyyLyfZmmKQgjB4sJOYHV5DQYIPw0orvxpGMeaVCOgfP0RvB21QLHyazmGlnVNcahscHYieZmLJdpwHYMQ==} + + '@lexical/hashtag@0.31.2': + resolution: {integrity: sha512-/sa8bsCq2CKmdpvN/l2B8K/sJrsmd4pAafFG4JWB7JXjPxJyDe80WbSaQfBPdrhvqdLY8l05GeWM17SsEV1sMw==} + + '@lexical/history@0.31.2': + resolution: {integrity: sha512-q3Ykv3oi711XmuFdg7LuppLImyedgpLD5KekXLXRVyOGOTvvaNfb2YQfRjFBalxl3umj2QHYR22Zkamx8zfFXw==} + + '@lexical/html@0.31.2': + resolution: {integrity: sha512-92Oi9daBDNCaionS9ENnXkC+jzzz5WdFTHxTkPqcGaJZE/jF0rAe6LQo6356O/yr9dYK/KIsE8V79AJHqQKJhg==} + + '@lexical/link@0.31.2': + resolution: {integrity: sha512-sLtpW+cuFdVq1V6vlEFUEC1BRHyHBxEdCrxwTP7T0CreJDKrUrBD2oBafb/4AiOPhM7CHAwW88pbuY5KvWOovw==} + + '@lexical/list@0.31.2': + resolution: {integrity: sha512-NbdpxSttk/MmYCSovsxiQwS2h3h2U/Kg3WwNfW9vgpvdZE+qmg6jqpzUFVe51/i+GF2WU0uRPG0J5StMGhtYlg==} + + '@lexical/mark@0.31.2': + resolution: {integrity: sha512-orzsqWaejgdUhSHXRFogF0HNzRWKf2HD7DgiGxKF7LrjVLl4j14+zA8UWX9d4qNwIbRPdfQkYfeOSPwbYx3iRw==} + + '@lexical/markdown@0.31.2': + resolution: {integrity: sha512-2gWo7HiMONTor3whJo1237LZz769eVVRT8kGUgBq/p5QyFsb131NUYSxCperKdDaO43k+4ZQspPHyQJjoyOxHg==} + + '@lexical/offset@0.31.2': + resolution: {integrity: sha512-f8bNvys2jNgnjQWoUd6us7KBXdB7AhKqgWqso7nGeoB1CWGTkd88Qxm8A9uX/muPK0cb6fed4X7wN2xuRDWpyQ==} + + '@lexical/overflow@0.31.2': + resolution: {integrity: sha512-l5jbPglBX8CiXZ7F+okTcfdOwfAgf1JIa8BJhkQrtRP/fEiY3NnCehBYfp/Iyd9uBZDWlVlp1+UsqFFtEeT3Yg==} + + '@lexical/plain-text@0.31.2': + resolution: {integrity: sha512-CMKuWPUCyDZ8ET10YZM7RxDyIB2UiHJ7mEwqEKl86OS9XOhWtp0qUQUonyeAy4f9yfuMTA7fQ2iLlEmAaeVu+g==} + + '@lexical/react@0.31.2': + resolution: {integrity: sha512-A/Ub9Ub5vx9EE0WEhVeE3t/SMVecnaPGeN37Q5LMPXiGgQCsMKEYtjHKvAjjAXSk8YD1lGTd/k4LOjyl8Y9ZyA==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.31.2': + resolution: {integrity: sha512-iBkqY0CvTKbwk3T+a4wtI6/OjhM/CdxXvha6b88Gb9d5tYj5k7cT5SznYF1sXPmwtqpXg9TWkBN2Puqv3LPvsg==} + + '@lexical/selection@0.31.2': + resolution: {integrity: sha512-8hwNgAVWob09y8/Z2QKknw0z6vFcfjsQfHkyDwXwXUeTcJFjlAokrXrc65PRuufI4TaFDQHnXQpP5GcOYROE6Q==} + + '@lexical/table@0.31.2': + resolution: {integrity: sha512-S4W6DdkDCYP32qL6QD4jyksEatyfapRBc4sqoRove83fQEWnFhJ1iBheiG3hSm3YDbDmLclZxcE2CuSIZ6bd0Q==} + + '@lexical/text@0.31.2': + resolution: {integrity: sha512-+rGRAqE4uKdJf25e4stqDImhBh5RgVmxMJf00OyQdwq1P2M+/xF3NddqRpoACHyMyHhuR1wOSONSnYbMqMtc6w==} + + '@lexical/utils@0.31.2': + resolution: {integrity: sha512-vtPzZuJt134cz+oiHAPSIHT3hGt/9Gtug/Cf8OftqJeg3/7P6dKiTdAvAql3q4QxHlCAup4Ed87Ec8PYsICGGg==} + + '@lexical/yjs@0.31.2': + resolution: {integrity: sha512-H1OV+NFGTmHqr+0BFkxo4bDBsdw1WmSwCzIoMVU1uA4levH7tLay/xBV/67ghh+5InSwGR6gcJeFdbL86URuOw==} + peerDependencies: + yjs: '>=13.5.22' + '@lifeomic/attempt@3.0.3': resolution: {integrity: sha512-GlM2AbzrErd/TmLL3E8hAHmb5Q7VhDJp35vIbyPVA5Rz55LZuRr8pwL3qrwwkVNo05gMX1J44gURKb4MHQZo7w==} @@ -6012,6 +6110,10 @@ packages: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + code-red@1.0.4: resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} @@ -6325,9 +6427,6 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dayjs@1.11.9: - resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==} - debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -6485,6 +6584,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff2html@3.4.51: + resolution: {integrity: sha512-/rVCSDyokkzSCEGaGjkkElXtIRwyNDRzIa3S8VUhR6pjk25p6+AMnb1s2zGmhjl66D5m/HnV3IeZoxnWsvTy+w==} + engines: {node: '>=12'} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -6493,6 +6596,10 @@ packages: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -7410,12 +7517,20 @@ packages: resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} engines: {node: '>=6'} + highlight.js@11.9.0: + resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} + engines: {node: '>=12.0.0'} + himalaya@1.1.0: resolution: {integrity: sha512-LLase1dHCRMel68/HZTFft0N0wti0epHr3nNY7ynpLbyZpmrKMQ8YIpiOV77TM97cNpC8Wb2n6f66IRggwdWPw==} hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hogan.js@3.0.2: + resolution: {integrity: sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==} + hasBin: true + hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -8036,6 +8151,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lexical@0.31.2: + resolution: {integrity: sha512-1GRqzl/QAdtzqOoYXVfMFOkyiSQKIIPcazsgIs+WvsLL8UIcwP16WWeKUtamJgyvS84GN/tuMJsd1Iv+Qzw9WA==} + lib0@0.2.108: resolution: {integrity: sha512-+3eK/B0SqYoZiQu9fNk4VEc6EX8cb0Li96tPGKgugzoGj/OdRdREtuTLvUW+mtinoB2mFiJjSqOJBIaMkAGhxQ==} engines: {node: '>=16'} @@ -8527,6 +8645,10 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@0.3.0: + resolution: {integrity: sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==} + deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -8693,6 +8815,10 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + nopt@1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + nopt@6.0.0: resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -9285,6 +9411,10 @@ packages: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -9745,6 +9875,12 @@ packages: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 + react-error-boundary@3.1.4: + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + react-error-boundary@4.0.13: resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} peerDependencies: @@ -11778,7 +11914,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.24.6 '@babel/helper-plugin-utils': 7.24.6 - debug: 4.3.6 + debug: 4.4.1 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -12594,7 +12730,7 @@ snapshots: '@emotion/babel-plugin@11.10.6': dependencies: '@babel/helper-module-imports': 7.24.6 - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.27.1 '@emotion/hash': 0.9.0 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.1 @@ -12992,6 +13128,151 @@ snapshots: '@keyvhq/core': 2.0.0 mimic-fn: 3.0.0 + '@lexical/clipboard@0.31.2': + dependencies: + '@lexical/html': 0.31.2 + '@lexical/list': 0.31.2 + '@lexical/selection': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/code@0.31.2': + dependencies: + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.31.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@lexical/html': 0.31.2 + '@lexical/link': 0.31.2 + '@lexical/mark': 0.31.2 + '@lexical/table': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + + '@lexical/dragon@0.31.2': + dependencies: + lexical: 0.31.2 + + '@lexical/hashtag@0.31.2': + dependencies: + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/history@0.31.2': + dependencies: + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/html@0.31.2': + dependencies: + '@lexical/selection': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/link@0.31.2': + dependencies: + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/list@0.31.2': + dependencies: + '@lexical/selection': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/mark@0.31.2': + dependencies: + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/markdown@0.31.2': + dependencies: + '@lexical/code': 0.31.2 + '@lexical/link': 0.31.2 + '@lexical/list': 0.31.2 + '@lexical/rich-text': 0.31.2 + '@lexical/text': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/offset@0.31.2': + dependencies: + lexical: 0.31.2 + + '@lexical/overflow@0.31.2': + dependencies: + lexical: 0.31.2 + + '@lexical/plain-text@0.31.2': + dependencies: + '@lexical/clipboard': 0.31.2 + '@lexical/selection': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/react@0.31.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(yjs@13.6.8)': + dependencies: + '@lexical/devtools-core': 0.31.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@lexical/dragon': 0.31.2 + '@lexical/hashtag': 0.31.2 + '@lexical/history': 0.31.2 + '@lexical/link': 0.31.2 + '@lexical/list': 0.31.2 + '@lexical/mark': 0.31.2 + '@lexical/markdown': 0.31.2 + '@lexical/overflow': 0.31.2 + '@lexical/plain-text': 0.31.2 + '@lexical/rich-text': 0.31.2 + '@lexical/table': 0.31.2 + '@lexical/text': 0.31.2 + '@lexical/utils': 0.31.2 + '@lexical/yjs': 0.31.2(yjs@13.6.8) + lexical: 0.31.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-error-boundary: 3.1.4(react@18.2.0) + transitivePeerDependencies: + - yjs + + '@lexical/rich-text@0.31.2': + dependencies: + '@lexical/clipboard': 0.31.2 + '@lexical/selection': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/selection@0.31.2': + dependencies: + lexical: 0.31.2 + + '@lexical/table@0.31.2': + dependencies: + '@lexical/clipboard': 0.31.2 + '@lexical/utils': 0.31.2 + lexical: 0.31.2 + + '@lexical/text@0.31.2': + dependencies: + lexical: 0.31.2 + + '@lexical/utils@0.31.2': + dependencies: + '@lexical/list': 0.31.2 + '@lexical/selection': 0.31.2 + '@lexical/table': 0.31.2 + lexical: 0.31.2 + + '@lexical/yjs@0.31.2(yjs@13.6.8)': + dependencies: + '@lexical/offset': 0.31.2 + '@lexical/selection': 0.31.2 + lexical: 0.31.2 + yjs: 13.6.8 + '@lifeomic/attempt@3.0.3': {} '@mdx-js/react@3.0.1(@types/react@18.2.74)(react@18.2.0)': @@ -14853,7 +15134,7 @@ snapshots: '@rollup/pluginutils@5.0.2(rollup@3.29.4)': dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: @@ -16306,18 +16587,19 @@ snapshots: '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 8.56.7 - '@types/estree': 1.0.7 + '@types/estree': 1.0.5 '@types/eslint@8.56.7': dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 '@types/estree@0.0.51': {} '@types/estree@1.0.5': {} - '@types/estree@1.0.7': {} + '@types/estree@1.0.7': + optional: true '@types/express-serve-static-core@4.17.43': dependencies: @@ -16918,7 +17200,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.6 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -17563,7 +17845,7 @@ snapshots: chrono-node@2.6.4: dependencies: - dayjs: 1.11.9 + dayjs: 1.11.13 cipher-base@1.0.4: dependencies: @@ -17628,6 +17910,8 @@ snapshots: clsx@2.0.0: {} + clsx@2.1.1: {} + code-red@1.0.4: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -17958,14 +18242,12 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.27.1 date-fns@3.6.0: {} dayjs@1.11.13: {} - dayjs@1.11.9: {} - debounce@1.2.1: {} debug@2.6.9: @@ -18099,7 +18381,7 @@ snapshots: detect-port@1.5.1: dependencies: address: 1.2.2 - debug: 4.3.6 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -18107,11 +18389,20 @@ snapshots: diff-sequences@29.6.3: {} + diff2html@3.4.51: + dependencies: + diff: 7.0.0 + hogan.js: 3.0.2 + optionalDependencies: + highlight.js: 11.9.0 + diff@4.0.2: optional: true diff@5.1.0: {} + diff@7.0.0: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.0 @@ -18142,7 +18433,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.27.1 csstype: 3.1.3 dom-serializer@1.4.1: @@ -18715,7 +19006,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.5 esutils@2.0.3: {} @@ -19336,6 +19627,9 @@ snapshots: hex-rgb@4.3.0: {} + highlight.js@11.9.0: + optional: true + himalaya@1.1.0: {} hmac-drbg@1.0.1: @@ -19344,6 +19638,11 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 + hogan.js@3.0.2: + dependencies: + mkdirp: 0.3.0 + nopt: 1.0.10 + hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -19671,7 +19970,7 @@ snapshots: is-reference@1.2.1: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.5 is-reference@3.0.3: dependencies: @@ -20031,6 +20330,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lexical@0.31.2: {} + lib0@0.2.108: dependencies: isomorphic.js: 0.2.5 @@ -20694,6 +20995,8 @@ snapshots: mkdirp-classic@0.5.3: {} + mkdirp@0.3.0: {} + mkdirp@1.0.4: {} mlly@1.4.2: @@ -20876,6 +21179,10 @@ snapshots: node-releases@2.0.14: {} + nopt@1.0.10: + dependencies: + abbrev: 1.1.1 + nopt@6.0.0: dependencies: abbrev: 1.1.1 @@ -21462,6 +21769,8 @@ snapshots: pretty-hrtime@1.0.3: {} + prismjs@1.30.0: {} + process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -22115,6 +22424,11 @@ snapshots: react-dom: 18.2.0(react@18.2.0) react-is: 18.1.0 + react-error-boundary@3.1.4(react@18.2.0): + dependencies: + '@babel/runtime': 7.27.1 + react: 18.2.0 + react-error-boundary@4.0.13(react@18.2.0): dependencies: '@babel/runtime': 7.24.1 @@ -22463,7 +22777,7 @@ snapshots: require-in-the-middle@7.3.0: dependencies: - debug: 4.3.6 + debug: 4.4.1 module-details-from-path: 1.0.3 resolve: 1.22.8 transitivePeerDependencies: @@ -23436,7 +23750,7 @@ snapshots: bundle-require: 4.0.3(esbuild@0.19.5) cac: 6.7.14 chokidar: 3.6.0 - debug: 4.3.6 + debug: 4.4.1 esbuild: 0.19.5 execa: 5.1.1 globby: 11.1.0 diff --git a/moon/pnpm-workspace.yaml b/moon/pnpm-workspace.yaml index 33ce6b356..043b2508b 100644 --- a/moon/pnpm-workspace.yaml +++ b/moon/pnpm-workspace.yaml @@ -131,7 +131,6 @@ catalog: body-parser: ^1.20.1 cheerio: ^1.0.0-rc.12 class-variance-authority: ^0.7.0 - clsx: ^1.2.1 cmark-gfm-js: ^1.1.7 concurrently: '>=8' cookies-next: ^2.1.1 @@ -256,3 +255,9 @@ catalog: antd: ^5.25.0 github-markdown-css: ^5.8.1 '@heroicons/react': ^2.2.0 + diff2html: ^3.4.51 + '@lexical/react': ^0.31.2 + '@lexical/utils': ^0.31.2 + lexical: ^0.31.2 + clsx: ^2.1.1 +