forked from cerc-io/laconic-console
App download indicator.
This commit is contained in:
parent
d3772602c6
commit
dccd61c0c9
@ -14,7 +14,7 @@ First start the server:
|
|||||||
Then start the Webpack devserver.
|
Then start the Webpack devserver.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd packages/consoe-app
|
cd packages/console-app
|
||||||
yarn start
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -22,20 +22,19 @@ system:
|
|||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
prefix: '/app'
|
prefix: '/app'
|
||||||
server: 'http://127.0.0.1:5999'
|
server: 'https://xbox.local'
|
||||||
|
|
||||||
wns:
|
wns:
|
||||||
server: 'http://127.0.0.1:9473/api'
|
server: 'https://xbox.local/dxos/wns/api'
|
||||||
webui: 'http://127.0.0.1:9473/webui'
|
webui: 'https://xbox.local/dxos/wns/webui'
|
||||||
|
|
||||||
signal:
|
signal:
|
||||||
server: 'http://127.0.0.1:4000'
|
server: 'wss://xbox.local/dxos/signal'
|
||||||
api: 'http://127.0.0.1:4000'
|
api: 'https://xbox.local/dxos/signal/'
|
||||||
|
|
||||||
ipfs:
|
ipfs:
|
||||||
server: '/ip4/127.0.0.1/tcp/5001'
|
server: 'https://xbox.local/dxos/ipfs/api'
|
||||||
gateway: '/ip4//127.0.0.1:8888/ipfs/'
|
gateway: 'https://xbox.local/dxos/ipfs/gateway'
|
||||||
webui: 'http://127.0.0.1:5001/webui'
|
|
||||||
|
|
||||||
wellknown:
|
wellknown:
|
||||||
endpoint: 'http://127.0.0.1:9000/.well-known/dxos'
|
endpoint: 'https://xbox.local/.well-known/dxos'
|
||||||
|
30
packages/console-app/src/components/BooleanIcon.js
Normal file
30
packages/console-app/src/components/BooleanIcon.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS
|
||||||
|
//
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import YesIcon from '@material-ui/icons/CheckCircleOutline';
|
||||||
|
import NoIcon from '@material-ui/icons/RadioButtonUnchecked';
|
||||||
|
|
||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
error: {
|
||||||
|
color: theme.palette.error.main
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
color: theme.palette.primary[500]
|
||||||
|
},
|
||||||
|
off: {
|
||||||
|
color: 'transparent'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const BooleanIcon = ({ yes = false, error = false }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (yes
|
||||||
|
? <YesIcon className={classes.on} />
|
||||||
|
: <NoIcon className={error ? classes.error : classes.off} />
|
||||||
|
);
|
||||||
|
};
|
@ -3,36 +3,42 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
|
||||||
import { useQuery } from '@apollo/react-hooks';
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
import WNS_RECORDS from '../../../gql/wns_records.graphql';
|
|
||||||
|
|
||||||
import { ConsoleContext, useQueryStatusReducer, useSorter } from '../../../hooks';
|
|
||||||
|
|
||||||
import Link from '@material-ui/core/Link';
|
import Link from '@material-ui/core/Link';
|
||||||
import TableHead from '@material-ui/core/TableHead';
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
import TableRow from '@material-ui/core/TableRow';
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import TableBody from '@material-ui/core/TableBody';
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
import { getServiceUrl } from '../../../util/config';
|
import { BooleanIcon } from '../../../components/BooleanIcon';
|
||||||
|
|
||||||
import Table from '../../../components/Table';
|
import Table from '../../../components/Table';
|
||||||
import TableCell from '../../../components/TableCell';
|
import TableCell from '../../../components/TableCell';
|
||||||
import moment from 'moment';
|
import { ConsoleContext, useQueryStatusReducer, useSorter } from '../../../hooks';
|
||||||
|
import { getServiceUrl } from '../../../util/config';
|
||||||
|
|
||||||
|
import IPFS_STATUS from '../../../gql/ipfs_status.graphql';
|
||||||
|
import WNS_RECORDS from '../../../gql/wns_records.graphql';
|
||||||
|
|
||||||
const AppRecords = () => {
|
const AppRecords = () => {
|
||||||
const { config } = useContext(ConsoleContext);
|
const { config } = useContext(ConsoleContext);
|
||||||
const [sorter, sortBy] = useSorter('createTime', false);
|
const [sorter, sortBy] = useSorter('createTime', false);
|
||||||
const data = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
const appResponse = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||||
pollInterval: config.api.intervalQuery,
|
pollInterval: config.api.intervalQuery,
|
||||||
variables: { type: 'wrn:app' }
|
variables: { type: 'wrn:app' }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!data) {
|
// TODO(telackey): Does this also need an interval?
|
||||||
|
const ipfsResponse = useQueryStatusReducer(useQuery(IPFS_STATUS));
|
||||||
|
|
||||||
|
if (!appResponse || !ipfsResponse) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const records = data.wns_records.json;
|
const appData = appResponse.wns_records.json;
|
||||||
|
const ipfsData = JSON.parse(ipfsResponse.ipfs_status.json);
|
||||||
|
|
||||||
|
const localRefs = new Set(ipfsData.refs.local);
|
||||||
|
|
||||||
// TODO(burdon): Test if app is deployed.
|
// TODO(burdon): Test if app is deployed.
|
||||||
const getAppUrl = ({ name, version }) => {
|
const getAppUrl = ({ name, version }) => {
|
||||||
@ -47,8 +53,12 @@ const AppRecords = () => {
|
|||||||
pathComponents.push(config.services.app.prefix.substring(1));
|
pathComponents.push(config.services.app.prefix.substring(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
pathComponents.push(`${name}@${version}`);
|
if (version) {
|
||||||
return pathComponents.join('/');
|
pathComponents.push(`${name}@${version}`);
|
||||||
|
} else {
|
||||||
|
pathComponents.push(name);
|
||||||
|
}
|
||||||
|
return `${pathComponents.join('/')}/`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -56,26 +66,29 @@ const AppRecords = () => {
|
|||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell onClick={sortBy('name')}>Identifier</TableCell>
|
<TableCell onClick={sortBy('name')}>Identifier</TableCell>
|
||||||
|
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell>
|
||||||
<TableCell onClick={sortBy('version')} size='small'>Version</TableCell>
|
<TableCell onClick={sortBy('version')} size='small'>Version</TableCell>
|
||||||
<TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell>
|
<TableCell onClick={sortBy('createTime')} size='small'>Created</TableCell>
|
||||||
<TableCell onClick={sortBy('attributes.displayName')}>Name</TableCell>
|
<TableCell size='small'>Downloaded</TableCell>
|
||||||
<TableCell>Link</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{records.sort(sorter).map(({ id, name, version, createTime, attributes: { displayName, publicUrl } }) => {
|
{appData.sort(sorter).map(({ id, name, version, createTime, attributes: { displayName, publicUrl, package: hash } }) => {
|
||||||
const link = getAppUrl({ id, name, version, publicUrl });
|
const verLink = getAppUrl({ id, name, version, publicUrl });
|
||||||
|
const appLink = getAppUrl({ id, name, publicUrl });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={id} size='small'>
|
<TableRow key={id} size='small'>
|
||||||
<TableCell monospace>{name}</TableCell>
|
<TableCell monospace>
|
||||||
<TableCell monospace>{version}</TableCell>
|
<Link href={appLink} target={name}>{name}</Link>
|
||||||
<TableCell>{moment.utc(createTime).fromNow()}</TableCell>
|
</TableCell>
|
||||||
<TableCell>{displayName}</TableCell>
|
<TableCell>{displayName}</TableCell>
|
||||||
<TableCell monospace>
|
<TableCell monospace>
|
||||||
{link && (
|
<Link href={verLink} target={version}>{version}</Link>
|
||||||
<Link href={link} target={name}>{link}</Link>
|
</TableCell>
|
||||||
)}
|
<TableCell>{moment.utc(createTime).fromNow()}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<BooleanIcon yes={localRefs && localRefs.has(hash)} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"name": "@dxos/console-app",
|
"name": "@dxos/console-app",
|
||||||
"buildDate": "2020-06-01T01:13:48.575Z",
|
"buildDate": "2020-06-08T18:45:46.717Z",
|
||||||
"version": "1.0.0-beta.0"
|
"version": "1.0.0-beta.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
# NOTE: Set CONFIG_FILE to swap out this config file.
|
# NOTE: Set CONFIG_FILE to swap out this config file.
|
||||||
#
|
#
|
||||||
|
|
||||||
# TODO(burdon): Set defaults.
|
|
||||||
|
|
||||||
app:
|
app:
|
||||||
title: 'Console'
|
title: 'Console'
|
||||||
org': 'DxOS'
|
org': 'DxOS'
|
||||||
@ -24,20 +22,19 @@ system:
|
|||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
prefix: '/app'
|
prefix: '/app'
|
||||||
server: 'http://127.0.0.1:5999'
|
server: 'https://xbox.local'
|
||||||
|
|
||||||
wns:
|
wns:
|
||||||
server: 'https://node1.dxos.network/wns/api'
|
server: 'https://xbox.local/dxos/wns/api'
|
||||||
webui: 'https://node1.dxos.network/wns/webui'
|
webui: 'https://xbox.local/dxos/wns/webui'
|
||||||
|
|
||||||
signal:
|
signal:
|
||||||
server: 'http://127.0.0.1:4000'
|
server: 'wss://xbox.local/dxos/signal'
|
||||||
api: 'http://127.0.0.1:4000'
|
api: 'https://xbox.local/dxos/signal/status'
|
||||||
|
|
||||||
ipfs:
|
ipfs:
|
||||||
server: '/ip4/127.0.0.1/tcp/5001'
|
server: 'https://xbox.local/dxos/ipfs/api'
|
||||||
gateway: '/ip4//127.0.0.1:8888/ipfs/'
|
gateway: 'https://xbox.local/dxos/ipfs/gateway'
|
||||||
webui: 'http://127.0.0.1:5001/webui'
|
|
||||||
|
|
||||||
wellknown:
|
wellknown:
|
||||||
endpoint: 'http://127.0.0.1:9000/.well-known/dxos'
|
endpoint: 'https://xbox.local/.well-known/dxos'
|
||||||
|
@ -21,14 +21,36 @@ export const ipfsResolvers = {
|
|||||||
// NOTE: Hangs if server not running.
|
// NOTE: Hangs if server not running.
|
||||||
const ipfs = new IpfsHttpClient(config.services.ipfs.server);
|
const ipfs = new IpfsHttpClient(config.services.ipfs.server);
|
||||||
|
|
||||||
|
const id = await ipfs.id();
|
||||||
const version = await ipfs.version();
|
const version = await ipfs.version();
|
||||||
const status = await ipfs.id();
|
const peers = await ipfs.swarm.peers();
|
||||||
|
const stats = await ipfs.stats.repo();
|
||||||
|
// Do not expose the repo path.
|
||||||
|
delete stats['repoPath'];
|
||||||
|
|
||||||
|
const refs = [];
|
||||||
|
for await (const ref of ipfs.refs.local()) {
|
||||||
|
if (ref.err) {
|
||||||
|
log(ref.err);
|
||||||
|
} else {
|
||||||
|
refs.push(ref.ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timestamp: new Date().toUTCString(),
|
timestamp: new Date().toUTCString(),
|
||||||
json: JSON.stringify({
|
json: JSON.stringify({
|
||||||
|
id,
|
||||||
version,
|
version,
|
||||||
status
|
repo: {
|
||||||
|
stats
|
||||||
|
},
|
||||||
|
refs: {
|
||||||
|
local: refs
|
||||||
|
},
|
||||||
|
swarm: {
|
||||||
|
peers
|
||||||
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user