feat(web,server): server features (#3756)

* feat: server features

* chore: open api

* icon size

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Jason Rasmussen 2023-08-18 00:55:26 -04:00 committed by GitHub
parent 28d3d3e679
commit 2b839088c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 805 additions and 187 deletions

View file

@ -4,17 +4,23 @@
<script lang="ts">
export let color: Colors;
export let disabled = false;
const colorClasses: Record<Colors, string> = {
'light-gray': 'bg-gray-300/90 dark:bg-gray-600/90',
gray: 'bg-gray-300 dark:bg-gray-600',
};
const hoverClasses = disabled
? 'cursor-not-allowed'
: 'hover:bg-immich-primary hover:text-white dark:hover:bg-immich-dark-primary dark:hover:text-black';
</script>
<button
class="flex h-full w-full flex-col place-content-center place-items-center gap-2 px-8 py-2 text-xs text-gray-600 transition-colors hover:bg-immich-primary hover:text-white dark:text-gray-200 dark:hover:bg-immich-dark-primary dark:hover:text-black {colorClasses[
{disabled}
class="flex h-full w-full flex-col place-content-center place-items-center gap-2 px-8 py-2 text-xs text-gray-600 transition-colors dark:text-gray-200 {colorClasses[
color
]}"
]} {hoverClasses}"
on:click
>
<slot />

View file

