mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-02 19:55:18 +02:00
Merge remote-tracking branch 'upstream/dev' into feat/whatsapp-gateway-integration
This commit is contained in:
commit
e3de7c4667
465 changed files with 29171 additions and 6994 deletions
|
|
@ -13,8 +13,8 @@ import {
|
|||
CheckIcon,
|
||||
ClipboardPaste,
|
||||
CopyIcon,
|
||||
DownloadIcon,
|
||||
Dot,
|
||||
DownloadIcon,
|
||||
ExternalLink,
|
||||
Globe,
|
||||
MessageCircleReply,
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||
import { useApiKey } from "@/hooks/use-api-key";
|
||||
import { BACKEND_URL } from "@/lib/env-config";
|
||||
import { getConnectorBenefits } from "../connector-benefits";
|
||||
import type { ConnectFormProps } from "../index";
|
||||
import { BACKEND_URL } from "@/lib/env-config";
|
||||
|
||||
const PLUGIN_RELEASES_URL =
|
||||
"https://github.com/MODSetter/SurfSense/releases?q=obsidian&expanded=true";
|
||||
|
||||
|
||||
/**
|
||||
* Obsidian connect form for the plugin-only architecture.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import { Button } from "@/components/ui/button";
|
|||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||
import type { ConnectorConfigProps } from "../index";
|
||||
import { BACKEND_URL } from "@/lib/env-config";
|
||||
import type { ConnectorConfigProps } from "../index";
|
||||
export interface CirclebackConfigProps extends ConnectorConfigProps {
|
||||
onNameChange?: (name: string) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { LIVE_CONNECTOR_TYPES } from "../../constants/connector-constants";
|
|||
import { getConnectorDisplayName } from "../../tabs/all-connectors-tab";
|
||||
import { MCPServiceConfig } from "../components/mcp-service-config";
|
||||
import { getConnectorConfigComponent } from "../index";
|
||||
|
||||
const VISION_LLM_CONNECTOR_TYPES = new Set<SearchSourceConnector["connector_type"]>([
|
||||
EnumConnectorName.GOOGLE_DRIVE_CONNECTOR,
|
||||
EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { cn } from "@/lib/utils";
|
|||
import { LIVE_CONNECTOR_TYPES } from "../constants/connector-constants";
|
||||
import { useConnectorStatus } from "../hooks/use-connector-status";
|
||||
import { getConnectorDisplayName } from "../tabs/all-connectors-tab";
|
||||
|
||||
interface ConnectorAccountsListViewProps {
|
||||
connectorType: string;
|
||||
connectorTitle: string;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { ExternalLink, FileText } from "lucide-react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { FileText } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { useState } from "react";
|
||||
import { openCitationPanelAtom } from "@/atoms/citation/citation-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";
|
||||
import { CitationHoverPopover } from "@/components/tool-ui/citation/citation-hover-popover";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Drawer,
|
||||
|
|
@ -19,21 +16,8 @@ import {
|
|||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "@/components/ui/drawer";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
||||
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||
|
||||
// Lazily load MarkdownViewer here to break the static import cycle:
|
||||
// `markdown-viewer.tsx` → `citation-renderer.tsx` → `inline-citation.tsx`
|
||||
// would otherwise pull `markdown-viewer.tsx` back in at module-init time.
|
||||
// Only `SurfsenseDocCitation` (popover body) ever renders this viewer, so
|
||||
// the lazy boundary is invisible to most call paths.
|
||||
const MarkdownViewer = dynamic(
|
||||
() => import("@/components/markdown-viewer").then((m) => m.MarkdownViewer),
|
||||
{ ssr: false, loading: () => <Spinner size="xs" /> }
|
||||
);
|
||||
|
||||
interface InlineCitationProps {
|
||||
chunkId: number;
|
||||
|
|
@ -41,9 +25,7 @@ interface InlineCitationProps {
|
|||
}
|
||||
|
||||
/**
|
||||
* Inline citation badge for knowledge-base chunks (numeric chunk IDs) and
|
||||
* Surfsense documentation chunks (`isDocsChunk`). Negative chunk IDs render as
|
||||
* a static "doc" pill (anonymous/synthetic uploads).
|
||||
* Inline citation badge for knowledge-base chunks (numeric chunk IDs).
|
||||
*
|
||||
* Numeric KB chunks: clicking opens the citation panel in the right
|
||||
* sidebar (alongside the chat — does not replace it). The panel shows
|
||||
|
|
@ -51,12 +33,13 @@ interface InlineCitationProps {
|
|||
* `chunk_window`), with the cited one highlighted and an option to
|
||||
* expand the window or jump into the full document via the editor panel.
|
||||
*
|
||||
* Surfsense docs chunks: rendered as a hover-controlled shadcn Popover that
|
||||
* lazily fetches and previews the cited chunk inline, since those docs aren't
|
||||
* indexed into the user's search space and have no tab to open.
|
||||
* Negative chunk IDs and legacy SurfSense-docs chunks (`isDocsChunk`) render
|
||||
* as a static, non-interactive "doc" pill. The SurfSense product-docs feature
|
||||
* was removed, so those markers are inert (no fetch, no preview) — they only
|
||||
* survive in old persisted messages.
|
||||
*/
|
||||
export const InlineCitation: FC<InlineCitationProps> = ({ chunkId, isDocsChunk = false }) => {
|
||||
if (chunkId < 0) {
|
||||
if (chunkId < 0 || isDocsChunk) {
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
|
|
@ -68,15 +51,13 @@ export const InlineCitation: FC<InlineCitationProps> = ({ chunkId, isDocsChunk =
|
|||
doc
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Uploaded document</TooltipContent>
|
||||
<TooltipContent>
|
||||
{isDocsChunk ? "Documentation reference" : "Uploaded document"}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
if (isDocsChunk) {
|
||||
return <SurfsenseDocCitation chunkId={chunkId} />;
|
||||
}
|
||||
|
||||
return <NumericChunkCitation chunkId={chunkId} />;
|
||||
};
|
||||
|
||||
|
|
@ -127,128 +108,6 @@ const NumericChunkCitation: FC<{ chunkId: number }> = ({ chunkId }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const SurfsenseDocCitation: FC<{ chunkId: number }> = ({ chunkId }) => {
|
||||
const isTouchLike = useMediaQuery("(hover: none), (pointer: coarse)");
|
||||
const [mobilePreviewOpen, setMobilePreviewOpen] = useState(false);
|
||||
const docQuery = useSurfsenseDocPreviewQuery(chunkId, mobilePreviewOpen);
|
||||
|
||||
const handleMobileClick = () => {
|
||||
setMobilePreviewOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<CitationHoverPopover
|
||||
id={`doc-${chunkId}`}
|
||||
contentClassName="w-96 max-w-[calc(100vw-2rem)] p-0"
|
||||
align="start"
|
||||
trigger={(hoverProps) => (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size={null}
|
||||
onClick={isTouchLike ? handleMobileClick : undefined}
|
||||
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"
|
||||
aria-label={`Show Surfsense documentation chunk ${chunkId}`}
|
||||
title="Surfsense documentation"
|
||||
{...hoverProps}
|
||||
>
|
||||
<FileText className="size-3" />
|
||||
doc
|
||||
</Button>
|
||||
)}
|
||||
>
|
||||
<SurfsenseDocPreview chunkId={chunkId} />
|
||||
</CitationHoverPopover>
|
||||
<Drawer
|
||||
open={mobilePreviewOpen}
|
||||
onOpenChange={setMobilePreviewOpen}
|
||||
shouldScaleBackground={false}
|
||||
>
|
||||
<DrawerContent className="max-h-[85vh] z-80" overlayClassName="z-80">
|
||||
<DrawerHandle />
|
||||
<DrawerHeader className="pb-0">
|
||||
<DrawerTitle>Surfsense documentation</DrawerTitle>
|
||||
</DrawerHeader>
|
||||
<SurfsenseDocPreviewContent
|
||||
chunkId={chunkId}
|
||||
query={docQuery}
|
||||
contentClassName="max-h-[60vh]"
|
||||
/>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function useSurfsenseDocPreviewQuery(chunkId: number, enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: cacheKeys.documents.byChunk(`doc-${chunkId}`),
|
||||
queryFn: () => documentsApiService.getSurfsenseDocByChunk(chunkId),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
type SurfsenseDocPreviewQuery = ReturnType<typeof useSurfsenseDocPreviewQuery>;
|
||||
|
||||
const SurfsenseDocPreview: FC<{ chunkId: number }> = ({ chunkId }) => {
|
||||
const query = useSurfsenseDocPreviewQuery(chunkId);
|
||||
|
||||
return <SurfsenseDocPreviewContent chunkId={chunkId} query={query} />;
|
||||
};
|
||||
|
||||
const SurfsenseDocPreviewContent: FC<{
|
||||
chunkId: number;
|
||||
query: SurfsenseDocPreviewQuery;
|
||||
contentClassName?: string;
|
||||
}> = ({ chunkId, query, contentClassName = "max-h-72" }) => {
|
||||
const { data, isLoading, error } = query;
|
||||
|
||||
const citedChunk = data?.chunks.find((c) => c.id === chunkId) ?? data?.chunks[0];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center justify-between gap-2 border-b px-3 py-2">
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium">{data?.title ?? "Surfsense documentation"}</p>
|
||||
<p className="text-[11px] text-muted-foreground">Chunk #{chunkId}</p>
|
||||
</div>
|
||||
{data?.public_url && (
|
||||
<a
|
||||
href={data.public_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium text-primary hover:bg-primary/10"
|
||||
>
|
||||
<ExternalLink className="size-3" />
|
||||
Open
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${contentClassName} overflow-auto px-3 py-2 text-sm`}>
|
||||
{isLoading && (
|
||||
<div className="flex items-center gap-2 py-4 text-muted-foreground">
|
||||
<Spinner size="xs" />
|
||||
<span className="text-xs">Loading…</span>
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<p className="py-4 text-xs text-destructive">
|
||||
{error instanceof Error ? error.message : "Failed to load chunk"}
|
||||
</p>
|
||||
)}
|
||||
{!isLoading && !error && citedChunk?.content && (
|
||||
<MarkdownViewer content={citedChunk.content} maxLength={1500} enableCitations />
|
||||
)}
|
||||
{!isLoading && !error && !citedChunk?.content && (
|
||||
<p className="py-4 text-xs text-muted-foreground">No content available.</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
import { tryGetHostname } from "@/lib/url";
|
||||
|
||||
interface UrlCitationProps {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,12 @@ interface InlineMentionEditorProps {
|
|||
onActionClose?: () => void;
|
||||
onSubmit?: () => void;
|
||||
onChange?: (text: string, docs: MentionedDocument[]) => void;
|
||||
onDocumentRemove?: (docId: number, docType?: string, kind?: MentionKind, connectorType?: string) => void;
|
||||
onDocumentRemove?: (
|
||||
docId: number,
|
||||
docType?: string,
|
||||
kind?: MentionKind,
|
||||
connectorType?: string
|
||||
) => void;
|
||||
onKeyDown?: (e: React.KeyboardEvent) => void;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
|
|
@ -171,9 +176,10 @@ const MentionElement: FC<PlateElementProps<MentionElementNode>> = ({
|
|||
{isFolder ? (
|
||||
<FolderIcon className="h-3 w-3" />
|
||||
) : isConnector ? (
|
||||
getConnectorIcon(element.connector_type ?? element.document_type ?? "UNKNOWN", "h-3 w-3") ?? (
|
||||
<PlugIcon className="h-3 w-3" />
|
||||
)
|
||||
(getConnectorIcon(
|
||||
element.connector_type ?? element.document_type ?? "UNKNOWN",
|
||||
"h-3 w-3"
|
||||
) ?? <PlugIcon className="h-3 w-3" />)
|
||||
) : (
|
||||
getConnectorIcon(element.document_type ?? "UNKNOWN", "h-3 w-3")
|
||||
)}
|
||||
|
|
@ -357,7 +363,11 @@ function getSelectionAnchorRect(root: HTMLElement | null): SuggestionAnchorRect
|
|||
const rect = range.getClientRects()[0] ?? range.getBoundingClientRect();
|
||||
if (rect.width > 0 || rect.height > 0) return rectToAnchor(rect);
|
||||
|
||||
if (range.collapsed && range.startContainer.nodeType === Node.TEXT_NODE && range.startOffset > 0) {
|
||||
if (
|
||||
range.collapsed &&
|
||||
range.startContainer.nodeType === Node.TEXT_NODE &&
|
||||
range.startOffset > 0
|
||||
) {
|
||||
const fallbackRange = range.cloneRange();
|
||||
fallbackRange.setStart(range.startContainer, range.startOffset - 1);
|
||||
fallbackRange.setEnd(range.startContainer, range.startOffset);
|
||||
|
|
|
|||
|
|
@ -67,12 +67,8 @@ import {
|
|||
} from "@/components/assistant-ui/inline-mention-editor";
|
||||
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
||||
import { UserMessage } from "@/components/assistant-ui/user-message";
|
||||
import { ChatExamplePrompts } from "@/components/new-chat/chat-example-prompts";
|
||||
import { ComposerSuggestionPopoverContent } from "@/components/new-chat/composer-suggestion-popup";
|
||||
import {
|
||||
DocumentMentionPicker,
|
||||
promoteRecentMention,
|
||||
type DocumentMentionPickerRef,
|
||||
} from "../new-chat/document-mention-picker";
|
||||
import { PromptPicker, type PromptPickerRef } from "@/components/new-chat/prompt-picker";
|
||||
import { Avatar, AvatarFallback, AvatarGroup } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -112,6 +108,11 @@ import { captureDisplayToPngDataUrl } from "@/lib/chat/display-media-capture";
|
|||
import { getMentionDocKey } from "@/lib/chat/mention-doc-key";
|
||||
import { slideoutOpenedTickAtom } from "@/lib/layout-events";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DocumentMentionPicker,
|
||||
type DocumentMentionPickerRef,
|
||||
promoteRecentMention,
|
||||
} from "../new-chat/document-mention-picker";
|
||||
|
||||
const COMPOSER_PLACEHOLDER = "Ask anything, type / for prompts, type @ to mention docs";
|
||||
|
||||
|
|
@ -601,21 +602,24 @@ const Composer: FC = () => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
const handleActionTrigger = useCallback((trigger: SuggestionTriggerInfo) => {
|
||||
const anchorPoint = getComposerSuggestionAnchorPoint(
|
||||
trigger.anchorRect,
|
||||
clipboardInitialText ? "bottom" : "top"
|
||||
);
|
||||
if (!anchorPoint) {
|
||||
setShowPromptPicker(false);
|
||||
setActionQuery("");
|
||||
setSuggestionAnchorPoint(null);
|
||||
return;
|
||||
}
|
||||
setSuggestionAnchorPoint((current) => current ?? anchorPoint);
|
||||
setShowPromptPicker(true);
|
||||
setActionQuery(trigger.query);
|
||||
}, [clipboardInitialText]);
|
||||
const handleActionTrigger = useCallback(
|
||||
(trigger: SuggestionTriggerInfo) => {
|
||||
const anchorPoint = getComposerSuggestionAnchorPoint(
|
||||
trigger.anchorRect,
|
||||
clipboardInitialText ? "bottom" : "top"
|
||||
);
|
||||
if (!anchorPoint) {
|
||||
setShowPromptPicker(false);
|
||||
setActionQuery("");
|
||||
setSuggestionAnchorPoint(null);
|
||||
return;
|
||||
}
|
||||
setSuggestionAnchorPoint((current) => current ?? anchorPoint);
|
||||
setShowPromptPicker(true);
|
||||
setActionQuery(trigger.query);
|
||||
},
|
||||
[clipboardInitialText]
|
||||
);
|
||||
|
||||
const handleActionClose = useCallback(() => {
|
||||
if (showPromptPicker) {
|
||||
|
|
@ -654,6 +658,15 @@ const Composer: FC = () => {
|
|||
[actionQuery, aui]
|
||||
);
|
||||
|
||||
const handleExampleSelect = useCallback(
|
||||
(prompt: string) => {
|
||||
editorRef.current?.setText(prompt);
|
||||
aui.composer().setText(prompt);
|
||||
editorRef.current?.focus();
|
||||
},
|
||||
[aui]
|
||||
);
|
||||
|
||||
const handleQuickAskSelect = useCallback(
|
||||
(action: { name: string; prompt: string; mode: "transform" | "explore" }) => {
|
||||
if (!clipboardInitialText) return;
|
||||
|
|
@ -754,7 +767,12 @@ const Composer: FC = () => {
|
|||
]);
|
||||
|
||||
const handleDocumentRemove = useCallback(
|
||||
(docId: number, docType?: string, kind?: "doc" | "folder" | "connector", connectorType?: string) => {
|
||||
(
|
||||
docId: number,
|
||||
docType?: string,
|
||||
kind?: "doc" | "folder" | "connector",
|
||||
connectorType?: string
|
||||
) => {
|
||||
setMentionedDocuments((prev) => {
|
||||
const removedKey = getMentionDocKey({
|
||||
id: docId,
|
||||
|
|
@ -768,27 +786,30 @@ const Composer: FC = () => {
|
|||
[setMentionedDocuments]
|
||||
);
|
||||
|
||||
const handleDocumentsMention = useCallback((mentions: MentionedDocumentInfo[]) => {
|
||||
const parsedSearchSpaceId = Number(search_space_id);
|
||||
const editorMentionedDocs = editorRef.current?.getMentionedDocuments() ?? [];
|
||||
const editorDocKeys = new Set(editorMentionedDocs.map((doc) => getMentionDocKey(doc)));
|
||||
const handleDocumentsMention = useCallback(
|
||||
(mentions: MentionedDocumentInfo[]) => {
|
||||
const parsedSearchSpaceId = Number(search_space_id);
|
||||
const editorMentionedDocs = editorRef.current?.getMentionedDocuments() ?? [];
|
||||
const editorDocKeys = new Set(editorMentionedDocs.map((doc) => getMentionDocKey(doc)));
|
||||
|
||||
for (const mention of mentions) {
|
||||
const key = getMentionDocKey(mention);
|
||||
if (editorDocKeys.has(key)) continue;
|
||||
editorRef.current?.insertMentionChip(mention);
|
||||
if (Number.isFinite(parsedSearchSpaceId)) {
|
||||
promoteRecentMention(parsedSearchSpaceId, mention);
|
||||
for (const mention of mentions) {
|
||||
const key = getMentionDocKey(mention);
|
||||
if (editorDocKeys.has(key)) continue;
|
||||
editorRef.current?.insertMentionChip(mention);
|
||||
if (Number.isFinite(parsedSearchSpaceId)) {
|
||||
promoteRecentMention(parsedSearchSpaceId, mention);
|
||||
}
|
||||
// Track within the loop so a duplicate-in-batch can't double-insert.
|
||||
editorDocKeys.add(key);
|
||||
}
|
||||
// Track within the loop so a duplicate-in-batch can't double-insert.
|
||||
editorDocKeys.add(key);
|
||||
}
|
||||
|
||||
// Atom is reconciled by ``handleEditorChange`` via the editor's
|
||||
// onChange — no second write path here.
|
||||
setMentionQuery("");
|
||||
setSuggestionAnchorPoint(null);
|
||||
}, [search_space_id]);
|
||||
// Atom is reconciled by ``handleEditorChange`` via the editor's
|
||||
// onChange — no second write path here.
|
||||
setMentionQuery("");
|
||||
setSuggestionAnchorPoint(null);
|
||||
},
|
||||
[search_space_id]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const editor = editorRef.current;
|
||||
|
|
@ -905,6 +926,7 @@ const Composer: FC = () => {
|
|||
isThreadEmpty={isThreadEmpty}
|
||||
onVisibleChange={setConnectToolsTrayVisible}
|
||||
/>
|
||||
{isThreadEmpty && <ChatExamplePrompts onSelect={handleExampleSelect} />}
|
||||
</div>
|
||||
</ComposerPrimitive.Root>
|
||||
);
|
||||
|
|
@ -1582,7 +1604,7 @@ interface ToolGroup {
|
|||
const TOOL_GROUPS: ToolGroup[] = [
|
||||
{
|
||||
label: "Research",
|
||||
tools: ["search_surfsense_docs", "scrape_webpage"],
|
||||
tools: ["scrape_webpage"],
|
||||
},
|
||||
{
|
||||
label: "Generate",
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ const UserTextPart: FC = () => {
|
|||
const icon = isFolder ? (
|
||||
<FolderIcon className="size-3.5" />
|
||||
) : isConnector ? (
|
||||
getConnectorIcon(segment.doc.connector_type, "size-3.5") ?? (
|
||||
(getConnectorIcon(segment.doc.connector_type, "size-3.5") ?? (
|
||||
<Plug className="size-3.5" />
|
||||
)
|
||||
))
|
||||
) : (
|
||||
getConnectorIcon(segment.doc.document_type ?? "UNKNOWN", "size-3.5")
|
||||
);
|
||||
|
|
@ -123,7 +123,9 @@ const UserTextPart: FC = () => {
|
|||
: segment.doc.title
|
||||
}
|
||||
onClick={
|
||||
isFolder || isConnector ? undefined : () => handleOpenDoc(segment.doc.id, segment.doc.title)
|
||||
isFolder || isConnector
|
||||
? undefined
|
||||
: () => handleOpenDoc(segment.doc.id, segment.doc.title)
|
||||
}
|
||||
className="mx-0.5"
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue