mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-01-07 16:03:06 +00:00
Update the availability duration and size input
This commit is contained in:
parent
cd35972992
commit
174dcf78d9
@ -1,11 +1,16 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
import { Bytes } from "../src/utils/bytes"
|
||||
import { GB } from "../src/utils/constants"
|
||||
|
||||
test('create an availability', async ({ page }) => {
|
||||
await page.goto('/dashboard/availabilities');
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('.availability-edit button').first().click();
|
||||
await page.getByLabel('Total size').click();
|
||||
await page.getByLabel('Total size').fill('0.50');
|
||||
|
||||
const value = (Math.random() * 0.5);
|
||||
|
||||
await page.getByLabel('Total size').fill(value.toFixed(2));
|
||||
await page.getByLabel('Duration').click();
|
||||
await page.getByLabel('Duration').fill('30');
|
||||
await page.getByLabel('Min price').click();
|
||||
@ -20,7 +25,7 @@ test('create an availability', async ({ page }) => {
|
||||
await page.getByRole('button', { name: 'Next' }).click();
|
||||
await expect(page.getByText('Success', { exact: true })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Finish' }).click();
|
||||
await expect(page.getByText('512.0 MB allocated for the').first()).toBeVisible();
|
||||
await expect(page.getByText(Bytes.pretty(parseFloat(value.toFixed(1)) * GB)).first()).toBeVisible();
|
||||
})
|
||||
|
||||
test('availability navigation buttons', async ({ page }) => {
|
||||
@ -54,3 +59,63 @@ test('availability navigation buttons', async ({ page }) => {
|
||||
await page.getByRole('button', { name: 'Finish' }).click();
|
||||
await expect(page.locator('.modal--open')).not.toBeVisible();
|
||||
})
|
||||
|
||||
test('create an availability with changing the duration to months', async ({ page }) => {
|
||||
await page.goto('/dashboard/availabilities');
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('.availability-edit button').first().click();
|
||||
await page.getByLabel('Total size').click();
|
||||
|
||||
await page.getByLabel('Total size').fill("0.1");
|
||||
await page.getByLabel('Duration').click();
|
||||
await page.getByLabel('Duration').fill("3");
|
||||
await page.getByRole('combobox').nth(1).selectOption('months');
|
||||
|
||||
await page.getByLabel('Min price').click();
|
||||
await page.getByLabel('Min price').fill('5');
|
||||
await page.getByLabel('Max collateral').click();
|
||||
await page.getByLabel('Max collateral').fill('30');
|
||||
await page.getByLabel('Min price').fill('5');
|
||||
await page.getByLabel('Nickname').click();
|
||||
await page.getByLabel('Nickname').fill('test');
|
||||
await page.getByRole('button', { name: 'Next' }).click();
|
||||
await expect(page.getByText('Confirm your new sale')).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Next' }).click();
|
||||
await expect(page.getByText('Success', { exact: true })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Finish' }).click();
|
||||
await expect(page.getByText("3 months").first()).toBeVisible();
|
||||
})
|
||||
|
||||
|
||||
test('create an availability after checking max size and invalid input', async ({ page }) => {
|
||||
await page.goto('/dashboard/availabilities');
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('.availability-edit button').first().click();
|
||||
await page.getByLabel('Total size').click();
|
||||
|
||||
|
||||
await page.getByLabel('Total size').fill("9999");
|
||||
await expect(page.getByLabel('Total size')).toHaveAttribute("aria-invalid");
|
||||
|
||||
await page.getByText("Use max size").click()
|
||||
await expect(page.getByLabel('Total size')).not.toHaveAttribute("aria-invalid");
|
||||
|
||||
const value = (Math.random() * 0.5);
|
||||
await page.getByLabel('Total size').fill(value.toFixed(1));
|
||||
|
||||
await page.getByLabel('Duration').click();
|
||||
await page.getByLabel('Duration').fill('30');
|
||||
await page.getByLabel('Min price').click();
|
||||
await page.getByLabel('Min price').fill('5');
|
||||
await page.getByLabel('Max collateral').click();
|
||||
await page.getByLabel('Max collateral').fill('30');
|
||||
await page.getByLabel('Min price').fill('5');
|
||||
await page.getByLabel('Nickname').click();
|
||||
await page.getByLabel('Nickname').fill('test');
|
||||
await page.getByRole('button', { name: 'Next' }).click();
|
||||
await expect(page.getByText('Confirm your new sale')).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Next' }).click();
|
||||
await expect(page.getByText('Success', { exact: true })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Finish' }).click();
|
||||
await expect(page.getByText(Bytes.pretty(parseFloat(value.toFixed(1)) * GB)).first()).toBeVisible();
|
||||
})
|
||||
@ -28,8 +28,8 @@ type Props = {
|
||||
const CONFIRM_STATE = 2;
|
||||
|
||||
const defaultAvailabilityData: AvailabilityState = {
|
||||
totalSize: 0.5 * GB,
|
||||
duration: Times.value("days"),
|
||||
totalSize: 0.5,
|
||||
duration: 1,
|
||||
minPrice: 0,
|
||||
maxCollateral: 0,
|
||||
totalSizeUnit: "gb",
|
||||
@ -52,7 +52,7 @@ export function AvailabilityEdit({
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
WebStorage.get<number>("availability-step"),
|
||||
WebStorage.get<AvailabilityState>("availability"),
|
||||
WebStorage.get<AvailabilityState>("availability-1"),
|
||||
]).then(([s, a]) => {
|
||||
if (s) {
|
||||
dispatch({
|
||||
@ -67,26 +67,6 @@ export function AvailabilityEdit({
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
// We use a custom event to not re render the sunburst component
|
||||
// useEffect(() => {
|
||||
// const onAvailabilityIdChange = (e: Event) => {
|
||||
// const custom = e as CustomEvent;
|
||||
// setAvailabilityId(custom.detail);
|
||||
// };
|
||||
|
||||
// document.addEventListener(
|
||||
// "codexavailabilityid",
|
||||
// onAvailabilityIdChange,
|
||||
// false
|
||||
// );
|
||||
|
||||
// return () =>
|
||||
// document.removeEventListener(
|
||||
// "codexavailabilityid",
|
||||
// onAvailabilityIdChange
|
||||
// );
|
||||
// }, []);
|
||||
|
||||
const components = [
|
||||
AvailabilityForm,
|
||||
AvailabilityConfirm,
|
||||
@ -157,7 +137,7 @@ export function AvailabilityEdit({
|
||||
|
||||
editAvailabilityValue.current = a.totalSize;
|
||||
WebStorage.set("availability-step", 0);
|
||||
WebStorage.set("availability", a);
|
||||
WebStorage.set("availability-1", a);
|
||||
|
||||
const unit = Times.unit(a.duration);
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import NodesIcon from "../../assets/icons/nodes.svg?react";
|
||||
import InfoIcon from "../../assets/icons/info.svg?react";
|
||||
import { attributes } from "../../utils/attributes";
|
||||
import { AvailabilityUtils } from "./availability.utils";
|
||||
import { Times } from "../../utils/times";
|
||||
|
||||
export function AvailabilityForm({
|
||||
dispatch,
|
||||
@ -39,27 +38,24 @@ export function AvailabilityForm({
|
||||
const element = e.currentTarget;
|
||||
|
||||
onAvailabilityChange({
|
||||
totalSize: 0,
|
||||
totalSizeUnit: element.value as "tb" | "gb",
|
||||
});
|
||||
};
|
||||
|
||||
const onDurationChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const element = e.currentTarget;
|
||||
const unitValue = Times.value(availability.durationUnit);
|
||||
|
||||
onAvailabilityChange({
|
||||
duration: parseInt(element.value) * unitValue,
|
||||
duration: parseInt(element.value),
|
||||
});
|
||||
};
|
||||
|
||||
const onDurationUnitChange = async (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const element = e.currentTarget;
|
||||
const unit = element.value as "hours" | "days" | "months";
|
||||
const unitValue = Times.value(unit);
|
||||
|
||||
onAvailabilityChange({
|
||||
duration: unitValue,
|
||||
duration: availability.duration,
|
||||
durationUnit: unit,
|
||||
});
|
||||
};
|
||||
@ -67,10 +63,9 @@ export function AvailabilityForm({
|
||||
const onAvailablityChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const element = e.currentTarget;
|
||||
const v = element.value;
|
||||
const unit = AvailabilityUtils.unitValue(availability.totalSizeUnit);
|
||||
|
||||
onAvailabilityChange({
|
||||
totalSize: parseFloat(v) * unit,
|
||||
totalSize: parseFloat(v),
|
||||
});
|
||||
};
|
||||
|
||||
@ -87,7 +82,12 @@ export function AvailabilityForm({
|
||||
const available = AvailabilityUtils.maxValue(space);
|
||||
|
||||
onAvailabilityChange({
|
||||
totalSize: available,
|
||||
totalSize:
|
||||
Math.floor(
|
||||
((available - 1) /
|
||||
AvailabilityUtils.unitValue(availability.totalSizeUnit)) *
|
||||
10
|
||||
) / 10,
|
||||
});
|
||||
};
|
||||
|
||||
@ -96,20 +96,17 @@ export function AvailabilityForm({
|
||||
available += editAvailabilityValue;
|
||||
}
|
||||
|
||||
const isValid =
|
||||
availability.totalSize > 0 && available >= availability.totalSize;
|
||||
const totalSizeInBytes =
|
||||
availability.totalSize *
|
||||
AvailabilityUtils.unitValue(availability.totalSizeUnit);
|
||||
|
||||
const isValid = totalSizeInBytes > 0 && available >= totalSizeInBytes;
|
||||
|
||||
const helper = isValid
|
||||
? "Total size of sale's storage in bytes"
|
||||
: "The total size cannot exceed the space available.";
|
||||
|
||||
const value = AvailabilityUtils.toUnit(
|
||||
availability.totalSize,
|
||||
availability.totalSizeUnit
|
||||
).toFixed(2);
|
||||
|
||||
const unitValue = Times.value(availability.durationUnit);
|
||||
const duration = availability.duration / unitValue;
|
||||
const duration = availability.duration;
|
||||
|
||||
return (
|
||||
<div className="availability-form">
|
||||
@ -143,13 +140,12 @@ export function AvailabilityForm({
|
||||
name="totalSize"
|
||||
type="number"
|
||||
label="Total size"
|
||||
min={0.01}
|
||||
isInvalid={!isValid}
|
||||
max={available.toFixed(2)}
|
||||
onChange={onAvailablityChange}
|
||||
onGroupChange={onTotalSizeUnitChange}
|
||||
step={"0.01"}
|
||||
value={value}
|
||||
value={availability.totalSize.toString()}
|
||||
min={"0"}
|
||||
group={[
|
||||
["gb", "GB"],
|
||||
// ["tb", "TB"],
|
||||
|
||||
@ -39,7 +39,8 @@ export const AvailabilityUtils = {
|
||||
return bytes / this.unitValue(unit || "gb")
|
||||
},
|
||||
maxValue(space: CodexNodeSpace) {
|
||||
return space.quotaMaxBytes - space.quotaReservedBytes - space.quotaUsedBytes
|
||||
// Remove 1 byte to allow to create an availability with the max space possible
|
||||
return space.quotaMaxBytes - space.quotaReservedBytes - space.quotaUsedBytes - 1
|
||||
},
|
||||
unitValue(unit: "gb" | "tb") {
|
||||
return unit === "tb" ? TB : GB
|
||||
|
||||
@ -9,6 +9,8 @@ import {
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import { CodexAvailabilityCreateResponse } from "@codex-storage/sdk-js";
|
||||
import { Times } from "../../utils/times";
|
||||
import { AvailabilityUtils } from "./availability.utils";
|
||||
|
||||
|
||||
export function useAvailabilityMutation(
|
||||
@ -42,15 +44,15 @@ export function useAvailabilityMutation(
|
||||
|
||||
return fn({
|
||||
...input,
|
||||
duration,
|
||||
totalSize: Math.trunc(totalSize),
|
||||
duration: Times.value(durationUnit) * duration,
|
||||
totalSize: Math.trunc(totalSize * AvailabilityUtils.unitValue(totalSizeUnit)),
|
||||
});
|
||||
},
|
||||
onSuccess: (res, body) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["availabilities"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["space"] });
|
||||
|
||||
WebStorage.delete("availability");
|
||||
WebStorage.delete("availability-1");
|
||||
WebStorage.delete("availability-step");
|
||||
|
||||
if (typeof res === "object" && body.name) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user