React router.

This commit is contained in:
richburdon
2020-05-23 20:05:04 -04:00
parent 3057bc0f1d
commit 9eb1d0de16
18 changed files with 403 additions and 76 deletions
+6
View File
@@ -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": {
+16 -16
View File
@@ -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>
+20 -9
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright 2020 Wireline, Inc.
// Copyright 2020 DxOS
//
import { createContext } from 'react';
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright 2020 Wireline, Inc.
// Copyright 2020 DxOS
//
export * from './context';
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright 2019 Wireline, Inc.
// Copyright 2019 DxOS
//
import { useContext } from 'react';
+8 -8
View File
@@ -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 -1
View File
@@ -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"
}
}