Skip to content

fixed version to merge - #1806

Open
ikondrat wants to merge 1 commit into
mainfrom
feature/lig-9585-categorical-metadata-distribution.fixed
Open

fixed version to merge#1806
ikondrat wants to merge 1 commit into
mainfrom
feature/lig-9585-categorical-metadata-distribution.fixed

Conversation

@ikondrat

@ikondrat ikondrat commented Jul 30, 2026

Copy link
Copy Markdown
Contributor
  • Add useCategoricalMetadataDistribution to the $lib/hooks mock in layout.workspace.test.ts (missing after the merge brought in its usage in +layout.svelte)
  • Add itemNoun prop to DistributionConfigDialog and pass it through to ClassSetConfigDialog so the manual-selector empty state reads "No value found." for categorical distributions
  • Pass itemNoun to DistributionConfigDialog from DatasetDistributionPanel
  • Update DistributionConfigDialog test to supply itemNoun: 'value'

What has changed and why?

(Delete this: Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.)

How has it been tested?

(Delete this: Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.)

Did you update CHANGELOG.md?

  • Yes
  • Not needed (internal change)

Summary by CodeRabbit

  • New Features

    • Added categorical metadata distributions alongside existing numeric distributions.
    • Added filtering, searching, selection, clearing, sorting, and orientation controls for metadata values.
    • Categorical selections now apply consistently to image, frame, and video results.
    • Added clearer, context-aware labels such as “values” and improved handling of missing or unavailable values.
  • Bug Fixes

    • Preserved pinned and manually selected distribution items reliably.
    • Improved chart spacing and ignored clicks on non-selectable bars.
    • Preserved categorical selections and displayed results during loading or retryable errors.

- Add useCategoricalMetadataDistribution to the $lib/hooks mock in
  layout.workspace.test.ts (missing after the merge brought in its usage
  in +layout.svelte)
- Add itemNoun prop to DistributionConfigDialog and pass it through to
  ClassSetConfigDialog so the manual-selector empty state reads
  "No value found." for categorical distributions
- Pass itemNoun to DistributionConfigDialog from DatasetDistributionPanel
- Update DistributionConfigDialog test to supply itemNoun: 'value'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ikondrat
ikondrat requested a review from a team as a code owner July 30, 2026 13:03
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The PR adds categorical metadata distributions, filtering, selection chips, configuration dialogs, retry/loading states, and categorical filter propagation across image, frame, video, and infinite-image queries. Chart spacing and selectable-bar handling are also updated.

Categorical metadata distribution

