diff --git a/web/app/components/apps/app-list-header-filters.tsx b/web/app/components/apps/app-list-header-filters.tsx
index 824e77dd7d2..36b453c77bb 100644
--- a/web/app/components/apps/app-list-header-filters.tsx
+++ b/web/app/components/apps/app-list-header-filters.tsx
@@ -77,8 +77,9 @@ export function AppListHeaderFilters({
+
{t('studio.viewSnippets', { ns: 'app' })}
{showCreateButton && (
diff --git a/web/app/components/snippets/components/__tests__/snippet-collapsed-preview.spec.tsx b/web/app/components/snippets/components/__tests__/snippet-collapsed-preview.spec.tsx
new file mode 100644
index 00000000000..ab07e4f9444
--- /dev/null
+++ b/web/app/components/snippets/components/__tests__/snippet-collapsed-preview.spec.tsx
@@ -0,0 +1,11 @@
+import { render, screen } from '@testing-library/react'
+import { SnippetCollapsedPreview } from '../snippet-collapsed-preview'
+
+describe('SnippetCollapsedPreview', () => {
+ it('should render collapsed route navigation and input field count', () => {
+ render(
)
+
+ expect(screen.getByRole('link', { name: 'snippet.sectionOrchestrate' })).toHaveAttribute('href', '/snippets/snippet-1/orchestrate')
+ expect(screen.getByLabelText('2 snippet.inputVariables')).toHaveTextContent('2')
+ })
+})
diff --git a/web/app/components/snippets/components/__tests__/snippet-sidebar.spec.tsx b/web/app/components/snippets/components/__tests__/snippet-sidebar.spec.tsx
index 4b2a697278d..9f0328e3024 100644
--- a/web/app/components/snippets/components/__tests__/snippet-sidebar.spec.tsx
+++ b/web/app/components/snippets/components/__tests__/snippet-sidebar.spec.tsx
@@ -152,6 +152,19 @@ describe('SnippetSidebarContent', () => {
expect(capturedVarListProps?.readonly).toBe(true)
})
+ it('should render the orchestrate route menu item', () => {
+ render(
+
,
+ )
+
+ expect(screen.getByRole('link', { name: 'snippet.sectionOrchestrate' })).toHaveAttribute('href', '/snippets/snippet-1/orchestrate')
+ })
+
it('should add a new input field from the config variable modal', () => {
const onFieldsChange = vi.fn()
render(
diff --git a/web/app/components/snippets/components/snippet-collapsed-preview.tsx b/web/app/components/snippets/components/snippet-collapsed-preview.tsx
index 731af1c744d..81632114df9 100644
--- a/web/app/components/snippets/components/snippet-collapsed-preview.tsx
+++ b/web/app/components/snippets/components/snippet-collapsed-preview.tsx
@@ -1,27 +1,62 @@
'use client'
+import { cn } from '@langgenius/dify-ui/cn'
+import { useTranslation } from 'react-i18next'
+import NavLink from '@/app/components/app-sidebar/nav-link'
import { SnippetPlaceholderIcon } from './snippet-placeholder-icon'
+const NodeTreeIcon = ({ className }: { className?: string }) => (
+
+)
+
export function SnippetCollapsedPreview({
inputFieldCount,
+ snippetId,
}: {
inputFieldCount: number
+ snippetId?: string
}) {
+ const { t } = useTranslation()
+ const sectionLabel = t('sectionOrchestrate', { ns: 'snippet' })
+
return (
-
+
+
+ {snippetId
+ ? (
+
+ )
+ : (
+
+ )}
99 ? 'h-5' : 'size-5',
+ )}
+ aria-label={`${inputFieldCount} ${t('inputVariables', { ns: 'snippet' })}`}
>
-
-
- {inputFieldCount}
-
+ {inputFieldCount}
)
diff --git a/web/app/components/snippets/components/snippet-detail-section.tsx b/web/app/components/snippets/components/snippet-detail-section.tsx
index e9798a903d5..0fa9d81442e 100644
--- a/web/app/components/snippets/components/snippet-detail-section.tsx
+++ b/web/app/components/snippets/components/snippet-detail-section.tsx
@@ -19,7 +19,7 @@ export function SnippetDetailSection({ expand }: SnippetDetailSectionProps) {
const snippetInputFields = useSnippetDraftStore(state => state.inputFields)
if (!expand)
- return
+ return
if (!snippetNavigation.snippet || !snippetNavigation.onFieldsChange)
return null
diff --git a/web/app/components/snippets/components/snippet-placeholder-icon.tsx b/web/app/components/snippets/components/snippet-placeholder-icon.tsx
index 982ba688e80..92153214719 100644
--- a/web/app/components/snippets/components/snippet-placeholder-icon.tsx
+++ b/web/app/components/snippets/components/snippet-placeholder-icon.tsx
@@ -14,17 +14,12 @@ export function SnippetPlaceholderIcon({
return (
-
-
-
-
-
-
+
)
}
diff --git a/web/app/components/snippets/components/snippet-sidebar.tsx b/web/app/components/snippets/components/snippet-sidebar.tsx
index a2090979d9b..83ae818f53a 100644
--- a/web/app/components/snippets/components/snippet-sidebar.tsx
+++ b/web/app/components/snippets/components/snippet-sidebar.tsx
@@ -7,6 +7,7 @@ import { toast } from '@langgenius/dify-ui/toast'
import { isEqual } from 'es-toolkit/predicate'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
+import NavLink from '@/app/components/app-sidebar/nav-link'
import SnippetInfoDropdown from '@/app/components/app-sidebar/snippet-info/dropdown'
import ConfigVarModal from '@/app/components/app/configuration/config-var/config-modal'
import Field from '@/app/components/workflow/nodes/_base/components/field'
@@ -36,6 +37,10 @@ const toSnippetInputField = (field: InputVar): SnippetInputField => ({
type: field.type as unknown as SnippetInputField['type'],
})
+const NodeTreeIcon = ({ className }: { className?: string }) => (
+
+)
+
export const SnippetSidebarContent = ({
snippet,
fields,
@@ -109,6 +114,16 @@ export const SnippetSidebarContent = ({
)}
+