Skip to content

feat: Introduce component updates to support categorical metadata - #1795

Open
ikondrat wants to merge 2 commits into
mainfrom
feature/lig-9585-categorical-metadata-distribution.components
Open

feat: Introduce component updates to support categorical metadata#1795
ikondrat wants to merge 2 commits into
mainfrom
feature/lig-9585-categorical-metadata-distribution.components

Conversation

@ikondrat

@ikondrat ikondrat commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

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 distribution support, including filtering, selection, sorting, orientation controls, loading states, retries, and error handling.
    • Added customizable category names and sort labels across distribution headers and dialogs.
    • Added support for categorical values in filter chips, including clear distinction between literal and missing values.
    • Added pinned-item handling and stable ID selection for manual and top-N distribution views.
  • Bug Fixes

    • Improved chart spacing and prevented clicks on non-selectable bars.

@ikondrat
ikondrat requested a review from a team as a code owner July 29, 2026 10:31
@coderabbitai

coderabbitai Bot commented Jul 29, 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: 4a25d35b-c784-4361-8301-e8e5d301cf13

📥 Commits

Reviewing files that changed from the base of the PR and between 1c71452 and d68ba25.

📒 Files selected for processing (1)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte
🚧 Files skipped from review as they are similar to previous changes (1)
  • lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte

📝 Walkthrough

Walkthrough

The distribution panel now supports categorical metadata buckets, selection, sorting, configuration, loading/error states, expanded views, accessibility summaries, and retry handling. Shared chart, header, dialog, selection, histogram, and filter-chip components were generalized and covered with tests.

Changes

Categorical distribution support

