mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
Feature - Add upload functionality on Web (#231)
* Added file selector * Extract metadata to upload files to the web * Added request for uploading * Generate jpeg/Webp thumbnail for asset uploaded without thumbnail data * Added generating thumbnail for video and WebSocket broadcast after thumbnail is generated * Added video length extraction * Added Uploading Panel * Added upload progress store and styling the uploaded asset * Added condition to only show upload panel when there is upload in progress * Remove asset from the upload list after successfully uploading * Added WebSocket to listen to upload event on the web * Added mechanism to check for existing assets before uploading on the web * Added test workflow * Update readme
This commit is contained in:
@@ -22,8 +22,8 @@
|
||||
import { blur } from 'svelte/transition';
|
||||
|
||||
import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte';
|
||||
import FullScreenModal from '../lib/components/shared/full-screen-modal.svelte';
|
||||
import AnnouncementBox from '../lib/components/shared/announcement-box.svelte';
|
||||
import AnnouncementBox from '$lib/components/shared/announcement-box.svelte';
|
||||
import UploadPanel from '$lib/components/shared/upload-panel.svelte';
|
||||
|
||||
export let url: string;
|
||||
export let shouldShowAnnouncement: boolean;
|
||||
@@ -36,7 +36,7 @@
|
||||
<div transition:blur={{ duration: 250 }}>
|
||||
<slot />
|
||||
<DownloadPanel />
|
||||
|
||||
<UploadPanel />
|
||||
{#if shouldShowAnnouncement}
|
||||
<AnnouncementBox {localVersion} {remoteVersion} on:close={() => (shouldShowAnnouncement = false)} />
|
||||
{/if}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<script lang="ts">
|
||||
import { serverEndpoint } from '$lib/constants';
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let isAdminUserExist: boolean;
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
import AssetViewer from '../../lib/components/asset-viewer/asset-viewer.svelte';
|
||||
import DownloadPanel from '../../lib/components/asset-viewer/download-panel.svelte';
|
||||
import StatusBox from '../../lib/components/shared/status-box.svelte';
|
||||
import { fileUploader } from '../../lib/utils/file-uploader';
|
||||
import { openWebsocketConnection } from '../../lib/stores/websocket';
|
||||
|
||||
export let user: ImmichUser;
|
||||
let selectedAction: AppSideBarSelection;
|
||||
@@ -64,6 +66,8 @@
|
||||
|
||||
if ($session.user) {
|
||||
await getAssetsInfo($session.user.accessToken);
|
||||
|
||||
openWebsocketConnection($session.user.accessToken);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,7 +83,34 @@
|
||||
currentViewAssetIndex = $flattenAssetGroupByDate.findIndex((a) => a.id == assetId);
|
||||
currentSelectedAsset = $flattenAssetGroupByDate[currentViewAssetIndex];
|
||||
isShowAsset = true;
|
||||
// pushState(assetId);
|
||||
};
|
||||
|
||||
const uploadClickedHandler = async () => {
|
||||
if ($session.user) {
|
||||
try {
|
||||
let fileSelector = document.createElement('input');
|
||||
|
||||
fileSelector.type = 'file';
|
||||
fileSelector.multiple = true;
|
||||
fileSelector.accept = 'image/*,video/*,.heic,.heif';
|
||||
|
||||
fileSelector.onchange = async (e: any) => {
|
||||
const files = Array.from<File>(e.target.files);
|
||||
|
||||
const acceptedFile = files.filter(
|
||||
(e) => e.type.split('/')[0] === 'video' || e.type.split('/')[0] === 'image',
|
||||
);
|
||||
|
||||
for (const asset of acceptedFile) {
|
||||
await fileUploader(asset, $session.user!.accessToken);
|
||||
}
|
||||
};
|
||||
|
||||
fileSelector.click();
|
||||
} catch (e) {
|
||||
console.log('Error seelcting file', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -88,10 +119,10 @@
|
||||
</svelte:head>
|
||||
|
||||
<section>
|
||||
<NavigationBar {user} />
|
||||
<NavigationBar {user} on:uploadClicked={uploadClickedHandler} />
|
||||
</section>
|
||||
|
||||
<section class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen">
|
||||
<section class="grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg">
|
||||
<!-- Sidebar -->
|
||||
<section id="sidebar" class="flex flex-col gap-4 pt-8 pr-6">
|
||||
<SideBarButton
|
||||
@@ -111,7 +142,7 @@
|
||||
|
||||
<!-- Main Section -->
|
||||
<section class="overflow-y-auto relative">
|
||||
<section id="assets-content" class="relative pt-8 pl-4">
|
||||
<section id="assets-content" class="relative pt-8 pl-4 mb-12 bg-immich-bg">
|
||||
<section id="image-grid" class="flex flex-wrap gap-14">
|
||||
{#each $assetsGroupByDate as assetsInDateGroup, groupIndex}
|
||||
<!-- Asset Group By Date -->
|
||||
@@ -121,7 +152,7 @@
|
||||
on:mouseleave={() => (isMouseOverGroup = false)}
|
||||
>
|
||||
<!-- Date group title -->
|
||||
<p class="font-medium text-sm text-black mb-2 flex place-items-center h-6">
|
||||
<p class="font-medium text-sm text-immich-fg mb-2 flex place-items-center h-6">
|
||||
{#if selectedGroupThumbnail === groupIndex && isMouseOverGroup}
|
||||
<div
|
||||
in:fly={{ x: -24, duration: 200, opacity: 0.5 }}
|
||||
@@ -136,7 +167,7 @@
|
||||
</p>
|
||||
|
||||
<!-- Image grid -->
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<div class="flex flex-wrap gap-[2px]">
|
||||
{#each assetsInDateGroup as asset}
|
||||
<ImmichThumbnail
|
||||
{asset}
|
||||
|
||||
Reference in New Issue
Block a user