mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-24 21:38:09 +02:00
Merge remote-tracking branch 'upstream/dev' into feat/api-key
This commit is contained in:
commit
3695e1d5c5
64 changed files with 1043 additions and 1852 deletions
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
import { useSetAtom } from "jotai";
|
||||
import { FileText } from "lucide-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { FC } from "react";
|
||||
import { useId, useState } from "react";
|
||||
import { openCitationPanelAtom } from "@/atoms/citation/citation-panel.atom";
|
||||
import { openEditorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
||||
import { useCitationMetadata } from "@/components/assistant-ui/citation-metadata-context";
|
||||
import { CitationPanelContent } from "@/components/citation-panel/citation-panel";
|
||||
import { Citation } from "@/components/tool-ui/citation";
|
||||
|
|
@ -110,50 +108,6 @@ const NumericChunkCitation: FC<{ chunkId: number }> = ({ chunkId }) => {
|
|||
);
|
||||
};
|
||||
|
||||
interface LineCitationProps {
|
||||
documentId: number;
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline citation for a knowledge-base document line range
|
||||
* (`[citation:d<documentId>#L<start>-<end>]`). Clicking opens the document in
|
||||
* the editor's read-only source view, scrolled to and highlighting the cited
|
||||
* lines — the same anchor the citation panel uses for chunk citations.
|
||||
*/
|
||||
export const LineCitation: FC<LineCitationProps> = ({ documentId, startLine, endLine }) => {
|
||||
const openEditorPanel = useSetAtom(openEditorPanelAtom);
|
||||
const params = useParams();
|
||||
const searchSpaceId = Number(params?.search_space_id);
|
||||
|
||||
const label = startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
|
||||
|
||||
const handleClick = () => {
|
||||
if (!Number.isFinite(searchSpaceId)) return;
|
||||
openEditorPanel({
|
||||
documentId,
|
||||
searchSpaceId,
|
||||
highlightLines: { start: startLine, end: endLine },
|
||||
forceSourceView: true,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={handleClick}
|
||||
className="ml-0.5 inline-flex h-5 min-w-5 items-center justify-center gap-0.5 rounded-md bg-popover px-1.5 text-[11px] font-medium text-popover-foreground/80 align-baseline"
|
||||
title={`View cited lines ${startLine}–${endLine}`}
|
||||
aria-label={`View cited document lines ${startLine} to ${endLine}`}
|
||||
>
|
||||
<FileText className="size-3" />
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
import { tryGetHostname } from "@/lib/url";
|
||||
|
||||
interface UrlCitationProps {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { BUILD_TIME_AUTH_TYPE, buildBackendUrl } from "@/lib/env-config";
|
||||
import { buildBackendUrl } from "@/lib/env-config";
|
||||
import { trackLoginAttempt } from "@/lib/posthog/events";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
|
|
@ -46,7 +46,6 @@ interface SignInButtonProps {
|
|||
}
|
||||
|
||||
export const SignInButton = ({ variant = "desktop" }: SignInButtonProps) => {
|
||||
const isGoogleAuth = BUILD_TIME_AUTH_TYPE === "GOOGLE";
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
|
|
@ -56,44 +55,45 @@ export const SignInButton = ({ variant = "desktop" }: SignInButtonProps) => {
|
|||
window.location.href = buildBackendUrl("/auth/google/authorize-redirect");
|
||||
};
|
||||
|
||||
const getClassName = () => {
|
||||
const getGoogleClassName = () => {
|
||||
if (variant === "desktop") {
|
||||
return isGoogleAuth
|
||||
? "hidden rounded-full border border-white bg-white px-5 py-2 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] md:flex dark:border-white"
|
||||
: "hidden rounded-full bg-black px-8 py-2 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] md:block dark:bg-white dark:text-black";
|
||||
return "hidden rounded-full border border-white bg-white px-5 py-2 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] md:flex dark:border-white";
|
||||
}
|
||||
if (variant === "compact") {
|
||||
return isGoogleAuth
|
||||
? "rounded-full border border-white bg-white px-4 py-1.5 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white"
|
||||
: "rounded-full bg-black px-6 py-1.5 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black";
|
||||
return "rounded-full border border-white bg-white px-4 py-1.5 text-sm font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white";
|
||||
}
|
||||
// mobile
|
||||
return isGoogleAuth
|
||||
? "w-full rounded-lg border border-white bg-white px-8 py-2.5 font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white touch-manipulation"
|
||||
: "w-full rounded-lg bg-black px-8 py-2 font-medium text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black text-center touch-manipulation";
|
||||
return "w-full rounded-lg border border-white bg-white px-8 py-2.5 font-medium text-[#1f1f1f] shadow-sm hover:bg-zinc-100 hover:text-[#1f1f1f] dark:border-white touch-manipulation";
|
||||
};
|
||||
|
||||
if (isGoogleAuth) {
|
||||
return (
|
||||
const getLocalClassName = () => {
|
||||
if (variant === "desktop") {
|
||||
return "hidden rounded-full bg-black px-8 py-2 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] md:block dark:bg-white dark:text-black";
|
||||
}
|
||||
if (variant === "compact") {
|
||||
return "rounded-full bg-black px-6 py-1.5 text-sm font-bold text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black";
|
||||
}
|
||||
return "w-full rounded-lg bg-black px-8 py-2 font-medium text-white shadow-[0px_-2px_0px_0px_rgba(255,255,255,0.4)_inset] dark:bg-white dark:text-black text-center touch-manipulation";
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={handleGoogleLogin}
|
||||
disabled={isRedirecting}
|
||||
className={cn(
|
||||
"flex items-center justify-center gap-2 transition-colors duration-200 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
getClassName()
|
||||
"runtime-auth-google flex items-center justify-center gap-2 transition-colors duration-200 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
getGoogleClassName()
|
||||
)}
|
||||
>
|
||||
<GoogleLogo className="h-4 w-4" />
|
||||
<span>Sign In</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href="/login" className={getClassName()}>
|
||||
Sign In
|
||||
</Link>
|
||||
<Link href="/login" className={cn("runtime-auth-local", getLocalClassName())}>
|
||||
Sign In
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,13 +46,6 @@ export const CitationPanelContent: FC<CitationPanelContentProps> = ({
|
|||
|
||||
const cited = useMemo(() => data?.chunks.find((c) => c.id === chunkId) ?? null, [data, chunkId]);
|
||||
|
||||
const citedLineLabel = useMemo(() => {
|
||||
const start = data?.cited_start_line;
|
||||
const end = data?.cited_end_line;
|
||||
if (start == null || end == null) return null;
|
||||
return start === end ? `Line ${start}` : `Lines ${start}–${end}`;
|
||||
}, [data?.cited_start_line, data?.cited_end_line]);
|
||||
|
||||
const totalChunks = data?.total_chunks ?? data?.chunks.length ?? 0;
|
||||
const startIndex = data?.chunk_start_index ?? 0;
|
||||
const hasMoreAbove = startIndex > 0;
|
||||
|
|
@ -82,15 +75,10 @@ export const CitationPanelContent: FC<CitationPanelContentProps> = ({
|
|||
|
||||
const handleOpenFullDocument = () => {
|
||||
if (!data) return;
|
||||
const hasLineAnchor = data.cited_start_line != null && data.cited_end_line != null;
|
||||
openEditorPanel({
|
||||
documentId: data.id,
|
||||
searchSpaceId: data.search_space_id,
|
||||
title: data.title,
|
||||
highlightLines: hasLineAnchor
|
||||
? { start: data.cited_start_line as number, end: data.cited_end_line as number }
|
||||
: null,
|
||||
forceSourceView: hasLineAnchor,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +110,6 @@ export const CitationPanelContent: FC<CitationPanelContentProps> = ({
|
|||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 shrink-0 text-[11px] text-muted-foreground">
|
||||
{citedLineLabel && <span>{citedLineLabel}</span>}
|
||||
{totalChunks > 0 && <span>{totalChunks} chunks</span>}
|
||||
{!isLoading && !error && data && (
|
||||
<Button
|
||||
|
|
@ -185,9 +172,7 @@ export const CitationPanelContent: FC<CitationPanelContentProps> = ({
|
|||
Chunk #{chunk.id}
|
||||
</span>
|
||||
{isCited && (
|
||||
<span className="text-[11px] font-semibold text-primary">
|
||||
{citedLineLabel ? `Cited chunk · ${citedLineLabel}` : "Cited chunk"}
|
||||
</span>
|
||||
<span className="text-[11px] font-semibold text-primary">Cited chunk</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { InlineCitation, LineCitation, UrlCitation } from "@/components/assistant-ui/inline-citation";
|
||||
import { InlineCitation, UrlCitation } from "@/components/assistant-ui/inline-citation";
|
||||
import {
|
||||
type CitationToken,
|
||||
type CitationUrlMap,
|
||||
|
|
@ -21,16 +21,6 @@ export function renderCitationToken(token: CitationToken, ordinalKey: number): R
|
|||
if (token.kind === "url") {
|
||||
return <UrlCitation key={`citation-url-${ordinalKey}`} url={token.url} />;
|
||||
}
|
||||
if (token.kind === "line") {
|
||||
return (
|
||||
<LineCitation
|
||||
key={`citation-line-${token.documentId}-${token.startLine}-${ordinalKey}`}
|
||||
documentId={token.documentId}
|
||||
startLine={token.startLine}
|
||||
endLine={token.endLine}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<InlineCitation
|
||||
key={`citation-${token.isDocsChunk ? "doc-" : ""}${token.chunkId}-${ordinalKey}`}
|
||||
|
|
|
|||
|
|
@ -149,8 +149,6 @@ export function EditorPanelContent({
|
|||
searchSpaceId,
|
||||
title,
|
||||
onClose,
|
||||
highlightLines = null,
|
||||
forceSourceView = false,
|
||||
}: {
|
||||
kind?: "document" | "local_file" | "memory";
|
||||
documentId?: number;
|
||||
|
|
@ -159,8 +157,6 @@ export function EditorPanelContent({
|
|||
searchSpaceId?: number;
|
||||
title: string | null;
|
||||
onClose?: () => void;
|
||||
highlightLines?: { start: number; end: number } | null;
|
||||
forceSourceView?: boolean;
|
||||
}) {
|
||||
const electronAPI = useElectronAPI();
|
||||
const [editorDoc, setEditorDoc] = useState<EditorContent | null>(null);
|
||||
|
|
@ -209,7 +205,7 @@ export function EditorPanelContent({
|
|||
const isLargeDocument = docSizeBytes > plateMaxBytes || docLineCount > plateMaxLines;
|
||||
const viewerMode: ViewerMode = isMemoryMode
|
||||
? "plate"
|
||||
: editorDoc?.viewer_mode === "monaco" || isLargeDocument || forceSourceView
|
||||
: editorDoc?.viewer_mode === "monaco" || isLargeDocument
|
||||
? "monaco"
|
||||
: "plate";
|
||||
|
||||
|
|
@ -832,7 +828,6 @@ export function EditorPanelContent({
|
|||
value={editorDoc.source_markdown}
|
||||
readOnly
|
||||
onChange={() => {}}
|
||||
highlightLines={highlightLines}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -923,8 +918,6 @@ function DesktopEditorPanel() {
|
|||
searchSpaceId={panelState.searchSpaceId ?? undefined}
|
||||
title={panelState.title}
|
||||
onClose={closePanel}
|
||||
highlightLines={panelState.highlightLines}
|
||||
forceSourceView={panelState.forceSourceView}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -964,8 +957,6 @@ function MobileEditorDrawer() {
|
|||
memoryScope={panelState.memoryScope ?? undefined}
|
||||
searchSpaceId={panelState.searchSpaceId ?? undefined}
|
||||
title={panelState.title}
|
||||
highlightLines={panelState.highlightLines}
|
||||
forceSourceView={panelState.forceSourceView}
|
||||
/>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
import { type Descendant, KEYS } from "platejs";
|
||||
import { createPlatePlugin, type PlateElementProps } from "platejs/react";
|
||||
import type { FC } from "react";
|
||||
import { InlineCitation, LineCitation, UrlCitation } from "@/components/assistant-ui/inline-citation";
|
||||
import { InlineCitation, UrlCitation } from "@/components/assistant-ui/inline-citation";
|
||||
import {
|
||||
CITATION_REGEX,
|
||||
type CitationToken,
|
||||
type CitationUrlMap,
|
||||
parseTextWithCitations,
|
||||
} from "@/lib/citations/citation-parser";
|
||||
|
|
@ -18,12 +17,9 @@ import {
|
|||
*/
|
||||
export type CitationElementNode = {
|
||||
type: "citation";
|
||||
kind: "chunk" | "doc" | "url" | "line";
|
||||
kind: "chunk" | "doc" | "url";
|
||||
chunkId?: number;
|
||||
url?: string;
|
||||
documentId?: number;
|
||||
startLine?: number;
|
||||
endLine?: number;
|
||||
/** Original literal token that produced this citation node. */
|
||||
rawText: string;
|
||||
children: [{ text: "" }];
|
||||
|
|
@ -37,22 +33,11 @@ const CitationElement: FC<PlateElementProps<CitationElementNode>> = ({
|
|||
element,
|
||||
}) => {
|
||||
const isUrl = element.kind === "url";
|
||||
const isLine =
|
||||
element.kind === "line" &&
|
||||
element.documentId !== undefined &&
|
||||
element.startLine !== undefined &&
|
||||
element.endLine !== undefined;
|
||||
return (
|
||||
<span {...attributes} className="inline-flex align-baseline">
|
||||
<span contentEditable={false}>
|
||||
{isUrl && element.url ? (
|
||||
<UrlCitation url={element.url} />
|
||||
) : isLine ? (
|
||||
<LineCitation
|
||||
documentId={element.documentId as number}
|
||||
startLine={element.startLine as number}
|
||||
endLine={element.endLine as number}
|
||||
/>
|
||||
) : element.chunkId !== undefined ? (
|
||||
<InlineCitation chunkId={element.chunkId} isDocsChunk={element.kind === "doc"} />
|
||||
) : null}
|
||||
|
|
@ -112,7 +97,10 @@ function copyMarks(textNode: SlateText): Record<string, unknown> {
|
|||
return marks;
|
||||
}
|
||||
|
||||
function makeCitationElement(rawText: string, segment: CitationToken): CitationElementNode {
|
||||
function makeCitationElement(
|
||||
rawText: string,
|
||||
segment: { kind: "url"; url: string } | { kind: "chunk"; chunkId: number; isDocsChunk: boolean }
|
||||
): CitationElementNode {
|
||||
if (segment.kind === "url") {
|
||||
return {
|
||||
type: CITATION_TYPE,
|
||||
|
|
@ -122,17 +110,6 @@ function makeCitationElement(rawText: string, segment: CitationToken): CitationE
|
|||
children: [{ text: "" }],
|
||||
};
|
||||
}
|
||||
if (segment.kind === "line") {
|
||||
return {
|
||||
type: CITATION_TYPE,
|
||||
kind: "line",
|
||||
documentId: segment.documentId,
|
||||
startLine: segment.startLine,
|
||||
endLine: segment.endLine,
|
||||
rawText,
|
||||
children: [{ text: "" }],
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: CITATION_TYPE,
|
||||
kind: segment.isDocsChunk ? "doc" : "chunk",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import dynamic from "next/dynamic";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
const MonacoEditor = dynamic(() => import("@monaco-editor/react"), {
|
||||
|
|
@ -17,8 +17,6 @@ interface SourceCodeEditorProps {
|
|||
readOnly?: boolean;
|
||||
fontSize?: number;
|
||||
onSave?: () => Promise<void> | void;
|
||||
/** 1-based inclusive line range to reveal and highlight (e.g. a citation). */
|
||||
highlightLines?: { start: number; end: number } | null;
|
||||
}
|
||||
|
||||
export function SourceCodeEditor({
|
||||
|
|
@ -29,45 +27,10 @@ export function SourceCodeEditor({
|
|||
readOnly = false,
|
||||
fontSize = 12,
|
||||
onSave,
|
||||
highlightLines = null,
|
||||
}: SourceCodeEditorProps) {
|
||||
const { resolvedTheme } = useTheme();
|
||||
const onSaveRef = useRef(onSave);
|
||||
const monacoRef = useRef<any>(null);
|
||||
const editorRef = useRef<any>(null);
|
||||
const decorationsRef = useRef<any>(null);
|
||||
const highlightLinesRef = useRef(highlightLines);
|
||||
highlightLinesRef.current = highlightLines;
|
||||
|
||||
const applyHighlight = useCallback(() => {
|
||||
const editor = editorRef.current;
|
||||
const monaco = monacoRef.current;
|
||||
if (!editor || !monaco) return;
|
||||
if (decorationsRef.current) {
|
||||
decorationsRef.current.clear();
|
||||
decorationsRef.current = null;
|
||||
}
|
||||
const range = highlightLinesRef.current;
|
||||
if (!range) return;
|
||||
const lineCount = editor.getModel()?.getLineCount() ?? range.end;
|
||||
const start = Math.min(Math.max(1, Math.floor(range.start)), lineCount);
|
||||
const end = Math.min(Math.max(start, Math.floor(range.end)), lineCount);
|
||||
try {
|
||||
decorationsRef.current = editor.createDecorationsCollection([
|
||||
{
|
||||
range: new monaco.Range(start, 1, end, 1),
|
||||
options: { isWholeLine: true, className: "citation-line-highlight" },
|
||||
},
|
||||
]);
|
||||
} catch {
|
||||
// Decoration failure must not block the reveal below.
|
||||
}
|
||||
editor.revealLinesInCenter(start, end, monaco.editor.ScrollType.Immediate);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
applyHighlight();
|
||||
}, [applyHighlight, highlightLines?.start, highlightLines?.end]);
|
||||
const normalizedModelPath = (() => {
|
||||
const raw = (path || "local-file.txt").trim();
|
||||
const withLeadingSlash = raw.startsWith("/") ? raw : `/${raw}`;
|
||||
|
|
@ -141,16 +104,7 @@ export function SourceCodeEditor({
|
|||
}}
|
||||
onMount={(editor, monaco) => {
|
||||
monacoRef.current = monaco;
|
||||
editorRef.current = editor;
|
||||
applySidebarTheme(monaco);
|
||||
// Reveal now, then once more after the first layout settles:
|
||||
// the panel slide-in animation means the editor often has no
|
||||
// usable viewport height on the initial frame.
|
||||
applyHighlight();
|
||||
const layoutSub = editor.onDidLayoutChange(() => {
|
||||
applyHighlight();
|
||||
layoutSub.dispose();
|
||||
});
|
||||
if (!isManualSaveEnabled) return;
|
||||
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
|
||||
void onSaveRef.current?.();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import {
|
|||
getAssetLabel,
|
||||
usePrimaryDownload,
|
||||
} from "@/lib/desktop-download-utils";
|
||||
import { BUILD_TIME_AUTH_TYPE, buildBackendUrl } from "@/lib/env-config";
|
||||
import { buildBackendUrl } from "@/lib/env-config";
|
||||
import { trackLoginAttempt } from "@/lib/posthog/events";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
|
|
@ -314,7 +314,6 @@ export function HeroSection() {
|
|||
}
|
||||
|
||||
function GetStartedButton() {
|
||||
const isGoogleAuth = BUILD_TIME_AUTH_TYPE === "GOOGLE";
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
|
|
@ -324,29 +323,26 @@ function GetStartedButton() {
|
|||
window.location.href = buildBackendUrl("/auth/google/authorize-redirect");
|
||||
};
|
||||
|
||||
if (isGoogleAuth) {
|
||||
return (
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={handleGoogleLogin}
|
||||
disabled={isRedirecting}
|
||||
className="h-14 w-full cursor-pointer gap-3 rounded-lg border border-white bg-white text-center text-base font-medium text-[#1f1f1f] shadow-sm transition duration-150 hover:bg-zinc-100 hover:text-[#1f1f1f] sm:w-56 dark:border-white"
|
||||
className="runtime-auth-google h-14 w-full cursor-pointer gap-3 rounded-lg border border-white bg-white text-center text-base font-medium text-[#1f1f1f] shadow-sm transition duration-150 hover:bg-zinc-100 hover:text-[#1f1f1f] sm:w-56 dark:border-white"
|
||||
>
|
||||
<GoogleLogo className="h-5 w-5" />
|
||||
<span>Continue with Google</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
asChild
|
||||
variant="ghost"
|
||||
className="h-14 w-full rounded-lg bg-black text-center text-base font-medium text-white shadow-sm ring-1 shadow-black/10 ring-black/10 transition duration-150 active:scale-98 hover:bg-black sm:w-52 dark:bg-white dark:text-black dark:hover:bg-white"
|
||||
>
|
||||
<Link href="/login">Get Started</Link>
|
||||
</Button>
|
||||
<Button
|
||||
asChild
|
||||
variant="ghost"
|
||||
className="runtime-auth-local h-14 w-full rounded-lg bg-black text-center text-base font-medium text-white shadow-sm ring-1 shadow-black/10 ring-black/10 transition duration-150 active:scale-98 hover:bg-black sm:w-52 dark:bg-white dark:text-black dark:hover:bg-white"
|
||||
>
|
||||
<Link href="/login">Get Started</Link>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { rightPanelCollapsedAtom, rightPanelTabAtom } from "@/atoms/layout/right
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/features/chat-messages/hitl";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { DocumentsSidebar } from "../sidebar";
|
||||
|
||||
|
|
@ -197,9 +196,6 @@ export function RightPanel({
|
|||
const citationState = useAtomValue(citationPanelAtom);
|
||||
const closeCitation = useSetAtom(closeCitationPanelAtom);
|
||||
const [collapsed, setCollapsed] = useAtom(rightPanelCollapsedAtom);
|
||||
// Desktop-only surface; mobile uses the dedicated Mobile* drawers. Without
|
||||
// this guard both render together and two editors fight over one model.
|
||||
const isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||
|
||||
const documentsOpen = documentsPanel?.open ?? false;
|
||||
const reportOpen = reportState.isOpen && !!reportState.reportId;
|
||||
|
|
@ -271,7 +267,7 @@ export function RightPanel({
|
|||
<CollapseButton onClick={() => setCollapsed(true)} />
|
||||
) : null;
|
||||
|
||||
if (!isVisible || !isDesktop) return null;
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<aside
|
||||
|
|
@ -312,8 +308,6 @@ export function RightPanel({
|
|||
searchSpaceId={editorState.searchSpaceId ?? undefined}
|
||||
title={editorState.title}
|
||||
onClose={closeEditor}
|
||||
highlightLines={editorState.highlightLines}
|
||||
forceSourceView={editorState.forceSourceView}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ export function ModelSelector({
|
|||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
aria-label="Select chat model"
|
||||
className={cn(
|
||||
"h-8 min-w-0 gap-2 rounded-md px-3 text-muted-foreground transition-colors",
|
||||
"select-none",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue