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.
- Updated API routes to use app_id instead of sandbox_id for file operations, aligning with user-specific sandbox workspaces.
- Enhanced SandboxFileService and related classes to accommodate app_id in file listing and download functionalities.
- Refactored storage key generation for sandbox archives to include app_id, ensuring proper file organization.
- Adjusted frontend contracts and services to reflect the new app_id parameter in API calls.
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.