forked from cerc-io/laconic-console
App/Bots/Records.
This commit is contained in:
parent
9fbdd0625a
commit
75459af67b
20
README.md
20
README.md
@ -6,23 +6,31 @@ Apollo GraphQL client and server using express.
|
|||||||
|
|
||||||
### POC
|
### POC
|
||||||
|
|
||||||
- [ ] Trigger server-side wire commands (mutation or separate express path?)
|
- [ ] Complete WNS functionality
|
||||||
|
- [ ] Logging
|
||||||
|
- [ ] Webpack and dynamic config
|
||||||
|
- [ ] Routes for services
|
||||||
|
- [ ] Trigger server-side wire commands
|
||||||
|
- [ ] Test on device in production.
|
||||||
|
|
||||||
|
- [ ] IPFS
|
||||||
|
- [ ] Signal
|
||||||
|
- [ ] Apps
|
||||||
|
- [ ] Bots
|
||||||
|
- [ ] Meta
|
||||||
|
|
||||||
### Next
|
### Next
|
||||||
|
|
||||||
- [ ] Config routes for services (test).
|
|
||||||
- [ ] Webpack config (remove dynamic config?)
|
|
||||||
|
|
||||||
- [ ] Client/server API abstraction (error handler, etc.)
|
- [ ] Client/server API abstraction (error handler, etc.)
|
||||||
- [ ] Port dashboard API calls (resolve config first).
|
- [ ] Port dashboard API calls (resolve config first).
|
||||||
- [ ] Port dashboard react modules with dummy resolvers.
|
- [ ] Port dashboard react modules with dummy resolvers.
|
||||||
|
|
||||||
- [ ] Fix JsonTree (yarn link).
|
|
||||||
- [ ] https://github.com/standard/standardx (JSX)
|
- [ ] https://github.com/standard/standardx (JSX)
|
||||||
|
|
||||||
### Done
|
### Done
|
||||||
|
|
||||||
- [c] Client resolvers: https://www.apollographql.com/docs/tutorial/local-state/
|
- [x] Fix JsonTree (yarn link).
|
||||||
|
- [x] Client resolvers: https://www.apollographql.com/docs/tutorial/local-state/
|
||||||
- [x] Test backend IPFS client request.
|
- [x] Test backend IPFS client request.
|
||||||
- [x] Hash Router.
|
- [x] Hash Router.
|
||||||
- [x] Layout (with Material UI).
|
- [x] Layout (with Material UI).
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -22,6 +22,7 @@ system:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
|
prefix: '/app'
|
||||||
server: 'http://127.0.0.1:5999' # TODO(burdon): ???
|
server: 'http://127.0.0.1:5999' # TODO(burdon): ???
|
||||||
|
|
||||||
wns:
|
wns:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2020 DxOS
|
# Copyright 2020 DxOS.org
|
||||||
#
|
#
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2020 DxOS
|
# Copyright 2020 DxOS.org
|
||||||
#
|
#
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2020 DxOS
|
# Copyright 2020 DxOS.org
|
||||||
#
|
#
|
||||||
|
|
||||||
mutation Action($command: String!) {
|
mutation ($command: String!) {
|
||||||
wns_action(command: $command) {
|
wns_action(command: $command) {
|
||||||
timestamp
|
timestamp
|
||||||
code
|
code
|
||||||
|
9
packages/console-client/gql/wns_log.graphql
Normal file
9
packages/console-client/gql/wns_log.graphql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2020 DxOS.org
|
||||||
|
#
|
||||||
|
|
||||||
|
{
|
||||||
|
wns_log @client {
|
||||||
|
log
|
||||||
|
}
|
||||||
|
}
|
9
packages/console-client/gql/wns_records.graphql
Normal file
9
packages/console-client/gql/wns_records.graphql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2020 DxOS.org
|
||||||
|
#
|
||||||
|
|
||||||
|
query ($type: String) {
|
||||||
|
wns_records (type: $type) @client {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2020 DxOS
|
# Copyright 2020 DxOS.org
|
||||||
#
|
#
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -39,10 +39,12 @@
|
|||||||
"apollo-cache-inmemory": "^1.6.6",
|
"apollo-cache-inmemory": "^1.6.6",
|
||||||
"apollo-client": "^2.6.10",
|
"apollo-client": "^2.6.10",
|
||||||
"apollo-link-http": "^1.5.17",
|
"apollo-link-http": "^1.5.17",
|
||||||
|
"build-url": "^2.0.0",
|
||||||
"clsx": "^1.1.0",
|
"clsx": "^1.1.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"graphql-tag": "^2.10.3",
|
"graphql-tag": "^2.10.3",
|
||||||
"lodash.defaultsdeep": "^4.6.1",
|
"lodash.defaultsdeep": "^4.6.1",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
"lodash.isobject": "^3.0.2",
|
"lodash.isobject": "^3.0.2",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
"lodash.transform": "^4.6.0",
|
"lodash.transform": "^4.6.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import { ApolloClient } from 'apollo-client';
|
import { ApolloClient } from 'apollo-client';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -45,7 +45,7 @@ const AppBar = ({ config }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MuiAppBar position="fixed">
|
<MuiAppBar position="fixed">
|
||||||
<Toolbar variant="dense">
|
<Toolbar>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<div className={classes.logo}>
|
<div className={classes.logo}>
|
||||||
<DxOSIcon />
|
<DxOSIcon />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import isObject from 'lodash.isobject';
|
import isObject from 'lodash.isobject';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
@ -36,7 +36,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
width: 200,
|
width: 200,
|
||||||
borderRight: `1px solid ${theme.palette.primary.dark}`
|
borderRight: `1px solid ${theme.palette.divider}`
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
57
packages/console-client/src/components/PackageLink.js
Normal file
57
packages/console-client/src/components/PackageLink.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import Link from '@material-ui/core/Link';
|
||||||
|
|
||||||
|
import { getServiceUrl } from '../util/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render IPFS links in package.
|
||||||
|
* @param {Object} config
|
||||||
|
* @param {string} [type]
|
||||||
|
* @param {string} pkg
|
||||||
|
*/
|
||||||
|
const PackageLink = ({ config, type, pkg }) => {
|
||||||
|
|
||||||
|
// TODO(burdon): Pass in expected arg types.
|
||||||
|
if (typeof pkg === 'string') {
|
||||||
|
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${pkg}` });
|
||||||
|
return <Link href={ipfsUrl} target="ipfs">{pkg}</Link>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line default-case
|
||||||
|
switch (type) {
|
||||||
|
case 'wrn:bot': {
|
||||||
|
const packageLinks = [];
|
||||||
|
Object.keys(pkg).forEach(platform => {
|
||||||
|
Object.keys(pkg[platform]).forEach(arch => {
|
||||||
|
const cid = pkg[platform][arch];
|
||||||
|
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${cid}` });
|
||||||
|
|
||||||
|
packageLinks.push(
|
||||||
|
<Fragment>
|
||||||
|
<Link
|
||||||
|
key={cid}
|
||||||
|
href={ipfsUrl}
|
||||||
|
title={cid}
|
||||||
|
target="ipfs"
|
||||||
|
>
|
||||||
|
{platform}/{arch}: {cid}
|
||||||
|
</Link>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>{packageLinks}</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PackageLink;
|
@ -4,9 +4,8 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import Paper from '@material-ui/core/Paper';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(() => ({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -28,9 +27,9 @@ const Panel = ({ toolbar, children }) => {
|
|||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
{toolbar}
|
{toolbar}
|
||||||
<Paper className={classes.container}>
|
<div className={classes.container}>
|
||||||
{children}
|
{children}
|
||||||
</Paper>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
@ -16,7 +16,8 @@ const useStyles = makeStyles(theme => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'space-between'
|
justifyContent: 'space-between',
|
||||||
|
// backgroundColor: theme.palette.grey[100]
|
||||||
},
|
},
|
||||||
|
|
||||||
list: {
|
list: {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
@ -86,7 +86,7 @@ const StatusBar = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toolbar variant="dense" className={classes.root}>
|
<Toolbar className={classes.root}>
|
||||||
<div className={classes.left}>
|
<div className={classes.left}>
|
||||||
<Link className={classes.link} href={config.app.website} rel="noreferrer" target="_blank">
|
<Link className={classes.link} href={config.app.website} rel="noreferrer" target="_blank">
|
||||||
<PublicIcon />
|
<PublicIcon />
|
||||||
|
41
packages/console-client/src/components/Table.js
Normal file
41
packages/console-client/src/components/Table.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import MuiTable from '@material-ui/core/Table';
|
||||||
|
import TableContainer from '@material-ui/core/TableContainer';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
overflowY: 'scroll',
|
||||||
|
backgroundColor: theme.palette.background.paper
|
||||||
|
},
|
||||||
|
|
||||||
|
table: {
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
|
||||||
|
'& th': {
|
||||||
|
fontVariant: 'all-small-caps',
|
||||||
|
fontSize: 18,
|
||||||
|
cursor: 'ns-resize'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Table = ({ children }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableContainer className={classes.root}>
|
||||||
|
<MuiTable stickyHeader size="small" className={classes.table}>
|
||||||
|
{children}
|
||||||
|
</MuiTable>
|
||||||
|
</TableContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
@ -1,28 +1,38 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import MuiTableCell from '@material-ui/core/TableCell';
|
import MuiTableCell from '@material-ui/core/TableCell';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
|
||||||
// TODO(burdon): Size for header.
|
const useStyles = makeStyles(() => ({
|
||||||
// TODO(burdon): Standardize table.
|
small: {
|
||||||
|
width: 160
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
const TableCell = ({ children, monospace = false, title, ...rest }) => (
|
const TableCell = ({ children, size, monospace = false, title, ...rest }) => {
|
||||||
<MuiTableCell
|
const classes = useStyles();
|
||||||
{...rest}
|
|
||||||
style={{
|
return (
|
||||||
overflow: 'hidden',
|
<MuiTableCell
|
||||||
textOverflow: 'ellipsis',
|
{...rest}
|
||||||
whiteSpace: 'nowrap',
|
className={clsx(size && classes[size])}
|
||||||
fontFamily: monospace ? 'monospace' : 'inherit',
|
style={{
|
||||||
fontSize: monospace ? 14 : 'inherit'
|
overflow: 'hidden',
|
||||||
}}
|
textOverflow: 'ellipsis',
|
||||||
title={title}
|
whiteSpace: 'nowrap',
|
||||||
>
|
fontFamily: monospace ? 'monospace' : 'inherit',
|
||||||
{children}
|
fontSize: monospace ? 14 : 'inherit'
|
||||||
</MuiTableCell>
|
}}
|
||||||
);
|
title={title}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</MuiTableCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default TableCell;
|
export default TableCell;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -10,18 +10,20 @@ const useStyles = makeStyles(theme => ({
|
|||||||
toolbar: {
|
toolbar: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
|
||||||
'& > button': {
|
'& > button': {
|
||||||
margin: theme.spacing(0.5),
|
margin: theme.spacing(0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// TODO(burdon): Tabs.
|
||||||
const Toolbar = ({ children }) => {
|
const Toolbar = ({ children }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiToolbar variant="dense" disableGutters className={classes.toolbar}>
|
<MuiToolbar disableGutters className={classes.toolbar}>
|
||||||
{children}
|
{children}
|
||||||
</MuiToolbar>
|
</MuiToolbar>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React, { useEffect, useReducer } from 'react';
|
import React, { useEffect, useReducer } from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
@ -17,10 +17,14 @@ import modules from '../modules';
|
|||||||
import Layout from '../components/Layout';
|
import Layout from '../components/Layout';
|
||||||
import ConsoleContextProvider from './ConsoleContextProvider';
|
import ConsoleContextProvider from './ConsoleContextProvider';
|
||||||
|
|
||||||
|
import AppRecords from './panels/apps/Apps';
|
||||||
|
import Bots from './panels/bots/Bots';
|
||||||
import Config from './panels/Config';
|
import Config from './panels/Config';
|
||||||
import IPFS from './panels/IPFS';
|
import IPFS from './panels/ipfs/IPFS';
|
||||||
|
import Metadata from './panels/Metadata';
|
||||||
|
import Signaling from './panels/Signaling';
|
||||||
import Status from './panels/Status';
|
import Status from './panels/Status';
|
||||||
import WNS from './panels/WNS';
|
import WNS from './panels/wns/WNS';
|
||||||
|
|
||||||
debug.enable(config.system.debug);
|
debug.enable(config.system.debug);
|
||||||
|
|
||||||
@ -34,8 +38,12 @@ const Main = () => {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/:module">
|
<Route path="/:module">
|
||||||
<Layout>
|
<Layout>
|
||||||
|
<Route path="/apps" component={AppRecords} />
|
||||||
|
<Route path="/bots" component={Bots} />
|
||||||
<Route path="/config" component={Config} />
|
<Route path="/config" component={Config} />
|
||||||
<Route path="/ipfs" component={IPFS} />
|
<Route path="/ipfs" component={IPFS} />
|
||||||
|
<Route path="/metadata" component={Metadata} />
|
||||||
|
<Route path="/signaling" component={Signaling} />
|
||||||
<Route path="/status" component={Status} />
|
<Route path="/status" component={Status} />
|
||||||
<Route path="/wns" component={WNS} />
|
<Route path="/wns" component={WNS} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
21
packages/console-client/src/containers/panels/Metadata.js
Normal file
21
packages/console-client/src/containers/panels/Metadata.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Signal = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Signal;
|
21
packages/console-client/src/containers/panels/Signaling.js
Normal file
21
packages/console-client/src/containers/panels/Signaling.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Signaling = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Signaling;
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
@ -1,123 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2020 DxOS
|
|
||||||
//
|
|
||||||
|
|
||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { useQuery } from '@apollo/react-hooks';
|
|
||||||
import { Mutation } from '@apollo/react-components';
|
|
||||||
import { makeStyles } from '@material-ui/core';
|
|
||||||
import Button from '@material-ui/core/Button';
|
|
||||||
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
|
||||||
import Tab from '@material-ui/core/Tab';
|
|
||||||
import Tabs from '@material-ui/core/Tabs';
|
|
||||||
import TabContext from '@material-ui/lab/TabContext';
|
|
||||||
import TabPanel from '@material-ui/lab/TabPanel';
|
|
||||||
|
|
||||||
import ControlButtons from '../../components/ControlButtons';
|
|
||||||
import Json from '../../components/Json';
|
|
||||||
import Log from '../../components/Log';
|
|
||||||
import Panel from '../../components/Panel';
|
|
||||||
import Toolbar from '../../components/Toolbar';
|
|
||||||
|
|
||||||
import { ConsoleContext, useQueryStatusReducer } from '../../hooks';
|
|
||||||
|
|
||||||
import WNS_STATUS from '../../../gql/wns_status.graphql';
|
|
||||||
import WNS_ACTION from '../../../gql/wns_action.graphql';
|
|
||||||
|
|
||||||
const types = [
|
|
||||||
{ key: null, label: 'ALL' },
|
|
||||||
{ key: 'wrn:xbox', label: 'XBox' },
|
|
||||||
{ key: 'wrn:resource', label: 'Resource' },
|
|
||||||
{ key: 'wrn:app', label: 'App' },
|
|
||||||
{ key: 'wrn:bot', label: 'Bot' },
|
|
||||||
{ key: 'wrn:type', label: 'Type' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const TAB_RECORDS = 'records';
|
|
||||||
const TAB_LOG = 'log';
|
|
||||||
const TAB_EXPLORER = 'explorer';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
|
||||||
expand: {
|
|
||||||
flex: 1
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const WNS = () => {
|
|
||||||
const classes = useStyles();
|
|
||||||
const { config } = useContext(ConsoleContext);
|
|
||||||
const [type, setType] = useState(types[0].key);
|
|
||||||
const [tab, setTab] = useState(TAB_RECORDS);
|
|
||||||
const data = useQueryStatusReducer(useQuery(WNS_STATUS, { pollInterval: config.api.pollInterval }));
|
|
||||||
if (!data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Panel
|
|
||||||
toolbar={
|
|
||||||
<Toolbar>
|
|
||||||
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
|
||||||
<Tab value={TAB_RECORDS} label="Records"/>
|
|
||||||
<Tab value={TAB_EXPLORER} label="Explorer"/>
|
|
||||||
<Tab value={TAB_LOG} label="Log"/>
|
|
||||||
</Tabs>
|
|
||||||
|
|
||||||
{tab === TAB_RECORDS && (
|
|
||||||
<ButtonGroup
|
|
||||||
className={classes.buttons}
|
|
||||||
disableRipple
|
|
||||||
disableFocusRipple
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
size="small"
|
|
||||||
aria-label="text primary button group"
|
|
||||||
>
|
|
||||||
{types.map(t => (
|
|
||||||
<Button
|
|
||||||
key={t.key}
|
|
||||||
className={t.key === type && classes.selected}
|
|
||||||
onClick={() => setType(t.key)}
|
|
||||||
>
|
|
||||||
{t.label}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</ButtonGroup>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={classes.expand} />
|
|
||||||
|
|
||||||
<Mutation mutation={WNS_ACTION}>
|
|
||||||
{(action, { data }) => (
|
|
||||||
<div>
|
|
||||||
<ControlButtons
|
|
||||||
onStart={() => {
|
|
||||||
action({ variables: { command: 'start' } });
|
|
||||||
}}
|
|
||||||
onStop={() => {
|
|
||||||
action({ variables: { command: 'stop' } });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Mutation>
|
|
||||||
</Toolbar>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TabContext value={tab}>
|
|
||||||
<TabPanel value={TAB_RECORDS}>
|
|
||||||
<Json data={JSON.parse(data.wns_status.json)} />
|
|
||||||
</TabPanel>
|
|
||||||
|
|
||||||
<TabPanel value={TAB_EXPLORER}>
|
|
||||||
</TabPanel>
|
|
||||||
|
|
||||||
<TabPanel value={TAB_LOG}>
|
|
||||||
<Log />
|
|
||||||
</TabPanel>
|
|
||||||
</TabContext>
|
|
||||||
</Panel>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WNS;
|
|
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
|
import WNS_RECORDS from '../../../../gql/wns_records.graphql';
|
||||||
|
|
||||||
|
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
|
import Link from '@material-ui/core/Link';
|
||||||
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
|
||||||
|
import { getServiceUrl } from '../../../util/config';
|
||||||
|
|
||||||
|
import Table from '../../../components/Table';
|
||||||
|
import TableCell from '../../../components/TableCell';
|
||||||
|
|
||||||
|
const AppRecords = () => {
|
||||||
|
const { config } = useContext(ConsoleContext);
|
||||||
|
const data = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||||
|
pollInterval: config.api.pollInterval,
|
||||||
|
variables: { type: 'wrn:app' }
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const records = data.wns_records.json;
|
||||||
|
|
||||||
|
// TODO(burdon): Factor out.
|
||||||
|
const sorter = (a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
||||||
|
|
||||||
|
// TODO(burdon): Test if app is deployed.
|
||||||
|
const getAppUrl = ({ name, version }) => {
|
||||||
|
const base = getServiceUrl(config, 'app.server');
|
||||||
|
const pathComponents = [base];
|
||||||
|
|
||||||
|
// TODO(burdon): Fix.
|
||||||
|
// `wire app serve` expects the /wrn/ prefix.
|
||||||
|
// That is OK in the production config where we can make it part of the the route,
|
||||||
|
// but in development it must be prepended since we don't want to make it part of services.app.server.
|
||||||
|
if (!base.startsWith(`/${config.services.app.prefix}`) && !base.endsWith(`/${config.services.app.prefix}`)) {
|
||||||
|
pathComponents.push(config.services.app.prefix.substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
pathComponents.push(`${name}@${version}`);
|
||||||
|
return pathComponents.join('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Name</TableCell>
|
||||||
|
<TableCell size="small">Version</TableCell>
|
||||||
|
<TableCell>Description</TableCell>
|
||||||
|
<TableCell>Link</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{records.sort(sorter).map(({ id, name, version, attributes: { displayName, publicUrl } }) => {
|
||||||
|
const link = getAppUrl({ id, name, version, publicUrl });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={id} size="small">
|
||||||
|
<TableCell monospace>{name}</TableCell>
|
||||||
|
<TableCell monospace>{version}</TableCell>
|
||||||
|
<TableCell>{displayName}</TableCell>
|
||||||
|
<TableCell monospace>
|
||||||
|
{link && (
|
||||||
|
<Link href={link} target={name}>{link}</Link>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppRecords;
|
42
packages/console-client/src/containers/panels/apps/Apps.js
Normal file
42
packages/console-client/src/containers/panels/apps/Apps.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
|
import Tab from '@material-ui/core/Tab';
|
||||||
|
|
||||||
|
import Panel from '../../../components/Panel';
|
||||||
|
import Toolbar from '../../../components/Toolbar';
|
||||||
|
|
||||||
|
import AppRecords from './AppRecords';
|
||||||
|
|
||||||
|
const TAB_RECORDS = 'records';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Apps = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [tab, setTab] = useState(TAB_RECORDS);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
toolbar={
|
||||||
|
<Toolbar>
|
||||||
|
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||||
|
<Tab value={TAB_RECORDS} label="Records" />
|
||||||
|
</Tabs>
|
||||||
|
</Toolbar>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tab === TAB_RECORDS && (
|
||||||
|
<AppRecords />
|
||||||
|
)}
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Apps;
|
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
|
import WNS_RECORDS from '../../../../gql/wns_records.graphql';
|
||||||
|
|
||||||
|
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
|
||||||
|
import Table from '../../../components/Table';
|
||||||
|
import TableCell from '../../../components/TableCell';
|
||||||
|
|
||||||
|
const AppRecords = () => {
|
||||||
|
const { config } = useContext(ConsoleContext);
|
||||||
|
const data = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||||
|
pollInterval: config.api.pollInterval,
|
||||||
|
variables: { type: 'wrn:bot' }
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const records = data.wns_records.json;
|
||||||
|
|
||||||
|
// TODO(burdon): Factor out.
|
||||||
|
const sorter = (a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Name</TableCell>
|
||||||
|
<TableCell size="small">Version</TableCell>
|
||||||
|
<TableCell>Description</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{records.sort(sorter).map(({ id, name, version, attributes: { displayName } }) => {
|
||||||
|
return (
|
||||||
|
<TableRow key={id} size="small">
|
||||||
|
<TableCell monospace>{name}</TableCell>
|
||||||
|
<TableCell monospace>{version}</TableCell>
|
||||||
|
<TableCell>{displayName}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppRecords;
|
42
packages/console-client/src/containers/panels/bots/Bots.js
Normal file
42
packages/console-client/src/containers/panels/bots/Bots.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
|
import Tab from '@material-ui/core/Tab';
|
||||||
|
|
||||||
|
import Panel from '../../../components/Panel';
|
||||||
|
import Toolbar from '../../../components/Toolbar';
|
||||||
|
|
||||||
|
import BotRecords from './BotRecords';
|
||||||
|
|
||||||
|
const TAB_RECORDS = 'records';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Apps = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [tab, setTab] = useState(TAB_RECORDS);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
toolbar={
|
||||||
|
<Toolbar>
|
||||||
|
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||||
|
<Tab value={TAB_RECORDS} label="Records" />
|
||||||
|
</Tabs>
|
||||||
|
</Toolbar>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tab === TAB_RECORDS && (
|
||||||
|
<BotRecords />
|
||||||
|
)}
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Apps;
|
@ -1,17 +1,17 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useQuery } from '@apollo/react-hooks';
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
import IPFS_STATUS from '../../../gql/ipfs_status.graphql';
|
import IPFS_STATUS from '../../../../gql/ipfs_status.graphql';
|
||||||
|
|
||||||
import { useQueryStatusReducer } from '../../hooks';
|
import { useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
import Json from '../../components/Json';
|
import Json from '../../../components/Json';
|
||||||
import Panel from '../../components/Panel';
|
import Panel from '../../../components/Panel';
|
||||||
import Toolbar from '../../components/Toolbar';
|
import Toolbar from '../../../components/Toolbar';
|
||||||
|
|
||||||
const IPFS = () => {
|
const IPFS = () => {
|
||||||
const data = useQueryStatusReducer(useQuery(IPFS_STATUS));
|
const data = useQueryStatusReducer(useQuery(IPFS_STATUS));
|
108
packages/console-client/src/containers/panels/wns/WNS.js
Normal file
108
packages/console-client/src/containers/panels/wns/WNS.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Mutation } from '@apollo/react-components';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import Tab from '@material-ui/core/Tab';
|
||||||
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
|
import TabContext from '@material-ui/lab/TabContext';
|
||||||
|
|
||||||
|
import WNS_ACTION from '../../../../gql/wns_action.graphql';
|
||||||
|
|
||||||
|
import ControlButtons from '../../../components/ControlButtons';
|
||||||
|
import Panel from '../../../components/Panel';
|
||||||
|
import Toolbar from '../../../components/Toolbar';
|
||||||
|
|
||||||
|
import WNSLog from './WNSLog';
|
||||||
|
import WNSRecords, { WNSRecordType } from './WNSRecords';
|
||||||
|
import WNSStatus from './WNSStatus';
|
||||||
|
|
||||||
|
const TAB_RECORDS = 'explorer';
|
||||||
|
const TAB_STATUS = 'records';
|
||||||
|
const TAB_LOG = 'log';
|
||||||
|
|
||||||
|
const useStyles = makeStyles(() => ({
|
||||||
|
expand: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
panel: {
|
||||||
|
display: 'flex',
|
||||||
|
overflow: 'hidden',
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
paper: {
|
||||||
|
display: 'flex',
|
||||||
|
overflow: 'hidden',
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const WNS = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [tab, setTab] = useState(TAB_RECORDS);
|
||||||
|
const [type, setType] = useState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
toolbar={
|
||||||
|
<Toolbar>
|
||||||
|
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||||
|
<Tab value={TAB_RECORDS} label="Records" />
|
||||||
|
<Tab value={TAB_STATUS} label="Status" />
|
||||||
|
<Tab value={TAB_LOG} label="Log" />
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
{tab === TAB_RECORDS && (
|
||||||
|
<WNSRecordType type={type} onChanged={setType} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className={classes.expand} />
|
||||||
|
|
||||||
|
<Mutation mutation={WNS_ACTION}>
|
||||||
|
{(action, { data }) => (
|
||||||
|
<div>
|
||||||
|
<ControlButtons
|
||||||
|
onStart={() => {
|
||||||
|
action({ variables: { command: 'start' } });
|
||||||
|
}}
|
||||||
|
onStop={() => {
|
||||||
|
action({ variables: { command: 'stop' } });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Mutation>
|
||||||
|
</Toolbar>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TabContext value={tab}>
|
||||||
|
{tab === TAB_RECORDS && (
|
||||||
|
<div className={classes.panel}>
|
||||||
|
<WNSRecords type={type} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tab === TAB_STATUS && (
|
||||||
|
<div className={classes.panel}>
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<WNSStatus />
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tab === TAB_LOG && (
|
||||||
|
<div className={classes.panel}>
|
||||||
|
<WNSLog />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabContext>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WNS;
|
26
packages/console-client/src/containers/panels/wns/WNSLog.js
Normal file
26
packages/console-client/src/containers/panels/wns/WNSLog.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
|
import WNS_LOG from '../../../../gql/wns_log.graphql';
|
||||||
|
|
||||||
|
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
|
import Log from '../../../components/Log';
|
||||||
|
|
||||||
|
const WNSLog = () => {
|
||||||
|
const { config } = useContext(ConsoleContext);
|
||||||
|
const data = useQueryStatusReducer(useQuery(WNS_LOG, { pollInterval: config.api.pollInterval }));
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Log log={data.wns_log.log} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WNSLog;
|
121
packages/console-client/src/containers/panels/wns/WNSRecords.js
Normal file
121
packages/console-client/src/containers/panels/wns/WNSRecords.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import get from 'lodash.get';
|
||||||
|
import moment from 'moment';
|
||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
|
||||||
|
import WNS_RECORDS from '../../../../gql/wns_records.graphql';
|
||||||
|
|
||||||
|
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
|
import Table from '../../../components/Table';
|
||||||
|
import TableCell from '../../../components/TableCell';
|
||||||
|
|
||||||
|
import PackageLink from '../../../components/PackageLink';
|
||||||
|
|
||||||
|
const types = [
|
||||||
|
{ key: null, label: 'ALL' },
|
||||||
|
{ key: 'wrn:xbox', label: 'XBox' },
|
||||||
|
{ key: 'wrn:resource', label: 'Resource' },
|
||||||
|
{ key: 'wrn:app', label: 'App' },
|
||||||
|
{ key: 'wrn:bot', label: 'Bot' },
|
||||||
|
{ key: 'wrn:type', label: 'Type' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
selected: {
|
||||||
|
color: theme.palette.text.primary
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const WNSRecordType = ({ type = types[0].key, onChanged }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ButtonGroup
|
||||||
|
disableRipple
|
||||||
|
disableFocusRipple
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
aria-label="text primary button group"
|
||||||
|
>
|
||||||
|
{types.map(t => (
|
||||||
|
<Button
|
||||||
|
key={t.key}
|
||||||
|
className={t.key === type && classes.selected}
|
||||||
|
onClick={() => onChanged(t.key)}
|
||||||
|
>
|
||||||
|
{t.label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</ButtonGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const WNSRecords = ({ type }) => {
|
||||||
|
const { config } = useContext(ConsoleContext);
|
||||||
|
const [{ sort, ascend }, setSort] = useState({ sort: 'type', ascend: true });
|
||||||
|
const data = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||||
|
pollInterval: config.api.pollInterval,
|
||||||
|
variables: { type }
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const records = data.wns_records.json;
|
||||||
|
|
||||||
|
// TODO(burdon): Factor out.
|
||||||
|
const sortBy = field => () => setSort({ sort: field, ascend: (field === sort ? !ascend : true) });
|
||||||
|
const sorter = (item1, item2) => {
|
||||||
|
const a = get(item1, sort);
|
||||||
|
const b = get(item2, sort);
|
||||||
|
const dir = ascend ? 1 : -1;
|
||||||
|
return (a < b) ? -1 * dir : (a > b) ? dir : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell onClick={sortBy('type')} size="small">Type</TableCell>
|
||||||
|
<TableCell onClick={sortBy('name')}>Name</TableCell>
|
||||||
|
<TableCell onClick={sortBy('version')} size="small">Version</TableCell>
|
||||||
|
<TableCell onClick={sortBy('attributes.displayName')}>Description</TableCell>
|
||||||
|
<TableCell onClick={sortBy('attributes.package')}>Package Hash</TableCell>
|
||||||
|
<TableCell onClick={sortBy('createTime')} size="small">Created</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{records.sort(sorter)
|
||||||
|
.map(({ id, type, name, version, createTime, attributes: { displayName, package: pkg } }) => (
|
||||||
|
<TableRow key={id} size="small">
|
||||||
|
<TableCell monospace>{type}</TableCell>
|
||||||
|
<TableCell monospace>{name}</TableCell>
|
||||||
|
<TableCell monospace>{version}</TableCell>
|
||||||
|
<TableCell>{displayName}</TableCell>
|
||||||
|
<TableCell title={JSON.stringify(pkg)} monospace>
|
||||||
|
{pkg && (
|
||||||
|
<PackageLink config={config} type={type} pkg={pkg} />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{moment.utc(createTime).fromNow()}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WNSRecords;
|
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useQuery } from '@apollo/react-hooks';
|
||||||
|
|
||||||
|
import WNS_STATUS from '../../../../gql/wns_status.graphql';
|
||||||
|
|
||||||
|
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||||
|
|
||||||
|
import Json from '../../../components/Json';
|
||||||
|
|
||||||
|
const WNSStatus = () => {
|
||||||
|
const { config } = useContext(ConsoleContext);
|
||||||
|
const data = useQueryStatusReducer(useQuery(WNS_STATUS, { pollInterval: config.api.pollInterval }));
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Json data={data.wns_status.json} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WNSStatus;
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
export * from './context';
|
export * from './context';
|
||||||
|
export * from './registry';
|
||||||
export * from './status';
|
export * from './status';
|
||||||
|
19
packages/console-client/src/hooks/registry.js
Normal file
19
packages/console-client/src/hooks/registry.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import { Registry } from '@wirelineio/registry-client';
|
||||||
|
|
||||||
|
import { getServiceUrl } from '../util/config';
|
||||||
|
|
||||||
|
export const useRegistry = (config) => {
|
||||||
|
const endpoint = getServiceUrl(config, 'wns.server', { absolute: true });
|
||||||
|
const registry = new Registry(endpoint);
|
||||||
|
|
||||||
|
return {
|
||||||
|
registry,
|
||||||
|
|
||||||
|
// TODO(burdon): Separate hook.
|
||||||
|
webui: getServiceUrl(config, 'wns.webui', { absolute: true })
|
||||||
|
};
|
||||||
|
};
|
@ -8,8 +8,12 @@ import { ConsoleContext } from './context';
|
|||||||
|
|
||||||
export const SET_STATUS = 'errors';
|
export const SET_STATUS = 'errors';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
export const useStatusReducer = () => {
|
export const useStatusReducer = () => {
|
||||||
const { state, dispatch } = useContext(ConsoleContext);
|
const { state, dispatch } = useContext(ConsoleContext);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
state[SET_STATUS] || {},
|
state[SET_STATUS] || {},
|
||||||
value => dispatch({ type: SET_STATUS, payload: value || { exceptions: [] } })
|
value => dispatch({ type: SET_STATUS, payload: value || { exceptions: [] } })
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
export * from './hooks';
|
export * from './hooks';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import AppsIcon from '@material-ui/icons/Apps';
|
import AppsIcon from '@material-ui/icons/Apps';
|
||||||
|
@ -1,34 +1,53 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
import { Registry } from '@wirelineio/registry-client';
|
import { Registry } from '@wirelineio/registry-client';
|
||||||
|
|
||||||
|
import { getServiceUrl } from './util/config';
|
||||||
|
|
||||||
const log = debug('dxos:console:client:resolvers');
|
const log = debug('dxos:console:client:resolvers');
|
||||||
|
|
||||||
//
|
/**
|
||||||
// Resolvers
|
* Resolvers
|
||||||
// https://www.apollographql.com/docs/tutorial/local-state/#local-resolvers
|
* https://www.apollographql.com/docs/tutorial/local-state/#local-resolvers
|
||||||
//
|
* @param config
|
||||||
|
*/
|
||||||
export const createResolvers = config => {
|
export const createResolvers = config => {
|
||||||
// TODO(burdon): Get route if served from xbox.
|
const endpoint = getServiceUrl(config, 'wns.server', { absolute: true });
|
||||||
const { services: { wns: { server } } } = config;
|
const registry = new Registry(endpoint);
|
||||||
|
|
||||||
const registry = new Registry(server);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Query: {
|
Query: {
|
||||||
wns_status: async () => {
|
wns_status: async () => {
|
||||||
log('Querying WNS...');
|
log('WNS status...');
|
||||||
|
const data = await registry.getStatus();
|
||||||
const status = await registry.getStatus();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
__typename: 'JSONResult',
|
__typename: 'JSONResult',
|
||||||
json: JSON.stringify(status)
|
json: data
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
wns_records: async (_, { type }) => {
|
||||||
|
log('WNS records...');
|
||||||
|
const data = await registry.queryRecords({ type });
|
||||||
|
|
||||||
|
return {
|
||||||
|
__typename: 'JSONResult',
|
||||||
|
json: data
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
wns_log: async () => {
|
||||||
|
log('WNS log...');
|
||||||
|
|
||||||
|
// TODO(burdon): Use Registry API rather than from CLI?
|
||||||
|
return {
|
||||||
|
__typename: 'JSONLog',
|
||||||
|
log: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,36 @@ export const createTheme = (theme) => createMuiTheme({
|
|||||||
props: {
|
props: {
|
||||||
MuiButtonBase: {
|
MuiButtonBase: {
|
||||||
disableRipple: true
|
disableRipple: true
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
MuiFilledInput: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiFormControl: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiFormHelperText: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiIconButton: {
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
MuiInputBase: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiInputLabel: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiTable: {
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
MuiTextField: {
|
||||||
|
margin: 'dense'
|
||||||
|
},
|
||||||
|
MuiToolbar: {
|
||||||
|
variant: 'dense'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
40
packages/console-client/src/util/config.js
Normal file
40
packages/console-client/src/util/config.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import assert from 'assert';
|
||||||
|
import buildUrl from 'build-url';
|
||||||
|
import get from 'lodash.get';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the service URL that can be used by the client.
|
||||||
|
* @param {Object} config
|
||||||
|
* @param {string} service
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {string} [options.path]
|
||||||
|
* @param {boolean} [options.absolute]
|
||||||
|
* @returns {string|*}
|
||||||
|
*/
|
||||||
|
export const getServiceUrl = (config, service, options = {}) => {
|
||||||
|
const { path, absolute = false } = options;
|
||||||
|
const { routes, services } = config;
|
||||||
|
|
||||||
|
const appendPath = (url) => buildUrl(url, { path });
|
||||||
|
|
||||||
|
// Relative route.
|
||||||
|
const routePath = get(routes, service);
|
||||||
|
if (routePath) {
|
||||||
|
if (absolute) {
|
||||||
|
assert(typeof window !== 'undefined');
|
||||||
|
return buildUrl(window.location.origin, { path: appendPath(routePath) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relative.
|
||||||
|
return appendPath(routePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absolute service path.
|
||||||
|
const serviceUrl = get(services, service);
|
||||||
|
assert(serviceUrl, `Invalid service definition: ${service}`);
|
||||||
|
return appendPath(serviceUrl);
|
||||||
|
};
|
42
packages/console-client/src/util/config.test.js
Normal file
42
packages/console-client/src/util/config.test.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 DxOS.org
|
||||||
|
//
|
||||||
|
|
||||||
|
import { getServiceUrl } from './config';
|
||||||
|
|
||||||
|
// noinspection JSConstantReassignment
|
||||||
|
global.window = {
|
||||||
|
location: {
|
||||||
|
origin: 'http://localhost'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
services: {
|
||||||
|
foo: {
|
||||||
|
server: 'http://localhost:3000/foo'
|
||||||
|
},
|
||||||
|
|
||||||
|
bar: {
|
||||||
|
server: 'http://localhost:3000/bar'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
routes: {
|
||||||
|
foo: {
|
||||||
|
server: '/foo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test('getServiceUrl', () => {
|
||||||
|
expect(() => getServiceUrl({}, 'foo.server')).toThrow();
|
||||||
|
|
||||||
|
expect(getServiceUrl(config, 'foo.server')).toEqual('/foo');
|
||||||
|
expect(getServiceUrl(config, 'foo.server', { path: '/123' })).toEqual('/foo/123');
|
||||||
|
expect(getServiceUrl(config, 'foo.server', { path: '/123', absolute: true })).toEqual('http://localhost/foo/123');
|
||||||
|
|
||||||
|
expect(getServiceUrl(config, 'bar.server')).toEqual('http://localhost:3000/bar');
|
||||||
|
expect(getServiceUrl(config, 'bar.server', { path: '/123' })).toEqual('http://localhost:3000/bar/123');
|
||||||
|
expect(getServiceUrl(config, 'bar.server', { path: '/123', absolute: true })).toEqual('http://localhost:3000/bar/123');
|
||||||
|
});
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"name": "@dxos/console-client",
|
"name": "@dxos/console-client",
|
||||||
"buildDate": "2020-05-25T02:29:08.942Z",
|
"buildDate": "2020-05-25T22:04:20.163Z",
|
||||||
"version": "1.0.0-beta.0"
|
"version": "1.0.0-beta.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2020 DxOS
|
# Copyright 2020 DxOS.org
|
||||||
#
|
#
|
||||||
|
|
||||||
type JSONResult {
|
type JSONResult {
|
||||||
@ -25,14 +25,16 @@ type Result {
|
|||||||
#
|
#
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
system_status: Status
|
system_status: Status!
|
||||||
ipfs_status: JSONResult
|
ipfs_status: JSONResult!
|
||||||
wns_status: JSONResult
|
wns_status: JSONResult!
|
||||||
wns_log: Log
|
# TODO(burdon): Import WNS schema!
|
||||||
|
wns_records(type: String): JSONResult!
|
||||||
|
wns_log: Log!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
wns_action(command: String!): Result
|
wns_action(command: String!): Result!
|
||||||
}
|
}
|
||||||
|
|
||||||
schema {
|
schema {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2020 DxOS
|
// Copyright 2020 DxOS.org
|
||||||
//
|
//
|
||||||
|
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
@ -9,12 +9,13 @@ import { version } from '../package.json';
|
|||||||
|
|
||||||
const log = debug('dxos:console:server:resolvers');
|
const log = debug('dxos:console:server:resolvers');
|
||||||
|
|
||||||
//
|
|
||||||
// Resolvers
|
|
||||||
//
|
|
||||||
|
|
||||||
const timestamp = () => new Date().toUTCString();
|
const timestamp = () => new Date().toUTCString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolvers
|
||||||
|
* https://www.apollographql.com/docs/graphql-tools/resolvers
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
export const createResolvers = config => ({
|
export const createResolvers = config => ({
|
||||||
Mutation: {
|
Mutation: {
|
||||||
//
|
//
|
||||||
|
@ -4672,6 +4672,11 @@ buffer@^5.2.1, buffer@^5.4.2, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0:
|
|||||||
base64-js "^1.0.2"
|
base64-js "^1.0.2"
|
||||||
ieee754 "^1.1.4"
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
|
build-url@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/build-url/-/build-url-2.0.0.tgz#7bdd4045e51caa96c1586990e4ca514937598fc2"
|
||||||
|
integrity sha512-LYvvOlDc9jT07wFXTQTKoQLYaXIJriVl/DgatTsSzY963+ip1O7M6G/jWBrlKKJ1L7HGD3oK+WykmOvbcSYXlQ==
|
||||||
|
|
||||||
builtin-status-codes@^3.0.0:
|
builtin-status-codes@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
|
Loading…
Reference in New Issue
Block a user