Skip to content

Commit

Permalink
Add FileSize component and refactor file size rendering in various co…
Browse files Browse the repository at this point in the history
…mponents (#5695)
  • Loading branch information
WithoutPants authored Mar 3, 2025
1 parent a391fa4 commit ce2d779
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 125 deletions.
32 changes: 7 additions & 25 deletions ui/v2.5/src/components/Images/ImageDetails/ImageFileInfoPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useState } from "react";
import { Accordion, Button, Card } from "react-bootstrap";
import { FormattedMessage, FormattedNumber, FormattedTime } from "react-intl";
import { FormattedMessage, FormattedTime } from "react-intl";
import { TruncatedText } from "src/components/Shared/TruncatedText";
import { DeleteFilesDialog } from "src/components/Shared/DeleteFilesDialog";
import * as GQL from "src/core/generated-graphql";
import { mutateImageSetPrimaryFile } from "src/core/StashService";
import { useToast } from "src/hooks/Toast";
import TextUtils from "src/utils/text";
import { TextField, URLField, URLsField } from "src/utils/field";
import { FileSize } from "src/components/Shared/FileSize";

interface IFileInfoPanelProps {
file: GQL.ImageFileDataFragment | GQL.VideoFileDataFragment;
Expand All @@ -21,29 +22,6 @@ interface IFileInfoPanelProps {
const FileInfoPanel: React.FC<IFileInfoPanelProps> = (
props: IFileInfoPanelProps
) => {
function renderFileSize() {
if (props.file.size === undefined) {
return;
}

const { size, unit } = TextUtils.fileSize(props.file.size ?? 0);

return (
<TextField id="filesize">
<span className="text-truncate">
<FormattedNumber
value={size}
// eslint-disable-next-line react/style-prop-object
style="unit"
unit={unit}
unitDisplay="narrow"
maximumFractionDigits={2}
/>
</span>
</TextField>
);
}

const checksum = props.file.fingerprints.find((f) => f.type === "md5");

return (
Expand All @@ -64,7 +42,11 @@ const FileInfoPanel: React.FC<IFileInfoPanelProps> = (
value={`file://${props.file.path}`}
truncate
/>
{renderFileSize()}
<TextField id="filesize">
<span className="text-truncate">
<FileSize size={props.file.size} />
</span>
</TextField>
<TextField id="file_mod_time">
<FormattedTime
dateStyle="medium"
Expand Down
13 changes: 3 additions & 10 deletions ui/v2.5/src/components/Images/ImageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import "flexbin/flexbin.css";
import Gallery from "react-photo-gallery";
import { ExportDialog } from "../Shared/ExportDialog";
import { objectTitle } from "src/core/files";
import TextUtils from "src/utils/text";
import { ConfigurationContext } from "src/hooks/Config";
import { ImageGridCard } from "./ImageGridCard";
import { View } from "../List/views";
import { IItemListOperation } from "../List/FilteredListToolbar";
import { FileSize } from "../Shared/FileSize";

interface IImageWallProps {
images: GQL.SlimImageDataFragment[];
Expand Down Expand Up @@ -230,7 +230,6 @@ function getCount(result: GQL.FindImagesQueryResult) {
function renderMetadataByline(result: GQL.FindImagesQueryResult) {
const megapixels = result?.data?.findImages?.megapixels;
const size = result?.data?.findImages?.filesize;
const filesize = size ? TextUtils.fileSize(size) : undefined;

if (!megapixels && !size) {
return;
Expand All @@ -247,15 +246,9 @@ function renderMetadataByline(result: GQL.FindImagesQueryResult) {
</span>
) : undefined}
{separator}
{size && filesize ? (
{size ? (
<span className="images-size">
<FormattedNumber
value={filesize.size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(
filesize.unit
)}
/>
{` ${TextUtils.formatFileSizeUnit(filesize.unit)}`}
<FileSize size={size} />
</span>
) : undefined}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { SceneMergeModal } from "../Scenes/SceneMergeDialog";
import { objectTitle } from "src/core/files";
import { FileSize } from "../Shared/FileSize";

const CLASSNAME = "duplicate-checker";

Expand Down Expand Up @@ -326,19 +327,6 @@ export const SceneDuplicateChecker: React.FC = () => {
resetCheckboxSelection();
}

const renderFilesize = (filesize: number | null | undefined) => {
const { size: parsedSize, unit } = TextUtils.fileSize(filesize ?? 0);
return (
<FormattedNumber
value={parsedSize}
style="unit"
unit={unit}
unitDisplay="narrow"
maximumFractionDigits={2}
/>
);
};

function maybeRenderMissingPhashWarning() {
const missingPhashes = missingPhash?.findScenes.count ?? 0;
if (missingPhashes > 0) {
Expand Down Expand Up @@ -917,7 +905,9 @@ export const SceneDuplicateChecker: React.FC = () => {
{file?.duration &&
TextUtils.secondsToTimestamp(file.duration)}
</td>
<td>{renderFilesize(file?.size ?? 0)}</td>
<td>
<FileSize size={file?.size ?? 0} />
</td>
<td>{`${file?.width ?? 0}x${file?.height ?? 0}`}</td>
<td>
<FormattedNumber
Expand Down
17 changes: 4 additions & 13 deletions ui/v2.5/src/components/Scenes/SceneCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ConfigurationContext } from "src/hooks/Config";
import { PerformerPopoverButton } from "../Shared/PerformerPopoverButton";
import { GridCard, calculateCardWidth } from "../Shared/GridCard/GridCard";
import { RatingBanner } from "../Shared/RatingBanner";
import { FormattedMessage, FormattedNumber } from "react-intl";
import { FormattedMessage } from "react-intl";
import {
faBox,
faCopy,
Expand All @@ -30,6 +30,7 @@ import { PatchComponent } from "src/patch";
import ScreenUtils from "src/utils/screen";
import { StudioOverlay } from "../Shared/GridCard/StudioOverlay";
import { GroupTag } from "../Groups/GroupTag";
import { FileSize } from "../Shared/FileSize";

interface IScenePreviewProps {
isPortrait: boolean;
Expand Down Expand Up @@ -362,21 +363,11 @@ const SceneCardImage = PatchComponent(
);

function maybeRenderSceneSpecsOverlay() {
let sizeObj = null;
if (file?.size) {
sizeObj = TextUtils.fileSize(file.size);
}
return (
<div className="scene-specs-overlay">
{sizeObj != null ? (
{file?.size !== undefined ? (
<span className="overlay-filesize extra-scene-info">
<FormattedNumber
value={sizeObj.size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(
sizeObj.unit
)}
/>
{TextUtils.formatFileSizeUnit(sizeObj.unit)}
<FileSize size={file.size} />
</span>
) : (
""
Expand Down
26 changes: 6 additions & 20 deletions ui/v2.5/src/components/Scenes/SceneDetails/SceneFileInfoPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import TextUtils from "src/utils/text";
import { TextField, URLField, URLsField } from "src/utils/field";
import { StashIDPill } from "src/components/Shared/StashID";
import { PatchComponent } from "../../../patch";
import { FileSize } from "src/components/Shared/FileSize";

interface IFileInfoPanelProps {
sceneID: string;
Expand All @@ -36,25 +37,6 @@ const FileInfoPanel: React.FC<IFileInfoPanelProps> = (
const intl = useIntl();
const history = useHistory();

function renderFileSize() {
const { size, unit } = TextUtils.fileSize(props.file.size);

return (
<TextField id="filesize">
<span className="text-truncate">
<FormattedNumber
value={size}
// eslint-disable-next-line react/style-prop-object
style="unit"
unit={unit}
unitDisplay="narrow"
maximumFractionDigits={2}
/>
</span>
</TextField>
);
}

// TODO - generalise fingerprints
const oshash = props.file.fingerprints.find((f) => f.type === "oshash");
const phash = props.file.fingerprints.find((f) => f.type === "phash");
Expand Down Expand Up @@ -94,7 +76,11 @@ const FileInfoPanel: React.FC<IFileInfoPanelProps> = (
value={`file://${props.file.path}`}
truncate
/>
{renderFileSize()}
<TextField id="filesize">
<span className="text-truncate">
<FileSize size={props.file.size} />
</span>
</TextField>
<TextField id="file_mod_time">
<FormattedTime
dateStyle="medium"
Expand Down
14 changes: 4 additions & 10 deletions ui/v2.5/src/components/Scenes/SceneList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import cloneDeep from "lodash-es/cloneDeep";
import { FormattedNumber, useIntl } from "react-intl";
import { useIntl } from "react-intl";
import { useHistory } from "react-router-dom";
import Mousetrap from "mousetrap";
import * as GQL from "src/core/generated-graphql";
Expand All @@ -25,6 +25,7 @@ import { SceneMergeModal } from "./SceneMergeDialog";
import { objectTitle } from "src/core/files";
import TextUtils from "src/utils/text";
import { View } from "../List/views";
import { FileSize } from "../Shared/FileSize";

function getItems(result: GQL.FindScenesQueryResult) {
return result?.data?.findScenes?.scenes ?? [];
Expand All @@ -37,7 +38,6 @@ function getCount(result: GQL.FindScenesQueryResult) {
function renderMetadataByline(result: GQL.FindScenesQueryResult) {
const duration = result?.data?.findScenes?.duration;
const size = result?.data?.findScenes?.filesize;
const filesize = size ? TextUtils.fileSize(size) : undefined;

if (!duration && !size) {
return;
Expand All @@ -54,15 +54,9 @@ function renderMetadataByline(result: GQL.FindScenesQueryResult) {
</span>
) : undefined}
{separator}
{size && filesize ? (
{size ? (
<span className="scenes-size">
<FormattedNumber
value={filesize.size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(
filesize.unit
)}
/>
{` ${TextUtils.formatFileSizeUnit(filesize.unit)}`}
<FileSize size={size} />
</span>
) : undefined}
)
Expand Down
21 changes: 5 additions & 16 deletions ui/v2.5/src/components/Scenes/SceneListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { Link } from "react-router-dom";
import * as GQL from "src/core/generated-graphql";
import NavUtils from "src/utils/navigation";
import TextUtils from "src/utils/text";
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
import { FormattedMessage, useIntl } from "react-intl";
import { objectTitle } from "src/core/files";
import { galleryTitle } from "src/core/galleries";
import SceneQueue from "src/models/sceneQueue";
import { RatingSystem } from "../Shared/Rating/RatingSystem";
import { useSceneUpdate } from "src/core/StashService";
import { IColumn, ListTable } from "../List/ListTable";
import { useTableColumns } from "src/hooks/useTableColumns";
import { FileSize } from "../Shared/FileSize";

interface ISceneListTableProps {
scenes: GQL.SlimSceneDataFragment[];
Expand Down Expand Up @@ -169,24 +170,12 @@ export const SceneListTable: React.FC<ISceneListTableProps> = (
</ul>
);

function renderFileSize(file: { size: number | undefined }) {
const { size, unit } = TextUtils.fileSize(file.size);

return (
<FormattedNumber
value={size}
style="unit"
unit={unit}
unitDisplay="narrow"
maximumFractionDigits={2}
/>
);
}

const FileSizeCell = (scene: GQL.SlimSceneDataFragment) => (
<ul className="comma-list">
{scene.files.map((file) => (
<li key={file.id}>{renderFileSize(file)}</li>
<li key={file.id}>
<FileSize size={file.size} />
</li>
))}
</ul>
);
Expand Down
17 changes: 17 additions & 0 deletions ui/v2.5/src/components/Shared/FileSize.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { FormattedNumber } from "react-intl";
import TextUtils from "src/utils/text";

export const FileSize: React.FC<{ size: number }> = ({ size: fileSize }) => {
const { size, unit } = TextUtils.fileSize(fileSize);

return (
<>
<FormattedNumber
value={size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(unit)}
/>
{` ${TextUtils.formatFileSizeUnit(unit)}`}
</>
);
};
20 changes: 3 additions & 17 deletions ui/v2.5/src/components/Stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ import { useStats } from "src/core/StashService";
import { FormattedMessage, FormattedNumber } from "react-intl";
import { LoadingIndicator } from "src/components/Shared/LoadingIndicator";
import TextUtils from "src/utils/text";
import { FileSize } from "./Shared/FileSize";

export const Stats: React.FC = () => {
const { data, error, loading } = useStats();

if (error) return <span>{error.message}</span>;
if (loading || !data) return <LoadingIndicator />;

const scenesSize = TextUtils.fileSize(data.stats.scenes_size);
const imagesSize = TextUtils.fileSize(data.stats.images_size);

const scenesDuration = TextUtils.secondsAsTimeString(
data.stats.scenes_duration,
3
Expand All @@ -28,13 +26,7 @@ export const Stats: React.FC = () => {
<div className="col col-sm-8 m-sm-auto row stats">
<div className="stats-element">
<p className="title">
<FormattedNumber
value={scenesSize.size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(
scenesSize.unit
)}
/>
{` ${TextUtils.formatFileSizeUnit(scenesSize.unit)}`}
<FileSize size={data.stats.scenes_size} />
</p>
<p className="heading">
<FormattedMessage id="stats.scenes_size" />
Expand Down Expand Up @@ -74,13 +66,7 @@ export const Stats: React.FC = () => {
<div className="col col-sm-8 m-sm-auto row stats">
<div className="stats-element">
<p className="title">
<FormattedNumber
value={imagesSize.size}
maximumFractionDigits={TextUtils.fileSizeFractionalDigits(
imagesSize.unit
)}
/>
{` ${TextUtils.formatFileSizeUnit(imagesSize.unit)}`}
<FileSize size={data.stats.images_size} />
</p>
<p className="heading">
<FormattedMessage id="stats.image_size" />
Expand Down

0 comments on commit ce2d779

Please sign in to comment.