Skip to content

feat: introduce SearchINput component#834

Open
ikondrat wants to merge 1 commit intomainfrom
add-search-input
Open

feat: introduce SearchINput component#834
ikondrat wants to merge 1 commit intomainfrom
add-search-input

Conversation

@ikondrat
Copy link
Copy Markdown
Contributor

@ikondrat ikondrat commented Mar 25, 2026

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)

SearchInput Component Introduction

Added a new SearchInput Svelte component to support text-based search with image upload capabilities in the GridSearch feature.

Component Implementation

The SearchInput.svelte component provides:

  • Two-way binding of search query text via the queryText prop
  • Search input field with a leading search icon and trailing image upload button
  • Visual feedback for drag-over state (active ring styling)
  • Dynamic input state management (disabled during image uploads)
  • Event handlers for keyboard input and clipboard paste operations
  • Configurable upload trigger through the triggerFileInput callback

Props Interface

  • queryText: string (bindable for two-way binding)
  • isUploading: boolean (controls input disabled state and upload button availability)
  • dragOver: boolean (applies visual ring styling to indicate drag-over state)
  • onkeydown: KeyboardEvent handler
  • onpaste: async ClipboardEvent handler
  • triggerFileInput: Callback to initiate file input

Test Coverage

Comprehensive test suite (SearchInput.test.ts) covering:

  • Placeholder text switching based on upload state
  • Query text display in input field
  • Drag-over visual styling
  • Input disabled state during uploads
  • Keyboard and paste event handling
  • Upload button click functionality and upload-state disabling
  • SVG icon rendering (exactly 2 icons)
  • Proper test identifiers (data-testid)

Metrics

  • Component: +43 lines
  • Tests: +82 lines

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Added a new SearchInput Svelte component that provides a text input field with a leading search icon and trailing upload-image button. The component supports two-way binding for query text, visual drag-over feedback, upload state management, and delegates keyboard/paste/upload events through callback handlers. Corresponding test suite validates all component behavior and event flows.

Changes

Cohort / File(s) Summary
SearchInput Component
lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.svelte
New Svelte component with bindable queryText prop, conditional placeholder/disabled states based on isUploading, drag-over visual ring, and event handlers for keyboard input, paste events, and file upload triggering.
SearchInput Tests
lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts
New test suite verifying placeholder text changes, input value binding, drag-over styling, disabled state during upload, keyboard/paste event invocation, upload button functionality, SVG icon rendering, and input element attributes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description contains only template placeholders with no actual content, missing required sections like change summary, testing details, and changelog status. Fill in the actual change summary, describe how the SearchInput component was tested, and indicate whether CHANGELOG.md was updated.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: introduce SearchINput component' is related to the changeset but contains a typo: 'SearchINput' should be 'SearchInput'. The title is clear and specific about the main change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 add-search-input

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 and usage tips.

Copy link
Copy Markdown

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

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: db027af122

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

<Search class="absolute left-2 top-[50%] h-4 w-4 translate-y-[-50%] text-muted-foreground" />
<Input
placeholder={isUploading ? 'Uploading...' : 'Search samples by description or image'}
class="pl-8 pr-8 {dragOver ? 'ring-2 ring-primary' : ''}"
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 Compose conditional Tailwind classes with cn()

The frontend guideline in docs/coding-guidelines/frontend.md recommends using cn() for Tailwind class composition, but this line builds a conditional class string inline. Keeping conditional styling in cn() avoids brittle string interpolation and keeps class composition consistent with the rest of the codebase.

Useful? React with 👍 / 👎.

Comment on lines +9 to +10
onkeydown: (event: KeyboardEvent) => void;
onpaste: (event: ClipboardEvent) => Promise<void>;
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 Rename event callback props to camelCase

The coding guideline specifies camelCase for props, but the public prop names here are lowercase (onkeydown, onpaste). This makes the component API inconsistent with the project’s TypeScript naming conventions and propagates non-standard names to every consumer and test.

Useful? React with 👍 / 👎.

<button
class="absolute right-2 top-[50%] translate-y-[-50%] text-muted-foreground hover:text-foreground disabled:opacity-50"
onclick={triggerFileInput}
title="Upload image for search"
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 Add aria-label to icon-only upload button

This icon-only button relies on title for its label, but title is not a reliable accessible name across assistive technologies. Adding an explicit aria-label keeps the control consistently discoverable for screen-reader users while still allowing a tooltip via title if needed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts (2)

32-35: Make the drag-over style assertion more targeted.

