mirror of
https://github.com/immich-app/immich.git
synced 2025-11-22 16:10:47 +09:00
refactor(web) open api client (#7103)
* refactor: person api * refactor: shared link and others
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user