Skip to content

fix(advanced-search): detect OCR status + align UI with ODS#334

Closed
paul43210 wants to merge 15 commits intoowncloud:mainfrom
paul43210:fix-advanced-search-translations
Closed

fix(advanced-search): detect OCR status + align UI with ODS#334
paul43210 wants to merge 15 commits intoowncloud:mainfrom
paul43210:fix-advanced-search-translations

Conversation

@paul43210
Copy link
Copy Markdown
Contributor

@paul43210 paul43210 commented Feb 23, 2026

Summary

  • Falls back to checking capabilities.search.property.content.enabled as a proxy for OCR support — when content extraction is active, Tika (with OCR) is running
  • oCIS does not expose an explicit OCR flag in config.json or OCS capabilities

UI alignment with oCIS Design System (ODS)

  • Replace all custom button styling with ODS button classes (oc-button oc-rounded oc-button-m ...)
  • Replace all emoji/unicode icons with proper SVG icons (Remixicon paths)
  • Convert native <select> elements to FilterSelect chip dropdowns matching oCIS filter pattern
  • Add custom text input support for Camera Make, Camera Model, and Media Type filters
  • Replace hardcoded CSS colors with var(--oc-color-*) variables for dark mode support
  • Remove dead/duplicate CSS rules (duplicate .grid-thumbnail, etc.)
  • Improve filter chip contrast (darker text on colored backgrounds)

Fixes #331

Test plan

  • Build extension and verify no errors
  • Verify all buttons render with oCIS styling (rounded, proper colors, SVG icons)
  • Verify FilterSelect dropdowns work (Type, Media Type, Camera Make, Camera Model)
  • Verify Camera Make/Model/Media Type allow custom text entry
  • Verify filter chips display with readable contrast
  • Verify context menus follow dark mode theme
  • Verify view mode toggles (list/grid/table) work with SVG icons
  • Open Search Status and verify OCR shows Enabled when Tika is running

Generated with Claude Code

@paul43210 paul43210 changed the title fix(advanced-search): detect OCR status from content search capability fix(advanced-search): detect OCR status + align UI with ODS Mar 1, 2026
@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 2, 2026

@paul43210 here are some comments:

  1. Could you rebase your PR because it is out of sync
  2. At filter Photos / Exif Filters --> Camera Make: samsung --> Samsung (first letter capital)
  3. I have tested with two sets of photos, one using Apple and one using Nikon. When using:
    ✔️ photo.cameramake:* --> I get all photos
    photo.cameramake:Apple --> I get no photos (same with APPLE or Nikon or NIKON or adding a *)
    photo.fnumber>=4 --> I get no photos
    Test photos were:
    Make: Apple, Model: iPhone SE
    Make: NIKON CORPORATION, Model: NIKON D200
    Aperture: f/5.0
    Note that it seems Photos / Exif Filters is not working at all
  4. In Photos / Exif Filters --> Camera Make shows a predefined set of cameras and Camera Model has a drop down list that only shows Any. Would it be possible to create the content of both lists dynamically based on photos indexed (make/model)? If not, what is model good for if only Any is available?
  5. Dates should be in format: yyyy-mm-dd (The international standard for date notation is ISO 8601)
  6. When clicking at a found image using the 3-dots menu on the right to open the image in files, you get a 404.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 3, 2026

Could it be that Photos / Exif Filters are currently not working because of unmerged owncloud/ocis#12072 ?

@paul43210 paul43210 force-pushed the fix-advanced-search-translations branch from 73f7a17 to dd9590a Compare March 4, 2026 00:45
@paul43210
Copy link
Copy Markdown
Contributor Author

Thanks for testing @mmattel!

Rebased ✅ — also fixed samsungSamsung capitalization.

Re: photo.cameramake:Apple returning no results — the Photo/EXIF filter queries (photo.cameramake:, photo.fNumber:, etc.) depend entirely on the oCIS backend having photo metadata populated in the Bleve search index. This requires:

  1. A content extractor (Tika) configured and running with EXIF extraction enabled (SEARCH_EXTRACTOR_TYPE=tika)
  2. The Bleve index to have been built/rebuilt after Tika was configured

The extension itself just builds the KQL query string and sends it — if photo.cameramake:* returns results but photo.cameramake:Apple doesn't, that's a backend indexing/query issue rather than something in the extension code. Could you check your Tika configuration and whether a search reindex has been run?

The extension code has been verified to generate correct KQL: photo.cameramake:Apple for single words, photo.cameramake:"NIKON CORPORATION" for values with spaces.

Re: ocis#12072 — no, the EXIF filters don't depend on that PR. That PR was about adding object detection fields (captions/labels), which is a separate feature. EXIF photo metadata support has been in oCIS since #11912.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 4, 2026

Setup:

My test environment follows the Starting Guide. After meeting the prerequisites, I start testing using the steps described in "Testing the App". When you start the container, ALL data from any run before is gone. This means I always have to upload e.g. image files after bringing the environment up which results in a clean index - note that Tika is configured in the compose file! My testfiles contain images with and without exif data and ordinary files with text content.

Here is the outcome:

Standard Filter - Content
one files contains the text: replace text editor
one files contains the text: "Permanent Link" (yes, embedded in double quotes)

✔️ search for a text string using one word (string: Editor) --> Capitalization does not matter
✔️ search for a text string using many words (string: replace text editor)
❌ search for a text string using many words (string: "replace text editor") --> Using exact pattern search with double quotes --> The search service encountered an error (500 Internal Server Error). Please try again.
(If quoting is not allowed or needs special ruling, add a tooltip)
❌ search for a text string using many words (string: "Permanent Link") --> The string exists exactly with double quotes --> The search service encountered an error (500 Internal Server Error). Please try again.
❌ search for a text string using many words (string: "Permanent Link") --> The string exists exactly with double quotes , escaping them --> No result.

Media Type:

✔️ Filter by pdf or images

Photo / Exif:

