Skip to content

feat: Implement context menu for drill by#23454

Merged
kgabryje merged 11 commits into
apache:masterfrom
kgabryje:feat/drill-by-context-menu
Mar 29, 2023
Merged

feat: Implement context menu for drill by#23454
kgabryje merged 11 commits into
apache:masterfrom
kgabryje:feat/drill-by-context-menu

Conversation

@kgabryje
Copy link
Copy Markdown
Member

@kgabryje kgabryje commented Mar 22, 2023

SUMMARY

Charts that support drill by: all Echarts, World Map, Table, Pivot Table.

This PR implements right-click context menu with drill by option for charts that support the feature. When user right-click on series, the chart plugin constructs a filter object (similar to drill to detail filter), which in the result chart will be appended to original chart's adhoc filters. Then, user can select a column from drill by submenu that later will be used as a dimension of the result chart.
The columns are fetched when user opens the context menu. The result is cached, so that the request is not repeated for charts that use the same dataset. Only columns that are marked as dimensions in the dataset and are not used as dimensions of current chart can be selected.
If there are more than 10 available columns, a search input in the submenu is displayed.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

image

TESTING INSTRUCTIONS

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@kgabryje kgabryje requested a review from lilykuang March 22, 2023 11:59
@kgabryje kgabryje marked this pull request as draft March 22, 2023 11:59
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 22, 2023

Codecov Report

Merging #23454 (a80bbd2) into master (a3ffc67) will decrease coverage by 0.01%.
The diff coverage is 54.76%.

❗ Current head a80bbd2 differs from pull request most recent head 22a585f. Consider uploading reports for the commit 22a585f to get more accurate results

@@            Coverage Diff             @@
##           master   #23454      +/-   ##
==========================================
- Coverage   67.65%   67.64%   -0.01%     
==========================================
  Files        1910     1913       +3     
  Lines       73746    73838      +92     
  Branches     7987     8021      +34     
==========================================
+ Hits        49891    49951      +60     
- Misses      21814    21845      +31     
- Partials     2041     2042       +1     
Flag Coverage Δ
javascript 53.87% <54.76%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
.../packages/superset-ui-core/src/chart/types/Base.ts 100.00% <ø> (ø)
...gins/legacy-plugin-chart-world-map/src/WorldMap.js 0.00% <0.00%> (ø)
...plugins/legacy-plugin-chart-world-map/src/index.js 66.66% <ø> (ø)
.../plugins/plugin-chart-echarts/src/BoxPlot/index.ts 50.00% <ø> (ø)
...d/plugins/plugin-chart-echarts/src/Funnel/index.ts 50.00% <ø> (ø)
...nd/plugins/plugin-chart-echarts/src/Gauge/index.ts 50.00% <ø> (ø)
...ns/plugin-chart-echarts/src/Graph/EchartsGraph.tsx 0.00% <0.00%> (ø)
...nd/plugins/plugin-chart-echarts/src/Graph/index.ts 50.00% <ø> (ø)
...rts/src/MixedTimeseries/EchartsMixedTimeseries.tsx 0.00% <0.00%> (ø)
.../plugin-chart-echarts/src/MixedTimeseries/index.ts 25.00% <ø> (ø)
... and 31 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@kgabryje kgabryje force-pushed the feat/drill-by-context-menu branch from c7539e8 to 59587d0 Compare March 24, 2023 12:12
@kgabryje kgabryje force-pushed the feat/drill-by-context-menu branch from de1c31f to d793393 Compare March 28, 2023 07:40
@kgabryje kgabryje changed the title [WIP] feat: Implement context menu for drill by feat: Implement context menu for drill by Mar 28, 2023
@kgabryje kgabryje marked this pull request as ready for review March 28, 2023 07:40
@geido
Copy link
Copy Markdown
Member

geido commented Mar 28, 2023

/testenv up FEATURE_DRILL_BY=true FEATURE_DRILL_TO_DETAIL=true FEATURE_DASHBOARD_CROSS_FILTERS=true

@github-actions
Copy link
Copy Markdown
Contributor

@geido Ephemeral environment spinning up at http://54.191.91.221:8080. Credentials are admin/admin. Please allow several minutes for bootstrapping and startup.

Copy link
Copy Markdown
Member

@villebro villebro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and tested to work as expected, both with and without the FF. Since this is behind a FF I don't see any reason to not merge this as-is (if there are issues they will only affect users that have enabled the feature).

@kgabryje kgabryje merged commit 9fbfd1c into apache:master Mar 29, 2023
@github-actions
Copy link
Copy Markdown
Contributor

Ephemeral environment shutdown and build artifacts deleted.

@mistercrunch mistercrunch added 🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels 🚢 3.0.0 First shipped in 3.0.0 labels Mar 13, 2024
@mistercrunch
Copy link
Copy Markdown
Member

Found this PR researching why things that should be cached seemed to be cached ... Claude's analysis:

