mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-05-04 16:43:10 +00:00
Clean components and update dependencies
This commit is contained in:
parent
dbc4562571
commit
810a7f5336
3856
package-lock.json
generated
3856
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@
|
||||
"React"
|
||||
],
|
||||
"dependencies": {
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.44",
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.45",
|
||||
"@codex-storage/sdk-js": "^0.0.15",
|
||||
"@sentry/browser": "^8.32.0",
|
||||
"@sentry/react": "^8.31.0",
|
||||
|
||||
@ -34,6 +34,8 @@ export default defineConfig({
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
|
||||
screenshot: "only-on-failure",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { ReactNode } from "react";
|
||||
import "./App.css";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -87,9 +87,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @media (min-width: 1000px) {
|
||||
.appBar-burger {
|
||||
display: none;
|
||||
}
|
||||
} */
|
||||
|
||||
@ -11,7 +11,6 @@ import { Times } from "../../utils/times";
|
||||
import { Fragment, useState } from "react";
|
||||
import { AvailabilityReservations } from "./AvailabilityReservations";
|
||||
import { AvailabilityIdCell } from "./AvailabilityIdCell";
|
||||
import { Arrays } from "../../utils/arrays";
|
||||
import { SlotRow } from "./SlotRow";
|
||||
import { AvailabilityWithSlots } from "./types";
|
||||
import { AvailabilityDiskRow } from "./AvailabilityDiskRow";
|
||||
@ -68,7 +67,8 @@ export function AvailabilitiesTable({ availabilities, space }: Props) {
|
||||
const rows = sorted.map((a) => {
|
||||
const showDetails = details.includes(a.id);
|
||||
|
||||
const onShowDetails = () => setDetails(Arrays.toggle(details, a.id));
|
||||
const onShowDetails = () =>
|
||||
setDetails(AvailabilityUtils.toggle(details, a.id));
|
||||
const hasSlots = a.slots.length > 0;
|
||||
|
||||
return (
|
||||
|
||||
@ -3,29 +3,29 @@
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.availabilitConfirm-bottom {
|
||||
margin-top: 1.5rem;
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
> div {
|
||||
margin-top: 1.5rem;
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: flex-start;
|
||||
|
||||
.availabilitConfirm-subtitle {
|
||||
margin-bottom: 0.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
> div:first-child {
|
||||
background-color: rgb(var(--codex-color-primary-rgb), 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.availabilitConfirm-iconContainer {
|
||||
background-color: rgb(var(--codex-color-primary-rgb), 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
svg {
|
||||
color: rgb(var(--codex-color-primary-rgb));
|
||||
}
|
||||
}
|
||||
|
||||
.availabilitConfirm-icon {
|
||||
color: rgb(var(--codex-color-primary-rgb));
|
||||
b {
|
||||
margin-bottom: 0.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,15 +54,15 @@ export function AvailabilityConfirm({
|
||||
},
|
||||
]}></SpaceAllocation>
|
||||
|
||||
<div className="availabilitConfirm-bottom">
|
||||
<div className="availabilitConfirm-iconContainer">
|
||||
<Info className="availabilitConfirm-icon" />
|
||||
<div>
|
||||
<div>
|
||||
<Info />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<b className="availabilitConfirm-subtitle">Confirm your new sale</b>
|
||||
<b>Confirm your new sale</b>
|
||||
|
||||
<p className="availabilitConfirm-message">
|
||||
<p>
|
||||
By clicking 'Next', you will establish a new sale based on the space
|
||||
allocation specified above. Do you want to confirm ?
|
||||
</p>
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
import { createContext } from "react";
|
||||
import { AvailabilityWithSlots } from "./types";
|
||||
|
||||
export const AvailabilityContext = createContext<AvailabilityWithSlots | null>(null);
|
||||
@ -42,9 +42,9 @@ export function AvailabilityEdit({
|
||||
hasLabel = true,
|
||||
}: Props) {
|
||||
const steps = useRef(["Sale", "Confirmation", "Success"]);
|
||||
const [availability, setAvailability] = useState<AvailabilityState>(
|
||||
defaultAvailabilityData
|
||||
);
|
||||
const [availability, setAvailability] = useState<
|
||||
AvailabilityState & { slots?: unknown }
|
||||
>(defaultAvailabilityData);
|
||||
const { state, dispatch } = useStepperReducer();
|
||||
const { mutateAsync, error } = useAvailabilityMutation(dispatch, state);
|
||||
const editAvailabilityValue = useRef(0);
|
||||
@ -112,7 +112,8 @@ export function AvailabilityEdit({
|
||||
WebStorage.set("availability-step", step);
|
||||
|
||||
if (step == CONFIRM_STATE) {
|
||||
const { slots, name, ...rest } = availability as any;
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const { slots, name, ...rest } = availability;
|
||||
mutateAsync(rest);
|
||||
} else {
|
||||
dispatch({
|
||||
|
||||
@ -11,14 +11,14 @@ import { Promises } from "../../utils/promises";
|
||||
import { CodexAvailability } from "@codex-storage/sdk-js";
|
||||
import { useEffect } from "react";
|
||||
import { ErrorPlaceholder } from "../ErrorPlaceholder/ErrorPlaceholder";
|
||||
import { availabilityColors } from "./availability.colors";
|
||||
import { AvailabilityUtils } from "./availability.utils";
|
||||
|
||||
type Props = {
|
||||
availability: CodexAvailability | null;
|
||||
open: boolean;
|
||||
onClose: () => unknown;
|
||||
};
|
||||
// TODO remove this
|
||||
|
||||
export function AvailabilityReservations({
|
||||
availability,
|
||||
onClose,
|
||||
@ -95,12 +95,15 @@ export function AvailabilityReservations({
|
||||
...data.map((val, index) => ({
|
||||
title: val.id,
|
||||
size: parseInt(val.size, 10),
|
||||
color: availabilityColors[index],
|
||||
color: AvailabilityUtils.availabilityColors[index],
|
||||
})),
|
||||
{
|
||||
title: "Availability remaining",
|
||||
size: totalSize - totalUsed,
|
||||
color: availabilityColors[availabilityColors.length - 1],
|
||||
color:
|
||||
AvailabilityUtils.availabilityColors[
|
||||
AvailabilityUtils.availabilityColors.length - 1
|
||||
],
|
||||
},
|
||||
];
|
||||
const isEmpty = !data.length;
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
import {
|
||||
Stepper,
|
||||
useStepperReducer,
|
||||
Button,
|
||||
Modal,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { AvailabilityForm } from "./AvailabilityForm";
|
||||
import { Plus } from "lucide-react";
|
||||
import { CodexNodeSpace } from "@codex-storage/sdk-js";
|
||||
import { AvailabilityConfirm } from "./AvailabilityConfirmation";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { AvailabilityState } from "./types";
|
||||
import { STEPPER_DURATION } from "../../utils/constants";
|
||||
import { useAvailabilityMutation } from "./useAvailabilityMutation";
|
||||
import { AvailabilitySuccess } from "./AvailabilitySuccess";
|
||||
import { AvailabilityError } from "./AvailabilityError";
|
||||
import "./AvailabilityCreate.css";
|
||||
|
||||
type Props = {
|
||||
space: CodexNodeSpace;
|
||||
hasLabel?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const CONFIRM_STATE = 2;
|
||||
|
||||
const defaultAvailabilityData: AvailabilityState = {
|
||||
totalSize: 1,
|
||||
duration: 1,
|
||||
minPrice: 0,
|
||||
maxCollateral: 0,
|
||||
totalSizeUnit: "gb",
|
||||
durationUnit: "days",
|
||||
};
|
||||
|
||||
export function AvailabilitySheetCreate({
|
||||
space,
|
||||
className = "",
|
||||
hasLabel = true,
|
||||
}: Props) {
|
||||
const steps = useRef(["Sale", "Confirmation", "Success"]);
|
||||
const [availability, setAvailability] = useState<AvailabilityState>(
|
||||
defaultAvailabilityData
|
||||
);
|
||||
const { state, dispatch } = useStepperReducer();
|
||||
const { mutateAsync, error } = useAvailabilityMutation(dispatch, state);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
WebStorage.get<number>("availability-step"),
|
||||
WebStorage.get<AvailabilityState>("availability"),
|
||||
]).then(([s, a]) => {
|
||||
if (s) {
|
||||
dispatch({
|
||||
type: "next",
|
||||
step: s,
|
||||
});
|
||||
}
|
||||
|
||||
if (a) {
|
||||
setAvailability(a);
|
||||
}
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
const components = [
|
||||
AvailabilityForm,
|
||||
AvailabilityConfirm,
|
||||
error ? AvailabilityError : AvailabilitySuccess,
|
||||
];
|
||||
|
||||
const onNextStep = async (step: number) => {
|
||||
if (step === components.length) {
|
||||
setAvailability(defaultAvailabilityData);
|
||||
|
||||
dispatch({
|
||||
step: 0,
|
||||
type: "next",
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: "close",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WebStorage.set("availability-step", step);
|
||||
|
||||
if (step == CONFIRM_STATE) {
|
||||
mutateAsync(availability);
|
||||
} else {
|
||||
dispatch({
|
||||
step,
|
||||
type: "next",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onAvailabilityChange = (data: Partial<AvailabilityState>) => {
|
||||
const val = { ...availability, ...data };
|
||||
|
||||
WebStorage.set("availability", val);
|
||||
|
||||
setAvailability(val);
|
||||
};
|
||||
|
||||
const onOpen = () => {
|
||||
if (availability.id) {
|
||||
WebStorage.set("availability-step", 0);
|
||||
WebStorage.set("availability", defaultAvailabilityData);
|
||||
|
||||
setAvailability(defaultAvailabilityData);
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: "open",
|
||||
});
|
||||
|
||||
dispatch({
|
||||
step: 0,
|
||||
type: "next",
|
||||
});
|
||||
};
|
||||
|
||||
const onClose = () => dispatch({ type: "close" });
|
||||
|
||||
const Body = components[state.step] || (() => <span />);
|
||||
const backLabel = state.step ? "Back" : "Close";
|
||||
const nextLabel = state.step === steps.current.length - 1 ? "Finish" : "Next";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
label={hasLabel ? "Sale" : ""}
|
||||
Icon={Plus}
|
||||
onClick={onOpen}
|
||||
variant="primary"
|
||||
className={className}
|
||||
/>
|
||||
|
||||
<Modal open={state.open} onClose={onClose}>
|
||||
<Stepper
|
||||
titles={steps.current}
|
||||
state={state}
|
||||
dispatch={dispatch}
|
||||
duration={STEPPER_DURATION}
|
||||
onNextStep={onNextStep}
|
||||
backLabel={backLabel}
|
||||
nextLabel={nextLabel}>
|
||||
<Body
|
||||
dispatch={dispatch}
|
||||
state={state}
|
||||
onAvailabilityChange={onAvailabilityChange}
|
||||
availability={availability}
|
||||
space={space}
|
||||
error={error}
|
||||
/>
|
||||
</Stepper>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
.availabilitySpaceAllocation-title {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
import { CodexNodeSpace } from "@codex-storage/sdk-js";
|
||||
import { AvailabilityState } from "./types";
|
||||
import { SpaceAllocation } from "@codex-storage/marketplace-ui-components";
|
||||
import "./AvailabilitySpaceAllocation.css";
|
||||
import { nodeSpaceAllocationColors } from "../NodeSpace/nodeSpace.domain";
|
||||
|
||||
type Props = {
|
||||
space: CodexNodeSpace;
|
||||
availability: AvailabilityState;
|
||||
};
|
||||
|
||||
export function AvailabilitySpaceAllocation({ availability, space }: Props) {
|
||||
const { quotaMaxBytes, quotaReservedBytes, quotaUsedBytes } = space;
|
||||
const isUpdating = !!availability.id;
|
||||
const allocated = isUpdating
|
||||
? quotaReservedBytes - availability.totalSize + quotaUsedBytes
|
||||
: quotaReservedBytes + quotaUsedBytes;
|
||||
const remaining =
|
||||
availability.totalSize > quotaMaxBytes - allocated
|
||||
? quotaMaxBytes - allocated
|
||||
: quotaMaxBytes - allocated - availability.totalSize;
|
||||
|
||||
const spaceData = [
|
||||
{
|
||||
title: "Space allocated",
|
||||
size: Math.trunc(allocated),
|
||||
color: nodeSpaceAllocationColors[0],
|
||||
},
|
||||
{
|
||||
title: "New space allocation",
|
||||
size: Math.trunc(availability.totalSize),
|
||||
color: nodeSpaceAllocationColors[1],
|
||||
},
|
||||
{
|
||||
title: "Remaining space",
|
||||
size: Math.trunc(remaining),
|
||||
color: nodeSpaceAllocationColors[nodeSpaceAllocationColors.length - 1],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<b className="availabilitySpaceAllocation-title">Node space allocation</b>
|
||||
|
||||
<SpaceAllocation data={spaceData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { Placeholder } from "@codex-storage/marketplace-ui-components";
|
||||
import { SuccessIcon } from "../SuccessIcon/SuccessIcon";
|
||||
import { AvailabilityComponentProps } from "./types";
|
||||
import { useEffect } from "react";
|
||||
import SuccessCircleIcon from "../../assets/icons/success-circle.svg?react";
|
||||
|
||||
export function AvailabilitySuccess({ dispatch }: AvailabilityComponentProps) {
|
||||
useEffect(() => {
|
||||
@ -14,7 +14,7 @@ export function AvailabilitySuccess({ dispatch }: AvailabilityComponentProps) {
|
||||
|
||||
return (
|
||||
<Placeholder
|
||||
Icon={<SuccessIcon />}
|
||||
Icon={<SuccessCircleIcon />}
|
||||
title="Success"
|
||||
message="The new sale will appear in your sale list. You can safely close this dialog."></Placeholder>
|
||||
);
|
||||
|
||||
@ -5,9 +5,9 @@ import { PrettyBytes } from "../../utils/bytes";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { CallbackDataParams, ECBasicOption } from "echarts/types/dist/shared";
|
||||
import * as echarts from "echarts";
|
||||
import { availabilityColors, slotColors } from "./availability.colors";
|
||||
import { AvailabilityWithSlots } from "./types";
|
||||
import "./Sunburst.css";
|
||||
import { AvailabilityUtils } from "./availability.utils";
|
||||
|
||||
type Props = {
|
||||
availabilities: AvailabilityWithSlots[];
|
||||
@ -33,7 +33,7 @@ export function Sunburst({ availabilities, space }: Props) {
|
||||
name: Strings.shortId(a.id),
|
||||
value: a.totalSize,
|
||||
itemStyle: {
|
||||
color: availabilityColors[index],
|
||||
color: AvailabilityUtils.availabilityColors[index],
|
||||
borderColor: "transparent",
|
||||
},
|
||||
tooltip: {
|
||||
@ -66,7 +66,7 @@ export function Sunburst({ availabilities, space }: Props) {
|
||||
value: parseFloat(slot.size),
|
||||
children: [],
|
||||
itemStyle: {
|
||||
color: slotColors[index],
|
||||
color: AvailabilityUtils.slotColors[index],
|
||||
borderColor: "transparent",
|
||||
},
|
||||
tooltip: {
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
export const availabilityColors = [
|
||||
"#34A0FFFF",
|
||||
"#34A0FFEE",
|
||||
"#34A0FFDD",
|
||||
"#34A0FFCC",
|
||||
"#34A0FFBB",
|
||||
"#34A0FFAA",
|
||||
"#34A0FF99",
|
||||
];
|
||||
|
||||
export const slotColors = [
|
||||
"#D2493CFF",
|
||||
"#D2493CEE",
|
||||
"#D2493CDD",
|
||||
"#D2493CCC",
|
||||
"#D2493CBB",
|
||||
"#D2493CAA",
|
||||
"#D2493C99",
|
||||
];
|
||||
@ -1,46 +0,0 @@
|
||||
import { CodexNodeSpace } from "@codex-storage/sdk-js";
|
||||
import { GB, TB } from "../../utils/constants";
|
||||
import { AvailabilityState } from "./types";
|
||||
|
||||
export class AvailabilityDomain {
|
||||
space: CodexNodeSpace
|
||||
state: AvailabilityState
|
||||
|
||||
constructor(space: CodexNodeSpace, availability: AvailabilityState) {
|
||||
this.space = space
|
||||
this.state = availability
|
||||
}
|
||||
|
||||
get unitInBytes() {
|
||||
return this.state.totalSizeUnit === "gb" ? GB : TB;
|
||||
}
|
||||
|
||||
get unit() {
|
||||
return this.state.totalSizeUnit;
|
||||
}
|
||||
|
||||
get sizeInUnit() {
|
||||
return this.state.totalSize
|
||||
}
|
||||
|
||||
get maxInBytes() {
|
||||
return this.space.quotaMaxBytes - this.space.quotaReservedBytes - this.space.quotaUsedBytes
|
||||
}
|
||||
|
||||
get maxInUnit() {
|
||||
return this.maxInBytes / this.unitInBytes / this.unitInBytes
|
||||
}
|
||||
|
||||
isValid() {
|
||||
const size = this.state.totalSize * this.unitInBytes;
|
||||
|
||||
return size > 0 && size <= this.maxInBytes;
|
||||
}
|
||||
}
|
||||
|
||||
export const isAvailabilityValid = (
|
||||
availability: AvailabilityState,
|
||||
max: number
|
||||
) => availability.totalSize > 0 && availability.totalSize <= max;
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { assert, describe, it } from "vitest";
|
||||
import { AvailabilityUtils } from "./availability.utils";
|
||||
import { GB, TB } from "../../utils/constants";
|
||||
import { CodexNodeSpace } from "@codex-storage/sdk-js";
|
||||
import { AvailabilityState } from "./types";
|
||||
|
||||
describe("files", () => {
|
||||
it("sorts by id", async () => {
|
||||
@ -156,4 +159,35 @@ describe("files", () => {
|
||||
|
||||
assert.deepEqual(ascSorted, [a, b]);
|
||||
});
|
||||
|
||||
it("returns the number of bytes per unit", async () => {
|
||||
assert.deepEqual(AvailabilityUtils.toUnit(GB, "gb"), 1);
|
||||
assert.deepEqual(AvailabilityUtils.toUnit(TB, "tb"), 1);
|
||||
})
|
||||
|
||||
|
||||
it("returns the max value possible for an availability", async () => {
|
||||
const space: CodexNodeSpace = {
|
||||
quotaMaxBytes: 8 * GB,
|
||||
quotaReservedBytes: 2 * GB,
|
||||
quotaUsedBytes: GB,
|
||||
totalBlocks: 0
|
||||
}
|
||||
assert.deepEqual(AvailabilityUtils.maxValue(space), 5 * GB);
|
||||
})
|
||||
|
||||
it("checks the availability max value", async () => {
|
||||
const availability = {
|
||||
totalSize: GB
|
||||
} as AvailabilityState
|
||||
assert.deepEqual(AvailabilityUtils.isValid(availability, GB * 2), true);
|
||||
assert.deepEqual(AvailabilityUtils.isValid({ ...availability, totalSize: -1 }, GB), false);
|
||||
assert.deepEqual(AvailabilityUtils.isValid({ ...availability, totalSize: 2 * GB }, GB), false);
|
||||
})
|
||||
|
||||
it("toggles item in array", async () => {
|
||||
const array: string[] = []
|
||||
assert.deepEqual(AvailabilityUtils.toggle(array, "1"), ["1"]);
|
||||
assert.deepEqual(AvailabilityUtils.toggle(AvailabilityUtils.toggle(array, "1"), "1"), []);
|
||||
})
|
||||
})
|
||||
@ -48,5 +48,27 @@ export const AvailabilityUtils = {
|
||||
availability: AvailabilityState,
|
||||
max: number
|
||||
) => availability.totalSize > 0 && availability.totalSize <= max
|
||||
,
|
||||
toggle: <T>(arr: Array<T>, value: T) =>
|
||||
arr.includes(value) ? arr.filter(i => i !== value) : [...arr, value],
|
||||
|
||||
availabilityColors: [
|
||||
"#34A0FFFF",
|
||||
"#34A0FFEE",
|
||||
"#34A0FFDD",
|
||||
"#34A0FFCC",
|
||||
"#34A0FFBB",
|
||||
"#34A0FFAA",
|
||||
"#34A0FF99",
|
||||
],
|
||||
|
||||
slotColors: [
|
||||
"#D2493CFF",
|
||||
"#D2493CEE",
|
||||
"#D2493CDD",
|
||||
"#D2493CCC",
|
||||
"#D2493CBB",
|
||||
"#D2493CAA",
|
||||
"#D2493C99",
|
||||
]
|
||||
}
|
||||
@ -58,34 +58,6 @@ export function CardNumbers({
|
||||
<InfoIcon></InfoIcon>
|
||||
</Tooltip>
|
||||
<span>{unit}</span>
|
||||
|
||||
{/* <div
|
||||
className={classnames(["cardNumber"], ["cardNumber--error", !!error])}>
|
||||
<div className="cardNumber-dataContainer">
|
||||
<>
|
||||
<p
|
||||
ref={ref}
|
||||
className="cardNumber-data"
|
||||
onBlur={onBlur}
|
||||
onInput={onInput}
|
||||
contentEditable={true}
|
||||
/>
|
||||
|
||||
<ButtonIcon
|
||||
onClick={onEditingClick}
|
||||
variant="small"
|
||||
Icon={Icon}></ButtonIcon>
|
||||
</>
|
||||
</div>
|
||||
<div className="cardNumber-info">
|
||||
<b className="cardNumber-title">{title}</b>
|
||||
</div>
|
||||
</div>
|
||||
{error ? (
|
||||
<small className="cardNumber-errorText">{error}</small>
|
||||
) : (
|
||||
<small className="cardNumber-helperText">{helper}</small>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ type Props = {
|
||||
value: number;
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
export function ProgressCircle(_: Props) {
|
||||
return (
|
||||
<div className="progress-circle">
|
||||
|
||||
@ -25,18 +25,10 @@ export const CustomStateCellRender = ({ state, message }: Props) => {
|
||||
<p className={"cell-state"}>
|
||||
{message ? (
|
||||
<Tooltip message={message}>
|
||||
<Icon
|
||||
width={20}
|
||||
className="cell-stateIcon"
|
||||
data-testid={"cell-" + state}
|
||||
/>
|
||||
<Icon width={20} data-testid={"cell-" + state} />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Icon
|
||||
width={20}
|
||||
className="cell-stateIcon"
|
||||
data-testid={"cell-" + state}
|
||||
/>
|
||||
<Icon width={20} data-testid={"cell-" + state} />
|
||||
)}
|
||||
</p>
|
||||
</Cell>
|
||||
|
||||
@ -8,7 +8,7 @@ export function Debug() {
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="settings-debug-loader">
|
||||
<div>
|
||||
<Spinner width="3rem" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
.dialog::backdrop {
|
||||
background: rgba(70, 70, 70, 0.75);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.dialog {
|
||||
background-color: var(--codex-background-secondary);
|
||||
border: none;
|
||||
color: var(--codex-color);
|
||||
min-width: 200px;
|
||||
|
||||
&::backdrop {
|
||||
background: rgba(70, 70, 70, 0.75);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ export function Download() {
|
||||
id="cid"
|
||||
placeholder="CID"
|
||||
inputClassName="download-input"
|
||||
size={"medium" as any}
|
||||
variant={"medium"}
|
||||
autoComplete="off"
|
||||
onChange={onCidChange}></Input>
|
||||
<Button label="Download" onClick={onDownload} variant="outline"></Button>
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
import { CircleX } from "lucide-react";
|
||||
|
||||
export function ErrorIcon() {
|
||||
return (
|
||||
<span className="text--error">
|
||||
<CircleX size="4rem" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { Placeholder } from "@codex-storage/marketplace-ui-components";
|
||||
import { ErrorIcon } from "../ErrorIcon/ErrorIcon";
|
||||
import ErrorCircleIcon from "../../assets/icons/error-circle.svg?react";
|
||||
|
||||
type Props = {
|
||||
subtitle?: string;
|
||||
@ -13,7 +13,7 @@ export function ErrorPlaceholder({ subtitle, error }: Props) {
|
||||
|
||||
return (
|
||||
<Placeholder
|
||||
Icon={<ErrorIcon />}
|
||||
Icon={<ErrorCircleIcon />}
|
||||
title="Error"
|
||||
subtitle={subtitle}
|
||||
message={message}></Placeholder>
|
||||
|
||||
@ -1,24 +1,18 @@
|
||||
.fileCell {
|
||||
.file-render {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.fileCell-cid {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tooltip:hover::after {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.fileCell-subtitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fileCell-tooltip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fileCell .tooltip:hover:after {
|
||||
left: -33%;
|
||||
small {
|
||||
white-space: nowrap;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
text-align: left;
|
||||
color: #7d7d7d;
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,17 +69,17 @@ export function FileCell({ requestId, purchaseCid, data, onMetadata }: Props) {
|
||||
|
||||
return (
|
||||
<Cell>
|
||||
<div className="fileCell">
|
||||
<div className="file-render">
|
||||
<WebFileIcon type={metadata.mimetype || "-"} />
|
||||
<div>
|
||||
<span className="fileCell-title">
|
||||
<div>
|
||||
<Tooltip message={filename}>{filename}</Tooltip>
|
||||
</span>
|
||||
<span className="fileCell-subtitle">
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip message={cid}>
|
||||
<span className="fileCell-cid">{cidTruncated}</span>
|
||||
<small>{cidTruncated}</small>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Cell>
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { CodexDataContent, CodexPurchase } from "@codex-storage/sdk-js";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { Dates } from "../../utils/dates";
|
||||
import { CidCopyButton } from "./CidCopyButton";
|
||||
import "./FileDetails.css";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
@ -43,7 +42,8 @@ export function FileDetails({ onClose, details }: Props) {
|
||||
}
|
||||
|
||||
return {
|
||||
error: false as any,
|
||||
/* eslint-disable @typescript-eslint/prefer-as-const */
|
||||
error: false as false,
|
||||
data: all,
|
||||
};
|
||||
})
|
||||
@ -115,7 +115,11 @@ export function FileDetails({ onClose, details }: Props) {
|
||||
|
||||
<li>
|
||||
<p>Date:</p>
|
||||
<p>{Dates.format(details.manifest.uploadedAt).toString()}</p>
|
||||
<p>
|
||||
{FilesUtils.formatDate(
|
||||
details.manifest.uploadedAt
|
||||
).toString()}
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { ChangeEvent, useEffect, useState } from "react";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { Dates } from "../../utils/dates";
|
||||
import "./Files.css";
|
||||
import {
|
||||
Tabs,
|
||||
@ -166,7 +165,9 @@ export function Files({ limit }: Props) {
|
||||
cells={[
|
||||
<FileCell content={c}></FileCell>,
|
||||
<Cell>{PrettyBytes(c.manifest.datasetSize)}</Cell>,
|
||||
<Cell>{Dates.format(c.manifest.uploadedAt).toString()}</Cell>,
|
||||
<Cell>
|
||||
{FilesUtils.formatDate(c.manifest.uploadedAt).toString()}
|
||||
</Cell>,
|
||||
<FileActions
|
||||
content={c}
|
||||
folders={folders}
|
||||
@ -198,7 +199,7 @@ export function Files({ limit }: Props) {
|
||||
pattern="[A-Za-z0-9_\-]*"
|
||||
autoComplete="off"
|
||||
maxLength={9}
|
||||
size={"medium" as any}
|
||||
variant={"medium"}
|
||||
placeholder="Folder name"
|
||||
onChange={onFolderChange}></Input>
|
||||
|
||||
|
||||
@ -292,4 +292,10 @@ describe("files", () => {
|
||||
|
||||
assert.deepEqual(FilesUtils.applyFilters(files, ["archive"]), [files[1]]);
|
||||
});
|
||||
|
||||
it("formats date", async () => {
|
||||
|
||||
assert.equal(FilesUtils.formatDate(1732102577), "20 Nov 2024, 12:36");
|
||||
|
||||
})
|
||||
})
|
||||
@ -89,6 +89,16 @@ export const FilesUtils = {
|
||||
return files.filter(
|
||||
(file) => filters.length === 0 || filters.includes(this.type(file.manifest.mimetype))
|
||||
)
|
||||
},
|
||||
formatDate(date: number) {
|
||||
if (!date) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
return new Intl.DateTimeFormat("en-GB", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
}).format(new Date(date * 1000));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -96,8 +96,6 @@ export function HealthChecks({ online, onStepValid }: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
console.info("address", address);
|
||||
|
||||
return (
|
||||
<div className="health-checks">
|
||||
<div
|
||||
|
||||
@ -48,7 +48,7 @@ export function ManifestFetch() {
|
||||
id="cid"
|
||||
value={cid}
|
||||
placeholder="CID"
|
||||
size={"medium" as any}
|
||||
variant={"medium"}
|
||||
autoComplete="off"
|
||||
onChange={onCidChange}></Input>
|
||||
<Button label="Fetch" onClick={onDownload} variant="outline"></Button>
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
export const nodeSpaceAllocationColors = [
|
||||
"var(--codex-color-primary)",
|
||||
"#f9fa93",
|
||||
"#ccc",
|
||||
]
|
||||
@ -1,5 +1,5 @@
|
||||
import { assert, describe, it } from "vitest";
|
||||
import { PeerGeo, PeerUtils } from "./peers.utils";
|
||||
import { PeerGeo, PeerNode, PeerUtils } from "./peers.utils";
|
||||
|
||||
describe("peers", () => {
|
||||
it("sorts by boolean", async () => {
|
||||
@ -41,14 +41,14 @@ describe("peers", () => {
|
||||
});
|
||||
|
||||
it("adds a new pin", async () => {
|
||||
const latLng = { latitude: 0, longitude: 0 } as any
|
||||
const values = PeerUtils.incPin([], latLng)
|
||||
const latLng = { latitude: 0, longitude: 0 }
|
||||
const values = PeerUtils.incPin([], latLng as PeerNode & PeerGeo)
|
||||
|
||||
assert.deepEqual(values, [[latLng, 1]]);
|
||||
});
|
||||
|
||||
it("increments an existing pin", async () => {
|
||||
const latLng = { lat: 0, lng: 0 } as any
|
||||
const latLng = { lat: 0, lng: 0 } as unknown as PeerNode & PeerGeo
|
||||
const values = PeerUtils.incPin([[latLng, 1]], latLng)
|
||||
|
||||
assert.deepEqual(values, [[latLng, 2]]);
|
||||
|
||||
@ -114,7 +114,7 @@ export function PurchasesTable() {
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="purchases-loader">
|
||||
<div>
|
||||
<Spinner width="3rem" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,145 +0,0 @@
|
||||
.range {
|
||||
/* width: 100%;
|
||||
accent-color: var(--codex-color-primary);
|
||||
height: 1px;
|
||||
outline: none; */
|
||||
--val: 50;
|
||||
width: 100%;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.range-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@property --c {
|
||||
syntax: "<color>";
|
||||
inherits: true;
|
||||
initial-value: #0000;
|
||||
}
|
||||
|
||||
.glow {
|
||||
--c: rgb(0, 255, 255, calc(0.25 + var(--val) / 125));
|
||||
--c: hsl(160deg 80% 50% / calc(0.25 + var(--val) / 125));
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.glow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc((var(--val) - 1) * 1%);
|
||||
min-width: 0.5em;
|
||||
height: 100%;
|
||||
background: var(--c);
|
||||
box-shadow:
|
||||
0 0 0.2em 0 hsl(0 0% 0%) inset,
|
||||
-0.1em 0.1em 0.1em -0.1em hsl(0 0% 100% / 0.5),
|
||||
0 0 calc(1em + 0.001em * var(--val)) calc(0.1em + 0.00025em * var(--val))
|
||||
var(--c);
|
||||
border-radius: 1em 0 0 1em;
|
||||
aopacity: calc(20% + var(--val) * 1%);
|
||||
}
|
||||
|
||||
/***** Track Styles *****/
|
||||
/***** Chrome, Safari, Opera, and Edge Chromium *****/
|
||||
.glow::-webkit-slider-runnable-track {
|
||||
box-shadow:
|
||||
0 0 0.2em 0 hsl(0 0% 0%) inset,
|
||||
-0.1em 0.1em 0.1em -0.1em hsl(0 0% 100% / 0.5);
|
||||
background: linear-gradient(to bottom right, #0001, #0000), #343133;
|
||||
border-radius: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
/******** Firefox ********/
|
||||
.glow::-moz-range-track {
|
||||
box-shadow:
|
||||
0 0 2px 0 hsl(0 0% 0%) inset,
|
||||
-1px 1px 1px -1px hsl(0 0% 100% / 0.5);
|
||||
background:
|
||||
linear-gradient(var(--c) 0 0) 0 0 / calc(var(--val) * 1%) 100% no-repeat,
|
||||
linear-gradient(to bottom right, #0001, #0000),
|
||||
#343133;
|
||||
border-radius: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
/***** Thumb Styles *****/
|
||||
/***** Chrome, Safari, Opera, and Edge Chromium *****/
|
||||
.glow::-webkit-slider-thumb {
|
||||
--d: var(--c);
|
||||
--d: rgb(from var(--c) r g b / calc(0.35 * var(--val) * 1%));
|
||||
-webkit-appearance: none; /* Override default look */
|
||||
appearance: none;
|
||||
background-color: #5cd5eb;
|
||||
transform: translateY(calc(-50% + 0.5em));
|
||||
width: 4em;
|
||||
aspect-ratio: 1;
|
||||
background: red;
|
||||
border-radius: 50%;
|
||||
background:
|
||||
radial-gradient(
|
||||
farthest-side,
|
||||
#0000 22.5%,
|
||||
var(--d) 0,
|
||||
#0000 calc(var(--val) * 0.75%)
|
||||
)
|
||||
50% 50% / 100% 100% no-repeat,
|
||||
radial-gradient(#0000 15%, #343133 16%, #545153 20%),
|
||||
repeating-linear-gradient(#0000 0 10%, #0002 0 20%) 50% 50% / 25% 25%
|
||||
no-repeat,
|
||||
repeating-linear-gradient(90deg, #0000 0 10%, #0002 0 20%) 50% 50% / 25% 25%
|
||||
no-repeat,
|
||||
radial-gradient(var(--c) 17%, #0000 0),
|
||||
#545153;
|
||||
box-shadow:
|
||||
inset -0.15em -0.15em 0.2em #0008,
|
||||
inset 0.15em 0.15em 0.2em #ffffff22,
|
||||
inset calc(var(--val) * 1em / 500) 0em calc(var(--val) * 1em / 500)
|
||||
calc(var(--val) * -1em / 700) var(--c),
|
||||
0.25em 0.25em 0.5em #0006,
|
||||
calc(0.0125em * var(--val)) calc(0.005em * var(--val))
|
||||
calc(0.02em * var(--val)) calc(-0.01em * var(--val)) #000a;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/***** Firefox *****/
|
||||
.glow::-moz-range-thumb {
|
||||
/* --d: var(--c);
|
||||
--d: rgb(from var(--c) r g b / calc(0.35 * var(--val) * 1%)); */
|
||||
border: none; /*Removes extra border that FF applies*/
|
||||
-webkit-appearance: none; /* Override default look */
|
||||
appearance: none;
|
||||
background-color: #5cd5eb;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
aspect-ratio: 1;
|
||||
background: red;
|
||||
border-radius: 50%;
|
||||
background:
|
||||
/* radial-gradient(farthest-side, #0000 22.5%, var(--d) 0, #0000 calc(var(--val) * 0.75%)) 50% 50% / 100% 100% no-repeat, */
|
||||
radial-gradient(#0000 15%, #343133 16%, #545153 20%),
|
||||
repeating-linear-gradient(#0000 0 10%, #0002 0 20%) 50% 50% / 25% 25%
|
||||
no-repeat,
|
||||
repeating-linear-gradient(90deg, #0000 0 10%, #0002 0 20%) 50% 50% / 25% 25%
|
||||
no-repeat,
|
||||
radial-gradient(var(--c) 17%, #0000 0),
|
||||
#545153;
|
||||
box-shadow:
|
||||
inset -0.15em -0.15em 0.2em #0008,
|
||||
inset 0.15em 0.15em 0.2em #ffffff22,
|
||||
inset calc(var(--val) * 1em / 500) 0em calc(var(--val) * 1em / 500)
|
||||
calc(var(--val) * -1em / 700) var(--c),
|
||||
0.25em 0.25em 0.5em #0006,
|
||||
calc(0.015em * var(--val)) calc(0.005em * var(--val))
|
||||
calc(0.02em * var(--val)) calc(-0.01em * var(--val)) #0008;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
import { ChangeEvent, FormEvent, useState } from "react";
|
||||
import "./Range.css";
|
||||
|
||||
type Props = {
|
||||
label?: string;
|
||||
max: number;
|
||||
labels: string[];
|
||||
className?: string;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
defaultValue?: number | string;
|
||||
value?: number | string;
|
||||
};
|
||||
|
||||
export function Range({
|
||||
label,
|
||||
max,
|
||||
onChange,
|
||||
defaultValue,
|
||||
value,
|
||||
className = "",
|
||||
}: Props) {
|
||||
const [val, setVal] = useState(value);
|
||||
|
||||
const onInput = (e: FormEvent<HTMLInputElement>) => {
|
||||
setVal(parseInt(e.currentTarget.value, 10));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{label}
|
||||
<input
|
||||
type="range"
|
||||
max={max}
|
||||
min={1}
|
||||
className="range glow"
|
||||
onChange={onChange}
|
||||
defaultValue={defaultValue}
|
||||
value={value}
|
||||
style={{ "--val": val } as React.CSSProperties}
|
||||
onInput={onInput}
|
||||
/>
|
||||
{/* <div className="range-labels">
|
||||
{labels.map((l) => (
|
||||
<div className="range-label" key={l}>
|
||||
{l}
|
||||
</div>
|
||||
))}
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
.storageRequestAvailability {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||
import "./StorageRequestAvailability.css";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { StorageAvailabilityUnit, StorageAvailabilityValue } from "./types";
|
||||
import { InputGroup } from "@codex-storage/marketplace-ui-components";
|
||||
|
||||
type Props = {
|
||||
onToggleNext: (next: boolean) => void;
|
||||
};
|
||||
|
||||
export function StorageRequestAvailability({ onToggleNext }: Props) {
|
||||
const [unit, setUnit] = useState<StorageAvailabilityUnit>("minutes");
|
||||
const [value, setValue] = useState(0);
|
||||
const cache = useRef<StorageAvailabilityValue | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (cache.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebStorage.get<StorageAvailabilityValue>("storage-request-step-2").then(
|
||||
(val) => {
|
||||
if (val) {
|
||||
cache.current = val;
|
||||
setUnit(val.unit);
|
||||
setValue(val.value);
|
||||
onToggleNext(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
WebStorage.set("storage-request-step-2", cache.current);
|
||||
};
|
||||
}, [onToggleNext]);
|
||||
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!cache.current) {
|
||||
cache.current = { unit: "months", value: 0 };
|
||||
}
|
||||
|
||||
cache.current.value = parseInt(e.currentTarget.value, 10);
|
||||
|
||||
setValue(parseInt(e.currentTarget.value, 10));
|
||||
onToggleNext(!!e.currentTarget.value);
|
||||
};
|
||||
|
||||
const onUnitChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
if (!cache.current) {
|
||||
cache.current = { unit: "months", value: 0 };
|
||||
}
|
||||
|
||||
setUnit(e.currentTarget.value as StorageAvailabilityUnit);
|
||||
cache.current.unit = e.currentTarget.value as StorageAvailabilityUnit;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="storageRequest-title">
|
||||
How long do you want to store your file?
|
||||
</span>
|
||||
|
||||
<InputGroup
|
||||
id="availability"
|
||||
label="Availability"
|
||||
type="number"
|
||||
className="storageRequestAvailability"
|
||||
group={[
|
||||
["years", "Years"],
|
||||
["months", "Months"],
|
||||
["days", "Days"],
|
||||
["hours", "Hours"],
|
||||
["minutes", "Minutes"],
|
||||
]}
|
||||
value={value.toString()}
|
||||
groupValue={unit}
|
||||
onChange={onChange}
|
||||
onGroupChange={onUnitChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,128 +0,0 @@
|
||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { StorageDurabilityStepValue } from "./types";
|
||||
import { InputGroup } from "@codex-storage/marketplace-ui-components";
|
||||
|
||||
type Props = {
|
||||
onToggleNext: (next: boolean) => void;
|
||||
};
|
||||
|
||||
type Cache = { tolerance: number; nodes: number; proofProbability: number };
|
||||
|
||||
export function StorageRequestDurability({ onToggleNext }: Props) {
|
||||
const [tolerance, setTolerance] = useState("");
|
||||
const [proofProbability, setProofProbability] = useState("");
|
||||
const [nodes, setNodes] = useState("");
|
||||
const cache = useRef<Cache | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (cache.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebStorage.get<StorageDurabilityStepValue>("storage-request-step-3").then(
|
||||
(val) => {
|
||||
if (val) {
|
||||
cache.current = val;
|
||||
setTolerance(val.tolerance.toString());
|
||||
setProofProbability(val.proofProbability.toString());
|
||||
setNodes(val.nodes.toString());
|
||||
onToggleNext(shouldEnableNext());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
WebStorage.set("storage-request-step-3", cache.current);
|
||||
};
|
||||
}, [onToggleNext]);
|
||||
|
||||
const shouldEnableNext = () => {
|
||||
return (
|
||||
cache.current?.tolerance != undefined &&
|
||||
!!cache.current.proofProbability != undefined &&
|
||||
!!cache.current.nodes
|
||||
);
|
||||
};
|
||||
|
||||
const updateCache = (data: Partial<Cache>) => {
|
||||
if (!cache.current) {
|
||||
cache.current = { nodes: 0, proofProbability: 0, tolerance: 0 };
|
||||
}
|
||||
|
||||
cache.current = { ...cache.current, ...data };
|
||||
};
|
||||
|
||||
const onChangeTolerance = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setTolerance(e.currentTarget.value);
|
||||
updateCache({ tolerance: parseInt(e.currentTarget.value || "0", 10) });
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
const onChangeProofProbability = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setProofProbability(e.currentTarget.value);
|
||||
updateCache({
|
||||
proofProbability: parseInt(e.currentTarget.value || "0", 10),
|
||||
});
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
const onChangeNodes = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setNodes(e.currentTarget.value);
|
||||
updateCache({ nodes: parseInt(e.currentTarget.value || "0", 10) });
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className="storageRequest-title">
|
||||
Define your criteria to make your data durable
|
||||
</span>
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Nodes"
|
||||
id="nodes"
|
||||
value={nodes}
|
||||
onChange={onChangeNodes}
|
||||
group={"nodes"}
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary input-full">
|
||||
Minimal number of nodes the content should be stored on
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Tolerance"
|
||||
id="tolerance"
|
||||
value={tolerance}
|
||||
onChange={onChangeTolerance}
|
||||
group={"nodes"}
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary">
|
||||
Additional number of nodes on top of the nodes property that can be
|
||||
lost before pronouncing the content lost
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Proof probability"
|
||||
id="proofProbability"
|
||||
value={proofProbability}
|
||||
onChange={onChangeProofProbability}
|
||||
group={"seconds"}
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary">
|
||||
How often storage proofs are required as decimal string
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,134 +0,0 @@
|
||||
import { useState, useRef, useEffect, ChangeEvent } from "react";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { StoragePriceStepValue } from "./types";
|
||||
import { InputGroup } from "@codex-storage/marketplace-ui-components";
|
||||
|
||||
type Props = {
|
||||
onToggleNext: (next: boolean) => void;
|
||||
};
|
||||
|
||||
export function StorageRequestPrice({ onToggleNext }: Props) {
|
||||
const [reward, setReward] = useState("");
|
||||
const [collateral, setCollateral] = useState("");
|
||||
const [expiration, setExpiration] = useState("");
|
||||
const cache = useRef<StoragePriceStepValue | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (cache.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebStorage.get<StoragePriceStepValue>("storage-request-step-4").then(
|
||||
(val) => {
|
||||
if (val) {
|
||||
cache.current = val;
|
||||
setReward(val.reward.toString());
|
||||
setCollateral(val.collateral.toString());
|
||||
setExpiration(val.expiration.toString());
|
||||
onToggleNext(shouldEnableNext());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
WebStorage.set("storage-request-step-4", cache.current);
|
||||
};
|
||||
}, [onToggleNext]);
|
||||
|
||||
const updateCache = (data: Partial<StoragePriceStepValue>) => {
|
||||
if (!cache.current) {
|
||||
cache.current = { collateral: 0, expiration: 0, reward: 0 };
|
||||
}
|
||||
|
||||
cache.current = { ...cache.current, ...data };
|
||||
};
|
||||
|
||||
const shouldEnableNext = () => {
|
||||
return (
|
||||
!!cache.current?.reward &&
|
||||
!!cache.current.collateral &&
|
||||
!!cache.current.expiration
|
||||
);
|
||||
};
|
||||
|
||||
const onChangeReward = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setReward(e.currentTarget.value);
|
||||
updateCache({ reward: parseFloat(e.currentTarget.value || "0") });
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
const onChangeCollateral = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setCollateral(e.currentTarget.value);
|
||||
updateCache({ collateral: parseFloat(e.currentTarget.value || "0") });
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
const onChangeExpiration = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setExpiration(e.currentTarget.value);
|
||||
updateCache({ expiration: parseFloat(e.currentTarget.value || "0") });
|
||||
onToggleNext(shouldEnableNext());
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className="storageRequest-title">
|
||||
Define your criteria for the payments
|
||||
</span>
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Reward"
|
||||
id="reward"
|
||||
value={reward}
|
||||
onChange={onChangeReward}
|
||||
group={"tokens"}
|
||||
type={"number"}
|
||||
step="0.1"
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary">
|
||||
The maximum amount of tokens paid per second per slot to hosts the
|
||||
client is willing to pay
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Collateral"
|
||||
id="collateral"
|
||||
value={collateral}
|
||||
onChange={onChangeCollateral}
|
||||
group={"tokens"}
|
||||
type={"number"}
|
||||
step="0.1"
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary">
|
||||
Number as decimal string that represents how much collateral is
|
||||
asked from hosts that wants to fill a slots
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="input-spacing">
|
||||
<InputGroup
|
||||
label="Expiration"
|
||||
id="expiration"
|
||||
value={expiration}
|
||||
onChange={onChangeExpiration}
|
||||
group={"minutes"}
|
||||
type={"number"}
|
||||
/>
|
||||
<div>
|
||||
<span className="input-helper-text text-secondary">
|
||||
Number as decimal string that represents expiry threshold in seconds
|
||||
from when the Request is submitted. When the threshold is reached
|
||||
and the Request does not find requested amount of nodes to host the
|
||||
data, the Request is voided. The number of seconds can not be higher
|
||||
then the Request's duration itself.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
.storageRequest-title {
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.storageRequest-intro {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.storageRequest-steps {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.storageRequest-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.storageRequest-stepText {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.storageRequest-stepCompleted {
|
||||
text-decoration: line-through;
|
||||
mix-blend-mode: difference;
|
||||
}
|
||||
|
||||
.storageRequest-stepDisabled {
|
||||
background-color: var(--codex-border-color);
|
||||
color: var(--codex-text-disabled);
|
||||
border: none;
|
||||
border-radius: var(--codex-border-radius);
|
||||
padding: 0.25rem 0.75rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.storageRequest-step-action {
|
||||
background-color: var(--codex-border-color);
|
||||
color: var(--codex-text-disabled);
|
||||
border: none;
|
||||
border-radius: var(--codex-border-radius);
|
||||
padding: 0.25rem 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.35s;
|
||||
}
|
||||
|
||||
.storageRequest-step-action:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.storageRequest-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.75rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.storageRequest {
|
||||
.stepper-body,
|
||||
.stepper {
|
||||
/* width: calc(100% - 3rem); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 801px) {
|
||||
.storageRequest {
|
||||
margin: auto;
|
||||
width: 85%;
|
||||
}
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
import { CircleCheck, Database, Server } from "lucide-react";
|
||||
import { ICON_SIZE } from "../../utils/constants";
|
||||
import "./StorageRequestSetup.css";
|
||||
|
||||
export function StorageRequestSetup() {
|
||||
return (
|
||||
<div className="storageRequest">
|
||||
<h2 className="storageRequest-title">Storage setup</h2>
|
||||
<p className="text-secondary storageRequest-intro">
|
||||
You need to follow these steps to start a new request storage.
|
||||
</p>
|
||||
<p>
|
||||
<b>3 of 5 completed</b>
|
||||
</p>
|
||||
<div className="storageRequest-steps">
|
||||
<div className="storageRequest-step">
|
||||
<CircleCheck
|
||||
size={ICON_SIZE}
|
||||
fill="currentColor"
|
||||
className="primary upload-progress-check"
|
||||
stroke="var(--codex-background)"></CircleCheck>
|
||||
<span className="storageRequest-stepText storageRequest-step-completed">
|
||||
Offers storage for sale
|
||||
</span>
|
||||
<button className="storageRequest-stepDisabled" disabled>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
<div className="storageRequest-step">
|
||||
<CircleCheck
|
||||
size={ICON_SIZE}
|
||||
fill="currentColor"
|
||||
className="primary upload-progress-check"
|
||||
stroke="var(--codex-background)"></CircleCheck>
|
||||
<span className="storageRequest-stepText storageRequest-step-completed">
|
||||
Updates availability
|
||||
</span>
|
||||
<button className="storageRequest-stepDisabled" disabled>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
<div className="storageRequest-step">
|
||||
<CircleCheck
|
||||
size={ICON_SIZE}
|
||||
fill="currentColor"
|
||||
className="primary upload-progress-check"
|
||||
stroke="var(--codex-background)"></CircleCheck>
|
||||
<span className="storageRequest-stepText storageRequest-step-completed">
|
||||
Get availability's reservations
|
||||
</span>
|
||||
<button className="storageRequest-stepDisabled" disabled>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
<div className="storageRequest-step">
|
||||
<Database
|
||||
size={ICON_SIZE}
|
||||
fill="currentColor"
|
||||
className="upload-progress-check"
|
||||
stroke="var(--codex-background)"></Database>
|
||||
<span className="storageRequest-stepText">
|
||||
Check list of purchase IDs
|
||||
</span>
|
||||
<button className="storageRequest-step-action" disabled>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
<div className="storageRequest-step">
|
||||
<Server
|
||||
size={ICON_SIZE}
|
||||
fill="currentColor"
|
||||
className="upload-progress-check"
|
||||
stroke="var(--codex-background)"></Server>
|
||||
<span className="storageRequest-stepText">
|
||||
Check storage that is for sale
|
||||
</span>
|
||||
<button className="storageRequest-step-action" disabled>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
.storageRequestDone {
|
||||
.storage-success {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.storageRequestDone-icon {
|
||||
color: var(--codex-color-primary);
|
||||
svg {
|
||||
color: var(--codex-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,9 +18,9 @@ export function StorageRequestSuccess({
|
||||
return (
|
||||
<Placeholder
|
||||
Icon={<CircleCheck size="4rem" className="storageRequestDone-icon" />}
|
||||
className="storageRequestDone"
|
||||
className=".storage-success"
|
||||
title="Your request is being processed."
|
||||
message=" Processing your request may take some time. Once completed, it will
|
||||
message="Processing your request may take some time. Once completed, it will
|
||||
appear in your purchase list. You can safely close this dialog."></Placeholder>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
import { CircleCheck } from "lucide-react";
|
||||
|
||||
export function SuccessIcon() {
|
||||
return (
|
||||
<span className="text--primary">
|
||||
<CircleCheck size="4rem" className="successIcon" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -1,26 +1,11 @@
|
||||
.truncateCell {
|
||||
.truncate-cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.truncateCell .tooltip:hover:after {
|
||||
left: -33%;
|
||||
}
|
||||
|
||||
.truncateCell-point {
|
||||
height: 0.5rem;
|
||||
width: 3rem;
|
||||
border-radius: var(--codex-border-radius);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.truncateCell--ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.table-tbodyTr:hover .truncateCell--ellipsis {
|
||||
white-space: unset;
|
||||
word-break: break-all;
|
||||
small {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 150px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Cell } from "@codex-storage/marketplace-ui-components";
|
||||
import { Cell, Tooltip } from "@codex-storage/marketplace-ui-components";
|
||||
import "./TruncateCell.css";
|
||||
|
||||
type Props = {
|
||||
@ -11,11 +11,11 @@ export function TruncateCell({ value }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Cell>
|
||||
<div className="truncateCell" id={value}>
|
||||
<div className="truncateCell--ellipsis">
|
||||
<span>{value}</span>
|
||||
</div>
|
||||
<Cell className="truncate-cell">
|
||||
<div>
|
||||
<Tooltip message={value}>
|
||||
<small>{value}</small>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Cell>
|
||||
);
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
export function TruncateCellRender(cid: string) {
|
||||
const truncated = cid.slice(0, 5) + ".".repeat(5) + cid.slice(-5);
|
||||
return <span>{truncated}</span>;
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
/* prettier-ignore-start */
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file is auto-generated by TanStack Router
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
// Import Routes
|
||||
|
||||
@ -18,7 +18,6 @@ import { Route as IndexImport } from './routes/index'
|
||||
import { Route as DashboardIndexImport } from './routes/dashboard/index'
|
||||
import { Route as DashboardWalletImport } from './routes/dashboard/wallet'
|
||||
import { Route as DashboardSettingsImport } from './routes/dashboard/settings'
|
||||
import { Route as DashboardRequestsImport } from './routes/dashboard/requests'
|
||||
import { Route as DashboardPurchasesImport } from './routes/dashboard/purchases'
|
||||
import { Route as DashboardPeersImport } from './routes/dashboard/peers'
|
||||
import { Route as DashboardNodesImport } from './routes/dashboard/nodes'
|
||||
@ -76,12 +75,6 @@ const DashboardSettingsRoute = DashboardSettingsImport.update({
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
|
||||
const DashboardRequestsRoute = DashboardRequestsImport.update({
|
||||
id: '/requests',
|
||||
path: '/requests',
|
||||
getParentRoute: () => DashboardRoute,
|
||||
} as any)
|
||||
|
||||
const DashboardPurchasesRoute = DashboardPurchasesImport.update({
|
||||
id: '/purchases',
|
||||
path: '/purchases',
|
||||
@ -270,13 +263,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof DashboardPurchasesImport
|
||||
parentRoute: typeof DashboardImport
|
||||
}
|
||||
'/dashboard/requests': {
|
||||
id: '/dashboard/requests'
|
||||
path: '/requests'
|
||||
fullPath: '/dashboard/requests'
|
||||
preLoaderRoute: typeof DashboardRequestsImport
|
||||
parentRoute: typeof DashboardImport
|
||||
}
|
||||
'/dashboard/settings': {
|
||||
id: '/dashboard/settings'
|
||||
path: '/settings'
|
||||
@ -316,7 +302,6 @@ interface DashboardRouteChildren {
|
||||
DashboardNodesRoute: typeof DashboardNodesRoute
|
||||
DashboardPeersRoute: typeof DashboardPeersRoute
|
||||
DashboardPurchasesRoute: typeof DashboardPurchasesRoute
|
||||
DashboardRequestsRoute: typeof DashboardRequestsRoute
|
||||
DashboardSettingsRoute: typeof DashboardSettingsRoute
|
||||
DashboardWalletRoute: typeof DashboardWalletRoute
|
||||
DashboardIndexRoute: typeof DashboardIndexRoute
|
||||
@ -335,7 +320,6 @@ const DashboardRouteChildren: DashboardRouteChildren = {
|
||||
DashboardNodesRoute: DashboardNodesRoute,
|
||||
DashboardPeersRoute: DashboardPeersRoute,
|
||||
DashboardPurchasesRoute: DashboardPurchasesRoute,
|
||||
DashboardRequestsRoute: DashboardRequestsRoute,
|
||||
DashboardSettingsRoute: DashboardSettingsRoute,
|
||||
DashboardWalletRoute: DashboardWalletRoute,
|
||||
DashboardIndexRoute: DashboardIndexRoute,
|
||||
@ -362,7 +346,6 @@ export interface FileRoutesByFullPath {
|
||||
'/dashboard/nodes': typeof DashboardNodesRoute
|
||||
'/dashboard/peers': typeof DashboardPeersRoute
|
||||
'/dashboard/purchases': typeof DashboardPurchasesRoute
|
||||
'/dashboard/requests': typeof DashboardRequestsRoute
|
||||
'/dashboard/settings': typeof DashboardSettingsRoute
|
||||
'/dashboard/wallet': typeof DashboardWalletRoute
|
||||
'/dashboard/': typeof DashboardIndexRoute
|
||||
@ -384,7 +367,6 @@ export interface FileRoutesByTo {
|
||||
'/dashboard/nodes': typeof DashboardNodesRoute
|
||||
'/dashboard/peers': typeof DashboardPeersRoute
|
||||
'/dashboard/purchases': typeof DashboardPurchasesRoute
|
||||
'/dashboard/requests': typeof DashboardRequestsRoute
|
||||
'/dashboard/settings': typeof DashboardSettingsRoute
|
||||
'/dashboard/wallet': typeof DashboardWalletRoute
|
||||
'/dashboard': typeof DashboardIndexRoute
|
||||
@ -408,7 +390,6 @@ export interface FileRoutesById {
|
||||
'/dashboard/nodes': typeof DashboardNodesRoute
|
||||
'/dashboard/peers': typeof DashboardPeersRoute
|
||||
'/dashboard/purchases': typeof DashboardPurchasesRoute
|
||||
'/dashboard/requests': typeof DashboardRequestsRoute
|
||||
'/dashboard/settings': typeof DashboardSettingsRoute
|
||||
'/dashboard/wallet': typeof DashboardWalletRoute
|
||||
'/dashboard/': typeof DashboardIndexRoute
|
||||
@ -433,7 +414,6 @@ export interface FileRouteTypes {
|
||||
| '/dashboard/nodes'
|
||||
| '/dashboard/peers'
|
||||
| '/dashboard/purchases'
|
||||
| '/dashboard/requests'
|
||||
| '/dashboard/settings'
|
||||
| '/dashboard/wallet'
|
||||
| '/dashboard/'
|
||||
@ -454,7 +434,6 @@ export interface FileRouteTypes {
|
||||
| '/dashboard/nodes'
|
||||
| '/dashboard/peers'
|
||||
| '/dashboard/purchases'
|
||||
| '/dashboard/requests'
|
||||
| '/dashboard/settings'
|
||||
| '/dashboard/wallet'
|
||||
| '/dashboard'
|
||||
@ -476,7 +455,6 @@ export interface FileRouteTypes {
|
||||
| '/dashboard/nodes'
|
||||
| '/dashboard/peers'
|
||||
| '/dashboard/purchases'
|
||||
| '/dashboard/requests'
|
||||
| '/dashboard/settings'
|
||||
| '/dashboard/wallet'
|
||||
| '/dashboard/'
|
||||
@ -501,8 +479,6 @@ export const routeTree = rootRoute
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
/* prettier-ignore-end */
|
||||
|
||||
/* ROUTE_MANIFEST_START
|
||||
{
|
||||
"routes": {
|
||||
@ -533,7 +509,6 @@ export const routeTree = rootRoute
|
||||
"/dashboard/nodes",
|
||||
"/dashboard/peers",
|
||||
"/dashboard/purchases",
|
||||
"/dashboard/requests",
|
||||
"/dashboard/settings",
|
||||
"/dashboard/wallet",
|
||||
"/dashboard/"
|
||||
@ -593,10 +568,6 @@ export const routeTree = rootRoute
|
||||
"filePath": "dashboard/purchases.tsx",
|
||||
"parent": "/dashboard"
|
||||
},
|
||||
"/dashboard/requests": {
|
||||
"filePath": "dashboard/requests.tsx",
|
||||
"parent": "/dashboard"
|
||||
},
|
||||
"/dashboard/settings": {
|
||||
"filePath": "dashboard/settings.tsx",
|
||||
"parent": "/dashboard"
|
||||
|
||||
@ -16,7 +16,6 @@ import { Strings } from "../../utils/strings";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { Sunburst } from "../../components/Availability/Sunburst";
|
||||
import { Errors } from "../../utils/errors";
|
||||
import { availabilityColors } from "../../components/Availability/availability.colors";
|
||||
import { AvailabilityWithSlots } from "../../components/Availability/types";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { NodeSpace } from "../../components/NodeSpace/NodeSpace";
|
||||
@ -116,7 +115,7 @@ export function Availabilities() {
|
||||
title: Strings.shortId(a.id),
|
||||
size: a.totalSize,
|
||||
tooltip: a.id + "\u000D\u000A" + PrettyBytes(a.totalSize),
|
||||
color: availabilityColors[index],
|
||||
color: AvailabilityUtils.availabilityColors[index],
|
||||
})
|
||||
);
|
||||
|
||||
@ -128,7 +127,7 @@ export function Availabilities() {
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="purchases-loader">
|
||||
<div>
|
||||
<Spinner width="3rem" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.disclaimer-title {
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.disclaimer-text {
|
||||
line-height: 1.5rem;
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,37 +3,34 @@ import "./disclaimer.css";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/disclaimer")({
|
||||
component: () => (
|
||||
<div className="container">
|
||||
<div className="disclaimer">
|
||||
<h1 className="disclaimer-title">Disclaimer</h1>
|
||||
<div className="disclaimer">
|
||||
<h1>Disclaimer</h1>
|
||||
|
||||
<p className="disclaimer-text">
|
||||
The website and the content herein is not intended for public use and
|
||||
is for informational and demonstration purposes only.
|
||||
</p>
|
||||
<p>
|
||||
The website and the content herein is not intended for public use and is
|
||||
for informational and demonstration purposes only.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p className="disclaimer-text">
|
||||
The website and any associated functionalities are provided on an “as
|
||||
is” basis without any guarantees, warranties, or representations of
|
||||
any kind, either express or implied. The website and any associated
|
||||
functionalities may not reflect the final version of the project and
|
||||
is subject to changes, updates, or removal at any time and without
|
||||
notice.
|
||||
</p>
|
||||
<p>
|
||||
The website and any associated functionalities are provided on an “as
|
||||
is” basis without any guarantees, warranties, or representations of any
|
||||
kind, either express or implied. The website and any associated
|
||||
functionalities may not reflect the final version of the project and is
|
||||
subject to changes, updates, or removal at any time and without notice.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p className="disclaimer-text">
|
||||
By accessing and using this website, you agree that we, Logos
|
||||
Collective Association and its affiliates, will not be liable for any
|
||||
direct, indirect, incidental, or consequential damages arising from
|
||||
the use of, or inability to use, this website. Any data, content, or
|
||||
interactions on this site are non-binding and should not be considered
|
||||
final or actionable. Your use of this website is at your sole risk.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
By accessing and using this website, you agree that we, Logos Collective
|
||||
Association and its affiliates, will not be liable for any direct,
|
||||
indirect, incidental, or consequential damages arising from the use of,
|
||||
or inability to use, this website. Any data, content, or interactions on
|
||||
this site are non-binding and should not be considered final or
|
||||
actionable. Your use of this website is at your sole risk.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
@ -1,44 +1,44 @@
|
||||
.help {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.help-title {
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
color: var(--codex-color-light);
|
||||
}
|
||||
> div {
|
||||
padding-bottom: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid var(--codex-border-color);
|
||||
gap: 1rem;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.help-itemTitle {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
div {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
}
|
||||
|
||||
.help-itemIcon {
|
||||
color: var(--codex-color-disabled);
|
||||
min-width: 1.5rem;
|
||||
height: auto;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.help-itemBody {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
p {
|
||||
color: var(--codex-color-light);
|
||||
}
|
||||
|
||||
.help-item {
|
||||
padding-bottom: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid var(--codex-border-color);
|
||||
gap: 1rem;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
svg {
|
||||
color: var(--codex-color-disabled);
|
||||
min-width: 1.5rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.help-link {
|
||||
color: var(--codex-color-primary);
|
||||
text-decoration: underline;
|
||||
a {
|
||||
color: var(--codex-color-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,93 +18,86 @@ const Help = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="help">
|
||||
<h1 className="help-title">You might be wondering...</h1>
|
||||
<div className="help">
|
||||
<h1>You might be wondering...</h1>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1.5rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">What's Codex?</p>
|
||||
<p className="help-text">
|
||||
Codex is a decentralised data storage platform that provides
|
||||
exceptionally strong censorship resistance and durability
|
||||
guarantees. It serves as the storage layer of the Logos tech
|
||||
stack.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1.5rem"} />
|
||||
<div>
|
||||
<h2>What's Codex?</h2>
|
||||
<p>
|
||||
Codex is a decentralised data storage platform that provides
|
||||
exceptionally strong censorship resistance and durability
|
||||
guarantees. It serves as the storage layer of the Logos tech stack.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">
|
||||
What is the purpose of this web application?
|
||||
</p>
|
||||
<p className="help-text">
|
||||
This application allows you to interact with the Codex Marketplace
|
||||
network in a user-friendly manner.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1rem"} />
|
||||
<div>
|
||||
<h2>What is the purpose of this web application?</h2>
|
||||
<p>
|
||||
This application allows you to interact with the Codex Marketplace
|
||||
network in a user-friendly manner.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">Can Codex handle big files ?</p>
|
||||
<p className="help-text">
|
||||
Codex can handle very large files, which is its main purpose.
|
||||
However, for this UI, the files used should not be too large.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1rem"} />
|
||||
<div>
|
||||
<h2>Can Codex handle big files ?</h2>
|
||||
<p>
|
||||
Codex can handle very large files, which is its main purpose.
|
||||
However, for this UI, the files used should not be too large.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">Is it production ready ?</p>
|
||||
<p className="help-text">
|
||||
Not at all! This is a very early alpha version. You should expect
|
||||
to encounter bugs, but don't worry—feel free to reach out to us if
|
||||
you need assistance.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1rem"} />
|
||||
<div>
|
||||
<h2>Is it production ready ?</h2>
|
||||
<p>
|
||||
Not at all! This is a very early alpha version. You should expect to
|
||||
encounter bugs, but don't worry—feel free to reach out to us if you
|
||||
need assistance.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">
|
||||
How can I reach you if I am stuck ?
|
||||
</p>
|
||||
<p className="help-text">
|
||||
Please create a new issue on our GitHub repository
|
||||
<a
|
||||
href="https://github.com/codex-storage/codex-marketplace-ui"
|
||||
className="help-link"
|
||||
target="_blank">
|
||||
https://github.com/codex-storage/codex-marketplace-ui
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1rem"} />
|
||||
<div>
|
||||
<h2>How can I reach you if I am stuck ?</h2>
|
||||
<p>
|
||||
Please create a new issue on our GitHub repository
|
||||
<a
|
||||
href="https://github.com/codex-storage/codex-marketplace-ui"
|
||||
className="help-link"
|
||||
target="_blank">
|
||||
https://github.com/codex-storage/codex-marketplace-ui
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="help-item">
|
||||
<HelpCircle className="help-itemIcon" size={"1rem"} />
|
||||
<div className="help-itemBody">
|
||||
<p className="help-itemTitle">How can I build and run Codex ?</p>
|
||||
<p className="help-text">
|
||||
For instructions, please visit{" "}
|
||||
<a
|
||||
href="https://docs.codex.storage"
|
||||
className="help-link"
|
||||
target="_blank">
|
||||
https://docs.codex.storage
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<HelpCircle size={"1rem"} />
|
||||
<div>
|
||||
<h2>How can I build and run Codex ?</h2>
|
||||
<p>
|
||||
For instructions, please visit{" "}
|
||||
<a
|
||||
href="https://docs.codex.storage"
|
||||
className="help-link"
|
||||
target="_blank">
|
||||
https://docs.codex.storage
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -26,6 +26,7 @@ const Logs = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const { table, ...rest } = data ?? {};
|
||||
|
||||
return (
|
||||
|
||||
@ -12,14 +12,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.purchases-loader {
|
||||
margin: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.purchases-modal {
|
||||
width: calc(100% - 2rem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
.requests {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--codex-background-light);
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import "./requests.css";
|
||||
import { StorageRequestSetup } from "../../components/StorageRequestSetup/StorageRequestSetup";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/requests")({
|
||||
component: () => {
|
||||
return (
|
||||
<div className="container requests">
|
||||
<div className="stepper-container"></div>
|
||||
|
||||
<StorageRequestSetup />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
@ -1,4 +0,0 @@
|
||||
export const Arrays = {
|
||||
toggle: <T>(arr: Array<T>, value: T) =>
|
||||
arr.includes(value) ? arr.filter(i => i !== value) : [...arr, value]
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
export const Dates = {
|
||||
format(date: number) {
|
||||
if (!date) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
return new Intl.DateTimeFormat("en-GB", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
}).format(new Date(date * 1000));
|
||||
},
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user