<commit_before>import { Icon } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import {
  CanvasWidget,
  SelectionBoxLayerFactory
} from "@projectstorm/react-canvas-core"
import {
  DefaultDiagramState,
  DiagramEngine,
  DiagramModel,
  LinkLayerFactory,
  NodeLayerFactory,
  PortModelAlignment
} from "@projectstorm/react-diagrams-core"
import { DefaultLabelFactory } from "@projectstorm/react-diagrams-defaults"
import {
  PathFindingLinkFactory,
  DagreEngine
} from "@projectstorm/react-diagrams-routing"
import { Settings } from "api"
import MultiTypeAdvancedSelectComponent from "components/advancedSelectWidget/MultiTypeAdvancedSelectComponent"
import { mapPageDispatchersToProps } from "components/Page"
import FileSaver from "file-saver"
import * as Models from "models"
import PropTypes from "prop-types"
import React, { useEffect, useRef, useState } from "react"
import { Badge, Button, Modal, Panel } from "react-bootstrap"
import { connect } from "react-redux"
import { useParams } from "react-router-dom"
import DOWNLOAD_ICON from "resources/download.png"
import "./BoardDashboard.css"
import LinkTo from "components/LinkTo"
import {
  DiagramLinkFactory,
  DiagramNodeFactory,
  DiagramNodeModel,
  DiagramPortModel,
  SimplePortFactory
} from "./DiagramNode"

const createEngine = options => {
  const engine = new DiagramEngine({})
  engine.getLayerFactories().registerFactory(new NodeLayerFactory())
  engine.getLayerFactories().registerFactory(new LinkLayerFactory())
  engine.getLayerFactories().registerFactory(new SelectionBoxLayerFactory())

  engine.getLabelFactories().registerFactory(new DefaultLabelFactory())
  engine.getNodeFactories().registerFactory(new DiagramNodeFactory())
  engine.getLinkFactories().registerFactory(new DiagramLinkFactory())
  engine.getLinkFactories().registerFactory(new PathFindingLinkFactory())
  engine
    .getPortFactories()
    .registerFactory(
      new SimplePortFactory(
        "anet",
        config => new DiagramPortModel(PortModelAlignment.LEFT)
      )
    )

  engine.getStateMachine().pushState(new DefaultDiagramState())
  return engine
}

const PrototypeNode = ({ name, model, onClick }) => (
  <Badge style={{ margin: 10, background: "white", color: "#106ba3" }}>
    <div
      draggable
      onClick={onClick}
      onDragStart={event => {
        event.dataTransfer.setData(
          "storm-diagram-node",
          JSON.stringify({ anetObjectType: model.constructor.resourceName })
        )
      }}
      style={{ textAlign: "left", cursor: "grab" }}
    >
      <img
        src={model.iconUrl()}
        alt=""
        style={{
          marginLeft: 5,
          marginRight: 5,
          height: "2em",
          pointerEvents: "none"
        }}
      />
      {name}
    </div>
  </Badge>
)

PrototypeNode.propTypes = {
  name: PropTypes.string,
  model: PropTypes.object,
  onClick: PropTypes.func
}

const BoardDashboard = () => {
  const { dashboard } = useParams()
  const dashboardSettings = Settings.dashboards.find(o => o.label === dashboard)
  const [dropEvent, setDropEvent] = useState(null)
  const engineRef = useRef(createEngine())
  const [model, setModel] = useState(null)
  const [edit, setEdit] = useState(false)
  const [selectingEntity, setSelectingEntity] = useState(false)
  const [editedNode, setEditedNode] = useState(null)
  const dagreEngineRef = useRef(
    new DagreEngine({
      graph: {
        rankdir: "RL",
        ranker: "longest-path",
        marginx: 25,
        marginy: 25
      },
      includeLinks: true
    })
  )

  useEffect(() => {
    setModel(new DiagramModel())
    return () => setModel(null)
  }, [])

  useEffect(() => {
    const previousModel = engineRef.current.getModel()
    if (previousModel) {
      previousModel.clearListeners()
      previousModel.getNodes().forEach(node => node.clearListeners())
    }
    engineRef.current.setModel(model)
    if (model) {
      const selectionListener = {
        selectionChanged: () =>
          setEditedNode(
            model.getSelectedEntities().length === 1
              ? model.getSelectedEntities()[0]
              : null
          )
      }
      model.registerListener({
        nodesUpdated: function(event) {
          if (event.isCreated) {
            event.node.registerListener(selectionListener)
          } else {
            if (
              editedNode?.options.anetObject.uuid ===
              event.node.anetObject?.uuid
            ) {
              setEditedNode(null)
            }
          }
        }
      })
      model.getNodes().forEach(node => node.registerListener(selectionListener))
    }
  }, [model])<commit_msg>NCI-Agency/anet#2889: Add missing dependency in BoardDashboard effect<commit_after>import { Icon } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import {
  CanvasWidget,
  SelectionBoxLayerFactory
} from "@projectstorm/react-canvas-core"
import {
  DefaultDiagramState,
  DiagramEngine,
  DiagramModel,
  LinkLayerFactory,
  NodeLayerFactory,
  PortModelAlignment
} from "@projectstorm/react-diagrams-core"
import { DefaultLabelFactory } from "@projectstorm/react-diagrams-defaults"
import {
  PathFindingLinkFactory,
  DagreEngine
} from "@projectstorm/react-diagrams-routing"
import { Settings } from "api"
import MultiTypeAdvancedSelectComponent from "components/advancedSelectWidget/MultiTypeAdvancedSelectComponent"
import { mapPageDispatchersToProps } from "components/Page"
import FileSaver from "file-saver"
import * as Models from "models"
import PropTypes from "prop-types"
import React, { useEffect, useRef, useState } from "react"
import { Badge, Button, Modal, Panel } from "react-bootstrap"
import { connect } from "react-redux"
import { useParams } from "react-router-dom"
import DOWNLOAD_ICON from "resources/download.png"
import "./BoardDashboard.css"
import LinkTo from "components/LinkTo"
import {
  DiagramLinkFactory,
  DiagramNodeFactory,
  DiagramNodeModel,
  DiagramPortModel,
  SimplePortFactory
} from "./DiagramNode"