@ -6,6 +6,7 @@
import FastForward from 'svelte-material-icons/FastForward.svelte';
import AllInclusive from 'svelte-material-icons/AllInclusive.svelte';
import Close from 'svelte-material-icons/Close.svelte';
import AlertCircle from 'svelte-material-icons/AlertCircle.svelte';
import { locale } from '$lib/stores/preferences.store';
import { createEventDispatcher } from 'svelte';
import { JobCommand, JobCommandDto, JobCountsDto, QueueStatusDto } from '@api';
@ -19,6 +20,7 @@
export let queueStatus: QueueStatusDto;
export let allowForceCommand = true;
export let icon: typeof Icon;
export let disabled = false;
export let allText: string;
export let missingText: string;
@ -94,7 +96,15 @@
</div>
</div>
<div class="flex w-full flex-row overflow-hidden sm:w-32 sm:flex-col">
{#if !isIdle}
{#if disabled}
<JobTileButton
disabled={true}
color="light-gray"
on:click={() => dispatch('command', { command: JobCommand.Start, force: false })}
>
<AlertCircle size="36" /> DISABLED
</JobTileButton>
{:else if !isIdle}
{#if waitingCount > 0}
<JobTileButton color="gray" on:click={() => dispatch('command', { command: JobCommand.Empty, force: false })}>
<Close size="24" /> CLEAR

View file

@ -4,6 +4,7 @@
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import { featureFlags } from '$lib/stores/feature-flags.store';
import { handleError } from '$lib/utils/handle-error';
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
import type { ComponentType } from 'svelte';
@ -29,6 +30,7 @@
subtitle?: string;
allText?: string;
missingText?: string;
disabled?: boolean;
icon: typeof Icon;
allowForceCommand?: boolean;
component?: ComponentType;
@ -51,7 +53,7 @@
handleCommand(JobName.RecognizeFaces, { command: JobCommand.Start, force: true });
};
const jobDetails: Partial<Record<JobName, JobDetails>> = {
$: jobDetails = <Partial<Record<JobName, JobDetails>>>{
[JobName.ThumbnailGeneration]: {
icon: FileJpgBox,
title: api.getJobName(JobName.ThumbnailGeneration),
@ -73,17 +75,20 @@
icon: TagMultiple,
title: api.getJobName(JobName.ObjectTagging),
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
disabled: !$featureFlags.machineLearning,
},
[JobName.ClipEncoding]: {
icon: VectorCircle,
title: api.getJobName(JobName.ClipEncoding),
subtitle: 'Run machine learning to generate clip embeddings',
disabled: !$featureFlags.machineLearning,
},
[JobName.RecognizeFaces]: {
icon: FaceRecognition,
title: api.getJobName(JobName.RecognizeFaces),
subtitle: 'Run machine learning to recognize faces',
handleCommand: handleFaceCommand,
disabled: !$featureFlags.machineLearning,
},
[JobName.VideoConversion]: {
icon: Video,
@ -97,8 +102,7 @@
component: StorageMigrationDescription,
},
};
const jobDetailsArray = Object.entries(jobDetails) as [JobName, JobDetails][];
$: jobList = Object.entries(jobDetails) as [JobName, JobDetails][];
async function handleCommand(jobId: JobName, jobCommand: JobCommandDto) {
const title = jobDetails[jobId]?.title;
@ -138,11 +142,12 @@
</Button>
</a>
</div>
{#each jobDetailsArray as [jobName, { title, subtitle, allText, missingText, allowForceCommand, icon, component, handleCommand: handleCommandOverride }]}
{#each jobList as [jobName, { title, subtitle, disabled, allText, missingText, allowForceCommand, icon, component, handleCommand: handleCommandOverride }]}
{@const { jobCounts, queueStatus } = jobs[jobName]}
<JobTile
{icon}
{title}
{disabled}
{subtitle}
allText={allText || 'ALL'}
missingText={missingText || 'MISSING'}

View file

@ -16,6 +16,7 @@
import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
import Cog from 'svelte-material-icons/Cog.svelte';
import UserAvatar from '../user-avatar.svelte';
import { featureFlags } from '$lib/stores/feature-flags.store';
export let user: UserResponseDto;
export let showUploadButton = true;
@ -45,17 +46,21 @@
</a>
<div class="flex justify-between gap-16 pr-6">
<div class="hidden w-full max-w-5xl flex-1 pl-4 sm:block">
<SearchBar grayTheme={true} />
{#if $featureFlags.search}
<SearchBar grayTheme={true} />
{/if}
</div>
<section class="flex place-items-center justify-end gap-4 max-sm:w-full">
<a href={AppRoute.SEARCH} id="search-button" class="pl-4 sm:hidden">
<IconButton title="Search">
<div class="flex gap-2">
<Magnify size="1.5em" />
</div>
</IconButton>
</a>
{#if $featureFlags.search}
<a href={AppRoute.SEARCH} id="search-button" class="pl-4 sm:hidden">
<IconButton title="Search">
<div class="flex gap-2">
<Magnify size="1.5em" />
</div>
</IconButton>
</a>
{/if}
<ThemeButton />

View file

@ -17,6 +17,7 @@
import SideBarButton from './side-bar-button.svelte';
import { locale } from '$lib/stores/preferences.store';
import SideBarSection from './side-bar-section.svelte';
import { featureFlags } from '$lib/stores/feature-flags.store';
const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
const { data: stats } = await api.assetApi.getAssetStats(dto);
@ -56,9 +57,11 @@
</svelte:fragment>
</SideBarButton>
</a>
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.EXPLORE} draggable="false">
<SideBarButton title="Explore" logo={Magnify} isSelected={$page.route.id === '/(user)/explore'} />
</a>
{#if $featureFlags.search}
<a data-sveltekit-preload-data="hover" data-sveltekit-noscroll href={AppRoute.EXPLORE} draggable="false">
<SideBarButton title="Explore" logo={Magnify} isSelected={$page.route.id === '/(user)/explore'} />
</a>
{/if}
<a data-sveltekit-preload-data="hover" href={AppRoute.MAP} draggable="false">
<SideBarButton title="Map" logo={Map} isSelected={$page.route.id === '/(user)/map'} />
</a>

View file

@ -2,16 +2,16 @@
import { getGithubVersion } from '$lib/utils/get-github-version';
import { onMount } from 'svelte';
import FullScreenModal from './full-screen-modal.svelte';
import type { ServerVersionReponseDto } from '@api';
import type { ServerVersionResponseDto } from '@api';
import Button from '../elements/buttons/button.svelte';
export let serverVersion: ServerVersionReponseDto;
export let serverVersion: ServerVersionResponseDto;
let showModal = false;
let githubVersion: string;
$: serverVersionName = semverToName(serverVersion);
function semverToName({ major, minor, patch }: ServerVersionReponseDto) {
function semverToName({ major, minor, patch }: ServerVersionResponseDto) {
return `v${major}.${minor}.${patch}`;
}