Skip to content
Permalink
Browse files

fix(cli): fix broken table formatting in prod cli build (JS-33)

  • Loading branch information...
RangerRick committed May 2, 2019
1 parent 5d0278a commit db507241c72e41fbfcc2a27b106121fcaea65b0a
Showing with 139 additions and 64 deletions.
  1. +4 −2 package.json
  2. +68 −57 src/CLI.ts
  3. +67 −5 yarn.lock
@@ -43,7 +43,6 @@
"husky": "^1.3.1",
"jest": "^23.6.0",
"jest-environment-node-debug": "^2.0.0",
"lodash": "^4.17.11",
"parallel-webpack": "^2.3.0",
"regenerator-runtime": "^0.11.1",
"standard-changelog": "^1.0.13",
@@ -79,13 +78,16 @@
},
"dependencies": {
"axios": "^0.16.1",
"chalk": "^2.4.2",
"cli-table3": "^0.5.0",
"commander": "^2.9.0",
"fs": "^0.0.1-security",
"html-to-formatted-text": "^2.6.0",
"ip-address": "^5.8.8",
"lodash.startcase": "^4.4.0",
"lodash": "^4.17.11",
"moment": "^2.19.3",
"qs": "^6.5.0",
"table": "^5.2.3",
"typescript-logging": "^0.3.1",
"version_compare": "^0.0.3",
"x2js": "^3.1.1",
@@ -1,6 +1,4 @@
import * as startCase from 'lodash.startcase';

import {API, Model, Rest, DAO, Client} from './API';
import {API, Rest, DAO, Client} from './API';

import {log, catRoot, setLogLevel} from './api/Log';
import {
@@ -10,48 +8,34 @@ import {
LogLevel,
} from 'typescript-logging';

import chalk from 'chalk';
import {cloneDeep, startCase} from 'lodash';
import {table, getBorderCharacters} from 'table';

/** @hidden */
const CLI = () => {
const version = global.OPENNMS_JS_VERSION || require('../package.json').version || 'unknown';
const catCLI = new Category('cli', catRoot);

// tslint:disable
const Table = require('cli-table3');
const colors = require('colors');
const fs = require('fs');
const htmlToFormattedText = require("html-to-formatted-text");
const path = require('path');
const program = require('commander');
// tslint:enable

const homedir = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
const defaultConfigFile = path.join(homedir, '.opennms-cli.config.json');

const tableFormat = {
/* tslint:disable:object-literal-sort-keys */
head: [],
colWidths: [],
chars: {
'middle': ' ',
'top': '',
'top-mid': '',
'top-left': '',
'top-right': '',
'left': '',
'left-mid': '',
'mid': '',
'mid-mid': '',
'right': '',
'right-mid': '',
'bottom': '',
'bottom-mid': '',
'bottom-left': '',
'bottom-right': '',
const tableConfig = {
border: getBorderCharacters(`void`),
columnDefault: {
paddingLeft: 0,
paddingRight: 2,
},
style: {
'padding-left': 0,
'padding-right': 0,
drawHorizontalLine: () => {
return false;
},
wordWrap: true,
};

const readConfig = () => {
@@ -106,7 +90,7 @@ const CLI = () => {
.option('-u, --username <username>', 'The username to authenticate as (default: admin)')
.option('-p, --password <password>', 'The password to authenticate with (default: admin)')
.action((url, options) => {
console.log(colors.red('WARNING: This command saves your login'
console.log(chalk.red('WARNING: This command saves your login'
+ ' information to ~/.opennms-cli.config.json in clear text.'));
const config = readConfig();
if (url) {
@@ -126,7 +110,7 @@ const CLI = () => {
const server = new API.OnmsServer('OpenNMS', config.url, auth);
const http = new Rest.AxiosHTTP(server);
return Client.checkServer(server, http).then(() => {
console.log(colors.green('Connection succeeded.'));
console.log(chalk.green('Connection succeeded.'));
if (!program.config) { // don't write the config if a config was passed in
log.debug('Saving configuration to ' + defaultConfigFile, catCLI);
fs.writeFileSync(defaultConfigFile, JSON.stringify(config, undefined, 2), { mode: 0o600 });
@@ -147,24 +131,24 @@ const CLI = () => {
const server = new API.OnmsServer('OpenNMS', config.url, auth);
const http = new Rest.AxiosHTTP(server);
return Client.getMetadata(server, http).then((res) => {
let c = colors.green;
let c = chalk.green;
if (res.type === API.ServerTypes.MERIDIAN) {
console.log(colors.blue('OpenNMS Meridian ' + res.version.displayVersion + ' Capabilities:'));
c = colors.blue;
console.log(chalk.blue('OpenNMS Meridian ' + res.version.displayVersion + ' Capabilities:'));
c = chalk.blue;
} else {
console.log(colors.green('OpenNMS Horizon ' + res.version.displayVersion + ' Capabilities:'));
console.log(chalk.green('OpenNMS Horizon ' + res.version.displayVersion + ' Capabilities:'));
}
console.log('');

const data = [];
const caps = res.capabilities();
const t = new Table(tableFormat);
for (const cap in caps) {
if (cap === 'type') {
continue;
}
t.push([startCase(cap) + ':', caps[cap]]);
data.push([chalk.bold(startCase(cap) + ':'), caps[cap]]);
}
console.log(t.toString());
console.log(table(data, tableConfig));
console.log('');

return res;
@@ -177,13 +161,13 @@ const CLI = () => {

const colorify = (severity: string) => {
switch (severity) {
case 'INDETERMINATE': return colors.grey(severity);
case 'CLEARED': return colors.white(severity);
case 'NORMAL': return colors.green(severity);
case 'WARNING': return colors.magenta(severity);
case 'MINOR': return colors.yellow(severity);
case 'MAJOR': return colors.bold.yellow(severity);
case 'CRITICAL': return colors.bold.red(severity);
case 'INDETERMINATE': return chalk.grey(severity);
case 'CLEARED': return chalk.white(severity);
case 'NORMAL': return chalk.green(severity);
case 'WARNING': return chalk.magenta(severity);
case 'MINOR': return chalk.yellow(severity);
case 'MAJOR': return chalk.bold.yellow(severity);
case 'CRITICAL': return chalk.bold.red(severity);
default: return severity;
}
};
@@ -194,14 +178,17 @@ const CLI = () => {
return Math.min(m, max);
};

const logMessageLength = 50;
const formatAlarms = (alarms) => {
return alarms.map((alarm) => {
const severityLabel = ((alarm.severity && alarm.severity.label) ? alarm.severity.label : '');

let logMessage = '';
if (alarm.logMessage) {
logMessage = alarm.logMessage.replace('[\r\n].*$', '').replace('<p>', '').replace('</p>', '').trim();
logMessage = alarm.logMessage
.replace(new RegExp('[\r\n]+', 'gs'), ' ')
.replace(new RegExp('\s+', 'gs'), ' ')
.trim();
logMessage = htmlToFormattedText(logMessage);
}

return {
@@ -243,20 +230,44 @@ const CLI = () => {
return;
}

const format = Object.assign({}, tableFormat);
const formatted = formatAlarms(alarms);

format.head = [ 'ID', 'Severity', 'Node', 'Count', 'Time', 'Log' ];
format.colWidths = [3, 8, getMaxWidth(formatted, 'node', 30), 5, 17];
const existingWidths = format.colWidths.reduce((acc, val) => acc + val);
const spacers = (format.colWidths.length * 2);
const remainder = process.stdout.columns - existingWidths - spacers;
format.colWidths.push(remainder);
const t = new Table(format);
const alarmTableConfig = cloneDeep(tableConfig) as any;
alarmTableConfig.columns = {};

const data = [
[ 'ID', 'Severity', 'Node', 'Count', 'Time', 'Log' ].map((header) => chalk.bold(header)),
];

const colWidths = [
/* id */
getMaxWidth(formatted, 'id', 10),
/* severity */
8,
/* node */
getMaxWidth(formatted, 'node', 30),
/* count */
5,
/* time */
16,
];
const existingWidths = colWidths.reduce((acc, val) => acc + val);
const spacers = (colWidths.length + 1) * 2;
const remainder = (process.stdout.columns || 200) - existingWidths - spacers;
/* log */
colWidths.push(remainder);

colWidths.forEach((width, index) => {
alarmTableConfig.columns[index] = {
width,
};
});

alarmTableConfig.columns[5].wrapWord = true;
for (const alarm of formatted) {
t.push([alarm.id, alarm.severity, alarm.node, alarm.count, alarm.time, alarm.log]);
data.push([alarm.id, alarm.severity, alarm.node, alarm.count, alarm.time, alarm.log]);
}
console.log(t.toString());
console.log(table(data, alarmTableConfig));
console.log('');
});
}).catch((err) => {
@@ -149,7 +149,7 @@ ajv@^6.1.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"

ajv@^6.5.5:
ajv@^6.5.5, ajv@^6.9.1:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
@@ -185,6 +185,11 @@ ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"

ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==

ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@@ -1500,6 +1505,15 @@ chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"

chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"

chalk@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
@@ -2257,6 +2271,11 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"

emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==

emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@@ -3179,6 +3198,13 @@ html-encoding-sniffer@^1.0.2:
dependencies:
whatwg-encoding "^1.0.1"

html-to-formatted-text@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/html-to-formatted-text/-/html-to-formatted-text-2.6.0.tgz#a5c5df92cc785b06e4b857ed4a4211370d51b49f"
integrity sha512-ktMgspXmA0EYsQn4lkk6MpnDA29tVucg21QCFfbMz8MNT6MvXiyP/rd9x8pjs8UmYF8Zc0vXwl2jCtzYquiR9g==
dependencies:
striptags "3.1.1"

http-cache-semantics@3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
@@ -4474,10 +4500,6 @@ lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"

lodash.startcase@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"

lodash.template@^3.0.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
@@ -6209,6 +6231,15 @@ slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"

slice-ansi@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
dependencies:
ansi-styles "^3.2.0"
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"

slide@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@@ -6514,6 +6545,15 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"

string-width@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"

string_decoder@^0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@@ -6536,6 +6576,13 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"

strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"

strip-ansi@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
@@ -6575,6 +6622,11 @@ strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"

striptags@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.1.1.tgz#c8c3e7fdd6fb4bb3a32a3b752e5b5e3e38093ebd"
integrity sha1-yMPn/db7S7OjKjt1LltePjgJPr0=

supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -6609,6 +6661,16 @@ symbol-tree@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"

table@^5.2.3:
version "5.2.3"
resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2"
integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==
dependencies:
ajv "^6.9.1"
lodash "^4.17.11"
slice-ansi "^2.1.0"
string-width "^3.0.0"

tapable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2"

0 comments on commit db50724

Please sign in to comment.
You can’t perform that action at this time.