import { Module } from 'vuex' ; import store , { RootState } from '@/store' ; import _ from 'lodash' ; import { DataflowState , CreateNodeOptions , CreateEdgeOptions , CreateEdgeBetweenPortAndNodeOptions , CreateEdgeFromPortToPortOptions , NodeType , } from './types' ; import * as helper from './helper' ; import * as saveLoad from './save-load' ; import * as nodeTypes from './node-types' ; import * as history from './history' ; import * as layout from './layout' ; export * from './util' ; import Node from '@/components/node/node' ; import Edge from '@/components/edge/edge' ; import { Port , OutputPort , InputPort } from '@/components/port' ; import DataflowCanvas from '@/components/dataflow-canvas/dataflow-canvas' ; import { HistoryDiagramEvent } from '@/store/history/types' ; import TabularDataset from '@/data/tabular-dataset' ; import DataSource from '@/components/data-source/data-source' ; /** It is expected that the number of nodes do not exceed this limit, and we can rotate 500 layers. */ const MAX_NODE_LAYERS = 500 ; export const getInitialState = ( ) : DataflowState => ( { canvas : undefined , nodeTypes : nodeTypes . nodeTypes , nodes : [ ] , numNodeLayers : 0 , filename : '' , diagramName : '' , isDeserializing : false , lastDiagramList : null , autoSaveTimer : null } ) ; export const initialState = getInitialState ( ) ; const getters = { /**
     * Gets the z-index of the largest node layer. This is used to move activated node to the front and above
     * all other nodes.
     */ topNodeLayer : ( state ) : number => { return state . numNodeLayers ; } , /**
     * Retrieves the img source for a given type of node.
     */ getImgSrc : ( state ) : ( type : string ) => string => { return ( type ) => nodeTypes . getImgSrc ( type ) ; } , /**
     * Retrieves the supported node types.
     */ nodeTypes : ( state ) : NodeType [ ] => { if ( store . state . systemOptions . useBetaFeatures ) { return nodeTypes . nodeTypes ; } return nodeTypes . nodeTypes . filter ( nodeType => ! nodeType . isBeta ) ; } , /**
     * Retrieves the node labels used in the diagram.
     */ nodeLabels : ( state ) : string [ ] => { return state . nodes . map ( node => node . getLabel ( ) ) ; } , /**
     * Retrieves the tabular datasets used in the diagram.
     */ tabularDatasets : ( state ) : TabularDataset [ ] => { return state . nodes . filter ( node => node . nodeType === 'data-source' && ( node as DataSource ) . getDataset ( ) ) . map ( node => ( node as DataSource ) . getDataset ( ) as TabularDataset ) ; } } ; const mutations = { /**
     * Sets the rendering canvas to the global Vue Dataflow instance.
     * This is called exactly once when App component is mounted.
     */ setCanvas : ( state , canvas ) => { state . canvas = canvas ; } , /**
     * Assigns a new layer for a node.
     * This typically happens when a node is clicked so that it appears on top of the other nodes.
     */ incrementNodeLayer : ( state ) => { if ( state . numNodeLayers === MAX_NODE_LAYERS ) { state . nodes . forEach ( node => { node . layer = node . layer - MAX_NODE_LAYERS / 2 ; } ) ; state . numNodeLayers -= MAX_NODE_LAYERS / 2 ; } state . numNodeLayers ++ ; } , /**
     * Creates a node without propagation. This assumes the new node does not connect to any other node.
     */ createNode : ( state , options ) => { const node = helper . createNode ( state , options ) ; store . commit ( 'interaction/clickBackground' ) ; if ( store . state . interaction . mouseupEdge ) { const result = helper . insertNodeOnEdge ( state , node , store . state . interaction . mouseupEdge ) ; store . commit ( 'interaction/clearMouseupEdge' ) ; store . commit ( 'history/commit' , history . createNodeOnEdgeEvent ( [ history . removeEdgeEvent ( result . removedEdge ) , history . createNodeEvent ( node , state . nodes ) , ] . concat ( result . createdEdges . map ( edge => history . createEdgeEvent ( edge ) ) ) ) ) ; } else { store . commit ( 'history/commit' , history . createNodeEvent ( node , state . nodes ) ) ; } } , /** Removes a node and propagates. */ removeNode : ( state , node ) => { store . commit ( 'history/commit' , history . removeNodeAndIncidentEdgesEvent ( node , state . nodes ) ) ; helper . removeNode ( state , node , true ) ; } , /** Removes the nodes that are currently selected. */ removeSelectedNodes : ( state ) => { const result = helper . removeSelectedNodes ( state ) ; store . commit ( 'history/commit' , history . removeNodesEvent ( result . removedEdges . map ( edge => history . removeEdgeEvent ( edge ) ) . concat ( result . removedNodes . map ( node => history . removeNodeEvent ( node , state . nodes ) ) ) ) ) ; } , /** Creates an edge and propagates. */ createEdge : ( state , options ) => { let edge = null ; if ( ( options as CreateEdgeFromPortToPortOptions ) . sourcePort ) { const portPortOptions = options as CreateEdgeFromPortToPortOptions ; edge = helper . createEdge ( state , portPortOptions . sourcePort , portPortOptions . targetPort , true ) ; } else { const portNodeOptions = options as CreateEdgeBetweenPortAndNodeOptions ; if ( portNodeOptions . port . isInput ) { edge = helper . createEdgeFromNode ( state , portNodeOptions . node , portNodeOptions . port as InputPort , true ) ; } else { edge = helper . createEdgeToNode ( state , portNodeOptions . port as OutputPort , portNodeOptions . node , true ) ; } } if ( edge !== null ) { store . commit ( 'history/commit' , history . createEdgeEvent ( edge ) ) ; } } , /** Removes an edge and propagates. */ removeEdge : ( state , edge ) => { store . commit ( 'history/commit' , history . removeEdgeEvent ( edge ) ) ; helper . removeEdge ( state , edge , true ) ; } , /**
     * Inerts a node onto the given edge.
     * This happens when the user drags a node on canvas onto an edge on canvas, and is triggered by store/interaction.
     */ insertNodeOnEdge : ( state , { node , edge } ) => { const result = helper . insertNodeOnEdge ( state , node , edge ) ; store . commit ( 'interaction/clearMouseupEdge' ) ; const events = [ history . removeEdgeEvent ( edge ) ] . concat ( result . createdEdges . map ( e => history . createEdgeEvent ( e ) ) ) ; store . commit ( 'history/commit' , history . insertNodeOnEdgeEvent ( events , node ) ) ; } , /** Removes all incident edges to a port and propagates. */ disconnectPort : ( state , port ) => { const removedEdges = helper . disconnectPort ( state , port , true ) ; store . commit ( 'history/commit' , history . disconnectPortEvent ( removedEdges . map ( e => history . removeEdgeEvent ( e ) ) ) ) ; } , /** Notifies of port data change and propagates the change. */ portUpdated : ( state , port ) => { if ( state . isDeserializing ) { console . log ( 'propagation blocked during deserialization from port of node' , port . node . id ) ; return ; } helper . propagatePort ( port ) ; } , /** Notifies of node data change and propagates the change. */ nodeUpdated : ( state , node ) => { if ( state . isDeserializing ) { console . log ( 'propagation blocked during deserialization from node' , node . id ) ; return ; } helper . propagateNode ( node ) ; } , /** Moves all nodes by (dx, dy). */ moveDiagram : ( state , { dx , dy } ) => { _ . each ( state . nodes . filter ( node => node . isVisible ) , node => node . moveBy ( dx , dy ) ) ; } , undo : ( state , evt ) => { history . undo ( state , evt ) ; } , redo : ( state , evt ) => { history . redo ( state , evt ) ; } , autoLayout : ( state , movableNodes ? ) => { let nodes = movableNodes || store . getters [ 'interaction/selectedNodes' ] ; if ( nodes . length === 0 ) { nodes = undefined ; } layout . autoLayout ( state , nodes , { onComplete : ( result , transitionDone ) => { if ( transitionDone ) { store . commit ( 'history/commit' , history . autoLayoutEvent ( result ) ) ; } } } ) ; } , /** Turns on the node labels for all nodes. */ labelAllNodes : ( state ) => { state . nodes . forEach ( node => node . setLabelVisible ( true ) ) ; } , /** Toggles the data mutation boundary. */ toggleDataMutationBoundary : ( state , visible ) => { helper . dataMutationBoundary ( visible ) ; } , ... saveLoad . mutations } ; const actions = { ... saveLoad . actions } ; const dataflow = { namespaced : true , state : initialState , getters , mutations , actions } ; export default dataflow ;