mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-22 16:41:38 +03:00
integration: reduced client to essential functions
This commit is contained in:
parent
d65a9efd8e
commit
bf4761eb37
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ DS_STORE
|
||||
/**/*/.data
|
||||
|
||||
.data/**/*
|
||||
.library/**/*
|
||||
|
@ -8,7 +8,7 @@ const REQUEST_HEADERS = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const SERVER_PATH = '';
|
||||
const SERVER_PATH = 'http://localhost:1337';
|
||||
|
||||
export const rehydrateViewer = async () => {
|
||||
const options = {
|
||||
@ -18,10 +18,24 @@ export const rehydrateViewer = async () => {
|
||||
body: JSON.stringify({}),
|
||||
};
|
||||
|
||||
const response = await fetch(`/_/viewer`, options);
|
||||
const response = await fetch(`${SERVER_PATH}/_/viewer`, options);
|
||||
const json = await response.json();
|
||||
|
||||
return State.getInitialState(json.data);
|
||||
return json;
|
||||
};
|
||||
|
||||
export const setDefaultConfig = async (data) => {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: REQUEST_HEADERS,
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
|
||||
const response = await fetch(`${SERVER_PATH}/_/settings`, options);
|
||||
const json = await response.json();
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
export const createWalletAddress = async (data) => {
|
||||
@ -36,7 +50,7 @@ export const createWalletAddress = async (data) => {
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
|
||||
const response = await fetch(`/_/wallet/create`, options);
|
||||
const response = await fetch(`${SERVER_PATH}/_/wallet/create`, options);
|
||||
const json = await response.json();
|
||||
|
||||
return json;
|
||||
@ -62,7 +76,7 @@ export const sendWalletAddressFilecoin = async (data) => {
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
|
||||
const response = await fetch(`/_/wallet/send`, options);
|
||||
const response = await fetch(`${SERVER_PATH}/_/wallet/send`, options);
|
||||
const json = await response.json();
|
||||
|
||||
return json;
|
||||
|
@ -488,6 +488,7 @@ export const NavigationState = [
|
||||
name: 'Wallet',
|
||||
pageTitle: 'your wallet and addresses',
|
||||
decorator: 'WALLET',
|
||||
/*
|
||||
children: [
|
||||
{
|
||||
id: 3,
|
||||
@ -497,6 +498,7 @@ export const NavigationState = [
|
||||
decorator: 'CHANNELS',
|
||||
},
|
||||
],
|
||||
*/
|
||||
},
|
||||
constructFilesTreeForNavigation(),
|
||||
{
|
||||
@ -514,6 +516,7 @@ export const NavigationState = [
|
||||
},
|
||||
],
|
||||
},
|
||||
/*
|
||||
{
|
||||
id: 9,
|
||||
name: 'Stats',
|
||||
@ -557,6 +560,7 @@ export const NavigationState = [
|
||||
decorator: 'LOGS',
|
||||
children: null,
|
||||
},
|
||||
*/
|
||||
{
|
||||
id: 13,
|
||||
name: 'Edit account',
|
||||
|
@ -1,4 +1,4 @@
|
||||
const STATIC_ADDRESS_TYPE_MAP = { bls: 'BLS' };
|
||||
const STATIC_ADDRESS_TYPE_MAP = { bls: 'BLS', secp256k1: 'SECP256K1', multisig: 'MULTISIG' };
|
||||
|
||||
const transformAddresses = (addrsList, info) => {
|
||||
const balanceMap = {};
|
||||
@ -8,7 +8,8 @@ const transformAddresses = (addrsList, info) => {
|
||||
|
||||
return addrsList.map((each, index) => {
|
||||
return {
|
||||
value: `${index + 1}`,
|
||||
id: each.addr,
|
||||
value: each.addr,
|
||||
balance: balanceMap[each.addr],
|
||||
name: each.name,
|
||||
address: each.addr,
|
||||
@ -26,7 +27,7 @@ const transformPeers = (peersList) => {
|
||||
'peer-avatar': null,
|
||||
'chain-head': null,
|
||||
height: null,
|
||||
location: each.location.country,
|
||||
location: null,
|
||||
upload: null,
|
||||
download: null,
|
||||
};
|
||||
@ -35,12 +36,11 @@ const transformPeers = (peersList) => {
|
||||
|
||||
export const getInitialState = (props) => {
|
||||
const { status, messageList, peersList, addrsList, info } = props;
|
||||
console.log(props);
|
||||
|
||||
return {
|
||||
id: info.id,
|
||||
name: 'Andrew Hill',
|
||||
photoURL: '/static/avatar-andrew-hill.jpg',
|
||||
name: 'New Node',
|
||||
photoURL: '/static/system/avatar.png',
|
||||
config: '',
|
||||
upload_bandwidth: 0,
|
||||
download_bandwidth: 0,
|
||||
|
@ -5,37 +5,42 @@ const WEEK = DAY * 7;
|
||||
const MONTH = (DAY * 365) / 12;
|
||||
const YEAR = DAY * 365;
|
||||
|
||||
export const copyText = (str) => {
|
||||
const el = document.createElement('textarea');
|
||||
el.value = str;
|
||||
el.setAttribute('readonly', '');
|
||||
el.style.position = 'absolute';
|
||||
el.style.left = '-9999px';
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const hexToRGBA = (hex, alpha = 1) => {
|
||||
hex = hex.replace("#", "");
|
||||
var r = parseInt(
|
||||
hex.length == 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2),
|
||||
16
|
||||
);
|
||||
var g = parseInt(
|
||||
hex.length == 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4),
|
||||
16
|
||||
);
|
||||
var b = parseInt(
|
||||
hex.length == 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6),
|
||||
16
|
||||
);
|
||||
hex = hex.replace('#', '');
|
||||
var r = parseInt(hex.length == 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2), 16);
|
||||
var g = parseInt(hex.length == 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4), 16);
|
||||
var b = parseInt(hex.length == 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6), 16);
|
||||
if (alpha) {
|
||||
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
|
||||
return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')';
|
||||
} else {
|
||||
return "rgb(" + r + ", " + g + ", " + b + ")";
|
||||
return 'rgb(' + r + ', ' + g + ', ' + b + ')';
|
||||
}
|
||||
};
|
||||
|
||||
export const bytesToSize = (bytes, decimals = 2) => {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
export const getRemainingTime = (seconds) => {
|
||||
@ -43,18 +48,18 @@ export const getRemainingTime = (seconds) => {
|
||||
|
||||
let [value, unit] =
|
||||
seconds < MINUTE
|
||||
? [Math.round(seconds), "second"]
|
||||
? [Math.round(seconds), 'second']
|
||||
: seconds < HOUR
|
||||
? [Math.round(seconds / MINUTE), "minute"]
|
||||
? [Math.round(seconds / MINUTE), 'minute']
|
||||
: seconds < DAY
|
||||
? [Math.round(seconds / HOUR), "hour"]
|
||||
? [Math.round(seconds / HOUR), 'hour']
|
||||
: seconds < WEEK
|
||||
? [Math.round(seconds / DAY), "day"]
|
||||
? [Math.round(seconds / DAY), 'day']
|
||||
: seconds < MONTH
|
||||
? [Math.round(seconds / WEEK), "week"]
|
||||
? [Math.round(seconds / WEEK), 'week']
|
||||
: seconds < YEAR
|
||||
? [Math.round(seconds / MONTH), "month"]
|
||||
: [Math.round(seconds / YEAR), "year"];
|
||||
? [Math.round(seconds / MONTH), 'month']
|
||||
: [Math.round(seconds / YEAR), 'year'];
|
||||
|
||||
unit = pluralize(unit, value);
|
||||
|
||||
@ -73,7 +78,7 @@ export const pluralize = (text, count) => {
|
||||
return count > 1 || count === 0 ? `${text}s` : text;
|
||||
};
|
||||
|
||||
export const elide = (string, length = 140, emptyState = "...") => {
|
||||
export const elide = (string, length = 140, emptyState = '...') => {
|
||||
if (isEmpty(string)) {
|
||||
return emptyState;
|
||||
}
|
||||
@ -91,5 +96,5 @@ export const toDate = (data) => {
|
||||
};
|
||||
|
||||
export const formatNumber = (x) => {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
};
|
||||
|
@ -1,13 +1,11 @@
|
||||
import * as React from "react";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as System from "~/components/system";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as React from 'react';
|
||||
import * as Constants from '~/common/constants';
|
||||
import * as System from '~/components/system';
|
||||
import * as SVG from '~/common/svg';
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import Avatar from "~/components/core/Avatar";
|
||||
import Pill from "~/components/core/Pill";
|
||||
import Avatar from '~/components/core/Avatar';
|
||||
|
||||
const STYLES_CIRCLE = css`
|
||||
height: 32px;
|
||||
@ -115,118 +113,52 @@ const STYLES_INPUT = css`
|
||||
transition: 200ms ease all;
|
||||
|
||||
:focus {
|
||||
box-shadow: 0 1px 4px rgba(0, 71, 255, 0.3),
|
||||
inset 0 0 0 1px ${Constants.system.brand};
|
||||
box-shadow: 0 1px 4px rgba(0, 71, 255, 0.3), inset 0 0 0 1px ${Constants.system.brand};
|
||||
outline: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export default class ApplicationHeader extends React.Component {
|
||||
render() {
|
||||
const isBackDisabled =
|
||||
this.props.currentIndex === 0 || this.props.history.length < 2;
|
||||
const isBackDisabled = this.props.currentIndex === 0 || this.props.history.length < 2;
|
||||
|
||||
const isForwardDisabled =
|
||||
this.props.currentIndex === this.props.history.length - 1 ||
|
||||
this.props.history.length < 2;
|
||||
this.props.currentIndex === this.props.history.length - 1 || this.props.history.length < 2;
|
||||
|
||||
return (
|
||||
<header css={STYLES_APPLICATION_HEADER}>
|
||||
<div css={STYLES_LEFT}>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT_CUSTOM}
|
||||
style={{ marginRight: 16, marginLeft: 12 }}
|
||||
>
|
||||
<span css={STYLES_ICON_ELEMENT_CUSTOM} style={{ marginRight: 16, marginLeft: 12 }}>
|
||||
<SVG.Logo height="32px" />
|
||||
</span>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={
|
||||
isBackDisabled
|
||||
? { cursor: "not-allowed", color: Constants.system.border }
|
||||
: null
|
||||
}
|
||||
onClick={isBackDisabled ? () => {} : this.props.onBack}
|
||||
>
|
||||
<SVG.NavigationArrow
|
||||
height="16px"
|
||||
style={{ transform: `rotate(180deg)` }}
|
||||
/>
|
||||
style={isBackDisabled ? { cursor: 'not-allowed', color: Constants.system.border } : null}
|
||||
onClick={isBackDisabled ? () => {} : this.props.onBack}>
|
||||
<SVG.NavigationArrow height="16px" style={{ transform: `rotate(180deg)` }} />
|
||||
</span>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={
|
||||
isForwardDisabled
|
||||
? { cursor: "not-allowed", color: Constants.system.border }
|
||||
: null
|
||||
}
|
||||
onClick={isForwardDisabled ? () => {} : this.props.onForward}
|
||||
>
|
||||
style={isForwardDisabled ? { cursor: 'not-allowed', color: Constants.system.border } : null}
|
||||
onClick={isForwardDisabled ? () => {} : this.props.onForward}>
|
||||
<SVG.NavigationArrow height="16px" />
|
||||
</span>
|
||||
</div>
|
||||
<div css={STYLES_MIDDLE}>
|
||||
<input
|
||||
css={STYLES_INPUT}
|
||||
placeholder={`Type to search ${this.props.pageTitle}`}
|
||||
/>
|
||||
</div>
|
||||
<div css={STYLES_MIDDLE}></div>
|
||||
<div css={STYLES_RIGHT}>
|
||||
<System.StatUpload style={{ marginRight: 8 }}>
|
||||
{Strings.bytesToSize(this.props.viewer.upload_bandwidth)}
|
||||
</System.StatUpload>{" "}
|
||||
<System.StatDownload style={{ marginRight: 8 }}>
|
||||
{Strings.bytesToSize(this.props.viewer.download_bandwidth)}
|
||||
</System.StatDownload>
|
||||
<div
|
||||
css={STYLES_CIRCLE}
|
||||
onClick={() =>
|
||||
this.props.onAction({
|
||||
name: "Connection",
|
||||
type: "ACTION",
|
||||
value: "ACTION_TOGGLE_CONNECTION",
|
||||
})
|
||||
}
|
||||
>
|
||||
<SVG.PowerButton height="16px" />
|
||||
</div>
|
||||
<div
|
||||
css={STYLES_CIRCLE}
|
||||
style={{
|
||||
marginLeft: 12,
|
||||
}}
|
||||
onClick={() =>
|
||||
this.props.onAction({
|
||||
name: "Notifications",
|
||||
type: "SIDEBAR",
|
||||
value: "SIDEBAR_NOTIFICATIONS",
|
||||
})
|
||||
}
|
||||
>
|
||||
<SVG.Bell height="16px" />
|
||||
{this.props.viewer.notifications.length > 0 ? (
|
||||
<Pill
|
||||
style={{
|
||||
left: 20,
|
||||
top: `-4px`,
|
||||
}}
|
||||
>
|
||||
{this.props.viewer.notifications.length}
|
||||
</Pill>
|
||||
) : null}
|
||||
</div>
|
||||
<Avatar
|
||||
style={{ marginLeft: 12 }}
|
||||
onClick={() => {}}
|
||||
size={32}
|
||||
url={this.props.viewer.photoURL}
|
||||
popover={
|
||||
<System.PopoverNavigation
|
||||
style={{ right: 0, top: "48px" }}
|
||||
style={{ right: 0, top: '48px', cursor: 'pointer' }}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
onAction={this.props.onAction}
|
||||
navigation={[
|
||||
{ text: "Edit account", value: 13 },
|
||||
{ text: "Settings", value: 14 },
|
||||
{ text: 'Edit account', value: 13 },
|
||||
{ text: 'Settings', value: 14 },
|
||||
]}
|
||||
/>
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as React from 'react';
|
||||
import * as Constants from '~/common/constants';
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import Dismissible from "~/components/core/Dismissible";
|
||||
import Dismissible from '~/components/core/Dismissible';
|
||||
|
||||
const STYLES_AVATAR = css`
|
||||
display: inline-flex;
|
||||
@ -56,9 +56,8 @@ export default class AvatarEntity extends React.Component {
|
||||
height: `${this.props.size}px`,
|
||||
borderRadius: `${this.props.size}px`,
|
||||
backgroundImage: `url('${this.props.url}')`,
|
||||
cursor: this.props.onClick ? "pointer" : null,
|
||||
}}
|
||||
>
|
||||
cursor: this.props.onClick ? 'pointer' : this.props.style,
|
||||
}}>
|
||||
{this.state.visible ? this.props.popover : null}
|
||||
{this.props.online ? <span css={STYLES_AVATAR_ONLINE} /> : null}
|
||||
</Dismissible>
|
||||
|
@ -9,23 +9,36 @@ import { css } from '@emotion/react';
|
||||
const SELECT_MENU_OPTIONS = [
|
||||
{ value: '1', name: 'BLS' },
|
||||
{ value: '2', name: 'SECP256K1' },
|
||||
{ value: '3', name: 'MULTISIG' },
|
||||
// { value: '3', name: 'MULTISIG' },
|
||||
];
|
||||
|
||||
const SELECT_MENU_MAP = {
|
||||
'1': 'BLS',
|
||||
'2': 'SECP256K1',
|
||||
'3': 'MULTISIG',
|
||||
// '3': 'MULTISIG',
|
||||
};
|
||||
|
||||
const SELECT_MENU_SAVE_STRINGS = {
|
||||
'1': 'bls',
|
||||
'2': 'secp256k1',
|
||||
};
|
||||
|
||||
export default class SidebarCreateWalletAddress extends React.Component {
|
||||
state = {
|
||||
name: '',
|
||||
type: '1',
|
||||
default: false,
|
||||
};
|
||||
|
||||
_handleSubmit = () => {
|
||||
this.props.onSubmit({ name: this.state.name, type: 'CREATE_WALLET_ADDRESS' });
|
||||
const data = {
|
||||
name: this.state.name,
|
||||
wallet_type: SELECT_MENU_SAVE_STRINGS[this.state.type],
|
||||
makeDefault: this.state.default,
|
||||
type: 'CREATE_WALLET_ADDRESS',
|
||||
};
|
||||
|
||||
this.props.onSubmit(data);
|
||||
};
|
||||
|
||||
_handleCancel = () => {
|
||||
@ -60,6 +73,14 @@ export default class SidebarCreateWalletAddress extends React.Component {
|
||||
{SELECT_MENU_MAP[this.state.type]}
|
||||
</System.SelectMenuFull>
|
||||
|
||||
<System.CheckBox
|
||||
style={{ marginTop: 24 }}
|
||||
name="default"
|
||||
value={this.state.default}
|
||||
onChange={this._handleChange}>
|
||||
Make this wallet the default
|
||||
</System.CheckBox>
|
||||
|
||||
<System.ButtonPrimaryFull style={{ marginTop: 48 }} onClick={this._handleSubmit}>
|
||||
Create {this.state.name}
|
||||
</System.ButtonPrimaryFull>
|
||||
|
@ -1,19 +1,19 @@
|
||||
import * as React from "react";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/components/system/svg";
|
||||
import * as System from "~/components/system";
|
||||
import * as React from 'react';
|
||||
import * as Strings from '~/common/strings';
|
||||
import * as Constants from '~/common/constants';
|
||||
import * as SVG from '~/components/system/svg';
|
||||
import * as System from '~/components/system';
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
const STYLES_FOCUS = css`
|
||||
font-size: ${Constants.typescale.lvl1};
|
||||
font-family: "inter-medium";
|
||||
font-family: 'inter-medium';
|
||||
overflow-wrap: break-word;
|
||||
width: 100%;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -34,30 +34,27 @@ const STYLES_IMAGE_PREVIEW = css`
|
||||
`;
|
||||
|
||||
const SELECT_MENU_OPTIONS = [
|
||||
{ value: "1", name: "Anywhere" },
|
||||
{ value: "2", name: "China" },
|
||||
{ value: "3", name: "Russia" },
|
||||
{ value: "4", name: "USA" },
|
||||
{ value: '1', name: 'Anywhere' },
|
||||
{ value: '2', name: 'China' },
|
||||
{ value: '3', name: 'Russia' },
|
||||
{ value: '4', name: 'USA' },
|
||||
];
|
||||
|
||||
const SELECT_MENU_MAP = {
|
||||
"1": "Anywhere",
|
||||
"2": "China",
|
||||
"3": "Russia",
|
||||
"4": "USA",
|
||||
'1': 'Anywhere',
|
||||
'2': 'China',
|
||||
'3': 'Russia',
|
||||
'4': 'USA',
|
||||
};
|
||||
|
||||
export default class SidebarFileStorageDeal extends React.Component {
|
||||
state = {
|
||||
settings_deal_duration: 1,
|
||||
settings_replication_factor: 1,
|
||||
settings_country: "1",
|
||||
settings_miners: "t111, t112, t113",
|
||||
settings_confirmation: false,
|
||||
settings_deal_duration: this.props.viewer.settings_cold_default_duration,
|
||||
settings_replication_factor: this.props.viewer.settings_cold_default_replication_factor,
|
||||
};
|
||||
|
||||
_handleSubmit = () => {
|
||||
alert("TODO: Make a storage deal");
|
||||
alert('TODO: Make a storage deal');
|
||||
this.props.onSubmit({});
|
||||
};
|
||||
|
||||
@ -71,18 +68,20 @@ export default class SidebarFileStorageDeal extends React.Component {
|
||||
|
||||
render() {
|
||||
let addresses = {};
|
||||
let lastAddress;
|
||||
|
||||
this.props.viewer.addresses.forEach((a) => {
|
||||
addresses[a.value] = a;
|
||||
addresses[a.address] = a;
|
||||
lastAddress = a.address;
|
||||
});
|
||||
|
||||
const currentAddress = addresses[this.props.selected.address];
|
||||
const currentAddress = this.props.selected.address
|
||||
? addresses[this.props.selected.address]
|
||||
: addresses[lastAddress];
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<System.P style={{ fontFamily: "inter-semi-bold" }}>
|
||||
Upload a file to the network
|
||||
</System.P>
|
||||
<System.P style={{ fontFamily: 'inter-semi-bold' }}>Upload a file to the network</System.P>
|
||||
|
||||
<img src="/static/test-image-upload.jpg" css={STYLES_IMAGE_PREVIEW} />
|
||||
|
||||
@ -96,9 +95,7 @@ export default class SidebarFileStorageDeal extends React.Component {
|
||||
<div css={STYLES_SUBTEXT}>File size</div>
|
||||
</div>
|
||||
|
||||
<System.ButtonSecondaryFull style={{ marginTop: 24 }}>
|
||||
Change file
|
||||
</System.ButtonSecondaryFull>
|
||||
<System.ButtonSecondaryFull style={{ marginTop: 24 }}>Change file</System.ButtonSecondaryFull>
|
||||
|
||||
<System.Input
|
||||
containerStyle={{ marginTop: 48 }}
|
||||
@ -123,49 +120,16 @@ export default class SidebarFileStorageDeal extends React.Component {
|
||||
value={this.props.selected.address}
|
||||
category="address"
|
||||
onChange={this.props.onSelectedChange}
|
||||
options={this.props.viewer.addresses}
|
||||
>
|
||||
options={this.props.viewer.addresses}>
|
||||
{currentAddress.name}
|
||||
</System.SelectMenuFull>
|
||||
|
||||
<System.SelectMenuFull
|
||||
containerStyle={{ marginTop: 24 }}
|
||||
name="settings_country"
|
||||
label="Country"
|
||||
value={this.props.settings_country}
|
||||
category="miner location"
|
||||
onChange={this._handleChange}
|
||||
options={SELECT_MENU_OPTIONS}
|
||||
>
|
||||
{SELECT_MENU_MAP[this.state.settings_country]}
|
||||
</System.SelectMenuFull>
|
||||
|
||||
<System.Input
|
||||
containerStyle={{ marginTop: 24 }}
|
||||
label="Trusted miners"
|
||||
name="settings_miners"
|
||||
value={this.state.settings_miners}
|
||||
onChange={this._handleChange}
|
||||
/>
|
||||
|
||||
<System.CheckBox
|
||||
style={{ marginTop: 24 }}
|
||||
name="settings_confirmation"
|
||||
value={this.state.settings_confirmation}
|
||||
onChange={this._handleChange}
|
||||
>
|
||||
Please do not show this confirmation again.
|
||||
</System.CheckBox>
|
||||
|
||||
<div css={STYLES_ITEM}>
|
||||
<div css={STYLES_FOCUS}>2 FIL</div>
|
||||
<div css={STYLES_SUBTEXT}>Last order price</div>
|
||||
</div>
|
||||
|
||||
<System.ButtonPrimaryFull
|
||||
style={{ marginTop: 48 }}
|
||||
onClick={this._handleSubmit}
|
||||
>
|
||||
<System.ButtonPrimaryFull style={{ marginTop: 48 }} onClick={this._handleSubmit}>
|
||||
Make storage deal
|
||||
</System.ButtonPrimaryFull>
|
||||
</React.Fragment>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import * as Strings from '~/common/strings';
|
||||
import * as Constants from '~/common/constants';
|
||||
import * as SVG from '~/components/system/svg';
|
||||
import * as System from '~/components/system';
|
||||
|
||||
import { css } from '@emotion/react';
|
||||
@ -104,12 +103,12 @@ export default class SidebarWalletSendFunds extends React.Component {
|
||||
/>
|
||||
|
||||
<div css={STYLES_ITEM}>
|
||||
<div css={STYLES_FOCUS}>2 FIL</div>
|
||||
<div css={STYLES_FOCUS}>0 FIL</div>
|
||||
<div css={STYLES_SUBTEXT}>Transaction Fee</div>
|
||||
</div>
|
||||
|
||||
<div css={STYLES_ITEM}>
|
||||
<div css={STYLES_FOCUS}>2</div>
|
||||
<div css={STYLES_FOCUS}>{Strings.formatNumber(this.state.amount)}</div>
|
||||
<div css={STYLES_SUBTEXT}>Total Filecoin</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/components/system/svg";
|
||||
import * as OldSVG from "~/common/svg";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as SubSystem from "~/components/system/sub-system";
|
||||
import * as React from 'react';
|
||||
import * as Constants from '~/common/constants';
|
||||
import * as SVG from '~/components/system/svg';
|
||||
import * as OldSVG from '~/common/svg';
|
||||
import * as Strings from '~/common/strings';
|
||||
import * as SubSystem from '~/components/system/sub-system';
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
//
|
||||
//
|
||||
@ -30,7 +30,7 @@ import { css } from "@emotion/react";
|
||||
// UTILITY COMPONENTS
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
import TextareaAutoSize from "~/vendor/react-textarea-autosize";
|
||||
import TextareaAutoSize from '~/vendor/react-textarea-autosize';
|
||||
|
||||
//
|
||||
//
|
||||
@ -55,9 +55,9 @@ import TextareaAutoSize from "~/vendor/react-textarea-autosize";
|
||||
// VENDOR
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
import { Tooltip } from "react-tippy";
|
||||
import { LineChart } from "~/vendor/react-chartkick";
|
||||
import "chart.js";
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import { LineChart } from '~/vendor/react-chartkick';
|
||||
import 'chart.js';
|
||||
|
||||
//
|
||||
//
|
||||
@ -83,7 +83,7 @@ import "chart.js";
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const STYLES_CODE_TEXTAREA = css`
|
||||
font-family: "mono";
|
||||
font-family: 'mono';
|
||||
display: block;
|
||||
max-width: 480px;
|
||||
border-radius: 4px;
|
||||
@ -160,9 +160,7 @@ export class TooltipAnchor extends React.Component {
|
||||
{this.props.children ? (
|
||||
this.props.children
|
||||
) : (
|
||||
<SVG.Information
|
||||
height={this.props.height ? this.props.height : "24px"}
|
||||
/>
|
||||
<SVG.Information height={this.props.height ? this.props.height : '24px'} />
|
||||
)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
@ -198,8 +196,7 @@ const STYLES_POPOVER = css`
|
||||
width: 288px;
|
||||
border-radius: 4px;
|
||||
background-color: ${Constants.system.white};
|
||||
box-shadow: inset 0 0 0 1px ${Constants.system.border},
|
||||
0 1px 4px rgba(0, 0, 0, 0.07);
|
||||
box-shadow: inset 0 0 0 1px ${Constants.system.border}, 0 1px 4px rgba(0, 0, 0, 0.07);
|
||||
`;
|
||||
|
||||
const STYLES_POPOVER_ITEM = css`
|
||||
@ -223,7 +220,7 @@ const STYLES_POPOVER_ITEM = css`
|
||||
export class PopoverNavigation extends React.Component {
|
||||
static defaultProps = {
|
||||
onNavigateTo: () => {
|
||||
console.error("requires onNavigateTo");
|
||||
console.error('requires onNavigateTo');
|
||||
},
|
||||
};
|
||||
|
||||
@ -232,11 +229,7 @@ export class PopoverNavigation extends React.Component {
|
||||
<div css={STYLES_POPOVER} style={this.props.style}>
|
||||
{this.props.navigation.map((each) => {
|
||||
return (
|
||||
<div
|
||||
key={each.value}
|
||||
css={STYLES_POPOVER_ITEM}
|
||||
onClick={() => this.props.onNavigateTo({ id: each.value })}
|
||||
>
|
||||
<div key={each.value} css={STYLES_POPOVER_ITEM} onClick={() => this.props.onNavigateTo({ id: each.value })}>
|
||||
{each.text}
|
||||
</div>
|
||||
);
|
||||
@ -298,7 +291,7 @@ const STYLES_STAT_CARD_VALUE_GROUP = css`
|
||||
`;
|
||||
|
||||
const STYLES_STAT_CARD_VALUE = css`
|
||||
font-family: "inter-medium";
|
||||
font-family: 'inter-medium';
|
||||
font-size: ${Constants.typescale.lvl3};
|
||||
color: ${Constants.system.brand};
|
||||
display: block;
|
||||
@ -306,7 +299,7 @@ const STYLES_STAT_CARD_VALUE = css`
|
||||
|
||||
const STYLES_STAT_CARD_DENOMINATION = css`
|
||||
display: block;
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.1px;
|
||||
margin: 4px 0 16px 0;
|
||||
@ -319,14 +312,12 @@ export const StatCard = (props) => {
|
||||
<div css={STYLES_STAT_CARD}>
|
||||
<div css={STYLES_STAT_CARD_TOP}>
|
||||
<div css={STYLES_STAT_CARD_VALUE_GROUP}>
|
||||
<span css={STYLES_STAT_CARD_VALUE}>
|
||||
{Strings.formatNumber(props.value)}
|
||||
</span>{" "}
|
||||
<span css={STYLES_STAT_CARD_VALUE}>{Strings.formatNumber(props.value)}</span>{' '}
|
||||
<span css={STYLES_STAT_CARD_DENOMINATION}>{props.denomination}</span>
|
||||
<LineChart
|
||||
data={props.data}
|
||||
library={{
|
||||
backgroundColor: "transparent",
|
||||
backgroundColor: 'transparent',
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
@ -372,14 +363,14 @@ export const StatCard = (props) => {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const TABLE_COLUMN_WIDTH_DEFAULTS = {
|
||||
1: "100%",
|
||||
2: "50%",
|
||||
3: "33.333%",
|
||||
4: "25%",
|
||||
5: "20%",
|
||||
6: "16.666%",
|
||||
7: "14.28%",
|
||||
8: "12.5%",
|
||||
1: '100%',
|
||||
2: '50%',
|
||||
3: '33.333%',
|
||||
4: '25%',
|
||||
5: '20%',
|
||||
6: '16.666%',
|
||||
7: '14.28%',
|
||||
8: '12.5%',
|
||||
};
|
||||
|
||||
const STYLES_TABLE_PLACEHOLDER = css`
|
||||
@ -426,7 +417,7 @@ const STYLES_TABLE_SELECTED_ROW = css`
|
||||
`;
|
||||
|
||||
const STYLES_TABLE_TOP_ROW = css`
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
width: 100%;
|
||||
padding: 0 8px 0 8px;
|
||||
border-bottom: 1px solid ${Constants.system.gray};
|
||||
@ -436,8 +427,8 @@ const STYLES_TABLE_TOP_ROW = css`
|
||||
|
||||
export class Table extends React.Component {
|
||||
static defaultProps = {
|
||||
onNavigateTo: () => console.log("No navigation function set"),
|
||||
onAction: () => console.log("No action function set"),
|
||||
onNavigateTo: () => console.log('No navigation function set'),
|
||||
onAction: () => console.log('No action function set'),
|
||||
};
|
||||
|
||||
// NOTE(jim): Local state for local filtering.
|
||||
@ -467,7 +458,7 @@ export class Table extends React.Component {
|
||||
ac[data.columns[x].key] = {
|
||||
...data.columns[x],
|
||||
index: x,
|
||||
color: x % 2 !== 0 ? "rgba(0, 0, 0, 0.01)" : null,
|
||||
color: x % 2 !== 0 ? 'rgba(0, 0, 0, 0.01)' : null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -477,15 +468,11 @@ export class Table extends React.Component {
|
||||
<React.Fragment>
|
||||
<div css={STYLES_TABLE_TOP_ROW}>
|
||||
{data.columns.map((c, cIndex) => {
|
||||
const text = c.hideLabel
|
||||
? ""
|
||||
: Strings.isEmpty(c.name)
|
||||
? c.key
|
||||
: c.name;
|
||||
const text = c.hideLabel ? '' : Strings.isEmpty(c.name) ? c.key : c.name;
|
||||
let localWidth = c.width ? c.width : width;
|
||||
let flexShrink = c.width && c.width !== "100%" ? "0" : null;
|
||||
let flexShrink = c.width && c.width !== '100%' ? '0' : null;
|
||||
if (cIndex === 0 && !c.width) {
|
||||
localWidth = "100%";
|
||||
localWidth = '100%';
|
||||
}
|
||||
|
||||
return (
|
||||
@ -497,13 +484,11 @@ export class Table extends React.Component {
|
||||
backgroundColor: ac[c.key].color,
|
||||
flexShrink,
|
||||
}}
|
||||
tooltip={c.tooltip}
|
||||
>
|
||||
tooltip={c.tooltip}>
|
||||
{text}
|
||||
</SubSystem.TableColumn>
|
||||
);
|
||||
})}
|
||||
<div css={STYLES_TABLE_EXPAND_SECTION} />
|
||||
</div>
|
||||
|
||||
{data.rows.map((r, i) => {
|
||||
@ -517,10 +502,9 @@ export class Table extends React.Component {
|
||||
const text = r[each];
|
||||
|
||||
let localWidth = field.width ? field.width : width;
|
||||
let flexShrink =
|
||||
field.width && field.width !== "100%" ? "0" : null;
|
||||
let flexShrink = field.width && field.width !== '100%' ? '0' : null;
|
||||
if (cIndex === 0 && !field.width) {
|
||||
localWidth = "100%";
|
||||
localWidth = '100%';
|
||||
}
|
||||
|
||||
return (
|
||||
@ -531,8 +515,7 @@ export class Table extends React.Component {
|
||||
backgroundColor: field.color,
|
||||
flexShrink,
|
||||
}}
|
||||
copyable={field.copyable}
|
||||
>
|
||||
copyable={field.copyable}>
|
||||
<SubSystem.TableContent
|
||||
data={r}
|
||||
text={text}
|
||||
@ -544,22 +527,10 @@ export class Table extends React.Component {
|
||||
</SubSystem.TableColumn>
|
||||
);
|
||||
})}
|
||||
<div
|
||||
css={STYLES_TABLE_EXPAND_SECTION}
|
||||
onClick={() => this._handleChange(r.id)}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<SVG.Plus
|
||||
height="16px"
|
||||
style={{
|
||||
transform: selected ? `rotate(45deg)` : null,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{selected ? (
|
||||
<div css={STYLES_TABLE_SELECTED_ROW}>
|
||||
<span css={STYLES_TABLE_PLACEHOLDER}>Placeholder</span>
|
||||
<span css={STYLES_TABLE_PLACEHOLDER}>{r.children}</span>
|
||||
</div>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
@ -644,6 +615,10 @@ const STYLES_BUTTON_PRIMARY = css`
|
||||
`;
|
||||
|
||||
export const ButtonPrimary = (props) => {
|
||||
if (props.type === 'label') {
|
||||
return <label css={STYLES_BUTTON_PRIMARY} {...props} />;
|
||||
}
|
||||
|
||||
return <button css={STYLES_BUTTON_PRIMARY} {...props} />;
|
||||
};
|
||||
|
||||
@ -808,12 +783,8 @@ export class Toggle extends React.Component {
|
||||
onClick={this._handleChange}
|
||||
style={{
|
||||
backgroundColor: this.props.active ? Constants.system.brand : null,
|
||||
}}
|
||||
>
|
||||
<figure
|
||||
css={STYLES_DIAL}
|
||||
style={{ transform: this.props.active ? `translateX(40px)` : null }}
|
||||
/>
|
||||
}}>
|
||||
<figure css={STYLES_DIAL} style={{ transform: this.props.active ? `translateX(40px)` : null }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -903,7 +874,7 @@ const STYLES_RADIO_LABEL = css`
|
||||
overflow-wrap: break-word;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -924,10 +895,7 @@ export class RadioGroup extends React.Component {
|
||||
return (
|
||||
<label css={STYLES_RADIO} key={`radio-${radio.value}`}>
|
||||
<span css={STYLES_RADIO_CUSTOM}>
|
||||
<span
|
||||
css={STYLES_RADIO_CUSTOM_SELECTED}
|
||||
style={{ opacity: checked ? 1 : 0 }}
|
||||
/>
|
||||
<span css={STYLES_RADIO_CUSTOM_SELECTED} style={{ opacity: checked ? 1 : 0 }} />
|
||||
</span>
|
||||
<input
|
||||
css={STYLES_RADIO_INPUT}
|
||||
@ -935,7 +903,7 @@ export class RadioGroup extends React.Component {
|
||||
value={radio.value}
|
||||
checked={checked}
|
||||
onChange={() => this._handleChange(radio.value)}
|
||||
/>{" "}
|
||||
/>{' '}
|
||||
<span css={STYLES_RADIO_LABEL}>{radio.label}</span>
|
||||
</label>
|
||||
);
|
||||
@ -1008,7 +976,7 @@ const STYLES_CHECKBOX_LABEL = css`
|
||||
overflow-wrap: break-word;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -1023,9 +991,7 @@ export class CheckBox extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<label css={STYLES_CHECKBOX} style={this.props.style}>
|
||||
<figure css={STYLES_CHECKBOX_FIGURE}>
|
||||
{this.props.value ? <SVG.CheckBox height="20px" /> : null}
|
||||
</figure>
|
||||
<figure css={STYLES_CHECKBOX_FIGURE}>{this.props.value ? <SVG.CheckBox height="20px" /> : null}</figure>
|
||||
<input
|
||||
css={STYLES_CHECKBOX_INPUT}
|
||||
name={this.props.name}
|
||||
@ -1066,15 +1032,14 @@ const STYLES_CARD_TAB_GROUP = css`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
box-shadow: 0 -1px 0 0 ${Constants.system.border},
|
||||
0 1px 0 0 ${Constants.system.border};
|
||||
box-shadow: 0 -1px 0 0 ${Constants.system.border}, 0 1px 0 0 ${Constants.system.border};
|
||||
`;
|
||||
|
||||
const STYLES_CARD_TAB_GROUP_TAB = css`
|
||||
background: #fdfdfd;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
font-size: 14px;
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
height: 48px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@ -1112,14 +1077,11 @@ export class CardTabGroup extends React.Component {
|
||||
style={{
|
||||
color: selected ? Constants.system.brand : null,
|
||||
backgroundColor: selected ? Constants.system.white : null,
|
||||
borderBottom: selected
|
||||
? `2px solid ${Constants.system.brand}`
|
||||
: null,
|
||||
borderBottom: selected ? `2px solid ${Constants.system.brand}` : null,
|
||||
width: TAB_GROUP_SIZE_MAP[this.props.options.length],
|
||||
cursor: !selected ? "pointer" : null,
|
||||
cursor: !selected ? 'pointer' : null,
|
||||
}}
|
||||
onClick={() => this._handleChange(tab.value)}
|
||||
>
|
||||
onClick={() => this._handleChange(tab.value)}>
|
||||
{tab.label}
|
||||
</div>
|
||||
);
|
||||
@ -1167,7 +1129,7 @@ const STYLES_TAB_GROUP_TAB = css`
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
transition: 200ms ease all;
|
||||
user-select: none;
|
||||
|
||||
@ -1177,10 +1139,10 @@ const STYLES_TAB_GROUP_TAB = css`
|
||||
`;
|
||||
|
||||
const TAB_GROUP_SIZE_MAP = {
|
||||
1: "100%",
|
||||
2: "50%",
|
||||
3: "33.33%",
|
||||
4: "25%",
|
||||
1: '100%',
|
||||
2: '50%',
|
||||
3: '33.33%',
|
||||
4: '25%',
|
||||
};
|
||||
|
||||
export class TabGroup extends React.Component {
|
||||
@ -1203,11 +1165,10 @@ export class TabGroup extends React.Component {
|
||||
style={{
|
||||
backgroundColor: selected ? Constants.system.white : null,
|
||||
width: TAB_GROUP_SIZE_MAP[this.props.options.length],
|
||||
cursor: !selected ? "pointer" : null,
|
||||
cursor: !selected ? 'pointer' : null,
|
||||
borderBottom: !selected ? `1px solid #D7D7D7` : null,
|
||||
}}
|
||||
onClick={() => this._handleChange(tab.value)}
|
||||
>
|
||||
onClick={() => this._handleChange(tab.value)}>
|
||||
{tab.label}
|
||||
</div>
|
||||
);
|
||||
@ -1241,7 +1202,7 @@ export class TabGroup extends React.Component {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const STYLES_DESCRIPTION_GROUP_LABEL = css`
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-size: 14px;
|
||||
padding: 0 0 0 0;
|
||||
margin-bottom: 8px;
|
||||
@ -1258,20 +1219,12 @@ export const DescriptionGroup = (props) => {
|
||||
<div style={props.style}>
|
||||
{!Strings.isEmpty(props.label) ? (
|
||||
<div css={STYLES_DESCRIPTION_GROUP_LABEL}>
|
||||
{props.label}{" "}
|
||||
{props.tooltip ? (
|
||||
<TooltipAnchor
|
||||
tooltip={props.tooltip}
|
||||
height="14px"
|
||||
style={{ paddingTop: 16 }}
|
||||
/>
|
||||
) : null}
|
||||
{props.label}{' '}
|
||||
{props.tooltip ? <TooltipAnchor tooltip={props.tooltip} height="14px" style={{ paddingTop: 16 }} /> : null}
|
||||
</div>
|
||||
) : null}
|
||||
{!Strings.isEmpty(props.description) ? (
|
||||
<div css={STYLES_DESCRIPTION_GROUP_DESCRIPTION}>
|
||||
{props.description}
|
||||
</div>
|
||||
<div css={STYLES_DESCRIPTION_GROUP_DESCRIPTION}>{props.description}</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
@ -1326,14 +1279,12 @@ const INPUT_STYLES = css`
|
||||
const STYLES_INPUT = css`
|
||||
${INPUT_STYLES}
|
||||
padding: 0 24px 0 24px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15),
|
||||
inset 0 0 0 1px ${Constants.system.darkGray};
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15), inset 0 0 0 1px ${Constants.system.darkGray};
|
||||
|
||||
:focus {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.07),
|
||||
inset 0 0 0 2px ${Constants.system.brand};
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.07), inset 0 0 0 2px ${Constants.system.brand};
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
@ -1377,7 +1328,7 @@ export class Input extends React.Component {
|
||||
|
||||
_handleCopy = (e) => {
|
||||
this._input.select();
|
||||
document.execCommand("copy");
|
||||
document.execCommand('copy');
|
||||
};
|
||||
|
||||
_handleKeyUp = (e) => {
|
||||
@ -1390,10 +1341,7 @@ export class Input extends React.Component {
|
||||
};
|
||||
|
||||
_handleChange = (e) => {
|
||||
if (
|
||||
!Strings.isEmpty(this.props.pattern) &&
|
||||
!Strings.isEmpty(e.target.value)
|
||||
) {
|
||||
if (!Strings.isEmpty(this.props.pattern) && !Strings.isEmpty(e.target.value)) {
|
||||
const TestRegex = new RegExp(this.props.pattern);
|
||||
if (!TestRegex.test(e.target.value)) {
|
||||
e.preventDefault();
|
||||
@ -1414,11 +1362,7 @@ export class Input extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div css={STYLES_INPUT_CONTAINER} style={this.props.containerStyle}>
|
||||
<DescriptionGroup
|
||||
tooltip={this.props.tooltip}
|
||||
label={this.props.label}
|
||||
description={this.props.description}
|
||||
/>
|
||||
<DescriptionGroup tooltip={this.props.tooltip} label={this.props.label} description={this.props.description} />
|
||||
<input
|
||||
ref={(c) => {
|
||||
this._input = c;
|
||||
@ -1435,18 +1379,12 @@ export class Input extends React.Component {
|
||||
style={{
|
||||
...this.props.style,
|
||||
boxShadow: this.props.validation
|
||||
? `0 1px 4px rgba(0, 0, 0, 0.07), inset 0 0 0 2px ${
|
||||
INPUT_COLOR_MAP[this.props.validation]
|
||||
}`
|
||||
? `0 1px 4px rgba(0, 0, 0, 0.07), inset 0 0 0 2px ${INPUT_COLOR_MAP[this.props.validation]}`
|
||||
: null,
|
||||
}}
|
||||
/>
|
||||
{this.props.copyable ? (
|
||||
<SVG.CopyAndPaste
|
||||
height="16px"
|
||||
css={STYLES_COPY_AND_PASTE}
|
||||
onClick={this._handleCopy}
|
||||
/>
|
||||
<SVG.CopyAndPaste height="16px" css={STYLES_COPY_AND_PASTE} onClick={this._handleCopy} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
@ -1494,8 +1432,7 @@ const STYLES_TEXTAREA = css`
|
||||
box-sizing: border-box;
|
||||
transition: 200ms ease all;
|
||||
padding: 16px 24px 16px 24px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15),
|
||||
inset 0 0 0 1px ${Constants.system.darkGray};
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15), inset 0 0 0 1px ${Constants.system.darkGray};
|
||||
`;
|
||||
|
||||
export class Textarea extends React.Component {
|
||||
@ -1591,10 +1528,7 @@ export const SelectMenu = (props) => {
|
||||
|
||||
<div css={props.className ? props.className : STYLES_SELECT_MENU}>
|
||||
<label css={STYLES_SELECT_MENU_LABEL} htmlFor={`id-${props.name}`}>
|
||||
{props.children}{" "}
|
||||
{props.category ? (
|
||||
<span css={STYLES_SELECT_MENU_CATEGORY}>{props.category}</span>
|
||||
) : null}
|
||||
{props.children} {props.category ? <span css={STYLES_SELECT_MENU_CATEGORY}>{props.category}</span> : null}
|
||||
<SVG.ChevronDown height="16px" css={STYLES_SELECT_MENU_CHEVRON} />
|
||||
</label>
|
||||
<select
|
||||
@ -1602,8 +1536,7 @@ export const SelectMenu = (props) => {
|
||||
value={props.value}
|
||||
onChange={props.onChange}
|
||||
name={props.name}
|
||||
id={`id-${props.name}`}
|
||||
>
|
||||
id={`id-${props.name}`}>
|
||||
{props.options.map((each) => {
|
||||
return (
|
||||
<option value={each.value} key={each.value}>
|
||||
@ -1617,9 +1550,7 @@ export const SelectMenu = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const SelectMenuFull = (props) => (
|
||||
<SelectMenu {...props} css={STYLES_SELECT_MENU_FULL} />
|
||||
);
|
||||
export const SelectMenuFull = (props) => <SelectMenu {...props} css={STYLES_SELECT_MENU_FULL} />;
|
||||
|
||||
//
|
||||
//
|
||||
@ -1647,11 +1578,11 @@ export const SelectMenuFull = (props) => (
|
||||
const STYLES_H1 = css`
|
||||
font-size: ${Constants.typescale.lvl4};
|
||||
line-height: 1.1;
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -1663,11 +1594,11 @@ export const H1 = (props) => {
|
||||
const STYLES_H2 = css`
|
||||
font-size: ${Constants.typescale.lvl3};
|
||||
line-height: 1.1;
|
||||
font-family: "inter-medium";
|
||||
font-family: 'inter-medium';
|
||||
font-weight: 400;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -1681,7 +1612,7 @@ const STYLES_P = css`
|
||||
line-height: 1.5;
|
||||
|
||||
strong {
|
||||
font-family: "inter-semi-bold";
|
||||
font-family: 'inter-semi-bold';
|
||||
font-weight: 400;
|
||||
}
|
||||
`;
|
||||
@ -1716,7 +1647,7 @@ export const P = (props) => {
|
||||
const STYLES_BANDWIDTH = css`
|
||||
padding: 8px 8px 8px 8px;
|
||||
display: inline-flex;
|
||||
font-family: "mono";
|
||||
font-family: 'mono';
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.2px;
|
||||
align-items: center;
|
||||
@ -1726,8 +1657,7 @@ const STYLES_BANDWIDTH = css`
|
||||
export const StatUpload = (props) => {
|
||||
return (
|
||||
<div css={STYLES_BANDWIDTH} style={props.style}>
|
||||
<SVG.BandwidthUp height="16px" style={{ marginRight: 8 }} />{" "}
|
||||
{props.children}
|
||||
<SVG.BandwidthUp height="16px" style={{ marginRight: 8 }} /> {props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -1735,8 +1665,7 @@ export const StatUpload = (props) => {
|
||||
export const StatDownload = (props) => {
|
||||
return (
|
||||
<div css={STYLES_BANDWIDTH} style={props.style}>
|
||||
<SVG.BandwidthDown height="16px" style={{ marginRight: 8 }} />{" "}
|
||||
{props.children}
|
||||
<SVG.BandwidthDown height="16px" style={{ marginRight: 8 }} /> {props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -15,7 +15,7 @@
|
||||
"@emotion/css": "11.0.0-next.12",
|
||||
"@emotion/react": "11.0.0-next.12",
|
||||
"@emotion/server": "11.0.0-next.12",
|
||||
"@textile/powergate-client": "0.1.0-beta.6",
|
||||
"@textile/powergate-client": "0.1.0-beta.7",
|
||||
"babel-plugin-module-resolver": "^4.0.0",
|
||||
"body-parser": "^1.19.0",
|
||||
"chart.js": "^2.9.3",
|
||||
@ -23,6 +23,7 @@
|
||||
"compression": "^1.7.4",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"formidable": "^1.2.2",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"next": "^9.4.0",
|
||||
"react": "^16.12.0",
|
||||
|
@ -62,9 +62,15 @@ const getCurrentNavigationStateById = (navigation, targetId) => {
|
||||
return { target, activeIds };
|
||||
};
|
||||
|
||||
export const getServerSideProps = (context) => {
|
||||
export const getServerSideProps = async (context) => {
|
||||
if (context.query && context.query.production) {
|
||||
return { production: true };
|
||||
}
|
||||
|
||||
const data = await Actions.rehydrateViewer();
|
||||
|
||||
return {
|
||||
props: { ...context.query },
|
||||
props: { ...data.data },
|
||||
};
|
||||
};
|
||||
|
||||
@ -74,7 +80,7 @@ export default class IndexPage extends React.Component {
|
||||
currentIndex: 0,
|
||||
data: null,
|
||||
selected: {
|
||||
address: '1',
|
||||
address: null,
|
||||
},
|
||||
viewer: this.props.production ? Fixtures.getInitialState() : State.getInitialState(this.props),
|
||||
sidebar: null,
|
||||
@ -85,6 +91,11 @@ export default class IndexPage extends React.Component {
|
||||
console.log(this.props);
|
||||
}
|
||||
|
||||
rehydrate = async () => {
|
||||
const viewer = await Actions.rehydrateViewer();
|
||||
this.setState({ viewer: { ...State.getInitialState(viewer.data) } });
|
||||
};
|
||||
|
||||
_handleSubmit = async (data) => {
|
||||
if (this.props.production) {
|
||||
alert('TODO');
|
||||
@ -92,9 +103,13 @@ export default class IndexPage extends React.Component {
|
||||
}
|
||||
|
||||
if (data.type === 'CREATE_WALLET_ADDRESS') {
|
||||
const response = await Actions.createWalletAddress({ name: data.name });
|
||||
const viewer = await Actions.rehydrateViewer();
|
||||
this.setState({ viewer });
|
||||
const address = await Actions.createWalletAddress({
|
||||
name: data.name,
|
||||
type: data.wallet_type,
|
||||
makeDefault: data.makeDefault,
|
||||
});
|
||||
|
||||
await this.rehydrate();
|
||||
}
|
||||
|
||||
if (data.type === 'SEND_WALLET_ADDRESS_FILECOIN') {
|
||||
@ -104,8 +119,7 @@ export default class IndexPage extends React.Component {
|
||||
amount: data.amount,
|
||||
});
|
||||
|
||||
const viewer = await Actions.rehydrateViewer();
|
||||
this.setState({ viewer });
|
||||
await this.rehydrate();
|
||||
}
|
||||
|
||||
this._handleDismissSidebar();
|
||||
@ -272,6 +286,7 @@ export default class IndexPage extends React.Component {
|
||||
);
|
||||
|
||||
const scene = React.cloneElement(this.scenes[current.target.decorator], {
|
||||
rehydrate: this.rehydrate,
|
||||
viewer: this.state.viewer,
|
||||
selected: this.state.selected,
|
||||
data: current.target,
|
||||
|
BIN
public/static/system/avatar.png
Normal file
BIN
public/static/system/avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 165 KiB |
@ -1,16 +1,50 @@
|
||||
import * as React from "react";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as Fixtures from "~/common/fixtures";
|
||||
import * as System from "~/components/system";
|
||||
import * as React from 'react';
|
||||
import * as System from '~/components/system';
|
||||
import * as Actions from '~/common/actions';
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import Section from "~/components/core/Section";
|
||||
import ScenePage from "~/components/core/ScenePage";
|
||||
import Avatar from "~/components/core/Avatar";
|
||||
import ScenePage from '~/components/core/ScenePage';
|
||||
import Avatar from '~/components/core/Avatar';
|
||||
|
||||
const STYLES_FILE_HIDDEN = css`
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
position: fixed;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
`;
|
||||
|
||||
export default class SceneEditAccount extends React.Component {
|
||||
_handleUpload = async (e) => {
|
||||
e.persist();
|
||||
let file = e.target.files[0];
|
||||
|
||||
if (!file) {
|
||||
alert('Something went wrong');
|
||||
}
|
||||
|
||||
let data = new FormData();
|
||||
data.append('image', file);
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: data,
|
||||
};
|
||||
|
||||
const response = await fetch(`/_/upload/avatar`, options);
|
||||
const json = await response.json();
|
||||
|
||||
if (json && json.success) {
|
||||
console.log('reload');
|
||||
}
|
||||
};
|
||||
|
||||
_handleChange = (e) => {
|
||||
this.props.onViewerChange(e);
|
||||
};
|
||||
@ -26,17 +60,13 @@ export default class SceneEditAccount extends React.Component {
|
||||
description="This image will appear in various lists."
|
||||
/>
|
||||
|
||||
<Avatar
|
||||
style={{ marginTop: 24 }}
|
||||
size={256}
|
||||
url={this.props.viewer.photoURL}
|
||||
/>
|
||||
<Avatar style={{ marginTop: 24 }} size={256} url={this.props.viewer.photoURL} />
|
||||
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<System.ButtonPrimary style={{ margin: "0 16px 16px 0" }}>
|
||||
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
|
||||
<System.ButtonPrimary style={{ margin: '0 16px 16px 0' }} type="label" for="file">
|
||||
Upload
|
||||
</System.ButtonPrimary>
|
||||
<System.ButtonSecondary>Delete</System.ButtonSecondary>
|
||||
</div>
|
||||
|
||||
<System.Input
|
||||
@ -48,31 +78,6 @@ export default class SceneEditAccount extends React.Component {
|
||||
placeholder="Name"
|
||||
onChange={this._handleChange}
|
||||
/>
|
||||
|
||||
<System.DescriptionGroup
|
||||
style={{ marginTop: 48 }}
|
||||
label="Account secret configuration"
|
||||
description="Manage your JSON config for your peer id, private key, and secret."
|
||||
tooltip="If you make a mistake here, just click reset and you will have a new key."
|
||||
/>
|
||||
|
||||
<System.CodeTextarea
|
||||
value={this.props.viewer.config}
|
||||
onChange={this._handleChange}
|
||||
name="config"
|
||||
/>
|
||||
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<System.ButtonSecondary style={{ margin: "0 16px 16px 0" }}>
|
||||
Hide
|
||||
</System.ButtonSecondary>
|
||||
<System.ButtonSecondary style={{ margin: "0 16px 16px 0" }}>
|
||||
Reset
|
||||
</System.ButtonSecondary>
|
||||
<System.ButtonSecondary style={{ margin: "0 16px 16px 0" }}>
|
||||
Export
|
||||
</System.ButtonSecondary>
|
||||
</div>
|
||||
</ScenePage>
|
||||
);
|
||||
}
|
||||
|
@ -54,132 +54,6 @@ export default class SceneHome extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ScenePage>
|
||||
<GLRenderer width={1200} height={480} />
|
||||
|
||||
<div css={STYLES_ROW}>
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 14],
|
||||
['2017-20-01 00:00:00 UTC', 16],
|
||||
['2017-24-01 00:00:00 UTC', 2],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="GB">
|
||||
Total data stored
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 65],
|
||||
['2017-05-01 00:00:00 UTC', 12],
|
||||
['2017-20-01 00:00:00 UTC', 2],
|
||||
['2017-24-01 00:00:00 UTC', 20],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="GB">
|
||||
Total data retrieved
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 12],
|
||||
['2017-20-01 00:00:00 UTC', 16],
|
||||
['2017-24-01 00:00:00 UTC', 33],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="Deals">
|
||||
Total deals
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 22],
|
||||
['2017-20-01 00:00:00 UTC', 44],
|
||||
['2017-24-01 00:00:00 UTC', 20],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="FIL">
|
||||
Wallet Balance
|
||||
</System.StatCard>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div css={STYLES_ROW}>
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 12],
|
||||
['2017-20-01 00:00:00 UTC', 12],
|
||||
['2017-24-01 00:00:00 UTC', 20],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="FIL/GB/Month">
|
||||
Your average storage price
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 23],
|
||||
['2017-20-01 00:00:00 UTC', 16],
|
||||
['2017-24-01 00:00:00 UTC', 20],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="FIL/GB">
|
||||
Your average retrieval price
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 7],
|
||||
['2017-05-01 00:00:00 UTC', 12],
|
||||
['2017-20-01 00:00:00 UTC', 16],
|
||||
['2017-24-01 00:00:00 UTC', 23],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="FIL/GB/Month">
|
||||
Average storage market price
|
||||
</System.StatCard>
|
||||
</span>
|
||||
|
||||
<span css={STYLES_COLUMN}>
|
||||
<System.StatCard
|
||||
data={[
|
||||
['2017-01-01 00:00:00 UTC', 47],
|
||||
['2017-05-01 00:00:00 UTC', 42],
|
||||
['2017-20-01 00:00:00 UTC', 46],
|
||||
['2017-24-01 00:00:00 UTC', 40],
|
||||
[new Date(), 24],
|
||||
]}
|
||||
value={1000}
|
||||
denomination="FIL/GB">
|
||||
Average market retrieval price
|
||||
</System.StatCard>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Section
|
||||
onAction={this.props.onAction}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
@ -190,6 +64,11 @@ export default class SceneHome extends React.Component {
|
||||
type: 'NAVIGATE',
|
||||
value: 'folder-root',
|
||||
},
|
||||
{
|
||||
name: 'Store file on network',
|
||||
type: 'SIDEBAR',
|
||||
value: 'SIDEBAR_FILE_STORAGE_DEAL',
|
||||
},
|
||||
]}>
|
||||
<System.Table
|
||||
data={{
|
||||
@ -203,7 +82,7 @@ export default class SceneHome extends React.Component {
|
||||
},
|
||||
{ key: 'remaining', name: 'Remaining time', width: '180px' },
|
||||
],
|
||||
rows: Data.EXAMPLE_FILES.slice(0, 4),
|
||||
rows: [],
|
||||
}}
|
||||
selectedRowId={this.state.data}
|
||||
onChange={this._handleChange}
|
||||
@ -217,18 +96,22 @@ export default class SceneHome extends React.Component {
|
||||
<Section
|
||||
onAction={this.props.onAction}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
title="Recent transactions"
|
||||
title="Wallet addresses"
|
||||
buttons={[
|
||||
{
|
||||
name: 'View wallet',
|
||||
name: 'View all',
|
||||
type: 'NAVIGATE',
|
||||
value: 2,
|
||||
},
|
||||
]}>
|
||||
<System.Table
|
||||
data={{
|
||||
columns: SchemaTable.Transactions,
|
||||
rows: this.props.viewer.addresses[0].transactions,
|
||||
columns: [
|
||||
{ key: 'address', name: 'Address' },
|
||||
{ key: 'balance', name: 'Filecoin', width: '228px' },
|
||||
{ key: 'type', name: 'Type' },
|
||||
],
|
||||
rows: this.props.viewer.addresses,
|
||||
}}
|
||||
selectedRowId={this.state.transaction}
|
||||
onChange={this._handleChange}
|
||||
|
@ -1,26 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import * as Strings from '~/common/strings';
|
||||
import * as Constants from '~/common/constants';
|
||||
import * as Fixtures from '~/common/fixtures';
|
||||
import * as Actions from '~/common/actions';
|
||||
import * as System from '~/components/system';
|
||||
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import Section from '~/components/core/Section';
|
||||
import ScenePage from '~/components/core/ScenePage';
|
||||
|
||||
const SELECT_MENU_OPTIONS = [
|
||||
{ value: '1', name: 'China' },
|
||||
{ value: '2', name: 'United States' },
|
||||
{ value: '3', name: 'Russia' },
|
||||
];
|
||||
|
||||
const SELECT_MENU_MAP = {
|
||||
'1': 'China',
|
||||
'2': 'United States',
|
||||
'3': 'Russia',
|
||||
};
|
||||
|
||||
const STYLES_GROUP = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -45,8 +30,47 @@ const STYLES_RIGHT = css`
|
||||
`;
|
||||
|
||||
export default class SceneSettings extends React.Component {
|
||||
_deferredSave = null;
|
||||
|
||||
_handleSave = async () => {
|
||||
const response = await Actions.setDefaultConfig({
|
||||
config: {
|
||||
hot: {
|
||||
enabled: this.props.viewer.settings_cold_enabled,
|
||||
allowUnfreeze: this.props.viewer.settings_hot_allow_unfreeze,
|
||||
ipfs: {
|
||||
addTimeout: this.props.viewer.settings_hot_ipfs_add_timeout,
|
||||
},
|
||||
},
|
||||
cold: {
|
||||
enabled: this.props.viewer.settings_cold_enabled,
|
||||
filecoin: {
|
||||
addr: this.props.viewer.settings_cold_default_address,
|
||||
dealDuration: this.props.viewer.settings_cold_default_duration,
|
||||
repFactor: this.props.viewer.settings_cold_default_replication_factor,
|
||||
excludedMinersList: this.props.viewer.settings_cold_default_excluded_miners,
|
||||
trustedMinersList: this.props.viewer.settings_cold_default_trusted_miners,
|
||||
maxPrice: this.props.viewer.settings_cold_default_max_price,
|
||||
renew: {
|
||||
enabled: this.props.viewer.settings_cold_default_auto_renew,
|
||||
threshold: this.props.viewer.settings_cold_default_auto_renew_max_price,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await this.props.rehydrate();
|
||||
};
|
||||
|
||||
_handleChange = (e) => {
|
||||
window.clearTimeout(this._deferredSave);
|
||||
this._deferredSave = null;
|
||||
this.props.onViewerChange(e);
|
||||
|
||||
this._deferredSave = window.setTimeout(async () => {
|
||||
await this._handleSave();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -110,7 +134,7 @@ export default class SceneSettings extends React.Component {
|
||||
category="address"
|
||||
onChange={this._handleChange}
|
||||
options={this.props.viewer.addresses}>
|
||||
{currentAddress.name}
|
||||
{currentAddress ? currentAddress.name : 'None'}
|
||||
</System.SelectMenu>
|
||||
|
||||
<System.Input
|
||||
|
@ -15,6 +15,16 @@ const STYLES_GROUP = css`
|
||||
padding: 24px;
|
||||
`;
|
||||
|
||||
const STYLES_TARGET = css`
|
||||
position: fixed;
|
||||
top: -1;
|
||||
left: -1;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
`;
|
||||
|
||||
const STYLES_QR_CODE = css`
|
||||
background: ${Constants.system.white};
|
||||
border-radius: 4px;
|
||||
@ -88,7 +98,7 @@ const STYLES_ITEM = css`
|
||||
margin-top: 24px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
max-width: 180px;
|
||||
max-width: 220px;
|
||||
margin-right: 32px;
|
||||
`;
|
||||
|
||||
@ -128,14 +138,23 @@ export default class SceneWallet extends React.Component {
|
||||
this.setState({ visible: !this.state.visible });
|
||||
};
|
||||
|
||||
_handleCopy = (text) => {
|
||||
Strings.copyText(text);
|
||||
alert(`${text} Added to clipboard.`);
|
||||
};
|
||||
|
||||
render() {
|
||||
let addresses = {};
|
||||
let lastAddress;
|
||||
|
||||
this.props.viewer.addresses.forEach((a) => {
|
||||
addresses[a.value] = a;
|
||||
addresses[a.address] = a;
|
||||
lastAddress = a.address;
|
||||
});
|
||||
|
||||
const currentAddress = addresses[this.props.selected.address];
|
||||
const currentAddress = this.props.selected.address
|
||||
? addresses[this.props.selected.address]
|
||||
: addresses[lastAddress];
|
||||
|
||||
// TODO(jim):
|
||||
// Capture this state.
|
||||
@ -150,7 +169,7 @@ export default class SceneWallet extends React.Component {
|
||||
|
||||
return (
|
||||
<ScenePage>
|
||||
<System.H1>Your wallet</System.H1>
|
||||
<System.H1>Wallet</System.H1>
|
||||
|
||||
<Section
|
||||
onAction={this.props.onAction}
|
||||
@ -158,15 +177,10 @@ export default class SceneWallet extends React.Component {
|
||||
title="Addresses"
|
||||
buttons={[
|
||||
{
|
||||
name: 'Create new',
|
||||
name: 'Create a new address',
|
||||
type: 'SIDEBAR',
|
||||
value: 'SIDEBAR_CREATE_WALLET_ADDRESS',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
type: 'SIDEBAR',
|
||||
value: 'SIDEBAR_DELETE_WALLET_ADDRESS',
|
||||
},
|
||||
]}>
|
||||
<div css={STYLES_GROUP}>
|
||||
<System.SelectMenu
|
||||
@ -191,7 +205,10 @@ export default class SceneWallet extends React.Component {
|
||||
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<div css={STYLES_FOCUS}>
|
||||
{currentAddress.name} <strong css={STYLES_FOCUS_EMPAHSIS}>(Primary)</strong>
|
||||
{currentAddress.name}{' '}
|
||||
{this.props.viewer.settings_cold_default_address === currentAddress.address ? (
|
||||
<strong css={STYLES_FOCUS_EMPAHSIS}>(Primary)</strong>
|
||||
) : null}
|
||||
</div>
|
||||
<div css={STYLES_SUBTEXT}>Filecoin address alias</div>
|
||||
</div>
|
||||
@ -206,11 +223,6 @@ export default class SceneWallet extends React.Component {
|
||||
<div css={STYLES_FOCUS}>{currentAddress.type}</div>
|
||||
<div css={STYLES_SUBTEXT}>Address type</div>
|
||||
</div>
|
||||
|
||||
<div css={STYLES_ITEM_CLICKABLE} onClick={() => this.props.onNavigateTo({ id: 5 })}>
|
||||
<div css={STYLES_FOCUS}>{currentAddress.deals}</div>
|
||||
<div css={STYLES_SUBTEXT}>Active deals</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 24 }}>
|
||||
@ -236,41 +248,12 @@ export default class SceneWallet extends React.Component {
|
||||
}}>
|
||||
<SVG.Privacy height="16px" />
|
||||
</span>
|
||||
<span css={STYLES_CIRCLE_BUTTON}>
|
||||
<span css={STYLES_CIRCLE_BUTTON} onClick={() => this._handleCopy(currentAddress.address)}>
|
||||
<SVG.CopyAndPaste height="16px" />
|
||||
</span>
|
||||
</div>
|
||||
<div css={STYLES_ACTIONS}>
|
||||
<div css={STYLES_QR_CODE}>
|
||||
<img src="/static/qr-code-example.jpg" css={STYLES_QR_CODE_IMAGE} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
onAction={this.props.onAction}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
title={`Transactions for ${currentAddress.name}`}
|
||||
buttons={[
|
||||
{
|
||||
name: 'Export',
|
||||
type: 'DOWNLOAD',
|
||||
value: 'CSV_WALLET_TRANSACTIONS',
|
||||
},
|
||||
]}>
|
||||
<System.Table
|
||||
data={{
|
||||
columns: SchemaTable.Wallet,
|
||||
rows: transactions,
|
||||
}}
|
||||
selectedRowId={this.state.table_transaction}
|
||||
onChange={this._handleChange}
|
||||
onAction={this.props.onAction}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
name="table_transaction"
|
||||
/>
|
||||
</Section>
|
||||
</ScenePage>
|
||||
);
|
||||
}
|
||||
|
112
server.js
112
server.js
@ -7,6 +7,7 @@ import * as Middleware from '~/common/middleware';
|
||||
|
||||
import FS from 'fs';
|
||||
import express from 'express';
|
||||
import formidable from 'formidable';
|
||||
import next from 'next';
|
||||
import bodyParser from 'body-parser';
|
||||
import compression from 'compression';
|
||||
@ -15,14 +16,15 @@ const dev = process.env.NODE_ENV !== 'production';
|
||||
const port = process.env.PORT || 1337;
|
||||
const app = next({ dev, quiet: false });
|
||||
const nextRequestHandler = app.getRequestHandler();
|
||||
const AVATAR_STORAGE_URL = `${__dirname}/public/static/system/`;
|
||||
|
||||
// TODO(jim): Just a solution for testing.
|
||||
let token;
|
||||
let status;
|
||||
let messageList;
|
||||
let peersList;
|
||||
let addrsList;
|
||||
let info;
|
||||
let token = null;
|
||||
let status = null;
|
||||
let messageList = null;
|
||||
let peersList = null;
|
||||
let addrsList = null;
|
||||
let info = null;
|
||||
|
||||
const refresh = async () => {
|
||||
const Health = await pow.health.check();
|
||||
@ -35,10 +37,25 @@ const refresh = async () => {
|
||||
|
||||
const refreshWithToken = async () => {
|
||||
const Addresses = await pow.ffs.addrs();
|
||||
addrsList = Addresses.addrsList;
|
||||
addrsList = Addresses.addrsList ? Addresses.addrsList : null;
|
||||
|
||||
const NetworkInfo = await pow.ffs.info();
|
||||
info = NetworkInfo.info;
|
||||
info = NetworkInfo.info ? NetworkInfo.info : null;
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
const data = {
|
||||
production: !dev,
|
||||
status,
|
||||
messageList,
|
||||
peersList,
|
||||
addrsList,
|
||||
info,
|
||||
};
|
||||
|
||||
console.log('ON THE SERVER', data);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
app.prepare().then(async () => {
|
||||
@ -54,18 +71,26 @@ app.prepare().then(async () => {
|
||||
token = FFS.token ? FFS.token : null;
|
||||
|
||||
// NOTE(jim): Write a new token file.
|
||||
FS.writeFileSync('./.data/powergate-token', token);
|
||||
if (token) {
|
||||
FS.writeFileSync('./.data/powergate-token', token);
|
||||
}
|
||||
} else {
|
||||
token = FS.readFileSync('./.data/powergate-token', 'utf8');
|
||||
}
|
||||
|
||||
pow.setToken(token);
|
||||
if (token) {
|
||||
pow.setToken(token);
|
||||
}
|
||||
|
||||
await refreshWithToken();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
throw new Error('[ prototype ] can not start client without proper auth token');
|
||||
}
|
||||
|
||||
const server = express();
|
||||
|
||||
if (!dev) {
|
||||
@ -85,18 +110,57 @@ app.prepare().then(async () => {
|
||||
res.send('ok');
|
||||
});
|
||||
|
||||
server.post('/_/upload/avatar', async (req, res) => {
|
||||
const form = formidable({ multiples: true, uploadDir: AVATAR_STORAGE_URL });
|
||||
|
||||
form.once('error', console.error);
|
||||
|
||||
form.on('progress', (bytesReceived, bytesExpected) => {
|
||||
console.log(`[ prototype ] ${bytesReceived} / ${bytesExpected}`);
|
||||
});
|
||||
|
||||
form.on('fileBegin', (filename, file) => {
|
||||
form.emit('data', { name: '[ prototype ] file uploading', filename, value: file });
|
||||
});
|
||||
|
||||
form.on('file', (filename, file) => {
|
||||
form.emit('data', { name: '[ prototype ] file:', key: filename, value: file });
|
||||
});
|
||||
|
||||
form.on('field', (fieldName, fieldValue) => {
|
||||
form.emit('data', { name: '[ prototype ] field:', key: fieldName, value: fieldValue });
|
||||
});
|
||||
|
||||
form.once('end', () => {
|
||||
console.log('[ prototype ] finished upload');
|
||||
});
|
||||
|
||||
form.parse(req, (error, fields, files) => {
|
||||
if (error) {
|
||||
return res.status(500).send({ error });
|
||||
} else {
|
||||
const newPath = form.uploadDir + 'avatar.png';
|
||||
FS.rename(files.image.path, newPath, function (err) {});
|
||||
|
||||
return res.status(200).send({ success: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.post('/_/viewer', async (req, res) => {
|
||||
await refresh();
|
||||
await refreshWithToken();
|
||||
|
||||
const data = {
|
||||
production: !dev,
|
||||
status,
|
||||
messageList,
|
||||
peersList,
|
||||
addrsList,
|
||||
info,
|
||||
};
|
||||
return res.status(200).send({ success: true, data: await getData() });
|
||||
});
|
||||
|
||||
server.post('/_/settings', async (req, res) => {
|
||||
let data;
|
||||
try {
|
||||
data = await pow.ffs.setDefaultConfig(req.body.config);
|
||||
} catch (e) {
|
||||
return res.status(500).send({ error: e.message });
|
||||
}
|
||||
|
||||
return res.status(200).send({ success: true, data });
|
||||
});
|
||||
@ -104,7 +168,7 @@ app.prepare().then(async () => {
|
||||
server.post('/_/wallet/create', async (req, res) => {
|
||||
let data;
|
||||
try {
|
||||
data = await pow.ffs.newAddr(req.body.name);
|
||||
data = await pow.ffs.newAddr(req.body.name, req.body.type, req.body.makeDefault);
|
||||
} catch (e) {
|
||||
return res.status(500).send({ error: e.message });
|
||||
}
|
||||
@ -124,14 +188,7 @@ app.prepare().then(async () => {
|
||||
});
|
||||
|
||||
server.get('/', async (req, res) => {
|
||||
return app.render(req, res, '/', {
|
||||
production: !dev,
|
||||
status,
|
||||
messageList,
|
||||
peersList,
|
||||
addrsList,
|
||||
info,
|
||||
});
|
||||
return app.render(req, res, '/', { production: false });
|
||||
});
|
||||
|
||||
server.get('*', async (req, res) => {
|
||||
@ -146,5 +203,6 @@ app.prepare().then(async () => {
|
||||
console.log('[ prototype ] initializing ');
|
||||
console.log('[ prototype ] powergate token:', token);
|
||||
console.log(`[ prototype ] listening on: http://localhost:${port}`);
|
||||
console.log(`[ prototype ] avatar storage: ${AVATAR_STORAGE_URL}`);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user