fix: filter after searching by asset id (#26994)

* fix: filter after searching by asset id

* Update web/src/lib/modals/SearchFilterModal.svelte

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
This commit is contained in:
Jason Rasmussen 2026-03-18 09:32:54 -04:00 committed by GitHub
parent 88002cf7fe
commit cda4a2a5fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 111 additions and 114 deletions

View File

@ -14,11 +14,11 @@
import { t } from 'svelte-i18n';
import SearchHistoryBox from './search-history-box.svelte';
interface Props {
type Props = {
value?: string;
grayTheme: boolean;
searchQuery?: MetadataSearchDto | SmartSearchDto;
}
};
let { value = $bindable(''), grayTheme, searchQuery = {} }: Props = $props();

View File

@ -1,21 +1,14 @@
<script lang="ts" module>
export interface SearchCameraFilter {
make?: string;
model?: string;
lensModel?: string;
}
</script>
<script lang="ts">
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import type { SearchCameraFilter } from '$lib/types';
import { handlePromiseError } from '$lib/utils';
import { SearchSuggestionType, getSearchSuggestions } from '@immich/sdk';
import { Text } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
type Props = {
filters: SearchCameraFilter;
}
};
let { filters = $bindable() }: Props = $props();

View File

@ -1,18 +1,11 @@
<script lang="ts" module>
export interface SearchDateFilter {
takenBefore?: DateTime;
takenAfter?: DateTime;
}
</script>
<script lang="ts">
import type { SearchDateFilter } from '$lib/types';
import { DatePicker, Text } from '@immich/ui';
import type { DateTime } from 'luxon';
import { t } from 'svelte-i18n';
interface Props {
type Props = {
filters: SearchDateFilter;
}
};
let { filters = $bindable() }: Props = $props();

View File

@ -1,19 +1,11 @@
<script lang="ts" module>
export interface SearchDisplayFilters {
isNotInAlbum: boolean;
isArchive: boolean;
isFavorite: boolean;
}
</script>
<script lang="ts">
import type { SearchDisplayFilters } from '$lib/types';
import { Checkbox, Label, Text } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
type Props = {
filters: SearchDisplayFilters;
}
};
let { filters = $bindable() }: Props = $props();
</script>

View File

@ -1,22 +1,15 @@
<script lang="ts" module>
export interface SearchLocationFilter {
country?: string;
state?: string;
city?: string;
}
</script>
<script lang="ts">
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import type { SearchLocationFilter } from '$lib/types';
import { handlePromiseError } from '$lib/utils';
import { getSearchSuggestions, SearchSuggestionType } from '@immich/sdk';
import { Text } from '@immich/ui';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
interface Props {
type Props = {
filters: SearchLocationFilter;
}
};
let { filters = $bindable() }: Props = $props();

View File

