diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0891d4d..5455058 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- [x] Fixed hook that causes 100x rerendering.
+- [x] Logging.
+- [x] Error handling.
- [x] Table sorting.
- [x] Version check.
- [x] Fix JsonTree (yarn link).
@@ -23,9 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [x] Monorepo for client/server.
- [x] Basic React/Apollo component.
-## Tasks
-
-### POC
+### Next
- [ ] Webpack and dynamic config
- [ ] Complete WNS functionality
@@ -38,8 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [ ] Signal
- [ ] Metadata
-### Next
-
- [ ] https://github.com/standard/standardx (JSX)
- [ ] Client/server API abstraction (error handler, etc.)
- [ ] Port dashboard API calls (resolve config first).
diff --git a/packages/console-client/package.json b/packages/console-client/package.json
index 0b8ef00..5fe81c3 100644
--- a/packages/console-client/package.json
+++ b/packages/console-client/package.json
@@ -30,8 +30,9 @@
"@apollo/react-components": "^3.1.5",
"@apollo/react-hooks": "^3.1.5",
"@babel/runtime": "^7.8.7",
+ "@dxos/debug": "^1.0.0-beta.20",
"@dxos/gem-core": "^1.0.0-beta.11",
- "@dxos/react-ux": "^1.0.0-beta.20",
+ "@dxos/react-ux": "^1.0.0-beta.37",
"@material-ui/core": "^4.10.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.54",
diff --git a/packages/console-client/src/components/Error.js b/packages/console-client/src/components/Error.js
index 93c07c7..deb5215 100644
--- a/packages/console-client/src/components/Error.js
+++ b/packages/console-client/src/components/Error.js
@@ -2,7 +2,7 @@
// Copyright 2020 DxOS.org
//
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Alert from '@material-ui/lab/Alert';
import AlertTitle from '@material-ui/lab/AlertTitle';
@@ -10,30 +10,37 @@ import Snackbar from '@material-ui/core/Snackbar';
const useStyles = makeStyles(() => ({
root: {
- marginBottom: 60
+ marginBottom: 48
+ },
+
+ alert: {
+ minWidth: 400
}
}));
-const Error = ({ message, ...rest }) => {
+const Error = ({ error, ...rest }) => {
const classes = useStyles();
- if (!message) {
- return null;
- }
+ const [message, setMessage] = useState(error);
- const messages = Array.isArray(message) ? message : [message];
+ useEffect(() => {
+ setMessage(error ? error.message || String(error) : null);
+ }, [error]);
+
+ const handleClose = () => {
+ setMessage(null);
+ };
return (
-
+
Error
- {messages.map((message, i) => (
- {message}
- ))}
+ {message}
);
diff --git a/packages/console-client/src/components/Log.js b/packages/console-client/src/components/Log.js
index b25c6f4..c65644e 100644
--- a/packages/console-client/src/components/Log.js
+++ b/packages/console-client/src/components/Log.js
@@ -4,31 +4,28 @@
import clsx from 'clsx';
import moment from 'moment';
-import React, { Fragment } from 'react';
+import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
flex: 1,
- flexDirection: 'column',
overflow: 'hidden'
},
- container: {
+ log: {
display: 'flex',
// Pin to bottom (render in time order).
flexDirection: 'column-reverse',
- flex: 1,
- overflowX: 'scroll',
- overflowY: 'scroll'
- },
-
- log: {
+ overflow: 'scroll',
padding: theme.spacing(1),
- fontSize: 16,
- fontFamily: 'monospace',
- whiteSpace: 'nowrap'
+
+ '& div': {
+ fontSize: 16,
+ fontFamily: 'monospace',
+ whiteSpace: 'nowrap'
+ }
},
level: {
@@ -50,7 +47,7 @@ const useStyles = makeStyles(theme => ({
}
}));
-const Log = ({ log = [], onClear }) => {
+const Log = ({ log = [] }) => {
const classes = useStyles();
const levels = {
@@ -91,11 +88,11 @@ const Log = ({ log = [], onClear }) => {
const pkg = levels[level] ? '' : `[${level}]: `;
message = (
-
+ <>
{datetime}
{label || level}
{pkg}{text}
-
+ >
);
return true;
@@ -111,10 +108,8 @@ const Log = ({ log = [], onClear }) => {
return (
-
-
- {log.reverse().map((line, i) => )}
-
+
+ {log.map((line, i) => )}
);
diff --git a/packages/console-client/src/components/PackageLink.js b/packages/console-client/src/components/PackageLink.js
index 1bca09d..27223cc 100644
--- a/packages/console-client/src/components/PackageLink.js
+++ b/packages/console-client/src/components/PackageLink.js
@@ -2,7 +2,7 @@
// Copyright 2020 DxOS.org.org
//
-import React, { Fragment } from 'react';
+import React from 'react';
import Link from '@material-ui/core/Link';
import { getServiceUrl } from '../util/config';
@@ -14,7 +14,6 @@ import { getServiceUrl } from '../util/config';
* @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}` });
@@ -25,28 +24,26 @@ const PackageLink = ({ config, type, pkg }) => {
switch (type) {
case 'wrn:bot': {
const packageLinks = [];
- Object.keys(pkg).forEach(platform => {
+ Object.keys(pkg).forEach((platform, i) => {
Object.keys(pkg[platform]).forEach(arch => {
const cid = pkg[platform][arch];
const ipfsUrl = getServiceUrl(config, 'ipfs.gateway', { path: `${cid}` });
packageLinks.push(
-
-
- {platform}/{arch}: {cid}
-
-
+
+ {platform}/{arch}: {cid}
+
);
});
});
return (
-
{packageLinks}
+ <>{packageLinks}>
);
}
}
diff --git a/packages/console-client/src/containers/ConsoleContextProvider.js b/packages/console-client/src/containers/ConsoleContextProvider.js
index 1d08ee5..2095147 100644
--- a/packages/console-client/src/containers/ConsoleContextProvider.js
+++ b/packages/console-client/src/containers/ConsoleContextProvider.js
@@ -7,7 +7,7 @@ import defaultsDeep from 'lodash.defaultsdeep';
import ErrorBoundary from '../components/ErrorBoundary';
-import { ConsoleContext, statusReducer, SET_STATUS } from '../hooks';
+import { ConsoleContext, statusReducer, STATUS, SET_STATUS } from '../hooks';
const defaultState = {};
@@ -18,8 +18,7 @@ const defaultState = {};
* @param {string} action
*/
const appReducer = (state, action) => ({
- // TODO(burdon): Key shouldn't be same as action type.
- [SET_STATUS]: statusReducer(state[SET_STATUS], action)
+ [STATUS]: statusReducer(state[STATUS], action)
});
/**
@@ -36,8 +35,6 @@ const appReducer = (state, action) => ({
const ConsoleContextProvider = ({ children, config, modules, initialState = {}, errorHandler }) => {
const [state, dispatch] = useReducer(appReducer, defaultsDeep({}, initialState, defaultState));
- const { errors: { exceptions = [] } = {} } = state[SET_STATUS] || {};
-
// Bind the error handler.
if (errorHandler) {
useEffect(() => {
@@ -45,7 +42,7 @@ const ConsoleContextProvider = ({ children, config, modules, initialState = {},
dispatch({
type: SET_STATUS,
payload: {
- exceptions: [error, ...exceptions]
+ error
}
});
});
diff --git a/packages/console-client/src/containers/Main.js b/packages/console-client/src/containers/Main.js
index 9ce9d12..d0d3b9a 100644
--- a/packages/console-client/src/containers/Main.js
+++ b/packages/console-client/src/containers/Main.js
@@ -9,6 +9,8 @@ import { ApolloProvider } from '@apollo/react-hooks';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
+import { ErrorHandler } from '@dxos/debug';
+
import config from '../../config.yml';
import { build } from '../../version.json';
@@ -33,13 +35,16 @@ Object.assign(config, { build });
debug.enable(config.system.debug);
+// Global error handler.
+const errorHandler = new ErrorHandler();
+
/**
* Root application.
*/
const Main = () => {
return (
-
+
diff --git a/packages/console-client/src/containers/StatusBar.js b/packages/console-client/src/containers/StatusBar.js
index 1a8da72..f32d40a 100644
--- a/packages/console-client/src/containers/StatusBar.js
+++ b/packages/console-client/src/containers/StatusBar.js
@@ -18,6 +18,8 @@ import red from '@material-ui/core/colors/red';
import { ConsoleContext, useStatusReducer } from '../hooks';
+import Error from '../components/Error';
+
import VersionCheck from './VersionCheck';
const useStyles = makeStyles((theme) => ({
@@ -30,17 +32,15 @@ const useStyles = makeStyles((theme) => ({
color: grey[400]
},
left: {
+ display: 'flex',
width: 160
},
right: {
+ display: 'flex',
width: 160,
- textAlign: 'right'
+ justifyContent: 'flex-end'
},
center: {
- flex: 1,
- textAlign: 'center'
- },
- info: {
display: 'flex',
fontFamily: 'monospace',
fontSize: 'large',
@@ -90,7 +90,7 @@ const StatusBar = () => {
const StatusIcon = ({ error }) => {
if (error) {
return (
-
+
);
} else {
return (
@@ -100,24 +100,28 @@ const StatusBar = () => {
};
return (
-
-
+ <>
+
+
-
-
{name} ({version})
-
{moment(buildDate).format('L')}
-
-
+
+
{name} ({version})
+
{moment(buildDate).format('L')}
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+ >
);
};
diff --git a/packages/console-client/src/containers/panels/wns/WNS.js b/packages/console-client/src/containers/panels/wns/WNS.js
index dc6e529..95fdaa5 100644
--- a/packages/console-client/src/containers/panels/wns/WNS.js
+++ b/packages/console-client/src/containers/panels/wns/WNS.js
@@ -20,8 +20,8 @@ import WNSLog from './WNSLog';
import WNSRecords, { WNSRecordType } from './WNSRecords';
import WNSStatus from './WNSStatus';
-const TAB_RECORDS = 'explorer';
-const TAB_STATUS = 'records';
+const TAB_RECORDS = 'records';
+const TAB_STATUS = 'status';
const TAB_LOG = 'log';
const useStyles = makeStyles(() => ({
diff --git a/packages/console-client/src/hooks/status.js b/packages/console-client/src/hooks/status.js
index 96cdf42..5bc0e21 100644
--- a/packages/console-client/src/hooks/status.js
+++ b/packages/console-client/src/hooks/status.js
@@ -2,20 +2,21 @@
// Copyright 2019 DxOS
//
-import { useContext } from 'react';
+import { useContext, useEffect } from 'react';
import { ConsoleContext } from './context';
-export const SET_STATUS = 'errors';
+export const STATUS = 'xxx';
+export const SET_STATUS = 'set.status';
/**
- *
+ * Dispatcher for app status.
*/
export const useStatusReducer = () => {
const { state, dispatch } = useContext(ConsoleContext);
return [
- state[SET_STATUS] || {},
+ state[STATUS] || {},
value => dispatch({ type: SET_STATUS, payload: value || { exceptions: [] } })
];
};
@@ -26,13 +27,15 @@ export const useStatusReducer = () => {
export const useQueryStatusReducer = ({ loading, error, data }) => {
const [, setStatus] = useStatusReducer();
- if (loading) {
- setTimeout(() => setStatus({ loading }));
- }
+ useEffect(() => {
+ if (loading) {
+ setTimeout(() => setStatus({ loading }));
+ }
- if (error) {
- setTimeout(() => setStatus({ error }));
- }
+ if (error) {
+ setTimeout(() => setStatus({ error }));
+ }
+ }, [loading, error]);
return data;
};
diff --git a/packages/console-client/src/resolvers.js b/packages/console-client/src/resolvers.js
index 2447af4..82cbbd7 100644
--- a/packages/console-client/src/resolvers.js
+++ b/packages/console-client/src/resolvers.js
@@ -12,6 +12,8 @@ const log = debug('dxos:console:client:resolvers');
const timestamp = () => new Date().toUTCString();
+const MAX_LOG_LENGTH = 200;
+
/**
* Resolvers
* https://www.apollographql.com/docs/tutorial/local-state/#local-resolvers
@@ -21,6 +23,11 @@ export const createResolvers = config => {
const endpoint = getServiceUrl(config, 'wns.server', { absolute: true });
const registry = new Registry(endpoint);
+ // TODO(burdon): Errors swallowed!
+
+ // Oldest to latest.
+ let cachedLog = [];
+
return {
Query: {
wns_status: async () => {
@@ -52,13 +59,29 @@ export const createResolvers = config => {
wns_log: async () => {
log('WNS log...');
- // TODO(burdon): Cache and merge previous state.
const data = await registry.getLogs();
+ // TODO(burdon): Bug returns blank line at end.
+ const filtered = data.map(line => line).filter(Boolean);
+
+ // Cache and merge previous state.
+ let i = filtered.findIndex(line => line === cachedLog[cachedLog.length - 1]);
+ if (i === -1) {
+ cachedLog = filtered;
+ } else {
+ i++;
+ for (; i < filtered.length - 1; i++) {
+ cachedLog.push(filtered[i]);
+ }
+
+ // Trim.
+ cachedLog.splice(0, cachedLog.length - MAX_LOG_LENGTH);
+ }
+
return {
__typename: 'JSONLog',
timestamp: timestamp(),
- log: data
+ log: [...cachedLog].reverse()
};
}
}
diff --git a/packages/console-client/version.json b/packages/console-client/version.json
index 9e9a3ed..1c14713 100644
--- a/packages/console-client/version.json
+++ b/packages/console-client/version.json
@@ -1,7 +1,7 @@
{
"build": {
"name": "@dxos/console-client",
- "buildDate": "2020-05-26T17:38:45.688Z",
+ "buildDate": "2020-05-27T01:16:27.565Z",
"version": "1.0.0-beta.0"
}
}
diff --git a/packages/console-server/src/resolvers.js b/packages/console-server/src/resolvers.js
index a7364e2..de5a764 100644
--- a/packages/console-server/src/resolvers.js
+++ b/packages/console-server/src/resolvers.js
@@ -15,6 +15,10 @@ const timestamp = () => new Date().toUTCString();
* @param config
*/
export const createResolvers = config => ({
+
+ // TODO(burdon): Auth mutations.
+ // https://www.apollographql.com/docs/apollo-server/data/errors/#codes
+
Mutation: {
//
// WNS
diff --git a/yarn.lock b/yarn.lock
index e635012..b6c2a74 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1179,6 +1179,13 @@
dependencies:
debug "^4.1.1"
+"@dxos/debug@^1.0.0-beta.37":
+ version "1.0.0-beta.37"
+ resolved "https://registry.yarnpkg.com/@dxos/debug/-/debug-1.0.0-beta.37.tgz#0fc3a1d9d0b2616c5c22da6fcea7c369610ec282"
+ integrity sha512-65jOaqMrjv1Comepqq2U0k9olpAiKtk6pVEnhZHb+FutPMnjIkA+TPedNfTpxWQEs3MpG0IVyj64JugGl2KhQA==
+ dependencies:
+ debug "^4.1.1"
+
"@dxos/gem-core@^1.0.0-beta.11":
version "1.0.0-beta.11"
resolved "https://registry.yarnpkg.com/@dxos/gem-core/-/gem-core-1.0.0-beta.11.tgz#b4b8e82b3cfe7a9dd06fac8596ccf04fa8028e21"
@@ -1194,17 +1201,16 @@
react-dom "^16.13.1"
react-resize-aware "^3.0.0"
-"@dxos/react-ux@^1.0.0-beta.20":
- version "1.0.0-beta.20"
- resolved "https://registry.yarnpkg.com/@dxos/react-ux/-/react-ux-1.0.0-beta.20.tgz#0f0801ae2ddb9089428034cc4b466ee98206a180"
- integrity sha512-larSB5cNCbyvP55/qan9uzioGXrcbtvrmy+fBRx7eLlsFs/eTgD/zrNMSVtq5mvMAn/oKKCOX1wipxm4gK6fdA==
+"@dxos/react-ux@^1.0.0-beta.37":
+ version "1.0.0-beta.37"
+ resolved "https://registry.yarnpkg.com/@dxos/react-ux/-/react-ux-1.0.0-beta.37.tgz#4a6003ce52f0afa156e0af457162d2d14695f153"
+ integrity sha512-QuRIAc4xY57uHRqRnXwGZEW5VD6NVmpIQWRB1T2XsmRdyIzwWDHgK6pBzd7zeNQI/6nqzHr0fkeRY0Lsqou8Cw==
dependencies:
"@dxos/crypto" "^1.0.0-beta.1"
- "@dxos/debug" "^1.0.0-beta.20"
+ "@dxos/debug" "^1.0.0-beta.37"
"@material-ui/core" "^4.9.0"
"@material-ui/icons" "^4.5.1"
"@material-ui/lab" "^4.0.0-alpha.42"
- "@material-ui/styles" "^4.9.0"
clsx "^1.0.4"
lodash.isplainobject "^4.0.6"
uuid "^3.3.3"
@@ -2189,7 +2195,7 @@
prop-types "^15.7.2"
react-is "^16.8.0"
-"@material-ui/styles@^4.10.0", "@material-ui/styles@^4.9.0":
+"@material-ui/styles@^4.10.0":
version "4.10.0"
resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071"
integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==