Layer / File(s) Summary
Distribution contracts and controls
lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts, .../MetadataCategoricalFilter.svelte, .../PanelHeader/*, .../DistributionConfigDialog/*, .../ExpandDialog/*
Categorical bucket state, labels, filtering controls, stable selection identifiers, configurable wording, and categorical dialog options are added with coverage for missing, other, retained, and colliding values.
Distribution querying and orchestration
lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte, lightly_studio_view/src/routes/datasets/.../+layout.svelte
Categorical distribution queries, filtered bucket counts, per-group configuration, loading/error handling, retry wiring, selection callbacks, and categorical chart rendering are integrated into the dataset layout and distribution panel.
Filter state propagation
lightly_studio_view/src/lib/components/MetadataFilterChips/*, lightly_studio_view/src/lib/hooks/*, lightly_studio_view/src/routes/datasets/.../{frames,videos}/+page.svelte, lightly_studio_view/src/lib/components/Images/Images.svelte
Categorical selections are represented in chips, converted into metadata predicates, included in image/frame/video requests, and incorporated into infinite-image query keys and scroll restoration hashes.
Chart behavior and spacing
lightly_studio_view/src/lib/components/BarChart/BarChart.svelte, lightly_studio_view/src/lib/components/Histogram/buildHistogramOption.ts
Bar charts accept configurable top padding and ignore non-selectable bars; histogram axis layouts use a four-pixel top grid padding.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DatasetLayout
  participant DistributionHooks
  participant DatasetDistributionPanel
  participant MetadataCategoricalFilter
  participant FilterBuilder
  participant MediaQueries
  DatasetLayout->>DistributionHooks: request categorical buckets
  DistributionHooks-->>DatasetLayout: return buckets and filtered counts
  DatasetLayout->>DatasetDistributionPanel: provide distribution groups
  DatasetDistributionPanel->>MetadataCategoricalFilter: render value selections
  MetadataCategoricalFilter->>DatasetLayout: toggle categorical value
  DatasetLayout->>FilterBuilder: build metadata predicates
  FilterBuilder-->>MediaQueries: return categorical metadata filters
Loading

Possibly related PRs

Suggested reviewers: leonardorosaa

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The template sections are mostly left as placeholders, with no real change summary or test details filled in. Fill in What has changed and why, How has it been tested, and changelog status with concrete details.
Title check ❓ Inconclusive The title is generic and doesn't describe the actual changes in this PR. Rename it to summarize the main change, e.g. fixing test mocks and threading itemNoun through distribution config components.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/lig-9585-categorical-metadata-distribution.fixed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lightly-fast-track-bot

Copy link
Copy Markdown

❌  Fast Track: checks did not pass

Guardrail Result Message
dummy Always passes.
frontend/complexity lightly_studio_view/src/lib/hooks/useFramesFilter/frameFilter.ts:23 — Arrow function has a complexity of 25. Maximum allowed is 10. lightly_studio_view/src/lib/hooks/useVideoFilters/useVideoFilters.ts:25 — Arrow function has a complexity of 30. Maximum allowed is 10. lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/+layout.svelte:155 — Function 'handleSelectAllKeydown' has a complexity of 11. Maximum allowed is 10. lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/+layout.svelte:413 — Arrow function has a complexity of 11. Maximum allowed is 10.
backend/complexity 0 file(s) checked.
backend/coverage 0 file(s) checked.
diff-size PR adds 1322 line(s), which exceeds the limit of 215.
frontend/coverage [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts: no test file found [FAIL] lightly_studio_view/src/lib/components/Images/Images.svelte: no test file found [FAIL] lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/frames/+page.svelte: no test file found [FAIL] lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/videos/+page.svelte: no test file found [FAIL] lightly_studio_view/src/lib/components/BarChart/BarChart.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/DistributionConfigDialog/DistributionConfigDialog.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/selectVisibleCounts.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/components/Histogram/buildHistogramOption.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/components/MetadataFilterChips/MetadataFilterChips.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.svelte.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/hooks/useFramesFilter/frameFilter.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/hooks/useVideoFilters/useVideoFilters.ts: coverage data not found [FAIL] lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/+layout.svelte: coverage data not found

View the guardrail run

To run the guardrails locally, from fast_track/ run make install once, then make run-guardrails (or GUARDRAILS=<name1>,<name2> make run-guardrails for some guardrails).

Reflects 8f33b5b.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.svelte.ts (1)

115-140: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

P2 — Track categorical filter changes.

Both categorical early-return branches bypass trackFilterChanged, so enabling, disabling, or clearing categorical filters is absent from metadata_filter_changed analytics.

Proposed fix
             updateCategoricalMetadataValues({
                 ...categoricalStore.current,
                 [key]: checked ? lastCategoricalValues[key] : []
             });
+            trackFilterChanged(key, checked ? 'enabled' : 'disabled');
             return;
@@
             lastCategoricalValues = Object.fromEntries(
                 Object.entries(lastCategoricalValues).filter(([valueKey]) => valueKey !== key)
             );
+            trackFilterChanged(key, 'disabled');
             return;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.svelte.ts`
around lines 115 - 140, Update the categorical branches in the filter toggle and
clear handlers to call trackFilterChanged with the affected key and
enabled/disabled state before returning. Ensure categorical enable, disable, and
clear actions emit metadata_filter_changed analytics consistently with range
filters.
lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/layout.workspace.test.ts (1)

111-118: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add the categorical metadata members to the useMetadataFilters mock.

+layout.svelte now derives metadataInfo, categoricalMetadataValues, and updateCategoricalMetadataValues; the metadataFilters derivation subscribes to the new categorical store, so the current mock makes these tests fail with an undefined subscription error.

🛠️ Proposed mock update
 vi.mock('$lib/hooks/useMetadataFilters/useMetadataFilters.js', () => ({
     useMetadataFilters: vi.fn(() => ({
         metadataValues: writable({}),
         metadataBounds: writable({}),
-        updateMetadataValues: vi.fn()
+        metadataInfo: writable([]),
+        categoricalMetadataValues: writable({}),
+        updateMetadataValues: vi.fn(),
+        updateCategoricalMetadataValues: vi.fn()
     })),
     createMetadataFilters: vi.fn(() => undefined)
 }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightly_studio_view/src/routes/datasets/`[dataset_id]/[collection_type]/[collection_id]/layout.workspace.test.ts
around lines 111 - 118, Update the useMetadataFilters mock to provide the
categorical metadata stores and updater expected by +layout.svelte: add
writable-backed categoricalMetadataValues and a vi.fn()
updateCategoricalMetadataValues alongside the existing metadata members, so
metadataFilters can subscribe without undefined values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.svelte`:
- Around line 100-104: The ExpandDialog invocation of DistributionConfigDialog
passes the plural noun but not the singular noun, causing categorical
manual-selector text to default to “class.” Forward the corresponding singular
category noun alongside itemNounPlural, using the existing category noun symbol
from the surrounding configuration.

In
`@lightly_studio_view/src/routes/datasets/`[dataset_id]/[collection_type]/[collection_id]/+layout.svelte:
- Around line 665-675: Update the categorical distribution mapping and the
associated retry handler near onCategoricalRetry to surface failures from
categoricalMetadataFilteredQuery: expose its error when the filtered query fails
and allow retrying that query alongside the unfiltered query. Keep the existing
loading behavior unless the intended UX explicitly requires showing
filtered-query fetching as loading.

---

Outside diff comments:
In
`@lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.svelte.ts`:
- Around line 115-140: Update the categorical branches in the filter toggle and
clear handlers to call trackFilterChanged with the affected key and
enabled/disabled state before returning. Ensure categorical enable, disable, and
clear actions emit metadata_filter_changed analytics consistently with range
filters.

In
`@lightly_studio_view/src/routes/datasets/`[dataset_id]/[collection_type]/[collection_id]/layout.workspace.test.ts:
- Around line 111-118: Update the useMetadataFilters mock to provide the
categorical metadata stores and updater expected by +layout.svelte: add
writable-backed categoricalMetadataValues and a vi.fn()
updateCategoricalMetadataValues alongside the existing metadata members, so
metadataFilters can subscribe without undefined values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16b411dd-e515-4374-a795-c36b0d1aed0b

📥 Commits

Reviewing files that changed from the base of the PR and between e9fc539 and 8f33b5b.

📒 Files selected for processing (34)
  • lightly_studio_view/src/lib/components/BarChart/BarChart.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DistributionConfigDialog/DistributionConfigDialog.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DistributionConfigDialog/DistributionConfigDialog.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/selectVisibleCounts.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/selectVisibleCounts.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts
  • lightly_studio_view/src/lib/components/Histogram/buildHistogramOption.test.ts
  • lightly_studio_view/src/lib/components/Histogram/buildHistogramOption.ts
  • lightly_studio_view/src/lib/components/Images/Images.svelte
  • lightly_studio_view/src/lib/components/MetadataFilterChips/MetadataFilterChips.svelte
  • lightly_studio_view/src/lib/components/MetadataFilterChips/MetadataFilterChips.test.ts
  • lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.svelte.ts
  • lightly_studio_view/src/lib/components/MetadataFilterChips/useMetadataFilterChips.test.ts
  • lightly_studio_view/src/lib/hooks/useFramesFilter/frameFilter.test.ts
  • lightly_studio_view/src/lib/hooks/useFramesFilter/frameFilter.ts
  • lightly_studio_view/src/lib/hooks/useImageFilters/useImageFilters.test.ts
  • lightly_studio_view/src/lib/hooks/useImagesInfinite/buildRequestBody.test.ts
  • lightly_studio_view/src/lib/hooks/useImagesInfinite/createImagesInfiniteOptions.test.ts
  • lightly_studio_view/src/lib/hooks/useMetadataFilters/useMetadataFilters.test.ts
  • lightly_studio_view/src/lib/hooks/useMetadataFilters/useMetadataFilters.ts
  • lightly_studio_view/src/lib/hooks/useVideoFilters/useVideoFilters.test.ts
  • lightly_studio_view/src/lib/hooks/useVideoFilters/useVideoFilters.ts
  • lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/+layout.svelte
  • lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/frames/+page.svelte
  • lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/layout.workspace.test.ts
  • lightly_studio_view/src/routes/datasets/[dataset_id]/[collection_type]/[collection_id]/videos/+page.svelte
💤 Files with no reviewable changes (1)
  • lightly_studio_view/src/lib/hooks/useMetadataFilters/useMetadataFilters.ts

Comment on lines +100 to +104
items={configurationItems}
{config}
{showCountMode}
itemNounPlural={categoryNounPlural}
{sortLabels}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Forward the singular category noun too.

DistributionConfigDialog defaults itemNoun to "class", so the expanded categorical manual selector will show singular class wording (for example, “No class found.”) despite receiving itemNounPlural="values".

Proposed fix
     items={configurationItems}
     {config}
     {showCountMode}
+    itemNoun={categoryNoun}
     itemNounPlural={categoryNounPlural}
     {sortLabels}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
items={configurationItems}
{config}
{showCountMode}
itemNounPlural={categoryNounPlural}
{sortLabels}
items={configurationItems}
{config}
{showCountMode}
itemNoun={categoryNoun}
itemNounPlural={categoryNounPlural}
{sortLabels}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.svelte`
around lines 100 - 104, The ExpandDialog invocation of DistributionConfigDialog
passes the plural noun but not the singular noun, causing categorical
manual-selector text to default to “class.” Forward the corresponding singular
category noun alongside itemNounPlural, using the existing category noun symbol
from the surrounding configuration.

Comment on lines +665 to +675
categorical: {
buckets: categoricalMetadataDistributions[key] ?? [],
// undefined until the filtered query has returned so the
// distribution panel waits before showing background bars.
filteredBuckets: categoricalMetadataFilteredDistributions?.[key],
selectedValues: $categoricalMetadataValues[key] ?? [],
loading: categoricalMetadataQuery.isFetching,
error: categoricalMetadataQuery.error?.message
}
}))
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Retry and error surfacing only cover the unfiltered categorical query.

error/loading come solely from categoricalMetadataQuery, and onCategoricalRetry refetches only that query. If categoricalMetadataFilteredQuery fails, filteredBuckets stays undefined forever with no error shown and no way to retry.

♻️ Suggested wiring
-                        loading: categoricalMetadataQuery.isFetching,
-                        error: categoricalMetadataQuery.error?.message
+                        loading:
+                            categoricalMetadataQuery.isFetching ||
+                            categoricalMetadataFilteredQuery.isFetching,
+                        error:
+                            categoricalMetadataQuery.error?.message ??
+                            categoricalMetadataFilteredQuery.error?.message
-                                            onCategoricalRetry={() =>
-                                                categoricalMetadataQuery.refetch()}
+                                            onCategoricalRetry={() => {
+                                                categoricalMetadataQuery.refetch();
+                                                categoricalMetadataFilteredQuery.refetch();
+                                            }}

Note that folding the filtered query's isFetching into loading will also make the "Updating values…" hint appear on filter changes — verify that is the desired UX before adopting the loading part.

Also applies to: 929-930

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightly_studio_view/src/routes/datasets/`[dataset_id]/[collection_type]/[collection_id]/+layout.svelte
around lines 665 - 675, Update the categorical distribution mapping and the
associated retry handler near onCategoricalRetry to surface failures from
categoricalMetadataFilteredQuery: expose its error when the filtered query fails
and allow retrying that query alongside the unfiltered query. Keep the existing
loading behavior unless the intended UX explicitly requires showing
filtered-query fetching as loading.

@ikondrat ikondrat changed the title Fix test mocks and thread itemNoun through DistributionConfigDialog fixed version to merge Jul 30, 2026
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.

1 participant