From 0ad392d15948e7cc38fdb93a9ada56aa05f42970 Mon Sep 17 00:00:00 2001 From: Melissa Page <73hl10n@gmail.com> Date: Wed, 24 Oct 2018 16:30:28 -0700 Subject: [PATCH] [Web UI] Check details page improvements (#2162) * Wrap commands, allow scrolling on env vars Signed-off-by: Melissa P <73hl10n@gmail.com> * Add buttons for publish and unpublish Signed-off-by: Melissa P <73hl10n@gmail.com> * Added check publish and unpublish actions Signed-off-by: Melissa P <73hl10n@gmail.com> * Fix syntax Signed-off-by: Melissa P <73hl10n@gmail.com> * Render single button depending on state of publish Signed-off-by: Melissa P <73hl10n@gmail.com> * update changelog Signed-off-by: Melissa P <73hl10n@gmail.com> * Review tweaks Signed-off-by: Melissa P <73hl10n@gmail.com> * Review tweaks Signed-off-by: Melissa P <73hl10n@gmail.com> * Rework Monospaced to be more clear at it's intention Signed-off-by: Melissa P <73hl10n@gmail.com> * Set DV back to table-cell and give optional scrollable prop Signed-off-by: Melissa P <73hl10n@gmail.com> * Initial implementation of code highlighting Signed-off-by: Melissa P <73hl10n@gmail.com> * Implement code highlighting Signed-off-by: Melissa P <73hl10n@gmail.com> * Update eslint rule Signed-off-by: Melissa P <73hl10n@gmail.com> * update changelog Signed-off-by: Melissa P <73hl10n@gmail.com> * Fallback theme colour re-added Signed-off-by: Melissa P <73hl10n@gmail.com> --- CHANGELOG.md | 2 + dashboard/.eslintrc.yml | 3 + dashboard/config/webpack.config.js | 14 ++ dashboard/package.json | 6 +- dashboard/src/components/Code.js | 13 +- .../Monospaced.js => CodeBlock/CodeBlock.js} | 29 ++-- dashboard/src/components/CodeBlock/index.js | 1 + .../components/CodeHighlight/CodeHighlight.js | 72 ++++++++++ .../CodeHighlight/CodeHighlight.worker.js | 14 ++ .../components/Dictionary/DictionaryValue.js | 10 ++ dashboard/src/components/Monospaced/index.js | 1 - .../CheckDetailsConfiguration.js | 45 ++++-- .../CheckDetailsPublishAction.js | 53 +++++++ .../CheckDetailsToolbar.js | 16 +++ .../CheckDetailsUnpublishAction.js | 54 +++++++ .../partials/ChecksList/ChecksListItem.js | 5 +- .../EntityDetailsInformation.js | 14 +- .../EventDetailsCheckResult.js | 6 +- .../EventDetailsSummary.js | 14 +- dashboard/yarn.lock | 133 +++++++++++++++++- 20 files changed, 455 insertions(+), 50 deletions(-) rename dashboard/src/components/{Monospaced/Monospaced.js => CodeBlock/CodeBlock.js} (76%) create mode 100644 dashboard/src/components/CodeBlock/index.js create mode 100644 dashboard/src/components/CodeHighlight/CodeHighlight.js create mode 100644 dashboard/src/components/CodeHighlight/CodeHighlight.worker.js delete mode 100644 dashboard/src/components/Monospaced/index.js create mode 100644 dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsPublishAction.js create mode 100644 dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsUnpublishAction.js diff --git a/CHANGELOG.md b/CHANGELOG.md index bbbd85c625..879a676c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ Versioning](http://semver.org/spec/v2.0.0.html). - Added a debug log message for interval timer initial offset. - Added a privilege escalation test for RBAC. - Web ui allows publishing and unpublishing on checks page +- Web ui allows publishing and unpublishing on check details page +- Code highlighting added ### Removed - Staging resources and configurations have been removed from sensu-go. diff --git a/dashboard/.eslintrc.yml b/dashboard/.eslintrc.yml index 3cd491daf9..d21aa83421 100644 --- a/dashboard/.eslintrc.yml +++ b/dashboard/.eslintrc.yml @@ -47,6 +47,9 @@ rules: import/prefer-default-export: 0 + # Code Highlighting requirees dangerously setting + react/no-danger: 0 + # https://github.com/apollographql/eslint-plugin-graphql graphql/template-strings: - error diff --git a/dashboard/config/webpack.config.js b/dashboard/config/webpack.config.js index 463b438fcb..107d230d84 100644 --- a/dashboard/config/webpack.config.js +++ b/dashboard/config/webpack.config.js @@ -28,6 +28,8 @@ export default () => { entry: [path.resolve(root, "src/index.js")], output: { + globalObject: "self", + path: outputPath, publicPath: "/", @@ -111,6 +113,18 @@ export default () => { name: "static/media/[name].[hash:8].[ext]", }, }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, + { + test: /\.worker\.js$/, + loader: "worker-loader", + options: { + name: "static/[hash].worker.js", + }, + }, + { test: /\.macro\.js$/, exclude: path.resolve(root, "node_modules"), diff --git a/dashboard/package.json b/dashboard/package.json index ea2a2df6cf..f3dac1215e 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -58,6 +58,7 @@ "connect-history-api-fallback": "^1.5.0", "core-js": "^2.5.6", "cronstrue": "^1.31.0", + "css-loader": "^1.0.0", "debounce": "^1.2.0", "deepmerge": "^2.0.1", "enzyme": "^3.3.0", @@ -83,6 +84,7 @@ "graphql": "0.13.0", "graphql-config": "^2.0.1", "graphql-tag": "^2.9.2", + "highlight.js": "^9.13.1", "hoist-non-react-statics": "^2.5.0", "html-webpack-plugin": "^3.2.0", "http-proxy-middleware": "^0.18.0", @@ -121,6 +123,7 @@ "regenerator-runtime": "^0.11.1", "source-map-loader": "bryanforbes/source-map-loader#module-context", "stacktrace-js": "^2.0.0", + "style-loader": "^0.23.1", "sw-precache-webpack-plugin": "^0.11.5", "typeface-roboto": "^0.0.54", "uglifyjs-webpack-plugin": "^1.2.5", @@ -130,7 +133,8 @@ "warning": "^3.0.0", "webpack": "^4.8.1", "webpack-stats-plugin": "^0.2.1", - "whatwg-fetch": "^2.0.4" + "whatwg-fetch": "^2.0.4", + "worker-loader": "^2.0.0" }, "jest": { "collectCoverageFrom": [ diff --git a/dashboard/src/components/Code.js b/dashboard/src/components/Code.js index 4fa81a7004..01d80c0669 100644 --- a/dashboard/src/components/Code.js +++ b/dashboard/src/components/Code.js @@ -5,7 +5,7 @@ import { fade } from "@material-ui/core/styles/colorManipulator"; const styles = theme => ({ root: { - whiteSpace: "nowrap", + whiteSpace: "pre-wrap", margin: "0 1px", padding: `${2 / 16}em ${4 / 16}em`, borderRadius: `${5 / 16}em`, @@ -24,11 +24,18 @@ const styles = theme => ({ class Code extends React.PureComponent { static propTypes = { classes: PropTypes.object.isRequired, + children: PropTypes.node, }; + static defaultProps = { children: null }; + render() { - const { classes, ...props } = this.props; - return ; + const { classes, children, ...props } = this.props; + return ( + + {children} + + ); } } diff --git a/dashboard/src/components/Monospaced/Monospaced.js b/dashboard/src/components/CodeBlock/CodeBlock.js similarity index 76% rename from dashboard/src/components/Monospaced/Monospaced.js rename to dashboard/src/components/CodeBlock/CodeBlock.js index eadcad11e2..ef6c978cf6 100644 --- a/dashboard/src/components/Monospaced/Monospaced.js +++ b/dashboard/src/components/CodeBlock/CodeBlock.js @@ -7,48 +7,42 @@ import Typography from "@material-ui/core/Typography"; const styles = theme => ({ root: { - // TODO: Move into theme so that it can be overridden. - fontFamily: `"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace`, + fontFamily: theme.typography.monospace.fontFamily, overflowX: "scroll", userSelect: "text", tabSize: 2, - }, - background: { - backgroundColor: emphasize(theme.palette.background.paper, 0.01875), - }, - highlight: { color: theme.palette.type === "dark" ? theme.palette.secondary.light : theme.palette.secondary.dark, - "& $background": { - backgroundColor: emphasize(theme.palette.text.primary, 0.05), - }, + }, + background: { + backgroundColor: emphasize(theme.palette.background.paper, 0.01875), }, scaleFont: { // Browsers tend to render monospaced fonts a little larger than intended. // Attempt to scale accordingly. fontSize: "0.8125rem", // TODO: Scale given fontSize from theme? }, + wrap: { whiteSpace: "pre-wrap" }, }); -class Monospaced extends React.Component { +class CodeBlock extends React.Component { static propTypes = { background: PropTypes.bool, classes: PropTypes.object.isRequired, className: PropTypes.string, component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), children: PropTypes.node.isRequired, - highlight: PropTypes.bool, scaleFont: PropTypes.bool, }; static defaultProps = { - background: false, + background: true, component: "pre", className: "", - highlight: false, scaleFont: true, + highlight: null, }; render() { @@ -57,7 +51,6 @@ class Monospaced extends React.Component { classes, className: classNameProp, children, - highlight, scaleFont, ...props } = this.props; @@ -65,14 +58,14 @@ class Monospaced extends React.Component { const className = classnames(classes.root, classNameProp, { [classes.background]: background, [classes.scaleFont]: scaleFont, - [classes.highlight]: highlight, }); + return ( - {children} + {children} ); } } -export default withStyles(styles)(Monospaced); +export default withStyles(styles)(CodeBlock); diff --git a/dashboard/src/components/CodeBlock/index.js b/dashboard/src/components/CodeBlock/index.js new file mode 100644 index 0000000000..45a9fcacda --- /dev/null +++ b/dashboard/src/components/CodeBlock/index.js @@ -0,0 +1 @@ +export { default } from "./CodeBlock"; diff --git a/dashboard/src/components/CodeHighlight/CodeHighlight.js b/dashboard/src/components/CodeHighlight/CodeHighlight.js new file mode 100644 index 0000000000..f6a62a04ba --- /dev/null +++ b/dashboard/src/components/CodeHighlight/CodeHighlight.js @@ -0,0 +1,72 @@ +import "highlight.js/styles/github-gist.css"; + +import React from "react"; +import PropTypes from "prop-types"; +import Worker from "./CodeHighlight.worker"; + +const worker = new Worker(); +const pending = {}; + +worker.onmessage = event => { + const [key, data] = event.data; + pending[key].call(this, data); +}; + +let idx = 0; +function postMessage(msg, callback) { + const key = idx; + pending[idx] = data => { + callback(data); + delete pending[idx]; + }; + worker.postMessage({ key, msg }); + idx += 1; +} + +class CodeHighlight extends React.Component { + static propTypes = { + language: PropTypes.oneOf(["json", "bash", "properties"]).isRequired, + code: PropTypes.string.isRequired, + children: PropTypes.func.isRequired, + }; + + static getDerivedStateFromProps(props, state) { + if (props.code !== state.code) { + return { code: props.code, result: props.code }; + } + return null; + } + + state = { + code: this.props.code, + result: this.props.code, + }; + + componentDidMount() { + this.update(); + } + + componentDidUpdate() { + if (this.props.code === this.state.result) { + this.update(); + } + } + + componentWillUnmount() { + this.unmounted = true; + } + + update = () => { + postMessage([this.props.language, this.props.code], result => { + if (!this.unmounted) { + this.setState({ result }); + } + }); + }; + + render() { + return this.props.children(this.state.result); + } +} + +export default CodeHighlight; diff --git a/dashboard/src/components/CodeHighlight/CodeHighlight.worker.js b/dashboard/src/components/CodeHighlight/CodeHighlight.worker.js new file mode 100644 index 0000000000..9da67b0aea --- /dev/null +++ b/dashboard/src/components/CodeHighlight/CodeHighlight.worker.js @@ -0,0 +1,14 @@ +import hljs from "highlight.js/lib/highlight"; +import bash from "highlight.js/lib/languages/bash"; +import json from "highlight.js/lib/languages/json"; +import properties from "highlight.js/lib/languages/properties"; + +hljs.registerLanguage("bash", bash); +hljs.registerLanguage("json", json); +hljs.registerLanguage("properties", properties); + +onmessage = message => { + const [language, data] = message.data.msg; + const result = hljs.highlight(language, data); + postMessage([message.data.key, result.value]); +}; diff --git a/dashboard/src/components/Dictionary/DictionaryValue.js b/dashboard/src/components/Dictionary/DictionaryValue.js index c9e19f2a8f..295c57bb8f 100644 --- a/dashboard/src/components/Dictionary/DictionaryValue.js +++ b/dashboard/src/components/Dictionary/DictionaryValue.js @@ -13,6 +13,8 @@ const styles = theme => ({ limit: { maxWidth: "60%", }, + scrollableContent: { display: "inline-grid" }, + explicitRightMargin: { paddingRight: "24px" }, }); class DictionaryValue extends React.Component { @@ -21,11 +23,15 @@ class DictionaryValue extends React.Component { classes: PropTypes.object.isRequired, className: PropTypes.string, constrain: PropTypes.bool, + explicitRightMargin: PropTypes.bool, + scrollableContent: PropTypes.bool, }; static defaultProps = { className: null, constrain: false, + explicitRightMargin: false, + scrollableContent: false, }; render() { @@ -34,10 +40,14 @@ class DictionaryValue extends React.Component { classes, children, constrain, + explicitRightMargin, + scrollableContent, ...props } = this.props; const className = classnames(classes.root, classNameProp, { [classes.limit]: constrain, + [classes.explicitRightMargin]: explicitRightMargin, + [classes.scrollableContent]: scrollableContent, }); return ( diff --git a/dashboard/src/components/Monospaced/index.js b/dashboard/src/components/Monospaced/index.js deleted file mode 100644 index e04b4f5523..0000000000 --- a/dashboard/src/components/Monospaced/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Monospaced"; diff --git a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsConfiguration.js b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsConfiguration.js index 2923c531b0..89339e53e3 100644 --- a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsConfiguration.js +++ b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsConfiguration.js @@ -16,7 +16,8 @@ import Grid from "@material-ui/core/Grid"; import List from "@material-ui/core/List"; import ListItem, { ListItemTitle } from "/components/DetailedListItem"; import Maybe from "/components/Maybe"; -import Monospaced from "/components/Monospaced"; +import CodeBlock from "/components/CodeBlock"; +import CodeHighlight from "/components/CodeHighlight/CodeHighlight"; import SilencedIcon from "/icons/Silence"; import Typography from "@material-ui/core/Typography"; import Tooltip from "@material-ui/core/Tooltip"; @@ -137,8 +138,12 @@ class CheckDetailsConfiguration extends React.PureComponent { Command - - {check.command} + + + {code => ( + + )} + @@ -247,11 +252,18 @@ class CheckDetailsConfiguration extends React.PureComponent { ENV Vars - + {check.envVars.length > 0 ? ( - - {check.envVars.join("\n")} - + + + {code => ( + + )} + + ) : ( "None" )} @@ -324,15 +336,20 @@ class CheckDetailsConfiguration extends React.PureComponent { {Object.keys(check.extendedAttributes).length > 0 && ( - + - {`# Extra\n\n${JSON.stringify( - check.extendedAttributes, - null, - "\t", - )}`} + + {code => } + - + )} diff --git a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsPublishAction.js b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsPublishAction.js new file mode 100644 index 0000000000..fd51b5a08d --- /dev/null +++ b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsPublishAction.js @@ -0,0 +1,53 @@ +import React from "react"; +import PropTypes from "prop-types"; +import gql from "graphql-tag"; +import { withApollo } from "react-apollo"; + +import setCheckPublish from "/mutations/setCheckPublish"; + +import ToastConnector from "/components/relocation/ToastConnector"; +import PublishCheckStatusToast from "/components/relocation/PublishCheckStatusToast"; + +class CheckDetailsPublishAction extends React.PureComponent { + static propTypes = { + children: PropTypes.func.isRequired, + client: PropTypes.object.isRequired, + check: PropTypes.object.isRequired, + }; + + static fragments = { + check: gql` + fragment CheckDetailsPublishAction_check on CheckConfig { + id + name + publish + } + `, + }; + + render() { + const { children, client, check } = this.props; + + return ( + + {({ addToast }) => + children(() => { + const promise = setCheckPublish(client, { + id: check.id, + publish: true, + }); + addToast(({ remove }) => ( + + )); + }) + } + + ); + } +} + +export default withApollo(CheckDetailsPublishAction); diff --git a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsToolbar.js b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsToolbar.js index 96f03c7e67..339d603d2b 100644 --- a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsToolbar.js +++ b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsToolbar.js @@ -3,14 +3,18 @@ import PropTypes from "prop-types"; import gql from "graphql-tag"; import DeleteMenuItem from "/components/partials/ToolbarMenuItems/Delete"; +import PublishMenuItem from "/components/partials/ToolbarMenuItems/Publish"; import SilenceMenuItem from "/components/partials/ToolbarMenuItems/Silence"; import Toolbar from "/components/partials/Toolbar"; import ToolbarMenu from "/components/partials/ToolbarMenu"; +import UnpublishMenuItem from "/components/partials/ToolbarMenuItems/Unpublish"; import UnsilenceMenuItem from "/components/partials/ToolbarMenuItems/Unsilence"; import QueueMenuItem from "/components/partials/ToolbarMenuItems/QueueExecution"; import DeleteAction from "./CheckDetailsDeleteAction"; import ExecuteAction from "./CheckDetailsExecuteAction"; +import PublishAction from "./CheckDetailsPublishAction"; +import UnpublishAction from "./CheckDetailsUnpublishAction"; import SilenceAction from "./CheckDetailsSilenceAction"; import ClearSilenceAction from "./CheckDetailsClearSilenceAction"; @@ -81,6 +85,18 @@ class CheckDetailsToolbar extends React.Component { )} + + {!check.publish && ( + + {handler => } + + )} + {check.publish && ( + + {handler => } + + )} + {handler => } diff --git a/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsUnpublishAction.js b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsUnpublishAction.js new file mode 100644 index 0000000000..17e43a82d8 --- /dev/null +++ b/dashboard/src/components/partials/CheckDetailsContainer/CheckDetailsUnpublishAction.js @@ -0,0 +1,54 @@ +import React from "react"; +import PropTypes from "prop-types"; +import gql from "graphql-tag"; +import { withApollo } from "react-apollo"; + +import setCheckPublish from "/mutations/setCheckPublish"; + +import ToastConnector from "/components/relocation/ToastConnector"; +import PublishCheckStatusToast from "/components/relocation/PublishCheckStatusToast"; + +class CheckDetailsUnpublishAction extends React.PureComponent { + static propTypes = { + children: PropTypes.func.isRequired, + client: PropTypes.object.isRequired, + check: PropTypes.object.isRequired, + }; + + static fragments = { + check: gql` + fragment CheckDetailsPublishAction_check on CheckConfig { + id + name + publish + } + `, + }; + + render() { + const { children, client, check } = this.props; + + return ( + + {({ addToast }) => + children(() => { + const promise = setCheckPublish(client, { + id: check.id, + publish: false, + }); + addToast(({ remove }) => ( + + )); + }) + } + + ); + } +} + +export default withApollo(CheckDetailsUnpublishAction); diff --git a/dashboard/src/components/partials/ChecksList/ChecksListItem.js b/dashboard/src/components/partials/ChecksList/ChecksListItem.js index 6fa1c99247..c581e55344 100644 --- a/dashboard/src/components/partials/ChecksList/ChecksListItem.js +++ b/dashboard/src/components/partials/ChecksList/ChecksListItem.js @@ -4,6 +4,7 @@ import gql from "graphql-tag"; import Checkbox from "@material-ui/core/Checkbox"; import Code from "/components/Code"; +import CodeHighlight from "/components/CodeHighlight/CodeHighlight"; import ConfirmDelete from "/components/partials/ConfirmDelete"; import DeleteMenuItem from "/components/partials/ToolbarMenuItems/Delete"; import NamespaceLink from "/components/util/NamespaceLink"; @@ -82,7 +83,9 @@ class CheckListItem extends React.Component { } details={ - {check.command} + + {code => } +
diff --git a/dashboard/src/components/partials/EntityDetailsContainer/EntityDetailsInformation.js b/dashboard/src/components/partials/EntityDetailsContainer/EntityDetailsInformation.js index ddc37dc581..06d83a52e6 100644 --- a/dashboard/src/components/partials/EntityDetailsContainer/EntityDetailsInformation.js +++ b/dashboard/src/components/partials/EntityDetailsContainer/EntityDetailsInformation.js @@ -17,7 +17,8 @@ import Dictionary, { import List from "@material-ui/core/List"; import ListItem, { ListItemTitle } from "/components/DetailedListItem"; import Maybe from "/components/Maybe"; -import Monospaced from "/components/Monospaced"; +import CodeBlock from "/components/CodeBlock"; +import CodeHighlight from "/components/CodeHighlight/CodeHighlight"; import { RelativeToCurrentDate } from "/components/RelativeDate"; import StatusIcon from "/components/CheckStatusIcon"; import SilencedIcon from "/icons/Silence"; @@ -233,11 +234,16 @@ class EntityDetailsInformation extends React.PureComponent { {Object.keys(entity.extendedAttributes).length > 0 && ( - + - {JSON.stringify(entity.extendedAttributes, null, "\t")} + + {code => } + - + )} diff --git a/dashboard/src/components/partials/EventDetailsContainer/EventDetailsCheckResult.js b/dashboard/src/components/partials/EventDetailsContainer/EventDetailsCheckResult.js index b5879646a4..052a5ff7a4 100644 --- a/dashboard/src/components/partials/EventDetailsContainer/EventDetailsCheckResult.js +++ b/dashboard/src/components/partials/EventDetailsContainer/EventDetailsCheckResult.js @@ -21,7 +21,7 @@ import { } from "/components/DateFormatter"; import Duration from "/components/Duration"; import StatusIcon from "/components/CheckStatusIcon"; -import Monospaced from "/components/Monospaced"; +import CodeBlock from "/components/CodeBlock"; import Maybe from "/components/Maybe"; import SilencedIcon from "/icons/Silence"; import Tooltip from "@material-ui/core/Tooltip"; @@ -154,9 +154,9 @@ class EventDetailsCheckResult extends React.PureComponent { {check.output ? ( - + {check.output} - + ) : ( diff --git a/dashboard/src/components/partials/EventDetailsContainer/EventDetailsSummary.js b/dashboard/src/components/partials/EventDetailsContainer/EventDetailsSummary.js index 899f5935cd..0420271fab 100644 --- a/dashboard/src/components/partials/EventDetailsContainer/EventDetailsSummary.js +++ b/dashboard/src/components/partials/EventDetailsContainer/EventDetailsSummary.js @@ -11,7 +11,8 @@ import Dictionary, { DictionaryEntry, } from "/components/Dictionary"; import { RelativeToCurrentDate } from "/components/RelativeDate"; -import Monospaced from "/components/Monospaced"; +import CodeBlock from "/components/CodeBlock"; +import CodeHighlight from "/components/CodeHighlight/CodeHighlight"; import Maybe from "/components/Maybe"; import InlineLink from "/components/InlineLink"; import Typography from "@material-ui/core/Typography"; @@ -127,11 +128,16 @@ class EventDetailsSummary extends React.Component { {check.command && ( - + - {`# Executed command\n$ ${check.command}`} + + {code => } + - + )} diff --git a/dashboard/yarn.lock b/dashboard/yarn.lock index 5e637335f5..70c049848c 100644 --- a/dashboard/yarn.lock +++ b/dashboard/yarn.lock @@ -372,6 +372,10 @@ address@1.0.3, address@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" +ajv-errors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" + ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" @@ -2101,6 +2105,23 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +css-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.0.tgz#9f46aaa5ca41dbe31860e3b62b8e23c42916bf56" + dependencies: + babel-code-frame "^6.26.0" + css-selector-tokenizer "^0.7.0" + icss-utils "^2.1.0" + loader-utils "^1.0.2" + lodash.camelcase "^4.3.0" + postcss "^6.0.23" + postcss-modules-extract-imports "^1.2.0" + postcss-modules-local-by-default "^1.2.0" + postcss-modules-scope "^1.1.0" + postcss-modules-values "^1.3.0" + postcss-value-parser "^3.3.0" + source-list-map "^2.0.0" + css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -2110,6 +2131,14 @@ css-select@^1.1.0, css-select@~1.2.0: domutils "1.5.1" nth-check "~1.0.1" +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + css-vendor@^0.3.8: version "0.3.8" resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa" @@ -2120,6 +2149,10 @@ css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.2" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" @@ -3001,6 +3034,10 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + faye-websocket@~0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" @@ -3601,6 +3638,10 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +highlight.js@^9.13.1: + version "9.13.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" + history@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" @@ -3779,6 +3820,16 @@ iconv-lite@~0.4.13: dependencies: safer-buffer ">= 2.1.2 < 3" +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + +icss-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" + dependencies: + postcss "^6.0.1" + ieee754@^1.1.4: version "1.1.11" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" @@ -4988,7 +5039,7 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.2, loader-utils@^1.1.0: +loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" dependencies: @@ -5035,6 +5086,10 @@ lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -6017,10 +6072,49 @@ posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" +postcss-modules-extract-imports@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + dependencies: + postcss "^6.0.1" + +postcss-modules-local-by-default@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-scope@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-values@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" + postcss-value-parser@^3.2.3: version "3.3.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" +postcss-value-parser@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + +postcss@^6.0.1, postcss@^6.0.23: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + postcss@^6.0.17: version "6.0.22" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3" @@ -6539,6 +6633,14 @@ regexpp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -6837,6 +6939,13 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" +schema-utils@^0.4.0: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" @@ -6844,6 +6953,14 @@ schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4.5: ajv "^6.1.0" ajv-keywords "^3.1.0" +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -7257,6 +7374,13 @@ 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" +style-loader@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -7974,6 +8098,13 @@ worker-farm@^1.5.2: dependencies: errno "~0.1.7" +worker-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-2.0.0.tgz#45fda3ef76aca815771a89107399ee4119b430ac" + dependencies: + loader-utils "^1.0.0" + schema-utils "^0.4.0" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"