Better ui

This commit is contained in:
Pavel Murygin
2021-07-22 02:27:32 +03:00
parent 5a787dcf22
commit aa094a9f1d
9 changed files with 154 additions and 201 deletions

View File

@ -3,7 +3,7 @@ $color2: rgb(214, 214, 214);
$accent-color: rgb(225, 30, 90); $accent-color: rgb(225, 30, 90);
.logo { .logo {
height: 15vmin; height: 10vmin;
pointer-events: none; pointer-events: none;
} }
@ -16,7 +16,7 @@ $accent-color: rgb(225, 30, 90);
} }
header { header {
margin-top: 10vmin; margin-top: 3vmin;
} }
header, header,
@ -44,23 +44,13 @@ li {
padding: 0; padding: 0;
} }
.p { p {
width: 550px; margin: 0.5em;
text-align: left;
} }
.btn-clipboard { .row {
border: none; width: 100%;
background-color: transparent;
cursor: pointer;
&:hover,
&:focus {
color: $accent-color;
}
&:focus {
outline: none;
}
} }
.btn { .btn {
@ -88,27 +78,49 @@ li {
} }
} }
.btn-hello { .btn-right {
width: 200px; width: 250px;
display: inline; display: inline;
float: right; float: right;
} }
.btn-inline {
background-color: transparent;
margin: 5px;
display: inline;
border: none;
font-size: inherit;
font-family: inherit;
color: $accent-color;
outline: none;
&:hover,
&:focus {
outline: none;
text-decoration: underline;
cursor: pointer;
}
}
table { table {
text-align: right; text-align: right;
} }
.label { .label {
width: 240px; width: 30%;
display: inline-block; display: inline-block;
text-align: right;
margin-right: 5px;
} }
.input { .input {
width: 500px; width: calc(70% - 15px);
height: 26px; height: 26px;
box-sizing: border-box; box-sizing: border-box;
margin: 5px; margin: 5px;
padding: 0 5px;
border: 1px solid; border: 1px solid;
border-color: $color2; border-color: $color2;
@ -125,75 +137,15 @@ table {
} }
} }
.gg-clipboard { .input-ro {
display: inline;
width: 500px;
height: 26px;
box-sizing: border-box; box-sizing: border-box;
position: relative;
display: block; margin: 5px;
transform: scale(var(--ggs, 1));
width: 18px;
height: 18px;
border: 2px solid;
border-radius: 2px;
}
.gg-clipboard::after,
.gg-clipboard::before {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
border-radius: 2px;
width: 10px;
left: 2px;
}
.gg-clipboard::before {
border: 2px solid;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
top: -2px;
height: 6px;
}
.gg-clipboard::after {
height: 2px;
background: currentColor;
box-shadow: 0 -4px 0 0;
bottom: 2px;
} }
.gg-trash { .article {
box-sizing: border-box; margin-bottom: 10px;
position: relative;
display: block;
transform: scale(var(--ggs, 1));
width: 10px;
height: 12px;
border: 2px solid transparent;
box-shadow: 0 0 0 2px, inset -2px 0 0, inset 2px 0 0;
border-bottom-left-radius: 1px;
border-bottom-right-radius: 1px;
margin-top: 4px;
}
.gg-trash::after,
.gg-trash::before {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
}
.gg-trash::after {
background: currentColor;
border-radius: 3px;
width: 16px;
height: 2px;
top: -4px;
left: -5px;
}
.gg-trash::before {
width: 10px;
height: 4px;
border: 2px solid;
border-bottom: transparent;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
top: -7px;
left: -2px;
} }

View File

