feat: upload assets to locked folder (#18806)

* feat: upload assets to locked folder

* chore: refactor params
This commit is contained in:
Arno 2025-06-02 04:45:39 +02:00 committed by GitHub
parent 5589616921
commit b5c3a675b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 43 additions and 18 deletions

View File

@ -43,7 +43,7 @@
dragAndDropFilesStore.subscribe((value) => { dragAndDropFilesStore.subscribe((value) => {
if (value.isDragging && value.files.length > 0) { if (value.isDragging && value.files.length > 0) {
handlePromiseError(fileUploadHandler(value.files, album.id)); handlePromiseError(fileUploadHandler({ files: value.files, albumId: album.id }));
dragAndDropFilesStore.set({ isDragging: false, files: [] }); dragAndDropFilesStore.set({ isDragging: false, files: [] });
} }
}); });

View File

@ -52,7 +52,7 @@
let results: (string | undefined)[] = []; let results: (string | undefined)[] = [];
results = await (!files || files.length === 0 || !Array.isArray(files) results = await (!files || files.length === 0 || !Array.isArray(files)
? openFileUploadDialog() ? openFileUploadDialog()
: fileUploadHandler(files)); : fileUploadHandler({ files }));
const data = await addSharedLinkAssets({ const data = await addSharedLinkAssets({
id: sharedLink.id, id: sharedLink.id,
assetIdsDto: { assetIdsDto: {

View File

@ -4,12 +4,13 @@
import { authManager } from '$lib/managers/auth-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { fileUploadHandler } from '$lib/utils/file-uploader'; import { fileUploadHandler } from '$lib/utils/file-uploader';
import { isAlbumsRoute } from '$lib/utils/navigation'; import { isAlbumsRoute, isLockedFolderRoute } from '$lib/utils/navigation';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import ImmichLogo from './immich-logo.svelte'; import ImmichLogo from './immich-logo.svelte';
let albumId = $derived(isAlbumsRoute(page.route?.id) ? page.params.albumId : undefined); let albumId = $derived(isAlbumsRoute(page.route?.id) ? page.params.albumId : undefined);
let isInLockedFolder = $derived(isLockedFolderRoute(page.route.id));
let dragStartTarget: EventTarget | null = $state(null); let dragStartTarget: EventTarget | null = $state(null);
@ -126,7 +127,7 @@
if (authManager.key) { if (authManager.key) {
dragAndDropFilesStore.set({ isDragging: true, files: filesArray }); dragAndDropFilesStore.set({ isDragging: true, files: filesArray });
} else { } else {
await fileUploadHandler(filesArray, albumId); await fileUploadHandler({ files: filesArray, albumId, isLockedAssets: isInLockedFolder });
} }
}; };

View File

@ -32,7 +32,7 @@
const handleRetry = async (uploadAsset: UploadAsset) => { const handleRetry = async (uploadAsset: UploadAsset) => {
uploadAssetsStore.removeItem(uploadAsset.id); uploadAssetsStore.removeItem(uploadAsset.id);
await fileUploadHandler([uploadAsset.file], uploadAsset.albumId); await fileUploadHandler({ files: [uploadAsset.file], albumId: uploadAsset.albumId });
}; };
const asLink = (asset: UploadAsset) => { const asLink = (asset: UploadAsset) => {

View File

@ -7,6 +7,7 @@ import { ExecutorQueue } from '$lib/utils/executor-queue';
import { import {
Action, Action,
AssetMediaStatus, AssetMediaStatus,
AssetVisibility,
checkBulkUpload, checkBulkUpload,
getAssetOriginalPath, getAssetOriginalPath,
getBaseUrl, getBaseUrl,
@ -73,7 +74,7 @@ export const openFileUploadDialog = async (options: FileUploadParam = {}) => {
} }
const files = Array.from(target.files); const files = Array.from(target.files);
resolve(fileUploadHandler(files, albumId, assetId)); resolve(fileUploadHandler({ files, albumId, replaceAssetId: assetId }));
}); });
fileSelector.click(); fileSelector.click();
@ -84,11 +85,16 @@ export const openFileUploadDialog = async (options: FileUploadParam = {}) => {
}); });
}; };
export const fileUploadHandler = async ( type FileUploadHandlerParams = Omit<FileUploaderParams, 'deviceAssetId' | 'assetFile'> & {
files: File[], files: File[];
albumId?: string, };
replaceAssetId?: string,
): Promise<string[]> => { export const fileUploadHandler = async ({
files,
albumId,
replaceAssetId,
isLockedAssets = false,
}: FileUploadHandlerParams): Promise<string[]> => {
const extensions = await getExtensions(); const extensions = await getExtensions();
const promises = []; const promises = [];
for (const file of files) { for (const file of files) {
@ -96,7 +102,11 @@ export const fileUploadHandler = async (
if (extensions.some((extension) => name.endsWith(extension))) { if (extensions.some((extension) => name.endsWith(extension))) {
const deviceAssetId = getDeviceAssetId(file); const deviceAssetId = getDeviceAssetId(file);
uploadAssetsStore.addItem({ id: deviceAssetId, file, albumId }); uploadAssetsStore.addItem({ id: deviceAssetId, file, albumId });
promises.push(uploadExecutionQueue.addTask(() => fileUploader(file, deviceAssetId, albumId, replaceAssetId))); promises.push(
uploadExecutionQueue.addTask(() =>
fileUploader({ assetFile: file, deviceAssetId, albumId, replaceAssetId, isLockedAssets }),
),
);
} }
} }
@ -108,13 +118,22 @@ function getDeviceAssetId(asset: File) {
return 'web' + '-' + asset.name + '-' + asset.lastModified; return 'web' + '-' + asset.name + '-' + asset.lastModified;
} }
type FileUploaderParams = {
assetFile: File;
albumId?: string;
replaceAssetId?: string;
isLockedAssets?: boolean;
deviceAssetId: string;
};
// TODO: should probably use the @api SDK // TODO: should probably use the @api SDK
async function fileUploader( async function fileUploader({
assetFile: File, assetFile,
deviceAssetId: string, deviceAssetId,
albumId?: string, albumId,
replaceAssetId?: string, replaceAssetId,
): Promise<string | undefined> { isLockedAssets = false,
}: FileUploaderParams): Promise<string | undefined> {
const fileCreatedAt = new Date(assetFile.lastModified).toISOString(); const fileCreatedAt = new Date(assetFile.lastModified).toISOString();
const $t = get(t); const $t = get(t);
@ -134,6 +153,10 @@ async function fileUploader(
formData.append(key, value); formData.append(key, value);
} }
if (isLockedAssets) {
formData.append('visibility', AssetVisibility.Locked);
}
let responseData: { id: string; status: AssetMediaStatus; isTrashed?: boolean } | undefined; let responseData: { id: string; status: AssetMediaStatus; isTrashed?: boolean } | undefined;
const key = authManager.key; const key = authManager.key;
if (crypto?.subtle?.digest && !key) { if (crypto?.subtle?.digest && !key) {

View File

@ -17,6 +17,7 @@ export const isSharedLinkRoute = (route?: string | null) => !!route?.startsWith(
export const isSearchRoute = (route?: string | null) => !!route?.startsWith('/(user)/search'); export const isSearchRoute = (route?: string | null) => !!route?.startsWith('/(user)/search');
export const isAlbumsRoute = (route?: string | null) => !!route?.startsWith('/(user)/albums/[albumId=id]'); export const isAlbumsRoute = (route?: string | null) => !!route?.startsWith('/(user)/albums/[albumId=id]');
export const isPeopleRoute = (route?: string | null) => !!route?.startsWith('/(user)/people/[personId]'); export const isPeopleRoute = (route?: string | null) => !!route?.startsWith('/(user)/people/[personId]');
export const isLockedFolderRoute = (route?: string | null) => !!route?.startsWith('/(user)/locked');
export const isAssetViewerRoute = (target?: NavigationTarget | null) => export const isAssetViewerRoute = (target?: NavigationTarget | null) =>
!!(target?.route.id?.endsWith('/[[assetId=id]]') && 'assetId' in (target?.params || {})); !!(target?.route.id?.endsWith('/[[assetId=id]]') && 'assetId' in (target?.params || {}));