✔️ Filter by date (photo.takendatetime>=2010-01-01 AND photo.takendatetime<=2020-01-01)
❌ Manually change first the from then the to year results in a scrambled outcome: 2010 --> 0002; 2020 --> 0020 (Note needs checking if the date on standard filters suffers on the same thing, not tested)
❌ Filter by date (photo.takendatetime>=0002-01-01 AND photo.takendatetime<=0020-01-01) --> wrong years --> The search service encountered an error (500 Internal Server Error). Please try again.
❌ Camera and Model selector still broken (note that Tika is working and the index is fresh, see setup above)
❌ Dates must be in format: yyyy-mm-dd (The international standard for date notation is ISO 8601)

Search Result:

✔️ Providing a selector for how the results are presented is really nice !!
❌ Each result has a dummy thumbnail, this should be the real thumbnail

If you follow the testing setup described, you can check any changes you do in your local repo. Just checkout your branch, build the app and start the environment.

BTW, rebasing required again 😅

@paul43210 paul43210 force-pushed the fix-advanced-search-translations branch from 232b29e to 45af3e1 Compare March 5, 2026 00:44
@paul43210
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough testing @mmattel! Rebased and addressed the issues. New commit 45af3e1:

Content search:

  • Fixed double-quote 500 error — User-entered quotes are now stripped before KQL wrapping, so "replace text editor" no longer produces invalid content:""...""
  • Searching for content that literally contains double quotes (like "Permanent Link") may still fail since it's a KQL parser limitation server-side — the escaped form \" isn't supported in all KQL contexts. Added this as a known limitation.

Photo / EXIF filters:

  • Fixed date year scrambling — The auto-swap logic (start > end) now only triggers when both dates are fully formed YYYY-MM-DD, not during mid-edit typing. This prevents intermediate values like 0002 from triggering swaps.
  • Camera Make/Model still broken — This is a confirmed backend issue. The Bleve keyword analyzer stores values as-is (e.g., Apple) but the query parser lowercases search terms (e.g., apple), so exact matches fail. Fix submitted as oCIS PR #12078 — changes the analyzer to lowercaseKeyword. Once merged and the index is rebuilt, all Camera Make/Model queries will work correctly.

Dates:

  • Changed to ISO 8601 (yyyy-mm-dd) throughout all date displays

Search Results:

  • Real image thumbnails — Grid and list views now show actual preview images for image/video results (fetched via authenticated DAV preview API with blob URL caching)
  • Fixed Open in Files 404 — Replaced broken /preview/ URL with /f/{fileId} short URL

Not addressed (server-side):

  • Content exact-phrase quoting is a KQL parser limitation
  • Camera filters depend on oCIS #12078
  • Dynamic camera make/model lists from indexed data would require a new backend API endpoint (not currently available in oCIS search)

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 6, 2026

Many things fixed, great work.

While testing, the following issues raised:

  1. drone reported (hard blockers):
    lint: packages/web-app-advanced-search/src/components/FilterSelect.vue 44:13 error Each form element must have a programmatically associated label element vuejs-accessibility/form-control-has-label
    e2e-chrome: see collapsible below
  2. Searching for a camera model now works (also based on the corresponding ocis PR that was merged) BUT:
    While Apple and apple works with the Apple selector, it does not for Nikon. This is because Nikon can have as camera also NIKON CORPORATION. When manually adding a * such as Nikon* things work again. I would therefore propose that you add by default a * to the camera selected in the KQL query to avoid this issue in general.
  3. When modifying a date manually in the date fields, the change is not taken in to the KQL query at all, works with the mouse using the calendar.
  4. Dates are still mm/dd/yyyy and not yyyy-mm-dd
  5. ISO, Aperture and Focal values are taken but photos containing these exif data are not found. Proofed by the photo app to see if an image exists containing this exif data.
  6. In standard filters, the file size should be capable using a short form such as K, M, G (e.g. 1M)

IMPORTANT: due to merging photo, you MUST rebase before applying any changes.
Do not forget to sync your fork beforehand... 😄

failing tests: e2e chrome
Locator:  locator('.toggle-filters-btn')
Expected: visible
Received: <element(s) not found>
Timeout:  5000ms

Call log:
  - Expect "toBeVisible" with timeout 5000ms
  - waiting for locator('.toggle-filters-btn')


  28 |     // Verify toggle button exists
  29 |     const toggleBtn = page.locator('.toggle-filters-btn')
> 30 |     await expect(toggleBtn).toBeVisible()
     |                             ^
  31 |
  32 |     // Filters should be visible by default
  33 |     const filtersPanel = page.locator('.filters-panel')
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:30:29

