Skip to content

Add tags support for pivot tables#9514

Merged
nishantmonu51 merged 6 commits into
mainfrom
nishant/pivot-table-tags
Jun 4, 2026
Merged

Add tags support for pivot tables#9514
nishantmonu51 merged 6 commits into
mainfrom
nishant/pivot-table-tags

Conversation

@nishantmonu51
Copy link
Copy Markdown
Collaborator

Brings the merged Explore tag feature into the pivot sidebar. When a metrics view defines tags on dimensions or measures, the sidebar shows a dedicated Tags column on the left (mirroring the Explore dropdown's two-column layout).

  • Click a tag to filter the Measures and Dimensions lists. Click again or use the inline × to clear.
  • Hover a tag for three icon actions: Add all to rows, Add all to columns, and Auto-arrange (dims to rows, measures to columns) when a tag has both kinds.
  • Drag a tag onto a zone for the same bulk-add, plus a contextual Auto-arrange drop zone that appears between Rows and Columns when the tag has both kinds of items.
  • / Ctrl + Click or + Drop replaces the target zone instead of appending. Replace paths also clean the opposite zone, so the same dimension never lands in both rows and columns. Append paths skip items already placed in either zone.

The tag index is hoisted into a shared state-managers/selectors/tags.ts so the Explore dropdown and the pivot sidebar consume the same derived index. DashboardMetricsDraggableList now takes tagIndex as a prop; its two callers pass the new selector value. Shared TagFilterBanner and modifier-key modules deduplicate the banner UI and CMD/Ctrl tracking across surfaces.

Closes APP-1234

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

Developed in collaboration with Claude Code

Adds tag-aware bulk actions to the Explore pivot. The sidebar now has a
dedicated Tags column when the metrics view defines tags on dimensions
or measures, mirroring the Explore dropdown's two-column layout.

Each tag row supports:
- Click to filter the Measures and Dimensions sections to items in that tag
- Drag the tag onto Rows / Columns to bulk-add (dims skipped from Rows)
- Drag onto a contextual Auto-arrange zone (dims to Rows, measures to Columns)
- CMD / Ctrl + Click or + Drop to replace the target zone instead of appending

Replace paths also clean the opposite zone so a dimension never appears
in both rows and columns at once, and append paths skip items already
placed in either zone.

Reuses the existing tag-utils module and hoists the tag index into a new
shared state-manager selector consumed by both the Explore dropdown and
the pivot sidebar. Extracts the CMD/Ctrl modifier store and the
"Filtered by tag" banner into reusable pieces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nishantmonu51 nishantmonu51 requested a review from AdityaHegde June 1, 2026 09:47
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
// Replace the rows zone with the given values. Anything in the new rows
// that already lived in columns is removed from columns, so the same
// dimension never appears in both zones.
replacePivotRows(name: string, values: PivotChipData[]) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets keep the state update method light. Other places in pivot calculate the rows/columns and call setPivotRows or setPivotColumns. Note that it has code to update sorting and other related fields.

We want to make as little changes to dashboard-stores.ts as possible, we will eventually replace it with class based state management.

</span>
<Tooltip.Root delayDuration={200}>
<Tooltip.Trigger>
<button
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: Add {#snippet child()} here so that items-center applies correctly. Otherwise the cancel icon is not aligned.

Comment thread web-common/src/features/dashboards/pivot/DragList.svelte
const replace = e.metaKey || e.ctrlKey;
const { dimensions, measures } = dragData.tagPayload;
if (replace) {
metricsExplorerStore.replacePivotRows($exploreName, dimensions);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here, lets call setRows or setColumns.

</div>
{/if}
{#if showAutoArrange && dragData?.tagPayload}
<div class="header-row" transition:slide={{ duration: 160, axis: "y" }}>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: maybe good to move this to a component? That way header will only render things, drag-drop handling will be in the new component or DragList

return splitTagItems(tagName, dimensionTagIndex, measureTagIndex);
}

function handleTagDragStart(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets move the drag-drop logic to PivotTagRow.

function addTagToRows(tagName: string, replace: boolean) {
const { dimensions: dims } = tagItemsFor(tagName);
if (replace) {
metricsExplorerStore.replacePivotRows(exploreName, dims);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets take in setRows and setColumns and use those instead of calling methods on metricsExplorerStore

nishantmonu51 and others added 3 commits June 2, 2026 16:45
- Keep dashboard-stores.ts light: remove addPivotFields, replacePivotRows,
  replacePivotColumns. Restore addPivotField to its original form. Callers
  compute the new row/column arrays and call the existing setPivotRows /
  setPivotColumns instead.
- Add pure helpers in pivot-utils.ts (appendChipsToZone,
  replaceZoneCleaningOther) for cross-zone-aware bulk updates.
- Move drag setup, portal rendering, and bulk-update logic into
  PivotTagRow so the sidebar just wires props.
- PivotSidebar takes setRows / setColumns instead of importing
  metricsExplorerStore. PivotDisplay wires the setters from the store.
- DragList tag-drop computes new items for its zone and calls onUpdate
  instead of invoking the store directly. The component is no longer
  coupled to the explore concept.
- Extract PivotAutoArrangeZone component. It owns the drop handling and
  modifier-aware copy; PivotHeader just renders it with the rows /
  columns / setters props.
- TagFilterBanner: wrap the Tooltip.Trigger button in a {#snippet child()}
  so flex alignment of the cancel icon is correct.
- AddField bulk-add now loops addPivotField for each item (since
  addPivotFields is removed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pre-existing handleRowClick/handleColumnClick handlers still need the
state managers; only the tag-drop path was meant to be decoupled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
svelte-check flagged the variable as updated-but-non-reactive. Wrapping
with $state makes the assignment in beginDrag drive reactivity correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
const { dimensions, measures } = dragData.tagPayload;
const newItems =
zone === "rows" ? dimensions : [...dimensions, ...measures];
if (replace) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

newItems.length > 0 check is needed for this as well no?

);
const toAdd = zone === "rows" ? dims : [...dims, ...meas];
for (const item of toAdd) {
metricsExplorerStore.addPivotField($exploreName, item, zone === "rows");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One edge case that this leads to is there is no dedupe. Lets reuse appendChipsToZone and also replace all calls of addPivotField in this file.

Comment thread web-common/src/lib/modifier-key.ts Outdated
window.addEventListener("blur", () => _modifierHeld.set(false));
}

export const modifierHeld: Readable<boolean> = derived(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets just do modifierHeld = _modifierHeld as Readable<boolean>

- DragList tag-drop now also guards the replace branch on
  newItems.length > 0, so a pure-measure tag CMD-dropped on rows is a
  no-op instead of wiping the zone.
- AddField now routes every selection through appendChipsToZone +
  setPivotRows / setPivotColumns. This adds cross-zone dedup (a time
  grain or tag bulk-add cannot duplicate something already placed in
  the other zone) and removes the remaining addPivotField calls in
  this file.
- modifier-key.ts: drop the unnecessary derived store and just cast the
  writable to Readable<boolean>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nishantmonu51 nishantmonu51 merged commit 81b6433 into main Jun 4, 2026
14 of 15 checks passed
@nishantmonu51 nishantmonu51 deleted the nishant/pivot-table-tags branch June 4, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants