forked from cerc-io/laconic-console
React router.
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
"@apollo/react-hooks": "^3.1.5",
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"@dxos/gem-core": "^1.0.0-beta.11",
|
||||
"@dxos/react-ux": "^1.0.0-beta.20",
|
||||
"@material-ui/core": "^4.10.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"apollo-cache-inmemory": "^1.6.6",
|
||||
@@ -39,8 +40,13 @@
|
||||
"debug": "^4.1.1",
|
||||
"graphql-tag": "^2.10.3",
|
||||
"lodash.defaultsdeep": "^4.6.1",
|
||||
"lodash.isobject": "^3.0.2",
|
||||
"lodash.omit": "^4.5.0",
|
||||
"lodash.transform": "^4.6.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"source-map-support": "^0.5.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -6,22 +6,22 @@ import { ApolloClient } from 'apollo-client';
|
||||
import { createHttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
|
||||
import config from '../config.json';
|
||||
|
||||
const defaultServer = `${window.location.protocol}//${window.location.hostname}`;
|
||||
|
||||
const { server = defaultServer, port = 80, path = '/graphql' } = config;
|
||||
|
||||
// TODO(burdon): Authentication: send signed message to server (from client wallet).
|
||||
// https://www.apollographql.com/docs/react/networking/authentication/
|
||||
|
||||
// https://www.apollographql.com/docs/link/
|
||||
const link = createHttpLink({
|
||||
uri: `${server}:${port}${path}`
|
||||
});
|
||||
|
||||
// https://www.apollographql.com/docs/react/api/apollo-client/
|
||||
export const client = new ApolloClient({
|
||||
cache: new InMemoryCache(),
|
||||
link
|
||||
});
|
||||
export const clientFactory = config => {
|
||||
const { server = defaultServer, port = 80, path = '/graphql' } = config;
|
||||
|
||||
// TODO(burdon): Authentication: send signed message to server (from client wallet).
|
||||
// https://www.apollographql.com/docs/react/networking/authentication/
|
||||
|
||||
// https://www.apollographql.com/docs/link/
|
||||
const link = createHttpLink({
|
||||
uri: `${server}:${port}${path}`
|
||||
});
|
||||
|
||||
return new ApolloClient({
|
||||
cache: new InMemoryCache(),
|
||||
link
|
||||
});
|
||||
};
|
||||
|
||||
@@ -45,7 +45,7 @@ const AppBar = ({ config }) => {
|
||||
<>
|
||||
<MuiAppBar position="fixed">
|
||||
<Toolbar variant="dense">
|
||||
<MuiLink href="/console">
|
||||
<MuiLink href="/">
|
||||
<div className={classes.logo}>
|
||||
<DxOSIcon />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import { JsonTreeView } from '@dxos/react-ux';
|
||||
|
||||
import { ConsoleContext } from '../hooks';
|
||||
|
||||
const Config = () => {
|
||||
const { config } = useContext(ConsoleContext);
|
||||
|
||||
return (
|
||||
<JsonTreeView data={config} />
|
||||
);
|
||||
};
|
||||
|
||||
export default Config;
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
import isObject from 'lodash.isobject';
|
||||
import omit from 'lodash.omit';
|
||||
import transform from 'lodash.transform';
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
import { JsonTreeView } from '@dxos/react-ux';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
root: {
|
||||
flex: 1
|
||||
}
|
||||
}));
|
||||
|
||||
const removeTypename = data => transform(data, (result, value, key) => {
|
||||
result[key] = isObject(value) && '__typename' in value ? omit(value, '__typename') : value;
|
||||
});
|
||||
|
||||
const Json = ({ data }) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<JsonTreeView className={classes.root} data={removeTypename(data)} />
|
||||
);
|
||||
};
|
||||
|
||||
export default Json;
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
|
||||
import { FullScreen } from '@dxos/gem-core';
|
||||
|
||||
import config from '../../config.json';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import AppBar from './AppBar';
|
||||
import Sidebar from './Sidebar';
|
||||
@@ -28,7 +28,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
width: 200,
|
||||
width: 180,
|
||||
borderRight: `1px solid ${theme.palette.primary.dark}`
|
||||
},
|
||||
main: {
|
||||
@@ -43,7 +43,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
|
||||
const Layout = ({ children }) => {
|
||||
const classes = useStyles();
|
||||
const { modules } = useContext(ConsoleContext);
|
||||
const { config, modules } = useContext(ConsoleContext);
|
||||
|
||||
return (
|
||||
<FullScreen>
|
||||
@@ -53,9 +53,9 @@ const Layout = ({ children }) => {
|
||||
<div className={classes.sidebar}>
|
||||
<Sidebar modules={modules} />
|
||||
</div>
|
||||
<div className={classes.main}>
|
||||
<Paper className={classes.main}>
|
||||
{children}
|
||||
</div>
|
||||
</Paper>
|
||||
</div>
|
||||
<div className={classes.footer}>
|
||||
<StatusBar />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { useHistory, useParams } from 'react-router';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
@@ -23,6 +24,7 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
|
||||
icon: {
|
||||
minWidth: 40,
|
||||
color: theme.palette.grey[500]
|
||||
},
|
||||
|
||||
@@ -33,16 +35,17 @@ const useStyles = makeStyles(theme => ({
|
||||
|
||||
const Sidebar = ({ modules: { services, settings } }) => {
|
||||
const classes = useStyles();
|
||||
const history = useHistory();
|
||||
const { module } = useParams();
|
||||
|
||||
// TODO(burdon): Change.
|
||||
const router = {};
|
||||
const isSelected = path => path === `/${module}`;
|
||||
|
||||
const Modules = ({ modules }) => (
|
||||
<List aria-label="items" className={classes.list}>
|
||||
{modules.map(({ path, title, icon: Icon }) => (
|
||||
<ListItem button selected={path === router.pathname} key={path} onClick={() => router.push(path)}>
|
||||
<ListItem button selected={isSelected(path)} key={path} onClick={() => history.push(path)}>
|
||||
<ListItemIcon classes={{ root: classes.icon }}>
|
||||
<Icon className={clsx(classes.icon, path === router.pathname && classes.selected)} />
|
||||
<Icon className={clsx(classes.icon, isSelected(path) && classes.selected)} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={title} />
|
||||
</ListItem>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2020 Wireline, Inc.
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
import React, { useEffect, useReducer } from 'react';
|
||||
@@ -27,12 +27,13 @@ const appReducer = (state, action) => ({
|
||||
* Wraps children with a React ErrorBoundary component, which catches runtime errors and enables reset.
|
||||
*
|
||||
* @param {function} children
|
||||
* @param {function} modules
|
||||
* @param {Object} config
|
||||
* @param {Object} modules
|
||||
* @param {Object} [initialState]
|
||||
* @param {function} [errorHandler]
|
||||
* @returns {function}
|
||||
*/
|
||||
const ConsoleContextProvider = ({ children, modules, initialState = {}, errorHandler }) => {
|
||||
const ConsoleContextProvider = ({ children, config, modules, initialState = {}, errorHandler }) => {
|
||||
const [state, dispatch] = useReducer(appReducer, defaultsDeep({}, initialState, defaultState));
|
||||
|
||||
const { errors: { exceptions = [] } = {} } = state[SET_STATUS] || {};
|
||||
@@ -52,7 +53,7 @@ const ConsoleContextProvider = ({ children, modules, initialState = {}, errorHan
|
||||
}
|
||||
|
||||
return (
|
||||
<ConsoleContext.Provider value={{ modules, state, dispatch }}>
|
||||
<ConsoleContext.Provider value={{ config, modules, state, dispatch }}>
|
||||
<ErrorBoundary>
|
||||
{children}
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
import React from 'react';
|
||||
import { HashRouter, Redirect, Route, Switch } from 'react-router-dom';
|
||||
import { ApolloProvider } from '@apollo/react-hooks';
|
||||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
@@ -10,23 +11,33 @@ import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import config from '../../config.json';
|
||||
|
||||
import { createTheme } from '../theme';
|
||||
import { client } from '../client';
|
||||
import { clientFactory } from '../client';
|
||||
import modules from '../modules';
|
||||
|
||||
import Config from '../components/Config';
|
||||
import Layout from '../components/Layout';
|
||||
|
||||
import ConsoleContextProvider from './ConsoleContextProvider';
|
||||
|
||||
import Status from './Status';
|
||||
|
||||
import Layout from '../components/Layout';
|
||||
import ConsoleContextProvider from './ConsoleContextProvider';
|
||||
|
||||
const Main = () => {
|
||||
return (
|
||||
<ApolloProvider client={client}>
|
||||
<ConsoleContextProvider modules={modules}>
|
||||
<ApolloProvider client={clientFactory(config)}>
|
||||
<ConsoleContextProvider config={config} modules={modules}>
|
||||
<ThemeProvider theme={createTheme(config.app.theme)}>
|
||||
<CssBaseline />
|
||||
<Layout>
|
||||
<Status />
|
||||
</Layout>
|
||||
<HashRouter>
|
||||
<Switch>
|
||||
<Route path="/:module">
|
||||
<Layout>
|
||||
<Route path="/status" component={Status} />
|
||||
<Route path="/config" component={Config} />
|
||||
</Layout>
|
||||
</Route>
|
||||
<Redirect to="/status" />
|
||||
</Switch>
|
||||
</HashRouter>
|
||||
</ThemeProvider>
|
||||
</ConsoleContextProvider>
|
||||
</ApolloProvider>
|
||||
|
||||
@@ -2,13 +2,22 @@
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
import isObject from 'lodash.isobject';
|
||||
import omit from 'lodash.omit';
|
||||
import transform from 'lodash.transform';
|
||||
import React from 'react';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
|
||||
import Json from '../components/Json';
|
||||
|
||||
import { useQueryStatusReducer } from '../hooks';
|
||||
|
||||
import QUERY_STATUS from '../../gql/status.graphql';
|
||||
|
||||
const removeTypename = data => transform(data, (result, value, key) => {
|
||||
result[key] = isObject(value) && '__typename' in value ? omit(value, '__typename') : value;
|
||||
});
|
||||
|
||||
const Status = () => {
|
||||
const data = useQueryStatusReducer(useQuery(QUERY_STATUS, { pollInterval: 5000 }));
|
||||
if (!data) {
|
||||
@@ -16,9 +25,7 @@ const Status = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<pre>
|
||||
{JSON.stringify(data, undefined, 2)}
|
||||
</pre>
|
||||
<Json data={removeTypename(data)} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import LoadingIcon from '@material-ui/icons/Wifi';
|
||||
@@ -12,9 +12,8 @@ import grey from '@material-ui/core/colors/grey';
|
||||
import green from '@material-ui/core/colors/green';
|
||||
import red from '@material-ui/core/colors/red';
|
||||
|
||||
import config from '../../config.json';
|
||||
import { version } from '../../package.json';
|
||||
import { useStatusReducer } from '../hooks';
|
||||
import { ConsoleContext, useStatusReducer } from '../hooks';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
@@ -56,6 +55,7 @@ const StatusBar = () => {
|
||||
const classes = useStyles();
|
||||
const [{ loading, error }] = useStatusReducer();
|
||||
const [isLoading, setLoading] = useState(loading);
|
||||
const { config } = useContext(ConsoleContext);
|
||||
|
||||
useEffect(() => {
|
||||
let t;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2020 Wireline, Inc.
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
import { createContext } from 'react';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2020 Wireline, Inc.
|
||||
// Copyright 2020 DxOS
|
||||
//
|
||||
|
||||
export * from './context';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2019 Wireline, Inc.
|
||||
// Copyright 2019 DxOS
|
||||
//
|
||||
|
||||
import { useContext } from 'react';
|
||||
|
||||
@@ -14,32 +14,32 @@ import ServicesIcon from '@material-ui/icons/Storage';
|
||||
export default {
|
||||
services: [
|
||||
{
|
||||
path: '/console/status',
|
||||
path: '/status',
|
||||
title: 'Status',
|
||||
icon: StatsIcon
|
||||
},
|
||||
{
|
||||
path: '/console/wns',
|
||||
path: '/wns',
|
||||
title: 'WNS',
|
||||
icon: RegistryIcon
|
||||
},
|
||||
{
|
||||
path: '/console/apps',
|
||||
path: '/apps',
|
||||
title: 'Apps',
|
||||
icon: AppsIcon
|
||||
},
|
||||
{
|
||||
path: '/console/bots',
|
||||
path: '/bots',
|
||||
title: 'Bots',
|
||||
icon: BotsIcon
|
||||
},
|
||||
{
|
||||
path: '/console/signal',
|
||||
path: '/signal',
|
||||
title: 'Signal Server',
|
||||
icon: SignalIcon
|
||||
},
|
||||
{
|
||||
path: '/console/ipfs',
|
||||
path: '/ipfs',
|
||||
title: 'IPFS',
|
||||
icon: IPFSIcon
|
||||
}
|
||||
@@ -47,12 +47,12 @@ export default {
|
||||
|
||||
settings: [
|
||||
{
|
||||
path: '/console/metadata',
|
||||
path: '/metadata',
|
||||
title: 'Metadata',
|
||||
icon: ServicesIcon
|
||||
},
|
||||
{
|
||||
path: '/console/config',
|
||||
path: '/config',
|
||||
title: 'Config',
|
||||
icon: ConfigIcon
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"name": "@dxos/console-client",
|
||||
"buildDate": "2020-05-23T22:14:40.153Z",
|
||||
"buildDate": "2020-05-23T23:08:59.032Z",
|
||||
"version": "1.0.0-beta.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user