Cache Architecture Analysis: PR #23454 Side Effects

Summary

PR #23454 introduced cachedSupersetGet for drill-by performance optimization. While this provided session-scoped performance benefits, it inadvertently created a cache invalidation architecture that causes data staleness issues in multi-user scenarios and cross-component data mutations.

Original Implementation Context

Commit: 9fbfd1c1d883f983ef96b8812297721e2a1a9695
Author: Kamil Gabryjelski
Date: March 29, 2023
PR: #23454 - "feat: Implement context menu for drill by"

Cache Implementation Details

Location: superset-frontend/src/utils/cachedSupersetGet.ts

export const supersetGetCache = new Map<string, any>();
export const cachedSupersetGet = cacheWrapper(
  SupersetClient.get,
  supersetGetCache,
  ({ endpoint }) => endpoint || '',
);

Design Characteristics:

  • Client-side JavaScript Map - Lives in browser memory
  • Endpoint-based keying - Cache key = API endpoint URL
  • Session-scoped persistence - Survives React Router navigation
  • Manual-only invalidation - No automatic expiration or refresh
  • No TTL mechanism - Data cached indefinitely until page refresh

Identified Issues

1. Cache Invalidation Gap

Problem: Dataset metadata changes (like drill_through_chart_id) don't invalidate related cached endpoints.

Affected Flow:

  1. User edits dataset in Dataset Editor → Saves drill_through_chart_id
  2. User navigates to dashboard (React Router navigation - cache persists)
  3. User clicks drill-through → Uses stale cached /api/v1/dataset/{id}/drill_info/ response
  4. Result: Old drill-through behavior despite configuration change

Current Invalidation: Only happens on API errors (supersetGetCache.delete(endpoint))

2. Multi-User Data Consistency

Problem: Client-side cache has no awareness of server-side data changes by other users.

Scenario:

  • User A caches dataset drill info
  • User B updates dataset drill configuration
  • User A continues seeing stale data until page refresh

3. Cross-Component State Synchronization

Problem: Components that modify data don't coordinate with components that display cached versions of that data.

Current Architecture:

DatasourceModal (saves data) ←→ NO COORDINATION ←→ DrillDetailPane (uses cached data)

Missing: Cache invalidation bridge between data mutations and data consumers.

Why This Wasn't a Problem Initially

Historical Context

Original drill-by scope: The cache was likely designed for read-only drill operations within a single session:

  1. Load dashboard → Cache dataset drill info
  2. Perform drill-by operations → Use cached data (performance benefit)
  3. Session ends → Cache naturally cleared

No data mutation: Original drill-by didn't involve editing dataset metadata during the session.

SPA Navigation Evolution

Pre-SPA behavior: Page refreshes between dataset editing and dashboard viewing would naturally clear caches.

Current SPA behavior: React Router navigation preserves JavaScript state, exposing the cache staleness issue.

Current Cache Usage Analysis

Cache is used in 4 locations:

  1. hooks/apiResources/datasets.ts - Dataset drill info loading
  2. nativeFilters/.../DatasetSelect.tsx - Dataset selection for filters
  3. nativeFilters/.../ColumnSelect.tsx - Column selection for filters
  4. nativeFilters/.../FiltersConfigForm.tsx - Filter configuration

Cache invalidation: Only on errors, no systematic invalidation strategy.

Recommended Solutions

Short-term (Current PR)

Add cache invalidation to DatasourceModal.onConfirmSave():

import { supersetGetCache } from 'src/utils/cachedSupersetGet';

// After successful dataset save:
const drillInfoEndpoint = `/api/v1/dataset/${currentDatasource.id}/drill_info/`;
supersetGetCache.delete(drillInfoEndpoint);

Medium-term (Architecture Fix)

Replace custom cache with proper cache management:

  • React Query with automatic invalidation
  • Server-side ETags for cache validation
  • Cache tags system for related data invalidation

Long-term (Systematic Solution)

Implement cache invalidation coordination:

  • Event-driven invalidation when datasets are modified
  • Cache versioning with server-side coordination
  • Optimistic updates with rollback on conflicts

Impact Assessment

Performance Impact: The cache provides meaningful performance benefits for drill operations by avoiding repeated API calls.

Data Consistency Impact: Cache staleness creates confusing UX where configuration changes don't take effect until hard refresh.

Trade-off: Session performance vs. data freshness - current implementation prioritizes performance over consistency.

Conclusion

PR #23454's caching implementation represents a performance optimization that didn't account for data mutation scenarios. The cache works well for read-only operations but breaks down when dataset metadata becomes editable during the same session.

This is a classic example of how performance optimizations can introduce subtle data consistency bugs that only manifest in specific user workflows involving cross-component data mutations.

The issue is architectural rather than implementation-specific - any feature that modifies cached data will face similar staleness problems until systematic cache invalidation is implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels size/XL 🚢 3.0.0 First shipped in 3.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants