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
7 changed files with 111 additions and 114 deletions

View File

@@ -14,11 +14,11 @@
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import SearchHistoryBox from './search-history-box.svelte'; import SearchHistoryBox from './search-history-box.svelte';
interface Props { type Props = {
value?: string; value?: string;
grayTheme: boolean; grayTheme: boolean;
searchQuery?: MetadataSearchDto | SmartSearchDto; searchQuery?: MetadataSearchDto | SmartSearchDto;
} };
let { value = $bindable(''), grayTheme, searchQuery = {} }: Props = $props(); 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"> <script lang="ts">
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte'; import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import type { SearchCameraFilter } from '$lib/types';
import { handlePromiseError } from '$lib/utils'; import { handlePromiseError } from '$lib/utils';
import { SearchSuggestionType, getSearchSuggestions } from '@immich/sdk'; import { SearchSuggestionType, getSearchSuggestions } from '@immich/sdk';
import { Text } from '@immich/ui'; import { Text } from '@immich/ui';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
interface Props { type Props = {
filters: SearchCameraFilter; filters: SearchCameraFilter;
} };
let { filters = $bindable() }: Props = $props(); 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"> <script lang="ts">
import type { SearchDateFilter } from '$lib/types';
import { DatePicker, Text } from '@immich/ui'; import { DatePicker, Text } from '@immich/ui';
import type { DateTime } from 'luxon';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
interface Props { type Props = {
filters: SearchDateFilter; filters: SearchDateFilter;
} };
let { filters = $bindable() }: Props = $props(); 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"> <script lang="ts">
import type { SearchDisplayFilters } from '$lib/types';
import { Checkbox, Label, Text } from '@immich/ui'; import { Checkbox, Label, Text } from '@immich/ui';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
interface Props { type Props = {
filters: SearchDisplayFilters; filters: SearchDisplayFilters;
} };
let { filters = $bindable() }: Props = $props(); let { filters = $bindable() }: Props = $props();
</script> </script>

View File

@@ -1,22 +1,15 @@
<script lang="ts" module>
export interface SearchLocationFilter {
country?: string;
state?: string;
city?: string;
}
</script>
<script lang="ts"> <script lang="ts">
import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte'; import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte';
import type { SearchLocationFilter } from '$lib/types';
import { handlePromiseError } from '$lib/utils'; import { handlePromiseError } from '$lib/utils';
import { getSearchSuggestions, SearchSuggestionType } from '@immich/sdk'; import { getSearchSuggestions, SearchSuggestionType } from '@immich/sdk';
import { Text } from '@immich/ui'; import { Text } from '@immich/ui';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
interface Props { type Props = {
filters: SearchLocationFilter; filters: SearchLocationFilter;
} };
let { filters = $bindable() }: Props = $props(); 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"> <script lang="ts">
import SearchCameraSection, { import SearchCameraSection from '$lib/components/shared-components/search-bar/search-camera-section.svelte';
type SearchCameraFilter,
} 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 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 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'; 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 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 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 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 { preferences } from '$lib/stores/user.store';
import type { SearchFilter } from '$lib/types';
import { parseUtcDate } from '$lib/utils/date-time'; import { parseUtcDate } from '$lib/utils/date-time';
import { generateId } from '$lib/utils/generate-id'; import { generateId } from '$lib/utils/generate-id';
import { AssetTypeEnum, AssetVisibility, type MetadataSearchDto, type SmartSearchDto } from '@immich/sdk'; import { AssetTypeEnum, AssetVisibility, type MetadataSearchDto, type SmartSearchDto } from '@immich/sdk';
@@ -41,10 +20,10 @@
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { SvelteSet } from 'svelte/reactivity'; import { SvelteSet } from 'svelte/reactivity';
interface Props { type Props = {
searchQuery: MetadataSearchDto | SmartSearchDto; searchQuery: MetadataSearchDto | SmartSearchDto;
onClose: (search?: SmartSearchDto | MetadataSearchDto) => void; onClose: (search?: SmartSearchDto | MetadataSearchDto) => void;
} };
let { searchQuery, onClose }: Props = $props(); let { searchQuery, onClose }: Props = $props();
@@ -66,6 +45,7 @@
return validQueryTypes.has(storedQueryType) ? storedQueryType : QueryType.SMART; return validQueryTypes.has(storedQueryType) ? storedQueryType : QueryType.SMART;
} }
const asFilter = (searchQuery: SmartSearchDto | MetadataSearchDto): SearchFilter => {
let query = ''; let query = '';
if ('query' in searchQuery && searchQuery.query) { if ('query' in searchQuery && searchQuery.query) {
query = searchQuery.query; query = searchQuery.query;
@@ -74,10 +54,11 @@
query = searchQuery.originalFileName; query = searchQuery.originalFileName;
} }
let filter: SearchFilter = $state({ return {
query, query,
ocr: searchQuery.ocr, ocr: searchQuery.ocr,
queryType: defaultQueryType(), queryType: defaultQueryType(),
queryAssetId: 'queryAssetId' in searchQuery ? searchQuery.queryAssetId : undefined,
personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []), personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []),
tagIds: tagIds:
'tagIds' in searchQuery 'tagIds' in searchQuery
@@ -111,7 +92,10 @@
? MediaType.Video ? MediaType.Video
: MediaType.All, : MediaType.All,
rating: searchQuery.rating, rating: searchQuery.rating,
}); };
};
let filter: SearchFilter = $state(asFilter(searchQuery));
const resetForm = () => { const resetForm = () => {
filter = { filter = {
@@ -145,6 +129,7 @@
let payload: SmartSearchDto | MetadataSearchDto = { let payload: SmartSearchDto | MetadataSearchDto = {
query: filter.queryType === 'smart' ? query : undefined, query: filter.queryType === 'smart' ? query : undefined,
queryAssetId: filter.queryAssetId || undefined,
ocr: filter.queryType === 'ocr' ? query : undefined, ocr: filter.queryType === 'ocr' ? query : undefined,
originalFileName: filter.queryType === 'metadata' ? query : undefined, originalFileName: filter.queryType === 'metadata' ? query : undefined,
description: filter.queryType === 'description' ? 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 { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { QueueResponseDto, ServerVersionResponseDto } from '@immich/sdk'; import type { QueueResponseDto, ServerVersionResponseDto } from '@immich/sdk';
import type { ActionItem } from '@immich/ui'; import type { ActionItem } from '@immich/ui';
import type { DateTime } from 'luxon';
import type { SvelteSet } from 'svelte/reactivity';
export interface ReleaseEvent { export interface ReleaseEvent {
isAvailable: boolean; isAvailable: boolean;
@@ -48,3 +51,41 @@ export type AssetControlContext = {
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
clearSelect: () => void; 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;
};