diff --git a/package-lock.json b/package-lock.json index a162def2fc..b949bb345c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "network-canvas", - "version": "4.0.0-alpha.4", + "version": "4.0.0-alpha.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3195,7 +3195,7 @@ }, "ansi": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "resolved": "http://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=" }, "balanced-match": { @@ -3215,7 +3215,7 @@ }, "bplist-parser": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", "integrity": "sha1-1g1dzCDLptx+HymbNdPh+V2vuuY=", "requires": { "big-integer": "1.6.26" @@ -3232,7 +3232,7 @@ }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": "http://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "cordova-common": { @@ -3257,12 +3257,12 @@ }, "cordova-registry-mapper": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz", + "resolved": "http://registry.npmjs.org/cordova-registry-mapper/-/cordova-registry-mapper-1.1.15.tgz", "integrity": "sha1-4kS5GFuBdUc7/2B5MkkFEV+D3Hw=" }, "elementtree": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/elementtree/-/elementtree-0.1.6.tgz", "integrity": "sha1-KsTEbqMFFsjEy9teOsdBjlkt4gw=", "requires": { "sax": "0.3.5" @@ -3270,7 +3270,7 @@ }, "glob": { "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "resolved": "http://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "requires": { "inflight": "1.0.6", @@ -3282,7 +3282,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": "http://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "1.4.0", @@ -3291,12 +3291,12 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": "http://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "lodash": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" }, "minimatch": { @@ -3309,7 +3309,7 @@ }, "nopt": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "resolved": "http://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { "abbrev": "1.1.1" @@ -3317,7 +3317,7 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1.0.2" @@ -3325,12 +3325,12 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -3344,12 +3344,12 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "plist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/plist/-/plist-1.2.0.tgz", "integrity": "sha1-CEtQk93JJQbiWfh0uNmxr7jHlZM=", "requires": { "base64-js": "0.0.8", @@ -3360,7 +3360,7 @@ }, "properties-parser": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.2.3.tgz", + "resolved": "http://registry.npmjs.org/properties-parser/-/properties-parser-0.2.3.tgz", "integrity": "sha1-91kSVfcHq7/yJ8e1a2N9uwNzoQ8=" }, "q": { @@ -3380,17 +3380,17 @@ }, "shelljs": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", + "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", "integrity": "sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=" }, "underscore": { "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, "unorm": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", + "resolved": "http://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" }, "util-deprecate": { @@ -3400,7 +3400,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "xmlbuilder": { @@ -3413,7 +3413,7 @@ }, "xmldom": { "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "resolved": "http://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" } } @@ -12841,8 +12841,7 @@ "object-hash": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", - "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==", - "dev": true + "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==" }, "object-inspect": { "version": "1.5.0", diff --git a/package.json b/package.json index cfbe65a9d2..2cbfb06fc9 100644 --- a/package.json +++ b/package.json @@ -159,6 +159,7 @@ "cordova-plugin-wkwebview-engine": "^1.1.4", "cordova-plugin-x-socialsharing": "^5.2.1", "cordova-plugin-zeroconf": "^1.3.3", + "object-hash": "^1.3.0", "react-id-swiper": "^1.6.4" }, "homepage": ".", diff --git a/public/protocols/development.netcanvas/protocol.json b/public/protocols/development.netcanvas/protocol.json index ba89023333..755c29ca00 100644 --- a/public/protocols/development.netcanvas/protocol.json +++ b/public/protocols/development.netcanvas/protocol.json @@ -482,35 +482,35 @@ "previousInterview": { "nodes": [ { - "uid": "previous_1", + "uid": "person_1", "type": "person", "name": "Anita", "nickname": "Annie", "age": "23" }, { - "uid": "previous_2", + "uid": "person_2", "type": "person", "name": "Barry", "nickname": "Baz", "age": "23" }, { - "uid": "previous_3", + "uid": "person_3", "type": "person", "name": "Carlito", "nickname": "Carl", "age": "23" }, { - "uid": "previous_4", + "uid": "person_4", "type": "person", "name": "Dee", "nickname": "Dee", "age": "23" }, { - "uid": "previous_5", + "uid": "person_5", "type": "person", "name": "Eugine", "nickname": "Eu", diff --git a/src/components/CardList.js b/src/components/CardList.js index e08204cb6b..eeb2beecaa 100644 --- a/src/components/CardList.js +++ b/src/components/CardList.js @@ -6,6 +6,7 @@ import cx from 'classnames'; import { scrollable, selectable } from '../behaviours'; import { Card } from '.'; import { Icon } from '../ui/components'; +import { NodePK } from '../ducks/modules/network'; const EnhancedCard = selectable(Card); @@ -23,7 +24,7 @@ const CardList = (props) => { onDeleteCard, onToggleCard, selected, - uid, + getKey, } = props; const classNames = cx('card-list', className); @@ -32,7 +33,7 @@ const CardList = (props) => {
{ nodes.map(node => ( - + {}, selected: () => false, - uid: node => node.uid, + getKey: node => node[NodePK], }; export default compose( diff --git a/src/components/ListSelect.js b/src/components/ListSelect.js index 200b5dbf98..48de483b36 100644 --- a/src/components/ListSelect.js +++ b/src/components/ListSelect.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { Button } from '../ui/components'; import { CardList } from '.'; +import { NodePK } from '../ducks/modules/network'; class ListSelect extends Component { constructor(props) { @@ -82,7 +83,7 @@ class ListSelect extends Component { /** * @param {object} node */ - selected = node => !!this.props.selectedNodes.find(current => current.uid === node.uid); + selected = node => !!this.props.selectedNodes.find(current => current[NodePK] === node[NodePK]); /** * @param property to sort by @@ -129,11 +130,12 @@ class ListSelect extends Component { * @param {object} node */ toggleCard = (node) => { - const index = this.props.selectedNodes.findIndex(current => current.uid === node.uid); + const matchingPK = n => n[NodePK] === node[NodePK]; + const index = this.props.selectedNodes.findIndex(matchingPK); if (index !== -1) { - this.props.onRemoveNode(this.props.nodes.find(current => current.uid === node.uid)); + this.props.onRemoveNode(this.props.nodes.find(matchingPK)); } else { - this.props.onSubmitNode(this.props.nodes.find(current => current.uid === node.uid)); + this.props.onSubmitNode(this.props.nodes.find(matchingPK)); } }; diff --git a/src/components/NodeBin.js b/src/components/NodeBin.js index 23d5a80b32..ff0fc46b54 100644 --- a/src/components/NodeBin.js +++ b/src/components/NodeBin.js @@ -5,6 +5,7 @@ import { compose, withProps } from 'recompose'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { actionCreators as sessionsActions } from '../ducks/modules/sessions'; +import { NodePK } from '../ducks/modules/network'; import { DropTarget, MonitorDropTarget } from '../behaviours/DragAndDrop'; /** @@ -43,7 +44,7 @@ export default compose( connect(null, mapDispatchToProps), withProps(props => ({ accepts: ({ meta }) => meta.itemType === 'EXISTING_NODE', - onDrop: ({ meta }) => props.removeNode(meta.uid), + onDrop: ({ meta }) => props.removeNode(meta[NodePK]), })), DropTarget, MonitorDropTarget(['isOver', 'willAccept']), diff --git a/src/components/NodeList.js b/src/components/NodeList.js index 2695abbf85..6b4b86870d 100644 --- a/src/components/NodeList.js +++ b/src/components/NodeList.js @@ -15,6 +15,7 @@ import { MonitorDragSource, } from '../behaviours/DragAndDrop'; import sortOrder from '../utils/sortOrder'; +import { NodePK } from '../ducks/modules/network'; const EnhancedNode = DragSource(selectable(Node)); @@ -98,7 +99,7 @@ class NodeList extends Component { exit, } = this.state; - const isSource = !!find(nodes, ['uid', get(meta, 'uid', null)]); + const isSource = !!find(nodes, [NodePK, get(meta, NodePK, null)]); const isValidTarget = !isSource && willAccept; const isHovering = isValidTarget && isOver; @@ -118,7 +119,7 @@ class NodeList extends Component { { nodes.map((node, index) => ( diff --git a/src/components/OrdinalBinBucket.js b/src/components/OrdinalBinBucket.js index 5a00a752fc..58631c2799 100644 --- a/src/components/OrdinalBinBucket.js +++ b/src/components/OrdinalBinBucket.js @@ -15,6 +15,7 @@ import { MonitorDragSource, } from '../behaviours/DragAndDrop'; import sortOrder from '../utils/sortOrder'; +import { NodePK } from '../ducks/modules/network'; const EnhancedNode = DragSource(selectable(Node)); @@ -92,7 +93,7 @@ class OrdinalBinBucket extends Component { exit, } = this.state; - const isSource = !!find(nodes, ['uid', get(meta, 'uid', null)]); + const isSource = !!find(nodes, [NodePK, get(meta, NodePK, null)]); const isValidTarget = !isSource && willAccept; const isHovering = isValidTarget && isOver; @@ -115,7 +116,7 @@ class OrdinalBinBucket extends Component { nodes.map((node, index) => ( index < 3 && ( diff --git a/src/components/__tests__/__snapshots__/CardList-test.js.snap b/src/components/__tests__/__snapshots__/CardList-test.js.snap index ed46f3d71c..f4cd71bcb9 100644 --- a/src/components/__tests__/__snapshots__/CardList-test.js.snap +++ b/src/components/__tests__/__snapshots__/CardList-test.js.snap @@ -45,6 +45,7 @@ ShallowWrapper { className="" compact={false} details={[Function]} + getKey={[Function]} label={[Function]} multiselect={true} nodes={ @@ -70,7 +71,6 @@ ShallowWrapper { onToggleCard={[Function]} scrollTop={[Function]} selected={[Function]} - uid={[Function]} />, "className": "scrollable", }, @@ -83,6 +83,7 @@ ShallowWrapper { "className": "", "compact": false, "details": [Function], + "getKey": [Function], "label": [Function], "multiselect": true, "nodes": Array [ @@ -106,7 +107,6 @@ ShallowWrapper { "onToggleCard": [Function], "scrollTop": [Function], "selected": [Function], - "uid": [Function], }, "ref": null, "rendered": null, @@ -124,6 +124,7 @@ ShallowWrapper { className="" compact={false} details={[Function]} + getKey={[Function]} label={[Function]} multiselect={true} nodes={ @@ -149,7 +150,6 @@ ShallowWrapper { onToggleCard={[Function]} scrollTop={[Function]} selected={[Function]} - uid={[Function]} />, "className": "scrollable", }, @@ -162,6 +162,7 @@ ShallowWrapper { "className": "", "compact": false, "details": [Function], + "getKey": [Function], "label": [Function], "multiselect": true, "nodes": Array [ @@ -185,7 +186,6 @@ ShallowWrapper { "onToggleCard": [Function], "scrollTop": [Function], "selected": [Function], - "uid": [Function], }, "ref": null, "rendered": null, diff --git a/src/containers/ConcentricCircles/ConcentricCircles.js b/src/containers/ConcentricCircles/ConcentricCircles.js index 3c4525f439..5a776b334d 100644 --- a/src/containers/ConcentricCircles/ConcentricCircles.js +++ b/src/containers/ConcentricCircles/ConcentricCircles.js @@ -5,7 +5,7 @@ import NodeLayout from './NodeLayout'; import EdgeLayout from './EdgeLayout'; import Background from './Background'; -const Sociogram = ({ stage, prompt }) => ( +const ConcentricCircles = ({ stage, prompt }) => (
{ @@ -27,11 +27,11 @@ const Sociogram = ({ stage, prompt }) => (
); -Sociogram.propTypes = { +ConcentricCircles.propTypes = { stage: PropTypes.object.isRequired, prompt: PropTypes.object.isRequired, }; -export { Sociogram }; +export { ConcentricCircles }; -export default Sociogram; +export default ConcentricCircles; diff --git a/src/containers/ConcentricCircles/NodeLayout.js b/src/containers/ConcentricCircles/NodeLayout.js index 5a420b75be..8bbdb14a83 100644 --- a/src/containers/ConcentricCircles/NodeLayout.js +++ b/src/containers/ConcentricCircles/NodeLayout.js @@ -8,6 +8,7 @@ import LayoutNode from './LayoutNode'; import { withBounds } from '../../behaviours'; import { makeGetSociogramOptions, makeGetPlacedNodes } from '../../selectors/sociogram'; import { actionCreators as sessionsActions } from '../../ducks/modules/sessions'; +import { NodePK } from '../../ducks/modules/network'; import { DropTarget } from '../../behaviours/DragAndDrop'; import sociogramOptionsProps from './propTypes'; @@ -30,7 +31,7 @@ const dropHandlers = compose( accepts: () => ({ meta }) => meta.itemType === 'POSITIONED_NODE', onDrop: props => (item) => { props.updateNode({ - uid: item.meta.uid, + [NodePK]: item.meta[NodePK], [props.layoutVariable]: relativeCoords(props, item), }); @@ -41,7 +42,7 @@ const dropHandlers = compose( if (!has(item.meta, props.layoutVariable)) { return; } props.updateNode({ - uid: item.meta.uid, + [NodePK]: item.meta[NodePK], [props.layoutVariable]: relativeCoords(props, item), }); }, @@ -84,9 +85,9 @@ class NodeLayout extends Component { if (!allowSelect) { return; } - this.connectNode(node.id); + this.connectNode(node[NodePK]); - this.toggleHighlightAttributes(node.uid); + this.toggleHighlightAttributes(node[NodePK]); this.forceUpdate(); } @@ -130,7 +131,7 @@ class NodeLayout extends Component { isLinking(node) { return this.props.allowSelect && this.props.canCreateEdge && - node.id === this.state.connectFrom; + node[NodePK] === this.state.connectFrom; } render() { @@ -148,7 +149,7 @@ class NodeLayout extends Component { return ( this.onSelected(node)} diff --git a/src/containers/ConcentricCircles/__tests__/NodeLayout.test.js b/src/containers/ConcentricCircles/__tests__/NodeLayout.test.js index 23e990878e..82d0503927 100644 --- a/src/containers/ConcentricCircles/__tests__/NodeLayout.test.js +++ b/src/containers/ConcentricCircles/__tests__/NodeLayout.test.js @@ -3,12 +3,13 @@ import React from 'react'; import { shallow } from 'enzyme'; import { NodeLayout } from '../NodeLayout'; +import { NodePK } from '../../../ducks/modules/network'; const layout = 'foo'; const mockProps = { nodes: [ - { bar: 'buzz', uid: 123, [layout]: { x: 0, y: 0 } }, + { bar: 'buzz', [NodePK]: 123, [layout]: { x: 0, y: 0 } }, ], updateNode: () => {}, toggleEdge: () => {}, @@ -47,12 +48,12 @@ describe('', () => { component.setProps({ ...mockProps, - nodes: [{ bar: 'buzz', uid: 123 }], + nodes: [{ bar: 'buzz', [NodePK]: 123 }], }); component.setProps({ ...mockProps, - nodes: [{ bar: 'buzz', uid: 123 }, { bar: 'bing', uid: 456 }], + nodes: [{ bar: 'buzz', [NodePK]: 123 }, { bar: 'bing', [NodePK]: 456 }], }); expect(componentDidUpdate.mock.calls.length).toEqual(1); @@ -69,7 +70,7 @@ describe('', () => { component.setProps({ ...mockProps, - nodes: [{ bar: 'buzz', uid: 123 }], + nodes: [{ bar: 'buzz', [NodePK]: 123 }], }); component.setProps({ diff --git a/src/containers/ConcentricCircles/__tests__/__snapshots__/ConcentricCircles.test.js.snap b/src/containers/ConcentricCircles/__tests__/__snapshots__/ConcentricCircles.test.js.snap index f0350c3fe6..847b31ac97 100644 --- a/src/containers/ConcentricCircles/__tests__/__snapshots__/ConcentricCircles.test.js.snap +++ b/src/containers/ConcentricCircles/__tests__/__snapshots__/ConcentricCircles.test.js.snap @@ -4,7 +4,7 @@ exports[` renders ok 1`] = ` ShallowWrapper { "length": 1, Symbol(enzyme.__root__): [Circular], - Symbol(enzyme.__unrendered__): { - this.props.removeNode(item.uid); + this.props.removeNode(item[NodePK]); } label = node => `${node[this.props.labelKey]}`; @@ -114,7 +115,10 @@ function makeMapStateToProps() { return function mapStateToProps(state, props) { let nodesForList = getDataByPrompt(state, props); if (!props.stage.showExistingNodes) { - nodesForList = differenceBy(getDataByPrompt(state, props), networkNodesForOtherPrompts(state, props), 'uid'); + nodesForList = differenceBy( + getDataByPrompt(state, props), + networkNodesForOtherPrompts(state, props), + NodePK); } return { diff --git a/src/containers/NodePanels.js b/src/containers/NodePanels.js index 60cd143bf8..c7c6418517 100644 --- a/src/containers/NodePanels.js +++ b/src/containers/NodePanels.js @@ -4,8 +4,9 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { includes, map, differenceBy } from 'lodash'; import { getNodeLabelFunction, networkNodes, makeNetworkNodesForOtherPrompts } from '../selectors/interface'; -import { getExternalData } from '../selectors/protocol'; +import { getExternalData } from '../selectors/externalData'; import { actionCreators as sessionsActions } from '../ducks/modules/sessions'; +import { NodePK } from '../ducks/modules/network'; import { makeGetPromptNodeAttributes, makeGetPanelConfiguration } from '../selectors/name-generator'; import { Panel, Panels, NodeList } from '../components/'; import { getCSSVariableAsString } from '../utils/CSSVariables'; @@ -52,9 +53,9 @@ class NodePanels extends PureComponent { onDrop = ({ meta }, dataSource) => { if (dataSource === 'existing') { - this.props.toggleNodeAttributes(meta.uid, { ...this.props.activePromptAttributes }); + this.props.toggleNodeAttributes(meta[NodePK], { ...this.props.activePromptAttributes }); } else { - this.props.removeNode(meta.uid); + this.props.removeNode(meta[NodePK]); } } @@ -112,13 +113,13 @@ class NodePanels extends PureComponent { const getNodesForDataSource = ({ nodes, existingNodes, externalData, dataSource }) => ( dataSource === 'existing' ? existingNodes : - differenceBy(externalData[dataSource].nodes, nodes, 'uid') + differenceBy(externalData[dataSource].nodes, nodes, NodePK) ); const getOriginNodeIds = ({ existingNodes, externalData, dataSource }) => ( dataSource === 'existing' ? - map(existingNodes, 'uid') : - map(externalData[dataSource].nodes, 'uid') + map(existingNodes, NodePK) : + map(externalData[dataSource].nodes, NodePK) ); function makeMapStateToProps() { @@ -155,7 +156,7 @@ function makeMapStateToProps() { ) : ({ meta }) => ( meta.itemType === 'EXISTING_NODE' && - includes(originNodeIds, meta.uid) + includes(originNodeIds, meta[NodePK]) ); return { diff --git a/src/containers/OrdinalBins.js b/src/containers/OrdinalBins.js index ebed68f494..d35f7c40bc 100644 --- a/src/containers/OrdinalBins.js +++ b/src/containers/OrdinalBins.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import color from 'color'; import { getNodeLabelFunction, makeNetworkNodesForSubject, makeGetOrdinalValues, makeGetPromptVariable } from '../selectors/interface'; import { actionCreators as sessionsActions } from '../ducks/modules/sessions'; +import { NodePK } from '../ducks/modules/network'; import { NodeList } from '../components/'; import { MonitorDragSource } from '../behaviours/DragAndDrop'; import { getCSSVariableAsString } from '../utils/CSSVariables'; @@ -63,7 +64,7 @@ class OrdinalBins extends PureComponent { const newValue = {}; newValue[this.props.activePromptVariable] = bin.value; - this.props.toggleNodeAttributes(meta.uid, newValue); + this.props.toggleNodeAttributes(meta[NodePK], newValue); }; const accentColor = this.calculateAccentColor(index, missingValue); diff --git a/src/containers/Search/Search.js b/src/containers/Search/Search.js index 41e9dd4eb1..dea31326b1 100644 --- a/src/containers/Search/Search.js +++ b/src/containers/Search/Search.js @@ -9,6 +9,7 @@ import SearchTransition from '../../components/Transition/Search'; import SearchResults from './SearchResults'; import AddCountButton from '../../components/AddCountButton'; import { actionCreators as searchActions } from '../../ducks/modules/search'; +import { NodePK } from '../../ducks/modules/network'; import { makeGetFuse } from '../../selectors/search'; /** @@ -110,35 +111,13 @@ class Search extends Component { }); } - /** - * A result is considered unique only if it presents some disambiguating - * information to the user (i.e., its combination of display attributes is unique). - * - * The `uid` attribute cannot be used to determine uniqueness: once an item - * from external data (having no `uid`) is added to the network, it will have - * a `uid`. - * - * @param {object} result A search result - * @return {string} a unique identifier for the result - */ - uniqueKeyForResult(result) { - const displayFields = [ - result[this.props.primaryDisplayField], - ...this.props.additionalAttributes.map(prop => prop.variable), - ]; - return displayFields.map(field => result[field]).join('.'); - } - - // See uniqueness discussion at uniqueKeyForResult. // If false, suppress candidate from appearing in search results — // for example, if the node has already been selected. // Assumption: // `excludedNodes` size is small, but search set may be large, // and so preferable to filter found results dynamically. isAllowedResult(candidate) { - const uid = this.uniqueKeyForResult.bind(this); - const candidateUid = uid(candidate); - return this.props.excludedNodes.every(excluded => uid(excluded) !== candidateUid); + return this.props.excludedNodes.every(excluded => excluded[NodePK] !== candidate[NodePK]); } render() { @@ -181,7 +160,6 @@ class Search extends Component { const getLabel = result => result[primaryDisplayField]; const getSelected = result => this.state.selectedResults.indexOf(result) > -1; const getDetails = result => additionalAttributes.map(attr => toDetail(result, attr)); - const getUid = result => this.uniqueKeyForResult(result); return ( jest.fn(() => ( const mockReduxState = { protocol: { variableRegistry: {}, - externalData: {}, }, + externalData: {}, search: { collapsed: false, }, diff --git a/src/containers/Setup/SessionList.js b/src/containers/Setup/SessionList.js index c7b030089b..14e0c79bce 100644 --- a/src/containers/Setup/SessionList.js +++ b/src/containers/Setup/SessionList.js @@ -12,7 +12,7 @@ import { protocolsByPath } from '../../selectors/protocols'; import { CardList } from '../../components'; import { matchSessionPath } from '../../utils/matchSessionPath'; -const shortUid = uid => (uid || '').replace(/-.*/, ''); +const shortId = uuid => (uuid || '').replace(/-.*/, ''); const displayDate = timestamp => timestamp && new Date(timestamp).toLocaleString(undefined, { year: 'numeric', month: 'numeric', day: 'numeric' }); @@ -46,8 +46,8 @@ const emptyView = ( */ class SessionList extends Component { onClickLoadSession = (session) => { - const pathname = this.props.getSessionPath(session.uid); - this.props.setSession(session.uid); + const pathname = this.props.getSessionPath(session.uuid); + this.props.setSession(session.uuid); this.props.loadSession(pathname); } @@ -56,7 +56,7 @@ class SessionList extends Component { // Display most recent first, and filter out any session that doesn't have a protocol const sessionList = Object.keys(sessions) - .map(key => ({ uid: key, value: sessions[key] })) + .map(key => ({ uuid: key, value: sessions[key] })) .filter(s => s.value.protocolPath); sessionList.sort((a, b) => b.value.updatedAt - a.value.updatedAt); @@ -72,12 +72,13 @@ class SessionList extends Component { onDeleteCard={(data) => { // eslint-disable-next-line no-alert if (confirm('Delete this interview?')) { - removeSession(data.uid); + removeSession(data.uuid); } }} - label={sessionInfo => shortUid(sessionInfo.uid)} + label={sessionInfo => shortId(sessionInfo.uuid)} nodes={sessionList} onToggleCard={this.onClickLoadSession} + getKey={sessionInfo => sessionInfo.uuid} details={(sessionInfo) => { const session = sessionInfo.value; const info = pathInfo(session.path); diff --git a/src/containers/__tests__/Field.test.js b/src/containers/__tests__/Field.test.js index e09e552f68..9ca7cb1f96 100644 --- a/src/containers/__tests__/Field.test.js +++ b/src/containers/__tests__/Field.test.js @@ -15,19 +15,13 @@ const validation = { minLength: 2, }; -jest.mock('uuid'); - const reduxFormFieldProperties = { input: { name: 'foo', value: '' }, meta: { invalid: false } }; describe('getInputComponent()', () => { - it('should return renderable component', () => { - const Input = getInputComponent('Alphanumeric'); - - const subject = shallow(( - - )); - - expect(subject).toMatchSnapshot(); + it('should return a dom input', () => { + const Input = getInputComponent(); + const subject = shallow(); + expect(subject.find('input')).toHaveLength(1); }); }); diff --git a/src/containers/__tests__/__snapshots__/Field.test.js.snap b/src/containers/__tests__/__snapshots__/Field.test.js.snap index d70a5d9eab..2bbcedfc8c 100644 --- a/src/containers/__tests__/__snapshots__/Field.test.js.snap +++ b/src/containers/__tests__/__snapshots__/Field.test.js.snap @@ -56,214 +56,3 @@ ShallowWrapper { }, } `; - -exports[`getInputComponent() should return renderable component 1`] = ` -ShallowWrapper { - "length": 1, - Symbol(enzyme.__root__): [Circular], - Symbol(enzyme.__unrendered__):