Skip to content

feat: introduce MetadataCategoricalFilter component - #1787

Merged
ikondrat merged 10 commits into
mainfrom
lig-9585.MetadataCategoricalFilter
Jul 28, 2026
Merged

feat: introduce MetadataCategoricalFilter component#1787
ikondrat merged 10 commits into
mainfrom
lig-9585.MetadataCategoricalFilter

Conversation

@ikondrat

@ikondrat ikondrat commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What has changed and why?

This PR introduces component to use as part of the dataset distribution panel to select values for categorical metadata values

How has it been tested?

Accompanied with unit test and storybook story for visual testing

Screen.Recording.2026-07-28.at.11.13.59.mov

Did you update CHANGELOG.md?

  • Yes
  • Not needed (internal change)

Summary by CodeRabbit

  • New Features
    • Added/updated the categorical metadata filter UI with a searchable checkbox list, selection summary text, loading-aware disabling, and a Clear control.
    • Enhanced handling of missing (null) values and retained selections not in the latest top results, including clearer “Other” and “Missing” labeling and “not in top” indicators.
  • Tests
    • Added unit and interaction test coverage for option-building and dynamic label logic, and included a Storybook story for the filter.

@ikondrat
ikondrat requested a review from a team as a code owner July 28, 2026 09:16
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0a169a05-0801-4d1c-8947-8a362513e61d

📥 Commits

Reviewing files that changed from the base of the PR and between 9d295af and cdb4dd3.

📒 Files selected for processing (5)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.test.ts

📝 Walkthrough

Walkthrough

Adds categorical bucket types and a Svelte metadata filter with searchable values, missing/other handling, retained selections, callback behavior, unit tests, component tests, and Storybook coverage.

Changes

Categorical metadata filter

