feat(UI): improve filesize input and use it in settings (#721)
* Improve file size input component layout * Fix filesize input value not getting set * Allow arbitrary props on filesize input * Update config variables to support filesize type and integrate FileSizeInput component * Update i18n entries * WARNING GUESSES: Update translation descriptions for max size and chunk size in multiple languages * Fix config service not being aware of filesize type * Fix backend config service not being aware of filesize type * Move FileSizeInput component to core
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { AdminConfig, UpdateConfig } from "../../../types/config.type";
|
||||
import FileSizeInput from "../../core/FileSizeInput";
|
||||
|
||||
const AdminConfigInput = ({
|
||||
configVariable,
|
||||
@@ -71,6 +72,15 @@ const AdminConfigInput = ({
|
||||
{...form.getInputProps("numberValue")}
|
||||
placeholder={configVariable.defaultValue}
|
||||
onChange={(number) => onValueChange(configVariable, number)}
|
||||
w={201}
|
||||
/>
|
||||
)}
|
||||
{configVariable.type == "filesize" && (
|
||||
<FileSizeInput
|
||||
{...form.getInputProps("numberValue")}
|
||||
value={parseInt(configVariable.value ?? configVariable.defaultValue)}
|
||||
onChange={(bytes) => onValueChange(configVariable, bytes)}
|
||||
w={201}
|
||||
/>
|
||||
)}
|
||||
{configVariable.type == "boolean" && (
|
||||
|
||||
76
frontend/src/components/core/FileSizeInput.tsx
Normal file
76
frontend/src/components/core/FileSizeInput.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { NativeSelect, NumberInput } from "@mantine/core";
|
||||
import { useState } from "react";
|
||||
|
||||
const multipliers = {
|
||||
B: 1,
|
||||
KB: 1000,
|
||||
KiB: 1024,
|
||||
MB: 1000 ** 2,
|
||||
MiB: 1024 ** 2,
|
||||
GB: 1000 ** 3,
|
||||
GiB: 1024 ** 3,
|
||||
TB: 1000 ** 4,
|
||||
TiB: 1024 ** 4,
|
||||
}
|
||||
|
||||
const units = (["B", "KB", "KiB", "MB", "MiB", "GB", "GiB", "TB", "TiB"] as const).map(unit => ({ label: unit, value: unit }));
|
||||
|
||||
function getLargestApplicableUnit(value: number) {
|
||||
return units.findLast(unit => value % multipliers[unit.value] === 0) || units[0];
|
||||
}
|
||||
|
||||
const FileSizeInput = ({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
...restProps
|
||||
}: {
|
||||
label?: string;
|
||||
value: number;
|
||||
onChange: (number: number) => void;
|
||||
[key: string]: any;
|
||||
}) => {
|
||||
const [unit, setUnit] = useState(getLargestApplicableUnit(value).value);
|
||||
const [inputValue, setInputValue] = useState(value / multipliers[unit]);
|
||||
const unitSelect = (
|
||||
<NativeSelect
|
||||
data={units}
|
||||
value={unit}
|
||||
rightSectionWidth={28}
|
||||
styles={{
|
||||
input: {
|
||||
fontWeight: 500,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
width: 76,
|
||||
marginRight: -2,
|
||||
},
|
||||
}}
|
||||
onChange={event => {
|
||||
const unit = event.currentTarget.value as typeof units[number]["value"];
|
||||
setUnit(unit);
|
||||
onChange(multipliers[unit] * inputValue);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<NumberInput
|
||||
label={label}
|
||||
value={inputValue}
|
||||
min={1}
|
||||
max={999999}
|
||||
precision={0}
|
||||
rightSection={unitSelect}
|
||||
rightSectionWidth={76}
|
||||
onChange={value => {
|
||||
const inputVal = value || 0;
|
||||
setInputValue(inputVal);
|
||||
onChange(multipliers[unit] * inputVal);
|
||||
}}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileSizeInput;
|
||||
@@ -1,64 +0,0 @@
|
||||
import { Col, Grid, NumberInput, Select } from "@mantine/core";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
byteToUnitAndSize,
|
||||
unitAndSizeToByte,
|
||||
} from "../../utils/fileSize.util";
|
||||
|
||||
const FileSizeInput = ({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
value: number;
|
||||
onChange: (number: number) => void;
|
||||
}) => {
|
||||
const [unit, setUnit] = useState("MB");
|
||||
const [size, setSize] = useState(100);
|
||||
|
||||
useEffect(() => {
|
||||
const { unit, size } = byteToUnitAndSize(value);
|
||||
setUnit(unit);
|
||||
setSize(size);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Grid align="flex-end">
|
||||
<Col xs={6}>
|
||||
<NumberInput
|
||||
min={1}
|
||||
max={99999}
|
||||
precision={0}
|
||||
variant="filled"
|
||||
label={label}
|
||||
value={size}
|
||||
onChange={(value) => {
|
||||
if (value) {
|
||||
setSize(value);
|
||||
onChange(unitAndSizeToByte(unit, value));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={6}>
|
||||
<Select
|
||||
data={[
|
||||
{ label: "B", value: "B" },
|
||||
{ label: "KB", value: "KB" },
|
||||
{ label: "MB", value: "MB" },
|
||||
{ label: "GB", value: "GB" },
|
||||
{ label: "TB", value: "TB" },
|
||||
]}
|
||||
value={unit}
|
||||
onChange={(value) => {
|
||||
setUnit(value!);
|
||||
onChange(unitAndSizeToByte(value!, size));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileSizeInput;
|
||||
@@ -22,7 +22,7 @@ import useTranslate, {
|
||||
import shareService from "../../../services/share.service";
|
||||
import { getExpirationPreview } from "../../../utils/date.util";
|
||||
import toast from "../../../utils/toast.util";
|
||||
import FileSizeInput from "../FileSizeInput";
|
||||
import FileSizeInput from "../../core/FileSizeInput";
|
||||
import showCompletedReverseShareModal from "./showCompletedReverseShareModal";
|
||||
|
||||
const showCreateReverseShareModal = (
|
||||
|
||||
Reference in New Issue
Block a user