Fix schema.

This commit is contained in:
richburdon 2020-05-27 22:35:37 -04:00
parent eb6bcd9c95
commit d18a1475ea
18 changed files with 1274 additions and 185 deletions

View File

@ -43,9 +43,6 @@
"graphql-tag": "^2.10.3",
"lodash.defaultsdeep": "^4.6.1",
"lodash.get": "^4.4.2",
"lodash.isobject": "^3.0.2",
"lodash.omit": "^4.5.0",
"lodash.transform": "^4.6.0",
"moment": "^2.26.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",

View File

@ -2,37 +2,24 @@
// Copyright 2020 DxOS.org
//
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';
import { omitDeep } from '../util/omit';
const useStyles = makeStyles(() => ({
root: {
flex: 1
}
}));
/**
* Remove Apollo __typename directive.
* @param {Object} data
* @returns {Object}
*/
const removeTypename = data => transform(data, (result, value, key) => {
if (key !== '__typename') {
result[key] = isObject(value) ? ('__typename' in value ? omit(value, '__typename') : value) : value;
}
}, {});
const Json = ({ data }) => {
const classes = useStyles();
// TODO(burdon): Bug expands when updated.
return (
<JsonTreeView className={classes.root} data={removeTypename(data)} />
<JsonTreeView className={classes.root} data={omitDeep(data, '__typename')} />
);
};

View File