@ -2,18 +2,25 @@ import React from "react";
import logo from "./logo.svg"; import logo from "./logo.svg";
import "./App.scss"; import "./App.scss";
import { gotRpcAddrState, isConnectedState, isDeployedState } from "./state"; import {
gotRpcAddrState,
hasResultState,
isConnectedState,
isDeployedState,
} from "./state";
import { useRecoilValue } from "recoil"; import { useRecoilValue } from "recoil";
import { ConnectedInfo } from "./Components/ConnectedInfo"; import { ConnectedInfo } from "./Components/ConnectedInfo";
import { ConnectionForm } from "./Components/ConnectionForm"; import { ConnectionForm } from "./Components/ConnectionForm";
import { IpfsForm } from "./Components/IpfsForm"; import { IpfsForm } from "./Components/IpfsForm";
import { IpfsDeploymentInfo } from "./Components/IpfsDeploymentInfo"; import { IpfsDeploymentInfo } from "./Components/IpfsDeploymentInfo";
import { SizeCalcForm } from "./Components/SizeCalcForm"; import { SizeCalcForm } from "./Components/SizeCalcForm";
import { SizeCalcResult } from "./Components/SizeCalcResult";
function App() { function App() {
const isConnected = useRecoilValue(isConnectedState); const isConnected = useRecoilValue(isConnectedState);
const gotRpcAddr = useRecoilValue(gotRpcAddrState); const gotRpcAddr = useRecoilValue(gotRpcAddrState);
const isDeployed = useRecoilValue(isDeployedState); const isDeployed = useRecoilValue(isDeployedState);
const hasResult = useRecoilValue(hasResultState);
console.log( console.log(
"isConnected gotRpcAddr deployed\n", "isConnected gotRpcAddr deployed\n",
@ -38,6 +45,7 @@ function App() {
<SizeCalcForm /> <SizeCalcForm />
</> </>
)} )}
{isDeployed && hasResult && <SizeCalcResult />}
</div> </div>
</div> </div>
); );

View File

