@elyra/canvas 13.15.0 → 13.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/canvas-controller-98ea28eb.js +2 -0
  2. package/dist/canvas-controller-98ea28eb.js.map +1 -0
  3. package/dist/canvas-controller-c134dba5.js +2 -0
  4. package/dist/canvas-controller-c134dba5.js.map +1 -0
  5. package/dist/common-canvas-a12b2116.js +2 -0
  6. package/dist/common-canvas-a12b2116.js.map +1 -0
  7. package/dist/common-canvas-ee905f14.js +2 -0
  8. package/dist/common-canvas-ee905f14.js.map +1 -0
  9. package/dist/common-canvas.es.js +1 -1
  10. package/dist/common-canvas.js +1 -1
  11. package/dist/{common-properties-5a47972a.js → common-properties-629a8ee6.js} +2 -2
  12. package/dist/common-properties-629a8ee6.js.map +1 -0
  13. package/dist/{common-properties-5d7d30a3.js → common-properties-b829036e.js} +2 -2
  14. package/dist/common-properties-b829036e.js.map +1 -0
  15. package/dist/lib/canvas-controller.es.js +1 -1
  16. package/dist/lib/canvas-controller.js +1 -1
  17. package/dist/lib/canvas.es.js +1 -1
  18. package/dist/lib/canvas.js +1 -1
  19. package/dist/lib/properties.es.js +1 -1
  20. package/dist/lib/properties.js +1 -1
  21. package/package.json +2 -2
  22. package/src/common-canvas/cc-top-panel.jsx +3 -10
  23. package/src/common-properties/controls/abstract-table.jsx +2 -1
  24. package/src/object-model/config-utils.js +2 -1
  25. package/src/object-model/object-model.js +97 -41
  26. package/src/palette/palette-content-list-item.jsx +45 -13
  27. package/src/palette/palette-content-list.jsx +8 -0
  28. package/src/palette/palette-dialog-content-grid-node.jsx +17 -4
  29. package/src/palette/palette-dialog-content-grid.jsx +3 -0
  30. package/src/palette/palette-dialog-content.jsx +3 -0
  31. package/src/palette/palette-dialog-under.jsx +2 -0
  32. package/src/palette/palette-dialog.jsx +3 -0
  33. package/src/palette/palette-flyout-content-category.jsx +23 -9
  34. package/src/palette/palette-flyout-content-filtered-list.jsx +2 -0
  35. package/src/palette/palette-flyout-content.jsx +3 -0
  36. package/src/palette/palette-flyout.jsx +2 -0
  37. package/src/palette/palette.jsx +3 -0
  38. package/stats.html +1 -1
  39. package/dist/canvas-controller-3f4f6f8a.js +0 -2
  40. package/dist/canvas-controller-3f4f6f8a.js.map +0 -1
  41. package/dist/canvas-controller-f38976ec.js +0 -2
  42. package/dist/canvas-controller-f38976ec.js.map +0 -1
  43. package/dist/common-canvas-4796f111.js +0 -2
  44. package/dist/common-canvas-4796f111.js.map +0 -1
  45. package/dist/common-canvas-f34148dc.js +0 -2
  46. package/dist/common-canvas-f34148dc.js.map +0 -1
  47. package/dist/common-properties-5a47972a.js.map +0 -1
  48. package/dist/common-properties-5d7d30a3.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import"../createClass-a140e270.js";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../get-0aeefae2.js";export{C as default}from"../canvas-controller-3f4f6f8a.js";import"./command-stack.es.js";import"../canvas-constants-3e720cc5.js";import"../canvas-logger-037c0c68.js";import"../common-canvas-utils-cc218b20.js";import"../inherits-860188e5.js";import"../datarecord-metadata-v3-schema-bb227243.js";import"uuid";import"redux";import"jsonschema";import"@elyra/pipeline-schemas";import"immutable";
1
+ import"../createClass-a140e270.js";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../get-0aeefae2.js";export{C as default}from"../canvas-controller-c134dba5.js";import"./command-stack.es.js";import"../canvas-constants-3e720cc5.js";import"../canvas-logger-037c0c68.js";import"../common-canvas-utils-cc218b20.js";import"../inherits-860188e5.js";import"../datarecord-metadata-v3-schema-bb227243.js";import"uuid";import"redux";import"jsonschema";import"@elyra/pipeline-schemas";import"immutable";
2
2
  //# sourceMappingURL=canvas-controller.es.js.map