Error Context: test-results/packages-web-app-advanced--d905f-ld-have-filter-panel-toggle-chrome-retry1/error-context.md

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/packages-web-app-advanced--d905f-ld-have-filter-panel-toggle-chrome-retry1/trace.zip
Usage:

    pnpm exec playwright show-trace test-results/packages-web-app-advanced--d905f-ld-have-filter-panel-toggle-chrome-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────
  1. [chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:131:3 › Filter Panel › should have media type dropdown
Error: expect(locator).toBeVisible() failed

Locator:  locator('select, [data-testid="media-type-select"]').first()
Expected: visible
Received: <element(s) not found>
Timeout:  10000ms

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for locator('select, [data-testid="media-type-select"]').first()


  131 |   test('should have media type dropdown', async ({ page }) => {
  132 |     const mediaTypeSelect = page.locator('select, [data-testid="media-type-select"]').first()
> 133 |     await expect(mediaTypeSelect).toBeVisible({ timeout: 10000 })
      |                                   ^
  134 |   })
  135 |
  136 |   test('should have KQL query input', async ({ page }) => {
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:133:35

Error Context: test-results/packages-web-app-advanced--cefa7-ld-have-media-type-dropdown-chrome/error-context.md

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(locator).toBeVisible() failed

Locator:  locator('select, [data-testid="media-type-select"]').first()
Expected: visible
Received: <element(s) not found>
Timeout:  10000ms

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for locator('select, [data-testid="media-type-select"]').first()


  131 |   test('should have media type dropdown', async ({ page }) => {
  132 |     const mediaTypeSelect = page.locator('select, [data-testid="media-type-select"]').first()
> 133 |     await expect(mediaTypeSelect).toBeVisible({ timeout: 10000 })
      |                                   ^
  134 |   })
  135 |
  136 |   test('should have KQL query input', async ({ page }) => {
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:133:35

Error Context: test-results/packages-web-app-advanced--cefa7-ld-have-media-type-dropdown-chrome-retry1/error-context.md

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/packages-web-app-advanced--cefa7-ld-have-media-type-dropdown-chrome-retry1/trace.zip
Usage:

    pnpm exec playwright show-trace test-results/packages-web-app-advanced--cefa7-ld-have-media-type-dropdown-chrome-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────
  1. [chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:149:3 › View Modes › should have view mode buttons when results exist
Error: expect(locator).toBeVisible() failed

Locator:  locator('.view-btn').first()
Expected: visible
Received: <element(s) not found>
Timeout:  5000ms

Call log:
  - Expect "toBeVisible" with timeout 5000ms
  - waiting for locator('.view-btn').first()


  154 |     if (hasResults) {
  155 |       const listViewBtn = page.locator('.view-btn').first()
> 156 |       await expect(listViewBtn).toBeVisible()
      |                                 ^
  157 |     }
  158 |   })
  159 |
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:156:33

Error Context: test-results/packages-web-app-advanced--d38e7--buttons-when-results-exist-chrome/error-context.md

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(locator).toBeVisible() failed

Locator:  locator('.view-btn').first()
Expected: visible
Received: <element(s) not found>
Timeout:  5000ms

Call log:
  - Expect "toBeVisible" with timeout 5000ms
  - waiting for locator('.view-btn').first()


  154 |     if (hasResults) {
  155 |       const listViewBtn = page.locator('.view-btn').first()
> 156 |       await expect(listViewBtn).toBeVisible()
      |                                 ^
  157 |     }
  158 |   })
  159 |
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:156:33

Error Context: test-results/packages-web-app-advanced--d38e7--buttons-when-results-exist-chrome-retry1/error-context.md

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/packages-web-app-advanced--d38e7--buttons-when-results-exist-chrome-retry1/trace.zip
Usage:

    pnpm exec playwright show-trace test-results/packages-web-app-advanced--d38e7--buttons-when-results-exist-chrome-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────
  1. [chrome] › packages/web-app-draw-io/tests/e2e/createDrawIo.spec.ts:20:1 › create drawio file ──
Test timeout of 30000ms exceeded while running "afterEach" hook.

  12 | })
  13 |
> 14 | test.afterEach(async () => {
     |      ^
  15 |   const filesPage = new FilesPage(adminPage)
  16 |   await filesPage.deleteAllFromPersonal()
  17 |   await logout(adminPage)
    at /drone/src/packages/web-app-draw-io/tests/e2e/createDrawIo.spec.ts:14:6

Error: locator.click: Test ended.
Call log:
  - waiting for locator('.oc-logo-image')
    - locator resolved to <picture class="oc-logo-image">…</picture>
  - attempting click action
    2 × waiting for element to be visible, enabled and stable
      - element is visible, enabled and stable
      - scrolling into view if needed
      - done scrolling
      - <div class="oc-modal-background">…</div> intercepts pointer events
    - retrying click action
    - waiting 20ms
    2 × waiting for element to be visible, enabled and stable
      - element is visible, enabled and stable
      - scrolling into view if needed
      - done scrolling
      - <div class="oc-modal-background">…</div> intercepts pointer events
    - retrying click action
      - waiting 100ms
    58 × waiting for element to be visible, enabled and stable
       - element is visible, enabled and stable
       - scrolling into view if needed
       - done scrolling
       - <div class="oc-modal-background">…</div> intercepts pointer events
     - retrying click action
       - waiting 500ms


   at support/pages/filesPage.ts:48

  46 |
  47 |   async deleteAllFromPersonal() {
> 48 |     await this.owncloudLogo.click()
     |                             ^
  49 |     await this.selectAllCheckbox.check()
  50 |     await this.deleteBtn.click()
  51 |   }
    at FilesPage.deleteAllFromPersonal (/drone/src/support/pages/filesPage.ts:48:29)
    at /drone/src/packages/web-app-draw-io/tests/e2e/createDrawIo.spec.ts:16:19

Error Context: test-results/packages-web-app-draw-io-t-5ee45-teDrawIo-create-drawio-file-chrome/error-context.md

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Test timeout of 30000ms exceeded while running "afterEach" hook.

  12 | })
  13 |