@ -1,28 +1,5 @@
<script lang="ts" module>
import { MediaType, QueryType, validQueryTypes } from '$lib/constants';
import type { SearchDateFilter } from '../components/shared-components/search-bar/search-date-section.svelte';
import type { SearchDisplayFilters } from '../components/shared-components/search-bar/search-display-section.svelte';
import type { SearchLocationFilter } from '../components/shared-components/search-bar/search-location-section.svelte';
export type SearchFilter = {
query: string;
ocr?: string;
queryType: 'smart' | 'metadata' | 'description' | 'ocr';
personIds: SvelteSet<string>;
tagIds: SvelteSet<string> | null;
location: SearchLocationFilter;
camera: SearchCameraFilter;
date: SearchDateFilter;
display: SearchDisplayFilters;
mediaType: MediaType;
rating?: number | null;
};
</script>
<script lang="ts">
import SearchCameraSection, {
type SearchCameraFilter,
} from '$lib/components/shared-components/search-bar/search-camera-section.svelte';
import SearchCameraSection from '$lib/components/shared-components/search-bar/search-camera-section.svelte';
import SearchDateSection from '$lib/components/shared-components/search-bar/search-date-section.svelte';
import SearchDisplaySection from '$lib/components/shared-components/search-bar/search-display-section.svelte';
import SearchLocationSection from '$lib/components/shared-components/search-bar/search-location-section.svelte';
@ -31,7 +8,9 @@
import SearchRatingsSection from '$lib/components/shared-components/search-bar/search-ratings-section.svelte';
import SearchTagsSection from '$lib/components/shared-components/search-bar/search-tags-section.svelte';
import SearchTextSection from '$lib/components/shared-components/search-bar/search-text-section.svelte';
import { MediaType, QueryType, validQueryTypes } from '$lib/constants';
import { preferences } from '$lib/stores/user.store';
import type { SearchFilter } from '$lib/types';
import { parseUtcDate } from '$lib/utils/date-time';
import { generateId } from '$lib/utils/generate-id';
import { AssetTypeEnum, AssetVisibility, type MetadataSearchDto, type SmartSearchDto } from '@immich/sdk';
@ -41,10 +20,10 @@
import { t } from 'svelte-i18n';
import { SvelteSet } from 'svelte/reactivity';
interface Props {
type Props = {
searchQuery: MetadataSearchDto | SmartSearchDto;
onClose: (search?: SmartSearchDto | MetadataSearchDto) => void;
}
};
let { searchQuery, onClose }: Props = $props();
@ -66,52 +45,57 @@
return validQueryTypes.has(storedQueryType) ? storedQueryType : QueryType.SMART;
}
let query = '';
if ('query' in searchQuery && searchQuery.query) {
query = searchQuery.query;
}
if ('originalFileName' in searchQuery && searchQuery.originalFileName) {
query = searchQuery.originalFileName;
}
const asFilter = (searchQuery: SmartSearchDto | MetadataSearchDto): SearchFilter => {
let query = '';
if ('query' in searchQuery && searchQuery.query) {
query = searchQuery.query;
}
if ('originalFileName' in searchQuery && searchQuery.originalFileName) {
query = searchQuery.originalFileName;
}
let filter: SearchFilter = $state({
query,
ocr: searchQuery.ocr,
queryType: defaultQueryType(),
personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []),
tagIds:
'tagIds' in searchQuery
? searchQuery.tagIds === null
? null
: new SvelteSet(searchQuery.tagIds)
: new SvelteSet(),
location: {
country: withNullAsUndefined(searchQuery.country),
state: withNullAsUndefined(searchQuery.state),
city: withNullAsUndefined(searchQuery.city),
},
camera: {
make: withNullAsUndefined(searchQuery.make),
model: withNullAsUndefined(searchQuery.model),
lensModel: withNullAsUndefined(searchQuery.lensModel),
},
date: {
takenAfter: searchQuery.takenAfter ? toStartOfDayDate(searchQuery.takenAfter) : undefined,
takenBefore: searchQuery.takenBefore ? toStartOfDayDate(searchQuery.takenBefore) : undefined,
},
display: {
isArchive: searchQuery.visibility === AssetVisibility.Archive,
isFavorite: searchQuery.isFavorite ?? false,
isNotInAlbum: 'isNotInAlbum' in searchQuery ? (searchQuery.isNotInAlbum ?? false) : false,
},
mediaType:
searchQuery.type === AssetTypeEnum.Image
? MediaType.Image
: searchQuery.type === AssetTypeEnum.Video
? MediaType.Video
: MediaType.All,
rating: searchQuery.rating,
});
return {
query,
ocr: searchQuery.ocr,
queryType: defaultQueryType(),
queryAssetId: 'queryAssetId' in searchQuery ? searchQuery.queryAssetId : undefined,
personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []),
tagIds:
'tagIds' in searchQuery
? searchQuery.tagIds === null
? null
: new SvelteSet(searchQuery.tagIds)
: new SvelteSet(),
location: {
country: withNullAsUndefined(searchQuery.country),
state: withNullAsUndefined(searchQuery.state),
city: withNullAsUndefined(searchQuery.city),
},
camera: {
make: withNullAsUndefined(searchQuery.make),
model: withNullAsUndefined(searchQuery.model),
lensModel: withNullAsUndefined(searchQuery.lensModel),
},
date: {
takenAfter: searchQuery.takenAfter ? toStartOfDayDate(searchQuery.takenAfter) : undefined,
takenBefore: searchQuery.takenBefore ? toStartOfDayDate(searchQuery.takenBefore) : undefined,
},
display: {
isArchive: searchQuery.visibility === AssetVisibility.Archive,
isFavorite: searchQuery.isFavorite ?? false,
isNotInAlbum: 'isNotInAlbum' in searchQuery ? (searchQuery.isNotInAlbum ?? false) : false,
},
mediaType:
searchQuery.type === AssetTypeEnum.Image
? MediaType.Image
: searchQuery.type === AssetTypeEnum.Video
? MediaType.Video
: MediaType.All,
rating: searchQuery.rating,
};
};
let filter: SearchFilter = $state(asFilter(searchQuery));
const resetForm = () => {
filter = {
@ -145,6 +129,7 @@
let payload: SmartSearchDto | MetadataSearchDto = {
query: filter.queryType === 'smart' ? query : undefined,
queryAssetId: filter.queryAssetId || undefined,
ocr: filter.queryType === 'ocr' ? query : undefined,
originalFileName: filter.queryType === 'metadata' ? query : undefined,
description: filter.queryType === 'description' ? query : undefined,

View File

@ -1,6 +1,9 @@
import { MediaType } from '$lib/constants';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { QueueResponseDto, ServerVersionResponseDto } from '@immich/sdk';
import type { ActionItem } from '@immich/ui';
import type { DateTime } from 'luxon';
import type { SvelteSet } from 'svelte/reactivity';
export interface ReleaseEvent {
isAvailable: boolean;
@ -48,3 +51,41 @@ export type AssetControlContext = {
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
clearSelect: () => void;
};
export type SearchCameraFilter = {
make?: string;
model?: string;
lensModel?: string;
};
export type SearchDateFilter = {
takenBefore?: DateTime;
takenAfter?: DateTime;
};
export type SearchDisplayFilters = {
isNotInAlbum: boolean;
isArchive: boolean;
isFavorite: boolean;
};
export type SearchLocationFilter = {
country?: string;
state?: string;
city?: string;
};
export type SearchFilter = {
query: string;
ocr?: string;
queryType: 'smart' | 'metadata' | 'description' | 'ocr';
personIds: SvelteSet<string>;
tagIds: SvelteSet<string> | null;
location: SearchLocationFilter;
queryAssetId?: string;
camera: SearchCameraFilter;
date: SearchDateFilter;
display: SearchDisplayFilters;
mediaType: MediaType;
rating?: number | null;
};