const createEngine = options => {
  const engine = new DiagramEngine({})
  engine.getLayerFactories().registerFactory(new NodeLayerFactory())
  engine.getLayerFactories().registerFactory(new LinkLayerFactory())
  engine.getLayerFactories().registerFactory(new SelectionBoxLayerFactory())

  engine.getLabelFactories().registerFactory(new DefaultLabelFactory())
  engine.getNodeFactories().registerFactory(new DiagramNodeFactory())
  engine.getLinkFactories().registerFactory(new DiagramLinkFactory())
  engine.getLinkFactories().registerFactory(new PathFindingLinkFactory())
  engine
    .getPortFactories()
    .registerFactory(
      new SimplePortFactory(
        "anet",
        config => new DiagramPortModel(PortModelAlignment.LEFT)
      )
    )

  engine.getStateMachine().pushState(new DefaultDiagramState())
  return engine
}

const PrototypeNode = ({ name, model, onClick }) => (
  <Badge style={{ margin: 10, background: "white", color: "#106ba3" }}>
    <div
      draggable
      onClick={onClick}
      onDragStart={event => {
        event.dataTransfer.setData(
          "storm-diagram-node",
          JSON.stringify({ anetObjectType: model.constructor.resourceName })
        )
      }}
      style={{ textAlign: "left", cursor: "grab" }}
    >
      <img
        src={model.iconUrl()}
        alt=""
        style={{
          marginLeft: 5,
          marginRight: 5,
          height: "2em",
          pointerEvents: "none"
        }}
      />
      {name}
    </div>
  </Badge>
)

PrototypeNode.propTypes = {
  name: PropTypes.string,
  model: PropTypes.object,
  onClick: PropTypes.func
}

const BoardDashboard = () => {
  const { dashboard } = useParams()
  const dashboardSettings = Settings.dashboards.find(o => o.label === dashboard)
  const [dropEvent, setDropEvent] = useState(null)
  const engineRef = useRef(createEngine())
  const [model, setModel] = useState(null)
  const [edit, setEdit] = useState(false)
  const [selectingEntity, setSelectingEntity] = useState(false)
  const [editedNode, setEditedNode] = useState(null)
  const dagreEngineRef = useRef(
    new DagreEngine({
      graph: {
        rankdir: "RL",
        ranker: "longest-path",
        marginx: 25,
        marginy: 25
      },
      includeLinks: true
    })
  )

  useEffect(() => {
    setModel(new DiagramModel())
    return () => setModel(null)
  }, [])

  useEffect(() => {
    const previousModel = engineRef.current.getModel()
    if (previousModel) {
      previousModel.clearListeners()
      previousModel.getNodes().forEach(node => node.clearListeners())
    }
    engineRef.current.setModel(model)
    if (model) {
      const selectionListener = {
        selectionChanged: () =>
          setEditedNode(
            model.getSelectedEntities().length === 1
              ? model.getSelectedEntities()[0]
              : null
          )
      }
      model.registerListener({
        nodesUpdated: function(event) {
          if (event.isCreated) {
            event.node.registerListener(selectionListener)
          } else {
            if (
              editedNode?.options.anetObject.uuid ===
              event.node.anetObject?.uuid
            ) {
              setEditedNode(null)
            }
          }
        }
      })
      model.getNodes().forEach(node => node.registerListener(selectionListener))
    }
  }, [editedNode, model])
{'fraction_non_alphanumeric': 0.11705294492876887, 'fraction_numerical': 0.0036147140123325536, 'mean_word_length': 3.2070661896243293, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4730526', 'n_tokens_mistral': 2736, 'n_tokens_neox': 2723, 'n_words': 540}