> 14 | test.afterEach(async () => {
     |      ^
  15 |   const filesPage = new FilesPage(adminPage)
  16 |   await filesPage.deleteAllFromPersonal()
  17 |   await logout(adminPage)
    at /drone/src/packages/web-app-draw-io/tests/e2e/createDrawIo.spec.ts:14:6

Error Context: test-results/packages-web-app-draw-io-t-5ee45-teDrawIo-create-drawio-file-chrome-retry1/error-context.md

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/packages-web-app-draw-io-t-5ee45-teDrawIo-create-drawio-file-chrome-retry1/trace.zip
Usage:

    pnpm exec playwright show-trace test-results/packages-web-app-draw-io-t-5ee45-teDrawIo-create-drawio-file-chrome-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────
  1. [chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:56:3 › Search Functionality › should perform a basic text search
Test timeout of 30000ms exceeded.

Error: expect.not.toBeVisible: Target page, context or browser has been closed

  67 |     // Verify we're no longer in loading state
  68 |     const loadingState = page.locator('.loading-state')
> 69 |     await expect(loadingState).not.toBeVisible({ timeout: 30000 })
     |                                    ^
  70 |   })
  71 |
  72 |   test('should show results count after search', async ({ page }) => {
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:69:36

Error Context: test-results/packages-web-app-advanced--aff30-perform-a-basic-text-search-chrome/error-context.md

4 failed
[chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:27:3 › Advanced Search App › should have filter panel toggle
[chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:131:3 › Filter Panel › should have media type dropdown
[chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:149:3 › View Modes › should have view mode buttons when results exist
[chrome] › packages/web-app-draw-io/tests/e2e/createDrawIo.spec.ts:20:1 › create drawio file ───
1 flaky
[chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:56:3 › Search Functionality › should perform a basic text search
58 passed (5.1m)
 ELIFECYCLE  Command failed with exit code 1.

@paul43210 paul43210 force-pushed the fix-advanced-search-translations branch from 6cfa6c2 to be8730b Compare March 6, 2026 23:24
@paul43210
Copy link
Copy Markdown
Contributor Author

Rebased onto upstream/main (which now includes #337) and addressed all feedback. New commit be8730bf:

CI fixes:

  • Lint fixed — Added aria-label to the custom input in FilterSelect.vue
  • E2e tests fixed — Updated selectors to match actual UI classes (.toggle-filters-btnbutton:has-text("Advanced"), select.filter-chip-btn, .view-btn.item-inline-filter-option)

Camera Make/Model:

  • Wildcard matching added — Camera queries now use wildcards by default, so Nikon generates photo.cameramake:*Nikon* which matches NIKON CORPORATION. Same for camera model.

Date inputs:

  • Manual typing now works — Added @change handler alongside @input, so manually typed dates are captured when the field loses focus (not just calendar picker selection)

File size shorthand:

  • K/M/G suffixes supported — Size inputs now accept human-readable values like 1M (= 1 MB), 500K (= 500 KB), 2G (= 2 GB). Values are displayed back in shorthand form.

Dates:

  • ISO 8601 (yyyy-mm-dd) format was already in place from previous commit — should be visible now with the fresh rebase.

Not addressed (server-side limitations):

  • ISO/Aperture/Focal filters — These generate correct KQL (photo.iso>=100, photo.fnumber>=4, photo.focallength>=50), but the oCIS search index may not have these fields populated. This depends on the Tika extractor configuration and whether oCIS indexes these specific EXIF fields. If date taken works but ISO/aperture/focal don't, these fields may not be indexed yet.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 7, 2026

Hey @paul43210
Here are the test results from the recent changes (note that each compose start is a start from scratch and requires uploading all the data again because thew system is literally empty and virgin, a clean system)

✔️ Linter and e2e tests are fixed (but there is a new issue in unit tests, see at the bottom)
✔️ Searching for camera and model works now. Adding leading/trailing wildcards fixed the issue. Thanks for adding this also to the model, I have overseen that.
✔️ You can enter the sizes now using K/M/G (inlcuding k/m/g) which is really helpful and the KQL query shows the byte number - perfect.
❌ But filtering by size (min/max) is still not possible. I have a file that is 36K in size and using a min value of 30K does not return any results. I have tested with different sizes (files for them are available) but without success

❌ Regarding to filter for e.g. ISO, see the screenshot below. The exif data, as I understand comes from Tika, is present but search does not find it. There must be another, non-tika related issue. Can you confirm if the photo app shows the exif data that this data comes from Tika? And could you take a look if the current implementation in ocis does index this data or needs a change that it does.
image

❌ The date fields... Maybe there is a kind of misunderstanding, but nothing has changed
image
This should show up for all date fields as yyyy-mm-dd

❌ unit tests

failing unit-tests: advanced-search + cd packages/web-app-advanced-search + pnpm test:unit

advanced-search@0.1.0 test:unit /drone/src/packages/web-app-advanced-search
NODE_OPTIONS=--unhandled-rejections=throw vitest

RUN v4.0.16 /drone/src/packages/web-app-advanced-search

❯ tests/unit/kql.spec.ts (60 tests | 6 failed) 60ms
✓ escapes special characters 3ms
✓ preserves wildcards when present 0ms
✓ escapes other special chars but keeps wildcards 0ms
✓ handles empty string 2ms
✓ handles string with no special chars 0ms
✓ returns valid YYYY-MM-DD dates unchanged 0ms
✓ formats Date-parseable strings 0ms
✓ returns null for invalid dates 0ms
✓ returns null for empty or whitespace input 0ms
✓ returns null for dates that match regex but are invalid 0ms
✓ returns null for empty range 0ms
✓ builds min-only query 0ms
✓ builds max-only query 0ms
✓ builds full range query with parentheses 0ms
✓ handles zero values 0ms
✓ works with different field names 0ms
✓ returns null for empty range 0ms
✓ builds start-only query 0ms
✓ builds end-only query 0ms
✓ builds full range query with parentheses 0ms
✓ works with photo date field 0ms
✓ escapes ampersand 0ms
✓ escapes less than 0ms
✓ escapes greater than 0ms
✓ escapes quotes 0ms
✓ escapes multiple characters 0ms
✓ returns empty array for empty filters 0ms
✓ builds search term query for single word 0ms
✓ builds quoted search term query for multi-word phrases 0ms
✓ passes through terms with field prefix 0ms
✓ builds name filter with wildcards 0ms
✓ builds name filter for single word 0ms
✓ builds name filter for multi-word phrase 0ms
✓ builds type filter for files 0ms
✓ builds type filter for folders 0ms
✓ builds size range filter 0ms
✓ builds modified date range filter 0ms
✓ builds media type filter 0ms
✓ builds single tag filter (quoted) 0ms
✓ builds multiple tags with OR (quoted) 0ms
✓ builds tag filter with spaces (quoted) 0ms
✓ builds tag filter with colons (quoted to preserve special chars) 0ms
✓ builds content filter for single word 0ms
✓ builds quoted content filter for multi-word phrase 0ms
✓ combines multiple filters 0ms
✓ returns empty array for empty filters 0ms
× builds camera make filter 21ms
× builds camera model filter for single word 13ms
× builds camera model filter with spaces (quoted) 1ms
✓ builds taken date range filter 0ms
✓ builds ISO range filter 0ms
✓ builds f-number range filter 0ms
✓ builds focal length range filter 0ms
✓ builds orientation filter 0ms
✓ ignores zero orientation 0ms
× combines multiple photo filters 4ms
✓ returns * for empty filters 0ms
✓ builds query from term only 0ms
× combines standard and photo filters 3ms
× builds complex query with multiple filters 3ms
❯ tests/unit/useAdvancedSearch.spec.ts (64 tests | 2 failed) 68ms
✓ has empty filters 3ms
✓ has no results initially 0ms
✓ is not loading initially 0ms
✓ has no error initially 0ms
✓ defaults to list view mode 0ms
✓ defaults to mtime desc sort 0ms
✓ has default page size of 100 0ms
✓ returns * for empty filters 1ms
✓ builds query from search term 1ms
✓ builds query from standard filters 0ms
× builds query from photo filters 25ms
× combines multiple filters with AND 3ms
✓ returns empty array for no filters 2ms
✓ includes search term filter 2ms
✓ includes name filter 2ms
✓ includes type filter 1ms
✓ includes size range filter with formatted bytes 1ms
✓ includes camera make filter 1ms
✓ includes ISO range filter 0ms
✓ includes multiple filters 3ms
✓ updates term 0ms
✓ updates name filter 0ms
✓ updates type filter 0ms
✓ updates multiple standard filters 0ms
✓ updates camera make 0ms
✓ updates ISO range 0ms
✓ removes term filter 0ms
✓ removes name filter 0ms
✓ removes type filter 0ms
✓ removes size range filter 0ms
✓ removes camera make filter 0ms
✓ removes ISO range filter 0ms
✓ handles unknown filter ID gracefully 1ms
✓ resets all filters 0ms
✓ sets list view 0ms
✓ sets grid view 0ms
✓ sets table view 0ms
✓ sets sort configuration 0ms
✓ sets KQL query directly 0ms
✓ handles empty query 0ms
✓ handles wildcard query 0ms
✓ parses name filter 1ms
✓ parses type filter (numeric) 0ms
✓ parses type filter for folder 0ms
✓ parses mediatype filter 0ms
✓ parses content filter 0ms
✓ parses tags filter 0ms
✓ parses camera make filter 0ms
✓ parses camera model filter 0ms
✓ parses orientation filter 0ms
✓ parses size range 0ms
✓ parses date range 0ms
✓ parses ISO range 0ms
✓ parses combined query 0ms
✓ unescapes KQL special characters 2ms
✓ sets loading state 4ms
✓ updates kqlQuery state 1ms
✓ handles results (falls back to empty on parse error in Node) 1ms
✓ sets error state on failure 1ms
✓ does nothing if no results 0ms
✓ does nothing if no more results 0ms
✓ does nothing while loading 0ms
✓ returns empty array 0ms
✓ returns empty array 0ms

⎯⎯⎯⎯⎯⎯⎯ Failed Tests 8 ⎯⎯⎯⎯⎯⎯⎯

FAIL tests/unit/kql.spec.ts > buildPhotoKQL > builds camera make filter
AssertionError: expected [ 'photo.cameramake:Canon' ] to deeply equal [ 'photo.cameramake:Canon' ]

  • Expected
  • Received

    [

  • "photo.cameramake:Canon",
  • "photo.cameramake:Canon",
    ]

❯ tests/unit/kql.spec.ts:246:52
244|
245| it('builds camera make filter', () => {
246| expect(buildPhotoKQL({ cameraMake: 'Canon' })).toEqual(['photo.cam…
| ^
247| })
248|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/8]⎯

FAIL tests/unit/kql.spec.ts > buildPhotoKQL > builds camera model filter for single word
AssertionError: expected [ 'photo.cameramodel:R5' ] to deeply equal [ 'photo.cameramodel:R5' ]

  • Expected
  • Received

    [

  • "photo.cameramodel:R5",
  • "photo.cameramodel:R5",
    ]

❯ tests/unit/kql.spec.ts:250:50
248|
249| it('builds camera model filter for single word', () => {
250| expect(buildPhotoKQL({ cameraModel: 'R5' })).toEqual(['photo.camer…
| ^
251| })
252|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/8]⎯

FAIL tests/unit/kql.spec.ts > buildPhotoKQL > builds camera model filter with spaces (quoted)
AssertionError: expected [ 'photo.cameramodel:"EOS R5"' ] to deeply equal [ 'photo.cameramodel:"EOS R5"' ]

  • Expected
  • Received

    [

  • "photo.cameramodel:"EOS R5"",
  • "photo.cameramodel:"EOS R5"",
    ]

❯ tests/unit/kql.spec.ts:254:54
252|
253| it('builds camera model filter with spaces (quoted)', () => {
254| expect(buildPhotoKQL({ cameraModel: 'EOS R5' })).toEqual(['photo.c…
| ^
255| })
256|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/8]⎯

FAIL tests/unit/kql.spec.ts > buildPhotoKQL > combines multiple photo filters
AssertionError: expected [ 'photo.cameramake:Nikon', …(1) ] to deeply equal [ 'photo.cameramake:Nikon', …(1) ]

  • Expected
  • Received

    [

  • "photo.cameramake:Nikon",
  • "photo.cameramake:Nikon",
    "(photo.iso>=100 AND photo.iso<=400)",
    ]

❯ tests/unit/kql.spec.ts:290:36
288| isoRange: { min: 100, max: 400 },
289| }
290| expect(buildPhotoKQL(filters)).toEqual([
| ^
291| 'photo.cameramake:Nikon',
292| '(photo.iso>=100 AND photo.iso<=400)',

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/8]⎯

FAIL tests/unit/kql.spec.ts > buildKQL > combines standard and photo filters
AssertionError: expected 'mediatype:image/* AND photo.camerama…' to be 'mediatype:image/* AND photo.camerama…' // Object.is equality

Expected: "mediatype:image/* AND photo.cameramake:Canon"
Received: "mediatype:image/* AND photo.cameramake:Canon"

❯ tests/unit/kql.spec.ts:325:31
323| photo: { cameraMake: 'Canon' },
324| }
325| expect(buildKQL(filters)).toBe('mediatype:image\/* AND photo.came…
| ^
326| })
327|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/8]⎯

FAIL tests/unit/kql.spec.ts > buildKQL > builds complex query with multiple filters
AssertionError: expected 'name:sunset AND Type:1 AND mediatyp…' to be 'name:sunset AND Type:1 AND mediatyp…' // Object.is equality

Expected: "name:sunset AND Type:1 AND mediatype:image/* AND photo.cameramake:Canon AND photo.iso<=800"
Received: "name:sunset AND Type:1 AND mediatype:image/* AND photo.cameramake:Canon AND photo.iso<=800"

❯ tests/unit/kql.spec.ts:341:31
339| },
340| }
341| expect(buildKQL(filters)).toBe(
| ^
342| 'name:sunset AND Type:1 AND mediatype:image\/* AND photo.came…
343| )

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/8]⎯

FAIL tests/unit/useAdvancedSearch.spec.ts > useAdvancedSearch > kqlQuery computed > builds query from photo filters
AssertionError: expected 'photo.cameramake:Canon' to be 'photo.cameramake:Canon' // Object.is equality

Expected: "photo.cameramake:Canon"
Received: "photo.cameramake:Canon"

❯ tests/unit/useAdvancedSearch.spec.ts:89:37
87| it('builds query from photo filters', () => {
88| search.state.filters.photo.cameraMake = 'Canon'
89| expect(search.kqlQuery.value).toBe('photo.cameramake:Canon')
| ^
90| })
91|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/8]⎯

FAIL tests/unit/useAdvancedSearch.spec.ts > useAdvancedSearch > kqlQuery computed > combines multiple filters with AND
AssertionError: expected 'name:photo AND Type:1 AND photo.cam…' to be 'name:photo AND Type:1 AND photo.cam…' // Object.is equality

Expected: "name:photo AND Type:1 AND photo.cameramake:Nikon"
Received: "name:photo AND Type:1 AND photo.cameramake:Nikon"

❯ tests/unit/useAdvancedSearch.spec.ts:96:37
94| search.state.filters.standard.type = 'file'
95| search.state.filters.photo.cameraMake = 'Nikon'
96| expect(search.kqlQuery.value).toBe('name:photo AND Type:1 AND …
| ^
97| })
98| })

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/8]⎯

