From bee72e656118d4a75444ca17f1e86807e57b9c93 Mon Sep 17 00:00:00 2001 From: benstov Date: Thu, 25 Apr 2019 17:10:00 +0200 Subject: [PATCH] feat(dashboard): add 'more info' pane to stack graph --- dashboard/package-lock.json | 5 + dashboard/package.json | 1 + dashboard/public/favicon.ico | Bin 1150 -> 5398 bytes dashboard/src/api/index.ts | 12 + dashboard/src/api/types.ts | 36 ++- dashboard/src/app.tsx | 27 +- dashboard/src/assets/close-pane.svg | 4 + dashboard/src/assets/open-pane.svg | 4 + dashboard/src/components/card.tsx | 13 +- dashboard/src/components/checkbox.tsx | 16 +- dashboard/src/components/graph/graph.scss | 41 ++- dashboard/src/components/graph/index.tsx | 173 ++++++++--- dashboard/src/components/logs.tsx | 5 +- dashboard/src/components/overview.tsx | 23 +- dashboard/src/components/table.tsx | 1 - dashboard/src/components/tag.tsx | 45 +++ dashboard/src/containers/graph.tsx | 46 ++- dashboard/src/containers/sidebar.tsx | 5 +- .../src/containers/task-result-node-info.tsx | 210 +++++++++++++ .../src/containers/test-result-node-info.tsx | 204 +++++++++++++ dashboard/src/context/data.tsx | 122 ++++++-- dashboard/src/context/ui.tsx | 22 ++ dashboard/src/styles/custom-flexboxgrid.scss | 287 ++++++++++++++++++ dashboard/src/styles/icons.scss | 21 ++ dashboard/src/styles/variables.ts | 1 + dashboard/src/util/helpers.ts | 20 ++ docs/reference/commands.md | 31 ++ garden-service/src/commands/base.ts | 1 - .../src/commands/get/get-task-result.ts | 101 ++++++ .../src/commands/get/get-test-result.ts | 124 ++++++++ garden-service/src/commands/get/get.ts | 4 + 31 files changed, 1485 insertions(+), 120 deletions(-) create mode 100644 dashboard/src/assets/close-pane.svg create mode 100644 dashboard/src/assets/open-pane.svg create mode 100644 dashboard/src/components/tag.tsx create mode 100644 dashboard/src/containers/task-result-node-info.tsx create mode 100644 dashboard/src/containers/test-result-node-info.tsx create mode 100644 dashboard/src/styles/custom-flexboxgrid.scss create mode 100644 dashboard/src/styles/icons.scss create mode 100644 garden-service/src/commands/get/get-task-result.ts create mode 100644 garden-service/src/commands/get/get-test-result.ts diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 4b0501e4bf..587ad45377 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -6535,6 +6535,11 @@ "resolved": "https://registry.npmjs.org/flexboxgrid/-/flexboxgrid-6.3.1.tgz", "integrity": "sha1-6ZiYr8B7cEdyK7galYpfuk1OIP0=" }, + "flexboxgrid-helpers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/flexboxgrid-helpers/-/flexboxgrid-helpers-1.1.3.tgz", + "integrity": "sha1-qLvRX9Rtyf0inmgbz++wezdQaKs=" + }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", diff --git a/dashboard/package.json b/dashboard/package.json index a0463ca44e..6e446dd14d 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -25,6 +25,7 @@ "dagre-d3": "^0.6.1", "emotion": "^10.0.0", "flexboxgrid": "^6.3.1", + "flexboxgrid-helpers": "^1.1.3", "http-proxy-middleware": "^0.19.1", "lodash": "^4.17.11", "node-sass": "^4.10.0", diff --git a/dashboard/public/favicon.ico b/dashboard/public/favicon.ico index 4862e0d9a97aebfaffbd45d5d7192eaa285f53ee..8d241d0b36b886c914010af276555f834f12f7d9 100644 GIT binary patch literal 5398 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 literal 1150 zcmdUvyGz4R7{$*8|A0=;4px%Cs}EeNPIhn=1$7WA=+Igp;Gz|DFlr`i!HONKf>0d9 z*QTJGlE?A8DFG8&g-n|8-3#C4$35rdBY=`Om4d887##ox0T@!!l1{fT8z5(CIn)(C zg(^5!0ZT=2Edw@Y!1o&XbUMP8ljZeCo}X8Fdaaz_xi{Uj7sZo1I0xtOrI>`T|3Q99 z{I6%l|19{{&;LW$e_a3gD!3)N9Zi9krI1he%`eVR2*0}k)~CUn70oNje^~fT&-{Dw zwUA%_ffxPFSH+}!`_^>rN5$h#^!sc5zuoU#(T4YZesq4~-w*r;`oZT$ zG(XLkEz>J(E6!QMH^FfJ { return apiPost("get.status") } +export async function fetchTaskResult(params: FetchTaskResultParam): Promise { + return apiPost("get.task-result", params) +} + +export async function fetchTestResult(params: FetchTestResultParam): Promise { + return apiPost("get.test-result", params) +} + export async function fetchLogs(services: FetchLogsParam): Promise { const tail = Math.floor(MAX_LOG_LINES / services.length) return apiPost("logs", { services, tail }) diff --git a/dashboard/src/api/types.ts b/dashboard/src/api/types.ts index 569592c376..d01d64863c 100644 --- a/dashboard/src/api/types.ts +++ b/dashboard/src/api/types.ts @@ -11,7 +11,9 @@ export type Primitive = string | number | boolean -export interface PrimitiveMap { [key: string]: Primitive } +export interface PrimitiveMap { + [key: string]: Primitive +} export interface DashboardPage { title: string @@ -58,7 +60,7 @@ export interface ServiceStatus { version?: string state?: string runningReplicas?: number - ingresses?: ServiceIngress[], + ingresses?: ServiceIngress[] lastMessage?: string lastError?: string createdAt?: string @@ -91,9 +93,18 @@ export type RenderedNode = { moduleName: string, } -export type RenderedNodeType = "build" | "deploy" | "run" | "test" | "push" | "publish" +export type RenderedNodeType = + | "build" + | "deploy" + | "run" + | "test" + | "push" + | "publish" -export type RenderedEdge = { dependant: RenderedNode, dependency: RenderedNode } +export type RenderedEdge = { + dependant: RenderedNode, + dependency: RenderedNode, +} export interface FetchGraphResponse { nodes: RenderedNode[], @@ -127,3 +138,20 @@ export interface WsMessage { name: NodeTask | "taskGraphProcessing" | "taskGraphComplete" payload: WsPayload } + +export interface FetchTaskResultResponse { + name: string + module: string + version: string + output: string + startedAt: Date + completedAt: Date +} +export interface FetchTestResultResponse { + name: string + version: string + output: string + module: string + startedAt: Date + completedAt: Date +} diff --git a/dashboard/src/app.tsx b/dashboard/src/app.tsx index d6ba03aa02..77a06cb380 100644 --- a/dashboard/src/app.tsx +++ b/dashboard/src/app.tsx @@ -21,20 +21,25 @@ import Provider from "./components/provider" import { colors } from "./styles/variables" import "flexboxgrid/dist/flexboxgrid.min.css" import "./styles/padding-margin-mixin.scss" +import "./styles/custom-flexboxgrid.scss" +import "./styles/icons.scss" + import { EventProvider } from "./context/events" import { DataProvider } from "./context/data" import { NavLink } from "./components/links" import logo from "./assets/logo.png" -import { ReactComponent as Hamburger } from "./assets/hamburger.svg" +import { ReactComponent as OpenSidebarIcon } from "./assets/open-pane.svg" +import { ReactComponent as CloseSidebarIcon } from "./assets/close-pane.svg" import { UiStateProvider, UiStateContext } from "./context/ui" // Style and align properly const Logo = styled.img` + width: 10rem; height: auto; - width: 100%; max-width: 10rem; + margin-top: .7rem; ` const SidebarWrapper = styled.div` @@ -43,13 +48,14 @@ const SidebarWrapper = styled.div` position: relative; ` const SidebarContainer = styled.div` - display: ${props => (props.visible ? `block` : "none")} - width: ${props => (props.visible ? `19rem` : "0")} + display: ${props => (props.visible ? `block` : "none")}; + width: ${props => (props.visible ? `12rem` : "0")}; ` + const SidebarToggleButton = styled.div` position: absolute; - right: -2.5rem; - top: 1rem; + right: -2.2rem; + top: 3rem; width: 1.5rem; cursor: pointer; ` @@ -81,11 +87,16 @@ const App = () => { height: 100vh; max-height: 100vh; overflow-y: hidden; + background: ${colors.gardenGrayLighter}; `} > - + {isSidebarOpen ? ( + + ) : ( + + )}
@@ -111,7 +122,7 @@ const App = () => { flex-grow: 1; `, "pl-3", - "pt-4", + "pt-2", "pr-1", )} > diff --git a/dashboard/src/assets/close-pane.svg b/dashboard/src/assets/close-pane.svg new file mode 100644 index 0000000000..7c6a7d03ed --- /dev/null +++ b/dashboard/src/assets/close-pane.svg @@ -0,0 +1,4 @@ + + + + diff --git a/dashboard/src/assets/open-pane.svg b/dashboard/src/assets/open-pane.svg new file mode 100644 index 0000000000..ce11e32113 --- /dev/null +++ b/dashboard/src/assets/open-pane.svg @@ -0,0 +1,4 @@ + + + + diff --git a/dashboard/src/components/card.tsx b/dashboard/src/components/card.tsx index 6fac9245a6..6eb46a34f8 100644 --- a/dashboard/src/components/card.tsx +++ b/dashboard/src/components/card.tsx @@ -13,13 +13,16 @@ import { colors, fontMedium } from "../styles/variables" interface CardProps { children: JSX.Element - title?: string + title?: string, + backgroundColor?: string } const Wrapper = styled.div` - background-color: ${colors.gardenWhite}; + background-color: ${props => props.backgroundColor || colors.gardenWhite}; border-radius: 2px; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + width: 100%; + overflow: hidden; ` export const CardTitle = styled.h3` @@ -28,16 +31,16 @@ export const CardTitle = styled.h3` margin: 0; ` -const Card: React.SFC = ({ children, title }) => { +const Card: React.SFC = ({ children, title, backgroundColor }) => { const titleEl = title ? ( -
+
{title}
) : null return ( - + {titleEl} {children} diff --git a/dashboard/src/components/checkbox.tsx b/dashboard/src/components/checkbox.tsx index 6887e9a1ea..c102d04591 100644 --- a/dashboard/src/components/checkbox.tsx +++ b/dashboard/src/components/checkbox.tsx @@ -15,15 +15,10 @@ const Label = styled.label` display: block; position: relative; padding-left: 35px; - margin-bottom: 12px; cursor: pointer; font-size: 1.1rem; user-select: none; - :hover { - input, span { - background-color: ${colors.gray}; - } - } + margin-bottom: 1rem; ` const Input = styled.input` @@ -39,8 +34,8 @@ const Input = styled.input` const Checkmark = styled.span` position: absolute; - top: 0; - left: 0; + top: 0rem; + left: 0rem; height: 21px; width: 21px; border: 1px solid ${colors.gardenGrayLight}; @@ -68,16 +63,15 @@ const CheckmarkChecked = styled(Checkmark)` interface Props { name: string - label: string checked?: boolean onChange: (event: ChangeEvent) => void } -const CheckBox: React.SFC = ({ name, label, onChange, checked = false }) => { +const CheckBox: React.SFC = ({ name, onChange, checked = false, children }) => { const Mark = checked ? CheckmarkChecked : Checkmark return ( diff --git a/dashboard/src/components/graph/graph.scss b/dashboard/src/components/graph/graph.scss index f7e5799451..1b402e5d70 100644 --- a/dashboard/src/components/graph/graph.scss +++ b/dashboard/src/components/graph/graph.scss @@ -23,11 +23,6 @@ stroke: red; } - text { - font-weight: 700; - font-size: 1em; - } - .node rect { fill: #fff; stroke: #02f2b4; @@ -35,21 +30,37 @@ } .edgePath path { - stroke: rgba(0,0,0,0.32); + stroke: rgba(0, 0, 0, 0.32); stroke-width: 1.5px; } - div.label-wrap { - text-align: center; + .label-container { + cursor: pointer; + } + + .label-container { + cursor: pointer; + } - span.name { - font-weight: 700; - font-size: 0.9rem; + div.node-container { + text-align: center; + padding: 1rem; + background-repeat: no-repeat; + background-position: left; + background-position-x: -0.5rem; + background-size: 4rem; + &--run, + &--test { + cursor: pointer; } - span.type { - display: inline-block; - margin-top: 0.5em + .type { + color: gray; + padding-bottom: 0.2rem; } - } + .module-name { + color: #343434; + font-weight: bold; + } + } } diff --git a/dashboard/src/components/graph/index.tsx b/dashboard/src/components/graph/index.tsx index 0f9f8d092c..e170ef89ca 100644 --- a/dashboard/src/components/graph/index.tsx +++ b/dashboard/src/components/graph/index.tsx @@ -26,6 +26,7 @@ import "./graph.scss" import { colors, fontMedium } from "../../styles/variables" import Spinner from "../spinner" import CheckBox from "../checkbox" +import { SelectGraphNode } from "../../context/ui" interface Node { name: string @@ -48,11 +49,18 @@ export interface Graph { const MIN_CHART_WIDTH = 200 const MIN_CHART_HEIGHT = 200 -function drawChart(graph: Graph, width: number, height: number) { +function drawChart( + graph: Graph, + width: number, + height: number, + onNodeSelected: (string) => void, +) { // Create the input graph const g = new dagreD3.graphlib.Graph() .setGraph({}) - .setDefaultEdgeLabel(function() { return {} }) + .setDefaultEdgeLabel(function() { + return {} + }) // Here we"re setting nodeclass, which is used by our custom drawNodes function // below. @@ -69,11 +77,11 @@ function drawChart(graph: Graph, width: number, height: number) { const node = g.node(v) // Round the corners of the nodes node.rx = node.ry = 5 - // Add more padding - node.paddingBottom = 20 - node.paddingTop = 20 - node.paddingLeft = 20 - node.paddingRight = 20 + // Remove node padding + node.paddingBottom = 0 + node.paddingTop = 0 + node.paddingLeft = 0 + node.paddingRight = 0 }) // Set up edges, no special attributes. @@ -91,7 +99,9 @@ function drawChart(graph: Graph, width: number, height: number) { width = Math.max(width, MIN_CHART_WIDTH) height = Math.max(height, MIN_CHART_HEIGHT) - const svg = d3.select("#chart").append("svg") + const svg = d3 + .select("#chart") + .append("svg") .attr("width", width) .attr("height", height) @@ -120,11 +130,17 @@ function drawChart(graph: Graph, width: number, height: number) { const zoomTranslate = d3.zoomIdentity.translate(xCenterOffset, yCenterOffset).scale(initialScale) svg.call(zoom.transform, zoomTranslate) + const selections = svg.select("g").selectAll("g.node") + selections.on("click", evt => { + onNodeSelected(evt) + }) } interface Props { config: FetchConfigResponse graph: FetchGraphResponse + selectGraphNode: SelectGraphNode + selectedGraphNode: string message?: WsMessage } @@ -136,12 +152,29 @@ interface State { // Renders as HTML const makeLabel = (name: string, type: string, moduleName: string) => { - if (type === "test") { - type = `${type} (${name})` - name = moduleName - } - return "
" + - name + "
" + type + "
" + return ` +
+
${type}
+ + ${moduleName} + ${ + moduleName !== name + ? ` / + ${name}` + : `` + } +
` + // return ` + //
+ // + // ${moduleName} + // ${ + // moduleName !== name + // ? ` / + // ${name}` + // : `` + // } + //
` } const Span = styled.span` @@ -157,8 +190,16 @@ const ProcessSpinner = styled(Spinner)` margin: 16px 0 0 20px; ` -class Chart extends Component { +// const IconContainer = styled.span` +// display: inline-block; +// width: 3rem; +// height: 3rem; +// background-size: contain; +// background-repeat: no-repeat; +// vertical-align: middle; +// ` +class Chart extends Component { _nodes: Node[] _edges: Edge[] _chartRef: React.RefObject @@ -215,7 +256,7 @@ class Chart extends Component { this._edges = graph.edges const width = this._chartRef.current.offsetWidth const height = this._chartRef.current.offsetHeight - drawChart(graph, width, height) + drawChart(graph, width, height, this.props.selectGraphNode) } makeGraph() { @@ -243,7 +284,7 @@ class Chart extends Component { return { edges, nodes } } - componentDidUpdate(_prevProps, prevState: State) { + componentDidUpdate(prevProps: Props, prevState: State) { const message = this.props.message if (message && message.type === "event") { this.updateNodeClass(message) @@ -251,6 +292,10 @@ class Chart extends Component { if (prevState.filters !== this.state.filters) { this.drawChart() } + + if (prevProps.selectedGraphNode !== this.props.selectedGraphNode) { + this.drawChart() + } } clearClasses(el: HTMLElement) { @@ -281,47 +326,99 @@ class Chart extends Component { let status = "" if (message && message.name !== "taskGraphComplete") { status = "Processing..." - spinner = + spinner = ( + + ) } return ( -
-
- {taskTypes.map(type => ( -
+
+
+ {taskTypes.map(type => { + return
+ > + {/* {capitalize(type)} */} + {capitalize(type)} + +
- ))} -
-
+ })}
-
-
+
+
+
{status} {spinner}

- Ready - -- Pending - Error + + + —{" "} + + Ready + + + + --{" "} + + Pending + + + + —{" "} + + Error +

) } - } export default Chart diff --git a/dashboard/src/components/logs.tsx b/dashboard/src/components/logs.tsx index 3f6b8eded3..b4622b30a7 100644 --- a/dashboard/src/components/logs.tsx +++ b/dashboard/src/components/logs.tsx @@ -34,10 +34,11 @@ interface State { const Header = styled.div` display: flex; justify-content: space-between; + align-items: center; ` const Button = styled.div` - padding: 0.5em; + padding: 0.3em; border-radius: 10%; border: 2px solid ${colors.gardenGrayLight}; cursor: pointer; @@ -147,7 +148,7 @@ class Logs extends Component {
-
+
{title}