Layer / File(s) Summary
Categorical contracts and controls
lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts, .../PanelHeader/*, .../DistributionConfigDialog/*, .../ExpandDialog/*
Categorical bucket state, configurable labels and sort text, manual selection items, and value-oriented expanded/configuration flows are added.
Categorical panel orchestration
lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte, .../DatasetDistributionPanel.test.ts
The panel derives categorical chart data and per-group configuration, routes value toggles and retries, and renders categorical controls, chart states, errors, and accessibility summaries.
Selection and chart layout
lightly_studio_view/src/lib/components/BarChart/*, .../selectVisibleCounts*, .../Histogram/*, .../MetadataFilterChips/*
Selection uses stable IDs and preserves pinned items; charts support configurable top padding and selectable clicks, while filter chips render categorical values and distinguish missing-value variants.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MetadataCategoricalFilter
  participant DatasetDistributionPanel
  participant BarChart
  User->>MetadataCategoricalFilter: toggle categorical value
  MetadataCategoricalFilter->>DatasetDistributionPanel: value toggle callback
  DatasetDistributionPanel->>BarChart: derived bucket data and chart options
  BarChart->>DatasetDistributionPanel: selectable bar click
Loading

Possibly related PRs

Suggested reviewers: leonardorosaa

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only contains the template prompts and no actual summary, testing details, or changelog status. Replace the template text with a real change summary, testing steps/results, and explicitly mark the CHANGELOG.md checkbox.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main change: adding categorical metadata support to components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/lig-9585-categorical-metadata-distribution.components

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

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

Copy link
Copy Markdown

❌  Fast Track: checks did not pass

Guardrail Result Message
dummy Always passes.
frontend/complexity 16 file(s) checked, no violations.
backend/complexity 0 file(s) checked.
backend/coverage 0 file(s) checked.
diff-size PR adds 726 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/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/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

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

@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: 3

🧹 Nitpick comments (6)
lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte (1)

361-377: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the shared Button for the inline retry.

The full-error state at Line 448 uses the Button component while this refetch-error retry is a raw <button> with underline; styling/focus treatment diverges. A Button with variant="link"/size="sm" keeps both retries consistent.

🤖 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/DatasetDistributionPanel.svelte`
around lines 361 - 377, Replace the raw retry button in the activeCategorical
error block with the shared Button component, using variant="link" and size="sm"
while preserving its type, click handler, label, and existing layout classes.
Match the full-error retry implementation for consistent styling and focus
treatment.
lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter.svelte (1)

78-78: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hardcoded top-N assumptions.

Not in top 20 and the > 5 search threshold both bake in numbers owned elsewhere (the distribution hook's limit). If the bucket limit changes, this text silently lies. Consider deriving the wording from a shared constant or a prop.

Also applies to: 139-141

🤖 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.svelte`
at line 78, Replace the hardcoded bucket-limit assumptions in
MetadataCategoricalFilter, including the showSearch threshold and “Not in top
20” wording, with the distribution hook’s shared limit or an explicit prop. Use
that single source for both the displayed top-N text and search behavior so they
remain consistent when the limit changes.
lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.svelte (1)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer the exported DistributionSortOption key type.

ExpandDialog types the same prop as Record<DistributionSortOption, string>; using keyof typeof DISTRIBUTION_SORT_LABELS here is equivalent but inconsistent across the layer.

♻️ Proposed tweak
-        sortLabels?: Record<keyof typeof DISTRIBUTION_SORT_LABELS, string>;
+        sortLabels?: Record<DistributionSortOption, string>;

Update the import accordingly:

-    import { DISTRIBUTION_SORT_LABELS, type DistributionConfig } from '../types';
+    import {
+        DISTRIBUTION_SORT_LABELS,
+        type DistributionConfig,
+        type DistributionSortOption
+    } from '../types';
🤖 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/PanelHeader/PanelHeader.svelte`
at line 26, Update the sortLabels prop type in PanelHeader to use the exported
DistributionSortOption key type, matching ExpandDialog. Adjust the related
import and leave the existing prop behavior unchanged.
lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.test.ts (1)

141-147: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Negative class assertions are weak.

Asserting the absence of mb-2/mb-1 passes for any unrelated class rename, so it won't catch spacing regressions. If the intent is consistent chart spacing, asserting the actual expected wrapper classes (or the chart grid.top, as done in ExpandDialog.test.ts) is more durable.

🤖 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/PanelHeader/PanelHeader.test.ts`
around lines 141 - 147, Strengthen the “does not add plot-specific bottom
margins” test in the PanelHeader test suite by asserting the expected spacing
classes on the summary element and its parent, rather than only asserting mb-2
and mb-1 are absent. Align the assertions with the intended chart spacing
contract and the durable grid.top approach used by ExpandDialog.test.
lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts (1)

42-56: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document mutual exclusivity like the sibling fields.

data/histogram both state they are mutually exclusive; categorical doesn't, yet DatasetDistributionPanel prefers categorical over data when both are set. A one-line comment keeps the contract discoverable.

♻️ Proposed doc tweak
-    /** Controlled categorical distribution and selection state. */
+    /**
+     * Controlled categorical distribution and selection state. Takes precedence
+     * over `data` and is mutually exclusive with `histogram`.
+     */
     categorical?: {
🤖 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/types.ts`
around lines 42 - 56, Add a concise documentation comment to the categorical
field in the relevant type definition stating that categorical and
data/histogram distribution states are mutually exclusive, matching the sibling
field contracts. Preserve the existing DatasetDistributionPanel precedence and
type shape.
lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.test.ts (1)

273-276: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Order assertion is really a sort-by-count assertion.

The bucket counts (4, 3, 2) already match sortBy: 'count', so this passes even if bucket order were not preserved. Using counts that differ from bucket order would actually pin the behavior the test name claims. The hardcoded rgba(59,217,159,0.85) is also worth importing from the chart's colour constant if one is exported.

🤖 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/DatasetDistributionPanel.test.ts`
around lines 273 - 276, The test data in DatasetDistributionPanel should use
bucket counts whose descending count order differs from the original bucket
order, so the assertion verifies that sortBy: 'count' reorders buckets rather
than merely matching the existing order. Update the expected order accordingly,
and replace the hardcoded selected-item color with the chart color constant if
an exported symbol is available.
🤖 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/DatasetDistributionPanel.svelte`:
- Around line 489-498: Unify the manual-selector data contract between
DatasetDistributionPanel’s DistributionConfigDialog usage and ExpandDialog:
determine whether the dialog should consume stable item ids or labels, then
remove the redundant allClasses/items prop and update the consuming logic and
call sites to use the single source consistently. Preserve the displayed labels
while retaining stable ids for selection.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/DistributionConfigDialog/DistributionConfigDialog.svelte`:
- Around line 22-38: Expose an optional singular itemNoun prop in
DistributionConfigDialog alongside itemNounPlural, defaulting to the existing
singular label, and forward it to the manual selector and relevant categorical
wording. Update ClassSetConfigDialog integration so its itemNoun value is passed
through while preserving existing plural-label behavior.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/ExpandDialog/ExpandDialog.svelte`:
- Around line 100-104: Align the prop contract between DistributionConfigDialog
call sites: inspect how DatasetDistributionPanel uses allClasses and items, then
either remove the redundant allClasses prop everywhere or pass it from
ExpandDialog alongside items if it is required. Update the component’s
declaration and all call sites consistently.

---

Nitpick comments:
In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.svelte`:
- Around line 361-377: Replace the raw retry button in the activeCategorical
error block with the shared Button component, using variant="link" and size="sm"
while preserving its type, click handler, label, and existing layout classes.
Match the full-error retry implementation for consistent styling and focus
treatment.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/DatasetDistributionPanel.test.ts`:
- Around line 273-276: The test data in DatasetDistributionPanel should use
bucket counts whose descending count order differs from the original bucket
order, so the assertion verifies that sortBy: 'count' reorders buckets rather
than merely matching the existing order. Update the expected order accordingly,
and replace the hardcoded selected-item color with the chart color constant if
an exported symbol is available.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/MetadataCategoricalFilter.svelte`:
- Line 78: Replace the hardcoded bucket-limit assumptions in
MetadataCategoricalFilter, including the showSearch threshold and “Not in top
20” wording, with the distribution hook’s shared limit or an explicit prop. Use
that single source for both the displayed top-N text and search behavior so they
remain consistent when the limit changes.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.svelte`:
- Line 26: Update the sortLabels prop type in PanelHeader to use the exported
DistributionSortOption key type, matching ExpandDialog. Adjust the related
import and leave the existing prop behavior unchanged.

In
`@lightly_studio_view/src/lib/components/DatasetDistributionPanel/PanelHeader/PanelHeader.test.ts`:
- Around line 141-147: Strengthen the “does not add plot-specific bottom
margins” test in the PanelHeader test suite by asserting the expected spacing
classes on the summary element and its parent, rather than only asserting mb-2
and mb-1 are absent. Align the assertions with the intended chart spacing
contract and the durable grid.top approach used by ExpandDialog.test.

In `@lightly_studio_view/src/lib/components/DatasetDistributionPanel/types.ts`:
- Around line 42-56: Add a concise documentation comment to the categorical
field in the relevant type definition stating that categorical and
data/histogram distribution states are mutually exclusive, matching the sibling
field contracts. Preserve the existing DatasetDistributionPanel precedence and
type shape.
🪄 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: d91f7e1f-3c37-4091-98f0-bdf621fea6c7

📥 Commits

Reviewing files that changed from the base of the PR and between 60e1646 and 1c71452.

📒 Files selected for processing (18)
  • 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/MetadataFilterChips/MetadataFilterChips.svelte
  • lightly_studio_view/src/lib/components/MetadataFilterChips/MetadataFilterChips.test.ts

Comment on lines +489 to +498
<DistributionConfigDialog
bind:open={configDialogOpen}
allClasses={displayedData.map((item) => item.label)}
items={configurationItems}
config={activeViewConfig}
showCountMode={!activeCategorical}
itemNounPlural={activeCategorical ? 'values' : 'classes'}
sortLabels={activeCategorical ? CATEGORICAL_DISTRIBUTION_SORT_LABELS : undefined}
onApply={applyConfig}
/>

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Both allClasses and items are passed to DistributionConfigDialog.

allClasses carries labels while items carries stable ids — two sources of truth for the manual selector, and ExpandDialog passes only items. Whichever the dialog actually consumes, one call site is wrong or one prop is dead. See the consolidated note.

🤖 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/DatasetDistributionPanel.svelte`
around lines 489 - 498, Unify the manual-selector data contract between
DatasetDistributionPanel’s DistributionConfigDialog usage and ExpandDialog:
determine whether the dialog should consume stable item ids or labels, then
remove the redundant allClasses/items prop and update the consuming logic and
call sites to use the single source consistently. Preserve the displayed labels
while retaining stable ids for selection.

Comment on lines +22 to +38
/** Singular/plural labels used by categorical distributions. */
itemNounPlural?: string;
/** Labels for the available sort modes. */
sortLabels?: Record<DistributionSortOption, string>;
/** Invoked with the new config when the user clicks Apply. */
onApply: (config: DistributionConfig) => void;
}