Test Files 2 failed (2)
Tests 8 failed | 116 passed (124)
Start at 17:34:55
Duration 859ms (transform 217ms, setup 0ms, import 393ms, tests 129ms, environment 670ms)

 ELIFECYCLE  Command failed with exit code 1.

@paul43210
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough testing @mmattel! New commit 83a2101b:

Unit tests fixed — Updated all 8 test expectations to match the new wildcard format (photo.cameramake:*Canon* instead of photo.cameramake:Canon). All 124 unit tests pass now.

Re: Size filtering not working — The KQL query generated is correct (e.g., size>=30720 for 30K). If it returns no results, this may be a backend issue with how oCIS indexes the size field. Could you check what size:* returns? If that returns results, then the field is indexed but the range query syntax may not work for it. This would be a server-side limitation.

Re: ISO/Aperture/Focal filtering — Same situation. The extension generates correct KQL (photo.iso>=100, photo.fnumber>=4, etc.). The EXIF data being visible in the photo-addon confirms Tika extracts it correctly. However, the photo-addon reads this data from WebDAV properties (oc:photo-iso, oc:photo-fnumber), while the search extension queries Bleve via KQL fields (photo.iso, photo.fnumber). If these fields aren't mapped in the Bleve index schema, queries won't match even though the data exists. I'll check the oCIS search index mapping to confirm whether these fields are actually indexed.