Layer / File(s) Summary
Categorical bucket contracts
lightly_studio_view/src/lib/hooks/useCategoricalMetadataDistribution/types.ts, lightly_studio_view/src/lib/services/types.ts, lightly_studio_view/src/lib/hooks/useCategoricalMetadataDistribution/useCategoricalMetadataDistribution.svelte.ts
Defines value, missing, and other bucket variants, allows null categorical values, and imports the shared bucket type into the distribution hook.
Filter option and label logic
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/*
Builds selectable and retained options, excludes aggregate other buckets, and generates labels for missing, other, and retained values.
Filter behavior and rendering
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte, lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/index.ts
Implements the values popover, conditional search, checkbox selection, retained values, selection summaries, clear behavior, loading state, and named export.
Filter validation and Storybook coverage
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/*.test.ts, lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/*.test.ts, lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.stories.ts
Tests option construction, label formatting, special bucket handling, search, clearing, retained selections, and provides a default Storybook story.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MetadataCategoricalFilter
  participant buildOptions
  participant onToggle
  User->>MetadataCategoricalFilter: Open values filter
  MetadataCategoricalFilter->>buildOptions: Build selectable and retained options
  User->>MetadataCategoricalFilter: Toggle an option
  MetadataCategoricalFilter->>onToggle: Send selected categorical value
Loading

Possibly related PRs

Suggested reviewers: leonardorosaa

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: introducing the MetadataCategoricalFilter component.
Description check ✅ Passed The description covers what changed, how it was tested, and the changelog status, so it is mostly complete.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lig-9585.MetadataCategoricalFilter

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.

@ikondrat

Copy link
Copy Markdown
Contributor Author

/review

@lightly-fast-track-bot

lightly-fast-track-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

❌  Fast Track: checks did not pass

Guardrail Result Message
dummy Always passes.
frontend/complexity 14 file(s) checked, no violations.
backend/complexity 0 file(s) checked.
backend/coverage 0 file(s) checked.
diff-size PR adds 533 line(s), which exceeds the limit of 215.
frontend/coverage [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.stories.ts: no test file found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/index.ts: no test file found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/index.ts: no test file found [FAIL] lightly_studio_view/src/lib/hooks/useCategoricalMetadataDistribution/types.ts: no test file found [FAIL] lightly_studio_view/src/lib/services/types.ts: no test file found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getOptionLabel.ts: coverage data not found [FAIL] lightly_studio_view/src/lib/hooks/useCategoricalMetadataDistribution/useCategoricalMetadataDistribution.svelte.ts: 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 cdb4dd3.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c5aff6a9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@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

🤖 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/MetadataCategoricalFilter/helpers/buildOptions.ts`:
- Around line 13-33: Deduplicate selectedValues before filtering and mapping
retained options in buildOptions.ts, preserving the existing selectable
exclusion and bucket construction behavior. In buildOptions.test.ts, add
regression coverage asserting duplicate absent selections produce exactly one
retained option.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.ts`:
- Around line 3-6: Update getCheckboxLabel so a non-retained option with
bucket.count equal to one uses “sample” instead of “samples,” while preserving
the plural form for all other counts and the existing missing/retained behavior.
Add a one-sample expectation in getCheckboxLabel.test.ts covering this singular
label.
🪄 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: 258b787a-e066-4131-b30a-8efd2e243a37

📥 Commits

Reviewing files that changed from the base of the PR and between 7c5aff6 and 4d17a4b.

📒 Files selected for processing (9)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilterPopover/MetadataCategoricalFilterPopover.svelte
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/buildOptions.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getCheckboxLabel.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getOptionLabel.test.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/getOptionLabel.ts
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/helpers/index.ts

@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.

Caution

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

⚠️ Outside diff range comments (1)
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte (1)

29-37: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Cover retained boolean filter values.

buildOptions creates a retained option for stale selected values as { kind: 'value', value, ... }, so boolean selections are supported by the implementation. options.find(...)! is type-safe because FilterOption.bucket is narrowed to SelectableBucket, which excludes kind: 'other'. Add a buildOptions.test.ts case for buildOptions([], [true])/[false] to cover this retained boolean path.

🤖 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/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte`
around lines 29 - 37, The retained-value path in buildOptions needs test
coverage for boolean selections. Add buildOptions.test.ts cases exercising
buildOptions with an empty options list and selected values [true] and [false],
verifying each boolean is retained as a value option with the expected
label/value.
🧹 Nitpick comments (1)
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte (1)

78-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant optionLabel(option) computation per row (P2 style).

optionLabel(option) is invoked separately for checkboxLabel (line 81) and twice more for the title/text span (lines 84-85), recomputing getOptionLabel up to three times per rendered row. Cache it once per iteration with {@const}.

♻️ Suggested refactor
                 {`#each` visible as option (option.bucket.id)}
+                    {`@const` label = optionLabel(option)}
                     <label
                         class="flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 text-sm hover:bg-accent max-sm:min-h-11"
                     >
                         <Checkbox
                             checked={isSelected(option.bucket.value)}
                             onCheckedChange={() => onToggle(option.bucket.value)}
-                            aria-label={checkboxLabel(option)}
+                            aria-label={getCheckboxLabel(option, label)}
                         />
-                        <span class="min-w-0 flex-1 truncate" title={optionLabel(option)}
-                            >{optionLabel(option)}</span
+                        <span class="min-w-0 flex-1 truncate" title={label}
+                            >{label}</span
                         >

As per coding guidelines: "focus on code style, use succinct comments, assign style comments priority P2..." — treating this as a P2 style/perf nit.

🤖 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/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte`
around lines 78 - 89, Within the option-row iteration containing Checkbox and
the label spans, compute optionLabel(option) once with a Svelte {`@const`} binding
and reuse that value for checkboxLabel, the title attribute, and displayed text.
Preserve the existing labels and rendering behavior while eliminating repeated
optionLabel calls.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte`:
- Around line 29-37: The retained-value path in buildOptions needs test coverage
for boolean selections. Add buildOptions.test.ts cases exercising buildOptions
with an empty options list and selected values [true] and [false], verifying
each boolean is retained as a value option with the expected label/value.

---

Nitpick comments:
In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte`:
- Around line 78-89: Within the option-row iteration containing Checkbox and the
label spans, compute optionLabel(option) once with a Svelte {`@const`} binding and
reuse that value for checkboxLabel, the title attribute, and displayed text.
Preserve the existing labels and rendering behavior while eliminating repeated
optionLabel calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ec51145f-d10f-446f-86ff-d8fcb07ae089

📥 Commits

Reviewing files that changed from the base of the PR and between 4d17a4b and 9d295af.

📒 Files selected for processing (2)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter/MetadataCategoricalFilter.svelte
  • lightly_studio_view/src/lib/hooks/useCategoricalMetadataDistribution/useCategoricalMetadataDistribution.svelte.ts

@ikondrat
ikondrat enabled auto-merge July 28, 2026 16:42
@ikondrat
ikondrat added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit c1988d2 Jul 28, 2026
22 checks passed
@ikondrat
ikondrat deleted the lig-9585.MetadataCategoricalFilter branch July 28, 2026 17:17
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