@ -1,6 +1,6 @@
import { useRecoilValue } from "recoil"; import { useRecoilValue } from "recoil";
import { clientState } from "../state"; import { clientState } from "../state";
import { copyToClipboard } from "../util"; import { TextWithLabel } from "./TextInput";
export const ConnectedInfo = () => { export const ConnectedInfo = () => {
const client = useRecoilValue(clientState); const client = useRecoilValue(clientState);
@ -11,34 +11,8 @@ export const ConnectedInfo = () => {
return ( return (
<> <>
<h1>Connected</h1> <h1>Connected</h1>
<table> <TextWithLabel text={"Peer id:"} value={client.selfPeerId} />
<thead> <TextWithLabel text={"Relay peer id:"} value={client.selfPeerId} />
<tr>
<td className="bold">Peer id:</td>
<td className="mono">{client.selfPeerId}</td>
<td>
<button
className="btn-clipboard"
onClick={() => copyToClipboard(client.selfPeerId)}
>
<i className="gg-clipboard"></i>
</button>
</td>
</tr>
<tr>
<td className="bold">Relay peer id:</td>
<td className="mono">{client.relayPeerId}</td>
<td>
<button
className="btn-clipboard"
onClick={() => copyToClipboard(client.relayPeerId!)}
>
<i className="gg-clipboard"></i>
</button>
</td>
</tr>
</thead>
</table>
</> </>
); );
}; };

View File

@ -1,36 +1,29 @@
import { useRecoilValue } from "recoil"; import { useRecoilValue } from "recoil";
import { serviceIdState, useRemoveServuce, wasmState } from "../state"; import { serviceIdState, useRemoveService, wasmState } from "../state";
import { copyToClipboard } from "../util"; import { copyToClipboard } from "../util";
import { TextWithLabel } from "./TextInput";
export const IpfsDeploymentInfo = () => { export const IpfsDeploymentInfo = () => {
const wasm = useRecoilValue(wasmState); const wasm = useRecoilValue(wasmState);
const serviceId = useRecoilValue(serviceIdState); const serviceId = useRecoilValue(serviceIdState);
const removeService = useRemoveServuce; const removeService = useRemoveService();
return ( return (
<> <>
<h2>Deployed</h2> <h2>
<table> Service deployed{" "}
<tr> <button className="btn-inline" onClick={removeService}>
<td className="bold">process_files.wasm CID:</td> remove
<td className="mono">{wasm}</td> </button>
<td> </h2>
<button <div className="article">
className="btn-clipboard" <p>
onClick={() => copyToClipboard(wasm)} Service deployed into Fluence network. You can observe it's service ID
> as well as the CID of the wasm file used to create the service
<i className="gg-clipboard"></i> </p>
</button> </div>
</td> <TextWithLabel text={"CID:"} value={wasm} />
</tr> <TextWithLabel text={"Service ID:"} value={serviceId} />
<tr>
<td className="bold">ProcessFiles service ID:</td>
<td className="mono">{serviceId}</td>
<button className="btn-clipboard" onClick={removeService}>
<i className="gg-trash"></i>
</button>
</tr>
</table>
</> </>
); );
}; };

View File

@ -9,17 +9,19 @@ export const IpfsForm = () => {
return ( return (
<> <>
<h2>Ipfs</h2> <h2>Deploy service from IPFS</h2>
<p> <div className="article">
process_files.wasm will be downloaded via IPFS to the Fluence node, and <p>Now we can deploy service from IPFS into Fluence network</p>
then a service will be dynamically created from it! After that, you will <p>
be able to use that service to get sizes of IPFS files! process_files.wasm will be downloaded via IPFS to the Fluence node,
<br /> and then a service will be dynamically created from it! After that,
To do so, please specify IPFS RPC address to download process_files.wasm you will be able to use that service to get sizes of IPFS files!
from </p>
<br /> <p>
And specify CID of WebAssembly module. To do so, please specify IPFS RPC address of process_files.wasm from,
</p> and the CIP of WebAssembly module to use (process_files.wasm)
</p>
</div>
<TextInput <TextInput
text={"IPFS RPC address"} text={"IPFS RPC address"}
@ -33,7 +35,7 @@ export const IpfsForm = () => {
setValue={setWasm} setValue={setWasm}
/> />
<div className="row"> <div className="row">
<button className="btn btn-hello" onClick={deployService}> <button className="btn btn-right" onClick={deployService}>
deploy service deploy service
</button> </button>
</div> </div>

View File

@ -1,55 +1,29 @@
import { useRecoilState, useRecoilValue } from "recoil"; import { useRecoilState, useRecoilValue } from "recoil";
import { import { fileCIDState, rpcAddrState, useGetFileSize } from "../state";
fileCIDState, import { TextInput } from "./TextInput";
fileSizeCIDState,
fileSizeState,
rpcAddrState,
useGetFileSize,
} from "../state";
export const SizeCalcForm = () => { export const SizeCalcForm = () => {
const rpcAddr = useRecoilValue(rpcAddrState); const rpcAddr = useRecoilValue(rpcAddrState);
const [fileCID, setFileCID] = useRecoilState(fileCIDState); const [fileCID, setFileCID] = useRecoilState(fileCIDState);
const fileSize = useRecoilValue(fileSizeState);
const fileSizeCID = useRecoilValue(fileSizeCIDState);
const getFileSize = useGetFileSize(); const getFileSize = useGetFileSize();
return ( return (
<> <>
<div> <h2>Get file size</h2>
<h2>Get file size</h2> <div className="article">
<p className="p"> <p>
Upload any file to IPFS node Upload any file to IPFS node
<p> <b>{rpcAddr}</b>
<b>{rpcAddr}</b>
</p>
paste CID here and get the size of that file via ProcessFiles service paste CID here and get the size of that file via ProcessFiles service
you have just deployed you have just deployed
</p> </p>
<div className="row">
<label className="label bold">IPFS CID</label>
<input
className="input"
type="text"
onChange={(e) => setFileCID(e.target.value)}
value={fileCID}
/>
</div>
<div className="row">
<button className="btn btn-hello" onClick={getFileSize}>
get size
</button>
</div>
</div> </div>
<TextInput text={"IPFS CID"} value={fileCID} setValue={setFileCID} />
<div className="row"> <div className="row">
<label className="label bold">File Size:</label> <button className="btn btn-right" onClick={getFileSize}>
<label className="mono">{fileSize}</label> get size
</div> </button>
<div className="row">
<label className="label bold">
File size is uploaded to IPFS as CID:
</label>
<label className="mono">{fileSizeCID}</label>
</div> </div>
</> </>
); );

View File

@ -0,0 +1,23 @@
import { useRecoilValue } from "recoil";
import { fileSizeCIDState, fileSizeState } from "../state";
import { TextWithLabel } from "./TextInput";
export const SizeCalcResult = () => {
const fileSize = useRecoilValue(fileSizeState);
const fileSizeCID = useRecoilValue(fileSizeCIDState);
return (
<>
<h2>Result</h2>
<div className="article">
<p>
File size has been calculated and displayed below. Also the result of
the calculation has been uploaded to IPFS and is available under it's
CID
</p>
</div>
<TextWithLabel text="File size:" value={fileSize} />
<TextWithLabel text="File size IPFS CID:" value={fileSizeCID} />
</>
);
};

View File

@ -18,3 +18,15 @@ export const TextInput = (props: {
</div> </div>
); );
}; };
export const TextWithLabel = (props: {
text: string;
value: string | null;
}) => {
return (
<div className="row">
<label className="label bold">{props.text}</label>
<div className="input-ro">{props.value || ""}</div>
</div>
);
};

View File

@ -38,19 +38,19 @@ export const rpcAddrState = atom<string | null>({
default: null, default: null,
}); });
export const fileCIDState = atom<string>({ export const fileCIDState = atom<string | null>({
key: "fileCIDState", key: "fileCIDState",
default: "", default: null,
}); });
export const fileSizeState = atom<string>({ export const fileSizeState = atom<string | null>({
key: "fileSizeState", key: "fileSizeState",
default: "", default: null,
}); });
export const fileSizeCIDState = atom<string>({ export const fileSizeCIDState = atom<string | null>({
key: "fileSizeCIDState", key: "fileSizeCIDState",
default: "", default: null,
}); });
export const isConnectedState = selector({ export const isConnectedState = selector({
@ -81,6 +81,14 @@ export const isDeployedState = selector({
}, },
}); });
export const hasResultState = selector({
key: "hasResultState",
get: ({ get }) => {
const fileSize = get(fileSizeState);
return fileSize !== null;
},
});
const getRpcAddr = async (client: FluenceClient) => { const getRpcAddr = async (client: FluenceClient) => {
if (client === null) { if (client === null) {
console.log("getRpcAddr client is null"); console.log("getRpcAddr client is null");
@ -140,8 +148,9 @@ export const useGetFileSize = () => {
const rpcAddr = useRecoilValue(rpcAddrState); const rpcAddr = useRecoilValue(rpcAddrState);
const client = useRecoilValue(clientState); const client = useRecoilValue(clientState);
const serviceId = useRecoilValue(serviceIdState); const serviceId = useRecoilValue(serviceIdState);
const fileCID = useRecoilValue(fileCIDState);
const setFileSize = useSetRecoilState(fileSizeState); const setFileSize = useSetRecoilState(fileSizeState);
const [fileCID, setFileSizeCID] = useRecoilState(fileCIDState); const setFileSizeCID = useSetRecoilState(fileSizeCIDState);
return async () => { return async () => {
if (client === null || serviceId === null || rpcAddr === null) { if (client === null || serviceId === null || rpcAddr === null) {
@ -151,7 +160,7 @@ export const useGetFileSize = () => {
var putResult = await put_file_size( var putResult = await put_file_size(
client, client,
client.relayPeerId!, client.relayPeerId!,
fileCID, fileCID!,
rpcAddr, rpcAddr,
serviceId, serviceId,
(size) => setFileSize(size.toString()), (size) => setFileSize(size.toString()),
@ -170,9 +179,12 @@ export const useGetFileSize = () => {
}; };
}; };
export const useRemoveServuce = () => { export const useRemoveService = () => {
const client = useRecoilValue(clientState); const client = useRecoilValue(clientState);
const [serviceId, setServiceId] = useRecoilState(serviceIdState); const [serviceId, setServiceId] = useRecoilState(serviceIdState);
const setFileCID = useSetRecoilState(fileCIDState);
const setFileSize = useSetRecoilState(fileSizeState);
const setFileSizeCID = useSetRecoilState(fileSizeCIDState);
return async () => { return async () => {
if (client === null || serviceId === null) { if (client === null || serviceId === null) {
@ -183,5 +195,8 @@ export const useRemoveServuce = () => {
ttl: 10000, ttl: 10000,
}); });
setServiceId(null); setServiceId(null);
setFileCID(null);
setFileSize(null);
setFileSizeCID(null);
}; };
}; };