@ -35,7 +35,7 @@ const VersionCheck = () => {
// Check version.
useEffect(() => {
if (status && data) {
const { dxos: { image: current } } = JSON.parse(status.system_status.json);
const { dxos: { image: current } } = status.system_status;
let latest = current;
data.wns_records.json.forEach(({ attributes: { name, version } }) => {
// TODO(burdon): Filter by type (WRN?)

View File

@ -27,7 +27,7 @@ const Status = () => {
<Toolbar />
}
>
<Json data={JSON.parse(data.system_status.json)} />
<Json data={data.system_status} />
</Panel>
);
};

View File

@ -5,6 +5,17 @@
query {
system_status {
timestamp
json
dxos {
image
}
system {
network {
address
}
nodejs {
version
environment
}
}
}
}

View File

@ -59,19 +59,15 @@ export const createResolvers = config => {
wns_log: async () => {
log('WNS log...');
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]);
const data = await registry.getLogs();
let i = data.findIndex(line => line === cachedLog[cachedLog.length - 1]);
if (i === -1) {
cachedLog = filtered;
cachedLog = data;
} else {
i++;
for (; i < filtered.length - 1; i++) {
cachedLog.push(filtered[i]);
for (; i < data.length - 1; i++) {
cachedLog.push(data[i]);
}
// Trim.

View File

@ -0,0 +1,22 @@
//
// Copyright 2020 DxOS.org
//
// TODO(burdon): Factor out.
export const omitDeep = (value, key) => {
if (Array.isArray(value)) {
return value.map(i => omitDeep(i, key));
} else if (typeof value === 'object' && value !== null) {
return Object.keys(value).reduce((newObject, k) => {
if (k === key) {
return newObject;
}
return Object.assign({
[k]: omitDeep(value[k], key),
}, newObject);
}, {});
}
return value;
};

View File

@ -1,6 +1,6 @@
{
"build": {
"name": "@dxos/console-client",
"name": "@dxos/console-app",
"buildDate": "2020-05-27T22:04:52.661Z",
"version": "1.0.0-beta.0"
}

View File

@ -32,6 +32,7 @@
"@babel/polyfill": "^7.8.7",
"@babel/runtime": "^7.8.7",
"@dxos/console-app": "^1.0.0-beta.0",
"@wirelineio/wns-schema": "^0.1.1",
"apollo-boost": "^0.4.9",
"apollo-server-express": "^2.13.1",
"debug": "^4.1.1",
@ -39,12 +40,16 @@
"express-graphql": "^0.9.0",
"graphql": "^15.0.0",
"graphql-tag": "^2.10.3",
"graphql-tools": "^6.0.3",
"ipfs-http-client": "^44.1.0",
"js-yaml": "^3.14.0",
"lodash.defaultsdeep": "^4.6.1",
"lodash.pick": "^4.4.0",
"mustache-express": "^1.3.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"source-map-support": "^0.5.12",
"systeminformation": "^4.26.5",
"yargs": "^15.3.1"
},
"devDependencies": {
@ -62,6 +67,7 @@
"babel-plugin-inline-import": "^3.0.0",
"babel-plugin-inline-json-import": "^0.3.2",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"dotenv-webpack": "^1.8.0",
"eslint": "^6.7.2",
"eslint-config-semistandard": "^15.0.0",

View File

@ -6,7 +6,7 @@ import debug from 'debug';
import React from 'react';
import { render } from 'react-dom';
import { Main } from '@dxos/console-client';
import { Main } from '@dxos/console-app';
// Load from global printed into HTML page via template.
const { config } = window.__DXOS__;

View File

@ -2,6 +2,12 @@
# Copyright 2020 DxOS.org
#
# TODO(burdon): Replace generic results with schema.
type JSONResult {
timestamp: String!
json: String!
}
type Result {
timestamp: String!
code: Int!
@ -12,27 +18,20 @@ type Log {
log: [String]!
}
# TODO(burdon): Generic result.
type JSONResult {
timestamp: String!
json: String!
}
#
# Schema
#
type Query {
system_status: JSONResult!
ipfs_status: JSONResult!
wns_status: JSONResult!
# TODO(burdon): Import WNS schema!
wns_records(type: String): JSONResult!
wns_log: Log!
type Mutation {
action(command: String!): Result!
}
type Mutation {
wns_action(command: String!): Result!
type Query {
system_status: SystemStatus!
ipfs_status: JSONResult!
wns_status: JSONResult!
wns_records(type: String): JSONResult!
wns_log: Log!
}
schema {

View File

@ -0,0 +1,27 @@
#
# Copyright 2020 DxOS.org
#
type DXOSInfo {
image: String
}
type NetworkInfo {
address: [String]
}
type NodeInfo {
version: String
environment: String
}
type SystemInfo {
network: NetworkInfo
nodejs: NodeInfo
}
type SystemStatus {
timestamp: String!
dxos: DXOSInfo
system: SystemInfo
}

View File

@ -0,0 +1,32 @@
//
// Copyright 2020 DxOS.org
//
import debug from 'debug';
import defaultsDeep from 'lodash.defaultsdeep';
import { ipfsResolvers } from './ipfs';
import { systemResolvers } from './system';
const log = debug('dxos:console:server:resolvers');
/**
* Resolvers
* https://www.apollographql.com/docs/graphql-tools/resolvers
*/
export const resolvers = defaultsDeep({
// TODO(burdon): Auth.
// https://www.apollographql.com/docs/apollo-server/data/errors/#codes
Mutation: {
action: async (_, { command }) => {
log(`WNS action: ${command}`);
return {
timestamp: new Date().toUTCString(),
code: 0
};
}
}
}, ipfsResolvers, systemResolvers);

View File

@ -0,0 +1,36 @@
//
// Copyright 2020 DxOS.org
//
import debug from 'debug';
import IpfsHttpClient from 'ipfs-http-client';
const log = debug('dxos:console:server:resolvers');
export const ipfsResolvers = {
Query: {
//
// IPFS
// TODO(burdon): Call from client?
// https://github.com/ipfs/js-ipfs
// https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-http-client#api
//
ipfs_status: async (_, __, { config }) => {
log('Calling IPFS...');
// NOTE: Hangs if server not running.
const ipfs = new IpfsHttpClient(config.services.ipfs.server);
const version = await ipfs.version();
const status = await ipfs.id();
return {
timestamp: new Date().toUTCString(),
json: JSON.stringify({
version,
status
})
};
}
}
};

View File

@ -0,0 +1,91 @@
//
// Copyright 2020 DxOS.org
//
import moment from 'moment';
import pick from 'lodash.pick';
import os from 'os';
import si from 'systeminformation';
const num = new Intl.NumberFormat('en', { maximumSignificantDigits: 3 });
const size = (n, unit) => {
const units = {
K: 3,
M: 6,
G: 9,
T: 12
};
const power = units[unit] || 0;
return num.format(Math.round(n / (10 ** power))) + (unit ? ` ${unit}` : '');
};
/**
* Get system inforamtion.
* https://www.npmjs.com/package/systeminformation
*/
const getSystemInfo = async () => {
const ifaces = os.networkInterfaces();
const addresses = Object.entries(ifaces).reduce((result, [, values]) => {
values.forEach(({ family, address }) => {
if (family === 'IPv4' && address !== '127.0.0.1') {
result.push(address);
}
});
return result;
}, []);
const cpu = await si.cpu();
const memory = await si.mem();
const device = await si.system();
return {
cpu: pick(cpu, 'brand', 'cores', 'manufacturer', 'vendor'),
memory: {
total: size(memory.total, 'M'),
free: size(memory.free, 'M'),
used: size(memory.used, 'M'),
swaptotal: size(memory.swaptotal, 'M')
},
device: pick(device, 'model', 'serial', 'version'),
network: {
address: addresses
},
// https://nodejs.org/api/os.html
os: {
arch: os.arch(),
type: os.type(),
platform: os.platform(),
version: os.version ? os.version() : undefined, // Node > 13
uptime: moment().subtract(os.uptime(), 'seconds').fromNow()
},
nodejs: {
version: process.version,
environment: process.env.NODE_ENV
}
};
};
export const systemResolvers = {
Query: {
system_status: async () => {
const system = await getSystemInfo();
return {
timestamp: new Date().toUTCString(),
dxos: {
// TODO(burdon): ???
image: '0.0.1'
},
system
};
}
}
};

View File

@ -2,7 +2,9 @@
// Copyright 2020 DxOS.org
//
import compression from 'compression';
import bodyParser from 'body-parser';
import cors from 'cors';
import debug from 'debug';
import express from 'express';
import mustache from 'mustache-express';
@ -12,11 +14,15 @@ import { ApolloServer, gql } from 'apollo-server-express';
import { print } from 'graphql/language';
import yargs from 'yargs';
import SYSTEM_STATUS from '@dxos/console-client/src/gql/system_status.graphql';
// TODO(burdon): Use once published by @ashwinp.
// import { extensions as WNS_EXTENSIONS, schema as WNS_SCHEMA } from '@wirelineio/wns-schema';
import { createResolvers } from './resolvers';
import SYSTEM_STATUS from '@dxos/console-app/src/gql/system_status.graphql';
import SCHEMA from '../gql/api.graphql';
import { resolvers } from '../resolvers';
import API_SCHEMA from '../gql/api.graphql';
import SYSTEM_SCHEMA from '../gql/system.graphql';
const argv = yargs
.option('config', {
@ -53,16 +59,19 @@ if (argv.verbose) {
// Express server.
//
const { app: { publicUrl } } = config;
const app = express();
app.set('views', `${__dirname}/views`);
app.set('view engine', 'mustache');
app.engine('mustache', mustache());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(compression());
// TODO(burdon): Add react, webpack deps
// TODO(burdon): app.use(compression());
app.get('/', (req, res) => {
res.redirect(publicUrl);
});
//
// CORS
@ -71,18 +80,16 @@ app.use(bodyParser.urlencoded({ extended: true }));
// import cors from 'cors'
// https://expressjs.com/en/resources/middleware/cors.html
// https://www.prisma.io/blog/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d
// app.use(cors({
// origin: true,
// credentials: true
// }));
app.use(cors({
origin: true,
credentials: true
}));
//
// React app
// TODO(burdon): Can we load this via WNS?
//
const { app: { publicUrl } } = config;
const bundles = [
'runtime', 'vendor', 'material-ui', 'dxos', 'main'
];
@ -105,9 +112,23 @@ app.get(publicUrl, (req, res) => {
//
const server = new ApolloServer({
typeDefs: SCHEMA,
typeDefs: [
API_SCHEMA,
SYSTEM_SCHEMA
// WNS_EXTENSIONS,
// WNS_SCHEMA
],
resolvers: createResolvers(config),
// https://www.apollographql.com/docs/graphql-tools/resolvers
resolvers,
// https://www.apollographql.com/docs/apollo-server/data/resolvers/#the-context-argument
context: ({ req }) => ({
config,
// TODO(burdon): Auth.
authToken: req.headers.authorization
}),
// https://www.apollographql.com/docs/apollo-server/testing/graphql-playground
// https://github.com/prisma-labs/graphql-playground#usage

View File

@ -1,82 +0,0 @@
//
// Copyright 2020 DxOS.org
//
import debug from 'debug';
import IpfsHttpClient from 'ipfs-http-client';
const log = debug('dxos:console:server:resolvers');
const timestamp = () => new Date().toUTCString();
/**
* Resolvers
* https://www.apollographql.com/docs/graphql-tools/resolvers
* @param config
*/
export const createResolvers = config => ({
// TODO(burdon): Auth mutations.
// https://www.apollographql.com/docs/apollo-server/data/errors/#codes
Mutation: {
//
// WNS
//
wns_action: async (_, { command }) => {
log(`WNS action: ${command}`);
return {
timestamp: timestamp(),
code: 0
};
}
},
Query: {
//
// System
//
// TODO(burdon): System calls.
system_status: () => {
return {
timestamp: timestamp(),
json: JSON.stringify({
dxos: {
image: '0.0.1'
}
})
};
},
//
// IPFS
// TODO(burdon): Call from client?
// https://github.com/ipfs/js-ipfs
// https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-http-client#api
//
ipfs_status: async () => {
log('Calling IPFS...');
// TODO(burdon): Config.
// NOTE: Hangs if server not running.
const ipfs = new IpfsHttpClient('/ip4/127.0.0.1/tcp/5001');
const version = await ipfs.version();
const status = await ipfs.id();
console.log(version);
log('Done');
return {
json: JSON.stringify({
version,
status
})
};
}
}
});

1028
yarn.lock

File diff suppressed because it is too large Load Diff