From 874a3788b064f02ea27f38bdcf33c840f6ce635b Mon Sep 17 00:00:00 2001 From: ffalathel Date: Sun, 12 Oct 2025 19:00:30 -0400 Subject: [PATCH 1/2] Add lifecycle documentation for rapid chart creation and technical primer for modal focus feature - Created a detailed lifecycle document for business analysts outlining the rapid chart creation process, including user journey, component architecture, sequence diagrams, and pain points. - Developed a technical primer covering the implementation of the auto-focus feature for the visualization type modal, detailing core technologies, React hooks, TypeScript fundamentals, and accessibility considerations. - Added a comprehensive system overview document detailing the architecture of Apache Superset, including component catalog, technology stack, integration points, and deployment architecture. - Documented various use cases for Apache Superset, highlighting user journeys, roles, capabilities, and key features across different scenarios. --- .../001_lifecycle_explore_to_dashboard.md | 249 ++++++++++ ...fecycle_business_analyst_chart_creation.md | 282 +++++++++++ memory/system/003_technical_primer.md | 444 ++++++++++++++++++ memory/system/system_overview.md | 219 +++++++++ memory/system/use_cases.md | 173 +++++++ superset-frontend/package-lock.json | 5 +- .../VizTypeControl/VizTypeControl.test.tsx | 21 + .../VizTypeControl/VizTypeGallery.tsx | 13 + 8 files changed, 1405 insertions(+), 1 deletion(-) create mode 100644 memory/system/001_lifecycle_explore_to_dashboard.md create mode 100644 memory/system/002_lifecycle_business_analyst_chart_creation.md create mode 100644 memory/system/003_technical_primer.md create mode 100644 memory/system/system_overview.md create mode 100644 memory/system/use_cases.md diff --git a/memory/system/001_lifecycle_explore_to_dashboard.md b/memory/system/001_lifecycle_explore_to_dashboard.md new file mode 100644 index 000000000000..e4c29291e6d9 --- /dev/null +++ b/memory/system/001_lifecycle_explore_to_dashboard.md @@ -0,0 +1,249 @@ +# Explore to Dashboard Creation Lifecycle + +## User Story +As a business analyst, I want to explore data from a dataset, create visualizations, and save them to a dashboard so that I can share insights with stakeholders. + +## Layer 1: User Journey Flow + +```mermaid +flowchart TD + A[User selects dataset] --> B[Explore view loads] + B --> C[Configure chart parameters] + C --> D[Preview visualization] + D --> E[Save chart to dashboard] + E --> F[Dashboard created/updated] + F --> G[Redirect to dashboard view] +``` + +## Layer 2: Component Architecture + +```mermaid +graph TB + subgraph "UI Layer" + A[ExploreViewContainer] + B[SaveModal] + C[ControlPanelsContainer] + D[ExploreChartPanel] + end + + subgraph "State Layer" + E[Redux Store] + F[Chart State] + G[Form Data State] + end + + subgraph "Service Layer" + H[ChartDataRestApi] + I[ChartRestApi] + J[DashboardRestApi] + K[QueryContext] + end + + subgraph "External Layer" + L[Database] + M[Cache Layer] + N[Metadata DB] + end + + A --> E + B --> I + C --> F + D --> H + H --> K + K --> L + I --> N + J --> N + H --> M +``` + +### Component Mapping + +| Component | Implementation | File:Line | +|-----------|---------------|-----------| +| ExploreViewContainer | ExploreViewContainer | `superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:54` | +| SaveModal | SaveModal | `superset-frontend/src/explore/components/SaveModal.tsx:86` | +| ControlPanelsContainer | ConnectedControlPanelsContainer | `superset-frontend/src/explore/components/ControlPanelsContainer/index.jsx` | +| ExploreChartPanel | ExploreChartPanel | `superset-frontend/src/explore/components/ExploreChartPanel/index.jsx` | +| ChartDataRestApi | ChartDataRestApi | `superset/charts/data/api.py:64` | +| ChartRestApi | ChartRestApi | `superset/charts/api.py:107` | +| DashboardRestApi | DashboardRestApi | `superset/dashboards/api.py:161` | +| QueryContext | QueryContext | `superset/common/query_context.py:41` | +| Explore View | Superset.explore | `superset/views/core.py:397` | +| Dashboard Creation | CreateDashboardCommand | `superset/commands/dashboard/create.py:37` | +| Chart Creation | CreateChartCommand | `superset/commands/chart/create.py:42` | + +## Layer 3: Sequence Diagram + +```mermaid +sequenceDiagram + participant U as User + participant EVC as ExploreViewContainer + participant SM as SaveModal + participant CA as ChartActions + participant CRA as ChartRestApi + participant DRA as DashboardRestApi + participant QC as QueryContext + participant DB as Database + participant MD as MetadataDB + + U->>EVC: Navigate to /explore/ + EVC->>CRA: GET /api/v1/explore/ + CRA->>DB: Query datasource metadata + DB-->>CRA: Return schema/columns + CRA-->>EVC: Bootstrap data with form_data + EVC->>U: Render explore interface + + U->>EVC: Configure chart parameters + EVC->>CA: Update form data + CA->>CRA: POST /api/v1/chart/data + CRA->>QC: Create QueryContext + QC->>DB: Execute SQL query + DB-->>QC: Return result set + QC-->>CRA: Process data + CRA-->>EVC: Chart data response + EVC->>U: Display visualization + + U->>SM: Click Save button + SM->>U: Show save modal + U->>SM: Enter chart name, select dashboard + SM->>CA: saveOrOverwrite() + CA->>CRA: POST /api/v1/chart/ + CRA->>MD: Create/update Slice record + MD-->>CRA: Return slice ID + + alt New Dashboard + CA->>DRA: POST /api/v1/dashboard/ + DRA->>MD: Create Dashboard record + MD-->>DRA: Return dashboard ID + end + + CA->>MD: Link slice to dashboard + MD-->>CA: Success + CA->>U: Redirect to dashboard +``` + +### Key Design Patterns + +1. **Command Pattern**: `CreateChartCommand`, `CreateDashboardCommand` encapsulate business logic +2. **Repository Pattern**: `DashboardDAO`, `ChartDAO` abstract data access +3. **Observer Pattern**: Redux state management for UI updates + +## Data Structures + +```typescript +// Chart/Slice data structure +interface Slice { + id: number; + slice_name: string; + datasource_id: number; + datasource_type: string; + viz_type: string; + params: JsonObject; + query_context: string; + owners: User[]; + dashboards: Dashboard[]; +} + +// Dashboard data structure +interface Dashboard { + id: number; + dashboard_title: string; + position_json: string; // Layout configuration + json_metadata: string; // Chart configurations + description?: string; + css?: string; + slug: string; + slices: Slice[]; + owners: User[]; + published: boolean; +} + +// Form data for chart configuration +interface FormData { + datasource: string; // "table__123" + viz_type: string; + metrics: string[]; + groupby: string[]; + filters: Filter[]; + time_range: string; + granularity: string; + // ... many more chart-specific fields +} + +// Query context for data fetching +interface QueryContext { + datasource: BaseDatasource; + queries: QueryObject[]; + form_data: FormData; + result_type: ChartDataResultType; + result_format: ChartDataResultFormat; + force: boolean; + cache_values: Record; +} +``` + +## Quick Reference + +### Event Triggers +- **Chart Creation**: `saveOrOverwrite()` in SaveModal +- **Dashboard Creation**: `CreateDashboardCommand.run()` +- **Data Fetching**: `ChartDataRestApi.data()` endpoint +- **Navigation**: React Router with `/explore/` and `/dashboard/` routes + +### Data Formats +- **Form Data**: JSON object with chart configuration +- **Query Context**: Serialized query parameters +- **Dashboard Layout**: JSON with position and metadata +- **Chart Data**: JSON with columns, data array, and metadata + +### Error Handling +- **Datasource Not Found**: 404 response with fallback +- **Permission Denied**: 403 response for unauthorized access +- **Query Errors**: 400 response with validation messages +- **Database Connection**: Timeout and retry logic + +### Key Endpoints +- `GET /api/v1/explore/` - Bootstrap explore page +- `POST /api/v1/chart/data` - Fetch chart data +- `POST /api/v1/chart/` - Create/update chart +- `POST /api/v1/dashboard/` - Create dashboard +- `GET /superset/dashboard/{id}/` - View dashboard + +## Related Lifecycles + +1. **Dataset Registration Lifecycle** - Connecting to data sources +2. **SQL Lab Query Lifecycle** - Advanced SQL querying workflow +3. **Dashboard Sharing Lifecycle** - Permissions and collaboration +4. **Alert Configuration Lifecycle** - Setting up automated alerts +5. **Dashboard Embedding Lifecycle** - Embedding dashboards in external apps + +## Component Overview + +### Key Components and Services + +| Component | Role | Key Methods | +|-----------|------|-------------| +| **ExploreViewContainer** | Main explore page container | `componentDidMount()`, `render()` | +| **SaveModal** | Chart saving interface | `saveOrOverwrite()`, `loadDashboard()` | +| **ChartDataRestApi** | Data fetching service | `data()`, `data_from_cache()` | +| **QueryContext** | Query execution context | `get_payload()`, `get_data()` | +| **CreateChartCommand** | Chart creation business logic | `run()`, `validate()` | +| **CreateDashboardCommand** | Dashboard creation business logic | `run()`, `validate()` | +| **DashboardDAO** | Dashboard data access | `create()`, `update()`, `find_by_ids()` | +| **Superset.explore** | Explore view controller | `explore()`, `save_or_overwrite_slice()` | + +### State Management +- **Redux Store**: Global application state +- **Chart State**: Current chart configuration and data +- **Form Data**: Chart parameters and filters +- **Dashboard State**: Dashboard layout and metadata +- **User State**: Permissions and preferences + +### Data Flow +1. **Initialization**: Bootstrap data from backend +2. **Configuration**: User modifies form data +3. **Query Execution**: QueryContext processes requests +4. **Data Processing**: Backend processes and returns data +5. **Visualization**: Frontend renders chart +6. **Persistence**: Save chart and dashboard to database +7. **Navigation**: Redirect to dashboard view diff --git a/memory/system/002_lifecycle_business_analyst_chart_creation.md b/memory/system/002_lifecycle_business_analyst_chart_creation.md new file mode 100644 index 000000000000..ec53cbce8507 --- /dev/null +++ b/memory/system/002_lifecycle_business_analyst_chart_creation.md @@ -0,0 +1,282 @@ +# Business Analyst - Rapid Chart Creation Lifecycle + +## User Story +As a business analyst, I want to quickly create multiple charts from a dataset to explore different visualizations and find the best way to present my data insights to stakeholders. + +## Layer 1: User Journey Flow + +```mermaid +flowchart TD + A[Analyst selects dataset] --> B[Explore view loads] + B --> C[Analyst clicks 'View all charts'] + C --> D[Viz Type Modal opens] + D --> E[Analyst types chart name] + E --> F[Analyst selects chart type] + F --> G[Analyst configures parameters] + G --> H[Analyst previews chart] + H --> I{Analyst satisfied?} + I -->|No| J[Analyst changes viz type] + J --> D + I -->|Yes| K[Analyst saves chart] + K --> L[Analyst creates dashboard] + L --> M[Analyst shares insights] +``` + +## Layer 2: Component Architecture + +```mermaid +graph TB + subgraph "UI Layer" + A[ExploreViewContainer] + B[VizTypeControl] + C[VizTypeGallery] + D[SearchInput] + E[ChartPreview] + F[SaveModal] + end + + subgraph "State Layer" + G[Redux Store] + H[Form Data State] + I[Chart State] + J[Modal State] + end + + subgraph "Service Layer" + K[ChartDataRestApi] + L[ChartRestApi] + M[QueryContext] + N[FuseSearch] + end + + subgraph "External Layer" + O[Database] + P[Cache Layer] + Q[Metadata DB] + end + + A --> G + B --> C + C --> D + D --> N + E --> K + K --> M + M --> O + F --> L + L --> Q + K --> P +``` + +### Component Mapping + +| Component | Implementation | File:Line | +|-----------|---------------|-----------| +| ExploreViewContainer | ExploreViewContainer | `superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:54` | +| VizTypeControl | VizTypeControl | `superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:73` | +| VizTypeGallery | VizTypeGallery | `superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:438` | +| SearchInput | Input with Fuse.js | `superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:730` | +| ChartPreview | ExploreChartPanel | `superset-frontend/src/explore/components/ExploreChartPanel/index.jsx` | +| SaveModal | SaveModal | `superset-frontend/src/explore/components/SaveModal.tsx:86` | +| ChartDataRestApi | ChartDataRestApi | `superset/charts/data/api.py:64` | +| QueryContext | QueryContext | `superset/common/query_context.py:41` | +| FuseSearch | Fuse.js integration | `superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:526` | + +## Layer 3: Sequence Diagram + +```mermaid +sequenceDiagram + participant BA as Business Analyst + participant EVC as ExploreViewContainer + participant VTC as VizTypeControl + participant VTG as VizTypeGallery + participant SI as SearchInput + participant FS as FuseSearch + participant CRA as ChartDataRestApi + participant QC as QueryContext + participant DB as Database + + BA->>EVC: Navigate to /explore/ + EVC->>CRA: GET /api/v1/explore/ + CRA->>DB: Query datasource metadata + DB-->>CRA: Return schema/columns + CRA-->>EVC: Bootstrap data + EVC->>BA: Render explore interface + + BA->>VTC: Click "View all charts" + VTC->>VTG: Open modal + VTG->>SI: Render search input + Note over SI: **ISSUE: Search input not focused** + BA->>SI: Click search input (extra step) + SI->>BA: Focus search input + BA->>SI: Type "bar chart" + SI->>FS: Search with Fuse.js + FS-->>SI: Return filtered results + SI->>VTG: Update gallery display + VTG->>BA: Show matching charts + + BA->>VTG: Select chart type + VTG->>EVC: Update viz_type + EVC->>CRA: POST /api/v1/chart/data + CRA->>QC: Create QueryContext + QC->>DB: Execute SQL query + DB-->>QC: Return result set + QC-->>CRA: Process data + CRA-->>EVC: Chart data response + EVC->>BA: Display visualization + + Note over BA: Analyst iterates through multiple chart types + BA->>VTC: Click "View all charts" again + VTC->>VTG: Open modal + Note over SI: **ISSUE: Search input not focused again** + BA->>SI: Click search input (extra step again) + SI->>BA: Focus search input + BA->>SI: Type "line chart" + SI->>FS: Search with Fuse.js + FS-->>SI: Return filtered results + VTG->>BA: Show matching charts + BA->>VTG: Select different chart type + VTG->>EVC: Update viz_type + EVC->>CRA: POST /api/v1/chart/data + CRA-->>EVC: Chart data response + EVC->>BA: Display new visualization +``` + +### Key Design Patterns + +1. **Command Pattern**: `CreateChartCommand` encapsulates chart creation logic +2. **Observer Pattern**: Redux state management for UI updates +3. **Factory Pattern**: `QueryContextFactory` creates query contexts +4. **Search Pattern**: Fuse.js for fuzzy search functionality + +## Data Structures + +```typescript +// Chart configuration data +interface FormData { + viz_type: string; + datasource: string; + metrics: string[]; + groupby: string[]; + filters: Filter[]; + time_range: string; + // ... many more chart-specific fields +} + +// Search functionality +interface SearchState { + searchInputValue: string; + isSearchFocused: boolean; + isActivelySearching: boolean; +} + +// Chart metadata for search +interface ChartMetadata { + name: string; + category: string; + tags: string[]; + description: string; + thumbnail: string; + behaviors: string[]; +} + +// Fuse.js search configuration +interface FuseConfig { + ignoreLocation: boolean; + threshold: number; + keys: Array<{ + name: string; + weight: number; + }>; +} +``` + +## Quick Reference + +### Event Triggers +- **Modal Opening**: `VizTypeControl.openModal()` +- **Search Input Focus**: `VizTypeGallery.focusSearch()` +- **Search Execution**: `VizTypeGallery.changeSearch()` +- **Chart Selection**: `VizTypeGallery.onChange()` +- **Chart Data Fetch**: `ChartDataRestApi.data()` + +### Data Formats +- **Form Data**: JSON object with chart configuration +- **Search Query**: String input from user +- **Search Results**: Array of filtered ChartMetadata objects +- **Chart Data**: JSON with columns, data array, and metadata + +### Error Handling +- **Search Input Not Focused**: User must manually click (current issue) +- **No Search Results**: Show "No charts found" message +- **Chart Creation Errors**: Display validation messages +- **Network Errors**: Show error toast notifications + +### Key Endpoints +- `GET /api/v1/explore/` - Bootstrap explore page +- `POST /api/v1/chart/data` - Fetch chart data +- `POST /api/v1/chart/` - Create/update chart +- `GET /api/v1/dashboard/` - List dashboards + +## Related Lifecycles + +1. **Dataset Selection Lifecycle** - Choosing data source +2. **Chart Configuration Lifecycle** - Setting up chart parameters +3. **Dashboard Creation Lifecycle** - Building comprehensive dashboards +4. **Chart Sharing Lifecycle** - Collaborating with stakeholders +5. **Chart Iteration Lifecycle** - Rapid prototyping + +## Component Overview + +### Key Components and Services + +| Component | Role | Key Methods | +|-----------|------|-------------| +| **VizTypeControl** | Modal management | `openModal()`, `onSubmit()`, `onCancel()` | +| **VizTypeGallery** | Chart selection interface | `focusSearch()`, `changeSearch()`, `stopSearching()` | +| **SearchInput** | Search functionality | `onFocus()`, `onChange()`, `onBlur()` | +| **FuseSearch** | Fuzzy search engine | `search()`, `getResults()` | +| **ChartDataRestApi** | Data fetching | `data()`, `data_from_cache()` | +| **QueryContext** | Query execution | `get_payload()`, `get_data()` | + +### State Management +- **Modal State**: `showModal`, `modalKey`, `selectedViz` +- **Search State**: `searchInputValue`, `isSearchFocused`, `isActivelySearching` +- **Chart State**: Current chart configuration and data +- **Form Data**: Chart parameters and filters + +### Data Flow +1. **Modal Opening**: User clicks "View all charts" +2. **Search Input**: **ISSUE: Input not auto-focused** +3. **Search Execution**: User types and Fuse.js filters results +4. **Chart Selection**: User selects chart type +5. **Data Fetching**: QueryContext processes request +6. **Visualization**: Frontend renders chart +7. **Iteration**: Analyst repeats for different chart types + +## Business Impact Analysis + +### Current Pain Points +- **Extra Click Required**: Analyst must click search input before typing +- **Workflow Interruption**: Breaks the flow of rapid chart creation +- **Cognitive Load**: Analyst must remember to click search input +- **Efficiency Loss**: ~2-3 seconds per chart type change + +### User Experience Issues +- **Inconsistent Behavior**: Modal opens but search not ready +- **Accessibility Barrier**: Screen readers don't get immediate focus +- **Mobile Impact**: Extra tap required on touch devices +- **Power User Frustration**: Violates keyboard navigation expectations + +### Expected Behavior +- **Immediate Focus**: Search input should be focused when modal opens +- **Keyboard Ready**: User can start typing immediately +- **Consistent UX**: Follows modern modal interaction patterns +- **Accessibility Compliant**: Screen readers get immediate focus + +### Frequency Analysis +- **High Frequency**: Business analysts change chart types 5-10 times per session +- **Daily Impact**: Affects every chart creation workflow +- **Cumulative Time**: 10-30 seconds lost per session +- **User Satisfaction**: Creates frustration and feels unpolished + +This lifecycle analysis shows that the search input focus issue significantly impacts the business analyst workflow, which is one of the most common and important use cases in Superset. The fix would improve productivity, user satisfaction, and accessibility compliance. diff --git a/memory/system/003_technical_primer.md b/memory/system/003_technical_primer.md new file mode 100644 index 000000000000..23ab9696840c --- /dev/null +++ b/memory/system/003_technical_primer.md @@ -0,0 +1,444 @@ +# Technical Primer: Visualization Type Modal Focus Feature + +## Overview +This primer covers the essential technologies, concepts, and libraries needed to implement the auto-focus feature for the "Change Visualization Type" modal in Apache Superset. + +## Core Technologies + +### 1. React Hooks & State Management + +#### **useEffect Hook** +```typescript +// Auto-focus search input when modal opens +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, []); // Empty dependency array = run once on mount +``` + +**Key Concepts:** +- **Dependency Array**: `[]` means run once on mount +- **Cleanup**: Return function for cleanup if needed +- **Timing**: Runs after DOM is updated + +#### **useRef Hook** +```typescript +const searchInputRef = useRef(); + +// In JSX + +``` + +**Key Concepts:** +- **Direct DOM Access**: Bypass React's virtual DOM +- **Mutable Object**: `.current` property can be changed +- **Type Safety**: TypeScript generics for input elements + +#### **useState Hook** +```typescript +const [isSearchFocused, setIsSearchFocused] = useState(true); +const [searchInputValue, setSearchInputValue] = useState(''); +``` + +**Key Concepts:** +- **State Updates**: Trigger re-renders +- **Functional Updates**: `setState(prev => prev + 1)` +- **Object State**: Use spread operator for updates + +### 2. TypeScript Fundamentals + +#### **Interface Definitions** +```typescript +interface VizTypeGalleryProps { + onChange: (vizType: string | null) => void; + onDoubleClick: () => void; + selectedViz: string | null; + className?: string; + denyList: string[]; +} +``` + +**Key Concepts:** +- **Optional Properties**: `?` makes properties optional +- **Function Types**: `() => void` for callbacks +- **Union Types**: `string | null` for nullable values + +#### **Type Assertions** +```typescript +// Cast required because emotion +ref={searchInputRef as any} +``` + +**Key Concepts:** +- **Type Casting**: `as any` bypasses type checking +- **Emotion CSS**: Styled components need special handling +- **Ref Types**: HTMLInputElement for input refs + +### 3. React Component Patterns + +#### **Functional Components** +```typescript +export default function VizTypeGallery(props: VizTypeGalleryProps) { + // Component logic here + return
JSX content
; +} +``` + +**Key Concepts:** +- **Props Destructuring**: `{ onChange, onDoubleClick } = props` +- **Default Props**: `onChange = noOp` for optional callbacks +- **Return JSX**: Single root element or fragment + +#### **Event Handlers** +```typescript +const changeSearch: ChangeEventHandler = useCallback( + event => setSearchInputValue(event.target.value), + [] +); +``` + +**Key Concepts:** +- **Event Types**: `ChangeEventHandler` +- **useCallback**: Memoize functions to prevent re-renders +- **Dependency Arrays**: Empty `[]` for stable references + +### 4. CSS-in-JS with Emotion + +#### **Styled Components** +```typescript +const SearchWrapper = styled.div` + ${({ theme }) => ` + grid-area: search; + margin-top: ${theme.gridUnit * 3}px; + margin-bottom: ${theme.gridUnit}px; + `} +`; +``` + +**Key Concepts:** +- **Template Literals**: Backticks for CSS strings +- **Theme Access**: `({ theme }) => theme.colors.primary` +- **Grid Layout**: CSS Grid for complex layouts + +#### **CSS Props** +```typescript +const InputIconAlignment = styled.div` + display: flex; + justify-content: center; + align-items: center; + color: ${({ theme }) => theme.colors.grayscale.base}; +`; +``` + +**Key Concepts:** +- **Flexbox**: Modern layout system +- **Theme Variables**: Consistent spacing and colors +- **Responsive Design**: Mobile-first approach + +### 5. Search Functionality + +#### **Fuse.js Integration** +```typescript +const fuse = useMemo( + () => + new Fuse(chartMetadata, { + ignoreLocation: true, + threshold: 0.3, + keys: [ + { name: 'value.name', weight: 4 }, + { name: 'value.tags', weight: 2 }, + 'value.description', + ], + }), + [chartMetadata] +); +``` + +**Key Concepts:** +- **Fuzzy Search**: Approximate string matching +- **Weighted Keys**: Different importance for search fields +- **Threshold**: Sensitivity of search (0.3 = 30% match) +- **useMemo**: Cache expensive computations + +#### **Search Results Processing** +```typescript +const searchResults = useMemo(() => { + if (searchInputValue.trim() === '') { + return []; + } + return fuse + .search(searchInputValue) + .map(result => result.item) + .sort((a, b) => { + // Custom sorting logic + return bOrder - aOrder; + }); +}, [searchInputValue, fuse]); +``` + +**Key Concepts:** +- **Conditional Logic**: Early return for empty search +- **Array Methods**: `.map()`, `.sort()` for data transformation +- **Dependency Arrays**: Re-compute when search input changes + +### 6. Modal Management + +#### **Modal State** +```typescript +const [showModal, setShowModal] = useState(!!isModalOpenInit); +const [modalKey, setModalKey] = useState(0); + +const openModal = useCallback(() => { + setShowModal(true); +}, []); +``` + +**Key Concepts:** +- **Boolean State**: `showModal` controls visibility +- **Key Prop**: Forces component re-initialization +- **useCallback**: Memoize event handlers + +#### **Modal Lifecycle** +```typescript +const onCancel = useCallback(() => { + setShowModal(false); + setModalKey(key => key + 1); + setSelectedViz(initialValue); +}, [initialValue]); +``` + +**Key Concepts:** +- **State Reset**: Return to initial values +- **Key Increment**: Force re-render of child components +- **Dependency Arrays**: Include all used variables + +### 7. Redux State Management + +#### **State Structure** +```typescript +interface RootState { + explore: { + form_data: FormData; + slice: Slice | null; + datasource: Datasource | null; + }; + charts: { + [key: string]: ChartState; + }; +} +``` + +**Key Concepts:** +- **Normalized State**: Flat structure for performance +- **Immutable Updates**: Use spread operator +- **Type Safety**: TypeScript interfaces for state + +#### **Action Dispatching** +```typescript +const dispatch = useDispatch(); +const formData = useSelector((state: RootState) => state.explore.form_data); + +// Dispatch action +dispatch(updateFormData({ viz_type: 'bar_chart' })); +``` + +**Key Concepts:** +- **useSelector**: Extract state from store +- **useDispatch**: Get dispatch function +- **Action Creators**: Functions that return action objects + +### 8. Testing Concepts + +#### **React Testing Library** +```typescript +it('Auto-focuses search input when modal opens', async () => { + await waitForRenderWrapper(); + + // Open the modal + userEvent.click(screen.getByText('View all charts')); + + // Wait for the modal to open and the search input to be rendered + const searchInput = await screen.findByTestId(getTestId('search-input')); + + // Check that the search input is focused + expect(searchInput).toHaveFocus(); +}); +``` + +**Key Concepts:** +- **Async Testing**: `await` for DOM updates +- **User Events**: `userEvent.click()` simulates user interaction +- **Focus Testing**: `.toHaveFocus()` matcher +- **Test IDs**: `data-test` attributes for reliable selectors + +#### **Jest Matchers** +```typescript +expect(searchInput).toHaveFocus(); +expect(modal).toBeInTheDocument(); +expect(results).toHaveLength(3); +``` + +**Key Concepts:** +- **Custom Matchers**: `.toHaveFocus()` for accessibility +- **Document Queries**: `.toBeInTheDocument()` +- **Array Length**: `.toHaveLength()` for collections + +### 9. Accessibility (a11y) + +#### **Focus Management** +```typescript +// Auto-focus search input +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, []); +``` + +**Key Concepts:** +- **Keyboard Navigation**: Focus management for keyboard users +- **Screen Readers**: Focus indicates active element +- **Tab Order**: Logical focus sequence + +#### **ARIA Attributes** +```typescript + +``` + +**Key Concepts:** +- **aria-label**: Descriptive text for screen readers +- **placeholder**: Hint text for input purpose +- **data-test**: Testing and debugging attributes + +### 10. Performance Optimization + +#### **useMemo for Expensive Calculations** +```typescript +const searchResults = useMemo(() => { + // Expensive search operation + return fuse.search(searchInputValue).map(result => result.item); +}, [searchInputValue, fuse]); +``` + +**Key Concepts:** +- **Memoization**: Cache expensive computations +- **Dependency Arrays**: Re-compute when dependencies change +- **Performance**: Prevent unnecessary re-renders + +#### **useCallback for Event Handlers** +```typescript +const changeSearch = useCallback( + event => setSearchInputValue(event.target.value), + [] +); +``` + +**Key Concepts:** +- **Stable References**: Prevent child re-renders +- **Event Handlers**: Memoize functions passed as props +- **Dependency Arrays**: Empty for stable references + +## Implementation Checklist + +### 1. **Add useEffect Hook** +```typescript +// Auto-focus the search input when the modal opens +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, []); +``` + +### 2. **Update Tests** +```typescript +it('Auto-focuses search input when modal opens', async () => { + // Test implementation +}); +``` + +### 3. **Verify Accessibility** +- Screen readers get immediate focus +- Keyboard navigation works +- Focus indicators are visible + +### 4. **Test Edge Cases** +- Modal opens multiple times +- Search input is already focused +- Component unmounts before focus + +## Common Pitfalls + +### 1. **Timing Issues** +```typescript +// ❌ Wrong - ref might not be ready +useEffect(() => { + searchInputRef.current?.focus(); +}, []); + +// ✅ Correct - check if ref exists +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, []); +``` + +### 2. **Dependency Arrays** +```typescript +// ❌ Wrong - missing dependencies +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, [searchInputRef]); // Unnecessary dependency + +// ✅ Correct - empty array for mount-only effect +useEffect(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } +}, []); +``` + +### 3. **Type Safety** +```typescript +// ❌ Wrong - any type +const searchInputRef = useRef(); + +// ✅ Correct - specific type +const searchInputRef = useRef(); +``` + +## Debugging Tips + +### 1. **Console Logging** +```typescript +useEffect(() => { + console.log('Modal opened, focusing search input'); + if (searchInputRef.current) { + searchInputRef.current.focus(); + console.log('Search input focused'); + } else { + console.log('Search input ref not ready'); + } +}, []); +``` + +### 2. **React DevTools** +- Check component state +- Verify ref values +- Monitor re-renders + +### 3. **Browser DevTools** +- Inspect DOM elements +- Check focus states +- Test keyboard navigation + +This primer provides all the essential knowledge needed to implement the auto-focus feature for the visualization type modal in Apache Superset. diff --git a/memory/system/system_overview.md b/memory/system/system_overview.md new file mode 100644 index 000000000000..8cd15fb205a7 --- /dev/null +++ b/memory/system/system_overview.md @@ -0,0 +1,219 @@ +# Apache Superset System Architecture + +## System Overview Diagram + +```mermaid +graph TB + subgraph "Frontend Layer" + A[React SPA
TypeScript + Redux] + B[Webpack Dev Server
Node.js] + C[WebSocket Service
Node.js] + end + + subgraph "Backend Layer" + D[Flask Application
Python + Flask-AppBuilder] + E[Celery Workers
Python + Celery] + F[Query Engine
SQLAlchemy + Pandas] + end + + subgraph "Data Layer" + G[Metadata Database
PostgreSQL/MySQL] + H[Cache Layer
Redis] + I[External Databases
Snowflake, BigQuery, etc.] + end + + subgraph "Infrastructure" + J[Nginx
Reverse Proxy] + K[Docker Containers
Orchestration] + end + + A -->|HTTP/JSON| D + A -->|WebSocket| C + C -->|Redis Pub/Sub| H + D -->|SQL| G + D -->|Cache| H + D -->|Async Tasks| E + E -->|SQL| I + E -->|Cache| H + F -->|SQL| I + F -->|Data Processing| D + J -->|Load Balance| D + K -->|Orchestrate| A + K -->|Orchestrate| D + K -->|Orchestrate| E + K -->|Orchestrate| G + K -->|Orchestrate| H +``` + +## Component Catalog + +| Component Name | Technology/Framework | Primary Responsibility | Key Files | Heavy Logic | +|----------------|----------------------|------------------------|-----------|-------------| +| **React SPA** | React + TypeScript + Redux Toolkit | Frontend UI and state management | `superset-frontend/src/views/App.tsx`, `superset-frontend/src/views/store.ts` | Complex dashboard layouts, chart rendering, real-time updates | +| **Flask Application** | Python + Flask + Flask-AppBuilder | REST API, authentication, business logic | `superset/initialization/__init__.py`, `superset/views/core.py` | User management, permissions, data access control | +| **Query Engine** | SQLAlchemy + Pandas + NumPy | SQL query execution and data processing | `superset/common/query_context.py`, `superset/common/query_actions.py` | Query optimization, data transformation, caching | +| **Celery Workers** | Python + Celery + Redis | Background task processing | `superset/tasks/async_queries.py`, `superset/tasks/celery_app.py` | Async queries, report generation, alerts | +| **WebSocket Service** | Node.js + Socket.io | Real-time communication | `superset-websocket/src/` | Live query updates, collaborative editing | +| **Metadata Database** | PostgreSQL/MySQL + SQLAlchemy ORM | Application data persistence | `superset/models/core.py`, `superset/models/slice.py` | User data, charts, dashboards, permissions | +| **Cache Layer** | Redis + Flask-Caching | Query result caching and session storage | `superset/extensions/__init__.py` | Query result caching, session management | +| **Database Connectors** | SQLAlchemy + Custom Engines | External database connectivity | `superset/db_engine_specs/`, `superset/connectors/` | Database-specific query optimization | +| **Security Manager** | Flask-AppBuilder + Custom RBAC | Authentication and authorization | `superset/security/manager.py` | Role-based access control, data source permissions | +| **Command Layer** | Python + Command Pattern | Business logic encapsulation | `superset/commands/` | Chart creation, dashboard management, data operations | + +## Technology Stack + +### UI Layer +- **React 18** - Component framework +- **TypeScript** - Type safety +- **Redux Toolkit** - State management +- **Ant Design** - UI components +- **D3.js** - Data visualization +- **Webpack** - Module bundling + +### State/Logic Layer +- **Redux Store** - Global state management +- **RTK Query** - API state management +- **React Router** - Client-side routing +- **Context API** - Component state sharing + +### Service/API Layer +- **Flask** - Web framework +- **Flask-AppBuilder** - Admin interface +- **Marshmallow** - Serialization +- **SQLAlchemy** - ORM +- **Celery** - Task queue +- **Redis** - Message broker + +### Data Layer +- **PostgreSQL/MySQL** - Metadata database +- **Redis** - Caching and sessions +- **SQLAlchemy** - Database abstraction +- **Pandas** - Data processing +- **NumPy** - Numerical computing + +### External Dependencies +- **External Databases** - Snowflake, BigQuery, Redshift, etc. +- **Mapbox** - Geospatial visualizations +- **OAuth Providers** - Authentication +- **Email Services** - SMTP for alerts +- **Slack API** - Notifications + +## Integration Points + +### Frontend ↔ Backend +- **Protocol**: HTTP/HTTPS +- **Data Format**: JSON +- **Sync**: Request/Response +- **Authentication**: JWT tokens, session cookies + +### Backend ↔ Database +- **Protocol**: SQL over TCP +- **Data Format**: Binary SQL protocol +- **Sync**: Synchronous queries +- **Connection Pooling**: SQLAlchemy engine + +### Backend ↔ Cache +- **Protocol**: Redis protocol +- **Data Format**: Serialized objects +- **Sync**: Synchronous operations +- **Persistence**: Optional persistence + +### Backend ↔ External Databases +- **Protocol**: Database-specific (JDBC, ODBC, etc.) +- **Data Format**: SQL queries and result sets +- **Sync**: Synchronous queries +- **Connection Management**: Per-database engines + +### Workers ↔ Backend +- **Protocol**: Redis message queue +- **Data Format**: Serialized task data +- **Sync**: Asynchronous +- **Task Distribution**: Celery beat scheduler + +### WebSocket ↔ Frontend +- **Protocol**: WebSocket over HTTP +- **Data Format**: JSON messages +- **Sync**: Real-time bidirectional +- **Connection Management**: Socket.io + +## Where to Start + +### To understand user interactions, read: +- **Explore to Dashboard Lifecycle** (`001_lifecycle_explore_to_dashboard.md`) +- **Dashboard Creation Flow** - How users create and manage dashboards +- **SQL Lab Workflow** - Advanced querying capabilities + +### To understand data flow, start with: +- **QueryContext** (`superset/common/query_context.py`) - Central query processing +- **ChartDataRestApi** (`superset/charts/data/api.py`) - Data fetching endpoints +- **Database Models** (`superset/models/core.py`) - Data persistence layer + +### To understand business logic, start with: +- **Command Layer** (`superset/commands/`) - Business logic encapsulation +- **Security Manager** (`superset/security/manager.py`) - Access control +- **Flask Views** (`superset/views/core.py`) - Request handling + +### To understand frontend architecture, start with: +- **App Component** (`superset-frontend/src/views/App.tsx`) - Main application +- **Redux Store** (`superset-frontend/src/views/store.ts`) - State management +- **Route Configuration** (`superset-frontend/src/views/routes.tsx`) - Navigation + +## Key Architectural Patterns + +### 1. **Layered Architecture** +- Clear separation between UI, business logic, and data layers +- Each layer has specific responsibilities and interfaces + +### 2. **Command Pattern** +- Business logic encapsulated in command classes +- Enables transaction management and validation +- Examples: `CreateChartCommand`, `CreateDashboardCommand` + +### 3. **Repository Pattern** +- Data access abstracted through DAO classes +- Enables testing and database abstraction +- Examples: `DashboardDAO`, `ChartDAO` + +### 4. **Observer Pattern** +- Redux state management for UI updates +- Event-driven architecture for real-time features + +### 5. **Factory Pattern** +- Database engine specifications for different databases +- Query context factories for different data sources + +## Deployment Architecture + +### Development (Docker Compose) +- All services in separate containers +- Volume mounts for live code reloading +- Redis and PostgreSQL for data persistence + +### Production +- **Load Balancer**: Nginx or cloud load balancer +- **Application Servers**: Multiple Flask instances +- **Background Workers**: Celery workers on separate machines +- **Database**: Managed PostgreSQL/MySQL +- **Cache**: Managed Redis cluster +- **External Databases**: Cloud data warehouses + +## Performance Considerations + +### Caching Strategy +- **Query Results**: Cached in Redis with TTL +- **Metadata**: Database connection pooling +- **Static Assets**: CDN for frontend assets + +### Scalability +- **Horizontal Scaling**: Multiple Flask workers +- **Database Sharding**: Not implemented (single metadata DB) +- **Async Processing**: Celery for long-running tasks +- **Connection Pooling**: SQLAlchemy engine management + +### Security +- **Authentication**: Flask-AppBuilder with multiple providers +- **Authorization**: Role-based access control (RBAC) +- **Data Access**: Row-level security (RLS) support +- **API Security**: CSRF protection, input validation + +This architecture supports Superset's core mission of providing a modern, scalable business intelligence platform that can handle diverse data sources and user requirements while maintaining security and performance. diff --git a/memory/system/use_cases.md b/memory/system/use_cases.md new file mode 100644 index 000000000000..27e05e163192 --- /dev/null +++ b/memory/system/use_cases.md @@ -0,0 +1,173 @@ +# Apache Superset Use Cases + +## Overview + +Apache Superset is a modern, enterprise-ready business intelligence web application that provides data exploration and visualization capabilities. It serves as a comprehensive platform for data analysis, dashboard creation, and business intelligence workflows. + +## Core Use Cases + +### 1. Data Source Management +- **Connect to Databases**: Users can connect to various SQL databases (PostgreSQL, MySQL, Snowflake, BigQuery, etc.) +- **Dataset Registration**: Register specific tables as datasets for analysis +- **Database Configuration**: Configure connection parameters, timeouts, and security settings +- **Data Source Validation**: Test connections and validate data source accessibility + +### 2. Data Exploration and Analysis +- **No-Code Chart Building**: Create visualizations using drag-and-drop interface +- **SQL Lab**: Advanced SQL querying with syntax highlighting and autocomplete +- **Data Preview**: Explore data structure and sample records +- **Column Configuration**: Set up metrics, dimensions, and data types +- **Filtering and Slicing**: Apply filters to focus on specific data subsets + +### 3. Visualization Creation +- **Chart Types**: Support for 40+ visualization types (bar charts, line charts, pie charts, maps, etc.) +- **Interactive Charts**: Create dynamic, interactive visualizations +- **Custom Styling**: Customize colors, fonts, and chart aesthetics +- **Chart Configuration**: Set up axes, legends, tooltips, and other chart properties +- **Real-time Updates**: Charts that refresh with new data + +### 4. Dashboard Development +- **Dashboard Creation**: Build comprehensive dashboards with multiple charts +- **Layout Management**: Drag-and-drop dashboard layout with responsive design +- **Cross-filtering**: Enable interactive filtering across dashboard components +- **Dashboard Sharing**: Share dashboards with team members and stakeholders +- **Dashboard Publishing**: Make dashboards public or private + +### 5. SQL Query Management +- **Query Execution**: Run SQL queries against connected databases +- **Query History**: Track and manage query execution history +- **Query Templates**: Save and reuse common query patterns +- **Async Query Support**: Handle long-running queries asynchronously +- **Query Results Export**: Export query results to various formats + +### 6. Alerts and Reporting +- **Alert Configuration**: Set up alerts based on SQL conditions +- **Scheduled Reports**: Create automated reports sent via email or Slack +- **Report Templates**: Design report templates with charts and dashboards +- **Notification Management**: Configure recipients and delivery schedules +- **Alert Monitoring**: Track alert status and history + +### 7. User Management and Security +- **Role-Based Access Control**: Manage user permissions and roles +- **Data Source Access**: Control access to specific databases and tables +- **User Authentication**: Support for various authentication methods +- **Permission Management**: Granular control over user capabilities +- **Audit Logging**: Track user actions and system usage + +### 8. Data Upload and Integration +- **CSV Upload**: Upload CSV files directly to databases +- **Excel Integration**: Import Excel files for analysis +- **Columnar File Support**: Handle Parquet and other columnar formats +- **Google Sheets Connection**: Connect to Google Sheets data +- **File Processing**: Process and transform uploaded data + +## Typical User Journeys + +### 1. Business Analyst Journey +1. **Connect to Data Source**: Connect to company database (e.g., sales data warehouse) +2. **Explore Data**: Browse available tables and understand data structure +3. **Create Dataset**: Register relevant tables as datasets +4. **Build Charts**: Create visualizations showing sales trends, customer segments +5. **Assemble Dashboard**: Combine charts into comprehensive sales dashboard +6. **Share Insights**: Share dashboard with management team +7. **Set Up Alerts**: Configure alerts for unusual sales patterns + +### 2. Data Scientist Journey +1. **SQL Lab Exploration**: Use SQL Lab to explore raw data and test hypotheses +2. **Advanced Queries**: Write complex analytical queries with window functions +3. **Create Visualizations**: Build sophisticated charts for data analysis +4. **Dashboard Creation**: Create analytical dashboards for model performance +5. **Report Automation**: Set up automated reports for model monitoring +6. **Collaboration**: Share findings with data engineering team + +### 3. Executive Dashboard Journey +1. **High-Level Metrics**: Create executive dashboards with KPIs +2. **Real-time Monitoring**: Set up dashboards that refresh automatically +3. **Drill-down Capabilities**: Enable executives to drill into specific metrics +4. **Mobile Access**: Ensure dashboards work on mobile devices +5. **Alert Configuration**: Set up alerts for critical business metrics +6. **Stakeholder Sharing**: Share dashboards with board members and investors + +### 4. Data Engineer Journey +1. **Database Setup**: Configure connections to various data sources +2. **Data Pipeline Monitoring**: Create dashboards to monitor ETL processes +3. **Performance Metrics**: Track database performance and query execution times +4. **Error Monitoring**: Set up alerts for data pipeline failures +5. **Data Quality**: Create visualizations to monitor data quality metrics +6. **System Health**: Monitor overall system health and resource usage + +### 5. Marketing Analyst Journey +1. **Campaign Analysis**: Analyze marketing campaign performance +2. **Customer Segmentation**: Create visualizations for customer behavior analysis +3. **ROI Tracking**: Build dashboards to track marketing ROI +4. **A/B Testing**: Visualize A/B test results and statistical significance +5. **Attribution Modeling**: Create attribution analysis dashboards +6. **Report Automation**: Automate weekly marketing reports + +### 6. Operations Manager Journey +1. **Operational Metrics**: Monitor key operational indicators +2. **Resource Utilization**: Track system and human resource usage +3. **Process Monitoring**: Create dashboards for business process monitoring +4. **Exception Handling**: Set up alerts for operational exceptions +5. **Performance Tracking**: Monitor team and system performance +6. **Compliance Reporting**: Create compliance and regulatory reports + +## User Roles and Capabilities + +### Admin Users +- Full system access and configuration +- User management and role assignment +- Database and data source management +- System configuration and security settings + +### Alpha Users +- Access to all data sources +- Can create and modify datasets +- Can create charts and dashboards +- Cannot manage other users + +### Gamma Users +- Limited to assigned data sources +- Can create charts and dashboards +- Primarily content consumers +- Cannot add data sources + +### SQL Lab Users +- Access to SQL Lab functionality +- Can execute queries against assigned databases +- Can create temporary tables +- Can export query results + +## Key Features by Use Case + +### For Data Exploration +- No-code chart builder +- SQL Lab for advanced queries +- Data preview and sampling +- Column type detection and configuration + +### For Dashboard Creation +- Drag-and-drop dashboard builder +- Cross-filtering capabilities +- Responsive design +- Real-time data updates + +### For Collaboration +- Dashboard sharing +- Role-based access control +- Comment and annotation features +- Version control for dashboards + +### For Automation +- Scheduled reports +- Alert configuration +- API access for programmatic control +- Webhook integration + +### For Enterprise Use +- Multi-tenant architecture +- Advanced security features +- Audit logging +- Integration with enterprise authentication systems + +This comprehensive use case analysis provides a foundation for understanding how different users interact with Apache Superset and the value it provides across various business intelligence scenarios. diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 793ca61edfdd..48240a0b4888 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -321,7 +321,10 @@ "eslint-rules/eslint-plugin-icons": { "version": "1.0.0", "dev": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peerDependencies": { + "eslint": ">=0.8.0" + } }, "eslint-rules/eslint-plugin-theme-colors": { "version": "1.0.0", diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx index f427bc9f038d..1c5aa55bf117 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx @@ -43,6 +43,9 @@ import VizTypeControl, { VIZ_TYPE_CONTROL_TEST_ID } from './index'; jest.useFakeTimers(); +// Mock scrollIntoView to prevent errors with fake timers +jest.mock('scroll-into-view-if-needed', () => jest.fn()); + class MainPreset extends Preset { constructor() { super({ @@ -256,4 +259,22 @@ describe('VizTypeControl', () => { expect(defaultProps.onChange).toHaveBeenCalledWith(VizType.Line); }); + + it('Auto-focuses search input when modal opens', async () => { + await waitForRenderWrapper(); + + // Open the modal + userEvent.click(screen.getByText('View all charts')); + + // Wait for the modal to open and the search input to be rendered + const searchInput = await screen.findByTestId(getTestId('search-input')); + + // Run all timers to trigger the auto-focus setTimeout + jest.runAllTimers(); + + // Check that the search input is focused + await waitFor(() => { + expect(searchInput).toHaveFocus(); + }); + }); }); diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx index 85236ca3a452..58fae7696d09 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx @@ -443,6 +443,19 @@ export default function VizTypeGallery(props: VizTypeGalleryProps) { const [isSearchFocused, setIsSearchFocused] = useState(true); const isActivelySearching = isSearchFocused && !!searchInputValue; + // Auto-focus the search input when the modal opens + useEffect(() => { + // Use setTimeout to ensure the modal animation completes before focusing + const timeoutId = setTimeout(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } + }, 150); + + return () => clearTimeout(timeoutId); + }, []); + + const selectedVizMetadata: ChartMetadata | null = selectedViz ? mountedPluginMetadata[selectedViz] : null; From 46a119ec354c2d4f42f21ac8f29353e0fe28c34b Mon Sep 17 00:00:00 2001 From: ffalathel Date: Sun, 19 Oct 2025 20:03:34 -0400 Subject: [PATCH 2/2] Update Docker port mapping and enhance table chart sorting configuration - Changed PostgreSQL port mapping in docker-compose.yml from 5432 to 5433. - Modified default value for 'order_desc' in buildQuery.ts to true for table charts. - Added a new checkbox control for 'Sort descending' in controlPanel.tsx with visibility conditions based on aggregation mode and selected sort metric. --- .cursor/commands/design_system.md | 196 ++++++++++++++++++ .cursor/commands/implement.md | 5 + PR_DESCRIPTION.md | 102 +++++++++ docker-compose.yml | 2 +- .../design/001_sort_descending_visibility.md | 184 ++++++++++++++++ ...1_sort_descending_visibility_milestones.md | 177 ++++++++++++++++ .../plugin-chart-table/src/buildQuery.ts | 2 +- .../plugin-chart-table/src/controlPanel.tsx | 37 ++-- 8 files changed, 688 insertions(+), 17 deletions(-) create mode 100644 .cursor/commands/design_system.md create mode 100644 .cursor/commands/implement.md create mode 100644 PR_DESCRIPTION.md create mode 100644 memory/design/001_sort_descending_visibility.md create mode 100644 memory/milestones/001_sort_descending_visibility_milestones.md diff --git a/.cursor/commands/design_system.md b/.cursor/commands/design_system.md new file mode 100644 index 000000000000..d4cc3943b303 --- /dev/null +++ b/.cursor/commands/design_system.md @@ -0,0 +1,196 @@ +# Design System + +For the feature or bug in question, create a design document using the template below. + +Save the design using incrementing numbers like the following: memory/design/001_some_feature.md + +# [Feature/Component Name] Design Document + +## Metadata +- **Status:** [Draft | In Review | Approved | Implemented] +- **Author(s):** +- **Reviewers:** +- **Created:** +- **Updated:** +- **Implementation PR(s):** + +## Overview + + +## Goals + +## Proposed Solution + +### High-Level Approach + + +### Key Components + +- **Component A:** +- **Component B:** +- **Component C:** + +### Simple Architecture Diagram + +``` +[Diagram here - can be ASCII, Mermaid, or embedded image] +``` + +## Design Considerations + +### 1. [Design Choice Name] +**Context:** + +**Options:** +- **Option A:** + - Pros: + - Cons: +- **Option B:** + - Pros: + - Cons: +- **Option C:** + - Pros: + - Cons: + +**Recommendation:** + +### 2. [Design Choice Name] +**Context:** + +**Options:** +- **Option A:** + - Pros: + - Cons: +- **Option B:** + - Pros: + - Cons: + +**Recommendation:** + +## Lifecycle of Code for Key Use Case + + +1. **User initiates action:** +2. **System validates:** +3. **Processing step:** +4. **Data persistence:** +5. **Response to user:** +6. **Post-processing (if any):** + +### Error Scenarios +- **If validation fails:** +- **If external service is down:** +- **If database write fails:** + +## Detailed Design + +### Schema Updates +```sql +-- Example table or schema changes +CREATE TABLE example ( + id UUID PRIMARY KEY, + created_at TIMESTAMP NOT NULL, + ... +); +``` + +### API Endpoints + +#### `POST /api/v1/[endpoint]` +**Request:** +```json +{ + "field1": "value", + "field2": 123 +} +``` + +**Response (200 OK):** +```json +{ + "id": "uuid", + "status": "success", + "data": {} +} +``` + +**Error Response (4xx/5xx):** +```json +{ + "error": "error_code", + "message": "Human readable message" +} +``` + +#### `GET /api/v1/[endpoint]/{id}` +**Response (200 OK):** +```json +{ + "id": "uuid", + "field1": "value", + "field2": 123 +} +``` + +### UI Changes + +- **Screen/Component:** +- **User flow:** +- **Key interactions:** + +### Services / Business Logic + +#### Service A +```python +# Pseudocode or key algorithm +def process_request(input): + # Validate + # Transform + # Persist + # Return +``` + +#### Service B + + +### Data Migration Plan + +- **Migration strategy:** +- **Rollback plan:** +- **Estimated data volume:** + +## Risks & Mitigations + +| Risk | Impact | Likelihood | Mitigation | +|------|--------|------------|------------| +| [Risk description] | High/Med/Low | High/Med/Low | [How we prevent/handle it] | +| | | | | + +### Technical Debt + +- + +## Rollout Plan + +### Deployment Strategy +- [ ] Feature flag implementation +- [ ] Canary deployment percentage: +- [ ] Full rollout criteria: + +### Rollback Plan + + +### Monitoring & Alerts + +- **Key metrics:** +- **Alert thresholds:** +- **Dashboards:** + +## Open Questions + + + +## References +- [Link to related documents] +- [Link to previous ADRs this supersedes or relates to] +- [Link to external resources] \ No newline at end of file diff --git a/.cursor/commands/implement.md b/.cursor/commands/implement.md new file mode 100644 index 000000000000..3cb54adf501a --- /dev/null +++ b/.cursor/commands/implement.md @@ -0,0 +1,5 @@ +# Implement + +For the indicated milestone, ask any clarifying questions. If relevant, review different implementation choices with pros and cons. + +Implement the milestone, and be clear with that I need to check in the final integration tests. Where possible, write temporary scripts to test the milestone. \ No newline at end of file diff --git a/PR_DESCRIPTION.md b/PR_DESCRIPTION.md new file mode 100644 index 000000000000..3ec319c18ebb --- /dev/null +++ b/PR_DESCRIPTION.md @@ -0,0 +1,102 @@ +# 🎯 Auto-focus Search Input in Visualization Type Modal + +## Summary +This PR improves the user experience in the "Change Visualization Type" modal by automatically focusing the search input when the modal opens, eliminating the need for users to manually click on the search field before typing. + +## Problem +Currently, when users open the "Change Visualization Type" modal, they must manually click on the search input field before they can start typing to search for visualization types. This adds an unnecessary step to the workflow and creates friction in the user experience. + +**Before:** +1. User clicks to change visualization type +2. Modal opens +3. User must click on search input field +4. User can start typing to search + +**After:** +1. User clicks to change visualization type +2. Modal opens with search input automatically focused +3. User can immediately start typing to search + +## Solution +- Added `useRef` hook to create a reference to the search input element +- Implemented `useEffect` hook to automatically focus the search input when the `VizTypeGallery` component mounts +- Used `setTimeout` with 150ms delay to ensure the modal animation completes before focusing +- Added proper cleanup to prevent memory leaks + +## Changes Made + +### Files Modified +- `superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx` + - Added `useRef` and `useEffect` imports + - Created `searchInputRef` to reference the search input + - Added auto-focus logic with proper timing + - Added cleanup function to clear timeout + +- `superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx` + - Added comprehensive test case for auto-focus functionality + - Used `jest.useFakeTimers()` and `jest.runAllTimers()` for reliable testing + - Mocked `scroll-into-view-if-needed` to prevent test failures + - Added proper async assertions with `waitFor` + +## Technical Details + +### Implementation +```typescript +// Added to VizTypeGallery.tsx +const searchInputRef = useRef(); + +useEffect(() => { + // Use setTimeout to ensure the modal animation completes before focusing + const timeoutId = setTimeout(() => { + if (searchInputRef.current) { + searchInputRef.current.focus(); + } + }, 150); + + return () => clearTimeout(timeoutId); +}, []); +``` + +### Testing +- Added test case that verifies the search input is automatically focused when the modal opens +- Used fake timers to control the `setTimeout` behavior +- Ensured proper cleanup and async handling + +## Benefits +- **Improved UX**: Eliminates unnecessary click step for power users +- **Keyboard-friendly**: Enables full keyboard navigation workflow +- **Faster chart creation**: Reduces clicks needed to change visualization type +- **Consistent behavior**: Follows common modal interaction patterns + +## Use Cases +- **Business Analysts**: Faster chart creation workflow +- **Power Users**: Keyboard-only navigation support +- **General Users**: Smoother, more intuitive interaction + +## Testing +- ✅ Unit tests pass with new auto-focus test case +- ✅ Manual testing confirms search input is focused on modal open +- ✅ No regression in existing functionality +- ✅ Proper cleanup prevents memory leaks + +## Accessibility +- Maintains keyboard navigation support +- Preserves screen reader compatibility +- No impact on existing accessibility features + +## Backward Compatibility +- ✅ No breaking changes +- ✅ Existing functionality preserved +- ✅ No API changes required + +## Related Issues +- Addresses UX friction in visualization type selection +- Improves workflow efficiency for chart creation +- Enhances keyboard accessibility + +--- + +**Type:** Enhancement +**Impact:** User Experience +**Breaking Changes:** None +**Dependencies:** None diff --git a/docker-compose.yml b/docker-compose.yml index cb5953bee356..9d1eccc71845 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -71,7 +71,7 @@ services: container_name: superset_db restart: unless-stopped ports: - - "127.0.0.1:5432:5432" + - "127.0.0.1:5433:5432" volumes: - db_home:/var/lib/postgresql/data - ./docker/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d diff --git a/memory/design/001_sort_descending_visibility.md b/memory/design/001_sort_descending_visibility.md new file mode 100644 index 000000000000..33e238f8b04a --- /dev/null +++ b/memory/design/001_sort_descending_visibility.md @@ -0,0 +1,184 @@ +# Sort Descending Checkbox Visibility Design Document + +## Metadata +- **Status:** Draft +- **Author(s):** Development Team +- **Reviewers:** UX Team, Frontend Team +- **Created:** 2025-10-12 +- **Updated:** 2025-10-12 +- **Implementation PR(s):** TBD + +## Overview +The "Sort Descending" checkbox in the Table Chart control panel is currently always visible, regardless of whether a "Sort Query By" metric has been selected. This creates a confusing user experience where users can interact with a control that has no effect when no sort metric is selected. The checkbox should only be visible when a "Sort Query By" metric is selected, making it clear that these two controls work together. + +This enhancement improves the user experience by: +- Eliminating confusion about non-functional controls +- Creating a clearer visual relationship between dependent controls +- Following established UI patterns for conditional control visibility + +## Goals +- Hide the "Sort Descending" checkbox when no "Sort Query By" metric is selected +- Show the "Sort Descending" checkbox when a "Sort Query By" metric is selected +- Position the checkbox directly below the "Sort Query By" control for visual clarity +- Maintain existing functionality when controls are visible +- Preserve behavior in aggregation mode only + +## Proposed Solution + +### High-Level Approach +Modify the visibility logic of the "Sort Descending" checkbox to depend on the presence of a selected "Sort Query By" metric. The checkbox will use a dynamic visibility function that checks if `timeseries_limit_metric` has a value, and only show the checkbox when this condition is met. + +### Key Components +- **Control Panel Configuration:** Update the `order_desc` control visibility logic +- **Form Data Interface:** Leverage existing `timeseries_limit_metric` field +- **Query Building Logic:** Maintain existing sort behavior when controls are visible + +### Simple Architecture Diagram +``` +Table Chart Control Panel +├── Sort Query By (timeseries_limit_metric) +│ └── [Metric Selection Dropdown] +└── Sort Descending (order_desc) [VISIBLE ONLY IF METRIC SELECTED] + └── [Checkbox: Descending/Ascending] +``` + +## Design Considerations + +### 1. Visibility Logic Implementation +**Context:** The checkbox visibility must be tied to the presence of a sort metric selection. + +**Options:** +- **Option A:** Simple boolean check on `timeseries_limit_metric` value + - Pros: Simple implementation, clear logic + - Cons: May not handle edge cases with empty arrays +- **Option B:** Comprehensive validation including array length and null checks + - Pros: Handles all edge cases + - Cons: More complex implementation, potential over-engineering +- **Option C:** Use existing `isAggMode` combined with metric presence + - Pros: Leverages existing patterns, consistent with current code + - Cons: May be too restrictive + +**Recommendation:** Option B - Comprehensive validation to handle all edge cases properly. + +### 2. Control Positioning +**Context:** The checkbox should be visually connected to the "Sort Query By" control. + +**Options:** +- **Option A:** Keep current positioning, only change visibility + - Pros: Minimal changes, no layout disruption + - Cons: May not improve visual relationship +- **Option B:** Move checkbox to be directly adjacent to sort metric control + - Pros: Clear visual relationship, better UX + - Cons: Requires control panel restructuring +- **Option C:** Use visual grouping/grouping controls + - Pros: Professional appearance, scalable pattern + - Cons: More complex implementation + +**Recommendation:** Option A - Keep current positioning for minimal disruption, focus on visibility logic. + +## Lifecycle of Code for Key Use Case + +1. **User opens Table Chart:** Control panel renders with initial state +2. **System checks aggregation mode:** `isAggMode` determines if sort controls are relevant +3. **System evaluates metric selection:** `timeseries_limit_metric` value determines checkbox visibility +4. **User selects sort metric:** Checkbox becomes visible with current state +5. **User toggles sort direction:** Checkbox state updates, query rebuilds +6. **User clears sort metric:** Checkbox becomes hidden, sort direction resets + +### Error Scenarios +- **If no metrics available:** Checkbox remains hidden (expected behavior) +- **If aggregation mode disabled:** Checkbox remains hidden (existing behavior) +- **If metric selection cleared:** Checkbox becomes hidden, sort direction preserved for next selection + +## Detailed Design + +### Schema Updates +No database schema changes required. This is a UI-only enhancement. + +### API Endpoints +No new API endpoints required. Existing query building logic handles the sort parameters. + +### UI Changes +- **Control Panel:** Update `order_desc` control visibility logic +- **User flow:** Checkbox appears/disappears based on metric selection +- **Key interactions:** + - Select metric → checkbox appears + - Clear metric → checkbox disappears + - Toggle checkbox → sort direction changes + +### Services / Business Logic + +#### Control Panel Configuration +```typescript +// In controlPanel.tsx +{ + name: 'order_desc', + config: { + type: 'CheckboxControl', + label: t('Sort descending'), + default: true, + description: t( + 'If enabled, this control sorts the results/values descending, otherwise it sorts the results ascending.', + ), + visibility: ({ controls }: ControlPanelsContainerProps) => { + // Only show in aggregation mode AND when a sort metric is selected + return isAggMode({ controls }) && + controls?.timeseries_limit_metric?.value && + !isEmpty(controls?.timeseries_limit_metric?.value); + }, + resetOnHide: false, + }, +}, +``` + +#### Query Building Logic +```typescript +// In buildQuery.ts - existing logic remains unchanged +if (sortByMetric) { + orderby = [[sortByMetric, !orderDesc]]; +} else if (metrics?.length > 0) { + // default to ordering by first metric in descending order + orderby = [[metrics[0], false]]; +} +``` + +### Data Migration Plan +No data migration required. This is a UI enhancement that doesn't affect stored data. + +## Risks & Mitigations + +| Risk | Impact | Likelihood | Mitigation | +|------|--------|------------|------------| +| Checkbox state lost when metric cleared | Medium | Low | Preserve checkbox state in form data, restore on metric reselection | +| Confusion about sort behavior | Low | Low | Clear description text, maintain existing query logic | +| Layout disruption | Low | Low | Keep existing positioning, only change visibility | +| Performance impact | Low | Very Low | Simple boolean check, minimal computational overhead | + +### Technical Debt +- Consider future enhancement to group related controls visually +- Potential for more sophisticated control dependency management + +## Rollout Plan + +### Deployment Strategy +- [ ] Feature flag implementation: Not required (UI-only change) +- [ ] Canary deployment percentage: 100% (low risk) +- [ ] Full rollout criteria: Standard deployment process + +### Rollback Plan +Simple code revert if issues arise. No data migration or complex rollback required. + +### Monitoring & Alerts +- **Key metrics:** User interaction with sort controls, query performance +- **Alert thresholds:** None required for this UI enhancement +- **Dashboards:** Standard frontend performance monitoring + +## Open Questions +1. Should the checkbox state be preserved when the metric is cleared and then reselected? +2. Should we consider grouping the sort controls in a visual container? +3. Are there other chart types that would benefit from similar conditional visibility patterns? + +## References +- [Table Chart Control Panel Implementation](superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx) +- [Query Building Logic](superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts) +- [Shared Controls Pattern](superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx) diff --git a/memory/milestones/001_sort_descending_visibility_milestones.md b/memory/milestones/001_sort_descending_visibility_milestones.md new file mode 100644 index 000000000000..c201151d3f31 --- /dev/null +++ b/memory/milestones/001_sort_descending_visibility_milestones.md @@ -0,0 +1,177 @@ +# Sort Descending Checkbox Visibility - Implementation Milestones + +**Design Document:** [001_sort_descending_visibility.md](../design/001_sort_descending_visibility.md) +**Status:** Planning +**Created:** 2025-10-12 + +## Overview +This milestone plan implements the conditional visibility of the "Sort Descending" checkbox in the Table Chart control panel. The checkbox will only be visible when a "Sort Query By" metric is selected, improving the user experience by eliminating confusion about non-functional controls. + +## Milestone 1: Research and Setup +**Goal:** Understand current implementation and prepare development environment + +### Tasks +- [ ] **1.1** Analyze current `order_desc` control implementation in `controlPanel.tsx` +- [ ] **1.2** Review `timeseries_limit_metric` control configuration and data flow +- [ ] **1.3** Examine existing visibility patterns in other chart controls +- [ ] **1.4** Set up development environment with Table Chart plugin +- [ ] **1.5** Create test dataset with metrics for testing + +### Verification +- [ ] Can identify the exact location of `order_desc` control configuration +- [ ] Can identify the exact location of `timeseries_limit_metric` control configuration +- [ ] Can run Table Chart in development mode +- [ ] Can create a chart with metrics to test the feature + +--- + +## Milestone 2: Implement Basic Visibility Logic +**Goal:** Add conditional visibility to the "Sort Descending" checkbox + +### Tasks +- [ ] **2.1** Update `order_desc` control visibility function in `controlPanel.tsx` +- [ ] **2.2** Add comprehensive validation for `timeseries_limit_metric` value +- [ ] **2.3** Ensure visibility logic works with `isAggMode` condition +- [ ] **2.4** Test with empty metric selection (checkbox should be hidden) +- [ ] **2.5** Test with metric selection (checkbox should be visible) + +### Code Changes +```typescript +// In controlPanel.tsx - update order_desc control +{ + name: 'order_desc', + config: { + type: 'CheckboxControl', + label: t('Sort descending'), + default: true, + description: t( + 'If enabled, this control sorts the results/values descending, otherwise it sorts the results ascending.', + ), + visibility: ({ controls }: ControlPanelsContainerProps) => { + return isAggMode({ controls }) && + controls?.timeseries_limit_metric?.value && + !isEmpty(controls?.timeseries_limit_metric?.value); + }, + resetOnHide: false, + }, +}, +``` + +### Verification +- [ ] Checkbox is hidden when no metric is selected +- [ ] Checkbox appears when a metric is selected +- [ ] Checkbox disappears when metric is cleared +- [ ] Checkbox remains hidden in raw mode (existing behavior preserved) + +--- + +## Milestone 3: Edge Case Handling +**Goal:** Ensure robust handling of edge cases and data types + +### Tasks +- [ ] **3.1** Test with `null` values for `timeseries_limit_metric` +- [ ] **3.2** Test with empty array `[]` for `timeseries_limit_metric` +- [ ] **3.3** Test with single metric selection +- [ ] **3.4** Test with multiple metric selections +- [ ] **3.5** Test checkbox state preservation when metric is cleared and reselected + +### Verification +- [ ] Checkbox handles all edge cases correctly +- [ ] No console errors or warnings +- [ ] Checkbox state is preserved appropriately +- [ ] Performance is not impacted by visibility checks + +--- + +## Milestone 4: User Experience Testing +**Goal:** Verify the user experience flows work as expected + +### Tasks +- [ ] **4.1** Test complete user flow: select metric → checkbox appears → toggle checkbox → query updates +- [ ] **4.2** Test reverse flow: clear metric → checkbox disappears +- [ ] **4.3** Test with different chart configurations (various metrics, groupby, etc.) +- [ ] **4.4** Verify sort direction is applied correctly when checkbox is visible +- [ ] **4.5** Test keyboard navigation and accessibility + +### Verification +- [ ] User can intuitively understand the relationship between controls +- [ ] No confusion about non-functional controls +- [ ] Sort functionality works correctly when controls are visible +- [ ] Accessibility is maintained + +--- + +## Milestone 5: Integration Testing +**Goal:** Ensure the feature works correctly with other Table Chart functionality + +### Tasks +- [ ] **5.1** Test with server pagination enabled +- [ ] **5.2** Test with different query modes (aggregate vs raw) +- [ ] **5.3** Test with time-based filtering +- [ ] **5.4** Test with ad-hoc filters +- [ ] **5.5** Test with different data sources + +### Verification +- [ ] Feature works with all Table Chart configurations +- [ ] No conflicts with existing functionality +- [ ] Performance is maintained +- [ ] No regression in existing behavior + +--- + +## Milestone 6: Documentation and Cleanup +**Goal:** Document the changes and clean up the implementation + +### Tasks +- [ ] **6.1** Add inline code comments explaining the visibility logic +- [ ] **6.2** Update any relevant documentation +- [ ] **6.3** Remove any debugging code or console logs +- [ ] **6.4** Ensure code follows project style guidelines +- [ ] **6.5** Create unit tests for the visibility logic + +### Verification +- [ ] Code is well-documented and clean +- [ ] Unit tests cover the new visibility logic +- [ ] No debugging artifacts remain +- [ ] Code passes linting and style checks + +--- + +## Milestone 7: Final Testing and Validation +**Goal:** Comprehensive testing to ensure the feature is ready for production + +### Tasks +- [ ] **7.1** Manual testing of all user scenarios +- [ ] **7.2** Cross-browser testing (Chrome, Firefox, Safari) +- [ ] **7.3** Test with different screen sizes and responsive design +- [ ] **7.4** Performance testing with large datasets +- [ ] **7.5** User acceptance testing with stakeholders + +### Verification +- [ ] Feature works correctly across all browsers +- [ ] Responsive design is maintained +- [ ] Performance is acceptable +- [ ] Stakeholders approve the user experience + +--- + +## Success Criteria +- [ ] "Sort Descending" checkbox is only visible when a "Sort Query By" metric is selected +- [ ] Checkbox appears/disappears smoothly when metric selection changes +- [ ] Existing functionality is preserved when controls are visible +- [ ] No regression in other Table Chart features +- [ ] User experience is improved with clearer control relationships +- [ ] Code is maintainable and well-tested + +## Rollback Plan +If any milestone fails or causes issues: +1. **Immediate:** Revert to previous visibility logic (always show in aggregation mode) +2. **Investigation:** Identify root cause of the issue +3. **Fix:** Address the specific problem and re-test +4. **Re-deploy:** Implement the fix and continue with remaining milestones + +## Notes +- Each milestone should be completed and verified before moving to the next +- If issues arise, stop and address them before continuing +- Keep the implementation simple and focused on the core requirement +- Consider future enhancements (like visual grouping) as separate features diff --git a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts index 7068ab119304..2d1b22c4c503 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts @@ -58,7 +58,7 @@ const buildQuery: BuildQuery = ( ) => { const { percent_metrics: percentMetrics, - order_desc: orderDesc = false, + order_desc: orderDesc = true, extra_form_data, } = formData; const queryMode = getQueryMode(formData); diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index 933ee6a0c1d0..10ccd72e66b3 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -308,6 +308,28 @@ const config: ControlPanelConfig = { resetOnHide: false, }, }, + ], + [ + { + name: 'order_desc', + config: { + type: 'CheckboxControl', + label: t('Sort descending'), + default: true, + description: t( + 'If enabled, this control sorts the results/values descending, otherwise it sorts the results ascending.', + ), + visibility: ({ controls }: ControlPanelsContainerProps) => { + // Only show in aggregation mode AND when a sort metric is selected + return isAggMode({ controls }) && + Boolean(controls?.timeseries_limit_metric?.value) && + !isEmpty(controls?.timeseries_limit_metric?.value); + }, + resetOnHide: false, + }, + }, + ], + [ { name: 'order_by_cols', config: { @@ -362,21 +384,6 @@ const config: ControlPanelConfig = { }, }, ], - [ - { - name: 'order_desc', - config: { - type: 'CheckboxControl', - label: t('Sort descending'), - default: true, - description: t( - 'If enabled, this control sorts the results/values descending, otherwise it sorts the results ascending.', - ), - visibility: isAggMode, - resetOnHide: false, - }, - }, - ], [ { name: 'show_totals',