Migrate paths dashboard widget to react and add storage metrics

This commit is contained in:
Bill Thornton
2025-06-03 16:28:22 -04:00
parent a938650ded
commit 09063d3376
11 changed files with 322 additions and 81 deletions
+22
View File
@@ -0,0 +1,22 @@
import { describe, expect, it } from 'vitest';
import { getReadableSize } from './file';
describe('getReadableSize()', () => {
it('should return the correct units', () => {
expect(getReadableSize(5)).toBe('5.0 Bytes');
expect(getReadableSize(1024)).toBe('1.0 KiB');
expect(getReadableSize(1024 * 1024)).toBe('1.0 MiB');
expect(getReadableSize(1024 * 1024 * 1024)).toBe('1.0 GiB');
expect(getReadableSize(1024 * 1024 * 1024 * 1024)).toBe('1.0 TiB');
expect(getReadableSize(1024 * 1024 * 1024 * 1024 * 1024)).toBe('1.0 PiB');
expect(getReadableSize(1024 * 1024 * 1024 * 1024 * 1024 * 1024)).toBe('1.0 EiB');
expect(getReadableSize(1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)).toBe('1.0 ZiB');
expect(getReadableSize(1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)).toBe('1.0 YiB');
});
it('should return the correct precision', () => {
expect(getReadableSize(12345, 0)).toBe('12 KiB');
expect(getReadableSize(12345, 2)).toBe('12.06 KiB');
expect(getReadableSize(12345, 3)).toBe('12.056 KiB');
});
});
+8
View File
@@ -28,3 +28,11 @@ export function readFileAsText(file: File): Promise<string> {
reader.readAsText(file);
});
}
/** Gets a human readable string representing a file size in bytes */
export function getReadableSize(value: number, precision = 1) {
let d = Math.log(value) / Math.log(1024) | 0;
return (value / Math.pow(1024, d)).toFixed(precision)
+ ' ' + (d ? 'KMGTPEZY'[--d] + 'iB' : 'Bytes');
}
+17 -19
View File
@@ -1,36 +1,34 @@
import { createRoot } from 'react-dom/client';
import * as React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { QueryClientProvider } from '@tanstack/react-query';
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { ApiProvider } from 'hooks/useApi';
import { UserSettingsProvider } from 'hooks/useUserSettings';
import { WebConfigProvider } from 'hooks/useWebConfig';
import appTheme from 'themes/themes';
import { queryClient } from 'utils/query/queryClient';
import { useUserTheme } from 'hooks/useUserTheme';
import { ThemeProvider } from '@mui/material/styles';
import { getTheme } from 'themes/themes';
export const attachReactElement = (Element: (props: object) => React.ReactNode, props: object, element: HTMLElement, replace = false) => {
const domNode = document.createElement('div');
const root = createRoot(replace ? domNode : element);
root.render(
<RootContext>
<Element {...props} />
</RootContext>
);
if (replace) {
element.replaceWith(domNode);
}
export const renderComponent = <P extends object> (
Component: React.FC<P>,
props: P,
element: HTMLElement
) => {
createRoot(element)
.render(
<RootContext>
<Component {...props} />
</RootContext>
);
};
const RootContext: React.FC<React.PropsWithChildren> = ({ children }) => {
const { theme } = useUserTheme();
return (
<QueryClientProvider client={queryClient}>
<ApiProvider>
<UserSettingsProvider>
<WebConfigProvider>
<ThemeProvider theme={getTheme(theme)}>
<ThemeProvider theme={appTheme} defaultMode='dark'>
{children}
</ThemeProvider>
</WebConfigProvider>