refactor(web) open api client (#7103)

* refactor: person api

* refactor: shared link and others
This commit is contained in:
Jason Rasmussen 2024-02-14 08:09:49 -05:00 committed by GitHub
parent 5fc1d43012
commit d8631a00bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
81 changed files with 638 additions and 656 deletions

View file

@ -1,12 +1,10 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import { createEventDispatcher } from 'svelte';
import { JobCommand, type JobCommandDto, type JobCountsDto, type QueueStatusDto } from '@api';
import Badge from '$lib/components/elements/badge.svelte';
import JobTileButton from './job-tile-button.svelte';
import JobTileStatus from './job-tile-status.svelte';
import Button from '$lib/components/elements/buttons/button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { type JobCommandDto, type JobCountsDto, type QueueStatusDto } from '@immich/sdk';
import { JobCommand } from '@immich/sdk/axios';
import {
mdiAlertCircle,
mdiAllInclusive,
@ -16,6 +14,9 @@
mdiPlay,
mdiSelectionSearch,
} from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import JobTileButton from './job-tile-button.svelte';
import JobTileStatus from './job-tile-status.svelte';
export let title: string;
export let subtitle: string | undefined;

View file

@ -4,9 +4,10 @@
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { featureFlags } from '$lib/stores/server-config.store';
import { getJobName } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { type AllJobStatusResponseDto, api, JobCommand, type JobCommandDto, JobName } from '@api';
import type { ComponentType } from 'svelte';
import { sendJobCommand, type AllJobStatusResponseDto, type JobCommandDto } from '@immich/sdk';
import { JobCommand, JobName } from '@immich/sdk/axios';
import {
mdiFaceRecognition,
mdiFileJpgBox,
@ -18,10 +19,10 @@
mdiTagFaces,
mdiVideo,
} from '@mdi/js';
import type { ComponentType } from 'svelte';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
import JobTile from './job-tile.svelte';
import StorageMigrationDescription from './storage-migration-description.svelte';
import { sendJobCommand } from '@immich/sdk';
export let jobs: AllJobStatusResponseDto;
@ -59,23 +60,23 @@
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
[JobName.ThumbnailGeneration]: {
icon: mdiFileJpgBox,
title: api.getJobName(JobName.ThumbnailGeneration),
title: getJobName(JobName.ThumbnailGeneration),
subtitle: 'Generate large, small and blurred thumbnails for each asset, as well as thumbnails for each person',
},
[JobName.MetadataExtraction]: {
icon: mdiTable,
title: api.getJobName(JobName.MetadataExtraction),
title: getJobName(JobName.MetadataExtraction),
subtitle: 'Extract metadata information from each asset, such as GPS and resolution',
},
[JobName.Library]: {
icon: mdiLibraryShelves,
title: api.getJobName(JobName.Library),
title: getJobName(JobName.Library),
subtitle: 'Perform library tasks',
allText: 'ALL',
missingText: 'REFRESH',
},
[JobName.Sidecar]: {
title: api.getJobName(JobName.Sidecar),
title: getJobName(JobName.Sidecar),
icon: mdiFileXmlBox,
subtitle: 'Discover or synchronize sidecar metadata from the filesystem',
allText: 'SYNC',
@ -84,13 +85,13 @@
},
[JobName.SmartSearch]: {
icon: mdiImageSearch,
title: api.getJobName(JobName.SmartSearch),
title: getJobName(JobName.SmartSearch),
subtitle: 'Run machine learning on assets to support smart search',
disabled: !$featureFlags.smartSearch,
},
[JobName.FaceDetection]: {
icon: mdiFaceRecognition,
title: api.getJobName(JobName.FaceDetection),
title: getJobName(JobName.FaceDetection),
subtitle:
'Detect the faces in assets using machine learning. For videos, only the thumbnail is considered. "All" (re-)processes all assets. "Missing" queues assets that haven\'t been processed yet. Detected faces will be queued for Facial Recognition after Face Detection is complete, grouping them into existing or new people.',
handleCommand: handleConfirmCommand,
@ -98,7 +99,7 @@
},
[JobName.FacialRecognition]: {
icon: mdiTagFaces,
title: api.getJobName(JobName.FacialRecognition),
title: getJobName(JobName.FacialRecognition),
subtitle:
'Group detected faces into people. This step runs after Face Detection is complete. "All" (re-)clusters all faces. "Missing" queues faces that don\'t have a person assigned.',
handleCommand: handleConfirmCommand,
@ -106,18 +107,18 @@
},
[JobName.VideoConversion]: {
icon: mdiVideo,
title: api.getJobName(JobName.VideoConversion),
title: getJobName(JobName.VideoConversion),
subtitle: 'Transcode videos for wider compatibility with browsers and devices',
},
[JobName.StorageTemplateMigration]: {
icon: mdiFolderMove,
title: api.getJobName(JobName.StorageTemplateMigration),
title: getJobName(JobName.StorageTemplateMigration),
allowForceCommand: false,
component: StorageMigrationDescription,
},
[JobName.Migration]: {
icon: mdiFolderMove,
title: api.getJobName(JobName.Migration),
title: getJobName(JobName.Migration),
subtitle: 'Migrate thumbnails for assets and faces to the latest folder structure',
allowForceCommand: false,
},

View file

@ -1,10 +1,10 @@
<script lang="ts">
import { locale } from '$lib/stores/preferences.store';
import type { ServerStatsResponseDto } from '@api';
import { asByteUnitString, getBytesWithUnit } from '$lib/utils/byte-units';
import StatsCard from './stats-card.svelte';
import { mdiCameraIris, mdiChartPie, mdiPlayCircle } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { asByteUnitString, getBytesWithUnit } from '$lib/utils/byte-units';
import type { ServerStatsResponseDto } from '@immich/sdk';
import { mdiCameraIris, mdiChartPie, mdiPlayCircle } from '@mdi/js';
import StatsCard from './stats-card.svelte';
export let stats: ServerStatsResponseDto = {
photos: 0,

View file

@ -1,5 +1,5 @@
import type { ResetOptions } from '$lib/utils/dipatch';
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
export type SettingsEventType = {
reset: ResetOptions & { configKeys: Array<keyof SystemConfigDto> };

View file

@ -1,25 +1,18 @@
<script lang="ts">
import {
AudioCodec,
CQMode,
type SystemConfigDto,
ToneMapping,
TranscodeHWAccel,
TranscodePolicy,
VideoCodec,
} from '@api';
import Icon from '$lib/components/elements/icon.svelte';
import { type SystemConfigDto } from '@immich/sdk';
import { AudioCodec, CQMode, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec } from '@immich/sdk/axios';
import { mdiHelpCircleOutline } from '@mdi/js';
import { isEqual, sortBy } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import type { SettingsEventType } from '../admin-settings';
import SettingAccordion from '../setting-accordion.svelte';
import SettingButtonsRow from '../setting-buttons-row.svelte';
import SettingCheckboxes from '../setting-checkboxes.svelte';
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
import SettingSelect from '../setting-select.svelte';
import SettingSwitch from '../setting-switch.svelte';
import SettingCheckboxes from '../setting-checkboxes.svelte';
import { isEqual, sortBy } from 'lodash-es';
import { fade } from 'svelte/transition';
import SettingAccordion from '../setting-accordion.svelte';
import { mdiHelpCircleOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import { createEventDispatcher } from 'svelte';
import type { SettingsEventType } from '../admin-settings';
export let savedConfig: SystemConfigDto;
export let defaultConfig: SystemConfigDto;

View file

@ -1,5 +1,7 @@
<script lang="ts">
import { api, JobName, type SystemConfigDto, type SystemConfigJobDto } from '@api';
import { getJobName } from '$lib/utils';
import { type SystemConfigDto, type SystemConfigJobDto } from '@immich/sdk';
import { JobName } from '@immich/sdk/axios';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
@ -41,7 +43,7 @@
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
{disabled}
label="{api.getJobName(jobName)} Concurrency"
label="{getJobName(jobName)} Concurrency"
desc=""
bind:value={config.job[jobName].concurrency}
required={true}
@ -50,7 +52,7 @@
{:else}
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label="{api.getJobName(jobName)} Concurrency"
label="{getJobName(jobName)} Concurrency"
desc=""
value="1"
disabled={true}

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,6 @@
<script lang="ts">
import { LogLevel, type SystemConfigDto } from '@api';
import { type SystemConfigDto } from '@immich/sdk';
import { LogLevel } from '@immich/sdk/axios';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,11 +1,11 @@
<script lang="ts">
import SettingButtonsRow from '$lib/components/admin-page/settings/setting-buttons-row.svelte';
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { fade } from 'svelte/transition';
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import type { SettingsEventType } from '../admin-settings';
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
export let savedConfig: SystemConfigDto;
export let defaultConfig: SystemConfigDto;

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigTemplateStorageOptionDto } from '@api';
import type { SystemConfigTemplateStorageOptionDto } from '@immich/sdk';
import * as luxon from 'luxon';
export let options: SystemConfigTemplateStorageOptionDto;

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,7 +1,8 @@
<script lang="ts">
import SettingButtonsRow from '$lib/components/admin-page/settings/setting-buttons-row.svelte';
import SettingSelect from '$lib/components/admin-page/settings/setting-select.svelte';
import { Colorspace, type SystemConfigDto } from '@api';
import { type SystemConfigDto } from '@immich/sdk';
import { Colorspace } from '@immich/sdk/axios';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -1,5 +1,5 @@
<script lang="ts">
import type { SystemConfigDto } from '@api';
import type { SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';

View file

@ -3,6 +3,7 @@
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { user } from '$lib/stores/user.store';
import { getAssetThumbnailUrl } from '$lib/utils';
import { ThumbnailFormat, api, type AlbumResponseDto } from '@api';
import { getUserById } from '@immich/sdk';
import { mdiDotsVertical } from '@mdi/js';
@ -19,7 +20,7 @@
let showVerticalDots = false;
$: imageData = album.albumThumbnailAssetId
? api.getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)
? getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)
: noThumbnailUrl;
const dispatchClick = createEventDispatcher<OnClick>();

View file

@ -1,4 +1,4 @@
import type { AlbumResponseDto } from '@api';
import type { AlbumResponseDto } from '@immich/sdk';
export type OnShowContextMenu = {
showalbumcontextmenu: OnShowContextMenuDetail;

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { type AlbumResponseDto, type UserResponseDto } from '@api';
import { type AlbumResponseDto, type UserResponseDto } from '@immich/sdk';
import { getMyUserInfo, removeUserFromAlbum } from '@immich/sdk';
import { mdiDotsVertical } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';

View file

@ -2,8 +2,13 @@
import { goto } from '$app/navigation';
import Icon from '$lib/components/elements/icon.svelte';
import { AppRoute } from '$lib/constants';
import { api, type AlbumResponseDto, type SharedLinkResponseDto, type UserResponseDto } from '@api';
import { getAllUsers } from '@immich/sdk';
import {
getAllSharedLinks,
getAllUsers,
type AlbumResponseDto,
type SharedLinkResponseDto,
type UserResponseDto,
} from '@immich/sdk';
import { mdiCheck, mdiLink, mdiShareCircle } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import Button from '../elements/buttons/button.svelte';
@ -35,8 +40,7 @@
});
const getSharedLinks = async () => {
const { data } = await api.sharedLinkApi.getAllSharedLinks();
const data = await getAllSharedLinks();
sharedLinks = data.filter((link) => link.album?.id === album.id);
};

View file

@ -1,20 +1,21 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
import { getAssetThumbnailUrl } from '$lib/utils';
import { getAssetType } from '$lib/utils/asset-utils';
import { autoGrowHeight } from '$lib/utils/autogrow';
import { clickOutside } from '$lib/utils/click-outside';
import { handleError } from '$lib/utils/handle-error';
import { isTenMinutesApart } from '$lib/utils/timesince';
import {
AssetTypeEnum,
ReactionType,
ThumbnailFormat,
api,
createActivity,
deleteActivity,
getActivities,
type ActivityResponseDto,
type AssetTypeEnum,
type UserResponseDto,
} from '@api';
import { createActivity, deleteActivity, getActivities } from '@immich/sdk';
} from '@immich/sdk';
import { ReactionType, ThumbnailFormat } from '@immich/sdk/axios';
import { mdiClose, mdiDotsVertical, mdiHeart, mdiSend } from '@mdi/js';
import * as luxon from 'luxon';
import { createEventDispatcher, onMount } from 'svelte';
@ -191,7 +192,7 @@
<div class="aspect-square w-[75px] h-[75px]">
<img
class="rounded-lg w-[75px] h-[75px] object-cover"
src={api.getAssetThumbnailUrl(reaction.assetId, ThumbnailFormat.Webp)}
src={getAssetThumbnailUrl(reaction.assetId, ThumbnailFormat.Webp)}
alt="comment-thumbnail"
/>
</div>
@ -237,7 +238,7 @@
<div class="aspect-square w-[75px] h-[75px]">
<img
class="rounded-lg w-[75px] h-[75px] object-cover"
src={api.getAssetThumbnailUrl(reaction.assetId, ThumbnailFormat.Webp)}
src={getAssetThumbnailUrl(reaction.assetId, ThumbnailFormat.Webp)}
alt="like-thumbnail"
/>
</div>

