prototype: local file storage and local preview
14
.gitignore
vendored
@ -1,10 +1,9 @@
|
|||||||
.next
|
.next
|
||||||
.data
|
|
||||||
.env
|
.env
|
||||||
.DS_STORE
|
.DS_STORE
|
||||||
|
DS_STORE
|
||||||
package-lock.json
|
package-lock.json
|
||||||
node_modules
|
node_modules
|
||||||
DS_STORE
|
|
||||||
|
|
||||||
/**/*/package-lock.json
|
/**/*/package-lock.json
|
||||||
/**/*/.DS_STORE
|
/**/*/.DS_STORE
|
||||||
@ -12,5 +11,12 @@ DS_STORE
|
|||||||
/**/*/.next
|
/**/*/.next
|
||||||
/**/*/.data
|
/**/*/.data
|
||||||
|
|
||||||
.data/**/*
|
.data/*
|
||||||
.library/**/*
|
!.data/.gitkeep
|
||||||
|
|
||||||
|
public/static/files/*
|
||||||
|
!public/static/files/.gitkeep
|
||||||
|
|
||||||
|
public/static/system/*
|
||||||
|
!public/static/system/.gitkeep
|
||||||
|
!public/static/system/avatar.png
|
@ -8,7 +8,9 @@ const REQUEST_HEADERS = {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
|
||||||
const SERVER_PATH = 'http://localhost:1337';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
|
const SERVER_PATH = dev ? 'http://localhost:1337' : 'https://filecoin.onrender.com';
|
||||||
|
|
||||||
export const rehydrateViewer = async () => {
|
export const rehydrateViewer = async () => {
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -1,481 +1,17 @@
|
|||||||
import * as Strings from '~/common/strings';
|
const constructFilesTreeForNavigation = (library) => {
|
||||||
import * as Data from '~/common/data';
|
for (let i = 0; i < library.length; i++) {
|
||||||
|
for (let j = 0; j < library[i].children.length; j++) {
|
||||||
const LOCAL_CONFIG = `
|
let e = library[i].children[j];
|
||||||
"Identity": {
|
if (e.decorator === 'FILE') {
|
||||||
"PeerID": "Qma9T5YraSnpRDZqRR4krcS",
|
library[i].children[j].ignore = true;
|
||||||
"PubKey": "CAAS4AQwggJcAgEAAoGBAMB"
|
}
|
||||||
"PrivKey": "CAASogEwgZ8wDQYJKoZIhvd"
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const getInitialState = () => {
|
|
||||||
return {
|
|
||||||
name: 'Andrew Hill',
|
|
||||||
photoURL: '/static/avatar-andrew-hill.jpg',
|
|
||||||
config: LOCAL_CONFIG,
|
|
||||||
upload_bandwidth: 40023,
|
|
||||||
download_bandwidth: 12323,
|
|
||||||
settings_deal_country: `3`,
|
|
||||||
settings_deals_auto_approve: true,
|
|
||||||
settings_deal_default_duration: 1,
|
|
||||||
settings_deal_replication_factor: 1,
|
|
||||||
settings_deal_maximum_storage_payment: 100,
|
|
||||||
settings_deal_default_miners: 't0123, t0124, t0125',
|
|
||||||
notifications: [
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'cats-are-cool.png was retrieved from the Filecoin network.',
|
|
||||||
createdAt: '2017-01-01 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'cats-are-cool.png was transfered from Miner B over to your local storage.',
|
|
||||||
createdAt: '2016-12-28 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'A transfer has been initiated for cats-are-cool.png from Miner B.',
|
|
||||||
createdAt: '2016-12-27 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'cats-are-cool.png retrieval deal accepted by Miner B.',
|
|
||||||
createdAt: '2016-12-26 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'You have proposed a deal with Miner B for cats-are-cool.png.',
|
|
||||||
createdAt: '2016-12-25 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'cats-are-cool-2.png is stored with Miner A on the Filecoin Network.',
|
|
||||||
createdAt: '2016-12-24 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'cats-are-cool-2.png has been transferred to Miner A.',
|
|
||||||
createdAt: '2016-12-23 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'A transfer has begun for cats-are-cool-2.png to Miner A.',
|
|
||||||
createdAt: '2016-12-22 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'The storage deal for cats-are-cool-2.png has been accepted by Miner A.',
|
|
||||||
createdAt: '2016-12-21 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'A storage deal for cats-are-cool-2.png has been proposed to Miner A.',
|
|
||||||
createdAt: '2016-12-20 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
type: 'DEFAULT',
|
|
||||||
text: 'Searching for a Miner A to store cats-are-cool-2.png.',
|
|
||||||
createdAt: '2016-12-19 00:00:00 UTC',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
payment_channels_active: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
category: 1,
|
|
||||||
'channel-id': 'example-channel-id-1',
|
|
||||||
'max-value': Strings.formatAsFilecoin(3232100),
|
|
||||||
'current-value': Strings.formatAsFilecoin(423233),
|
|
||||||
redeemable: 'Redeem',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
category: 2,
|
|
||||||
'channel-id': 'example-channel-id-2',
|
|
||||||
'max-value': Strings.formatAsFilecoin(3232100),
|
|
||||||
'current-value': Strings.formatAsFilecoin(423233),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
payment_channels_redeemed: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
category: 1,
|
|
||||||
'channel-id': 'example-channel-id-3',
|
|
||||||
'max-value': Strings.formatAsFilecoin(3232100),
|
|
||||||
'redeemed-value': Strings.formatAsFilecoin(423233),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
category: 1,
|
|
||||||
'channel-id': 'example-channel-id-4',
|
|
||||||
'max-value': Strings.formatAsFilecoin(223100),
|
|
||||||
'redeemed-value': Strings.formatAsFilecoin(12200),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
data_transfers: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
'data-cid': '44Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '55Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'data-source': 'LOCAL',
|
|
||||||
'data-destination': 't05141',
|
|
||||||
size: Strings.bytesToSize(202000),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
'data-cid': '66Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '77Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'data-source': 'LOCAL',
|
|
||||||
'data-destination': 't05141',
|
|
||||||
size: Strings.bytesToSize(202000),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
'data-cid': '44Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '55Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'data-source': 't05141',
|
|
||||||
'data-destination': 'LOCAL',
|
|
||||||
size: Strings.bytesToSize(202000),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
peers: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
'peer-avatar': '/static/avatar-adrian-lanzafame.png',
|
|
||||||
online: true,
|
|
||||||
'chain-head': 'bafy2bzacecvuycbaik2dn4ktxeyrzrtuviqxvhbk67qxt5lqgrwogxhk4twx6',
|
|
||||||
height: 8888,
|
|
||||||
location: 1,
|
|
||||||
upload: 22222,
|
|
||||||
download: 11111,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
'peer-avatar': '/static/avatar-andrew-hill.jpg',
|
|
||||||
online: true,
|
|
||||||
'chain-head': 'bafy2bzacecvuycbaik2dn4ktxeyrzrtuviqxvhbk67qxt5lqgrwogxhk4twx6',
|
|
||||||
height: 8888,
|
|
||||||
location: 2,
|
|
||||||
upload: 22222,
|
|
||||||
download: 11111,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
'peer-avatar': '/static/avatar-colin-evran.jpg',
|
|
||||||
'chain-head': 'bafy2bzacecvuycbaik2dn4ktxeyrzrtuviqxvhbk67qxt5lqgrwogxhk4twx6',
|
|
||||||
height: 8888,
|
|
||||||
location: 3,
|
|
||||||
upload: 22222,
|
|
||||||
download: 11111,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
'peer-avatar': '/static/avatar-juan-benet.png',
|
|
||||||
'chain-head': 'bafy2bzacecvuycbaik2dn4ktxeyrzrtuviqxvhbk67qxt5lqgrwogxhk4twx6',
|
|
||||||
height: 8888,
|
|
||||||
location: 3,
|
|
||||||
upload: 22222,
|
|
||||||
download: 11111,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
deals: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '14Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '23Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner A',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 1,
|
|
||||||
remaining: null,
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '34Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '56Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner B',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 1,
|
|
||||||
remaining: null,
|
|
||||||
status: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '78Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '89Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner C',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 2,
|
|
||||||
remaining: null,
|
|
||||||
status: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '99Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '11Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner D',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 2,
|
|
||||||
remaining: null,
|
|
||||||
status: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '12Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '34Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner E',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 2,
|
|
||||||
remaining: null,
|
|
||||||
status: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
'deal-category': 1,
|
|
||||||
'data-cid': '56Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': '78Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner F',
|
|
||||||
price: Strings.formatAsFilecoin(1000),
|
|
||||||
'auto-renew': 1,
|
|
||||||
remaining: Strings.getRemainingTime(184000),
|
|
||||||
status: 6,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
'deal-category': 2,
|
|
||||||
'data-cid': 'abY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': 'cdY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner A',
|
|
||||||
price: Strings.formatAsFilecoin(100),
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
'deal-category': 2,
|
|
||||||
'data-cid': 'efY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': 'ghY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner B',
|
|
||||||
price: Strings.formatAsFilecoin(100),
|
|
||||||
status: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
'deal-category': 2,
|
|
||||||
'data-cid': 'ilY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': 'qqY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner C',
|
|
||||||
price: Strings.formatAsFilecoin(100),
|
|
||||||
status: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
'deal-category': 2,
|
|
||||||
'data-cid': 'xxY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': 'wwY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner D',
|
|
||||||
price: Strings.formatAsFilecoin(100),
|
|
||||||
status: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
'deal-category': 2,
|
|
||||||
'data-cid': 'zzY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
'deal-cid': 'qzY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU',
|
|
||||||
miner: 'Example Miner E',
|
|
||||||
price: Strings.formatAsFilecoin(100),
|
|
||||||
status: 5,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
addresses: [
|
|
||||||
{
|
|
||||||
value: '1',
|
|
||||||
name: 'Capricorn',
|
|
||||||
address: Data.EXAMPLE_ADDRESSES[0],
|
|
||||||
transactions: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
category: 1,
|
|
||||||
amount: Strings.formatAsFilecoin(11000),
|
|
||||||
source: Data.EXTERNAL_ADDRESSES[0],
|
|
||||||
destination: 'Capricorn',
|
|
||||||
date: Strings.toDate('2017-01-01 00:00:00 UTC'),
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
category: 2,
|
|
||||||
amount: Strings.formatAsFilecoin(11000),
|
|
||||||
source: 'Capricorn',
|
|
||||||
destination: Data.EXTERNAL_ADDRESSES[0],
|
|
||||||
date: Strings.toDate('2017-01-01 00:00:00 UTC'),
|
|
||||||
status: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
category: 1,
|
|
||||||
amount: Strings.formatAsFilecoin(11000),
|
|
||||||
source: Data.EXTERNAL_ADDRESSES[0],
|
|
||||||
destination: 'Capricorn',
|
|
||||||
date: Strings.toDate('2017-01-01 00:00:00 UTC'),
|
|
||||||
status: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
category: 2,
|
|
||||||
amount: Strings.formatAsFilecoin(11000),
|
|
||||||
source: 'Capricorn',
|
|
||||||
destination: Data.EXTERNAL_ADDRESSES[0],
|
|
||||||
date: Strings.toDate('2017-01-01 00:00:00 UTC'),
|
|
||||||
status: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: 'SECP256K',
|
|
||||||
balance: 10230,
|
|
||||||
deals: 42,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '2',
|
|
||||||
name: 'Aquarius',
|
|
||||||
address: Data.EXAMPLE_ADDRESSES[1],
|
|
||||||
transactions: [],
|
|
||||||
type: 'MULTISIG',
|
|
||||||
balance: 0,
|
|
||||||
deals: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '3',
|
|
||||||
name: 'Pisces',
|
|
||||||
address: Data.EXAMPLE_ADDRESSES[2],
|
|
||||||
transactions: [],
|
|
||||||
type: 'BLS',
|
|
||||||
balance: 0,
|
|
||||||
deals: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFolderById = (id) => {
|
|
||||||
for (let i = 0; i < Data.EXAMPLE_FOLDERS.length; i++) {
|
|
||||||
if (id === Data.EXAMPLE_FOLDERS[i].id) {
|
|
||||||
return Data.EXAMPLE_FOLDERS[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return library;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileById = (id) => {
|
export const generateNavigationState = (library) => [
|
||||||
for (let i = 0; i < Data.EXAMPLE_FILES.length; i++) {
|
|
||||||
if (id === Data.EXAMPLE_FILES[i].id) {
|
|
||||||
return Data.EXAMPLE_FILES[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const constructFilesTreeForNavigation = () => {
|
|
||||||
const SCAFFOLD = [
|
|
||||||
{
|
|
||||||
folderId: `folder-root`,
|
|
||||||
children: [
|
|
||||||
`folder-1`,
|
|
||||||
`folder-2`,
|
|
||||||
`file-1`,
|
|
||||||
`file-2`,
|
|
||||||
`file-3`,
|
|
||||||
`file-8`,
|
|
||||||
`file-9`,
|
|
||||||
`file-10`,
|
|
||||||
`file-11`,
|
|
||||||
`file-12`,
|
|
||||||
`file-13`,
|
|
||||||
`file-14`,
|
|
||||||
`file-15`,
|
|
||||||
`file-16`,
|
|
||||||
`file-17`,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
folderId: `folder-1`,
|
|
||||||
children: [`folder-3`, `file-4`, `file-5`, `file-6`],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
folderId: `folder-2`,
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
folderId: `folder-3`,
|
|
||||||
children: [`file-7`],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const navigation = {
|
|
||||||
...getFolderById('folder-root'),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO(jim): Refactor after proving the concept this is ugly.
|
|
||||||
SCAFFOLD.forEach((o) => {
|
|
||||||
if (navigation.children) {
|
|
||||||
for (let i = 0; i < navigation.children.length; i++) {
|
|
||||||
if (navigation.children[i] && navigation.children[i].id === o.folderId) {
|
|
||||||
if (!navigation.children[i].children) {
|
|
||||||
navigation.children[i].children = o.children.map((each) => {
|
|
||||||
const folder = getFolderById(each);
|
|
||||||
if (folder) {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = getFileById(each);
|
|
||||||
if (file) {
|
|
||||||
return { ...file, ignore: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (navigation.id === o.folderId) {
|
|
||||||
if (!navigation.children) {
|
|
||||||
navigation.children = o.children.map((each) => {
|
|
||||||
const folder = getFolderById(each);
|
|
||||||
if (folder) {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = getFileById(each);
|
|
||||||
if (file) {
|
|
||||||
return { ...file, ignore: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return navigation;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const NavigationState = [
|
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
@ -488,79 +24,8 @@ export const NavigationState = [
|
|||||||
name: 'Wallet',
|
name: 'Wallet',
|
||||||
pageTitle: 'your wallet and addresses',
|
pageTitle: 'your wallet and addresses',
|
||||||
decorator: 'WALLET',
|
decorator: 'WALLET',
|
||||||
/*
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'Payment Channels',
|
|
||||||
children: null,
|
|
||||||
pageTitle: 'your payment channels',
|
|
||||||
decorator: 'CHANNELS',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
constructFilesTreeForNavigation(),
|
...constructFilesTreeForNavigation(library),
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: 'Deals',
|
|
||||||
pageTitle: 'your deals',
|
|
||||||
decorator: 'DEALS',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: 'Data Transfer',
|
|
||||||
pageTitle: 'your data transfers',
|
|
||||||
decorator: 'DATA_TRANSFER',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: 'Stats',
|
|
||||||
pageTitle: 'your filecoin usage',
|
|
||||||
decorator: 'STATS',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: 'Storage Market',
|
|
||||||
pageTitle: 'the storage market',
|
|
||||||
decorator: 'STORAGE_MARKET',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
name: 'Miners',
|
|
||||||
pageTitle: 'miners',
|
|
||||||
decorator: 'MINERS',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: 'Status',
|
|
||||||
pageTitle: 'your status',
|
|
||||||
decorator: 'STATUS',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: 'Peers',
|
|
||||||
pageTitle: 'your peers',
|
|
||||||
decorator: 'PEERS',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
name: 'Logs',
|
|
||||||
pageTitle: 'your logs',
|
|
||||||
decorator: 'LOGS',
|
|
||||||
children: null,
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
id: 13,
|
id: 13,
|
||||||
name: 'Edit account',
|
name: 'Edit account',
|
||||||
|
@ -35,13 +35,26 @@ const transformPeers = (peersList) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getInitialState = (props) => {
|
export const getInitialState = (props) => {
|
||||||
const { status, messageList, peersList, addrsList, info } = props;
|
const { status, messageList, peersList, addrsList, info, library } = props;
|
||||||
|
|
||||||
|
if (!info || !info.id) {
|
||||||
|
return {
|
||||||
|
id: null,
|
||||||
|
notifications: [],
|
||||||
|
payment_channels_active: [],
|
||||||
|
payment_channels_redeemed: [],
|
||||||
|
data_transfers: [],
|
||||||
|
peers: [],
|
||||||
|
deals: [],
|
||||||
|
addresses: [],
|
||||||
|
library: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: info.id,
|
id: info.id,
|
||||||
name: 'New Node',
|
name: 'New Node',
|
||||||
photoURL: '/static/system/avatar.png',
|
photoURL: '/static/system/avatar.png',
|
||||||
config: '',
|
|
||||||
upload_bandwidth: 0,
|
upload_bandwidth: 0,
|
||||||
download_bandwidth: 0,
|
download_bandwidth: 0,
|
||||||
|
|
||||||
@ -53,7 +66,7 @@ export const getInitialState = (props) => {
|
|||||||
|
|
||||||
settings_cold_enabled: info.defaultConfig.cold.enabled,
|
settings_cold_enabled: info.defaultConfig.cold.enabled,
|
||||||
settings_cold_default_address: info.defaultConfig.cold.filecoin.addr,
|
settings_cold_default_address: info.defaultConfig.cold.filecoin.addr,
|
||||||
settings_cold_default_duration: info.defaultConfig.cold.filecoin.dealDuration,
|
settings_cold_default_duration: info.defaultConfig.cold.filecoin.dealMinDuration,
|
||||||
settings_cold_default_replication_factor: info.defaultConfig.cold.filecoin.repFactor,
|
settings_cold_default_replication_factor: info.defaultConfig.cold.filecoin.repFactor,
|
||||||
settings_cold_default_excluded_miners: info.defaultConfig.cold.filecoin.excludedMinersList,
|
settings_cold_default_excluded_miners: info.defaultConfig.cold.filecoin.excludedMinersList,
|
||||||
settings_cold_default_trusted_miners: info.defaultConfig.cold.filecoin.trustedMinersList,
|
settings_cold_default_trusted_miners: info.defaultConfig.cold.filecoin.trustedMinersList,
|
||||||
@ -68,5 +81,6 @@ export const getInitialState = (props) => {
|
|||||||
peers: transformPeers(peersList),
|
peers: transformPeers(peersList),
|
||||||
deals: [],
|
deals: [],
|
||||||
addresses: transformAddresses(addrsList, info),
|
addresses: transformAddresses(addrsList, info),
|
||||||
|
library,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,7 @@ const STYLES_AVATAR = css`
|
|||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
background-color: ${Constants.system.black};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_AVATAR_ONLINE = css`
|
const STYLES_AVATAR_ONLINE = css`
|
||||||
|
@ -6,6 +6,16 @@ import * as System from '~/components/system';
|
|||||||
|
|
||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
const STYLES_FILE_HIDDEN = css`
|
||||||
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
position: fixed;
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
`;
|
||||||
|
|
||||||
const STYLES_FOCUS = css`
|
const STYLES_FOCUS = css`
|
||||||
font-size: ${Constants.typescale.lvl1};
|
font-size: ${Constants.typescale.lvl1};
|
||||||
font-family: 'inter-medium';
|
font-family: 'inter-medium';
|
||||||
@ -49,13 +59,64 @@ const SELECT_MENU_MAP = {
|
|||||||
|
|
||||||
export default class SidebarFileStorageDeal extends React.Component {
|
export default class SidebarFileStorageDeal extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
settings_deal_duration: this.props.viewer.settings_cold_default_duration,
|
file: null,
|
||||||
settings_replication_factor: this.props.viewer.settings_cold_default_replication_factor,
|
settings_cold_default_duration: this.props.viewer.settings_cold_default_duration,
|
||||||
|
settings_cold_default_replication_factor: this.props.viewer.settings_cold_default_replication_factor,
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleSubmit = () => {
|
_handleUpload = async (e) => {
|
||||||
alert('TODO: Make a storage deal');
|
e.persist();
|
||||||
this.props.onSubmit({});
|
let file = e.target.files[0];
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
alert('Something went wrong');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = new FormData();
|
||||||
|
data.append('image', file);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
body: data,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(`/_/storage/${file.name}`, options);
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
|
if (json && json.success) {
|
||||||
|
this.setState({ file });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleMakeDeal = async (src) => {
|
||||||
|
console.log(src);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ src }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/_/deals/storage', options);
|
||||||
|
const json = await response.json();
|
||||||
|
return json;
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleSubmit = async (e) => {
|
||||||
|
e.persist();
|
||||||
|
|
||||||
|
const path = `/public/static/files/${this.state.file.name}`;
|
||||||
|
await this._handleMakeDeal(path);
|
||||||
|
|
||||||
|
await this.props.onSubmit({});
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleCancel = () => {
|
_handleCancel = () => {
|
||||||
@ -82,56 +143,68 @@ export default class SidebarFileStorageDeal extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<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>
|
||||||
|
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
|
||||||
|
|
||||||
<img src="/static/test-image-upload.jpg" css={STYLES_IMAGE_PREVIEW} />
|
{this.state.file ? (
|
||||||
|
<div>
|
||||||
|
<img src={`/static/files/${this.state.file.name}`} css={STYLES_IMAGE_PREVIEW} />
|
||||||
|
|
||||||
<div css={STYLES_ITEM}>
|
<div css={STYLES_ITEM}>
|
||||||
<div css={STYLES_FOCUS}>test-image-upload.jpg</div>
|
<div css={STYLES_FOCUS}>{this.state.file.name}</div>
|
||||||
<div css={STYLES_SUBTEXT}>Name</div>
|
<div css={STYLES_SUBTEXT}>Name</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div css={STYLES_ITEM}>
|
<div css={STYLES_ITEM}>
|
||||||
<div css={STYLES_FOCUS}>42 MB</div>
|
<div css={STYLES_FOCUS}>{this.state.file.size}</div>
|
||||||
<div css={STYLES_SUBTEXT}>File size</div>
|
<div css={STYLES_SUBTEXT}>File size</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<System.ButtonSecondaryFull style={{ marginTop: 24 }}>Change file</System.ButtonSecondaryFull>
|
<System.ButtonSecondaryFull type="label" htmlFor="file" style={{ marginTop: 24 }}>
|
||||||
|
Add file
|
||||||
|
</System.ButtonSecondaryFull>
|
||||||
|
|
||||||
<System.Input
|
{this.state.file ? (
|
||||||
containerStyle={{ marginTop: 48 }}
|
<System.Input
|
||||||
label="Deal duration"
|
containerStyle={{ marginTop: 48 }}
|
||||||
name="settings_deal_duration"
|
label="Deal duration"
|
||||||
value={this.state.settings_deal_duration}
|
name="settings_cold_default_duration"
|
||||||
onChange={this._handleChange}
|
placeholder="Type in months"
|
||||||
/>
|
type="number"
|
||||||
|
value={this.state.settings_cold_default_duration}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<System.Input
|
{this.state.file ? (
|
||||||
containerStyle={{ marginTop: 24 }}
|
<System.Input
|
||||||
label="Replication factor"
|
containerStyle={{ marginTop: 24 }}
|
||||||
name="settings_replication_factor"
|
label="Replication factor"
|
||||||
value={this.state.settings_replication_factor}
|
name="settings_cold_default_replication_factor"
|
||||||
onChange={this._handleChange}
|
value={this.state.settings_cold_default_replication_factor}
|
||||||
/>
|
onChange={this._handleChange}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<System.SelectMenuFull
|
{this.state.file ? (
|
||||||
containerStyle={{ marginTop: 24 }}
|
<System.SelectMenuFull
|
||||||
name="address"
|
containerStyle={{ marginTop: 24 }}
|
||||||
label="Payment address"
|
name="address"
|
||||||
value={this.props.selected.address}
|
label="Payment address"
|
||||||
category="address"
|
value={this.props.selected.address}
|
||||||
onChange={this.props.onSelectedChange}
|
category="address"
|
||||||
options={this.props.viewer.addresses}>
|
onChange={this.props.onSelectedChange}
|
||||||
{currentAddress.name}
|
options={this.props.viewer.addresses}>
|
||||||
</System.SelectMenuFull>
|
{currentAddress.name}
|
||||||
|
</System.SelectMenuFull>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div css={STYLES_ITEM}>
|
{this.state.file ? (
|
||||||
<div css={STYLES_FOCUS}>2 FIL</div>
|
<System.ButtonPrimaryFull style={{ marginTop: 48 }} onClick={this._handleSubmit}>
|
||||||
<div css={STYLES_SUBTEXT}>Last order price</div>
|
Make storage deal
|
||||||
</div>
|
</System.ButtonPrimaryFull>
|
||||||
|
) : null}
|
||||||
<System.ButtonPrimaryFull style={{ marginTop: 48 }} onClick={this._handleSubmit}>
|
|
||||||
Make storage deal
|
|
||||||
</System.ButtonPrimaryFull>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -431,11 +431,6 @@ export class Table extends React.Component {
|
|||||||
onAction: () => console.log('No action function set'),
|
onAction: () => console.log('No action function set'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(jim): Local state for local filtering.
|
|
||||||
state = {
|
|
||||||
data: this.props.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleChange = (value) => {
|
_handleChange = (value) => {
|
||||||
this.props.onChange({
|
this.props.onChange({
|
||||||
target: {
|
target: {
|
||||||
@ -446,7 +441,7 @@ export class Table extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { data } = this.state;
|
const { data } = this.props;
|
||||||
|
|
||||||
const ac = {};
|
const ac = {};
|
||||||
|
|
||||||
@ -642,6 +637,10 @@ const STYLES_BUTTON_PRIMARY_FULL = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ButtonPrimaryFull = (props) => {
|
export const ButtonPrimaryFull = (props) => {
|
||||||
|
if (props.type === 'label') {
|
||||||
|
return <label css={STYLES_BUTTON_PRIMARY_FULL} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
return <button css={STYLES_BUTTON_PRIMARY_FULL} {...props} />;
|
return <button css={STYLES_BUTTON_PRIMARY_FULL} {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -665,6 +664,10 @@ const STYLES_BUTTON_SECONDARY = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ButtonSecondary = (props) => {
|
export const ButtonSecondary = (props) => {
|
||||||
|
if (props.type === 'label') {
|
||||||
|
return <label css={STYLES_BUTTON_SECONDARY} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
return <button css={STYLES_BUTTON_SECONDARY} {...props} />;
|
return <button css={STYLES_BUTTON_SECONDARY} {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -688,6 +691,10 @@ const STYLES_BUTTON_SECONDARY_FULL = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ButtonSecondaryFull = (props) => {
|
export const ButtonSecondaryFull = (props) => {
|
||||||
|
if (props.type === 'label') {
|
||||||
|
return <label css={STYLES_BUTTON_SECONDARY_FULL} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
return <button css={STYLES_BUTTON_SECONDARY_FULL} {...props} />;
|
return <button css={STYLES_BUTTON_SECONDARY_FULL} {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from '~/common/constants';
|
||||||
import * as SVG from "~/components/system/svg";
|
import * as SVG from '~/components/system/svg';
|
||||||
import * as OldSVG from "~/common/svg";
|
import * as OldSVG from '~/common/svg';
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from '~/common/strings';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
import { Tooltip } from "react-tippy";
|
import { Tooltip } from 'react-tippy';
|
||||||
|
|
||||||
import Avatar from "~/components/core/Avatar";
|
import Avatar from '~/components/core/Avatar';
|
||||||
|
|
||||||
const STORAGE_DEAL_STATES = {
|
const STORAGE_DEAL_STATES = {
|
||||||
"1": "Searching for miners.",
|
'0': 'Local file only.',
|
||||||
"2": "Proposing storage deal.",
|
'1': 'Searching for miners.',
|
||||||
"3": "Accepted by miners.",
|
'2': 'Proposing storage deal.',
|
||||||
"4": "Data transfer in progress.",
|
'3': 'Accepted by miners.',
|
||||||
"5": "Data transfer complete.",
|
'4': 'Data transfer in progress.',
|
||||||
"6": "Stored",
|
'5': 'Data transfer complete.',
|
||||||
|
'6': 'Stored on network.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RETRIEVAL_DEAL_STATES = {
|
const RETRIEVAL_DEAL_STATES = {
|
||||||
"1": "Available on network",
|
'0': 'Local file',
|
||||||
"2": "Retrieval deal proposed.",
|
'1': 'Available on network',
|
||||||
"3": "Retrieval deal accepted.",
|
'2': 'Retrieval deal proposed.',
|
||||||
"4": "Data transfer in progress.",
|
'3': 'Retrieval deal accepted.',
|
||||||
"5": "Data transfer completed.",
|
'4': 'Data transfer in progress.',
|
||||||
"6": "Retrieved",
|
'5': 'Data transfer completed.',
|
||||||
|
'6': 'Retrieved from network.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const COMPONENTS_ICON = {
|
const COMPONENTS_ICON = {
|
||||||
@ -34,7 +36,7 @@ const COMPONENTS_ICON = {
|
|||||||
|
|
||||||
const STYLES_TABLE_TAG = css`
|
const STYLES_TABLE_TAG = css`
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-family: "inter-semi-bold";
|
font-family: 'inter-semi-bold';
|
||||||
letter-spacing: 0.2px;
|
letter-spacing: 0.2px;
|
||||||
padding: 4px 6px 4px 6px;
|
padding: 4px 6px 4px 6px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@ -46,21 +48,18 @@ const STYLES_TABLE_TAG = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const COMPONENTS_TRANSACTION_DIRECTION = {
|
const COMPONENTS_TRANSACTION_DIRECTION = {
|
||||||
"1": (
|
'1': (
|
||||||
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.green }}>
|
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.green }}>
|
||||||
+ incoming
|
+ incoming
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
"2": <span css={STYLES_TABLE_TAG}>- outgoing</span>,
|
'2': <span css={STYLES_TABLE_TAG}>- outgoing</span>,
|
||||||
};
|
};
|
||||||
|
|
||||||
const COMPONENTS_TRANSACTION_STATUS = {
|
const COMPONENTS_TRANSACTION_STATUS = {
|
||||||
"1": <span css={STYLES_TABLE_TAG}>complete</span>,
|
'1': <span css={STYLES_TABLE_TAG}>complete</span>,
|
||||||
"2": (
|
'2': (
|
||||||
<span
|
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.yellow }}>
|
||||||
css={STYLES_TABLE_TAG}
|
|
||||||
style={{ background: Constants.system.yellow }}
|
|
||||||
>
|
|
||||||
pending
|
pending
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
@ -115,7 +114,7 @@ const STYLES_CONTENT_BUTTON = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_TABLE_CONTENT_LINK = css`
|
const STYLES_TABLE_CONTENT_LINK = css`
|
||||||
font-family: "inter-medium";
|
font-family: 'inter-medium';
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@ -140,10 +139,7 @@ export const TableColumn = (props) => {
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span css={props.top ? STYLES_TOP_COLUMN : STYLES_COLUMN} style={props.style}>
|
||||||
css={props.top ? STYLES_TOP_COLUMN : STYLES_COLUMN}
|
|
||||||
style={props.style}
|
|
||||||
>
|
|
||||||
<span css={STYLES_CONTENT}>{props.children}</span>
|
<span css={STYLES_CONTENT}>{props.children}</span>
|
||||||
{tooltipElement}
|
{tooltipElement}
|
||||||
{copyableElement}
|
{copyableElement}
|
||||||
@ -151,94 +147,75 @@ export const TableColumn = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TableContent = ({
|
export const TableContent = ({ type, text, action, data = {}, onNavigateTo, onAction }) => {
|
||||||
type,
|
|
||||||
text,
|
|
||||||
action,
|
|
||||||
data = {},
|
|
||||||
onNavigateTo,
|
|
||||||
onAction,
|
|
||||||
}) => {
|
|
||||||
const { status, online } = data;
|
const { status, online } = data;
|
||||||
|
|
||||||
if (Strings.isEmpty(text)) {
|
if (text === null || text === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "DEAL_CATEGORY":
|
case 'DEAL_CATEGORY':
|
||||||
|
return <React.Fragment>{text == 1 ? 'Storage' : 'Retrieval'}</React.Fragment>;
|
||||||
|
case 'LOCATION':
|
||||||
|
return 'United States';
|
||||||
|
case 'BUTTON':
|
||||||
return (
|
return (
|
||||||
<React.Fragment>{text == 1 ? "Storage" : "Retrieval"}</React.Fragment>
|
<span css={STYLES_TABLE_CONTENT_LINK} onClick={() => onAction({ type: 'SIDEBAR', value: action })}>
|
||||||
);
|
|
||||||
case "LOCATION":
|
|
||||||
return "United States";
|
|
||||||
case "BUTTON":
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
css={STYLES_TABLE_CONTENT_LINK}
|
|
||||||
onClick={() => onAction({ type: "SIDEBAR", value: action })}
|
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
case "TRANSACTION_DIRECTION":
|
case 'TRANSACTION_DIRECTION':
|
||||||
return COMPONENTS_TRANSACTION_DIRECTION[text];
|
return COMPONENTS_TRANSACTION_DIRECTION[text];
|
||||||
case "TRANSACTION_STATUS":
|
case 'TRANSACTION_STATUS':
|
||||||
return COMPONENTS_TRANSACTION_STATUS[text];
|
return COMPONENTS_TRANSACTION_STATUS[text];
|
||||||
case "ICON":
|
case 'ICON':
|
||||||
return COMPONENTS_ICON[text];
|
return COMPONENTS_ICON[text];
|
||||||
case "AVATAR":
|
case 'AVATAR':
|
||||||
return <Avatar url={text} size={40} online={online} />;
|
return <Avatar url={text} size={40} online={online} />;
|
||||||
case "DEAL_STATUS_RETRIEVAL":
|
case 'DEAL_STATUS_RETRIEVAL':
|
||||||
return RETRIEVAL_DEAL_STATES[`${text}`];
|
return RETRIEVAL_DEAL_STATES[`${text}`];
|
||||||
case "DEAL_STATUS":
|
case 'DEAL_STATUS':
|
||||||
return data["deal-category"] === 1
|
return data['deal_category'] === 1 ? STORAGE_DEAL_STATES[`${text}`] : RETRIEVAL_DEAL_STATES[`${text}`];
|
||||||
? STORAGE_DEAL_STATES[`${text}`]
|
case 'BANDWIDTH_UPLOAD':
|
||||||
: RETRIEVAL_DEAL_STATES[`${text}`];
|
|
||||||
case "BANDWIDTH_UPLOAD":
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<SVG.BandwidthUp height="16px" style={{ marginRight: 8 }} />
|
<SVG.BandwidthUp height="16px" style={{ marginRight: 8 }} />
|
||||||
{Strings.bytesToSize(text)}
|
{Strings.bytesToSize(text)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
case "BANDWIDTH_DOWNLOAD":
|
case 'BANDWIDTH_DOWNLOAD':
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<SVG.BandwidthDown height="16px" style={{ marginRight: 8 }} />
|
<SVG.BandwidthDown height="16px" style={{ marginRight: 8 }} />
|
||||||
{Strings.bytesToSize(text)}
|
{Strings.bytesToSize(text)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
case "MINER_AVAILABILITY":
|
case 'MINER_AVAILABILITY':
|
||||||
return text == 1 ? (
|
return text == 1 ? (
|
||||||
<span
|
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.green }}>
|
||||||
css={STYLES_TABLE_TAG}
|
|
||||||
style={{ background: Constants.system.green }}
|
|
||||||
>
|
|
||||||
Online
|
Online
|
||||||
</span>
|
</span>
|
||||||
) : null;
|
) : null;
|
||||||
case "DEAL_AUTO_RENEW":
|
case 'DEAL_AUTO_RENEW':
|
||||||
return text == 1 ? (
|
return text == 1 ? (
|
||||||
<span
|
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.brand }}>
|
||||||
css={STYLES_TABLE_TAG}
|
|
||||||
style={{ background: Constants.system.brand }}
|
|
||||||
>
|
|
||||||
true
|
true
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span css={STYLES_TABLE_TAG}>false</span>
|
<span css={STYLES_TABLE_TAG}>false</span>
|
||||||
);
|
);
|
||||||
case "NOTIFICATION_ERROR":
|
case 'NOTIFICATION_ERROR':
|
||||||
return (
|
return (
|
||||||
<span
|
<span css={STYLES_TABLE_TAG} style={{ background: Constants.system.red }}>
|
||||||
css={STYLES_TABLE_TAG}
|
{text} {Strings.pluralize('error', text)}
|
||||||
style={{ background: Constants.system.red }}
|
|
||||||
>
|
|
||||||
{text} {Strings.pluralize("error", text)}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
case "FILE_LINK":
|
case 'FILE_DATE':
|
||||||
|
return Strings.toDate(text);
|
||||||
|
case 'FILE_SIZE':
|
||||||
|
return Strings.bytesToSize(text, 2);
|
||||||
|
case 'FILE_LINK':
|
||||||
// NOTE(jim): Special case to prevent navigation.
|
// NOTE(jim): Special case to prevent navigation.
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return text;
|
return text;
|
||||||
@ -249,44 +226,45 @@ export const TableContent = ({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
css={STYLES_TABLE_CONTENT_LINK}
|
css={STYLES_TABLE_CONTENT_LINK}
|
||||||
onClick={() =>
|
onClick={() => onAction({ type: 'NAVIGATE', value: data.folderId, data })}>
|
||||||
onAction({ type: "NAVIGATE", value: data.folderId, data })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(jim): Special case for navigating to a sidebar.
|
// NOTE(jim): Special case for navigating to a sidebar.
|
||||||
if (data && data["retrieval-status"] === 1) {
|
if (data && data['retrieval_status'] === 1) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
css={STYLES_TABLE_CONTENT_LINK}
|
css={STYLES_TABLE_CONTENT_LINK}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onAction({
|
onAction({
|
||||||
type: "SIDEBAR",
|
type: 'SIDEBAR',
|
||||||
value: "SIDEBAR_FILE_STORAGE_DEAL",
|
value: 'SIDEBAR_FILE_STORAGE_DEAL',
|
||||||
})
|
})
|
||||||
}
|
}>
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(jim): Special case to prevent navigation.
|
// NOTE(jim): Special case to prevent navigation.
|
||||||
if (data && data["retrieval-status"] !== 6) {
|
if (
|
||||||
|
data &&
|
||||||
|
(data['retrieval_status'] === 5 ||
|
||||||
|
data['retrieval_status'] === 4 ||
|
||||||
|
data['retrieval_status'] === 3 ||
|
||||||
|
data['retrieval_status'] === 2)
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onAction({
|
onAction({
|
||||||
name: "File does not exist",
|
name: 'File does not exist',
|
||||||
type: "ACTION",
|
type: 'ACTION',
|
||||||
value: "ACTION_FILE_MISSING",
|
value: 'ACTION_FILE_MISSING',
|
||||||
})
|
})
|
||||||
}
|
}>
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -294,10 +272,7 @@ export const TableContent = ({
|
|||||||
|
|
||||||
// NOTE(jim): Navigates to file.
|
// NOTE(jim): Navigates to file.
|
||||||
return (
|
return (
|
||||||
<span
|
<span css={STYLES_TABLE_CONTENT_LINK} onClick={() => onNavigateTo({ id: 15 }, data)}>
|
||||||
css={STYLES_TABLE_CONTENT_LINK}
|
|
||||||
onClick={() => onNavigateTo({ id: 15 }, data)}
|
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"@emotion/css": "11.0.0-next.12",
|
"@emotion/css": "11.0.0-next.12",
|
||||||
"@emotion/react": "11.0.0-next.12",
|
"@emotion/react": "11.0.0-next.12",
|
||||||
"@emotion/server": "11.0.0-next.12",
|
"@emotion/server": "11.0.0-next.12",
|
||||||
"@textile/powergate-client": "0.1.0-beta.7",
|
"@textile/powergate-client": "0.1.0-beta.9",
|
||||||
"babel-plugin-module-resolver": "^4.0.0",
|
"babel-plugin-module-resolver": "^4.0.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-tippy": "^1.3.4",
|
"react-tippy": "^1.3.4",
|
||||||
"three": "^0.108.0"
|
"three": "^0.108.0",
|
||||||
|
"ws": "^7.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,36 +64,46 @@ const getCurrentNavigationStateById = (navigation, targetId) => {
|
|||||||
|
|
||||||
export const getServerSideProps = async (context) => {
|
export const getServerSideProps = async (context) => {
|
||||||
if (context.query && context.query.production) {
|
if (context.query && context.query.production) {
|
||||||
return { production: true };
|
return { production: true, ...context.query };
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await Actions.rehydrateViewer();
|
const data = await Actions.rehydrateViewer();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: { ...data.data },
|
props: { ...context.query, ...data.data },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class IndexPage extends React.Component {
|
export default class IndexPage extends React.Component {
|
||||||
|
_socket = null;
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
history: [{ id: 1, scrollTop: 0 }],
|
history: [{ id: 1, scrollTop: 0 }],
|
||||||
currentIndex: 0,
|
currentIndex: 0,
|
||||||
data: null,
|
data: null,
|
||||||
selected: {
|
selected: {
|
||||||
address: null,
|
address: '',
|
||||||
},
|
},
|
||||||
viewer: this.props.production ? Fixtures.getInitialState() : State.getInitialState(this.props),
|
viewer: State.getInitialState(this.props),
|
||||||
sidebar: null,
|
sidebar: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
async componentDidMount() {
|
componentDidMount() {
|
||||||
// TODO(jim): You don't really need this.
|
this._socket = new WebSocket(`ws://localhost:${this.props.wsPort}`);
|
||||||
console.log(this.props);
|
this._socket.onmessage = (m) => {
|
||||||
|
console.log(m);
|
||||||
|
if (m.type === 'message') {
|
||||||
|
const parsed = JSON.parse(m.data);
|
||||||
|
|
||||||
|
if (parsed.action === 'UPDATE_VIEWER') {
|
||||||
|
this.rehydrate({ data: parsed.data });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rehydrate = async () => {
|
rehydrate = async ({ data }) => {
|
||||||
const viewer = await Actions.rehydrateViewer();
|
this.setState({ viewer: { ...State.getInitialState(data) } });
|
||||||
this.setState({ viewer: { ...State.getInitialState(viewer.data) } });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleSubmit = async (data) => {
|
_handleSubmit = async (data) => {
|
||||||
@ -108,8 +118,6 @@ export default class IndexPage extends React.Component {
|
|||||||
type: data.wallet_type,
|
type: data.wallet_type,
|
||||||
makeDefault: data.makeDefault,
|
makeDefault: data.makeDefault,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.rehydrate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'SEND_WALLET_ADDRESS_FILECOIN') {
|
if (data.type === 'SEND_WALLET_ADDRESS_FILECOIN') {
|
||||||
@ -118,8 +126,6 @@ export default class IndexPage extends React.Component {
|
|||||||
target: data.target,
|
target: data.target,
|
||||||
amount: data.amount,
|
amount: data.amount,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.rehydrate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._handleDismissSidebar();
|
this._handleDismissSidebar();
|
||||||
@ -258,21 +264,26 @@ export default class IndexPage extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const next = this.state.history[this.state.currentIndex];
|
if (this.props.production) {
|
||||||
const current = getCurrentNavigationStateById(Fixtures.NavigationState, next.id);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const navigation = (
|
const navigation = Fixtures.generateNavigationState(this.state.viewer.library);
|
||||||
|
const next = this.state.history[this.state.currentIndex];
|
||||||
|
const current = getCurrentNavigationStateById(navigation, next.id);
|
||||||
|
|
||||||
|
const navigationElement = (
|
||||||
<ApplicationNavigation
|
<ApplicationNavigation
|
||||||
viewer={this.state.viewer}
|
viewer={this.state.viewer}
|
||||||
activeId={current.target.id}
|
activeId={current.target.id}
|
||||||
activeIds={current.activeIds}
|
activeIds={current.activeIds}
|
||||||
navigation={Fixtures.NavigationState}
|
navigation={navigation}
|
||||||
onNavigateTo={this._handleNavigateTo}
|
onNavigateTo={this._handleNavigateTo}
|
||||||
onAction={this._handleAction}
|
onAction={this._handleAction}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const header = (
|
const headerElement = (
|
||||||
<ApplicationHeader
|
<ApplicationHeader
|
||||||
viewer={this.state.viewer}
|
viewer={this.state.viewer}
|
||||||
pageTitle={current.target.pageTitle}
|
pageTitle={current.target.pageTitle}
|
||||||
@ -286,7 +297,6 @@ export default class IndexPage extends React.Component {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const scene = React.cloneElement(this.scenes[current.target.decorator], {
|
const scene = React.cloneElement(this.scenes[current.target.decorator], {
|
||||||
rehydrate: this.rehydrate,
|
|
||||||
viewer: this.state.viewer,
|
viewer: this.state.viewer,
|
||||||
selected: this.state.selected,
|
selected: this.state.selected,
|
||||||
data: current.target,
|
data: current.target,
|
||||||
@ -299,9 +309,9 @@ export default class IndexPage extends React.Component {
|
|||||||
onForward: this._handleForward,
|
onForward: this._handleForward,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sidebar;
|
let sidebarElement;
|
||||||
if (this.state.sidebar) {
|
if (this.state.sidebar) {
|
||||||
sidebar = React.cloneElement(this.state.sidebar, {
|
sidebarElement = React.cloneElement(this.state.sidebar, {
|
||||||
viewer: this.state.viewer,
|
viewer: this.state.viewer,
|
||||||
selected: this.state.selected,
|
selected: this.state.selected,
|
||||||
onSelectedChange: this._handleSelectedChange,
|
onSelectedChange: this._handleSelectedChange,
|
||||||
@ -318,9 +328,9 @@ export default class IndexPage extends React.Component {
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<WebsitePrototypeWrapper title={title} description={description} url={url}>
|
<WebsitePrototypeWrapper title={title} description={description} url={url}>
|
||||||
<ApplicationLayout
|
<ApplicationLayout
|
||||||
navigation={navigation}
|
navigation={navigationElement}
|
||||||
header={header}
|
header={headerElement}
|
||||||
sidebar={sidebar}
|
sidebar={sidebarElement}
|
||||||
onDismissSidebar={this._handleDismissSidebar}>
|
onDismissSidebar={this._handleDismissSidebar}>
|
||||||
{scene}
|
{scene}
|
||||||
</ApplicationLayout>
|
</ApplicationLayout>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
const STYLES_LAYOUT = css`
|
const STYLES_LAYOUT = css`
|
||||||
max-width: 928px;
|
max-width: 928px;
|
||||||
@ -23,13 +23,13 @@ const STYLES_PARAGRAPH = css`
|
|||||||
margin-bottom: 48px;
|
margin-bottom: 48px;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
font-family: "inter-semi-bold";
|
font-family: 'inter-semi-bold';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_NAME = css`
|
const STYLES_NAME = css`
|
||||||
font-family: "inter-semi-bold";
|
font-family: 'inter-semi-bold';
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -88,66 +88,66 @@ const STYLES_CHOICE = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const LOGOS = [
|
const LOGOS = [
|
||||||
{ src: "idea-logo-1.jpg", votes: 1 },
|
{ src: 'idea-logo-1.jpg', votes: 1 },
|
||||||
{ src: "idea-logo-2.jpg", votes: 2 },
|
{ src: 'idea-logo-2.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-3.jpg", votes: 0 },
|
{ src: 'idea-logo-3.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-4.jpg", votes: 2 },
|
{ src: 'idea-logo-4.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-5.jpg", votes: 1 },
|
{ src: 'idea-logo-5.jpg', votes: 1 },
|
||||||
{ src: "idea-logo-6.jpg", votes: 0 },
|
{ src: 'idea-logo-6.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-7.jpg", votes: 0 },
|
{ src: 'idea-logo-7.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-8.jpg", votes: 1 },
|
{ src: 'idea-logo-8.jpg', votes: 1 },
|
||||||
{ src: "idea-logo-9.jpg", votes: 3 },
|
{ src: 'idea-logo-9.jpg', votes: 3 },
|
||||||
{ src: "idea-logo-10.jpg", votes: 1 },
|
{ src: 'idea-logo-10.jpg', votes: 1 },
|
||||||
{ src: "idea-logo-11.jpg", votes: 3 },
|
{ src: 'idea-logo-11.jpg', votes: 3 },
|
||||||
{ src: "idea-logo-12.jpg", votes: 1 },
|
{ src: 'idea-logo-12.jpg', votes: 1 },
|
||||||
{ src: "idea-logo-13.jpg", votes: 2 },
|
{ src: 'idea-logo-13.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-14.jpg", votes: 0 },
|
{ src: 'idea-logo-14.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-15.jpg", votes: 2 },
|
{ src: 'idea-logo-15.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-16.jpg", votes: 3 },
|
{ src: 'idea-logo-16.jpg', votes: 3 },
|
||||||
{ src: "idea-logo-17.jpg", votes: 0 },
|
{ src: 'idea-logo-17.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-18.jpg", votes: 0 },
|
{ src: 'idea-logo-18.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-19.jpg", votes: 0 },
|
{ src: 'idea-logo-19.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-20.jpg", votes: 2 },
|
{ src: 'idea-logo-20.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-21.jpg", votes: 0 },
|
{ src: 'idea-logo-21.jpg', votes: 0 },
|
||||||
{ src: "idea-logo-22.jpg", votes: 3 },
|
{ src: 'idea-logo-22.jpg', votes: 3 },
|
||||||
{ src: "idea-logo-23.jpg", votes: 2 },
|
{ src: 'idea-logo-23.jpg', votes: 2 },
|
||||||
{ src: "idea-logo-24.jpg", votes: 0 },
|
{ src: 'idea-logo-24.jpg', votes: 0 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const NAMES = [
|
const NAMES = [
|
||||||
{ src: "Petal", votes: 1 },
|
{ src: 'Petal', votes: 1 },
|
||||||
{ src: "Petals", votes: 0 },
|
{ src: 'Petals', votes: 0 },
|
||||||
{ src: "Pistil", votes: 0 },
|
{ src: 'Pistil', votes: 0 },
|
||||||
{ src: "Stamen", votes: 0 },
|
{ src: 'Stamen', votes: 0 },
|
||||||
{ src: "Pollen", votes: 0 },
|
{ src: 'Pollen', votes: 0 },
|
||||||
{ src: "Mission Control", votes: 0 },
|
{ src: 'Mission Control', votes: 0 },
|
||||||
{ src: "Hex", votes: 2 },
|
{ src: 'Hex', votes: 2 },
|
||||||
{ src: "Hive", votes: 2 },
|
{ src: 'Hive', votes: 2 },
|
||||||
{ src: "Hexagons", votes: 0 },
|
{ src: 'Hexagons', votes: 0 },
|
||||||
{ src: "Spheres", votes: 0 },
|
{ src: 'Spheres', votes: 0 },
|
||||||
{ src: "FileManager", votes: 0 },
|
{ src: 'FileManager', votes: 0 },
|
||||||
{ src: "FilePatron", votes: 0 },
|
{ src: 'FilePatron', votes: 0 },
|
||||||
{ src: "Filecoin Client", votes: 0 },
|
{ src: 'Filecoin Client', votes: 0 },
|
||||||
{ src: "Ponds", votes: 1 },
|
{ src: 'Ponds', votes: 1 },
|
||||||
{ src: "Outre", votes: 1 },
|
{ src: 'Outre', votes: 1 },
|
||||||
{ src: "Slate", votes: 2 },
|
{ src: 'Slate', votes: 2 },
|
||||||
{ src: "Case", votes: 2 },
|
{ src: 'Case', votes: 2 },
|
||||||
{ src: "Materials", votes: 0 },
|
{ src: 'Materials', votes: 0 },
|
||||||
{ src: "SeedDrive", votes: 0 },
|
{ src: 'SeedDrive', votes: 0 },
|
||||||
{ src: "Monet", votes: 2 },
|
{ src: 'Monet', votes: 2 },
|
||||||
{ src: "Lilypad", votes: 0 },
|
{ src: 'Lilypad', votes: 0 },
|
||||||
{ src: "StoreBuddy", votes: 0 },
|
{ src: 'StoreBuddy', votes: 0 },
|
||||||
{ src: "FileCabinet", votes: 0 },
|
{ src: 'FileCabinet', votes: 0 },
|
||||||
{ src: "Jacana", votes: 1 },
|
{ src: 'Jacana', votes: 1 },
|
||||||
{ src: "Argo", votes: 2 },
|
{ src: 'Argo', votes: 2 },
|
||||||
{ src: "Octavius", votes: 0 },
|
{ src: 'Octavius', votes: 0 },
|
||||||
{ src: "Corgi", votes: 0 },
|
{ src: 'Corgi', votes: 0 },
|
||||||
{ src: "Filing Cabinet", votes: 0 },
|
{ src: 'Filing Cabinet', votes: 0 },
|
||||||
{ src: "FileCorgi", votes: 0 },
|
{ src: 'FileCorgi', votes: 0 },
|
||||||
{ src: "Max", votes: 0 },
|
{ src: 'Max', votes: 0 },
|
||||||
{ src: "Nominal", votes: 0 },
|
{ src: 'Nominal', votes: 0 },
|
||||||
{ src: "X AE", votes: 0 },
|
{ src: 'X AE', votes: 0 },
|
||||||
{ src: "A 12", votes: 0 },
|
{ src: 'A 12', votes: 0 },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class LogoNameTest extends React.Component {
|
export default class LogoNameTest extends React.Component {
|
||||||
@ -155,17 +155,13 @@ export default class LogoNameTest extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div css={STYLES_LAYOUT}>
|
<div css={STYLES_LAYOUT}>
|
||||||
<p css={STYLES_PARAGRAPH}>
|
<p css={STYLES_PARAGRAPH}>
|
||||||
If you are looking at this page, it is a list of name and logo ideas
|
If you are looking at this page, it is a list of name and logo ideas (I did not make them). Names and logos do
|
||||||
(I did not make them). Names and logos do not correspond with each
|
not correspond with each other.{' '}
|
||||||
other.{" "}
|
<strong>Please let me know which ones you like through Slack direct message.</strong>
|
||||||
<strong>
|
|
||||||
Please let me know which ones you like through Slack direct message.
|
|
||||||
</strong>
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
All votes are anonymous. We will take the votes, consolidate the
|
All votes are anonymous. We will take the votes, consolidate the choices and then ask other designers to help
|
||||||
choices and then ask other designers to help out with refining what
|
out with refining what the team prefers.
|
||||||
the team prefers.
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
Key
|
Key
|
||||||
@ -183,18 +179,14 @@ export default class LogoNameTest extends React.Component {
|
|||||||
<span
|
<span
|
||||||
css={STYLES_PILL}
|
css={STYLES_PILL}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#0047FF",
|
backgroundColor: '#0047FF',
|
||||||
bottom: "auto",
|
bottom: 'auto',
|
||||||
top: -16,
|
top: -16,
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
{n.votes}
|
{n.votes}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
<span
|
<span css={STYLES_CHOICE} style={{ background: 'transparent', color: '#000' }}>
|
||||||
css={STYLES_CHOICE}
|
|
||||||
style={{ background: "transparent", color: "#000" }}
|
|
||||||
>
|
|
||||||
Option #{index + 1}
|
Option #{index + 1}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -208,20 +200,15 @@ export default class LogoNameTest extends React.Component {
|
|||||||
<div>
|
<div>
|
||||||
{LOGOS.map((l, index) => {
|
{LOGOS.map((l, index) => {
|
||||||
return (
|
return (
|
||||||
<span
|
<span key={l.src} css={STYLES_LOGO} style={{ backgroundImage: `url('/static/temp/${l.src}')` }}>
|
||||||
key={l.src}
|
|
||||||
css={STYLES_LOGO}
|
|
||||||
style={{ backgroundImage: `url('/static/${l.src}')` }}
|
|
||||||
>
|
|
||||||
{l.votes > 0 ? (
|
{l.votes > 0 ? (
|
||||||
<span
|
<span
|
||||||
css={STYLES_PILL}
|
css={STYLES_PILL}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#0047FF",
|
backgroundColor: '#0047FF',
|
||||||
bottom: "auto",
|
bottom: 'auto',
|
||||||
top: -16,
|
top: -16,
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
{l.votes}
|
{l.votes}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
Before Width: | Height: | Size: 1000 KiB |
Before Width: | Height: | Size: 509 KiB |
Before Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 412 KiB |
Before Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 501 KiB |
Before Width: | Height: | Size: 318 KiB |
Before Width: | Height: | Size: 857 KiB |
Before Width: | Height: | Size: 492 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 100 KiB |
0
public/static/files/.gitkeep
Normal file
Before Width: | Height: | Size: 39 KiB |
0
public/static/system/.gitkeep
Normal file
Before Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 234 KiB |
Before Width: | Height: | Size: 524 KiB |
Before Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 193 KiB |
Before Width: | Height: | Size: 159 KiB |
Before Width: | Height: | Size: 163 KiB |
@ -1,17 +1,17 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from '~/common/strings';
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from '~/common/constants';
|
||||||
import * as Fixtures from "~/common/fixtures";
|
import * as Fixtures from '~/common/fixtures';
|
||||||
import * as System from "~/components/system";
|
import * as System from '~/components/system';
|
||||||
import * as SchemaTable from "~/common/schema-table";
|
import * as SchemaTable from '~/common/schema-table';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from '~/components/core/ScenePage';
|
||||||
import Section from "~/components/core/Section";
|
import Section from '~/components/core/Section';
|
||||||
|
|
||||||
export default class SceneDataTransfer extends React.Component {
|
export default class SceneDataTransfer extends React.Component {
|
||||||
state = { sub_navigation: "1" };
|
state = { sub_navigation: '1' };
|
||||||
|
|
||||||
_handleChange = (e) => {
|
_handleChange = (e) => {
|
||||||
this.setState({ [e.target.name]: e.target.value });
|
this.setState({ [e.target.name]: e.target.value });
|
||||||
@ -26,19 +26,15 @@ export default class SceneDataTransfer extends React.Component {
|
|||||||
style={{ marginTop: 24 }}
|
style={{ marginTop: 24 }}
|
||||||
name="sub_navigation"
|
name="sub_navigation"
|
||||||
options={[
|
options={[
|
||||||
{ value: "1", label: "Current transfers" },
|
{ value: '1', label: 'Current transfers' },
|
||||||
{ value: "2", label: "Past transfers" },
|
{ value: '2', label: 'Past transfers' },
|
||||||
]}
|
]}
|
||||||
value={this.state.sub_navigation}
|
value={this.state.sub_navigation}
|
||||||
onChange={this._handleChange}
|
onChange={this._handleChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.state.sub_navigation === "2" ? (
|
{this.state.sub_navigation === '2' ? (
|
||||||
<Section
|
<Section title="Past transfers" onAction={this.props.onAction} onNavigateTo={this.props.onNavigateTo}>
|
||||||
title="Past transfers"
|
|
||||||
onAction={this.props.onAction}
|
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
|
||||||
>
|
|
||||||
<System.Table
|
<System.Table
|
||||||
data={{
|
data={{
|
||||||
columns: SchemaTable.DataTransfer,
|
columns: SchemaTable.DataTransfer,
|
||||||
@ -53,19 +49,8 @@ export default class SceneDataTransfer extends React.Component {
|
|||||||
</Section>
|
</Section>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{this.state.sub_navigation === "1" ? (
|
{this.state.sub_navigation === '1' ? (
|
||||||
<Section
|
<Section onAction={this.props.onAction} onNavigateTo={this.props.onNavigateTo} title="Current transfers">
|
||||||
onAction={this.props.onAction}
|
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
|
||||||
title="Current transfers"
|
|
||||||
buttons={[
|
|
||||||
{
|
|
||||||
name: "Cancel all",
|
|
||||||
type: "ACTION",
|
|
||||||
value: "ACTION_CANCEL_DATA_TRANSFERS",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<System.P style={{ padding: 24 }}>There are no transfers</System.P>
|
<System.P style={{ padding: 24 }}>There are no transfers</System.P>
|
||||||
</Section>
|
</Section>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from '~/common/strings';
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from '~/common/constants';
|
||||||
import * as Fixtures from "~/common/fixtures";
|
import * as Fixtures from '~/common/fixtures';
|
||||||
import * as System from "~/components/system";
|
import * as System from '~/components/system';
|
||||||
import * as SchemaTable from "~/common/schema-table";
|
import * as SchemaTable from '~/common/schema-table';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
import Section from "~/components/core/Section";
|
import Section from '~/components/core/Section';
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from '~/components/core/ScenePage';
|
||||||
|
|
||||||
export default class SceneDeals extends React.Component {
|
export default class SceneDeals extends React.Component {
|
||||||
state = {};
|
state = {};
|
||||||
@ -20,18 +20,7 @@ export default class SceneDeals extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScenePage>
|
<ScenePage>
|
||||||
<Section
|
<Section onAction={this.props.onAction} onNavigateTo={this.props.onNavigateTo} title="All deals" buttons={[]}>
|
||||||
onAction={this.props.onAction}
|
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
|
||||||
title="All deals"
|
|
||||||
buttons={[
|
|
||||||
{
|
|
||||||
name: "Export",
|
|
||||||
type: "DOWNLOAD",
|
|
||||||
value: "CSV_ALL_DEALS",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<System.Table
|
<System.Table
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
onNavigateTo={this.props.onNavigateTo}
|
||||||
|
@ -37,12 +37,7 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
body: data,
|
body: data,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`/_/upload/avatar`, options);
|
await fetch(`/_/upload/avatar`, options);
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
if (json && json.success) {
|
|
||||||
console.log('reload');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleChange = (e) => {
|
_handleChange = (e) => {
|
||||||
@ -64,7 +59,7 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
|
|
||||||
<div style={{ marginTop: 24 }}>
|
<div style={{ marginTop: 24 }}>
|
||||||
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
|
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
|
||||||
<System.ButtonPrimary style={{ margin: '0 16px 16px 0' }} type="label" for="file">
|
<System.ButtonPrimary style={{ margin: '0 16px 16px 0' }} type="label" htmlFor="file">
|
||||||
Upload
|
Upload
|
||||||
</System.ButtonPrimary>
|
</System.ButtonPrimary>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from '~/common/strings';
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from '~/common/constants';
|
||||||
import * as Fixtures from "~/common/fixtures";
|
import * as Fixtures from '~/common/fixtures';
|
||||||
import * as System from "~/components/system";
|
import * as System from '~/components/system';
|
||||||
import * as SVG from "~/components/system/svg";
|
import * as SVG from '~/components/system/svg';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
import Section from "~/components/core/Section";
|
import Section from '~/components/core/Section';
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from '~/components/core/ScenePage';
|
||||||
|
|
||||||
const STYLES_FLEX = css`
|
const STYLES_FLEX = css`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -21,6 +21,7 @@ const STYLES_FLEX = css`
|
|||||||
|
|
||||||
const STYLES_TOP = css`
|
const STYLES_TOP = css`
|
||||||
background: ${Constants.system.pitchBlack};
|
background: ${Constants.system.pitchBlack};
|
||||||
|
border-bottom: 1px solid ${Constants.system.black};
|
||||||
color: ${Constants.system.white};
|
color: ${Constants.system.white};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px 16px 12px 48px;
|
padding: 12px 16px 12px 48px;
|
||||||
@ -53,7 +54,9 @@ const STYLES_ASSET = css`
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
min-height: 10%;
|
min-height: 10%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-size: cover;
|
background-color: ${Constants.system.pitchBlack};
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -69,7 +72,7 @@ const STYLES_BOTTOM = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_PATH = css`
|
const STYLES_PATH = css`
|
||||||
font-family: "mono";
|
font-family: 'mono';
|
||||||
color: ${Constants.system.white};
|
color: ${Constants.system.white};
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@ -87,7 +90,7 @@ const STYLES_ITEM = css`
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: 0.2px;
|
letter-spacing: 0.2px;
|
||||||
font-family: "inter-semi-bold";
|
font-family: 'inter-semi-bold';
|
||||||
transition: 200ms ease all;
|
transition: 200ms ease all;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: ${Constants.system.brand};
|
background-color: ${Constants.system.brand};
|
||||||
@ -113,7 +116,7 @@ export default class SceneFile extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const fileURL = `/static/${this.props.file.file}`;
|
const fileURL = `/static/files/${this.props.file.file}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={STYLES_FLEX}>
|
<div css={STYLES_FLEX}>
|
||||||
@ -125,20 +128,7 @@ export default class SceneFile extends React.Component {
|
|||||||
<SVG.Dismiss height="24px" />
|
<SVG.Dismiss height="24px" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div css={STYLES_ASSET} style={{ backgroundImage: `url('${fileURL}')` }} />
|
||||||
css={STYLES_ASSET}
|
|
||||||
style={{ backgroundImage: `url('${fileURL}')` }}
|
|
||||||
/>
|
|
||||||
<div css={STYLES_BOTTOM}>
|
|
||||||
<div css={STYLES_LEFT}>
|
|
||||||
<span css={STYLES_PATH}>{this.props.file["cid"]}</span>
|
|
||||||
</div>
|
|
||||||
<div css={STYLES_RIGHT}>
|
|
||||||
<span css={STYLES_ITEM}>Copy CID</span>
|
|
||||||
<span css={STYLES_ITEM}>Copy gateways</span>
|
|
||||||
<span css={STYLES_ITEM}>Copy to downloads</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from '~/common/strings';
|
||||||
import * as Constants from "~/common/constants";
|
import * as Constants from '~/common/constants';
|
||||||
import * as Fixtures from "~/common/fixtures";
|
import * as Fixtures from '~/common/fixtures';
|
||||||
import * as System from "~/components/system";
|
import * as System from '~/components/system';
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
import Section from "~/components/core/Section";
|
import Section from '~/components/core/Section';
|
||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from '~/components/core/ScenePage';
|
||||||
|
|
||||||
export default class SceneFilesFolder extends React.Component {
|
export default class SceneFilesFolder extends React.Component {
|
||||||
state = {};
|
state = {};
|
||||||
@ -24,29 +24,21 @@ export default class SceneFilesFolder extends React.Component {
|
|||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
columns: [
|
columns: [
|
||||||
{ key: "icon", hideLabel: true, width: "32px", type: "ICON" },
|
{ key: 'icon', hideLabel: true, width: '32px', type: 'ICON' },
|
||||||
{ key: "file", name: "File", width: "100%", type: "FILE_LINK" },
|
{ key: 'file', name: 'File', width: '100%', type: 'FILE_LINK' },
|
||||||
{ key: "size", name: "Size", width: "140px" },
|
{ key: 'size', name: 'Size', width: '140px', type: 'FILE_SIZE' },
|
||||||
{
|
{
|
||||||
key: "date",
|
key: 'date',
|
||||||
name: "Date uploaded",
|
name: 'Date uploaded',
|
||||||
width: "160px",
|
width: '160px',
|
||||||
tooltip:
|
tooltip: 'This date represents when the file was first uploaded to the network.',
|
||||||
"This date represents when the file was first uploaded to the network.",
|
type: 'FILE_DATE',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "remaining",
|
key: 'storage_status',
|
||||||
name: "Remaining time",
|
name: 'Status',
|
||||||
tooltip:
|
type: 'DEAL_STATUS',
|
||||||
"This file will remain available to you on the network for a limited time. Once time elapses you will have to create a new storage deal.",
|
|
||||||
width: "180px",
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "retrieval-status",
|
|
||||||
name: "Status",
|
|
||||||
type: "DEAL_STATUS_RETRIEVAL",
|
|
||||||
},
|
|
||||||
{ key: "errors", hideLabel: true, type: "NOTIFICATION_ERROR" },
|
|
||||||
],
|
],
|
||||||
rows,
|
rows,
|
||||||
};
|
};
|
||||||
@ -59,17 +51,11 @@ export default class SceneFilesFolder extends React.Component {
|
|||||||
title={this.props.data.name}
|
title={this.props.data.name}
|
||||||
buttons={[
|
buttons={[
|
||||||
{
|
{
|
||||||
name: "Retrieve",
|
name: 'Store file on network',
|
||||||
type: "SIDEBAR",
|
type: 'SIDEBAR',
|
||||||
value: "SIDEBAR_FILE_RETRIEVAL_DEAL",
|
value: 'SIDEBAR_FILE_STORAGE_DEAL',
|
||||||
},
|
},
|
||||||
{
|
]}>
|
||||||
name: "Store file on network",
|
|
||||||
type: "SIDEBAR",
|
|
||||||
value: "SIDEBAR_FILE_STORAGE_DEAL",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<System.Table
|
<System.Table
|
||||||
key={this.props.data.folderId}
|
key={this.props.data.folderId}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -54,43 +54,50 @@ export default class SceneHome extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScenePage>
|
<ScenePage>
|
||||||
<Section
|
{this.props.viewer.library[0] ? (
|
||||||
onAction={this.props.onAction}
|
<Section
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
|
||||||
title="Recent data"
|
|
||||||
buttons={[
|
|
||||||
{
|
|
||||||
name: 'View files',
|
|
||||||
type: 'NAVIGATE',
|
|
||||||
value: 'folder-root',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Store file on network',
|
|
||||||
type: 'SIDEBAR',
|
|
||||||
value: 'SIDEBAR_FILE_STORAGE_DEAL',
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<System.Table
|
|
||||||
data={{
|
|
||||||
columns: [
|
|
||||||
{ key: 'file', name: 'File', type: 'FILE_LINK' },
|
|
||||||
{
|
|
||||||
key: 'date',
|
|
||||||
name: 'Date uploaded',
|
|
||||||
width: '160px',
|
|
||||||
tooltip: 'This date represents when the file was first uploaded to the network.',
|
|
||||||
},
|
|
||||||
{ key: 'remaining', name: 'Remaining time', width: '180px' },
|
|
||||||
],
|
|
||||||
rows: [],
|
|
||||||
}}
|
|
||||||
selectedRowId={this.state.data}
|
|
||||||
onChange={this._handleChange}
|
|
||||||
onAction={this.props.onAction}
|
onAction={this.props.onAction}
|
||||||
onNavigateTo={this.props.onNavigateTo}
|
onNavigateTo={this.props.onNavigateTo}
|
||||||
name="data"
|
title="Recent data"
|
||||||
/>
|
buttons={[
|
||||||
</Section>
|
{
|
||||||
|
name: 'View files',
|
||||||
|
type: 'NAVIGATE',
|
||||||
|
value: this.props.viewer.library[0].folderId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Store file on network',
|
||||||
|
type: 'SIDEBAR',
|
||||||
|
value: 'SIDEBAR_FILE_STORAGE_DEAL',
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<System.Table
|
||||||
|
data={{
|
||||||
|
columns: [
|
||||||
|
{ key: 'file', name: 'File', type: 'FILE_LINK' },
|
||||||
|
{ key: 'size', name: 'Size', width: '140px', type: 'FILE_SIZE' },
|
||||||
|
{
|
||||||
|
key: 'date',
|
||||||
|
name: 'Date uploaded',
|
||||||
|
width: '160px',
|
||||||
|
type: 'FILE_DATE',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'storage_status',
|
||||||
|
name: 'Status',
|
||||||
|
type: 'DEAL_STATUS',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rows: this.props.viewer.library[0].children,
|
||||||
|
}}
|
||||||
|
selectedRowId={this.state.data}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
onAction={this.props.onAction}
|
||||||
|
onNavigateTo={this.props.onNavigateTo}
|
||||||
|
name="data"
|
||||||
|
/>
|
||||||
|
</Section>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{this.props.viewer.addresses[0] ? (
|
{this.props.viewer.addresses[0] ? (
|
||||||
<Section
|
<Section
|
||||||
|
@ -33,7 +33,7 @@ export default class SceneSettings extends React.Component {
|
|||||||
_deferredSave = null;
|
_deferredSave = null;
|
||||||
|
|
||||||
_handleSave = async () => {
|
_handleSave = async () => {
|
||||||
const response = await Actions.setDefaultConfig({
|
await Actions.setDefaultConfig({
|
||||||
config: {
|
config: {
|
||||||
hot: {
|
hot: {
|
||||||
enabled: this.props.viewer.settings_cold_enabled,
|
enabled: this.props.viewer.settings_cold_enabled,
|
||||||
@ -46,7 +46,7 @@ export default class SceneSettings extends React.Component {
|
|||||||
enabled: this.props.viewer.settings_cold_enabled,
|
enabled: this.props.viewer.settings_cold_enabled,
|
||||||
filecoin: {
|
filecoin: {
|
||||||
addr: this.props.viewer.settings_cold_default_address,
|
addr: this.props.viewer.settings_cold_default_address,
|
||||||
dealDuration: this.props.viewer.settings_cold_default_duration,
|
dealMinDuration: this.props.viewer.settings_cold_default_duration,
|
||||||
repFactor: this.props.viewer.settings_cold_default_replication_factor,
|
repFactor: this.props.viewer.settings_cold_default_replication_factor,
|
||||||
excludedMinersList: this.props.viewer.settings_cold_default_excluded_miners,
|
excludedMinersList: this.props.viewer.settings_cold_default_excluded_miners,
|
||||||
trustedMinersList: this.props.viewer.settings_cold_default_trusted_miners,
|
trustedMinersList: this.props.viewer.settings_cold_default_trusted_miners,
|
||||||
@ -59,8 +59,6 @@ export default class SceneSettings extends React.Component {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.props.rehydrate();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleChange = (e) => {
|
_handleChange = (e) => {
|
||||||
@ -143,6 +141,7 @@ export default class SceneSettings extends React.Component {
|
|||||||
description="Default Filecoin deal duration settings description."
|
description="Default Filecoin deal duration settings description."
|
||||||
tooltip="Placeholder."
|
tooltip="Placeholder."
|
||||||
name="settings_cold_default_duration"
|
name="settings_cold_default_duration"
|
||||||
|
type="number"
|
||||||
value={this.props.viewer.settings_cold_default_duration}
|
value={this.props.viewer.settings_cold_default_duration}
|
||||||
placeholder="Type in months"
|
placeholder="Type in months"
|
||||||
onChange={this._handleChange}
|
onChange={this._handleChange}
|
||||||
|
333
server.js
@ -1,9 +1,10 @@
|
|||||||
import { createPow } from '@textile/powergate-client';
|
import { createPow, ffs } from '@textile/powergate-client';
|
||||||
|
|
||||||
const host = 'http://0.0.0.0:6002';
|
const host = 'http://0.0.0.0:6002';
|
||||||
const pow = createPow({ host });
|
const PowerGate = createPow({ host });
|
||||||
|
|
||||||
import * as Middleware from '~/common/middleware';
|
import * as Middleware from '~/common/middleware';
|
||||||
|
import * as Strings from '~/common/strings';
|
||||||
|
|
||||||
import FS from 'fs';
|
import FS from 'fs';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
@ -11,15 +12,22 @@ import formidable from 'formidable';
|
|||||||
import next from 'next';
|
import next from 'next';
|
||||||
import bodyParser from 'body-parser';
|
import bodyParser from 'body-parser';
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
|
import WebSocketServer from 'ws';
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== 'production';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
const port = process.env.PORT || 1337;
|
const port = process.env.PORT || 1337;
|
||||||
|
const wsPort = 2448;
|
||||||
const app = next({ dev, quiet: false });
|
const app = next({ dev, quiet: false });
|
||||||
const nextRequestHandler = app.getRequestHandler();
|
const nextRequestHandler = app.getRequestHandler();
|
||||||
|
|
||||||
const AVATAR_STORAGE_URL = `${__dirname}/public/static/system/`;
|
const AVATAR_STORAGE_URL = `${__dirname}/public/static/system/`;
|
||||||
|
const FILE_STORAGE_URL = `${__dirname}/public/static/files/`;
|
||||||
|
|
||||||
// TODO(jim): Just a solution for testing.
|
// TODO(jim): Just a solution for testing.
|
||||||
|
// Probably should refactor this or use a database.
|
||||||
|
let client = null;
|
||||||
let token = null;
|
let token = null;
|
||||||
|
let library = null;
|
||||||
let status = null;
|
let status = null;
|
||||||
let messageList = null;
|
let messageList = null;
|
||||||
let peersList = null;
|
let peersList = null;
|
||||||
@ -27,22 +35,66 @@ let addrsList = null;
|
|||||||
let info = null;
|
let info = null;
|
||||||
|
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
const Health = await pow.health.check();
|
const Health = await PowerGate.health.check();
|
||||||
status = Health.status ? Health.status : null;
|
status = Health.status ? Health.status : null;
|
||||||
messageList = Health.messageList ? Health.messageList : null;
|
messageList = Health.messageList ? Health.messageList : null;
|
||||||
|
|
||||||
const Peers = await pow.net.peers();
|
const Peers = await PowerGate.net.peers();
|
||||||
peersList = Peers.peersList ? Peers.peersList : null;
|
peersList = Peers.peersList ? Peers.peersList : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshWithToken = async () => {
|
const refreshWithToken = async () => {
|
||||||
const Addresses = await pow.ffs.addrs();
|
const Addresses = await PowerGate.ffs.addrs();
|
||||||
addrsList = Addresses.addrsList ? Addresses.addrsList : null;
|
addrsList = Addresses.addrsList ? Addresses.addrsList : null;
|
||||||
|
|
||||||
const NetworkInfo = await pow.ffs.info();
|
const NetworkInfo = await PowerGate.ffs.info();
|
||||||
info = NetworkInfo.info ? NetworkInfo.info : null;
|
info = NetworkInfo.info ? NetworkInfo.info : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFileName = (s) => {
|
||||||
|
let target = s;
|
||||||
|
if (target.endsWith('/')) {
|
||||||
|
target = target.substring(0, target.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return target.substr(target.lastIndexOf('/') + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createFile = (id, data) => {
|
||||||
|
return {
|
||||||
|
decorator: 'FILE',
|
||||||
|
id: id,
|
||||||
|
icon: 'PNG',
|
||||||
|
file: getFileName(id),
|
||||||
|
miner: null,
|
||||||
|
job_id: null,
|
||||||
|
cid: null,
|
||||||
|
date: new Date(),
|
||||||
|
size: data.size,
|
||||||
|
amount: 0,
|
||||||
|
remaining: null,
|
||||||
|
deal_category: 1,
|
||||||
|
retrieval_status: 0,
|
||||||
|
storage_status: 0,
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createFolder = (id) => {
|
||||||
|
return {
|
||||||
|
decorator: 'FOLDER',
|
||||||
|
id,
|
||||||
|
folderId: id,
|
||||||
|
icon: 'FOLDER',
|
||||||
|
file: getFileName(id),
|
||||||
|
name: getFileName(id),
|
||||||
|
pageTitle: null,
|
||||||
|
date: null,
|
||||||
|
size: null,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const data = {
|
const data = {
|
||||||
production: !dev,
|
production: !dev,
|
||||||
@ -51,47 +103,134 @@ const getData = async () => {
|
|||||||
peersList,
|
peersList,
|
||||||
addrsList,
|
addrsList,
|
||||||
info,
|
info,
|
||||||
|
library,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('ON THE SERVER', data);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
app.prepare().then(async () => {
|
const emitStateUpdate = async () => {
|
||||||
try {
|
await refresh();
|
||||||
await refresh();
|
await refreshWithToken();
|
||||||
|
const data = await getData();
|
||||||
|
client.send(JSON.stringify({ action: 'UPDATE_VIEWER', data }));
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE(jim): This is a configuration folder with all of the client tokens.
|
const checkFileStatus = async () => {
|
||||||
!FS.existsSync(`./.data`) && FS.mkdirSync(`./.data`, { recursive: true });
|
// TODO(jim): Refactor this so we repeat this less often.
|
||||||
|
let write = false;
|
||||||
|
for (let i = 0; i < library.length; i++) {
|
||||||
|
for (let j = 0; j < library[i].children.length; j++) {
|
||||||
|
if (library[i].children[j].job_id) {
|
||||||
|
if (library[i].children[j].storage_status === 1) {
|
||||||
|
library[i].children[j].storage_status = 2;
|
||||||
|
write = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(jim): This will create a token for authentication with powergate.
|
PowerGate.ffs.watchJobs((job) => {
|
||||||
if (!FS.existsSync('./.data/powergate-token')) {
|
console.log(job);
|
||||||
const FFS = await pow.ffs.create();
|
if (job.status === ffs.JobStatus.JOB_STATUS_SUCCESS) {
|
||||||
token = FFS.token ? FFS.token : null;
|
library[i].children[j].storage_status = 6;
|
||||||
|
write = true;
|
||||||
// NOTE(jim): Write a new token file.
|
}
|
||||||
if (token) {
|
}, library[i].children[j].job_id);
|
||||||
FS.writeFileSync('./.data/powergate-token', token);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
token = FS.readFileSync('./.data/powergate-token', 'utf8');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
|
||||||
pow.setToken(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
await refreshWithToken();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!token) {
|
if (write) {
|
||||||
throw new Error('[ prototype ] can not start client without proper auth token');
|
FS.writeFileSync('./.data/library.json', JSON.stringify({ library }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setIntervalViewerUpdates = async () => {
|
||||||
|
console.log('[ prototype ] checking for library deal updates.');
|
||||||
|
if (client) {
|
||||||
|
try {
|
||||||
|
await emitStateUpdate();
|
||||||
|
await checkFileStatus();
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
setTimeout(setIntervalViewerUpdates, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetAllLocalData = async () => {
|
||||||
|
// NOTE(jim): For testing purposes.
|
||||||
|
// We wipe all of the local data each time you run the application.
|
||||||
|
console.log('[ prototype ] deleting old token and library data ');
|
||||||
|
FS.rmdirSync('./.data', { recursive: true });
|
||||||
|
|
||||||
|
console.log('[ prototype ] deleting old avatar data ');
|
||||||
|
FS.rmdirSync(AVATAR_STORAGE_URL, { recursive: true });
|
||||||
|
|
||||||
|
console.log('[ prototype ] deleting old file data ');
|
||||||
|
FS.rmdirSync(FILE_STORAGE_URL, { recursive: true });
|
||||||
|
|
||||||
|
console.log('[ prototype ] creating new avatar folder ');
|
||||||
|
FS.mkdirSync(AVATAR_STORAGE_URL, { recursive: true });
|
||||||
|
FS.writeFileSync(`${AVATAR_STORAGE_URL}.gitkeep`, '');
|
||||||
|
|
||||||
|
console.log('[ prototype ] creating new local file folder ');
|
||||||
|
FS.mkdirSync(FILE_STORAGE_URL, { recursive: true });
|
||||||
|
FS.writeFileSync(`${FILE_STORAGE_URL}.gitkeep`, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
app.prepare().then(async () => {
|
||||||
|
if (dev) {
|
||||||
|
await resetAllLocalData();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await refresh();
|
||||||
|
|
||||||
|
// NOTE(jim): This is a configuration folder with all of the client tokens.
|
||||||
|
!FS.existsSync(`./.data`) && FS.mkdirSync(`./.data`, { recursive: true });
|
||||||
|
|
||||||
|
// NOTE(jim): This will create a token for authentication with powergate.
|
||||||
|
if (!FS.existsSync('./.data/powergate-token')) {
|
||||||
|
const FFS = await PowerGate.ffs.create();
|
||||||
|
token = FFS.token ? FFS.token : null;
|
||||||
|
|
||||||
|
// NOTE(jim): Write a new token file.
|
||||||
|
if (token) {
|
||||||
|
FS.writeFileSync('./.data/powergate-token', token);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token = FS.readFileSync('./.data/powergate-token', 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
PowerGate.setToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
await refreshWithToken();
|
||||||
|
|
||||||
|
if (!FS.existsSync('./.data/library.json')) {
|
||||||
|
const librarySchema = { library: [{ ...createFolder(FILE_STORAGE_URL), file: 'Files', name: 'Files' }] };
|
||||||
|
FS.writeFileSync('./.data/library.json', JSON.stringify(librarySchema));
|
||||||
|
library = librarySchema.library;
|
||||||
|
} else {
|
||||||
|
const parsedLibrary = FS.readFileSync('./.data/library.json', 'utf8');
|
||||||
|
library = JSON.parse(parsedLibrary).library;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = express();
|
const server = express();
|
||||||
|
const WSS = new WebSocketServer.Server({ port: wsPort });
|
||||||
|
|
||||||
|
WSS.on('connection', (s) => {
|
||||||
|
// TODO(jim): Suppport more than one client.
|
||||||
|
client = s;
|
||||||
|
|
||||||
|
s.on('close', function () {
|
||||||
|
s.send(JSON.stringify({ action: null, data: 'closed' }));
|
||||||
|
});
|
||||||
|
|
||||||
|
s.send(JSON.stringify({ action: null, data: 'connected' }));
|
||||||
|
});
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
server.use(compression());
|
server.use(compression());
|
||||||
@ -106,8 +245,87 @@ app.prepare().then(async () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
server.get('/health', async (req, res) => {
|
server.post('/_/viewer', async (req, res) => {
|
||||||
res.send('ok');
|
if (dev) {
|
||||||
|
await refresh();
|
||||||
|
await refreshWithToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).send({ success: true, data: await getData() });
|
||||||
|
});
|
||||||
|
|
||||||
|
server.post('/_/deals/storage', async (req, res) => {
|
||||||
|
if (Strings.isEmpty(req.body.src)) {
|
||||||
|
return res.status(500).send({ success: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
const localPath = `${__dirname}${req.body.src}`;
|
||||||
|
const buffer = FS.readFileSync(localPath);
|
||||||
|
const { cid } = await PowerGate.ffs.addToHot(buffer);
|
||||||
|
const { jobId } = await PowerGate.ffs.pushConfig(cid);
|
||||||
|
|
||||||
|
// TODO(jim): Refactor this so we repeat this less often.
|
||||||
|
let write = false;
|
||||||
|
for (let i = 0; i < library.length; i++) {
|
||||||
|
for (let j = 0; j < library[i].children.length; j++) {
|
||||||
|
if (localPath === library[i].children[j].id) {
|
||||||
|
library[i].children[j].job_id = jobId;
|
||||||
|
library[i].children[j].cid = cid;
|
||||||
|
library[i].children[j].storage_status = 1;
|
||||||
|
write = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write) {
|
||||||
|
FS.writeFileSync('./.data/library.json', JSON.stringify({ library }));
|
||||||
|
}
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
|
return res.status(200).send({ success: true, cid, jobId });
|
||||||
|
});
|
||||||
|
|
||||||
|
server.post('/_/storage/:file', async (req, res) => {
|
||||||
|
const form = formidable({ multiples: true, uploadDir: FILE_STORAGE_URL });
|
||||||
|
|
||||||
|
form.once('error', console.error);
|
||||||
|
|
||||||
|
form.on('progress', (bytesReceived, bytesExpected) => {
|
||||||
|
console.log(`[ prototype ] ${bytesReceived} / ${bytesExpected}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
form.parse(req, async (error, fields, files) => {
|
||||||
|
if (error) {
|
||||||
|
return res.status(500).send({ error });
|
||||||
|
} else {
|
||||||
|
if (!files.image) {
|
||||||
|
console.error('[ prototype ] File type unspported', files);
|
||||||
|
return res.status(500).send({ error: 'File type unsupported', files });
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPath = form.uploadDir + req.params.file;
|
||||||
|
FS.rename(files.image.path, newPath, function (err) {});
|
||||||
|
|
||||||
|
const localFile = createFile(newPath, files.image);
|
||||||
|
|
||||||
|
let pushed = false;
|
||||||
|
for (let i = 0; i < library.length; i++) {
|
||||||
|
const currentFolder = library[i];
|
||||||
|
if (!pushed) {
|
||||||
|
currentFolder.children.push(localFile);
|
||||||
|
pushed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushed) {
|
||||||
|
FS.writeFileSync('./.data/library.json', JSON.stringify({ library }));
|
||||||
|
}
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
|
return res.status(200).send({ success: true, file: localFile });
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.post('/_/upload/avatar', async (req, res) => {
|
server.post('/_/upload/avatar', async (req, res) => {
|
||||||
@ -119,83 +337,68 @@ app.prepare().then(async () => {
|
|||||||
console.log(`[ prototype ] ${bytesReceived} / ${bytesExpected}`);
|
console.log(`[ prototype ] ${bytesReceived} / ${bytesExpected}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
form.on('fileBegin', (filename, file) => {
|
form.parse(req, async (error, fields, files) => {
|
||||||
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) {
|
if (error) {
|
||||||
return res.status(500).send({ error });
|
return res.status(500).send({ error });
|
||||||
} else {
|
} else {
|
||||||
const newPath = form.uploadDir + 'avatar.png';
|
const newPath = form.uploadDir + 'avatar.png';
|
||||||
FS.rename(files.image.path, newPath, function (err) {});
|
FS.rename(files.image.path, newPath, function (err) {});
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
return res.status(200).send({ success: true });
|
return res.status(200).send({ success: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.post('/_/viewer', async (req, res) => {
|
|
||||||
await refresh();
|
|
||||||
await refreshWithToken();
|
|
||||||
|
|
||||||
return res.status(200).send({ success: true, data: await getData() });
|
|
||||||
});
|
|
||||||
|
|
||||||
server.post('/_/settings', async (req, res) => {
|
server.post('/_/settings', async (req, res) => {
|
||||||
let data;
|
let data;
|
||||||
try {
|
try {
|
||||||
data = await pow.ffs.setDefaultConfig(req.body.config);
|
data = await PowerGate.ffs.setDefaultConfig(req.body.config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res.status(500).send({ error: e.message });
|
return res.status(500).send({ error: e.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
return res.status(200).send({ success: true, data });
|
return res.status(200).send({ success: true, data });
|
||||||
});
|
});
|
||||||
|
|
||||||
server.post('/_/wallet/create', async (req, res) => {
|
server.post('/_/wallet/create', async (req, res) => {
|
||||||
let data;
|
let data;
|
||||||
try {
|
try {
|
||||||
data = await pow.ffs.newAddr(req.body.name, req.body.type, req.body.makeDefault);
|
data = await PowerGate.ffs.newAddr(req.body.name, req.body.type, req.body.makeDefault);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res.status(500).send({ error: e.message });
|
return res.status(500).send({ error: e.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
return res.status(200).send({ success: true, data });
|
return res.status(200).send({ success: true, data });
|
||||||
});
|
});
|
||||||
|
|
||||||
server.post('/_/wallet/send', async (req, res) => {
|
server.post('/_/wallet/send', async (req, res) => {
|
||||||
let data;
|
let data;
|
||||||
try {
|
try {
|
||||||
data = await pow.ffs.sendFil(req.body.source, req.body.target, req.body.amount);
|
data = await PowerGate.ffs.sendFil(req.body.source, req.body.target, req.body.amount);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res.status(500).send({ error: e.message });
|
return res.status(500).send({ error: e.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await emitStateUpdate();
|
||||||
return res.status(200).send({ success: true, data: { ...data, ...req.body } });
|
return res.status(200).send({ success: true, data: { ...data, ...req.body } });
|
||||||
});
|
});
|
||||||
|
|
||||||
server.get('/', async (req, res) => {
|
server.get('/', async (req, res) => {
|
||||||
return app.render(req, res, '/', { production: false });
|
if (!dev) {
|
||||||
|
return res.redirect('https://github.com/filecoin-project/filecoin-client');
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.render(req, res, '/', { production: false, wsPort });
|
||||||
});
|
});
|
||||||
|
|
||||||
server.get('*', async (req, res) => {
|
server.get('*', async (req, res) => {
|
||||||
return nextRequestHandler(req, res, req.url);
|
return nextRequestHandler(req, res, req.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(port, (err) => {
|
server.listen(port, async (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@ -204,5 +407,7 @@ app.prepare().then(async () => {
|
|||||||
console.log('[ prototype ] powergate token:', token);
|
console.log('[ prototype ] powergate token:', token);
|
||||||
console.log(`[ prototype ] listening on: http://localhost:${port}`);
|
console.log(`[ prototype ] listening on: http://localhost:${port}`);
|
||||||
console.log(`[ prototype ] avatar storage: ${AVATAR_STORAGE_URL}`);
|
console.log(`[ prototype ] avatar storage: ${AVATAR_STORAGE_URL}`);
|
||||||
|
|
||||||
|
await setIntervalViewerUpdates();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|