+ {/* Chrome controls match ResourceHeader's toggle+switcher cluster (9px
+ pull-out, gap-1 rhythm) inside the canonical 44px bar, so the pair
+ lands on the same 7px/7px spot as every other page and never shifts
+ during navigation. The 44px bar keeps the 27px chips at the same
+ 8.5px inset the old padding produced. */}
+
+
+
+
Integrations
diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/showcase-with-explore.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/showcase-with-explore.tsx
index 73666025dec..bc2653e7405 100644
--- a/apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/showcase-with-explore.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/showcase-with-explore.tsx
@@ -1,8 +1,8 @@
'use client'
-import { ArrowRight } from 'lucide-react'
import { useParams, useRouter } from 'next/navigation'
import { Chip } from '@/components/emcn'
+import { ArrowRight } from '@/components/emcn/icons'
import { IntegrationsShowcase } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase'
import { storeCuratedPrompt } from '@/blocks/integration-matcher'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
index 3ccdc46f638..e044e77ca2e 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
@@ -2,10 +2,10 @@
import { useCallback, useEffect, useEffectEvent, useMemo, useRef, useState } from 'react'
import { createLogger } from '@sim/logger'
-import { ChevronDown, ChevronUp, FileText, Pencil, Tag } from 'lucide-react'
+import { ChevronUp, FileText } from 'lucide-react'
import { useParams, useRouter, useSearchParams } from 'next/navigation'
-import { Badge, ChipCombobox, ChipConfirmModal, Plus, Trash } from '@/components/emcn'
-import { Database } from '@/components/emcn/icons'
+import { Badge, ChipCombobox, ChipConfirmModal } from '@/components/emcn'
+import { ChevronDown, Database, Pencil, Plus, TagIcon, Trash } from '@/components/emcn/icons'
import { SearchHighlight } from '@/components/ui/search-highlight'
import type { ChunkData } from '@/lib/knowledge/types'
import { formatTokenCount } from '@/lib/tokenization'
@@ -73,6 +73,13 @@ interface DocumentProps {
documentId: string
knowledgeBaseName?: string
documentName?: string
+ /**
+ * Panel-embedded mode: back-navigation to the knowledge base (breadcrumb,
+ * post-delete) is delegated to the host instead of routing the page away.
+ */
+ onNavigateToKnowledgeBase?: () => void
+ /** Embedded counterpart for the root "Knowledge Base" breadcrumb. */
+ onNavigateToRoot?: () => void
}
function truncateContent(content: string, maxLength = 150, searchQuery = ''): string {
@@ -115,6 +122,8 @@ export function Document({
documentId,
knowledgeBaseName,
documentName,
+ onNavigateToKnowledgeBase,
+ onNavigateToRoot,
}: DocumentProps) {
const { workspaceId } = useParams()
const router = useRouter()
@@ -428,12 +437,20 @@ export function Document({
)
const handleNavToKB = useCallback(() => {
+ if (onNavigateToRoot) {
+ onNavigateToRoot()
+ return
+ }
router.push(`/workspace/${workspaceId}/knowledge`)
- }, [router, workspaceId])
+ }, [router, workspaceId, onNavigateToRoot])
const handleNavToKBDetail = useCallback(() => {
+ if (onNavigateToKnowledgeBase) {
+ onNavigateToKnowledgeBase()
+ return
+ }
router.push(`/workspace/${workspaceId}/knowledge/${knowledgeBaseId}`)
- }, [router, workspaceId, knowledgeBaseId])
+ }, [router, workspaceId, knowledgeBaseId, onNavigateToKnowledgeBase])
const handleStartDocRename = useCallback(() => {
docRename.startRename(documentId, effectiveDocumentName)
@@ -479,7 +496,7 @@ export function Document({
...(userPermissions.canEdit
? [
{ label: 'Rename', icon: Pencil, onClick: handleStartDocRename },
- { label: 'Tags', icon: Tag, onClick: handleShowTags },
+ { label: 'Tags', icon: TagIcon, onClick: handleShowTags },
{ label: 'Delete', icon: Trash, onClick: handleShowDeleteDoc },
]
: []),
@@ -700,6 +717,10 @@ export function Document({
{ knowledgeBaseId, documentId },
{
onSuccess: () => {
+ if (onNavigateToKnowledgeBase) {
+ onNavigateToKnowledgeBase()
+ return
+ }
router.push(`/workspace/${workspaceId}/knowledge/${knowledgeBaseId}`)
},
}
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
index f0bbc811cec..f79c920a769 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
@@ -49,6 +49,7 @@ import type {
} from '@/app/workspace/[workspaceId]/components'
import { Resource } from '@/app/workspace/[workspaceId]/components'
import { FloatingOverflowText } from '@/app/workspace/[workspaceId]/components/resource/components/floating-overflow-text'
+import { Document } from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document'
import {
ActionBar,
AddConnectorModal,
@@ -109,6 +110,17 @@ interface KnowledgeBaseProps {
id: string
knowledgeBaseName?: string
workspaceId?: string
+ /**
+ * Panel-embedded mode (the chat's resource panel): opening a document swaps
+ * to the document view inside the panel instead of routing to the full
+ * page, so the chat beside it never closes.
+ */
+ embedded?: boolean
+ /**
+ * Embedded: where the root breadcrumb and KB deletion land (the host stages
+ * the Knowledge Base page) instead of routing to `/knowledge`.
+ */
+ onNavigateToRoot?: () => void
}
const AnimatedLoader = ({ className }: { className?: string }) => (
@@ -204,7 +216,13 @@ export function KnowledgeBase({
id,
knowledgeBaseName: passedKnowledgeBaseName,
workspaceId: propWorkspaceId,
+ embedded = false,
+ onNavigateToRoot,
}: KnowledgeBaseProps) {
+ /** Embedded only: the document opened inside the panel (null = the KB list). */
+ const [embeddedDocument, setEmbeddedDocument] = useState<{ id: string; name: string } | null>(
+ null
+ )
const params = useParams()
const workspaceId = propWorkspaceId || (params.workspaceId as string)
const router = useRouter()
@@ -572,9 +590,14 @@ export function KnowledgeBase({
const handleDocumentClick = (docId: string) => {
const document = documents.find((doc) => doc.id === docId)
if (document?.processingStatus !== 'completed') return
+ const docName = document?.filename || 'Document'
+ if (embedded) {
+ setEmbeddedDocument({ id: docId, name: docName })
+ return
+ }
const urlParams = new URLSearchParams({
kbName: knowledgeBaseName,
- docName: document?.filename || 'Document',
+ docName,
})
router.push(`/workspace/${workspaceId}/knowledge/${id}/${docId}?${urlParams.toString()}`)
}
@@ -590,6 +613,10 @@ export function KnowledgeBase({
{
onSuccess: () => {
removeKnowledgeBase(id)
+ if (onNavigateToRoot) {
+ onNavigateToRoot()
+ return
+ }
router.push(`/workspace/${workspaceId}/knowledge`)
},
}
@@ -800,7 +827,7 @@ export function KnowledgeBase({
{
label: 'Knowledge Base',
icon: Database,
- onClick: () => router.push(`/workspace/${workspaceId}/knowledge`),
+ onClick: onNavigateToRoot ?? (() => router.push(`/workspace/${workspaceId}/knowledge`)),
},
{
label: knowledgeBaseName,
@@ -1138,6 +1165,21 @@ export function KnowledgeBase({
)
}
+ // Embedded: the opened document takes the panel in place (its own header
+ // absorbs the panel chrome); its breadcrumbs walk back here, not the router.
+ if (embedded && embeddedDocument) {
+ return (
+
setEmbeddedDocument(null)}
+ onNavigateToRoot={onNavigateToRoot}
+ />
+ )
+ }
+
return (
<>
@@ -1392,9 +1434,14 @@ export function KnowledgeBase({
onViewTags={
contextMenuDocument && selectedDocuments.size === 1
? () => {
+ const docName = contextMenuDocument.filename || 'Document'
+ if (embedded) {
+ setEmbeddedDocument({ id: contextMenuDocument.id, name: docName })
+ return
+ }
const urlParams = new URLSearchParams({
kbName: knowledgeBaseName,
- docName: contextMenuDocument.filename || 'Document',
+ docName,
})
router.push(
`/workspace/${workspaceId}/knowledge/${id}/${contextMenuDocument.id}?${urlParams.toString()}`
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx
index d0d6d21d783..f3bf79af6b2 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx
@@ -1,7 +1,6 @@
'use client'
import { useMemo, useState } from 'react'
-import { ArrowLeft, Plus } from 'lucide-react'
import { useParams } from 'next/navigation'
import {
ArrowRight,
@@ -20,6 +19,7 @@ import {
type ComboboxOption,
Search,
} from '@/components/emcn'
+import { ArrowLeft, Plus } from '@/components/emcn/icons'
import { getSubscriptionAccessState } from '@/lib/billing/client'
import { cn } from '@/lib/core/utils/cn'
import { handleKeyboardActivation } from '@/lib/core/utils/keyboard'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
index 3e2b9fea59b..2e347a35631 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
@@ -3,19 +3,19 @@
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
import { createLogger } from '@sim/logger'
import { format, formatDistanceToNow, isPast } from 'date-fns'
+import { XCircle } from 'lucide-react'
+import { Badge, Button, Checkbox, ChipConfirmModal, Loader, Tooltip } from '@/components/emcn'
import {
- AlertCircle,
- AlertTriangle,
- CheckCircle2,
ChevronDown,
+ CircleAlert,
+ CircleCheck,
Pause,
Play,
RefreshCw,
Settings,
Trash,
- XCircle,
-} from 'lucide-react'
-import { Badge, Button, Checkbox, ChipConfirmModal, Loader, Tooltip } from '@/components/emcn'
+ TriangleAlert,
+} from '@/components/emcn/icons'
import { cn } from '@/lib/core/utils/cn'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import { getCanonicalScopesForProvider, getProviderIdFromServiceId } from '@/lib/oauth'
@@ -352,7 +352,7 @@ function ConnectorCard({
)}