import mxgraph from '@mxgraph/core'; import { globalTypes } from '../.storybook/preview'; export default { title: 'Misc/Monitor', argTypes: { ...globalTypes } }; const Template = ({ label, ...args }) => { const { mxGraph, mxEdgeStyle, mxDomHelpers, mxXmlUtils, mxPerimeter, mxUtils, mxConstants, mxCloneUtils, mxCodec } = mxgraph; const div = document.createElement('div'); const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; container.style.width = `${args.width}px`; container.style.height = `${args.height}px`; container.style.background = 'url(/images/grid.gif)'; container.style.cursor = 'default'; div.appendChild(container); mxConstants.SHADOWCOLOR = '#e0e0e0'; // Creates the graph inside the given container const graph = createGraph(container); // Creates a process display using the activity names as IDs to refer to the elements const xml = '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ''; const doc = mxXmlUtils.parseXml(xml); const codec = new mxCodec(doc); codec.decode(doc.documentElement, graph.getModel()); const buttons = document.createElement('div'); div.appendChild(buttons); // Creates a button to invoke the refresh function buttons.appendChild( mxDomHelpers.button('Update', function(evt) { // XML is normally fetched from URL at server using mxUtils.get - this is a client-side // string with randomized states to demonstrate the idea of the workflow monitor const xml = `` + `` + ``; update(graph, xml); }) ); /** * Updates the display of the given graph using the XML data */ function update(graph, xml) { if (xml != null && xml.length > 0) { const doc = mxXmlUtils.parseXml(xml); if (doc != null && doc.documentElement != null) { const model = graph.getModel(); const nodes = doc.documentElement.getElementsByTagName('update'); if (nodes != null && nodes.length > 0) { model.beginUpdate(); try { for (let i = 0; i < nodes.length; i++) { // Processes the activity nodes inside the process node const id = nodes[i].getAttribute('id'); const state = nodes[i].getAttribute('state'); // Gets the cell for the given activity name from the model const cell = model.getCell(id); // Updates the cell color and adds some tooltip information if (cell != null) { // Resets the fillcolor and the overlay graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, 'white', [ cell, ]); graph.removeCellOverlays(cell); // Changes the cell color for the known states if (state == 'Running') { graph.setCellStyles( mxConstants.STYLE_FILLCOLOR, '#f8cecc', [cell] ); } else if (state == 'Waiting') { graph.setCellStyles( mxConstants.STYLE_FILLCOLOR, '#fff2cc', [cell] ); } else if (state == 'Completed') { graph.setCellStyles( mxConstants.STYLE_FILLCOLOR, '#d4e1f5', [cell] ); } // Adds tooltip information using an overlay icon if (state != 'Init') { // Sets the overlay for the cell in the graph graph.addCellOverlay( cell, createOverlay(graph.warningImage, `State: ${state}`) ); } } } // for } finally { model.endUpdate(); } } } } } /** * Creates an overlay object using the given tooltip and text for the alert window * which is being displayed on click. */ function createOverlay(image, tooltip) { const overlay = new mxCellOverlay(image, tooltip); // Installs a handler for clicks on the overlay overlay.addListener(mxEvent.CLICK, function(sender, evt) { mxUtils.alert(`${tooltip}\nLast update: ${new Date()}`); }); return overlay; } /** * Creates and returns an empty graph inside the given container. */ function createGraph(container) { const graph = new mxGraph(container); graph.setTooltips(true); graph.setEnabled(false); // Disables folding graph.isCellFoldable = function(cell, collapse) { return false; }; // Creates the stylesheet for the process display let style = graph.getStylesheet().getDefaultVertexStyle(); style[mxConstants.STYLE_FONTSIZE] = 11; style[mxConstants.STYLE_FONTCOLOR] = 'black'; style[mxConstants.STYLE_STROKECOLOR] = '#808080'; style[mxConstants.STYLE_FILLCOLOR] = 'white'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_GRADIENT_DIRECTION] = mxConstants.DIRECTION_EAST; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_SHADOW] = true; style[mxConstants.STYLE_FONTSTYLE] = 1; style = graph.getStylesheet().getDefaultEdgeStyle(); style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; style[mxConstants.STYLE_STROKECOLOR] = '#808080'; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_SHADOW] = true; style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; style[mxConstants.STYLE_STROKECOLOR] = '#a0a0a0'; style[mxConstants.STYLE_FONTCOLOR] = '#606060'; style[mxConstants.STYLE_FILLCOLOR] = '#E0E0DF'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_STARTSIZE] = 30; style[mxConstants.STYLE_ROUNDED] = false; style[mxConstants.STYLE_FONTSIZE] = 12; style[mxConstants.STYLE_FONTSTYLE] = 0; style[mxConstants.STYLE_HORIZONTAL] = false; // To improve text quality for vertical labels in some old IE versions... style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#efefef'; graph.getStylesheet().putCellStyle('swimlane', style); style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; style[mxConstants.STYLE_STROKECOLOR] = '#91BCC0'; style[mxConstants.STYLE_FONTCOLOR] = 'gray'; style[mxConstants.STYLE_FILLCOLOR] = '#91BCC0'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; style[mxConstants.STYLE_FONTSIZE] = 16; graph.getStylesheet().putCellStyle('step', style); style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; style[mxConstants.STYLE_FONTCOLOR] = 'gray'; style[mxConstants.STYLE_FILLCOLOR] = '#A0C88F'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_STROKECOLOR] = '#A0C88F'; style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; style[mxConstants.STYLE_FONTSIZE] = 16; graph.getStylesheet().putCellStyle('start', style); style = mxCloneUtils.clone(style); style[mxConstants.STYLE_FILLCOLOR] = '#DACCBC'; style[mxConstants.STYLE_STROKECOLOR] = '#AF7F73'; graph.getStylesheet().putCellStyle('end', style); return graph; } /** * Returns a random state. */ function getState() { let state = 'Init'; const rnd = Math.random() * 4; if (rnd > 3) { state = 'Completed'; } else if (rnd > 2) { state = 'Running'; } else if (rnd > 1) { state = 'Waiting'; } return state; } return div; } export const Default = Template.bind({});