Fix schema.
This commit is contained in:
parent
eb6bcd9c95
commit
d18a1475ea
@ -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",
|
||||
|
@ -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')} />
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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?)
|
||||
|
@ -27,7 +27,7 @@ const Status = () => {
|
||||
<Toolbar />
|
||||
}
|
||||
>
|
||||
<Json data={JSON.parse(data.system_status.json)} />
|
||||
<Json data={data.system_status} />
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
@ -5,6 +5,17 @@
|
||||
query {
|
||||
system_status {
|
||||
timestamp
|
||||
json
|
||||
dxos {
|
||||
image
|
||||
}
|
||||
system {
|
||||
network {
|
||||
address
|
||||
}
|
||||
nodejs {
|
||||
version
|
||||
environment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
22
packages/console-app/src/util/omit.js
Normal file
22
packages/console-app/src/util/omit.js
Normal 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;
|
||||
};
|
@ -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"
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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__;
|
||||
|
@ -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 {
|
||||
|
27
packages/console-server/src/gql/system.graphql
Normal file
27
packages/console-server/src/gql/system.graphql
Normal 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
|
||||
}
|
32
packages/console-server/src/resolvers/index.js
Normal file
32
packages/console-server/src/resolvers/index.js
Normal 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);
|
36
packages/console-server/src/resolvers/ipfs.js
Normal file
36
packages/console-server/src/resolvers/ipfs.js
Normal 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
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
91
packages/console-server/src/resolvers/system.js
Normal file
91
packages/console-server/src/resolvers/system.js
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user