From 4e378d4dff07232620869bae56e4e01f17994615 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Fri, 5 Oct 2018 22:37:16 -0700 Subject: [PATCH] Show fault message and detail in faults page --- client/css/app.css | 19 ++++++++++++++++ client/dynamic-loader.js | 16 +++++++++++++- client/faults-page.js | 34 ++++++++++++++++++++++++----- client/long-text-component.js | 41 +++++++++++++++++++++++++++++++++++ package.json | 3 ++- server/mongodb-functions.js | 4 ---- 6 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 client/long-text-component.js diff --git a/client/css/app.css b/client/css/app.css index ea71300..16a00fc 100644 --- a/client/css/app.css +++ b/client/css/app.css @@ -637,3 +637,22 @@ span.tag { } } } + +span.long-text { + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 400px; + cursor: pointer; + &:hover { + text-decoration: underline; + text-decoration-style: dotted; + } +} + +textarea.long-text { + font-family: monospace; + min-width: 10vw; + min-height: 10vh; +} diff --git a/client/dynamic-loader.js b/client/dynamic-loader.js index b556484..baf7fed 100644 --- a/client/dynamic-loader.js +++ b/client/dynamic-loader.js @@ -1,6 +1,7 @@ "use strict"; let codeMirror; +let yaml; function loadCodeMirror() { if (codeMirror) return Promise.resolve(); @@ -19,4 +20,17 @@ function loadCodeMirror() { }); } -export { loadCodeMirror, codeMirror }; +function loadYaml() { + if (yaml) return Promise.resolve(); + + return new Promise((resolve, reject) => { + import(/* webpackChunkName: "yaml" */ "yaml") + .then(module => { + yaml = module; + resolve(); + }) + .catch(reject); + }); +} + +export { loadCodeMirror, codeMirror, loadYaml, yaml }; diff --git a/client/faults-page.js b/client/faults-page.js index 47b48d7..38efc39 100644 --- a/client/faults-page.js +++ b/client/faults-page.js @@ -9,6 +9,8 @@ import * as expression from "../common/expression"; import memoize from "../common/memoize"; import * as smartQuery from "./smart-query"; import * as expressionParser from "../common/expression-parser"; +import { loadYaml, yaml } from "./dynamic-loader"; +import longTextComponent from "./long-text-component"; const PAGE_SIZE = config.ui.pageSize || 10; @@ -19,6 +21,8 @@ const attributes = [ { id: "device", label: "Device" }, { id: "channel", label: "Channel" }, { id: "code", label: "Code" }, + { id: "message", label: "Message" }, + { id: "detail", label: "Detail", unsortable: true }, { id: "retries", label: "Retries" }, { id: "timestamp", label: "Timestamp" } ]; @@ -53,7 +57,13 @@ function init(args) { const sort = args.sort; const filter = args.filter; - return Promise.resolve({ filter, sort }); + return new Promise((resolve, reject) => { + loadYaml() + .then(() => { + resolve({ filter, sort }); + }) + .catch(reject); + }); } function renderTable( @@ -82,7 +92,13 @@ function renderTable( for (const attr of attributes) { const label = attr.label; - let direction = 1; + if (attr.unsortable) { + labels.push(m("th", label)); + continue; + } + + // Offset direction by 1 since sort["_id"] = -1 + let direction = 2; let symbol = "\u2981"; if (sort[attr.id] > 0) symbol = "\u2bc6"; @@ -121,11 +137,17 @@ function renderTable( const tds = [m("td", checkbox)]; for (const attr of attributes) { - if (attr.id === "device") - tds.push(m("a", { href: deviceHref }, f[attr.id])); - else if (attr.id === "timestamp") + if (attr.id === "device") { + tds.push(m("td", m("a", { href: deviceHref }, f[attr.id]))); + } else if (attr.id === "timestamp") { tds.push(m("td", new Date(f[attr.id]).toLocaleString())); - else tds.push(m("td", f[attr.id])); + } else if (attr.id === "detail") { + tds.push( + m("td", m(longTextComponent, { text: yaml.stringify(f[attr.id]) })) + ); + } else { + tds.push(m("td", f[attr.id])); + } } rows.push( diff --git a/client/long-text-component.js b/client/long-text-component.js new file mode 100644 index 0000000..08f4cff --- /dev/null +++ b/client/long-text-component.js @@ -0,0 +1,41 @@ +"use strict"; + +import m from "mithril"; +import * as overlay from "./overlay"; + +const component = { + view: vnode => { + const text = vnode.attrs.text; + const element = vnode.attrs.element || "span"; + + return m( + element, + { + class: "long-text", + title: text, + onclick: () => { + overlay.open(() => { + return m( + "textarea.long-text", + { + cols: 80, + rows: 24, + readonly: "", + oncreate: vnode2 => { + setTimeout(() => { + vnode2.dom.focus(); + vnode2.dom.select(); + }, 50); + } + }, + text + ); + }); + } + }, + text + ); + } +}; + +export default component; diff --git a/package.json b/package.json index 53c58c2..26377a1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "koa-router": "^7.4.0", "koa-static": "^5.0.0", "mongodb": "^3.1.1", - "parsimmon": "^1.12.0" + "parsimmon": "^1.12.0", + "yaml": "^1.0.0" }, "devDependencies": { "babel-eslint": "^8.2.6", diff --git a/server/mongodb-functions.js b/server/mongodb-functions.js index 0ebcc3b..c4f65a2 100644 --- a/server/mongodb-functions.js +++ b/server/mongodb-functions.js @@ -353,10 +353,6 @@ function flattenFault(fault) { const f = Object.assign({}, fault); if (f.timestamp) f.timestamp = +f.timestamp; if (f.expiry) f.expiry = +f.expiry; - if (f.detail) { - for (const [k, v] of Object.entries(f.detail)) fault[`detail.${k}`] = v; - delete f.detail; - } return f; }