storage bar changes/file kinds loader

This commit is contained in:
myung03 2024-06-26 16:28:20 -07:00
parent 4735adcb66
commit 45e54f33ee
5 changed files with 118 additions and 97 deletions

View file

@ -5,7 +5,7 @@ import { motion } from 'framer-motion';
import React, { MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react'; import React, { MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { KindStatistic, uint32ArrayToBigInt, useLibraryQuery } from '@sd/client'; import { KindStatistic, uint32ArrayToBigInt, useLibraryQuery } from '@sd/client';
import { Card, Tooltip } from '@sd/ui'; import { Card, Loader, Tooltip } from '@sd/ui';
import { useIsDark, useLocale } from '~/hooks'; import { useIsDark, useLocale } from '~/hooks';
const INFO_ICON_CLASSLIST = const INFO_ICON_CLASSLIST =
@ -71,7 +71,7 @@ const FileKindStats: React.FC<FileKindStatsProps> = () => {
const isDark = useIsDark(); const isDark = useIsDark();
const navigate = useNavigate(); const navigate = useNavigate();
const { t } = useLocale(); const { t } = useLocale();
const { data } = useLibraryQuery(['library.kindStatistics']); const { data, isLoading } = useLibraryQuery(['library.kindStatistics']);
const [fileKinds, setFileKinds] = useState<FileKind[]>([]); const [fileKinds, setFileKinds] = useState<FileKind[]>([]);
const [cardWidth, setCardWidth] = useState<number>(0); const [cardWidth, setCardWidth] = useState<number>(0);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
@ -182,90 +182,110 @@ const FileKindStats: React.FC<FileKindStatsProps> = () => {
ref={containerRef} ref={containerRef}
className="max-w-1/2 group mx-1 flex h-[220px] w-full min-w-[400px] shrink-0 flex-col gap-2 bg-app-box/50" className="max-w-1/2 group mx-1 flex h-[220px] w-full min-w-[400px] shrink-0 flex-col gap-2 bg-app-box/50"
> >
<div className={TOTAL_FILES_CLASSLIST}> {isLoading ? (
<Tooltip className="flex items-center" label={t('bar_graph_info')}> <>
<div className="flex items-center gap-2"> <div className="m-auto flex flex-col items-center justify-center gap-5">
<span <Loader />
className={clsx( <p className="text-m font-medium text-ink-faint">
'text-xl font-black', Calculating file kinds...
isDark ? 'text-white' : 'text-black' </p>
)} </div>
> </>
{data?.total_identified_files ) : (
? formatNumberWithCommas(data.total_identified_files) <>
: '0'}{' '} <div className={TOTAL_FILES_CLASSLIST}>
</span> <Tooltip className="flex items-center" label={t('bar_graph_info')}>
<div className="flex items-center"> <div className="flex items-center gap-2">
{t('total_files')} <span
<Info weight="fill" className={INFO_ICON_CLASSLIST} /> className={clsx(
'text-xl font-black',
isDark ? 'text-white' : 'text-black'
)}
>
{data?.total_identified_files
? formatNumberWithCommas(data.total_identified_files)
: '0'}{' '}
</span>
<div className="flex items-center">
{t('total_files')}
<Info weight="fill" className={INFO_ICON_CLASSLIST} />
</div>
</div>
</Tooltip>
<div className={UNIDENTIFIED_FILES_CLASSLIST}>
<Tooltip label={t('unidentified_files_info')}>
<span>
{data?.total_unidentified_files
? formatNumberWithCommas(data.total_unidentified_files)
: '0'}{' '}
unidentified files
</span>
</Tooltip>
</div> </div>
</div> </div>
</Tooltip> <div className={BARS_CONTAINER_CLASSLIST}>
<div className={UNIDENTIFIED_FILES_CLASSLIST}> {sortedFileKinds.map((fileKind, index) => {
<Tooltip label={t('unidentified_files_info')}> const iconImage = iconsRef.current[fileKind.kind];
<span> const barColor = interpolateHexColor(
{data?.total_unidentified_files BAR_COLOR_START,
? formatNumberWithCommas(data.total_unidentified_files) BAR_COLOR_END,
: '0'}{' '} index / (barCount - 1)
unidentified files );
</span>
</Tooltip>
</div>
</div>
<div className={BARS_CONTAINER_CLASSLIST}>
{sortedFileKinds.map((fileKind, index) => {
const iconImage = iconsRef.current[fileKind.kind];
const barColor = interpolateHexColor(
BAR_COLOR_START,
BAR_COLOR_END,
index / (barCount - 1)
);
const barHeight = const barHeight =
mapFractionalValue(fileKind.count, maxFileCount, BAR_MAX_HEIGHT) + 'px'; mapFractionalValue(
return ( fileKind.count,
<> maxFileCount,
<Tooltip BAR_MAX_HEIGHT
asChild ) + 'px';
key={fileKind.kind} return (
label={ <>
formatNumberWithCommas(fileKind.count) + <Tooltip
' ' + asChild
fileKind.kind + key={fileKind.kind}
's' label={
} formatNumberWithCommas(fileKind.count) +
position="left" ' ' +
> fileKind.kind +
<div 's'
className="relative flex w-full min-w-8 max-w-10 grow cursor-pointer flex-col items-center" }
onDoubleClick={makeBarClickHandler(fileKind)} position="left"
> >
{iconImage && ( <div
<img className="relative flex w-full min-w-8 max-w-10 grow cursor-pointer flex-col items-center"
src={iconImage.src} onDoubleClick={makeBarClickHandler(fileKind)}
alt={fileKind.kind} >
className="relative mb-1 size-4 duration-500" {iconImage && (
/> <img
)} src={iconImage.src}
<motion.div alt={fileKind.kind}
className="flex w-full flex-col items-center rounded transition-all duration-500" className="relative mb-1 size-4 duration-500"
initial={{ height: 0 }} />
animate={{ height: barHeight }} )}
transition={{ duration: 0.4, ease: [0.42, 0, 0.58, 1] }} <motion.div
style={{ className="flex w-full flex-col items-center rounded transition-all duration-500"
height: barHeight, initial={{ height: 0 }}
backgroundColor: barColor animate={{ height: barHeight }}
}} transition={{
></motion.div> duration: 0.4,
</div> ease: [0.42, 0, 0.58, 1]
</Tooltip> }}
<div className="sm col-span-1 row-start-2 row-end-auto text-center text-[10px] font-medium text-ink-faint"> style={{
{formatCount(fileKind.count)} height: barHeight,
</div> backgroundColor: barColor
</> }}
); ></motion.div>
})} </div>
</div> </Tooltip>
<div className="sm col-span-1 row-start-2 row-end-auto text-center text-[10px] font-medium text-ink-faint">
{formatCount(fileKind.count)}
</div>
</>
);
})}
</div>
</>
)}
</Card> </Card>
</div> </div>
); );

View file

@ -86,18 +86,18 @@ const LibraryStats = () => {
const StatItemNames: Partial<Record<keyof Statistics, string>> = { const StatItemNames: Partial<Record<keyof Statistics, string>> = {
total_library_bytes: t('library_bytes'), total_library_bytes: t('library_bytes'),
total_local_bytes_capacity: t('total_bytes_capacity'),
total_local_bytes_free: t('total_bytes_free'),
library_db_size: t('library_db_size'), library_db_size: t('library_db_size'),
total_library_preview_media_bytes: t('preview_media_bytes') total_library_preview_media_bytes: t('preview_media_bytes'),
total_local_bytes_capacity: t('total_bytes_capacity'),
total_local_bytes_free: t('total_bytes_free')
}; };
const StatDescriptions: Partial<Record<keyof Statistics, string>> = { const StatDescriptions: Partial<Record<keyof Statistics, string>> = {
total_library_bytes: t('library_bytes_description'), total_library_bytes: t('library_bytes_description'),
total_local_bytes_capacity: t('total_bytes_capacity_description'),
total_local_bytes_free: t('total_bytes_free_description'),
library_db_size: t('library_db_size_description'), library_db_size: t('library_db_size_description'),
total_library_preview_media_bytes: t('preview_media_bytes_description') total_library_preview_media_bytes: t('preview_media_bytes_description'),
total_local_bytes_capacity: t('total_bytes_capacity_description'),
total_local_bytes_free: t('total_bytes_free_description')
}; };
const displayableStatItems = Object.keys( const displayableStatItems = Object.keys(
@ -113,6 +113,7 @@ const LibraryStats = () => {
const totalUsedSpace = Number(statistics.total_local_bytes_used); const totalUsedSpace = Number(statistics.total_local_bytes_used);
// Define the major categories and aggregate the "Other" category // Define the major categories and aggregate the "Other" category
// TODO: edit to use library size as total capacity and split bar into major categories without system data
const majorCategories = ['Document', 'Text', 'Image', 'Video']; const majorCategories = ['Document', 'Text', 'Image', 'Video'];
const aggregatedData = (storageBarData ?? []).reduce( const aggregatedData = (storageBarData ?? []).reduce(
(acc, curr) => { (acc, curr) => {
@ -165,7 +166,7 @@ const LibraryStats = () => {
return ( return (
<Card className="flex h-[220px] w-[750px] shrink-0 flex-col bg-app-box/50"> <Card className="flex h-[220px] w-[750px] shrink-0 flex-col bg-app-box/50">
<div className="mb-1 flex overflow-hidden p-4"> <div className="flex overflow-hidden p-4">
{Object.entries(statistics) {Object.entries(statistics)
.sort( .sort(
([a], [b]) => ([a], [b]) =>

View file

@ -3,7 +3,7 @@ import { humanizeSize } from '@sd/client';
import { Tooltip } from '@sd/ui'; import { Tooltip } from '@sd/ui';
import { useIsDark } from '~/hooks'; import { useIsDark } from '~/hooks';
const BARWIDTH = 700; const BARWIDTH = 750;
const lightenColor = (color: string, percent: number) => { const lightenColor = (color: string, percent: number) => {
const num = parseInt(color.replace('#', ''), 16); const num = parseInt(color.replace('#', ''), 16);
@ -109,7 +109,7 @@ const StorageBar: React.FC<StorageBarProps> = ({ sections, totalSpace }) => {
{sections.map((section, index) => ( {sections.map((section, index) => (
<Tooltip key={index} label={section.tooltip} position="top"> <Tooltip key={index} label={section.tooltip} position="top">
<div <div
className="mb-2 mr-6 flex items-center" className="mb-2 mr-8 flex items-center"
onMouseEnter={() => setHoveredSectionIndex(index)} onMouseEnter={() => setHoveredSectionIndex(index)}
onMouseLeave={() => setHoveredSectionIndex(null)} onMouseLeave={() => setHoveredSectionIndex(null)}
> >

View file

@ -715,7 +715,7 @@
"toggle_sidebar": "تبديل الشريط الجانبي", "toggle_sidebar": "تبديل الشريط الجانبي",
"tools": "أدوات", "tools": "أدوات",
"total_bytes_capacity": "Total capacity", "total_bytes_capacity": "Total capacity",
"total_bytes_capacity_description": "The total capacity of all nodes connected to the library. May show incorrect values during alpha.", "total_bytes_capacity_description": "The total capacity of the current nodes connected to the library. May show incorrect values during alpha.",
"total_bytes_free": "Free space", "total_bytes_free": "Free space",
"total_bytes_free_description": "Free space available on all nodes connected to the library.", "total_bytes_free_description": "Free space available on all nodes connected to the library.",
"total_bytes_used": "Total used space", "total_bytes_used": "Total used space",

View file

@ -707,10 +707,10 @@
"toggle_quick_preview": "Toggle quick preview", "toggle_quick_preview": "Toggle quick preview",
"toggle_sidebar": "Toggle sidebar", "toggle_sidebar": "Toggle sidebar",
"tools": "Tools", "tools": "Tools",
"total_bytes_capacity": "Total capacity", "total_bytes_capacity": "Total local capacity",
"total_bytes_capacity_description": "The total capacity of all nodes connected to the library. May show incorrect values during alpha.", "total_bytes_capacity_description": "The total capacity the current node. May show incorrect values during alpha.",
"total_bytes_free": "Free space", "total_bytes_free": "Free local space",
"total_bytes_free_description": "Free space available on all nodes connected to the library.", "total_bytes_free_description": "Free space available on the current node.",
"total_bytes_used": "Total used space", "total_bytes_used": "Total used space",
"total_bytes_used_description": "Total space used on all nodes connected to the library.", "total_bytes_used_description": "Total space used on all nodes connected to the library.",
"total_files": "Total files", "total_files": "Total files",