This assertion can pass even if the ring class lands on a different element. Prefer asserting class presence on screen.getByTestId('text-embedding-search-input') directly (and optionally assert absence when dragOver is false).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts`
around lines 32 - 35, Update the test in SearchInput.test.ts so the dragOver
style assertion targets the specific input element: render SearchInput with
dragOver true and use screen.getByTestId('text-embedding-search-input') to
assert it has the 'ring-2' and 'ring-primary' classes (and add an extra
assertion that the same element does not have those classes when dragOver is
false); locate the existing test named "applies ring style when dragOver is
true" and replace the container.querySelector check with assertions against the
element returned by getByTestId.

68-71: Add a behavior test for disabled upload button clicks.

You already check disabled state; add one more check that clicking while isUploading: true does not call triggerFileInput, to lock in the interaction contract.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts`
around lines 68 - 71, Add an interaction assertion to the test that when
isUploading is true clicking the upload button does not call the helper that
opens the file picker: render the SearchInput with isUploading: true, simulate a
click on the element found by title 'Upload image for search' (e.g.,
fireEvent.click or userEvent.click) and assert that the mock function
triggerFileInput (the helper used in the component) was not called
(expect(triggerFileInput).not.toHaveBeenCalled()) to lock in the disabled
interaction contract.
lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.svelte (1)

26-40: Add explicit accessible labeling and button type semantics.

Line 26 currently relies on placeholder text for input meaning, and Lines 35-39 define an icon-only <button> without type="button". This is fragile for accessibility and can accidentally submit an enclosing form.

Suggested update
     <Input
+        aria-label="Search samples by description or image"
         placeholder={isUploading ? 'Uploading...' : 'Search samples by description or image'}
         class="pl-8 pr-8 {dragOver ? 'ring-2 ring-primary' : ''}"
         bind:value={queryText}
         {onkeydown}
         {onpaste}
         disabled={isUploading}
         data-testid="text-embedding-search-input"
     />
     <button
+        type="button"
+        aria-label="Upload image for search"
         class="absolute right-2 top-[50%] translate-y-[-50%] text-muted-foreground hover:text-foreground disabled:opacity-50"
         onclick={triggerFileInput}
         title="Upload image for search"
         disabled={isUploading}
     >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.svelte`
around lines 26 - 40, The input currently relies on placeholder text for its
accessible name — update the Input component (bound to queryText) to include an
explicit accessible label (e.g., add aria-label="Search samples by description
or image" or aria-labelledby pointing to a visible label) while preserving the
placeholder and disabled/isUploading behavior; and for the icon-only upload
button that calls triggerFileInput, add type="button" and an appropriate
aria-label (e.g., aria-label="Upload image for search") so it won't accidentally
submit a form and is accessible to screen readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.svelte`:
- Around line 26-40: The input currently relies on placeholder text for its
accessible name — update the Input component (bound to queryText) to include an
explicit accessible label (e.g., add aria-label="Search samples by description
or image" or aria-labelledby pointing to a visible label) while preserving the
placeholder and disabled/isUploading behavior; and for the icon-only upload
button that calls triggerFileInput, add type="button" and an appropriate
aria-label (e.g., aria-label="Upload image for search") so it won't accidentally
submit a form and is accessible to screen readers.

In
`@lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts`:
- Around line 32-35: Update the test in SearchInput.test.ts so the dragOver
style assertion targets the specific input element: render SearchInput with
dragOver true and use screen.getByTestId('text-embedding-search-input') to
assert it has the 'ring-2' and 'ring-primary' classes (and add an extra
assertion that the same element does not have those classes when dragOver is
false); locate the existing test named "applies ring style when dragOver is
true" and replace the container.querySelector check with assertions against the
element returned by getByTestId.
- Around line 68-71: Add an interaction assertion to the test that when
isUploading is true clicking the upload button does not call the helper that
opens the file picker: render the SearchInput with isUploading: true, simulate a
click on the element found by title 'Upload image for search' (e.g.,
fireEvent.click or userEvent.click) and assert that the mock function
triggerFileInput (the helper used in the component) was not called
(expect(triggerFileInput).not.toHaveBeenCalled()) to lock in the disabled
interaction contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 61e2e858-c2b6-438c-803f-1de534b7fdab

📥 Commits

Reviewing files that changed from the base of the PR and between 57a298d and db027af.

📒 Files selected for processing (2)
  • lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.svelte
  • lightly_studio_view/src/lib/components/GridSearch/SearchInput/SearchInput.test.ts

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