From 6ac5116e9d8fa261a8fc9e46434e5a5264f9bd9a Mon Sep 17 00:00:00 2001 From: benstov Date: Wed, 22 May 2019 17:20:09 +0200 Subject: [PATCH] fix(dashboard): stackgraph loses ws status when drawn --- dashboard/src/components/graph/index.tsx | 65 +++++++----------------- dashboard/src/containers/graph.tsx | 8 ++- dashboard/src/context/data.tsx | 11 +++- 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/dashboard/src/components/graph/index.tsx b/dashboard/src/components/graph/index.tsx index 4626fc1335..6d66199794 100644 --- a/dashboard/src/components/graph/index.tsx +++ b/dashboard/src/components/graph/index.tsx @@ -21,17 +21,17 @@ import { colors, fontMedium } from "../../styles/variables" import Spinner, { SpinnerProps } from "../spinner" import { SelectGraphNode, StackGraphSupportedFilterKeys } from "../../context/ui" import { WsEventMessage, SupportedEventName } from "../../context/events" -import { Events } from "garden-cli/src/events" import { Extends } from "garden-cli/src/util/util" import { ConfigDump } from "garden-cli/src/garden" -import { GraphOutput } from "garden-cli/src/commands/get/get-graph" import { FiltersButton, Filters } from "../group-filter" import { RenderedNodeType } from "garden-cli/src/config-graph" +import { GraphOutputWithNodeStatus } from "../../context/data" interface Node { name: string label: string id: string + status?: string } interface Edge { @@ -52,11 +52,6 @@ type TaskNodeEventName = Extends< "taskPending" | "taskProcessing" | "taskComplete" | "taskError" > -type WsTaskNodeMessage = WsEventMessage & { - name: TaskNodeEventName; - payload: Events[TaskNodeEventName]; -} - const taskNodeEventNames: Set = new Set([ "taskPending", "taskProcessing", @@ -72,18 +67,19 @@ function clearGraphNodeSelection() { selectedNode && selectedNode.classList.remove(selectedClassName) } -/** - * Type guard to check whether WsEventMessage is of type WsTaskNodeMessage - */ -function isTaskNodeMessage( - message: WsEventMessage, -): message is WsTaskNodeMessage { - return taskNodeEventNames.has((message as WsTaskNodeMessage).name) -} - const MIN_CHART_WIDTH = 200 const MIN_CHART_HEIGHT = 200 +function getNodeClass(node) { + let className = "" + if (selectedNodeId === node.id) { + className += selectedClassName + } + + className += (node.status && ` ${node.status}` || "") + return className +} + function drawChart( graph: Graph, width: number, @@ -97,13 +93,10 @@ function drawChart( return {} }) - // Here we"re setting nodeclass, which is used by our custom drawNodes function - // below. - for (const node of graph.nodes) { g.setNode(node.id, { label: node.label, - class: node.id === selectedNodeId ? selectedClassName : "", + class: getNodeClass(node), id: node.id, labelType: "html", }) @@ -188,7 +181,7 @@ function drawChart( interface Props { config: ConfigDump - graph: GraphOutput + graph: GraphOutputWithNodeStatus onGraphNodeSelected: SelectGraphNode selectedGraphNode: string | null layoutChanged: boolean @@ -322,6 +315,7 @@ class Chart extends Component { id: n.key, name: n.name, label: makeLabel(n.name, n.type, n.moduleName), + status: n.status, } }) const edges: Edge[] = this.props.graph.relationships @@ -340,20 +334,15 @@ class Chart extends Component { } componentDidUpdate(prevProps: Props, prevState: State) { - const message = this.props.message - if (message && message.type === "event") { - this.updateNodeClass(message) - } - if (prevState !== this.state) { - this.drawChart() - } - if ( + (prevState !== this.state) || + (prevProps.graph !== this.props.graph) || (!prevProps.selectedGraphNode && this.props.selectedGraphNode) || (prevProps.selectedGraphNode && !this.props.selectedGraphNode) || (prevProps.layoutChanged !== this.props.layoutChanged)) { this.drawChart() } + if (!this.props.selectedGraphNode) { clearGraphNodeSelection() } @@ -366,24 +355,6 @@ class Chart extends Component { } } - // Update the node class instead of re-rendering the graph for perf reasons - updateNodeClass(message: WsEventMessage) { - if (!isTaskNodeMessage(message)) { - return - } - for (const node of this._nodes) { - if (message.payload.key && node.id === message.payload.key) { - const nodeEl = document.getElementById(node.id) - if (nodeEl) { - this.clearClasses(nodeEl) - if (taskNodeEventNames.has(message.name)) { - nodeEl.classList.add(message.name) // we use the event name as the class name - } - } - } - } - } - render() { const { message } = this.props const chartHeightEstimate = `100vh - 2rem` diff --git a/dashboard/src/containers/graph.tsx b/dashboard/src/containers/graph.tsx index 394002a653..aec6357076 100644 --- a/dashboard/src/containers/graph.tsx +++ b/dashboard/src/containers/graph.tsx @@ -42,6 +42,13 @@ export default () => { if (!config.data || !graph.data || config.loading || graph.loading) { return } + if (message && message.type === "event") { + const nodeToUpdate = graph.data.nodes.find(node => node.key === (message.payload && message.payload["key"])) + if (nodeToUpdate) { + nodeToUpdate.status = message.name + graph.data = { ...graph.data } + } + } let moreInfoPane: React.ReactNode = null if (selectedGraphNode && graph.data) { @@ -59,7 +66,6 @@ export default () => {