@@ -1,2 +1,2 @@
1
- "use strict";require("../createClass-df7b07d6.js"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../get-ce68a4b3.js");var e=require("../canvas-controller-f38976ec.js");require("./command-stack.js"),require("../canvas-constants-6bc0dd7f.js"),require("../canvas-logger-45fa2be6.js"),require("../common-canvas-utils-6a327226.js"),require("../inherits-74e481d1.js"),require("../datarecord-metadata-v3-schema-df671574.js"),require("uuid"),require("redux"),require("jsonschema"),require("@elyra/pipeline-schemas"),require("immutable"),module.exports=e.CanvasController;
1
+ "use strict";require("../createClass-df7b07d6.js"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../get-ce68a4b3.js");var e=require("../canvas-controller-98ea28eb.js");require("./command-stack.js"),require("../canvas-constants-6bc0dd7f.js"),require("../canvas-logger-45fa2be6.js"),require("../common-canvas-utils-6a327226.js"),require("../inherits-74e481d1.js"),require("../datarecord-metadata-v3-schema-df671574.js"),require("uuid"),require("redux"),require("jsonschema"),require("@elyra/pipeline-schemas"),require("immutable"),module.exports=e.CanvasController;
2
2
  //# sourceMappingURL=canvas-controller.js.map
@@ -1,2 +1,2 @@
1
- export{c as CommonCanvas}from"../common-canvas-4796f111.js";export{C as CanvasController}from"../canvas-controller-3f4f6f8a.js";import"../createClass-a140e270.js";import"../inherits-860188e5.js";import"react";import"react-redux";import"react-intl";import"../get-0aeefae2.js";import"../toolbar-aa394d30.js";import"../iconPropTypes-4cbeb95d-f4b5dc39.js";import"prop-types";import"../datarecord-metadata-v3-schema-bb227243.js";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../canvas-constants-3e720cc5.js";import"react-resize-detector";import"../keyboard-utils-18c50c59.js";import"../common-canvas-utils-cc218b20.js";import"./tooltip.es.js";import"react-portal";import"@carbon/react";import"uuid";import"react-inlinesvg";import"../bucket-9-7ad0e1b8.js";import"../icon-5f32b619.js";import"../bucket-3-64d04e07.js";import"../canvas-logger-037c0c68.js";import"../context-menu-wrapper-eb9cc697.js";import"react-dom";import"./command-stack.es.js";import"immutable";import"redux";import"jsonschema";import"@elyra/pipeline-schemas";
1
+ export{c as CommonCanvas}from"../common-canvas-ee905f14.js";export{C as CanvasController}from"../canvas-controller-c134dba5.js";import"../createClass-a140e270.js";import"../inherits-860188e5.js";import"react";import"react-redux";import"react-intl";import"../get-0aeefae2.js";import"../toolbar-aa394d30.js";import"../iconPropTypes-4cbeb95d-f4b5dc39.js";import"prop-types";import"../datarecord-metadata-v3-schema-bb227243.js";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../canvas-constants-3e720cc5.js";import"react-resize-detector";import"../keyboard-utils-18c50c59.js";import"../common-canvas-utils-cc218b20.js";import"./tooltip.es.js";import"react-portal";import"@carbon/react";import"uuid";import"react-inlinesvg";import"../bucket-9-7ad0e1b8.js";import"../icon-5f32b619.js";import"../bucket-3-64d04e07.js";import"../canvas-logger-037c0c68.js";import"../context-menu-wrapper-eb9cc697.js";import"react-dom";import"./command-stack.es.js";import"immutable";import"redux";import"jsonschema";import"@elyra/pipeline-schemas";
2
2
  //# sourceMappingURL=canvas.es.js.map
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../common-canvas-f34148dc.js"),r=require("../canvas-controller-f38976ec.js");require("../createClass-df7b07d6.js"),require("../inherits-74e481d1.js"),require("react"),require("react-redux"),require("react-intl"),require("../get-ce68a4b3.js"),require("../toolbar-f58a9942.js"),require("../iconPropTypes-4cbeb95d-7a1b2520.js"),require("prop-types"),require("../datarecord-metadata-v3-schema-df671574.js"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../canvas-constants-6bc0dd7f.js"),require("react-resize-detector"),require("../keyboard-utils-75346513.js"),require("../common-canvas-utils-6a327226.js"),require("./tooltip.js"),require("react-portal"),require("@carbon/react"),require("uuid"),require("react-inlinesvg"),require("../bucket-9-ec902462.js"),require("../icon-e7b672ac.js"),require("../bucket-3-425f53cc.js"),require("../canvas-logger-45fa2be6.js"),require("../context-menu-wrapper-a0fc1308.js"),require("react-dom"),require("./command-stack.js"),require("immutable"),require("redux"),require("jsonschema"),require("@elyra/pipeline-schemas"),exports.CommonCanvas=e.commonCanvas,exports.CanvasController=r.CanvasController;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../common-canvas-a12b2116.js"),r=require("../canvas-controller-98ea28eb.js");require("../createClass-df7b07d6.js"),require("../inherits-74e481d1.js"),require("react"),require("react-redux"),require("react-intl"),require("../get-ce68a4b3.js"),require("../toolbar-f58a9942.js"),require("../iconPropTypes-4cbeb95d-7a1b2520.js"),require("prop-types"),require("../datarecord-metadata-v3-schema-df671574.js"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../canvas-constants-6bc0dd7f.js"),require("react-resize-detector"),require("../keyboard-utils-75346513.js"),require("../common-canvas-utils-6a327226.js"),require("./tooltip.js"),require("react-portal"),require("@carbon/react"),require("uuid"),require("react-inlinesvg"),require("../bucket-9-ec902462.js"),require("../icon-e7b672ac.js"),require("../bucket-3-425f53cc.js"),require("../canvas-logger-45fa2be6.js"),require("../context-menu-wrapper-a0fc1308.js"),require("react-dom"),require("./command-stack.js"),require("immutable"),require("redux"),require("jsonschema"),require("@elyra/pipeline-schemas"),exports.CommonCanvas=e.commonCanvas,exports.CanvasController=r.CanvasController;
2
2
  //# sourceMappingURL=canvas.js.map
