Skip to content

Commit

Permalink
Merge pull request #791 from garden-io/persistent-stackgraph-status
Browse files Browse the repository at this point in the history
fix(dashboard): stackgraph loses ws status when drawn
  • Loading branch information
eysi09 authored May 29, 2019
2 parents 385f17f + 112e582 commit a03cafb
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 49 deletions.
65 changes: 18 additions & 47 deletions dashboard/src/components/graph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -52,11 +52,6 @@ type TaskNodeEventName = Extends<
"taskPending" | "taskProcessing" | "taskComplete" | "taskError"
>

type WsTaskNodeMessage = WsEventMessage & {
name: TaskNodeEventName;
payload: Events[TaskNodeEventName];
}

const taskNodeEventNames: Set<TaskNodeEventName> = new Set([
"taskPending",
"taskProcessing",
Expand All @@ -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,
Expand All @@ -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",
})
Expand Down Expand Up @@ -188,7 +181,7 @@ function drawChart(

interface Props {
config: ConfigDump
graph: GraphOutput
graph: GraphOutputWithNodeStatus
onGraphNodeSelected: SelectGraphNode
selectedGraphNode: string | null
layoutChanged: boolean
Expand Down Expand Up @@ -322,6 +315,7 @@ class Chart extends Component<Props, State> {
id: n.key,
name: n.name,
label: makeLabel(n.name, n.type, n.moduleName),
status: n.status,
}
})
const edges: Edge[] = this.props.graph.relationships
Expand All @@ -340,20 +334,15 @@ class Chart extends Component<Props, State> {
}

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()
}
Expand All @@ -366,24 +355,6 @@ class Chart extends Component<Props, State> {
}
}

// 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`
Expand Down
8 changes: 7 additions & 1 deletion dashboard/src/containers/graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ export default () => {
if (!config.data || !graph.data || config.loading || graph.loading) {
return <Spinner />
}
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) {
Expand All @@ -59,7 +66,6 @@ export default () => {
<Wrapper className="row">
<div className={moreInfoPane ? "col-xs-7 col-sm-7 col-md-8 col-lg-8 col-xl-8" : "col-xs"}>
<Graph
message={message}
onGraphNodeSelected={selectGraphNode}
selectedGraphNode={selectedGraphNode}
layoutChanged={isSidebarOpen}
Expand Down
11 changes: 10 additions & 1 deletion dashboard/src/context/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,21 @@ import { TaskResultOutput } from "garden-cli/src/commands/get/get-task-result"
import { StatusCommandResult } from "garden-cli/src/commands/get/get-status"
import { TestResultOutput } from "garden-cli/src/commands/get/get-test-result"
import { AxiosError } from "axios"
import { RenderedNode } from "garden-cli/src/config-graph"
import { SupportedEventName } from "./events"

interface StoreCommon {
error?: AxiosError
loading: boolean
}

export interface RenderedNodeWithStatus extends RenderedNode {
status?: SupportedEventName
}
export interface GraphOutputWithNodeStatus extends GraphOutput {
nodes: RenderedNodeWithStatus[],
}

// This is the global data store
interface Store {
config: StoreCommon & {
Expand All @@ -42,7 +51,7 @@ interface Store {
data?: StatusCommandResult,
},
graph: StoreCommon & {
data?: GraphOutput,
data?: GraphOutputWithNodeStatus,
},
logs: StoreCommon & {
data?: ServiceLogEntry[],
Expand Down

0 comments on commit a03cafb

Please sign in to comment.