diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/CommentPane.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/CommentPane.tsx index 45536d9f6a6..188b76e33c7 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/CommentPane.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/CommentPane.tsx @@ -1,6 +1,5 @@ import { mermaid } from "@streamdown/mermaid"; import type { RendererContext } from "@superset/panes"; -import { Avatar, AvatarFallback, AvatarImage } from "@superset/ui/avatar"; import { type ReactNode, useCallback, @@ -8,7 +7,7 @@ import { useRef, useState, } from "react"; -import { LuCheck, LuCopy } from "react-icons/lu"; +import { LuCheck } from "react-icons/lu"; import ReactMarkdown from "react-markdown"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { @@ -30,84 +29,18 @@ interface CommentPaneProps { export function CommentPane({ context }: CommentPaneProps) { const data = context.pane.data as CommentPaneData; - const [copied, setCopied] = useState(false); - const copyTimerRef = useRef | null>(null); - const isMountedRef = useRef(true); - - useEffect(() => { - return () => { - isMountedRef.current = false; - if (copyTimerRef.current) clearTimeout(copyTimerRef.current); - }; - }, []); - - const handleCopyAll = useCallback(() => { - void electronTrpcClient.external.copyText - .mutate(data.body) - .then(() => { - if (!isMountedRef.current) return; - if (copyTimerRef.current) clearTimeout(copyTimerRef.current); - setCopied(true); - copyTimerRef.current = setTimeout(() => { - if (!isMountedRef.current) return; - setCopied(false); - copyTimerRef.current = null; - }, 1500); - }) - .catch((err) => { - console.warn("Failed to copy comment text", err); - }); - }, [data.body]); return ( -
-
- - {data.avatarUrl ? ( - - ) : null} - - {data.authorLogin.slice(0, 2).toUpperCase()} - - - - {data.authorLogin} - - {data.path && ( - - {data.path} - {data.line != null ? `:${data.line}` : ""} - - )} - -
-
-
- - {data.body} - -
-
+ {data.body} + +
); } diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/CommentPaneHeaderExtras.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/CommentPaneHeaderExtras.tsx new file mode 100644 index 00000000000..6aa00db8dbc --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/CommentPaneHeaderExtras.tsx @@ -0,0 +1,87 @@ +import type { RendererContext } from "@superset/panes"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { FaGithub } from "react-icons/fa"; +import { LuCheck, LuCopy } from "react-icons/lu"; +import { electronTrpcClient } from "renderer/lib/trpc-client"; +import type { CommentPaneData, PaneViewerData } from "../../../../../../types"; + +interface CommentPaneHeaderExtrasProps { + context: RendererContext; +} + +export function CommentPaneHeaderExtras({ + context, +}: CommentPaneHeaderExtrasProps) { + const data = context.pane.data as CommentPaneData; + const [copied, setCopied] = useState(false); + const copyTimerRef = useRef | null>(null); + const isMountedRef = useRef(true); + + useEffect(() => { + return () => { + isMountedRef.current = false; + if (copyTimerRef.current) clearTimeout(copyTimerRef.current); + }; + }, []); + + const handleCopyAll = useCallback(() => { + void electronTrpcClient.external.copyText + .mutate(data.body) + .then(() => { + if (!isMountedRef.current) return; + if (copyTimerRef.current) clearTimeout(copyTimerRef.current); + setCopied(true); + copyTimerRef.current = setTimeout(() => { + if (!isMountedRef.current) return; + setCopied(false); + copyTimerRef.current = null; + }, 1500); + }) + .catch((err) => { + console.warn("Failed to copy comment text", err); + }); + }, [data.body]); + + return ( + <> + {data.url && ( + + + + + + + + Open on GitHub + + + )} + + + + + + {copied ? "Copied" : "Copy comment"} + + + + ); +} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/index.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/index.ts new file mode 100644 index 00000000000..3f6f732e669 --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneHeaderExtras/index.ts @@ -0,0 +1 @@ +export { CommentPaneHeaderExtras } from "./CommentPaneHeaderExtras"; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/CommentPaneTitle.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/CommentPaneTitle.tsx new file mode 100644 index 00000000000..d46141028ee --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/CommentPaneTitle.tsx @@ -0,0 +1,45 @@ +import type { RendererContext } from "@superset/panes"; +import { cn } from "@superset/ui/utils"; +import { MessageSquare } from "lucide-react"; +import type { CommentPaneData, PaneViewerData } from "../../../../../../types"; + +interface CommentPaneTitleProps { + context: RendererContext; +} + +export function CommentPaneTitle({ context }: CommentPaneTitleProps) { + const data = context.pane.data as CommentPaneData; + const { isActive } = context; + + return ( +
+ {data.avatarUrl ? ( + + ) : ( + + )} + + {data.authorLogin} + + {data.path && ( + + {data.path} + {data.line != null ? `:${data.line}` : ""} + + )} +
+ ); +} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/index.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/index.ts new file mode 100644 index 00000000000..5b3ca95ae72 --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/CommentPane/components/CommentPaneTitle/index.ts @@ -0,0 +1 @@ +export { CommentPaneTitle } from "./CommentPaneTitle"; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx index 604f6773374..be57cffb6e0 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx @@ -17,10 +17,8 @@ import { TerminalSquare, } from "lucide-react"; import { useMemo } from "react"; -import { FaGithub } from "react-icons/fa"; import { LuArrowDownToLine, - LuArrowUpRight, LuClipboard, LuClipboardCopy, LuEraser, @@ -50,6 +48,8 @@ import type { import { BrowserPane, BrowserPaneToolbar } from "./components/BrowserPane"; import { ChatPane } from "./components/ChatPane"; import { CommentPane } from "./components/CommentPane"; +import { CommentPaneHeaderExtras } from "./components/CommentPane/components/CommentPaneHeaderExtras"; +import { CommentPaneTitle } from "./components/CommentPane/components/CommentPaneTitle"; import { DiffPane } from "./components/DiffPane"; import { FilePane } from "./components/FilePane"; import { FilePaneHeaderExtras } from "./components/FilePane/components/FilePaneHeaderExtras"; @@ -482,25 +482,15 @@ export function usePaneRegistry( const data = pane.data as CommentPaneData; return data.authorLogin; }, + renderTitle: (ctx: RendererContext) => ( + + ), renderPane: (ctx: RendererContext) => ( ), - renderHeaderExtras: (ctx: RendererContext) => { - const data = ctx.pane.data as CommentPaneData; - if (!data.url) return null; - return ( - - - - - ); - }, + renderHeaderExtras: (ctx: RendererContext) => ( + + ), contextMenuActions: (_ctx, defaults) => defaults.map((d) => d.key === "close-pane" ? { ...d, label: "Close Comment" } : d,