@@ -1,2 +1,2 @@
1
- export{c as CommonProperties,P as PropertiesController}from"../common-properties-5d7d30a3.js";export{F as FlexibleTable}from"../flexible-table-6fa3dba7.js";export{F as FieldPicker}from"../index-a62b6faf.js";export{clem}from"./properties/clem.es.js";export{getPythonHints}from"./properties/getPythonHints.es.js";import"../createClass-a140e270.js";import"../inherits-860188e5.js";import"react";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../get-0aeefae2.js";import"../canvas-constants-3e720cc5.js";import"../common-canvas-utils-cc218b20.js";import"../bucket-9-7ad0e1b8.js";import"../iconPropTypes-4cbeb95d-f4b5dc39.js";import"prop-types";import"../datarecord-metadata-v3-schema-bb227243.js";import"react-resize-detector";import"@carbon/react";import"react-portal";import"react-intl";import"react-redux";import"react-dom";import"../icon-5f32b619.js";import"react-inlinesvg";import"../bucket-3-64d04e07.js";import"uuid";import"./tooltip.es.js";import"redux";import"seedrandom";import"./command-stack.es.js";import"immutable";import"date-fns";import"../toolbar-aa394d30.js";import"../keyboard-utils-18c50c59.js";import"@codemirror/view";import"@codemirror/commands";import"codemirror";import"@codemirror/state";import"@codemirror/language";import"@codemirror/lang-python";import"@codemirror/lang-sql";import"@codemirror/lang-javascript";import"@codemirror/autocomplete";import"jsonschema";import"react-virtualized";import"react-draggable";
1
+ export{c as CommonProperties,P as PropertiesController}from"../common-properties-b829036e.js";export{F as FlexibleTable}from"../flexible-table-6fa3dba7.js";export{F as FieldPicker}from"../index-a62b6faf.js";export{clem}from"./properties/clem.es.js";export{getPythonHints}from"./properties/getPythonHints.es.js";import"../createClass-a140e270.js";import"../inherits-860188e5.js";import"react";import"../en-872b9ff3.js";import"../isArrayLikeObject-058fae1a.js";import"../get-0aeefae2.js";import"../canvas-constants-3e720cc5.js";import"../common-canvas-utils-cc218b20.js";import"../bucket-9-7ad0e1b8.js";import"../iconPropTypes-4cbeb95d-f4b5dc39.js";import"prop-types";import"../datarecord-metadata-v3-schema-bb227243.js";import"react-resize-detector";import"@carbon/react";import"react-portal";import"react-intl";import"react-redux";import"react-dom";import"../icon-5f32b619.js";import"react-inlinesvg";import"../bucket-3-64d04e07.js";import"uuid";import"./tooltip.es.js";import"redux";import"seedrandom";import"./command-stack.es.js";import"immutable";import"date-fns";import"../toolbar-aa394d30.js";import"../keyboard-utils-18c50c59.js";import"@codemirror/view";import"@codemirror/commands";import"codemirror";import"@codemirror/state";import"@codemirror/language";import"@codemirror/lang-python";import"@codemirror/lang-sql";import"@codemirror/lang-javascript";import"@codemirror/autocomplete";import"jsonschema";import"react-virtualized";import"react-draggable";
2
2
  //# sourceMappingURL=properties.es.js.map
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../common-properties-5a47972a.js"),r=require("../flexible-table-290fc108.js"),i=require("../index-632c879a.js"),o=require("./properties/clem.js"),t=require("./properties/getPythonHints.js");require("../createClass-df7b07d6.js"),require("../inherits-74e481d1.js"),require("react"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../get-ce68a4b3.js"),require("../canvas-constants-6bc0dd7f.js"),require("../common-canvas-utils-6a327226.js"),require("../bucket-9-ec902462.js"),require("../iconPropTypes-4cbeb95d-7a1b2520.js"),require("prop-types"),require("../datarecord-metadata-v3-schema-df671574.js"),require("react-resize-detector"),require("@carbon/react"),require("react-portal"),require("react-intl"),require("react-redux"),require("react-dom"),require("../icon-e7b672ac.js"),require("react-inlinesvg"),require("../bucket-3-425f53cc.js"),require("uuid"),require("./tooltip.js"),require("redux"),require("seedrandom"),require("./command-stack.js"),require("immutable"),require("date-fns"),require("../toolbar-f58a9942.js"),require("../keyboard-utils-75346513.js"),require("@codemirror/view"),require("@codemirror/commands"),require("codemirror"),require("@codemirror/state"),require("@codemirror/language"),require("@codemirror/lang-python"),require("@codemirror/lang-sql"),require("@codemirror/lang-javascript"),require("@codemirror/autocomplete"),require("jsonschema"),require("react-virtualized"),require("react-draggable"),exports.CommonProperties=e.commonProperties,exports.PropertiesController=e.PropertiesController,exports.FlexibleTable=r.FlexibleTable,exports.FieldPicker=i.FieldPicker,exports.clem=o.clem,exports.getPythonHints=t.getPythonHints;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../common-properties-629a8ee6.js"),r=require("../flexible-table-290fc108.js"),i=require("../index-632c879a.js"),o=require("./properties/clem.js"),t=require("./properties/getPythonHints.js");require("../createClass-df7b07d6.js"),require("../inherits-74e481d1.js"),require("react"),require("../en-72f12441.js"),require("../isArrayLikeObject-541cd370.js"),require("../get-ce68a4b3.js"),require("../canvas-constants-6bc0dd7f.js"),require("../common-canvas-utils-6a327226.js"),require("../bucket-9-ec902462.js"),require("../iconPropTypes-4cbeb95d-7a1b2520.js"),require("prop-types"),require("../datarecord-metadata-v3-schema-df671574.js"),require("react-resize-detector"),require("@carbon/react"),require("react-portal"),require("react-intl"),require("react-redux"),require("react-dom"),require("../icon-e7b672ac.js"),require("react-inlinesvg"),require("../bucket-3-425f53cc.js"),require("uuid"),require("./tooltip.js"),require("redux"),require("seedrandom"),require("./command-stack.js"),require("immutable"),require("date-fns"),require("../toolbar-f58a9942.js"),require("../keyboard-utils-75346513.js"),require("@codemirror/view"),require("@codemirror/commands"),require("codemirror"),require("@codemirror/state"),require("@codemirror/language"),require("@codemirror/lang-python"),require("@codemirror/lang-sql"),require("@codemirror/lang-javascript"),require("@codemirror/autocomplete"),require("jsonschema"),require("react-virtualized"),require("react-draggable"),exports.CommonProperties=e.commonProperties,exports.PropertiesController=e.PropertiesController,exports.FlexibleTable=r.FlexibleTable,exports.FieldPicker=i.FieldPicker,exports.clem=o.clem,exports.getPythonHints=t.getPythonHints;
2
2
  //# sourceMappingURL=properties.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elyra/canvas",
