- Implemented File Upload node with support for uploading files to the sandbox.
- Added necessary UI components including node panel and default configurations.
- Enhanced workflow constants and enums to include File Upload.
- Updated error handling for file upload operations.
- Integrated File Upload into existing workflow structure, ensuring compatibility with variable handling and output management.
- Added translations for new File Upload features in workflow.json.
- Use searchParams.toString() to forward all query params instead of
manually encoding only client_id and redirect_uri
- Remove legacy localStorage fallback since storage utility is now
the sole persistence layer
- Add tests for OAuth authorize page, home page, and post-login redirect
- Use storage utility instead of raw localStorage for OAuth pending
redirect with legacy fallback for backward compatibility
- Forward search params from root page to /apps so query strings
(e.g. redirect_url) are not lost during server-side redirect
Move OAuth pending redirect check out of page.tsx since AppInitializer
already handles it globally. Simplify home page to a server-side redirect
and remove dayjs dependency in favor of native Date.now().
Migrate all Remixicon component imports in workflow/skill to Tailwind CSS
icon utility classes (i-ri-*), reducing JS bundle size. Update MenuItem
to accept string icon classes alongside React components. Adjust test
selectors that relied on SVG element queries.
The frontend and backend implementation for the human input node.
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zhsama <torvalds@linux.do>
Remove border-right on Start tab and border-bottom on tab bar when no
file tabs are open, making the tab area blend seamlessly with the
content area below.
Replace placeholder sandbox provider icons with official brand assets:
- Docker: white whale SVG on brand blue (#1D63ED) background
- E2B: official PNG logo via CSS module
- Local: Dify-branded SVG icon (SandboxLocal)
Add a component-level regression test for variable inspect artifacts tab:\n- verifies selected file path is used before reset\n- verifies stale selected path is dropped after files are cleared\n- verifies download url query call keeps retry disabled in this component
Problem:\n- In variable inspect artifacts view, clicking Reset All invalidates sandbox download query keys.\n- If a previously selected file has been removed, the download-url query may still refetch with stale path and return 400.\n- Default query retry amplifies this into repeated failed requests in this scenario.\n\nSolution:\n- Extend sandbox file invalidation with an option to skip download query refetch.\n- Use that option in Reset All flow so download-url queries are marked stale without immediate refetch.\n- Derive selected file path from latest sandbox flat data and disable download-url query when file no longer exists.\n- Disable retry only for artifacts-tab download-url query to avoid repeated 400 retries in this path.\n- Align tree selectedPath with derived selectedFilePath and add hook tests for invalidation behavior.\n\nValidation:\n- pnpm vitest --run service/use-sandbox-file.spec.tsx
Extract SearchResultRow component with useDelayedClick to match file
tree behavior (single-click preview, double-click pin). Subscribe to
derived boolean instead of raw activeTabId to avoid unnecessary
re-renders across all rows.
Replace the tree-filtered search with a flat list that shows icon + name
on the left and parent path on the right, matching the Figma design.
Clicking a file opens its tab; clicking a folder clears the search and
reveals the folder in the tree.
Remove isFocused ring style from TreeNode since focus-visible already
handles keyboard focus indication. Add rowClassName="outline-none" to
suppress the default browser outline on react-arborist row containers.
Add editorAutoFocusFileId state to automatically focus the editor when
a new text file is created. Improve tree-tab synchronization by adding
syncSignal/isTreeLoading guards, deduplicating rAF calls, and skipping
redundant select/openParents operations when the node is already active.
Enable PDF files to be previewed directly in the file content panel
instead of showing as unsupported files requiring download. Uses the
existing react-pdf-highlighter library with zoom controls and keyboard
shortcuts (up/down arrows).
Add "Import skills(.zip)" option to root-level context menu and sidebar
add menu with a question mark tooltip showing usage hint. Update menu
item labels and icons for consistency with design.
- Change Reset All button visibility from Variables-tab-only to both tabs,
displaying when either variables or artifacts have data
- Invalidate sandbox files cache in deleteAllInspectorVars alongside
existing conversation/system var invalidations
The Skill view is locked (ViewPicker disabled) while a workflow
is running or chatflow is responding, so ArtifactsSection is never
mounted during runs. Polling there is dead code.
Add conditional refetchInterval to Artifacts components so the file
list refreshes automatically while a workflow debug run or chatflow
preview is in progress, stopping once the run completes.
Leverage React Query mutation's isPending to disable the Publish button,
header trigger, and keyboard shortcut while a publish is in progress,
preventing duplicate submissions even when the menu is closed and reopened.
Add a unified isPreviewable flag to useFileTypeInfo that guards against
rendering binary files as text in both skill artifacts and variable
inspect artifacts preview. Upgrade extension arrays to Sets for O(1)
lookups.
Split SkillSaveContext and useSkillSaveManager into a separate file to
fix react-refresh/only-export-components lint error. Destructure
mutateAsync from useUpdateAppAssetFileContent for a stable callback
reference, preventing unnecessary useCallback cascade rebuilds. Extract
shared patchFileContentCache helper to unify setQueryData logic between
updateCachedContent and the collaboration event handler.
The backend route /apps/{app_id}/sandbox/files expects the actual app ID
as the URL parameter and derives sandbox_id from the logged-in user
internally. The frontend was incorrectly passing userProfile.id (user ID)
as the appId, resulting in wrong storage paths.
Add useInvalidateSandboxFiles hook and call it alongside
fetchInspectVars/invalidAllLastRun so the Artifacts tab refreshes
automatically when a chatflow preview or workflow debug run finishes.
Move the Divider into the OnlineUsers component so it conditionally
renders together with the online users content, preventing an orphaned
divider from appearing next to the preview button.
Follow-up to SSR prefetch migration (2833965). Eliminates the Zustand
middleman that was syncing TanStack Query data into a separate store.
- Remove useGlobalPublicStore Zustand store entirely
- Create hooks/use-global-public.ts with useSystemFeatures,
useSystemFeaturesQuery, useIsSystemFeaturesPending, useSetupStatusQuery
- Migrate all 93 consumers to import from @/hooks/use-global-public
- Simplify global-public-context.tsx to a thin provider component
- Update 18 test files to mock the new hook interface
- Fix SetupStatusResponse.setup_at type from Date to string (JSON)
- Fix setup-status.spec.ts mock target to match consoleClient
BREAKING CHANGE: useGlobalPublicStore is removed. Use useSystemFeatures()
from @/hooks/use-global-public instead.
BREAKING CHANGE: commonLayout is now an async Server Component that
prefetches user-profile and current-workspace on the server via
TanStack Query's prefetchQuery + HydrationBoundary pattern. This
replaces the previous purely client-side data fetching approach.
Key changes:
- **SSR data prefetch (root layout)**: prefetch systemFeatures and
setupStatus in the root layout server component, wrap children with
HydrationBoundary to hydrate TanStack Query cache on the client.
- **SSR data prefetch (commonLayout)**: convert commonLayout from a
client component to an async server component that prefetches
user-profile (with x-version/x-env response headers) and
current-workspace. Client-side providers/UI extracted to a new
layout-client.tsx component.
- **Add loading.tsx (Next.js convention)**: add a Next.js loading.tsx
file in commonLayout that shows a centered spinner. This replaces the
deleted Splash component but works via Next.js built-in Suspense
boundary for route segments, not a client-side overlay.
- **Extract shared SSR fetch utilities (utils/ssr-fetch.ts)**: create
serverFetch (unauthenticated) and serverFetchWithAuth (with cookie
forwarding + CSRF token). getAuthHeaders is wrapped with React.cache()
for per-request deduplication across multiple SSR fetches.
- **Refactor AppInitializer**: split single monolithic async IIFE effect
into three independent useEffects (oauth tracking, education verify,
setup status check). Use useReducer for init flag, useRef to prevent
duplicate tracking in StrictMode. Now reads setupStatus from TanStack
Query cache (useSetupStatusQuery) instead of fetching independently.
- **Refactor global-public-context**: move Zustand store sync from
queryFn side-effect to a dedicated useEffect, keeping queryFn pure.
fetchSystemFeatures now simply returns the API response.
- **Fix usePSInfo SSR crash**: defer globalThis.location access from
hook top-level to callback execution time via getDomain() helper,
preventing "Cannot read properties of undefined" during server render.
- **Remove Splash component**: delete the client-side loading overlay
that relied on useIsLogin polling, replaced by Next.js loading.tsx.
- **Remove staleTime/gcTime overrides in useUserProfile**: allow the
SSR-prefetched data to be reused via default cache policy instead of
forcing refetch on every mount.
- **Revert middleware auth guard**: remove the cookie-based session
check in proxy.ts that caused false redirects to /signin for
authenticated users (Dify's auth uses token refresh, not simple
cookie presence).
Replace direct localStorage.getItem/setItem/removeItem with the
centralized storage module which provides versioned keys, automatic
JSON serialization, SSR safety, and error handling.
Add import skill modal that accepts .zip files via drag-and-drop or
file picker, extracts them client-side using fflate, validates structure
and security constraints, then batch uploads via presigned URLs.
- Add fflate dependency for browser-side ZIP decompression
- Create zip-extract.ts with fflate filter API for validation
- Create zip-to-upload-tree.ts for BatchUploadNodeInput tree building
- Create import-skill-modal.tsx with drag-and-drop support
- Lazy-load ImportSkillModal via next/dynamic for bundle optimization
- Add en-US and zh-Hans i18n keys for import modal
Drop CategoryTabs component, SkillTemplateTag type, icon/tags fields,
and UI_CONFIG from the fetch script. Upload folders now use the
kebab-case skill id (e.g. "skill-creator") instead of the display name.
Card shows the human-readable name from SKILL.md frontmatter while the
created folder uses the id for consistent naming.
Expose initialFocus prop on Modal component (passthrough to Headless
UI Dialog) so the create blank skill modal reliably focuses the name
input when opened, replacing the ineffective autoFocus attribute.
Wire up the "Create Blank Skill" action card to open a modal where
users enter a skill name. The modal validates against existing skill
names in real-time and creates a folder with a SKILL.md file via
batchUpload, then opens the file as a pinned tab.
Add useExistingSkillNames hook that derives root folder names from the
cached asset tree via TanStack Query select, then use it to show an
"Added" state on hover for already-present skills and block re-upload.
Pass disabled/loading props to TemplateCard declaratively from
loadingId state. All cards are disabled while any upload is in
progress, and the active card shows a loading spinner. Remove the
imperative pointer-events overlay in favor of native button disabled.
Replace custom search input with SearchInput component (built-in clear
button) and add 300ms debounce. Fix template card: use Tailwind token
for icon background, fix Badge to use children with badge-s class and
uppercase, match empty-tag fallback height to badge size.
Remove unused categories (Search, Security, Analysis) and add
real ones (Document, Design, Creative). Consolidate xlsx tags to
Document/Productivity and webapp-testing to Development only,
eliminating orphan tags with single-skill coverage.
Use useRef for batchUpload and emitTreeUpdate to remove unstable
dependencies from useCallback, preventing unnecessary memo invalidation
on all 16 TemplateCard components. Wrap filtered list in useMemo and
replace && conditional with ternary for rendering safety.
Add fetch-skill-templates.ts script that clones anthropics/skills repo
and generates complete directory trees (scripts, references, assets)
for all 16 skills with base64 encoding for binary files, replacing
the previous single-SKILL.md-only approach. Generated files are
lazy-loaded per skill on user click.
Introduce type definitions separating raw skill data (SkillTemplate)
from UI metadata (SkillTemplateWithMetadata) to match the actual
skill format from upstream repos. Add template card component with
hover state and file count display, template-to-upload conversion
utility, and i18n keys for en-US/zh-Hans.
Only enable the tool query matching the node's provider_type instead of
all four, and use primitive useMemo dependencies instead of the whole
data object to avoid redundant recomputations on every render.
Add `enabled` parameter to tool query hooks so non-plugin nodes
(LLM, Code, IfElse, etc.) avoid registering React Query observers.
Extract shared matching functions into plugin-install-check utils to
eliminate duplicate logic between the hook and the checklist.
Replace useEffect-based state sync (_pluginInstallLocked/_dimmed) with
render-time derived computation in BaseNode, breaking the cycle of
effect → node data update → re-render → effect. Extract plugin missing
check into a pure utility function for checklist reuse.
Migrate all icon usage in the skill directory from @remixicon/react
and custom SVG components to Tailwind CSS icon classes (i-ri-*, i-custom-*).
Update MenuItem API to accept string class names instead of React.ElementType.
Hardcoded colors (#354052, #676F83, #98A2B3, #155EEF, white) prevent
the Iconify parseColors callback from converting them to currentColor,
causing the icons to render as background-image instead of mask-image
and making text-* color utilities ineffective.
The toolbar download button now uses the already-fetched download URL
from useQuery (zero extra requests), while tree node downloads keep
using useMutation with React Query-managed isPending state instead of
a hand-rolled useState wrapper.
Introduce a dedicated Zustand ArtifactSlice to manage artifact selection
state with mutual exclusion against the main file tree. Artifact files
from the sandbox can now be opened as tabs in the skill editor, rendered
via a lightweight ArtifactContentPanel that reuses ReadOnlyFilePreview.
Backend returns extensions with a leading dot (e.g., `.png` from
`os.path.splitext`), causing binary/media files to be misclassified
as text since they didn't match the dot-free extension lists.
Implement ReadOnlyFilePreview to render sandbox files by type
(code, markdown, image, video, SQLite, unsupported) using existing
skill viewer components with readOnly support. Add
useSandboxFileDownloadUrl and useFetchTextContent hooks for data
fetching, and generalize useFileTypeInfo to accept any file-like
object.
Extract shared empty state card into ArtifactsEmpty component to
deduplicate the no-files and no-selection empty states. Align the
split-panel right-side empty state with the variables tab pattern.
Remove FC type annotations in favor of inline parameter types.
Mark the empty state SearchLinesSparkle icon as aria-hidden for screen
readers. Replace array-index keys with cumulative path keys (O(n) vs
O(n²)) to satisfy react/no-array-index-key and improve key stability.
Replace the minimal centered text card in artifacts tab empty state with
a full-height card layout matching the variables tab, including icon
container (SearchLinesSparkle), title, description, and learn more link.
Replace useClickAway + fixed positioning in file tree context menu with
a floating-ui based hook that provides collision detection (flip/shift),
ARIA role="menu", Escape/outside-click dismiss, and scroll dismiss via
passive capture listener with ref-stabilized callback.
Replaces window.open with the downloadUrl helper from utils/download.ts
to trigger proper browser download behavior via <a download> instead of
opening a new tab that may display garbled content.
Features:
- Add refresh button to clear test run history (data, inputs, node highlights)
- Persist workflowRunningData when closing panel (from previous commit)
Code quality improvements:
- Refactor to declarative pattern: effectiveTab derived from state, not set in effects
- Replace && with ternary operators for conditional rendering (Vercel best practices)
- Fix created_by type: change from string to object to match backend API
- Remove `as any` type assertion, use proper type-safe access
- Title now declaratively shows status based on workflowRunningData presence
Files changed:
- use-workflow-interactions.ts: add handleClearWorkflowRunHistory hook
- workflow-preview.tsx: declarative tab state, clear button, type-safe props
- types.ts: fix created_by type definition
- test files: update mock data to match corrected types
Position the clear button relative to the right divider instead of
following the tab labels, ensuring consistent positioning across
different language translations. Also fix tab switching jitter by
setting a fixed header height.
Use shared object reference instead of separate variables to track
upload progress across concurrent Promise.all operations, preventing
progress bar from showing incorrect or regressing values.
Introduce prepareSkillUploadFile utility that wraps markdown file content
in a JSON payload format before uploading. This ensures consistent handling
of skill files across file upload, folder upload, and drag-and-drop operations.
Replace simple uploading/success indicator with a full three-state
tooltip (uploading, success, partial_error) that overlays the DropTip
position. Add upload slice to skill editor store and wire progress
tracking into file/folder upload operations.
- add SplitPanel to share left/right shell and narrow menu handling
- reuse InspectHeaderProps for tab header + actions across tabs
- refactor variables/artifacts tabs to plug into shared split layout
- align right-side header/close behavior and consolidate empty/loading flows
Consolidate duplicated TabHeader + close button layout (8 occurrences) into a single
InspectLayout wrapper. Replace boolean props with children slots for better composition.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhance getFileIconType to accept an extension parameter and cover all
13 FileAppearanceTypeEnum types using an O(1) Map lookup. Update all
call sites to pass the API-provided extension for accurate icon display.
Refactor the variable inspect panel into a tabbed layout with Variables
and Artifacts tabs. Extract variable logic into VariablesTab, add new
ArtifactsTab with sandbox file tree selection and preview pane, and
improve accessibility across tree nodes and interactive elements.
Use useRef to store saveFile reference and remove it from useEffect
dependencies to prevent cleanup from re-triggering on reference changes.
Also normalize metadata before comparison when clearing dirty state to
ensure filtered tools match correctly.
Simpler approach: disable the view picker toggle when preview is running,
preventing users from switching views during active runs.
This replaces the previous mounted ref guard approach (commits a0188bd9b5,
b7f1eb9b7b, 8332f0de2b) which added complexity to handle post-unmount
operations. Disabling the toggle is more direct and follows KISS principle.
Changes:
- Add disabled prop to ViewPicker based on isResponding state
- Revert mounted ref guards in use-chat-flow-control.ts
- Revert isMountedRef parameter in use-nodes/edges-interactions-without-sync.ts
- Revert defensive type check in markdown-utils.ts (no longer needed)
In React StrictMode (dev mode), effects are run twice to help detect
side effects. The cleanup-only pattern left isMountedRef as false after
StrictMode's simulated unmount-remount cycle, causing stop/cancel
operations to be skipped even when the component was mounted.
Now the effect setup explicitly sets isMountedRef.current = true,
ensuring correct behavior in both development and production.
Related to a9c5201485 - when switching views during active preview run,
the markdown preprocessors could receive non-string content (e.g., frozen
arrays from immer). Returning the original value caused ReactMarkdown to
fail with "Cannot assign to read only property" error.
Now both preprocessLaTeX and preprocessThinkTag return '' for non-string
input, preventing runtime errors during view switches.
When switching from graph view to skill view during an active preview run,
SSE callbacks continue executing and attempt to update ReactFlow node/edge
states. This could cause errors since the component is unmounted.
Add optional `isMountedRef` parameter to `useNodesInteractionsWithoutSync`
and `useEdgesInteractionsWithoutSync` hooks. When provided, operations are
skipped if the component has unmounted, preventing potential errors while
allowing the SSE connection to continue running in the background.
BREAKING CHANGE: `useNodesInteractionsWithoutSync` and
`useEdgesInteractionsWithoutSync` now accept an optional `isMountedRef`
parameter. Existing callers are unaffected as the parameter is optional.
The sidebar layout was broken when ArtifactsSection expanded - it would
squeeze the FileTree and neither area could scroll. This restructures the
layout so each section has its own scroll container with proper height
constraints.
Remove enabled condition so data is fetched when component mounts,
allowing blue dot to show when files exist even before expanding.
TanStack Query handles request deduplication automatically.
- Replace placeholder with functional ArtifactsSection component
- Add ArtifactsTree component for file tree rendering
- Support expand/collapse with lazy loading
- Show blue dot indicator when collapsed with files
- Add empty state card with hint text
- Add download button on file hover
- Add i18n translations (en-US, zh-Hans)
Cover Ctrl+S and Cmd+S save triggers, guard clauses for start tab and
null active tab, success/error toast notifications, and fallback
registry integration.
Move global keyboard shortcut handling from component-level hook to
SkillSaveProvider, eliminating duplicate event listener registrations
and race conditions. Delete use-skill-file-save hook as its logic is
now consolidated in the provider with direct store access.
- use cleanup-based save on tab switch with stable fallback snapshots
- add fallback registry for metadata-only autosave consistency
- add autosave/save-manager tests
Centralize file save operations using Context/Provider pattern for better
maintainability. Add auto-save on tab switch, visibility change, page unload,
and component unmount.
Refactor StartTabContent into separate components following Figma design specs:
- ActionCard: reusable card with icon, title, description
- SectionHeader: title/xl-semi-bold header with description
- CreateImportSection: 3-column grid layout for Create/Import cards
- SkillTemplatesSection: templates area with placeholder
Align styles with Figma: 3-col grid, 16px title, proper spacing and padding.
Add i18n translations for all user-facing text (en-US, zh-Hans).