Clean components and update dependencies

This commit is contained in:
Arnaud 2024-11-20 14:07:12 +01:00
parent dbc4562571
commit 810a7f5336
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
66 changed files with 2028 additions and 3570 deletions

3856
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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 */

View File

View File

@ -1,5 +1,4 @@
import { ReactNode } from "react";
import "./App.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();

View File

@ -87,9 +87,3 @@
}
}
}
/* @media (min-width: 1000px) {
.appBar-burger {
display: none;
}
} */

View File

@ -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 (

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -1,4 +0,0 @@
import { createContext } from "react";
import { AvailabilityWithSlots } from "./types";
export const AvailabilityContext = createContext<AvailabilityWithSlots | null>(null);

View File

@ -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({

View File

@ -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;

View File

@ -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>
</>
);
}

View File

@ -1,5 +0,0 @@
.availabilitySpaceAllocation-title {
margin-left: auto;
margin-right: auto;
margin-bottom: 1rem;
}

View File

@ -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} />
</>
);
}

View File

@ -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>
);

View File

@ -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: {

View File

@ -1,19 +0,0 @@
export const availabilityColors = [
"#34A0FFFF",
"#34A0FFEE",
"#34A0FFDD",
"#34A0FFCC",
"#34A0FFBB",
"#34A0FFAA",
"#34A0FF99",
];
export const slotColors = [
"#D2493CFF",
"#D2493CEE",
"#D2493CDD",
"#D2493CCC",
"#D2493CBB",
"#D2493CAA",
"#D2493C99",
];

View File

@ -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;

View File

@ -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"), []);
})
})

View File

@ -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",
]
}

View File

@ -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>
);
}

View File

@ -4,6 +4,7 @@ type Props = {
value: number;
};
/* eslint-disable @typescript-eslint/no-unused-vars */
export function ProgressCircle(_: Props) {
return (
<div className="progress-circle">

View File

@ -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>

View File

@ -8,7 +8,7 @@ export function Debug() {
if (isPending) {
return (
<div className="settings-debug-loader">
<div>
<Spinner width="3rem" />
</div>
);

View File

@ -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);
}
}

View File

@ -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>

View File

@ -1,9 +0,0 @@
import { CircleX } from "lucide-react";
export function ErrorIcon() {
return (
<span className="text--error">
<CircleX size="4rem" />
</span>
);
}

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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");
})
})

View File

@ -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));
}
};

View File

@ -96,8 +96,6 @@ export function HealthChecks({ online, onStepValid }: Props) {
}
}
console.info("address", address);
return (
<div className="health-checks">
<div

View File

@ -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>

View File

@ -1,5 +0,0 @@
export const nodeSpaceAllocationColors = [
"var(--codex-color-primary)",
"#f9fa93",
"#ccc",
]

View File

@ -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]]);

View File

@ -114,7 +114,7 @@ export function PurchasesTable() {
if (isPending) {
return (
<div className="purchases-loader">
<div>
<Spinner width="3rem" />
</div>
);

View File

@ -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%;
}

View File

@ -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>
);
}

View File

@ -1,5 +0,0 @@
.storageRequestAvailability {
flex: 1;
display: flex;
align-items: center;
}

View File

@ -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}
/>
</>
);
}

View File

@ -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>
);
}

View File

@ -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>
);
}

View File

@ -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%;
}
}

View File

@ -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>
);
}

View File

@ -1,7 +1,7 @@
.storageRequestDone {
.storage-success {
margin: auto;
}
.storageRequestDone-icon {
color: var(--codex-color-primary);
svg {
color: var(--codex-color-primary);
}
}

View File

@ -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>
);
}

View File

@ -1,9 +0,0 @@
import { CircleCheck } from "lucide-react";
export function SuccessIcon() {
return (
<span className="text--primary">
<CircleCheck size="4rem" className="successIcon" />
</span>
);
}

View File

@ -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;
}
}

View File

@ -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>
);

View File

@ -1,4 +0,0 @@
export function TruncateCellRender(cid: string) {
const truncated = cid.slice(0, 5) + ".".repeat(5) + cid.slice(-5);
return <span>{truncated}</span>;
}

View File

@ -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"

View File

@ -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>
);

View File

@ -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;
}
}

View File

@ -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>
),
});

View File

@ -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;
}
}

View File

@ -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 worryfeel 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 worryfeel 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&nbsp;
<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&nbsp;
<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>

View File

@ -26,6 +26,7 @@ const Logs = () => {
};
}, []);
/* eslint-disable @typescript-eslint/no-unused-vars */
const { table, ...rest } = data ?? {};
return (

View File

@ -12,14 +12,3 @@
}
}
}
.purchases-loader {
margin: auto;
display: block;
}
@media (max-width: 800px) {
.purchases-modal {
width: calc(100% - 2rem);
}
}

View File

@ -1,7 +0,0 @@
.requests {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: var(--codex-background-light);
}

View File

@ -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>
);
},
});

View File

@ -1,4 +0,0 @@
export const Arrays = {
toggle: <T>(arr: Array<T>, value: T) =>
arr.includes(value) ? arr.filter(i => i !== value) : [...arr, value]
}

View File

@ -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));
},
};