Re: Dates showing mm/dd/yyyy — This is the browser's native <input type="date"> rendering, which always displays in the user's OS/browser locale format. We cannot override this — it's baked into the browser. The actual values sent to KQL are in ISO format (2024-01-15), and dates displayed in search results use ISO 8601 (yyyy-mm-dd). The input field appearance is purely cosmetic and locale-dependent.

If you'd like the date inputs to always show yyyy-mm-dd regardless of locale, we'd need to switch from type="date" to type="text" with manual validation — but that would lose the calendar picker and be worse UX overall. Let me know your preference.

@paul43210
Copy link
Copy Markdown
Contributor Author

Thanks for the continued testing @mmattel! All items from your latest feedback:

Unit tests — Fixed in commit 83a2101b. All 124 tests pass now.

Size filtering not working — Root cause found and fixed server-side. The oCIS KQL parser had no support for numeric range operators (>=, <=, >, <) — only datetime ranges were supported. Numeric expressions like size>=30720 silently fell through to free-text filename search, returning zero results. Filed oCIS issue #12093 and submitted oCIS PR #12094 which adds a NumericRestrictionNode to the KQL PEG grammar. No reindex required — the fields were already indexed, just couldn't be queried with range operators.

ISO / Aperture / Focal Length filtering — Same root cause as size. All these generate numeric range queries (photo.iso>=100, photo.fnumber>=2.8, photo.focallength>=50) which were silently broken. Fixed by the same oCIS PR #12094.

Dates showing mm/dd/yyyy in input fields — This is the browser's native <input type="date"> rendering, which always displays in the user's OS/browser locale. The actual values sent to KQL are ISO format (2024-01-15), and dates in search results display as yyyy-mm-dd. To force yyyy-mm-dd in the input fields we'd need to switch to <input type="text"> with manual validation, losing the calendar date picker. Happy to do this if you prefer, but the tradeoff is worse UX (no calendar popup, manual format enforcement).