3
- "version": "13.15.0",
3
+ "version": "13.16.0",
4
4
  "description": "Elyra common-canvas",
5
5
  "main": "dist/common-canvas.js",
6
6
  "module": "dist/common-canvas.es.js",
@@ -47,7 +47,7 @@
47
47
  "react-portal": "^4.2.1",
48
48
  "react-redux": "^8.1.3",
49
49
  "react-resize-detector": "^9.1.0",
50
- "react-virtualized": "^9.22.2",
50
+ "react-virtualized": "9.22.5",
51
51
  "redux": "^5.0.1",
52
52
  "seedrandom": "^3.0.5",
53
53
  "uuid": "^8.3.0"
@@ -30,14 +30,9 @@ class CanvasTopPanel extends React.Component {
30
30
  this.logger.log("render");
31
31
  let topPanel = null;
32
32
 
33
- let className = "top-panel";
34
- if (this.props.toolbarIsOpen) {
35
- className += " common-canvas-toolbar-none";
36
- }
37
-
38
33
  if (this.props.topPanelIsOpen) {
39
34
  topPanel = (
40
- <div className={className} >
35
+ <div className={"top-panel"} >
41
36
  {this.props.topPanelContent}
42
37
  </div>
43
38
  );
@@ -54,13 +49,11 @@ CanvasTopPanel.propTypes = {
54
49
 
55
50
  // Provided by Redux
56
51
  topPanelIsOpen: PropTypes.bool,
57
- topPanelContent: PropTypes.object,
58
- toolbarIsOpen: PropTypes.bool
52
+ topPanelContent: PropTypes.object
59
53
  };
60
54
 
61
55
  const mapStateToProps = (state, ownProps) => ({
62
56
  topPanelIsOpen: state.toppanel.isOpen,
63
- topPanelContent: state.toppanel.content,
64
- toolbarIsOpen: (state.canvasconfig.enableToolbarLayout === "None")
57
+ topPanelContent: state.toppanel.content
65
58
  });
66
59
  export default connect(mapStateToProps)(CanvasTopPanel);
@@ -744,7 +744,8 @@ export default class AbstractTable extends React.Component {
744
744
  const cell = this.buildChildItem(propertyName, rowIndex, tableState);
745
745
  columns.push(cell);
746
746
  }
747
- if (this.props.control.rowSelection === ROW_SELECTION.SINGLE && !this.isReadonlyTable()) {
747
+ // Do not show delete icon if add_remove_rows is false (default is true)
748
+ if (this.props.control.rowSelection === ROW_SELECTION.SINGLE && !this.isReadonlyTable() && this.props.addRemoveRows) {
748
749
  const toolTip = PropertyUtils.formatMessage(this.reactIntl, MESSAGE_KEYS.TABLE_DELETEICON_TOOLTIP);
749
750
  const tooltipId = "tooltip-delete-row";
750
751
  const deleteOption = (
@@ -92,6 +92,7 @@ export default class ConfigUtils {
92
92
  enableWYSIWYGComments: false,
93
93
  enableKeyboardNavigation: false,
94
94
  enableAutoLinkOnlyFromSelNodes: false,
95
+ enableSingleClickAddFromPalette: false,
95
96
  enableContextToolbar: false,
96
97
  enableSaveZoom: "None",
97
98
  enableSnapToGridType: "None",
@@ -105,7 +106,7 @@ export default class ConfigUtils {
105
106
  enableFocusOnMount: true,
106
107
  enableBoundingRectangles: false, // Not documented
107
108
  enableCanvasUnderlay: "None", // Not documented
108
- enableParentClass: "", // Not documented
109
+ enableParentClass: "",
109
110
  enablePositionNodeOnRightFlyoutOpen: false, // May also be an object: { x: 5, y: 5 }
110
111
  emptyCanvasContent: null,
111
112
  dropZoneCanvasContent: null,
@@ -1498,8 +1498,8 @@ export default class ObjectModel {
1498
1498
  } else {
1499
1499
  this.toggleSelection(objId, augment, pipelineId);
1500
1500
  }
1501
- } else if (augment) {
1502
- this.toggleSelection(objId, augment, pipelineId);
1501
+ } else if (augment || range) {
1502
+ this.toggleSelection(objId, augment || range, pipelineId);
1503
1503
  }
1504
1504
  }
1505
1505
 
@@ -1562,60 +1562,116 @@ export default class ObjectModel {
1562
1562
  this.setSelections([], apiPipeline.pipelineId);
1563
1563
  }
1564
1564
 
1565
- findNodesInSubGraph(startNodeId, endNodeId, selection, pipelineId) {
1566
- const pipeline = this.getAPIPipeline(pipelineId);
1567
- let retval = false;
1565
+ // Selects a set of nodes which represet all connected nodes from the
1566
+ // current set of selected nodes to the end node passed in. If no
1567
+ // connecting nodes are found, the set of selected nodes remains the same.
1568
+ selectSubGraph(endNodeId, pipelineId) {
1569
+ const selectedObjectIds = this.getSubGraphNodes(endNodeId, pipelineId);
1570
+ this.setSelections(selectedObjectIds, pipelineId);
1571
+ }
1568
1572
 
1569
- selection.push(startNodeId);
1570
- if (startNodeId === endNodeId) {
1571
- retval = true;
1572
- } else {
1573
- for (const link of pipeline.getLinks()) {
1574
- if (link.srcNodeId === startNodeId &&
1575
- link.srcNodeId !== link.trgNodeId) { // Ignore self-referencing links
1576
- const newRetval = this.findNodesInSubGraph(link.trgNodeId, endNodeId, selection, pipelineId);
1577
- if (newRetval !== true) {
1578
- selection.pop();
1573
+ // Returns an array of node IDs that represent all connected nodes from the
1574
+ // current set of selected nodes to the end node passed in.
1575
+ getSubGraphNodes(endNodeId, pipelineId) {
1576
+ const selectedObjectIds = this.getSelectedObjectIds();
1577
+
1578
+ if (pipelineId === this.getSelectedPipelineId()) {
1579
+ const pipeline = this.getAPIPipeline(pipelineId);
1580
+ const links = pipeline.getLinks();
1581
+ const allPaths = [];
1582
+
1583
+ // Loop through all the currently selected nodes which will be
1584
+ // our start nodes.
1585
+ for (const startNodeId of selectedObjectIds) {
1586
+ const paths = this.getGraphPaths(startNodeId, endNodeId, links);
1587
+ allPaths.push(...paths);
1588
+ }
1589
+
1590
+ // Add to the set of currently selected object IDs any nodes
1591
+ // found that connect from them to the end node.
1592
+ for (const path of allPaths) {
1593
+ for (const nodeId of path) {
1594
+ if (!selectedObjectIds.includes(nodeId)) {
1595
+ selectedObjectIds.push(nodeId);
1579
1596
  }
1580
- // This handles the case where there are multiple outward paths.
1581
- // Some of the outward paths could be true and some false. This
1582
- // will make sure that the node in the selection list of one of the
1583
- // paths contains the end nodeId.
1584
- retval = retval || newRetval;
1585
1597
  }
1586
1598
  }
1587
1599
  }
1588
1600
 
1589
- return retval;
1601
+ // Make sure the end node is included in the list of selected nodes.
1602
+ if (!selectedObjectIds.includes(endNodeId)) {
1603
+ selectedObjectIds.push(endNodeId);
1604
+ }
1605
+
1606
+ return selectedObjectIds;
1590
1607
  }
1591
1608
 
1592
- selectSubGraph(endNodeId, pipelineId) {
1593
- const selection = [];
1594
- let selectedObjectIds = [endNodeId];
1609
+ // Returns an array of paths where each path is an array of nodes from
1610
+ // the start node to the end node.
1611
+ getGraphPaths(startNodeId, endNodeId, links) {
1612
+ const visited = new Set();
1613
+ const path = [];
1614
+ const paths = [];
1595
1615
 
1596
- if (pipelineId === this.getSelectedPipelineId()) {
1597
- const currentSelectedObjects = this.getSelectedObjectIds();
1616
+ this.getGraphPathForNode(startNodeId, endNodeId, path, visited, paths, links);
1598
1617
 
1599
- // Get all the nodes in the path from a currently selected object to the end node
1600
- let foundPath = false;
1601
- for (const startNodeId of currentSelectedObjects) {
1602
- foundPath = foundPath || this.findNodesInSubGraph(startNodeId, endNodeId, selection, pipelineId);
1603
- }
1604
- if (!foundPath) {
1605
- // If no subgraph found which is also the case if current selection was empty, just select endNode
1606
- selection.push(endNodeId);
1618
+ return paths;
1619
+ }
1620
+
1621
+ // Updates the paths array with any new path found where a path is an array
1622
+ // of node IDs that connect the node passed in to the end node. To do this it uses
1623
+ // the path and visited arrays as working arrays.
1624
+ getGraphPathForNode(nodeId, endNodeId, path, visited, paths, links) {
1625
+ if (nodeId === endNodeId) {
1626
+ paths.push([...path, endNodeId]);
1627
+ return;
1628
+ }
1629
+
1630
+ if (visited.has(nodeId)) {
1631
+ // If we've visited this node before, and the node ID is in one of the
1632
+ // currently saved paths, we make the path to this node an additional
1633
+ // path even though it doesn't end at the end node. All nodes in paths
1634
+ // will get consolidated by our caller so that is not a problem.
1635
+ if (this.isInSavedPath(nodeId, paths)) {
1636
+ paths.push([...path, endNodeId]);
1607
1637
  }
1638
+ return;
1639
+ }
1608
1640
 
1609
- // Do not put multiple copies of a nodeId in selected nodeId list.
1610
- selectedObjectIds = this.getSelectedObjectIds().slice();
1611
- for (const selected of selection) {
1612
- if (!this.isSelected(selected, pipelineId)) {
1613
- selectedObjectIds.push(selected);
1614
- }
1641
+ visited.add(nodeId);
1642
+ path.push(nodeId);
1643
+
1644
+ const neighbors = this.getNeighbourNodeIDs(nodeId, links);
1645
+
1646
+ for (const neighbor of neighbors) {
1647
+ this.getGraphPathForNode(neighbor, endNodeId, path, visited, paths, links);
1648
+ }
1649
+
1650
+ path.pop();
1651
+ }
1652
+
1653
+ // Returns true if the node ID passed in is in one of the
1654
+ // paths stored in the paths array.
1655
+ isInSavedPath(nodeId, paths) {
1656
+ for (const path of paths) {
1657
+ if (path.includes(nodeId)) {
1658
+ return true;
1615
1659
  }
1616
1660
  }
1661
+ return false;
1662
+ }
1617
1663
 
1618
- this.setSelections(selectedObjectIds, pipelineId);
1664
+ // Returns an array of neighbor nodes for the node identified
1665
+ // by the ID passed in.
1666
+ getNeighbourNodeIDs(nodeId, links) {
1667
+ const neighbors = [];
1668
+
1669
+ links.forEach((l) => {
1670
+ if (l.srcNodeId === nodeId && l.trgNodeId && l.type !== ASSOCIATION_LINK) {
1671
+ neighbors.push(l.trgNodeId);
1672
+ }
1673
+ });
1674
+ return neighbors;
1619
1675
  }
1620
1676
 
1621
1677
  // Return true is nodeIds are contiguous.
@@ -43,6 +43,7 @@ class PaletteContentListItem extends React.Component {
43
43
 
44
44
  this.onDragStart = this.onDragStart.bind(this);
45
45
  this.onDragEnd = this.onDragEnd.bind(this);
46
+ this.onClick = this.onClick.bind(this);
46
47
  this.onDoubleClick = this.onDoubleClick.bind(this);
47
48
  this.onMouseOver = this.onMouseOver.bind(this);
48
49
  this.onMouseLeave = this.onMouseLeave.bind(this);
@@ -54,12 +55,20 @@ class PaletteContentListItem extends React.Component {
54
55
  // Make sure the tip doesn't appear when starting to drag a node.
55
56
  this.props.canvasController.closeTip();
56
57
 
58
+ // Sets the focus index on the parent palette-content-list so
59
+ // future key presses that move focus will work correctly.
60
+ if (this.props.setFocusIndex) {
61
+ this.props.setFocusIndex();
62
+ }
63
+
57
64
  // Prepare the ghost image on mouse down because asynchronous loading of
58
65
  // SVG files will be too slow if this is done in onDragStart.
59
66
  this.ghostData = this.props.canvasController.getGhostNode(this.props.nodeTypeInfo.nodeType);
60
67
  }
61
68
 
62
69
  onDragStart(ev) {
70
+ this.props.canvasController.closeTip();
71
+
63
72
  // We cannot use the dataTransfer object for the nodeTemplate because
64
73
  // the dataTransfer data is not available during dragOver events so we set
65
74
  // the nodeTemplate into the canvas controller.
@@ -98,19 +107,15 @@ class PaletteContentListItem extends React.Component {
98
107
  this.createAutoNode(true);
99
108
  }
100
109
 
101
- onMouseOver(ev) {
102
- if (!this.props.isDisplaySearchResult && ev.buttons === 0) {
103
- const nodeTemplate = this.props.nodeTypeInfo.category.empty_text
104
- ? { app_data: { ui_data: { label: this.props.nodeTypeInfo.category.empty_text } } }
105
- : this.props.nodeTypeInfo.nodeType;
106
-
107
- this.props.canvasController.openTip({
108
- id: "paletteTip_" + this.props.nodeTypeInfo.nodeType.op,
109
- type: TIP_TYPE_PALETTE_ITEM,
110
- targetObj: ev.currentTarget,
111
- nodeTemplate: nodeTemplate,
112
- category: this.props.nodeTypeInfo.category
113
- });
110
+ onClick() {
111
+ if (this.props.allowClickToAdd) {
112
+ this.createAutoNode(true);
113
+ }
114
+ }
115
+
116
+ onMouseOver(evt) {
117
+ if (!this.props.isDisplaySearchResult && evt.buttons === 0) {
118
+ this.displayTip();
114
119
  }
115
120
  }
116
121
 
@@ -262,8 +267,30 @@ class PaletteContentListItem extends React.Component {
262
267
  this.setState({ showFullDescription: false });
263
268
  }
264
269
 
270
+ // Sets the focus on this palette (node) item and displays
271
+ // a tooltip. This is called by the parent palette-content-list
272
+ // when the user moves focus to a new node using the keyboard, so
273
+ // we always show a tip for the keyboard user.
265
274
  focus() {
266
275
  this.itemRef.current.focus();
276
+ this.displayTip();
277
+ }
278
+
279
+ // Display a tip for this palette (node) item.
280
+ displayTip() {
281
+ this.props.canvasController.closeTip();
282
+
283
+ const nodeTemplate = this.props.nodeTypeInfo.category.empty_text
284
+ ? { app_data: { ui_data: { label: this.props.nodeTypeInfo.category.empty_text } } }
285
+ : this.props.nodeTypeInfo.nodeType;
286
+
287
+ this.props.canvasController.openTip({
288
+ id: "paletteTip_" + this.props.nodeTypeInfo.nodeType.op,
289
+ type: TIP_TYPE_PALETTE_ITEM,
290
+ targetObj: this.itemRef.current,
291
+ nodeTemplate: nodeTemplate,
292
+ category: this.props.nodeTypeInfo.category
293
+ });
267
294
  }
268
295
 
269
296
  // Returns true if this item is disabled and should not be draggable or double-clicked
@@ -289,6 +316,7 @@ class PaletteContentListItem extends React.Component {
289
316
  let labelText = get(this.props, "nodeTypeInfo.nodeType.app_data.ui_data.label", "");
290
317
  let draggable = this.isItemDisabled() ? "false" : "true";
291
318
  let icon = null;
319
+ const ariaDisabled = this.isItemDisabled();
292
320
 
293
321
  if (has(this.props.nodeTypeInfo.nodeType, "app_data.ui_data.image")) {
294
322
  let image = this.props.nodeTypeInfo.nodeType.app_data.ui_data.palette_image
@@ -355,6 +383,7 @@ class PaletteContentListItem extends React.Component {
355
383
  tabIndex={this.props.tabIndex}
356
384
  role={"button"}
357
385
  aria-label={labelText}
386
+ aria-disabled={ariaDisabled}
358
387
  draggable={draggable}
359
388
  className={mainDivClass}
360
389
  onMouseOver={this.onMouseOver}
@@ -363,6 +392,7 @@ class PaletteContentListItem extends React.Component {
363
392
  onMouseDown={this.props.isEditingEnabled ? this.onMouseDown : null}
364
393
  onDragStart={this.props.isEditingEnabled ? this.onDragStart : null}
365
394
  onDragEnd={this.props.isEditingEnabled ? this.onDragEnd : null}
395
+ onClick={this.props.isEditingEnabled ? this.onClick : null}
366
396
  onDoubleClick={this.props.isEditingEnabled ? this.onDoubleClick : null}
367
397
  >
368
398
  {categoryLabel}
@@ -384,6 +414,8 @@ PaletteContentListItem.propTypes = {
384
414
  tabIndex: PropTypes.number.isRequired,
385
415
  nextNodeInCategory: PropTypes.func,
386
416
  previousNodeInCategory: PropTypes.func,
417
+ setFocusIndex: PropTypes.func,
418
+ allowClickToAdd: PropTypes.bool,
387
419
  isEditingEnabled: PropTypes.bool.isRequired,
388
420
  isPaletteWide: PropTypes.bool,
389
421
  isShowRanking: PropTypes.bool
@@ -37,6 +37,10 @@ class PaletteContentList extends React.Component {
37
37
  this.contentItemRefs[this.currentFocusIndex].current.focus();
38
38
  }
39
39
 
40
+ setFocusIndex(idx) {
41
+ this.currentFocusIndex = idx;
42
+ }
43
+
40
44
  nextNodeInCategory(evt) {
41
45
  this.currentFocusIndex++;
42
46
  if (this.currentFocusIndex > this.contentItemRefs.length - 1) {
@@ -68,6 +72,7 @@ class PaletteContentList extends React.Component {
68
72
  nodeTypeInfo={{ nodeType: {}, category: this.props.category }}
69
73
  isDisplaySearchResult={false}
70
74
  canvasController={this.props.canvasController}
75
+ allowClickToAdd={this.props.allowClickToAdd}
71
76
  isPaletteWide={this.props.isPaletteWide}
72
77
  isEditingEnabled={this.props.isEditingEnabled}
73
78
  />
@@ -92,6 +97,8 @@ class PaletteContentList extends React.Component {
92
97
  isEditingEnabled={this.props.isEditingEnabled}
93
98
  nextNodeInCategory={this.nextNodeInCategory}
94
99
  previousNodeInCategory={this.previousNodeInCategory}
100
+ setFocusIndex={this.setFocusIndex.bind(this, idx)}
101
+ allowClickToAdd={this.props.allowClickToAdd}
95
102
  />
96
103
  );
97
104
  }
@@ -111,6 +118,7 @@ PaletteContentList.propTypes = {
111
118
  canvasController: PropTypes.object.isRequired,
112
119
  isPaletteWide: PropTypes.bool,
113
120
  isEditingEnabled: PropTypes.bool.isRequired,
121
+ allowClickToAdd: PropTypes.bool
114
122
  };
115
123
 
116
124
  export default PaletteContentList;
@@ -37,6 +37,7 @@ class PaletteDialogContentGridNode extends React.Component {
37
37
 
38
38
  this.onDragStart = this.onDragStart.bind(this);
39
39
  this.onDragEnd = this.onDragEnd.bind(this);
40
+ this.onClick = this.onClick.bind(this);
40
41
  this.onDoubleClick = this.onDoubleClick.bind(this);
41
42
  this.onMouseOver = this.onMouseOver.bind(this);
42
43
  this.onMouseLeave = this.onMouseLeave.bind(this);
@@ -72,13 +73,16 @@ class PaletteDialogContentGridNode extends React.Component {
72
73
  this.props.canvasController.nodeTemplateDragEnd();
73
74
  }
74
75
 
75
- onDoubleClick() {
76
- if (this.props.canvasController.createAutoNode) {
77
- const nodeTemplate = this.props.canvasController.convertNodeTemplate(this.props.nodeTemplate);
78
- this.props.canvasController.createAutoNode(nodeTemplate);
76
+ onClick() {
77
+ if (this.props.allowClickToAdd) {
78
+ this.createAutoNode();
79
79
  }
80
80
  }
81
81
 
82
+ onDoubleClick() {
83
+ this.createAutoNode();
84
+ }
85
+
82
86
  onMouseOver(ev) {
83
87
  if (ev.buttons === 0) {
84
88
  const nodeTemplate = this.props.category.empty_text
@@ -99,6 +103,13 @@ class PaletteDialogContentGridNode extends React.Component {
99
103
  this.props.canvasController.closeTip();
100
104
  }
101
105
 
106
+ createAutoNode() {
107
+ if (this.props.canvasController.createAutoNode) {
108
+ const nodeTemplate = this.props.canvasController.convertNodeTemplate(this.props.nodeTemplate);
109
+ this.props.canvasController.createAutoNode(nodeTemplate);
110
+ }
111
+ }
112
+
102
113
  render() {
103
114
  let label = "";
104
115
  if (has(this.props.nodeTemplate, "app_data.ui_data.label")) {
@@ -147,6 +158,7 @@ class PaletteDialogContentGridNode extends React.Component {
147
158
  onMouseDown={this.props.isEditingEnabled ? this.onMouseDown : null}
148
159
  onDragStart={this.props.isEditingEnabled ? this.onDragStart : null}
149
160
  onDragEnd={this.props.isEditingEnabled ? this.onDragEnd : null}
161
+ onClick={this.props.isEditingEnabled ? this.onClick : null}
150
162
  onDoubleClick={this.props.isEditingEnabled ? this.onDoubleClick : null}
151
163
  className="palette-dialog-grid-node-outer"
152
164
  >
@@ -167,6 +179,7 @@ PaletteDialogContentGridNode.propTypes = {
167
179
  category: PropTypes.object.isRequired,
168
180
  nodeTemplate: PropTypes.object.isRequired,
169
181
  canvasController: PropTypes.object.isRequired,
182
+ allowClickToAdd: PropTypes.bool,
170
183
  isEditingEnabled: PropTypes.bool.isRequired
171
184
  };
172
185
 
@@ -38,6 +38,7 @@ class PaletteDialogContentGrid extends React.Component {
38
38
  nodeTemplate={ {} }
39
39
  canvasController={this.props.canvasController}
40
40
  isEditingEnabled={this.props.isEditingEnabled}
41
+ allowClickToAdd={this.props.allowClickToAdd}
41
42
  />
42
43
  );
43
44
  } else {
@@ -48,6 +49,7 @@ class PaletteDialogContentGrid extends React.Component {
48
49
  nodeTemplate={this.props.nodeTypes[idx]}
49
50
  canvasController={this.props.canvasController}
50
51
  isEditingEnabled={this.props.isEditingEnabled}
52
+ allowClickToAdd={this.props.allowClickToAdd}
51
53
  />
52
54
  );
53
55
  }
@@ -65,6 +67,7 @@ PaletteDialogContentGrid.propTypes = {
65
67
  category: PropTypes.object.isRequired,
66
68
  nodeTypes: PropTypes.array.isRequired,
67
69
  isEditingEnabled: PropTypes.bool.isRequired,
70
+ allowClickToAdd: PropTypes.bool,
68
71
  canvasController: PropTypes.object.isRequired
69
72
  };
70
73
 
@@ -87,6 +87,7 @@ class PaletteDialogContent extends React.Component {
87
87
  nodeTypes={nodeTypes}
88
88
  canvasController={this.props.canvasController}
89
89
  isEditingEnabled={this.props.isEditingEnabled}
90
+ allowClickToAdd={this.props.allowClickToAdd}
90
91
  />)
91
92
  : (
92
93
  <PaletteContentList
@@ -95,6 +96,7 @@ class PaletteDialogContent extends React.Component {
95
96
  canvasController={this.props.canvasController}
96
97
  isPaletteWide
97
98
  isEditingEnabled={this.props.isEditingEnabled}
99
+ allowClickToAdd={this.props.allowClickToAdd}
98
100
  />);
99
101
  return (
100
102
  <div className="palette-dialog-content" ref="palettecontent">
@@ -112,6 +114,7 @@ PaletteDialogContent.propTypes = {
112
114
  paletteJSON: PropTypes.object.isRequired,
113
115
  showGrid: PropTypes.bool.isRequired,
114
116
  canvasController: PropTypes.object.isRequired,
117
+ allowClickToAdd: PropTypes.bool,
115
118
  isEditingEnabled: PropTypes.bool.isRequired
116
119
  };
117
120
 
@@ -542,6 +542,7 @@ class PaletteDialog extends React.Component {
542
542
  showGrid={this.state.showGrid}
543
543
  canvasController={this.props.canvasController}
544
544
  isEditingEnabled={this.props.isEditingEnabled}
545
+ allowClickToAdd={this.props.allowClickToAdd}
545
546
  />
546
547
  </div>
547
548
  </nav>
@@ -557,6 +558,7 @@ PaletteDialog.propTypes = {
557
558
  canvasController: PropTypes.object.isRequired,
558
559
  containingDivId: PropTypes.string.isRequired,
559
560
  paletteJSON: PropTypes.object,
561
+ allowClickToAdd: PropTypes.bool,
560
562
  isEditingEnabled: PropTypes.bool
561
563
  };
562
564
 
@@ -36,6 +36,7 @@ class PaletteDialog extends React.Component {
36
36
  canvasController={this.props.canvasController}
37
37
  paletteJSON={this.props.paletteJSON}
38
38
  containingDivId={this.props.containingDivId}
39
+ allowClickToAdd={this.props.allowClickToAdd}
39
40
  isEditingEnabled={this.props.isEditingEnabled}
40
41
  />);
41
42
  }
@@ -51,11 +52,13 @@ PaletteDialog.propTypes = {
51
52
 
52
53
  // Provided by redux
53
54
  paletteJSON: PropTypes.object,
55
+ allowClickToAdd: PropTypes.bool,
54
56
  isEditingEnabled: PropTypes.bool
55
57
  };
56
58
 
57
59
  const mapStateToProps = (state, ownProps) => ({
58
60
  paletteJSON: state.palette.content,
61
+ allowClickToAdd: state.canvasconfig.enableSingleClickAddFromPalette,
59
62
  isEditingEnabled: state.canvasconfig.enableEditingActions
60
63
  });
61
64