Files
2026-02-09 12:35:27 +03:00

3.9 KiB

Research: Superset-Style UX Redesign

Feature: 019-superset-ux-redesign Date: 2026-02-09

Research Tasks

1. SvelteKit Layout Patterns for Persistent UI

Decision: Use root +layout.svelte for Sidebar and TaskDrawer

Rationale:

  • SvelteKit's layout components persist across route changes by default
  • Placing Sidebar and TaskDrawer in the root layout ensures they are always available
  • Slot-based composition allows content pages to render in the main area

Alternatives Considered:

  • Per-page imports: Rejected due to code duplication and state management complexity
  • Web Components: Rejected as SvelteKit native layouts are more idiomatic

2. Real-time Task Updates via WebSocket

Decision: Extend existing WebSocket infrastructure for Task Drawer

Rationale:

  • Backend already has WebSocket support in backend/src/app.py
  • TaskManager emits events that can be broadcast to connected clients
  • Existing TaskLogViewer component already subscribes to task updates

Implementation Notes:

  • Create a new store taskDrawer.js that subscribes to WebSocket events
  • Map resource IDs to task IDs using a reactive resourceTaskMap store
  • Activity indicator reads from a derived store counting active tasks

3. Sidebar State Persistence

Decision: Use Svelte stores with localStorage sync

Rationale:

  • User preference for collapsed/expanded sidebar should persist across sessions
  • Svelte's writable stores can be extended with localStorage sync
  • Pattern already used in other parts of the application

Code Pattern:

function persistentStore(key, defaultValue) {
  const stored = localStorage.getItem(key);
  const store = writable(stored ? JSON.parse(stored) : defaultValue);
  store.subscribe(value => localStorage.setItem(key, JSON.stringify(value)));
  return store;
}

4. Resource-to-Task Mapping

Decision: Create a new store resourceTaskMap in taskDrawer.js

Rationale:

  • Need to track which task is associated with which resource (dashboard/dataset)
  • When user clicks a status badge, the drawer opens with the correct task
  • Map structure: { resourceUuid: { taskId, status } }

Alternatives Considered:

  • Backend tracking: Rejected to avoid additional API calls
  • URL-based task ID: Rejected as it doesn't support background tasks

5. Settings Consolidation

Decision: Create a unified Settings page with tabbed navigation

Rationale:

  • Current settings are scattered across multiple pages
  • Tabbed interface allows grouping: Environments, Connections, LLM, Logging, System
  • Existing settings APIs can be consolidated into a single route

Implementation Notes:

  • Reuse existing settings components where possible
  • Add role-based visibility for admin-only tabs
  • Use SvelteKit's nested routes for each settings tab

6. Responsive Sidebar Behavior

Decision: CSS media queries + conditional rendering

Rationale:

  • Desktop (≥1024px): Sidebar visible by default, collapsible
  • Tablet (768-1023px): Sidebar collapsed to icons
  • Mobile (<768px): Sidebar hidden, hamburger menu in top navbar

Implementation Notes:

  • Use Tailwind's responsive prefixes (md:, lg:)
  • Overlay mode on mobile with backdrop click-to-close
  • Store sidebar state in sidebar.js store

Resolved Clarifications

Item Resolution
Animation timing Sidebar: 200ms ease-in-out, Drawer: 150ms slide
Empty states Show illustration + message + CTA button
Breadcrumb depth limit Truncate middle items with ellipsis after 3 levels
Activity badge polling Real-time via WebSocket, no polling needed

Dependencies Confirmed

  • backend/src/core/task_manager: Available for task state
  • backend/src/core/superset_client: Available for resource fetching
  • frontend/src/lib/api.js: requestApi wrapper available
  • frontend/src/lib/i18n: i18n system available