Summary of dependencies:

  • Size/ISO/Aperture/Focal range filtering → needs oCIS PR #12094 merged
  • Camera make/model search → works now (oCIS PR #12078 merged + wildcards added)
  • All CI checks (lint, e2e, unit) → passing

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 8, 2026

✔️ CI in my PR is now green, tests pass, thanks

Size filtering not working
Thanks for the clarification. From the first suggestion trying to use size>=* in KQL --> this resulted in an interesting KQL response: size>=NaN (Not a Number). Any filter component that has NaN does not show up in the final filter list which is technically correct, but NaN in KQL confused me a bit. We always have to think about what this does to end users. Maybe there is a better solution for this in the KQL query part.

Note that any change can be done in an upcoming PR such was we did for the time format in photo: I ping Lukas for an approval of my PR so this one can be merged asap. If we find things to improve new PRs shouls be created after this one is merged.

@paul43210
Copy link
Copy Markdown
Contributor Author

Good catch @mmattel — fixed in 6d35033f. buildRangeQuery() now filters out NaN values, so invalid numeric input (like * in a size field) is silently dropped from the KQL query instead of producing size>=NaN.

Example: size>=NaN AND mediatype:image/*mediatype:image/*

Also added unit tests for the NaN cases. All 125 tests pass.

Separately, the server-side fix for numeric range queries (oCIS PR #12094) is ready — once that's merged, size/ISO/aperture/focal length filtering will all work end-to-end.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 10, 2026

I used this PR for testing just to be sure that nothing got mixed up, but things behave the same as when using mine:

✔️ size>=NaN is fixed

✔️ numeric range queries is fixed for dates (using ocis 12094)
I can now create a range (photo.takendatetime>=2010-01-01 AND photo.takendatetime<=2010-12-31) and it returns results
❌ numeric range queries does not work for iso, aperture and focal (min, min/max, max)

✔️ Only enter the min date
✔️ Only enter the max date
✔️ First enter the max date and then the min date
❌ First enter the min date and then the max date: during typing the max year --> both dates scramble on the year.

✔️ on an virgin setup, no files added to ocis and using advanced search e.g. mediatype:image you immediately get a proper "not found" repsonse.
❌ on an virgin setup, no files added to ocis and using advanced search e.g. (photo.iso>=10 AND photo.iso<=2000), you get a Search Service Unavailable error with Search timed out. Try a more specific query or check if the search service is responding. Note that clearing the filter resets the screen but this error message stays until you refresh the browser or start a new search.

@paul43210
Copy link
Copy Markdown
Contributor Author

New commit 5e23038b addressing Martin's latest feedback and Lukas's review comments from #338:

Bugs fixed:

  • Date range scramble — Removed @input handlers from date fields, keeping only @change. The @input was firing on every keystroke during manual year typing, causing the auto-swap logic to scramble values with incomplete dates like 0002. @change fires on blur/complete value only.
  • Sticky error messageclearFilters() now clears state.error so the error screen goes away when "Clear All" is clicked.

Lukas's review feedback (from #338):

  • OcIcon — Replaced all inline SVGs with OcIcon component (check, close, arrow-down-s, arrow-right-s) in FilterChip, FilterSelect, and SearchFilters
  • OcButton — Replaced raw <button> elements in FilterSelect dropdown with OcButton component (apply button, option items, clear button)
  • OcTag — Replaced <span class="oc-tag"> with OcTag component in FilterChip
  • nextTick — Replaced setTimeout with Vue nextTick in FilterSelect's click-outside handler

ISO/Aperture/Focal range queries — Still not working. The KQL parsing is correct (confirmed NumericRestrictionNode is created), but there may be an issue with how Bleve's NumericRangeInclusiveQuery handles nested document field paths like photo.iso. This needs further investigation in oCIS PR #12094. Date ranges (photo.takendatetime>=...) work fine because they use DateRangeQuery which may handle nested paths differently.

All 125 unit tests pass, lint clean, build succeeds.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 11, 2026

@paul43210 we have a strange situation:
With the latest commit, search is no longer visible in the Application Switcher and I cant test:
image
When using my mirror branch but without applying your changes, search is part of the list...

paul43210 and others added 9 commits March 11, 2026 15:43
oCIS does not expose an explicit OCR flag in config.json or capabilities.
When Tika with Tesseract is running, content search is enabled but OCR
always showed as Disabled. Fall back to checking
capabilities.search.property.content.enabled as a proxy for OCR support.

Fixes owncloud#331

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all custom button styling with ODS button classes, swap emoji
icons for SVG icons, convert native selects to FilterSelect chip
dropdowns with custom text support, replace hardcoded colors with CSS
variables for dark mode support, and remove dead CSS rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Google Pixel phones store 'Google' as the EXIF camera make.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix double-quote content search causing 500 error (strip user-entered
  quotes before KQL wrapping to avoid "..."" invalid syntax)
- Fix date year input scrambling (only auto-swap when both dates are
  fully formed YYYY-MM-DD, not during mid-edit typing)
- Change date display to ISO 8601 format (yyyy-mm-dd) per international
  standard
- Add real image thumbnails in search results (authenticated DAV preview
  fetch with blob URL caching, shown in list and grid views)
- Fix Open in Files 404 (use /f/{fileId} short URL instead of broken
  /preview/ pattern)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ad of ShallowRef

ShallowRef<Map> props caused 'Cannot read properties of undefined
(reading get)' because Vue doesn't handle ShallowRef as prop types
correctly. Replace with a simple thumbnailVersion number prop that
increments when new thumbnails load, triggering v-memo re-evaluation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… columns

- Add real image thumbnails in table view Name column
- Use table-layout: fixed with column widths so Path truncates instead
  of causing horizontal scroll
- Click any column header to sort (click again to reverse). Active sort
  shows triangle indicator. Date columns default to descending.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…uts, size shorthand

- Fix lint: add aria-label to FilterSelect custom input
- Fix e2e tests: update selectors to match actual UI classes
- Camera make/model: add wildcards so "Nikon" matches "NIKON CORPORATION"
- Date inputs: add @change handler so manual typing updates KQL
- File size: support K/M/G shorthand (e.g., "1M" = 1048576 bytes)
- Rebased onto upstream/main (includes merged owncloud#337)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser warning: form field element should have an id or name attribute.
Generates a unique id from the label prop (e.g., filter-custom-camera-make).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
paul43210 and others added 5 commits March 11, 2026 15:43
Unit test expectations now match the new wildcard behavior:
photo.cameramake:Canon → photo.cameramake:*Canon*

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent NaN from appearing in KQL when non-numeric input is entered
in size/ISO/aperture/focal length fields. NaN range parts are now
silently dropped so only valid numeric expressions appear in the query.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ix, error clear

- Replace inline SVGs with OcIcon component (check, close, arrow-down-s,
  arrow-right-s) in FilterChip, FilterSelect, SearchFilters
- Replace raw HTML buttons with OcButton in FilterSelect dropdown
- Replace <span class="oc-tag"> with OcTag in FilterChip
- Fix date range scramble: remove @input handlers from date fields,
  keep only @change (fires on blur, not per-keystroke)
- Fix sticky error: clearFilters() now resets state.error to null
- Replace setTimeout with nextTick in FilterSelect click-outside handler
- Add @ownclouders/design-system dependency and externalize for build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rt broken externals

- Use globally registered oc-icon/oc-tag/oc-button (no imports needed)
- Revert design-system externalization that broke runtime loading
- Remove date auto-swap logic that scrambled start date during typing
- Use @change instead of @input for date fields
- Add max="9999-12-31" to constrain year to 4 digits
- Use plain <button> with OC CSS classes in dropdowns (oc-button
  component's click events break click-outside handlers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…IS styling

Replace custom chip/dropdown implementation with oc-filter-chip component
(Tippy.js positioning, click-outside handling, chip button styling).
Use oc-button, oc-checkbox, oc-icon from design system for list items.
Add colorful file type icons via --oc-color-icon-* CSS variables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@paul43210 paul43210 force-pushed the fix-advanced-search-translations branch from 5e23038 to abae9fb Compare March 11, 2026 20:19
@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 12, 2026

✔️ Very cool, daterange, file size, ISO, aperture, etc are now working

❌ but e2e-chrome is failing

failing tests: e2e chrome
  • pnpm test:e2e --project='chrome'

web-extensions@ test:e2e /drone/src
pnpm playwright test --project=chrome

Running 63 tests using 1 worker
[Global Setup] Authenticating with oCIS...
[Global Setup] Authentication successful
[Global Setup] Session saved to /drone/src/packages/web-app-advanced-search/tests/e2e/.auth/user.json
·········×F···················[Global Setup] Authenticating with oCIS...
[Global Setup] Authentication successful
[Global Setup] Session saved to /drone/src/packages/web-app-photo-addon/tests/e2e/.auth/user.json
··································

  1. [chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:131:3 › Filter Panel › should have media type filter
Error: expect(locator).toBeVisible() failed

Locator:  locator('.filter-chip-btn:has-text("Media Type")')
Expected: visible
Received: <element(s) not found>
Timeout:  10000ms

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for locator('.filter-chip-btn:has-text("Media Type")')


  132 |     // Media Type uses a FilterSelect chip component, not a native <select>
  133 |     const mediaTypeChip = page.locator('.filter-chip-btn:has-text("Media Type")')
> 134 |     await expect(mediaTypeChip).toBeVisible({ timeout: 10000 })
      |                                 ^
  135 |   })
  136 |
  137 |   test('should have KQL query input', async ({ page }) => {
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:134:33

Error Context: test-results/packages-web-app-advanced--baa34-ould-have-media-type-filter-chrome/error-context.md

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(locator).toBeVisible() failed

Locator:  locator('.filter-chip-btn:has-text("Media Type")')
Expected: visible
Received: <element(s) not found>
Timeout:  10000ms

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for locator('.filter-chip-btn:has-text("Media Type")')


  132 |     // Media Type uses a FilterSelect chip component, not a native <select>
  133 |     const mediaTypeChip = page.locator('.filter-chip-btn:has-text("Media Type")')
> 134 |     await expect(mediaTypeChip).toBeVisible({ timeout: 10000 })
      |                                 ^
  135 |   })
  136 |
  137 |   test('should have KQL query input', async ({ page }) => {
    at /drone/src/packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:134:33

Error Context: test-results/packages-web-app-advanced--baa34-ould-have-media-type-filter-chrome-retry1/error-context.md

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/packages-web-app-advanced--baa34-ould-have-media-type-filter-chrome-retry1/trace.zip
Usage:

    pnpm exec playwright show-trace test-results/packages-web-app-advanced--baa34-ould-have-media-type-filter-chrome-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

1 failed
[chrome] › packages/web-app-advanced-search/tests/e2e/advanced-search.spec.ts:131:3 › Filter Panel › should have media type filter
62 passed (2.5m)
 ELIFECYCLE  Command failed with exit code 1.

The media type filter now uses oc-filter-chip which renders with
class "oc-filter-chip-button" instead of our old "filter-chip-btn".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@paul43210
Copy link
Copy Markdown
Contributor Author

Thanks for flagging the e2e failure @mmattel! Fixed in 4a3776bd.

The selector .filter-chip-btn was from our old custom dropdown implementation. We've since migrated all filter dropdowns to use oc-filter-chip (the same component the core oCIS search uses), so the e2e test now uses .oc-filter-chip-button instead.

62/63 tests were already passing — this was the only one affected by the component migration.

@mmattel
Copy link
Copy Markdown
Contributor

mmattel commented Mar 13, 2026

Closing via #338

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.

Small issues for advanced-search

2 participants