diff --git a/web/src/lib/components/shared-components/search-bar/search-bar.svelte b/web/src/lib/components/shared-components/search-bar/search-bar.svelte index 7e52b6b7b4..3ca9e35832 100644 --- a/web/src/lib/components/shared-components/search-bar/search-bar.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-bar.svelte @@ -2,12 +2,7 @@ import { AppRoute } from '$lib/constants'; import Icon from '$lib/components/elements/icon.svelte'; import { goto } from '$app/navigation'; - import { - isSearchEnabled, - preventRaceConditionSearchBar, - savedSearchTerms, - searchQuery, - } from '$lib/stores/search.store'; + import { isSearchEnabled, preventRaceConditionSearchBar, savedSearchTerms } from '$lib/stores/search.store'; import { clickOutside } from '$lib/utils/click-outside'; import { mdiClose, mdiMagnify, mdiTune } from '@mdi/js'; import IconButton from '$lib/components/elements/buttons/icon-button.svelte'; @@ -15,8 +10,10 @@ import SearchFilterBox from './search-filter-box.svelte'; import type { MetadataSearchDto, SmartSearchDto } from '@immich/sdk'; import { getMetadataSearchQuery } from '$lib/utils/metadata-search'; + export let value = ''; export let grayTheme: boolean; + export let searchQuery: MetadataSearchDto | SmartSearchDto = {}; let input: HTMLInputElement; @@ -30,8 +27,7 @@ showHistory = false; showFilter = false; $isSearchEnabled = false; - $searchQuery = payload; - goto(`${AppRoute.SEARCH}?${params}`, { invalidateAll: true }); + goto(`${AppRoute.SEARCH}?${params}`); }; const clearSearchTerm = (searchTerm: string) => { @@ -87,11 +83,11 @@ }; -
+
(value = '')} on:submit|preventDefault={onSubmit} @@ -148,9 +144,9 @@ on:selectSearchTerm={({ detail: searchTerm }) => onHistoryTermClick(searchTerm)} /> {/if} - - {#if showFilter} - onSearch(detail)} /> - {/if} + + {#if showFilter} + onSearch(detail)} /> + {/if}
diff --git a/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte b/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte index c433be947f..71b2c9d3a5 100644 --- a/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte @@ -17,7 +17,6 @@ import { fly } from 'svelte/transition'; import Combobox, { type ComboBoxOption } from '../combobox.svelte'; import { DateTime } from 'luxon'; - import { searchQuery } from '$lib/stores/search.store'; enum MediaType { All = 'all', @@ -44,7 +43,7 @@ type SearchFilter = { context?: string; - people: PersonResponseDto[]; + people: (PersonResponseDto | Pick)[]; location: { country?: ComboBoxOption; @@ -69,6 +68,8 @@ mediaType: MediaType; }; + export let searchQuery: MetadataSearchDto | SmartSearchDto; + let suggestions: SearchSuggestion = { people: [], country: [], @@ -112,19 +113,19 @@ populateExistingFilters(); }); - const showSelectedPeopleFirst = () => { - suggestions.people.sort((a, _) => { + function orderBySelectedPeopleFirst>(people: T[]) { + return people.sort((a, _) => { if (filter.people.some((p) => p.id === a.id)) { return -1; } return 1; }); - }; + } const getPeople = async () => { try { const { people } = await getAllPeople({ withHidden: false }); - suggestions.people = people; + suggestions.people = orderBySelectedPeopleFirst(people); } catch (error) { handleError(error, 'Failed to get people'); } @@ -133,14 +134,12 @@ const handlePeopleSelection = (id: string) => { if (filter.people.some((p) => p.id === id)) { filter.people = filter.people.filter((p) => p.id !== id); - showSelectedPeopleFirst(); return; } const person = suggestions.people.find((p) => p.id === id); if (person) { filter.people = [...filter.people, person]; - showSelectedPeopleFirst(); } }; @@ -280,35 +279,36 @@ }; function populateExistingFilters() { - if ($searchQuery) { + if (searchQuery) { + const personIds = 'personIds' in searchQuery && searchQuery.personIds ? searchQuery.personIds : []; + filter = { - context: 'query' in $searchQuery ? $searchQuery.query : '', - people: - 'personIds' in $searchQuery ? ($searchQuery.personIds?.map((id) => ({ id })) as PersonResponseDto[]) : [], + context: 'query' in searchQuery ? searchQuery.query : '', + people: orderBySelectedPeopleFirst(personIds.map((id) => ({ id }))), location: { - country: $searchQuery.country ? { label: $searchQuery.country, value: $searchQuery.country } : undefined, - state: $searchQuery.state ? { label: $searchQuery.state, value: $searchQuery.state } : undefined, - city: $searchQuery.city ? { label: $searchQuery.city, value: $searchQuery.city } : undefined, + country: searchQuery.country ? { label: searchQuery.country, value: searchQuery.country } : undefined, + state: searchQuery.state ? { label: searchQuery.state, value: searchQuery.state } : undefined, + city: searchQuery.city ? { label: searchQuery.city, value: searchQuery.city } : undefined, }, camera: { - make: $searchQuery.make ? { label: $searchQuery.make, value: $searchQuery.make } : undefined, - model: $searchQuery.model ? { label: $searchQuery.model, value: $searchQuery.model } : undefined, + make: searchQuery.make ? { label: searchQuery.make, value: searchQuery.make } : undefined, + model: searchQuery.model ? { label: searchQuery.model, value: searchQuery.model } : undefined, }, date: { - takenAfter: $searchQuery.takenAfter - ? DateTime.fromISO($searchQuery.takenAfter).toUTC().toFormat('yyyy-MM-dd') + takenAfter: searchQuery.takenAfter + ? DateTime.fromISO(searchQuery.takenAfter).toUTC().toFormat('yyyy-MM-dd') : undefined, - takenBefore: $searchQuery.takenBefore - ? DateTime.fromISO($searchQuery.takenBefore).toUTC().toFormat('yyyy-MM-dd') + takenBefore: searchQuery.takenBefore + ? DateTime.fromISO(searchQuery.takenBefore).toUTC().toFormat('yyyy-MM-dd') : undefined, }, - isArchive: $searchQuery.isArchived, - isFavorite: $searchQuery.isFavorite, - isNotInAlbum: 'isNotInAlbum' in $searchQuery ? $searchQuery.isNotInAlbum : undefined, + isArchive: searchQuery.isArchived, + isFavorite: searchQuery.isFavorite, + isNotInAlbum: 'isNotInAlbum' in searchQuery ? searchQuery.isNotInAlbum : undefined, mediaType: - $searchQuery.type === AssetTypeEnum.Image + searchQuery.type === AssetTypeEnum.Image ? MediaType.Image - : $searchQuery.type === AssetTypeEnum.Video + : searchQuery.type === AssetTypeEnum.Video ? MediaType.Video : MediaType.All, }; @@ -344,7 +344,7 @@ {#each peopleList as person (person.id)} {/each}
@@ -498,7 +498,7 @@
-
+

MEDIA TYPE

diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index 239df2f844..6608550200 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -69,7 +69,6 @@ export enum QueryParameter { PREVIOUS_ROUTE = 'previousRoute', QUERY = 'query', SEARCHED_PEOPLE = 'searchedPeople', - SEARCH_TERM = 'q', SMART_SEARCH = 'smartSearch', PAGE = 'page', } diff --git a/web/src/lib/stores/search.store.ts b/web/src/lib/stores/search.store.ts index ded7dc17ae..41fd287f4c 100644 --- a/web/src/lib/stores/search.store.ts +++ b/web/src/lib/stores/search.store.ts @@ -1,8 +1,6 @@ -import type { MetadataSearchDto, SmartSearchDto } from '@immich/sdk'; import { persisted } from 'svelte-local-storage-store'; import { writable } from 'svelte/store'; export const savedSearchTerms = persisted('search-terms', [], {}); export const isSearchEnabled = writable(false); export const preventRaceConditionSearchBar = writable(false); -export const searchQuery = writable(undefined); diff --git a/web/src/routes/(user)/search/+page.svelte b/web/src/routes/(user)/search/+page.svelte index 354a84bd89..fd84071d32 100644 --- a/web/src/routes/(user)/search/+page.svelte +++ b/web/src/routes/(user)/search/+page.svelte @@ -1,5 +1,4 @@ + +
{#if isMultiSelectionMode}
@@ -252,44 +221,43 @@
goto(previousRoute)} backIcon={mdiArrowLeft}>
- +
{/if}
-{#if terms} -
- {#each Object.keys(terms) as key, index (index)} -
-
- {getHumanReadableSearchKey(key)} -
- - {#if terms[key] !== true} -
- {#if key === 'takenAfter' || key === 'takenBefore'} - {getHumanReadableDate(terms[key])} - {:else if key === 'personIds'} - {#await getPersonName(terms[key]) then personName} - {personName} - {/await} - {:else} - {terms[key]} - {/if} -
- {/if} +
+ {#each getObjectKeys(terms) as key (key)} + {@const value = terms[key]} +
+
+ {getHumanReadableSearchKey(key)}
- {/each} -
-{/if} + + {#if value !== true} +
+ {#if (key === 'takenAfter' || key === 'takenBefore') && typeof value === 'string'} + {getHumanReadableDate(value)} + {:else if key === 'personIds' && Array.isArray(value)} + {#await getPersonName(value) then personName} + {personName} + {/await} + {:else} + {value} + {/if} +
+ {/if} +
+ {/each} +
- {#if albums && albums.length > 0} + {#if searchResultAlbums.length > 0}
ALBUMS