View file

@ -1,5 +1,6 @@
<script lang="ts">
import { type AlbumResponseDto, ThumbnailFormat, api } from '@api';
import { getAssetThumbnailUrl } from '$lib/utils';
import { ThumbnailFormat, type AlbumResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
@ -32,7 +33,7 @@
<div class="h-12 w-12 shrink-0 rounded-xl bg-slate-300">
{#if album.albumThumbnailAssetId}
<img
src={api.getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)}
src={getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)}
alt={album.albumName}
class="z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg"
data-testid="album-image"

View file

@ -1,9 +1,11 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { user } from '$lib/stores/user.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { getAssetJobName } from '$lib/utils';
import { clickOutside } from '$lib/utils/click-outside';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { AssetJobName, type AssetResponseDto, AssetTypeEnum, api } from '@api';
import { AssetJobName, AssetTypeEnum, type AssetResponseDto } from '@api';
import {
mdiAlertOutline,
mdiArrowLeft,
@ -22,7 +24,6 @@
import { createEventDispatcher } from 'svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import { user } from '$lib/stores/user.store';
export let asset: AssetResponseDto;
export let showCopyButton: boolean;
@ -182,16 +183,16 @@
<MenuOption
on:click={() => onJobClick(AssetJobName.RefreshMetadata)}
text={api.getAssetJobName(AssetJobName.RefreshMetadata)}
text={getAssetJobName(AssetJobName.RefreshMetadata)}
/>
<MenuOption
on:click={() => onJobClick(AssetJobName.RegenerateThumbnail)}
text={api.getAssetJobName(AssetJobName.RegenerateThumbnail)}
text={getAssetJobName(AssetJobName.RegenerateThumbnail)}
/>
{#if asset.type === AssetTypeEnum.Video}
<MenuOption
on:click={() => onJobClick(AssetJobName.TranscodeVideo)}
text={api.getAssetJobName(AssetJobName.TranscodeVideo)}
text={getAssetJobName(AssetJobName.TranscodeVideo)}
/>
{/if}
{/if}

View file

@ -11,6 +11,7 @@
import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
import { stackAssetsStore } from '$lib/stores/stacked-asset.store';
import { user } from '$lib/stores/user.store';
import { getAssetJobMessage, isSharedLink } from '$lib/utils';
import { addAssetsToAlbum, downloadFile } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
@ -19,7 +20,6 @@
AssetJobName,
AssetTypeEnum,
ReactionType,
api,
type ActivityResponseDto,
type AlbumResponseDto,
type AssetResponseDto,
@ -29,9 +29,13 @@
createActivity,
createAlbum,
deleteActivity,
deleteAssets,
getActivities,
getActivityStatistics,
getAllAlbums,
runAssetJobs,
updateAsset,
updateAssets,
} from '@immich/sdk';
import { mdiChevronLeft, mdiChevronRight, mdiImageBrokenVariant } from '@mdi/js';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
@ -235,7 +239,7 @@
$: asset.id && !sharedLink && handleGetAllAlbums(); // Update the album information when the asset ID changes
const handleGetAllAlbums = async () => {
if (api.isSharedLink) {
if (isSharedLink()) {
return;
}
@ -386,7 +390,7 @@
const trashAsset = async () => {
try {
await api.assetApi.deleteAssets({ assetBulkDeleteDto: { ids: [asset.id] } });
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id] } });
dispatch('action', { type: AssetAction.TRASH, asset });
@ -401,7 +405,7 @@
const deleteAsset = async () => {
try {
await api.assetApi.deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
dispatch('action', { type: AssetAction.DELETE, asset });
@ -418,7 +422,7 @@
const toggleFavorite = async () => {
try {
const { data } = await api.assetApi.updateAsset({
const data = await updateAsset({
id: asset.id,
updateAssetDto: {
isFavorite: !asset.isFavorite,
@ -470,7 +474,7 @@
const toggleArchive = async () => {
try {
const { data } = await api.assetApi.updateAsset({
const data = await updateAsset({
id: asset.id,
updateAssetDto: {
isArchived: !asset.isArchived,
@ -491,8 +495,8 @@
const handleRunJob = async (name: AssetJobName) => {
try {
await api.assetApi.runAssetJobs({ assetJobsDto: { assetIds: [asset.id], name } });
notificationController.show({ type: NotificationType.Info, message: api.getAssetJobMessage(name) });
await runAssetJobs({ assetJobsDto: { assetIds: [asset.id], name } });
notificationController.show({ type: NotificationType.Info, message: getAssetJobMessage(name) });
} catch (error) {
await handleError(error, `Unable to submit job`);
}
@ -552,7 +556,7 @@
const handleUnstack = async () => {
try {
const ids = $stackAssetsStore.map(({ id }) => id);
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, removeParent: true } });
await updateAssets({ assetBulkUpdateDto: { ids, removeParent: true } });
for (const child of $stackAssetsStore) {
child.stackParentId = null;
child.stackCount = 0;

View file

@ -1,15 +1,18 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { locale } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { user } from '$lib/stores/user.store';
import { websocketStore } from '$lib/stores/websocket';
import { getAssetThumbnailUrl, getPeopleThumbnailUrl, isSharedLink } from '$lib/utils';
import { getAssetFilename } from '$lib/utils/asset-utils';
import { type AlbumResponseDto, type AssetResponseDto, ThumbnailFormat, api } from '@api';
import { DateTime } from 'luxon';
import { createEventDispatcher, onDestroy } from 'svelte';
import { slide } from 'svelte/transition';
import { asByteUnitString } from '../../utils/byte-units';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import { autoGrowHeight } from '$lib/utils/autogrow';
import { clickOutside } from '$lib/utils/click-outside';
import { ThumbnailFormat, type AlbumResponseDto, type AssetResponseDto } from '@api';
import { getAssetInfo, updateAsset } from '@immich/sdk';
import {
mdiCalendar,
mdiCameraIris,
@ -17,22 +20,21 @@
mdiEye,
mdiEyeOff,
mdiImageOutline,
mdiMapMarkerOutline,
mdiInformationOutline,
mdiMapMarkerOutline,
mdiPencil,
} from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import Map from '../shared-components/map/map.svelte';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { websocketStore } from '$lib/stores/websocket';
import { AppRoute, QueryParameter } from '$lib/constants';
import ChangeLocation from '../shared-components/change-location.svelte';
import { DateTime } from 'luxon';
import { createEventDispatcher, onDestroy } from 'svelte';
import { slide } from 'svelte/transition';
import { asByteUnitString } from '../../utils/byte-units';
import { handleError } from '../../utils/handle-error';
import { user } from '$lib/stores/user.store';
import { autoGrowHeight } from '$lib/utils/autogrow';
import { clickOutside } from '$lib/utils/click-outside';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
import ChangeLocation from '../shared-components/change-location.svelte';
import Map from '../shared-components/map/map.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
export let asset: AssetResponseDto;
export let albums: AlbumResponseDto[] = [];
@ -61,8 +63,8 @@
description = newAsset?.exifInfo?.description || '';
// Get latest description from server
if (newAsset.id && !api.isSharedLink) {
const { data } = await api.assetApi.getAssetInfo({ id: asset.id });
if (newAsset.id && !isSharedLink()) {
const data = await getAssetInfo({ id: asset.id });
people = data?.people || [];
description = data.exifInfo?.description || '';
@ -127,9 +129,9 @@
};
const handleRefreshPeople = async () => {
await api.assetApi.getAssetInfo({ id: asset.id }).then((res) => {
people = res.data?.people || [];
textArea.value = res.data?.exifInfo?.description || '';
await getAssetInfo({ id: asset.id }).then((data) => {
people = data?.people || [];
textArea.value = data?.exifInfo?.description || '';
});
showEditFaces = false;
};
@ -146,10 +148,7 @@
originalDescription = description;
dispatch('descriptionFocusOut');
try {
await api.assetApi.updateAsset({
id: asset.id,
updateAssetDto: { description },
});
await updateAsset({ id: asset.id, updateAssetDto: { description } });
} catch (error) {
handleError(error, 'Cannot update the description');
}
@ -162,7 +161,7 @@
async function handleConfirmChangeDate(dateTimeOriginal: string) {
isShowChangeDate = false;
try {
await api.assetApi.updateAsset({ id: asset.id, updateAssetDto: { dateTimeOriginal } });
await updateAsset({ id: asset.id, updateAssetDto: { dateTimeOriginal } });
} catch (error) {
handleError(error, 'Unable to change date');
}
@ -174,13 +173,7 @@
isShowChangeLocation = false;
try {
await api.assetApi.updateAsset({
id: asset.id,
updateAssetDto: {
latitude: gps.lat,
longitude: gps.lng,
},
});
await updateAsset({ id: asset.id, updateAssetDto: { latitude: gps.lat, longitude: gps.lng } });
} catch (error) {
handleError(error, 'Unable to change location');
}
@ -219,7 +212,7 @@
<section class="px-4 mt-10">
{#key asset.id}
<textarea
disabled={!isOwner || api.isSharedLink}
disabled={!isOwner || isSharedLink()}
bind:this={textArea}
class="max-h-[500px]
w-full resize-none overflow-hidden border-b border-gray-500 bg-transparent text-base text-black outline-none transition-all focus:border-b-2 focus:border-immich-primary disabled:border-none dark:text-white dark:focus:border-immich-dark-primary"
@ -238,7 +231,7 @@
<p class="px-4 break-words whitespace-pre-line w-full text-black dark:text-white text-base">{description}</p>
{/if}
{#if !api.isSharedLink && people.length > 0}
{#if !isSharedLink() && people.length > 0}
<section class="px-4 py-4 text-sm">
<div class="flex h-10 w-full items-center justify-between">
<h2>PEOPLE</h2>
@ -284,7 +277,7 @@
<ImageThumbnail
curve
shadow
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={person.name}
title={person.name}
widthStyle="90px"
@ -670,7 +663,7 @@
alt={album.albumName}
class="h-[50px] w-[50px] rounded object-cover"
src={album.albumThumbnailAssetId &&
api.getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Jpeg)}
getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Jpeg)}
draggable="false"
/>
</div>

View file

@ -2,12 +2,13 @@
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { api, type AssetResponseDto } from '@api';
import { getKey } from '$lib/utils';
export let asset: AssetResponseDto;
const loadAssetData = async () => {
const { data } = await api.assetApi.serveFile(
{ id: asset.id, isThumb: false, isWeb: false, key: api.getKey() },
{ id: asset.id, isThumb: false, isWeb: false, key: getKey() },
{ responseType: 'blob' },
);
if (data instanceof Blob) {

View file

@ -1,17 +1,18 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { onDestroy, onMount } from 'svelte';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { api, type AssetResponseDto } from '@api';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import { useZoomImageWheel } from '@zoom-image/svelte';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { isWebCompatibleImage } from '$lib/utils/asset-utils';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { photoViewer } from '$lib/stores/assets.store';
import { getBoundingBox } from '$lib/utils/people-utils';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { alwaysLoadOriginalFile } from '$lib/stores/preferences.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { getKey } from '$lib/utils';
import { isWebCompatibleImage } from '$lib/utils/asset-utils';
import { getBoundingBox } from '$lib/utils/people-utils';
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
import { api, type AssetResponseDto } from '@api';
import { useZoomImageWheel } from '@zoom-image/svelte';
import { onDestroy, onMount } from 'svelte';
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
export let asset: AssetResponseDto;
export let element: HTMLDivElement | undefined = undefined;
@ -50,7 +51,7 @@
abortController = new AbortController();
const { data } = await api.assetApi.serveFile(
{ id: asset.id, isThumb: false, isWeb: !loadOriginal, key: api.getKey() },
{ id: asset.id, isThumb: false, isWeb: !loadOriginal, key: getKey() },
{
responseType: 'blob',
signal: abortController.signal,

View file

@ -1,10 +1,11 @@
<script lang="ts">
import { ThumbnailFormat, api } from '@api';
import { fade } from 'svelte/transition';
import { createEventDispatcher } from 'svelte';
import { videoViewerVolume } from '$lib/stores/preferences.store';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { getAssetFileUrl, getAssetThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { ThumbnailFormat } from '@api';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let assetId: string;
@ -35,9 +36,9 @@
on:canplay={handleCanPlay}
on:ended={() => dispatch('onVideoEnded')}
bind:volume={$videoViewerVolume}
poster={api.getAssetThumbnailUrl(assetId, ThumbnailFormat.Jpeg)}
poster={getAssetThumbnailUrl(assetId, ThumbnailFormat.Jpeg)}
>
<source src={api.getAssetFileUrl(assetId, false, true)} type="video/mp4" />
<source src={getAssetFileUrl(assetId, false, true)} type="video/mp4" />
<track kind="captions" />
</video>

View file

@ -1,12 +1,10 @@
<script lang="ts">
import { ProjectionType } from '$lib/constants';
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { ProjectionType } from '$lib/constants';
import { getAssetFileUrl, getAssetThumbnailUrl, isSharedLink } from '$lib/utils';
import { timeToSeconds } from '$lib/utils/time-to-seconds';
import { api, type AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import ImageThumbnail from './image-thumbnail.svelte';
import VideoThumbnail from './video-thumbnail.svelte';
import { AssetTypeEnum, ThumbnailFormat, type AssetResponseDto } from '@api';
import {
mdiArchiveArrowDownOutline,
mdiCameraBurst,
@ -17,7 +15,10 @@
mdiMotionPlayOutline,
mdiRotate360,
} from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import ImageThumbnail from './image-thumbnail.svelte';
import VideoThumbnail from './video-thumbnail.svelte';
const dispatch = createEventDispatcher<{
click: { asset: AssetResponseDto };
@ -138,13 +139,13 @@
/>
<!-- Favorite asset star -->
{#if !api.isSharedLink && asset.isFavorite}
{#if !isSharedLink() && asset.isFavorite}
<div class="absolute bottom-2 left-2 z-10">
<Icon path={mdiHeart} size="24" class="text-white" />
</div>
{/if}
{#if !api.isSharedLink && showArchiveIcon && asset.isArchived}
{#if !isSharedLink() && showArchiveIcon && asset.isArchived}
<div class="absolute {asset.isFavorite ? 'bottom-10' : 'bottom-2'} left-2 z-10">
<Icon path={mdiArchiveArrowDownOutline} size="24" class="text-white" />
</div>
@ -175,7 +176,7 @@
{#if asset.resized}
<ImageThumbnail
url={api.getAssetThumbnailUrl(asset.id, format)}
url={getAssetThumbnailUrl(asset.id, format)}
altText={asset.originalFileName}
widthStyle="{width}px"
heightStyle="{height}px"
@ -191,7 +192,7 @@
{#if asset.type === AssetTypeEnum.Video}
<div class="absolute top-0 h-full w-full">
<VideoThumbnail
url={api.getAssetFileUrl(asset.id, false, true)}
url={getAssetFileUrl(asset.id, false, true)}
enablePlayback={mouseOver}
curve={selected}
durationInSeconds={timeToSeconds(asset.duration)}
@ -202,7 +203,7 @@
{#if asset.type === AssetTypeEnum.Image && asset.livePhotoVideoId}
<div class="absolute top-0 h-full w-full">
<VideoThumbnail
url={api.getAssetFileUrl(asset.livePhotoVideoId, false, true)}
url={getAssetFileUrl(asset.livePhotoVideoId, false, true)}
pauseIcon={mdiMotionPauseOutline}
playIcon={mdiMotionPlayOutline}
showTime={false}

View file

@ -1,16 +1,18 @@
<script lang="ts">
import { api, AssetTypeEnum, type AssetFaceResponseDto, type PersonResponseDto, ThumbnailFormat } from '@api';
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
import { photoViewer } from '$lib/stores/assets.store';
import { getAssetThumbnailUrl, getPeopleThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { getPersonNameWithHiddenValue, searchNameLocal } from '$lib/utils/person';
import { AssetTypeEnum, ThumbnailFormat, type AssetFaceResponseDto, type PersonResponseDto } from '@api';
import { searchPerson } from '@immich/sdk';
import { mdiArrowLeftThin, mdiClose, mdiMagnify, mdiPlus } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { linear } from 'svelte/easing';
import { fly } from 'svelte/transition';
import Icon from '../elements/icon.svelte';
import { mdiArrowLeftThin, mdiClose, mdiMagnify, mdiPlus } from '@mdi/js';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import { getPersonNameWithHiddenValue, searchNameLocal } from '$lib/utils/person';
import { handleError } from '$lib/utils/handle-error';
import { photoViewer } from '$lib/stores/assets.store';
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
import Icon from '../elements/icon.svelte';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let peopleWithFaces: AssetFaceResponseDto[];
export let allPeople: PersonResponseDto[];
@ -42,7 +44,7 @@
if (assetType === AssetTypeEnum.Image) {
image = $photoViewer;
} else if (assetType === AssetTypeEnum.Video) {
const data = await api.getAssetThumbnailUrl(assetId, ThumbnailFormat.Webp);
const data = await getAssetThumbnailUrl(assetId, ThumbnailFormat.Webp);
const img: HTMLImageElement = new Image();
img.src = data;
@ -116,7 +118,7 @@
}
const timeout = setTimeout(() => (isShowLoadingSearch = true), timeBeforeShowLoadingSpinner);
try {
const { data } = await api.searchApi.searchPerson({ name: searchName });
const data = await searchPerson({ name: searchName });
searchedPeople = data;
searchedPeopleCopy = data;
searchWord = searchName;
@ -229,7 +231,7 @@
<ImageThumbnail
curve
shadow
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={getPersonNameWithHiddenValue(person.name, person.isHidden)}
title={getPersonNameWithHiddenValue(person.name, person.isHidden)}
widthStyle="90px"
@ -255,7 +257,7 @@
<ImageThumbnail
curve
shadow
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={getPersonNameWithHiddenValue(person.name, person.isHidden)}
title={getPersonNameWithHiddenValue(person.name, person.isHidden)}
widthStyle="90px"

View file

@ -1,7 +1,8 @@
<script lang="ts">
import { api, type PersonResponseDto } from '@api';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { type PersonResponseDto } from '@api';
import { createEventDispatcher } from 'svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
export let person: PersonResponseDto;
export let selectable = false;
@ -34,13 +35,7 @@
class:dark:border-immich-dark-primary={border}
class:border-immich-primary={border}
>
<ImageThumbnail
{circle}
url={api.getPeopleThumbnailUrl(person.id)}
altText={person.name}
widthStyle="100%"
shadow
/>
<ImageThumbnail {circle} url={getPeopleThumbnailUrl(person.id)} altText={person.name} widthStyle="100%" shadow />
</div>
<div

View file

@ -1,22 +1,23 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import Icon from '$lib/components/elements/icon.svelte';
import { ActionQueryParameterValue, AppRoute, QueryParameter } from '$lib/constants';
import { handleError } from '$lib/utils/handle-error';
import { type PersonResponseDto } from '@api';
import { getAllPeople, getPerson, mergePerson } from '@immich/sdk';
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import { api, type PersonResponseDto } from '@api';
import FaceThumbnail from './face-thumbnail.svelte';
import { flip } from 'svelte/animate';
import { quintOut } from 'svelte/easing';
import { fly } from 'svelte/transition';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import Button from '../elements/buttons/button.svelte';
import { flip } from 'svelte/animate';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import { handleError } from '$lib/utils/handle-error';
import { goto } from '$app/navigation';
import { ActionQueryParameterValue, AppRoute, QueryParameter } from '$lib/constants';
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import FaceThumbnail from './face-thumbnail.svelte';
import PeopleList from './people-list.svelte';
import { page } from '$app/stores';
export let person: PersonResponseDto;
let people: PersonResponseDto[] = [];
@ -35,7 +36,7 @@
);
onMount(async () => {
const { data } = await api.personApi.getAllPeople({ withHidden: false });
const data = await getAllPeople({ withHidden: false });
people = data.people;
});
@ -68,11 +69,11 @@
const handleMerge = async () => {
try {
let { data: results } = await api.personApi.mergePerson({
let results = await mergePerson({
id: person.id,
mergePersonDto: { ids: selectedPeople.map(({ id }) => id) },
});
const { data: mergedPerson } = await api.personApi.getPerson({ id: person.id });
const mergedPerson = await getPerson({ id: person.id });
const count = results.filter(({ success }) => success).length;
notificationController.show({
message: `Merged ${count} ${count === 1 ? 'person' : 'people'}`,

View file

@ -1,12 +1,13 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import { api, type PersonResponseDto } from '@api';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { type PersonResponseDto } from '@api';
import { mdiArrowLeft, mdiClose, mdiMerge } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import Button from '../elements/buttons/button.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiArrowLeft, mdiClose, mdiMerge } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let personMerge1: PersonResponseDto;
export let personMerge2: PersonResponseDto;
@ -60,7 +61,7 @@
<ImageThumbnail
circle
shadow
url={api.getPeopleThumbnailUrl(personMerge1.id)}
url={getPeopleThumbnailUrl(personMerge1.id)}
altText={personMerge1.name}
widthStyle="100%"
/>
@ -85,7 +86,7 @@
border={potentialMergePeople.length > 0}
circle
shadow
url={api.getPeopleThumbnailUrl(personMerge2.id)}
url={getPeopleThumbnailUrl(personMerge2.id)}
altText={personMerge2.name}
widthStyle="100%"
/>
@ -104,7 +105,7 @@
border={true}
circle
shadow
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={person.name}
widthStyle="100%"
on:click={() => changePersonToMerge(person)}

View file

@ -1,15 +1,16 @@
<script lang="ts">
import { type PersonResponseDto, api } from '@api';
import Icon from '$lib/components/elements/icon.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { getContextMenuPosition } from '$lib/utils/context-menu';
import { type PersonResponseDto } from '@api';
import { mdiDotsVertical } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import IconButton from '../elements/buttons/icon-button.svelte';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import Portal from '../shared-components/portal/portal.svelte';
import { createEventDispatcher } from 'svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { mdiDotsVertical } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
export let person: PersonResponseDto;
export let preload = false;
@ -50,7 +51,7 @@
<ImageThumbnail
shadow
{preload}
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={person.name}
title={person.name}
widthStyle="100%"

View file

@ -1,11 +1,12 @@
<script lang="ts">
import { api, type PersonResponseDto } from '@api';
import FaceThumbnail from './face-thumbnail.svelte';
import { createEventDispatcher } from 'svelte';
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
import { handleError } from '$lib/utils/handle-error';
import { searchNameLocal } from '$lib/utils/person';
import { type PersonResponseDto } from '@api';
import { searchPerson } from '@immich/sdk';
import { createEventDispatcher } from 'svelte';
import FaceThumbnail from './face-thumbnail.svelte';
import SearchBar from './search-bar.svelte';
import { maximumLengthSearchPeople, timeBeforeShowLoadingSpinner } from '$lib/constants';
export let screenHeight: number;
export let people: PersonResponseDto[];
@ -40,8 +41,7 @@
const timeout = setTimeout(() => (isSearchingPeople = true), timeBeforeShowLoadingSpinner);
try {
const { data } = await api.searchApi.searchPerson({ name });
people = data;
people = await searchPerson({ name });
searchWord = name;
} catch (error) {
handleError(error, "Can't search people");

View file

@ -1,20 +1,21 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import { linear } from 'svelte/easing';
import { api, type PersonResponseDto, type AssetFaceResponseDto, AssetTypeEnum } from '@api';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import { handleError } from '$lib/utils/handle-error';
import { createEventDispatcher, onMount } from 'svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import { mdiArrowLeftThin, mdiRestart } from '@mdi/js';
import Icon from '../elements/icon.svelte';
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { websocketStore } from '$lib/stores/websocket';
import AssignFaceSidePanel from './assign-face-side-panel.svelte';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { getPersonNameWithHiddenValue } from '$lib/utils/person';
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
import { getFaces, reassignFacesById } from '@immich/sdk';
import { AssetTypeEnum, type AssetFaceResponseDto, type PersonResponseDto } from '@api';
import { createPerson, getAllPeople, getFaces, reassignFacesById } from '@immich/sdk';
import { mdiArrowLeftThin, mdiRestart } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import { linear } from 'svelte/easing';
import { fly } from 'svelte/transition';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
import Icon from '../elements/icon.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import AssignFaceSidePanel from './assign-face-side-panel.svelte';
export let assetId: string;
export let assetType: AssetTypeEnum;
@ -69,8 +70,8 @@
onMount(async () => {
const timeout = setTimeout(() => (isShowLoadingPeople = true), timeBeforeShowLoadingSpinner);
try {
const { data } = await api.personApi.getAllPeople({ withHidden: true });
allPeople = data.people;
const { people } = await getAllPeople({ withHidden: true });
allPeople = people;
peopleWithFaces = await getFaces({ id: assetId });
selectedPersonToCreate = Array.from({ length: peopleWithFaces.length });
selectedPersonToReassign = Array.from({ length: peopleWithFaces.length });
@ -115,7 +116,7 @@
faceDto: { id: peopleWithFace.id },
});
} else if (selectedPersonToCreate[index]) {
const { data } = await api.personApi.createPerson();
const data = await createPerson();
numberOfPersonToCreate.push(data.id);
await reassignFacesById({
id: data.id,
@ -214,7 +215,7 @@
curve
shadow
url={selectedPersonToCreate[index] ||
api.getPeopleThumbnailUrl(selectedPersonToReassign[index]?.id || face.person.id)}
getPeopleThumbnailUrl(selectedPersonToReassign[index]?.id || face.person.id)}
altText={selectedPersonToReassign[index]
? selectedPersonToReassign[index]?.name || ''
: selectedPersonToCreate[index]

View file

@ -1,18 +1,24 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import FaceThumbnail from './face-thumbnail.svelte';
import { quintOut } from 'svelte/easing';
import { fly } from 'svelte/transition';
import { api, type AssetFaceUpdateItem, type PersonResponseDto } from '@api';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import Button from '../elements/buttons/button.svelte';
import { mdiPlus, mdiMerge } from '@mdi/js';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { handleError } from '$lib/utils/handle-error';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import PeopleList from './people-list.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
import { handleError } from '$lib/utils/handle-error';
import {
createPerson,
getAllPeople,
reassignFaces,
type AssetFaceUpdateItem,
type PersonResponseDto,
} from '@immich/sdk';
import { mdiMerge, mdiPlus } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import { quintOut } from 'svelte/easing';
import { fly } from 'svelte/transition';
import Button from '../elements/buttons/button.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import FaceThumbnail from './face-thumbnail.svelte';
import PeopleList from './people-list.svelte';
export let assetIds: string[];
export let personAssets: PersonResponseDto;
@ -41,7 +47,7 @@
}
onMount(async () => {
const { data } = await api.personApi.getAllPeople({ withHidden: false });
const data = await getAllPeople({ withHidden: false });
people = data.people;
});
@ -68,11 +74,8 @@
try {
disableButtons = true;
const { data } = await api.personApi.createPerson();
await api.personApi.reassignFaces({
id: data.id,
assetFaceUpdateDto: { data: selectedPeople },
});
const data = await createPerson();
await reassignFaces({ id: data.id, assetFaceUpdateDto: { data: selectedPeople } });
notificationController.show({
message: `Re-assigned ${assetIds.length} asset${assetIds.length > 1 ? 's' : ''} to a new person`,
@ -93,10 +96,7 @@
try {
disableButtons = true;
if (selectedPerson) {
await api.personApi.reassignFaces({
id: selectedPerson.id,
assetFaceUpdateDto: { data: selectedPeople },
});
await reassignFaces({ id: selectedPerson.id, assetFaceUpdateDto: { data: selectedPeople } });
notificationController.show({
message: `Re-assigned ${assetIds.length} asset${assetIds.length > 1 ? 's' : ''} to ${
selectedPerson.name || 'an existing person'

View file

@ -1,20 +1,21 @@
<script lang="ts">
import { memoryStore } from '$lib/stores/memory.store';
import { DateTime } from 'luxon';
import { onMount } from 'svelte';
import { api } from '@api';
import { goto } from '$app/navigation';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import { fromLocalDateTime } from '$lib/utils/timeline-util';
import { AppRoute, QueryParameter } from '$lib/constants';
import { page } from '$app/stores';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
import { fade } from 'svelte/transition';
import { tweened } from 'svelte/motion';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { memoryStore } from '$lib/stores/memory.store';
import { getAssetThumbnailUrl } from '$lib/utils';
import { fromLocalDateTime } from '$lib/utils/timeline-util';
import { getMemoryLane } from '@immich/sdk';
import { mdiChevronDown, mdiChevronLeft, mdiChevronRight, mdiChevronUp, mdiPause, mdiPlay } from '@mdi/js';
import { DateTime } from 'luxon';
import { onMount } from 'svelte';
import { tweened } from 'svelte/motion';
import { fade } from 'svelte/transition';
const parseIndex = (s: string | null, max: number | null) =>
Math.max(Math.min(Number.parseInt(s ?? '') || 0, max ?? 0), 0);
@ -87,11 +88,10 @@
onMount(async () => {
if (!$memoryStore) {
const localTime = new Date();
const { data } = await api.assetApi.getMemoryLane({
$memoryStore = await getMemoryLane({
month: localTime.getMonth() + 1,
day: localTime.getDate(),
});
$memoryStore = data;
}
});
@ -168,7 +168,7 @@
<button class="relative h-full w-full rounded-2xl" disabled={!previousMemory} on:click={toPreviousMemory}>
<img
class="h-full w-full rounded-2xl object-cover"
src={previousMemory ? api.getAssetThumbnailUrl(previousMemory.assets[0].id, 'JPEG') : noThumbnailUrl}
src={previousMemory ? getAssetThumbnailUrl(previousMemory.assets[0].id, 'JPEG') : noThumbnailUrl}
alt=""
draggable="false"
/>
@ -191,7 +191,7 @@
<img
transition:fade
class="h-full w-full rounded-2xl object-contain transition-all"
src={api.getAssetThumbnailUrl(currentAsset.id, 'JPEG')}
src={getAssetThumbnailUrl(currentAsset.id, 'JPEG')}
alt=""
draggable="false"
/>
@ -231,7 +231,7 @@
<button class="relative h-full w-full rounded-2xl" on:click={toNextMemory} disabled={!nextMemory}>
<img
class="h-full w-full rounded-2xl object-cover"
src={nextMemory ? api.getAssetThumbnailUrl(nextMemory.assets[0].id, 'JPEG') : noThumbnailUrl}
src={nextMemory ? getAssetThumbnailUrl(nextMemory.assets[0].id, 'JPEG') : noThumbnailUrl}
alt=""
draggable="false"
/>

View file

@ -4,12 +4,12 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import type { OnArchive } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import { updateAssets } from '@immich/sdk';
import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline, mdiTimerSand } from '@mdi/js';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiArchiveArrowUpOutline, mdiArchiveArrowDownOutline, mdiTimerSand } from '@mdi/js';
import type { OnArchive } from '$lib/utils/actions';
export let onArchive: OnArchive | undefined = undefined;
@ -32,7 +32,7 @@
const ids = assets.map(({ id }) => id);
if (ids.length > 0) {
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isArchived } });
await updateAssets({ assetBulkUpdateDto: { ids, isArchived } });
}
for (const asset of assets) {

View file

@ -4,8 +4,10 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetJobMessage, getAssetJobName } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetJobName, AssetTypeEnum, api } from '@api';
import { AssetJobName, AssetTypeEnum } from '@api';
import { runAssetJobs } from '@immich/sdk';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
export let jobs: AssetJobName[] = [
@ -21,8 +23,8 @@
const handleRunJob = async (name: AssetJobName) => {
try {
const ids = [...getOwnedAssets()].map(({ id }) => id);
await api.assetApi.runAssetJobs({ assetJobsDto: { assetIds: ids, name } });
notificationController.show({ message: api.getAssetJobMessage(name), type: NotificationType.Info });
await runAssetJobs({ assetJobsDto: { assetIds: ids, name } });
notificationController.show({ message: getAssetJobMessage(name), type: NotificationType.Info });
clearSelect();
} catch (error) {
handleError(error, 'Unable to submit job');
@ -32,6 +34,6 @@
{#each jobs as job}
{#if isAllVideos || job !== AssetJobName.TranscodeVideo}
<MenuOption text={api.getAssetJobName(job)} on:click={() => handleRunJob(job)} />
<MenuOption text={getAssetJobName(job)} on:click={() => handleRunJob(job)} />
{/if}
{/each}

View file

@ -1,12 +1,12 @@
<script lang="ts">
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import { updateAssets } from '@immich/sdk';
import { DateTime } from 'luxon';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();
@ -17,9 +17,7 @@
const ids = getSelectedAssets(getOwnedAssets(), $user);
try {
await api.assetApi.updateAssets({
assetBulkUpdateDto: { ids, dateTimeOriginal },
});
await updateAssets({ assetBulkUpdateDto: { ids, dateTimeOriginal } });
} catch (error) {
handleError(error, 'Unable to change date');
}

View file

@ -1,11 +1,11 @@
<script lang="ts">
import { api } from '@api';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import ChangeLocation from '$lib/components/shared-components/change-location.svelte';
import { handleError } from '../../../utils/handle-error';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();
@ -17,13 +17,7 @@
const ids = getSelectedAssets(getOwnedAssets(), $user);
try {
await api.assetApi.updateAssets({
assetBulkUpdateDto: {
ids,
latitude: point.lat,
longitude: point.lng,
},
});
await updateAssets({ assetBulkUpdateDto: { ids, latitude: point.lat, longitude: point.lng } });
} catch (error) {
handleError(error, 'Unable to update location');
}

View file

@ -5,11 +5,11 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api } from '@api';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
import type { OnFavorite } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
export let onFavorite: OnFavorite | undefined = undefined;
@ -33,7 +33,7 @@
const ids = assets.map(({ id }) => id);
if (ids.length > 0) {
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isFavorite } });
await updateAssets({ assetBulkUpdateDto: { ids, isFavorite } });
}
for (const asset of assets) {

View file

@ -1,11 +1,13 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { type SharedLinkResponseDto, api } from '@api';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
import { handleError } from '../../../utils/handle-error';
import { getKey } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { type SharedLinkResponseDto } from '@api';
import { removeSharedLinkAssets } from '@immich/sdk';
import { mdiDeleteOutline } from '@mdi/js';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
export let sharedLink: SharedLinkResponseDto;
@ -15,12 +17,12 @@
const handleRemove = async () => {
try {
const { data: results } = await api.sharedLinkApi.removeSharedLinkAssets({
const results = await removeSharedLinkAssets({
id: sharedLink.id,
assetIdsDto: {
assetIds: [...getAssets()].map((asset) => asset.id),
},
key: api.getKey(),
key: getKey(),
});
for (const result of results) {

View file

@ -1,13 +1,13 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { api } from '@api';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import type { OnStack } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
export let onStack: OnStack | undefined;
@ -26,7 +26,7 @@
const ids = children.map(({ id }) => id);
if (children.length > 0) {
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, stackParentId: parent.id } });
await updateAssets({ assetBulkUpdateDto: { ids, stackParentId: parent.id } });
}
let childrenCount = parent.stackCount ?? 0;

View file

@ -1,22 +1,19 @@
<script lang="ts">
import { onMount } from 'svelte';
import { api } from '@api';
import Icon from '$lib/components/elements/icon.svelte';
import { memoryStore } from '$lib/stores/memory.store';
import { goto } from '$app/navigation';
import { fade } from 'svelte/transition';
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { memoryStore } from '$lib/stores/memory.store';
import { getAssetThumbnailUrl } from '$lib/utils';
import { getMemoryLane } from '@immich/sdk';
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
$: shouldRender = $memoryStore?.length > 0;
onMount(async () => {
const localTime = new Date();
const { data } = await api.assetApi.getMemoryLane({
month: localTime.getMonth() + 1,
day: localTime.getDate(),
});
$memoryStore = data;
$memoryStore = await getMemoryLane({ month: localTime.getMonth() + 1, day: localTime.getDate() });
});
let memoryLaneElement: HTMLElement;
@ -76,7 +73,7 @@
>
<img
class="h-full w-full rounded-xl object-cover"
src={api.getAssetThumbnailUrl(memory.assets[0].id, 'JPEG')}
src={getAssetThumbnailUrl(memory.assets[0].id, 'JPEG')}
alt={memory.title}
draggable="false"
/>

View file

@ -1,9 +1,14 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
import { downloadArchive } from '$lib/utils/asset-utils';
import { api, type AssetResponseDto, type SharedLinkResponseDto } from '@api';
import { AppRoute } from '$lib/constants';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { getKey } from '$lib/utils';
import { downloadArchive } from '$lib/utils/asset-utils';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
import { handleError } from '$lib/utils/handle-error';
import { type AssetResponseDto, type SharedLinkResponseDto } from '@api';
import { addSharedLinkAssets } from '@immich/sdk';
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import DownloadAction from '../photos-page/actions/download-action.svelte';
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
@ -11,10 +16,7 @@
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
import ImmichLogo from '../shared-components/immich-logo.svelte';
import { notificationController, NotificationType } from '../shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { mdiArrowLeft, mdiFileImagePlusOutline, mdiFolderDownloadOutline, mdiSelectAll } from '@mdi/js';
import { AppRoute } from '$lib/constants';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
export let sharedLink: SharedLinkResponseDto;
export let isOwned: boolean;
@ -41,12 +43,12 @@
results = await (!files || files.length === 0 || !Array.isArray(files)
? openFileUploadDialog()
: fileUploadHandler(files));
const { data } = await api.sharedLinkApi.addSharedLinkAssets({
const data = await addSharedLinkAssets({
id: sharedLink.id,
assetIdsDto: {
assetIds: results.filter((id) => !!id) as string[],
},
key: api.getKey(),
key: getKey(),
});
const added = data.filter((item) => item.success).length;

View file

@ -4,16 +4,17 @@
} from '$lib/components/admin-page/settings/setting-input-field.svelte';
import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
import Button from '$lib/components/elements/buttons/button.svelte';
import { handleError } from '$lib/utils/handle-error';
import { api, copyToClipboard, makeSharedLinkUrl, type SharedLinkResponseDto, SharedLinkType } from '@api';
import { createEventDispatcher, onMount } from 'svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { serverConfig } from '$lib/stores/server-config.store';
import { handleError } from '$lib/utils/handle-error';
import { SharedLinkType, copyToClipboard, makeSharedLinkUrl, type SharedLinkResponseDto } from '@api';
import { createSharedLink, updateSharedLink } from '@immich/sdk';
import { mdiLink } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import BaseModal from '../base-modal.svelte';
import type { ImmichDropDownOption } from '../dropdown-button.svelte';
import DropdownButton from '../dropdown-button.svelte';
import { notificationController, NotificationType } from '../notification/notification';
import { mdiLink } from '@mdi/js';
import { serverConfig } from '$lib/stores/server-config.store';
import { NotificationType, notificationController } from '../notification/notification';
export let albumId: string | undefined = undefined;
export let assetIds: string[] = [];
@ -70,7 +71,7 @@
const expirationDate = expirationTime ? new Date(currentTime + expirationTime).toISOString() : undefined;
try {
const { data } = await api.sharedLinkApi.createSharedLink({
const data = await createSharedLink({
sharedLinkCreateDto: {
type: shareType,
albumId,
@ -135,7 +136,7 @@
? new Date(currentTime + expirationTime).toISOString()
: null;
await api.sharedLinkApi.updateSharedLink({
await updateSharedLink({
id: editingLink.id,
sharedLinkEditDto: {
description,

View file

@ -2,8 +2,8 @@
import Icon from '$lib/components/elements/icon.svelte';
import { Theme } from '$lib/constants';
import { colorTheme, mapSettings } from '$lib/stores/preferences.store';
import { api, type MapMarkerResponseDto } from '@api';
import { getMapStyle } from '@immich/sdk';
import { getAssetThumbnailUrl } from '$lib/utils';
import { getMapStyle, type MapMarkerResponseDto } from '@immich/sdk';
import { mdiCog, mdiMapMarker } from '@mdi/js';
import type { Feature, GeoJsonProperties, Geometry, Point } from 'geojson';
import type { GeoJSONSource, LngLatLike, StyleSpecification } from 'maplibre-gl';
@ -174,7 +174,7 @@
/>
{:else}
<img
src={api.getAssetThumbnailUrl(feature.properties?.id)}
src={getAssetThumbnailUrl(feature.properties?.id, undefined)}
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary"
alt={`Image with id ${feature.properties?.id}`}
/>

View file

@ -4,12 +4,11 @@
import { AppRoute } from '$lib/constants';
import { user } from '$lib/stores/user.store';
import { handleError } from '$lib/utils/handle-error';
import { UserAvatarColor } from '@api';
import { deleteProfileImage, updateUser } from '@immich/sdk';
import { deleteProfileImage, updateUser, type UserAvatarColor } from '@immich/sdk';
import { mdiCog, mdiLogout, mdiPencil } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import { notificationController, NotificationType } from '../notification/notification';
import { NotificationType, notificationController } from '../notification/notification';
import UserAvatar from '../user-avatar.svelte';
import AvatarSelector from './avatar-selector.svelte';

View file

@ -1,13 +1,15 @@
<script lang="ts">
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
import Button from '$lib/components/elements/buttons/button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { SearchSuggestionType, type PersonResponseDto } from '@api';
import { getAllPeople, getSearchSuggestions } from '@immich/sdk';
import { mdiArrowRight, mdiClose } from '@mdi/js';
import { onMount } from 'svelte';
import { fly } from 'svelte/transition';
import Combobox, { type ComboBoxOption } from '../combobox.svelte';
import { SearchSuggestionType, api, type PersonResponseDto } from '@api';
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiArrowRight, mdiClose } from '@mdi/js';
import { handleError } from '$lib/utils/handle-error';
import { onMount } from 'svelte';
enum MediaType {
All = 'all',
@ -108,8 +110,8 @@
const getPeople = async () => {
try {
const { data } = await api.personApi.getAllPeople({ withHidden: false });
suggestions.people = data.people;
const { people } = await getAllPeople({ withHidden: false });
suggestions.people = people;
} catch (error) {
handleError(error, 'Failed to get people');
}
@ -143,8 +145,8 @@
}
try {
const { data } = await api.searchApi.getSearchSuggestions({
type: type,
const data = await getSearchSuggestions({
$type: type,
country: params.country,
state: params.state,
make: params.cameraMake,
@ -251,7 +253,7 @@
<ImageThumbnail
circle
shadow
url={api.getPeopleThumbnailUrl(person.id)}
url={getPeopleThumbnailUrl(person.id)}
altText={person.name}
widthStyle="100px"
/>

View file

@ -2,8 +2,8 @@
import { page } from '$app/stores';
import { locale, sidebarSettings } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { api, type AssetApiGetAssetStatisticsRequest } from '@api';
import { getAlbumCount } from '@immich/sdk';
import { type AssetApiGetAssetStatisticsRequest } from '@api';
import { getAlbumCount, getAssetStatistics } from '@immich/sdk';
import {
mdiAccount,
mdiAccountMultiple,
@ -24,10 +24,7 @@
import SideBarButton from './side-bar-button.svelte';
import SideBarSection from './side-bar-section.svelte';
const getStats = async (dto: AssetApiGetAssetStatisticsRequest) => {
const { data: stats } = await api.assetApi.getAssetStatistics(dto);
return stats;
};
const getStats = (dto: AssetApiGetAssetStatisticsRequest) => getAssetStatistics(dto);
const handleAlbumCount = async () => {
try {

View file

@ -3,8 +3,9 @@
</script>
<script lang="ts">
import { getProfileImageUrl } from '$lib/utils';
import { type UserAvatarColor } from '@immich/sdk';
import { onMount, tick } from 'svelte';
import { UserAvatarColor, api } from '@api';
interface User {
id: string;
@ -74,7 +75,7 @@
{#if showProfileImage && user.profileImagePath}
<img
bind:this={img}
src={api.getProfileImageUrl(user.id)}
src={getProfileImageUrl(user.id)}
alt="Profile image of {title}"
class="h-full w-full object-cover"
class:hidden={showFallback}

View file

@ -1,14 +1,16 @@
<script lang="ts">
import { api, type AssetResponseDto, type SharedLinkResponseDto, SharedLinkType, ThumbnailFormat } from '@api';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import * as luxon from 'luxon';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
import Icon from '$lib/components/elements/icon.svelte';
import { AppRoute } from '$lib/constants';
import { getAssetThumbnailUrl } from '$lib/utils';
import { SharedLinkType, ThumbnailFormat, type AssetResponseDto, type SharedLinkResponseDto } from '@api';
import { getAssetInfo } from '@immich/sdk';
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
import * as luxon from 'luxon';
import { createEventDispatcher } from 'svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let link: SharedLinkResponseDto;
@ -28,9 +30,7 @@
assetId = link.assets[0].id;
}
const { data } = await api.assetApi.getAssetInfo({ id: assetId });
return data;
return getAssetInfo({ id: assetId });
};
const getCountDownExpirationDate = () => {
@ -72,7 +72,7 @@
{:then asset}
<img
id={asset.id}
src={api.getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
src={getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
alt={asset.id}
class="h-[100px] w-[100px] rounded-lg object-cover"
loading="lazy"