let { open = $bindable(), allClasses, config, showCountMode = true, onApply }: Props = $props();
let {
open = $bindable(),
allClasses,
items,
config,
showCountMode = true,
itemNounPlural = 'classes',
sortLabels = DISTRIBUTION_SORT_LABELS,
onApply

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

Expose and forward the singular noun too.

ClassSetConfigDialog defaults itemNoun to "class" and passes it to the manual selector. Categorical callers can currently customize only the plural label, resulting in mixed “values”/“class” wording.

Proposed fix
 interface Props {
+    itemNoun?: string;
     itemNounPlural?: string;
 }
 
 let {
+    itemNoun = 'class',
     itemNounPlural = 'classes',
 }: Props = $props();
 
 <ClassSetConfigDialog
+    {itemNoun}
     {itemNounPlural}
 />

Also applies to: 64-70

🤖 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/DistributionConfigDialog/DistributionConfigDialog.svelte`
around lines 22 - 38, Expose an optional singular itemNoun prop in
DistributionConfigDialog alongside itemNounPlural, defaulting to the existing
singular label, and forward it to the manual selector and relevant categorical
wording. Update ClassSetConfigDialog integration so its itemNoun value is passed
through while preserving existing plural-label behavior.

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

items vs allClasses prop paths look inconsistent across call sites.

Here DistributionConfigDialog receives only items, while DatasetDistributionPanel passes both allClasses and items. One of the two is redundant (or allClasses is still required and missing here). See the consolidated note for the full picture.

🤖 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, Align the prop contract between DistributionConfigDialog
call sites: inspect how DatasetDistributionPanel uses allClasses and items, then
either remove the redundant allClasses prop everywhere or pass it from
ExpandDialog alongside items if it is required. Update the component’s
declaration and all call sites consistently.

@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: 1c71452558

ℹ️ 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".

@@ -0,0 +1,163 @@
<script lang="ts">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reuse the existing categorical filter component

The repository already contains MetadataCategoricalFilter/MetadataCategoricalFilter.svelte with colocated helpers, tests, stories, and a barrel export. Adding a second same-named component here duplicates that implementation, violates the component-per-folder convention, and allows fixes to drift between two versions; import and extend the existing module instead.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

Comment on lines +125 to +129
const categoricalData = $derived<CategoryCount[]>(
(activeCategorical?.buckets ?? []).map((bucket) => {
// When filteredBuckets is defined (query has returned) look up the
// filtered count for this bucket. Absent = 0 (filter removed it entirely).
const filteredBucket = activeCategorical?.filteredBuckets?.find(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Split categorical logic out of the panel

This mapping begins another substantial block of data transformation, configuration state, handlers, and presentation inside an already oversized panel. The frontend guidelines call for components under 100 lines and separate business logic from presentation; move the categorical view-model/configuration logic into a component-specific helper or hook and render its controls through a focused child component.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

import type { ClassSetSelection } from '$lib/components/ClassSetConfig';
import { type AnnotationCountMode } from '$lib/api/lightly_studio_local/types.gen';
import type { HistogramData, HistogramRange } from '$lib/components/Histogram';
import type { CategoricalMetadataBucket } from '$lib/hooks/useCategoricalMetadataDistribution/useCategoricalMetadataDistribution';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Import the bucket type through a public module

This deep import reaches into the hook implementation instead of its public module API, and the same pattern is repeated in the new filter component. Re-export CategoricalMetadataBucket from the hook barrel and import it from the module-level entry point so consumers are not coupled to the hook's implementation filename.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

Comment on lines +268 to +272
const option = echartsMock.instance.setOption.mock.lastCall?.[0] as {
yAxis: { data: string[] };
series: [{ data: { itemStyle: { color: string } }[] }];
grid: { top: number };
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Assert categorical behavior instead of ECharts internals

These assertions inspect ECharts option structure and exact rendering colors, so harmless chart-implementation changes can break the component test without changing user behavior. Keep option-shape and color checks in buildEchartsOption.test.ts; here assert the accessible categorical summary, controls, and emitted toggle behavior as required by the frontend testing guidelines.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

Comment on lines +234 to +238
const sources: DistributionSource[] = [
{
id: 'metadata',
label: 'Metadata',
groups: [

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Factor out repeated categorical source fixtures

The new categorical tests repeatedly rebuild the same nested metadata source, group, selection, and bucket structure, making this test file lengthy and brittle. Add a shared defaultCategoricalSource or builder and override only the buckets or state relevant to each case, following the frontend guideline to use default-prop helpers.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

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