feat(server, web): quotas (#4471)

* feat: quotas

* chore: open api

* chore: update status box and upload error message

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
cfitzw 2024-01-12 18:43:36 -06:00 committed by GitHub
parent f4edb6c4bd
commit deb1f970a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 646 additions and 118 deletions

View file

@ -1,19 +1,43 @@
<script lang="ts">
import { browser } from '$app/environment';
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { websocketStore } from '$lib/stores/websocket';
import { api } from '@api';
import { onDestroy, onMount } from 'svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { UserResponseDto, api } from '@api';
import { onMount } from 'svelte';
import { asByteUnitString } from '../../utils/byte-units';
import LoadingSpinner from './loading-spinner.svelte';
import { mdiCloud, mdiDns } from '@mdi/js';
import { mdiChartPie, mdiDns } from '@mdi/js';
import { serverInfoStore } from '$lib/stores/server-info.store';
const { serverVersion, connected } = websocketStore;
let userInfo: UserResponseDto;
let usageClasses = '';
$: version = $serverVersion ? `v${$serverVersion.major}.${$serverVersion.minor}.${$serverVersion.patch}` : null;
$: usedPercentage = Math.round(($serverInfoStore?.diskUseRaw / $serverInfoStore?.diskSizeRaw) * 100);
$: hasQuota = userInfo?.quotaSizeInBytes !== null;
$: availableBytes = (hasQuota ? userInfo?.quotaSizeInBytes : $serverInfoStore.diskSizeRaw) || 0;
$: usedBytes = (hasQuota ? userInfo?.quotaUsageInBytes : $serverInfoStore.diskUseRaw) || 0;
$: usedPercentage = Math.round((usedBytes / availableBytes) * 100);
const onUpdate = () => {
usedPercentage = 81;
usageClasses = getUsageClass();
};
const getUsageClass = () => {
if (usedPercentage >= 95) {
return 'bg-red-500';
}
if (usedPercentage > 80) {
return 'bg-yellow-500';
}
return 'bg-immich-primary dark:bg-immich-dark-primary';
};
$: userInfo && onUpdate();
onMount(async () => {
await refresh();
@ -21,39 +45,33 @@
const refresh = async () => {
try {
const { data } = await api.serverInfoApi.getServerInfo();
$serverInfoStore = data;
[$serverInfoStore, userInfo] = await Promise.all([
api.serverInfoApi.getServerInfo().then(({ data }) => data),
api.userApi.getMyUserInfo().then(({ data }) => data),
]);
} catch (e) {
console.log('Error [StatusBox] [onMount]');
}
};
let interval: number;
if (browser) {
interval = window.setInterval(() => refresh(), 10_000);
}
onDestroy(() => clearInterval(interval));
</script>
<div class="dark:text-immich-dark-fg">
<div class="storage-status grid grid-cols-[64px_auto]">
<div
class="storage-status grid grid-cols-[64px_auto]"
title="Used {asByteUnitString(usedBytes, $locale, 3)} of {asByteUnitString(availableBytes, $locale, 3)}"
>
<div class="pb-[2.15rem] pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary group-hover:sm:pb-0 md:pb-0">
<Icon path={mdiCloud} size={'24'} />
<Icon path={mdiChartPie} size="24" />
</div>
<div class="hidden group-hover:sm:block md:block">
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Storage</p>
{#if $serverInfoStore}
<div class="my-2 h-[7px] w-full rounded-full bg-gray-200 dark:bg-gray-700">
<!-- style={`width: ${$downloadAssets[fileName]}%`} -->
<div
class="h-[7px] rounded-full bg-immich-primary dark:bg-immich-dark-primary"
style="width: {usedPercentage}%"
/>
<div class="h-[7px] rounded-full {usageClasses}" style="width: {usedPercentage}%" />
</div>
<p class="text-xs">
{asByteUnitString($serverInfoStore?.diskUseRaw, $locale)} of
{asByteUnitString($serverInfoStore?.diskSizeRaw, $locale)} used
{asByteUnitString(usedBytes, $locale)} of
{asByteUnitString(availableBytes, $locale)} used
</p>
{:else}
<div class="mt-2">
@ -67,7 +85,7 @@
</div>
<div class="server-status grid grid-cols-[64px_auto]">
<div class="pb-11 pl-5 pr-6 text-immich-primary dark:text-immich-dark-primary group-hover:sm:pb-0 md:pb-0">
<Icon path={mdiDns} size={'24'} />
<Icon path={mdiDns} size="26" />
</div>
<div class="hidden text-xs group-hover:sm:block md:block">
<p class="text-sm font-medium text-immich-primary dark:text-immich-dark-primary">Server</p>