Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PXD-1312 feat(search): Enable search function for data dictionary view #434

Merged
merged 33 commits into from
Jan 30, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1331ef2
feat(search): import search library, and link to autocomplete
qingyashu Dec 6, 2018
22a6e7a
feat(node): highlight matched nodes
qingyashu Dec 7, 2018
88b7a1f
feat(history): show search result and add to history
qingyashu Dec 10, 2018
ced16c1
feat(popup): add popup search result
qingyashu Dec 11, 2018
54f1423
Merge branch 'master' into feat/dd-search
qingyashu Dec 18, 2018
72e81dd
fix(search): add more for search overlay result, and some tests
qingyashu Dec 18, 2018
d4f9fea
fix(lint): eslint
qingyashu Dec 18, 2018
23daa9f
fix(search): if start typing, clear all current highlighted nodes
qingyashu Dec 18, 2018
a48134e
fix(fuse): bug in fuse sometimes return wrong indices, filter out them
qingyashu Dec 18, 2018
0b8f736
fix(typo): fix typo
qingyashu Dec 18, 2018
8cd54b5
fix(style): some style improvement
qingyashu Dec 18, 2018
cd39f09
fix(types): fix a bug that only showed one highlighted type
qingyashu Dec 18, 2018
cd50e63
fix(improve): improve according to review and design check
qingyashu Dec 20, 2018
8bc3d88
fix(half-fade): make node and edge half faded effect
qingyashu Dec 20, 2018
a89827d
fix(emphasize-node): add half-faded effect for search result
qingyashu Dec 20, 2018
5e4daab
fix(test): fix test
qingyashu Dec 20, 2018
8d383c8
fix(improve): more improve on UI
qingyashu Dec 20, 2018
c05ca62
Merge branch 'master' into feat/dd-search
qingyashu Dec 20, 2018
2a4fb57
fix(border): remove border for gray bar
qingyashu Dec 21, 2018
a2766c9
fix(search): improve search, and some little style change
qingyashu Dec 21, 2018
f77e6aa
fix(search): output error if keyword too shor or too long
qingyashu Dec 21, 2018
974a990
fix(clear): fix bugs on clear result button, and according to comments
qingyashu Jan 9, 2019
7c63077
Merge branch 'master' into feat/dd-search
qingyashu Jan 9, 2019
d3e7b6f
fix(review): fix according to review
qingyashu Jan 23, 2019
28a44d1
fix(autocomplete): sort autocomplete items according to string distance
qingyashu Jan 23, 2019
e6070ef
fix(package): add stringsimilarity package
qingyashu Jan 23, 2019
601ee34
Merge branch 'master' into feat/dd-search
qingyashu Jan 23, 2019
ae401eb
Merge branch 'master' into feat/dd-search
qingyashu Jan 28, 2019
e1104b5
fix(version): ui-component version to .22
qingyashu Jan 29, 2019
c2a910d
fix(review): fix some test and others according to review comments
qingyashu Jan 29, 2019
02ab6df
fix(typo): typo typo
qingyashu Jan 29, 2019
e37d375
Merge branch 'master' into feat/dd-search
qingyashu Jan 29, 2019
9916178
fix(NaN): fix console error about NaN
qingyashu Jan 30, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 209 additions & 212 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@fortawesome/fontawesome-svg-core": "^1.2.2",
"@fortawesome/free-solid-svg-icons": "^5.2.0",
"@fortawesome/react-fontawesome": "^0.1.0",
"@gen3/ui-component": "0.0.18",
"@gen3/ui-component": "0.0.19",
"@storybook/addon-actions": "^3.4.8",
"@storybook/react": "^3.4.8",
"babel-core": "^6.26.0",
Expand All @@ -27,6 +27,7 @@
"d3-zoom": "^1.7.3",
"fast-csv": "^2.4.0",
"file-saver": "^1.3.3",
"fuse.js": "^3.3.0",
"graphiql": "^0.11.11",
"graphql": "^0.12.3",
"history": "^4.7.2",
Expand Down Expand Up @@ -101,6 +102,7 @@
"html-webpack-plugin": "^3.2.0",
"jest": "^21.2.1",
"jest-fetch-mock": "^1.2.1",
"jest-localstorage-mock": "^2.3.0",
"mock-local-storage": "^1.0.5",
"prettier": "^1.4.4",
"react-hot-loader": "^1.3.0",
Expand All @@ -120,7 +122,8 @@
"automock": false,
"setupFiles": [
"./src/shim.js",
"./src/setupJest.js"
"./src/setupJest.js",
"jest-localstorage-mock"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
Expand Down
2 changes: 1 addition & 1 deletion src/DataDictionary/DataDictionary.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@
.data-dictionary__switch-button--active {
background-color: var(--g3-color__base-blue);
color: var(--g3-color__white);
}
}
20 changes: 16 additions & 4 deletions src/DataDictionary/DataDictionary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ import PropTypes from 'prop-types';
import ReduxDataDictionaryTable from './table/DataDictionaryTable';
import ReduxDataModelStructure from './DataModelStructure';
import DataDictionaryGraph from './graph/DataDictionaryGraph/.';
import ReduxDictionarySearcher from './search/DictionarySearcher/.';
import ReduxDictionarySearchHistory from './search/DictionarySearchHistory/.';
import './DataDictionary.css';

class DataDictionary extends React.Component {
constructor(props) {
super(props);
this.dictionarySearcherRef = React.createRef();
}

setGraphView = (isGraphView) => {
this.props.onSetGraphView(isGraphView);
}

handleClickSearchHistoryItem = (keyword) => {
this.dictionarySearcherRef.current.getWrappedInstance().launchSearchFromOutside(keyword);
}

render() {
return (
<div className='data-dictionary'>
Expand All @@ -32,10 +43,11 @@ class DataDictionary extends React.Component {
Table View
</span>
</div>
<div className='data-dictionary__model-structure'>
<ReduxDataModelStructure />
</div>
<div className='data-dictionary__search' />
<ReduxDictionarySearcher ref={this.dictionarySearcherRef} />
<ReduxDataModelStructure />
<ReduxDictionarySearchHistory
onClickSearchHistoryItem={this.handleClickSearchHistoryItem}
/>
<div className='data-dictionary__search-history' />
</div>
<div
Expand Down
46 changes: 46 additions & 0 deletions src/DataDictionary/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,49 @@ export const setHighlightingNodeSVGElement = highlightingNodeSVGElement => ({
highlightingNodeSVGElement,
});

export const setIsSearching = isSearching => ({
type: 'SEARCH_SET_IS_SEARCHING_STATUS',
isSearching,
});

export const setSearchResult = searchResult => ({
type: 'SEARCH_RESULT_UPDATED',
searchResult,
});

export const clearSearchHistoryItems = () => ({
type: 'SEARCH_CLEAR_HISTORY',
});

export const addSearchHistoryItem = searchHistoryItem => ({
type: 'SEARCH_HISTORY_ITEM_CREATED',
searchHistoryItem,
});

export const setGraphNodesSVGElements = graphNodesSVGElements => ({
type: 'GRAPH_NODES_SVG_ELEMENTS_UPDATED',
graphNodesSVGElements,
});

export const setMatchedNodeExpandingStatus = (nodeID, expanding) => ({
type: 'GRAPH_MATCHED_NODE_EXPANDED',
nodeID,
expanding,
});

export const clearSearchResult = () => ({
type: 'SEARCH_RESULT_CLEARED',
});

export const collapseAllMatchedNodePopups = () => ({
type: 'GRAPH_MATCHED_NODE_ALL_COLLAPSED',
});

export const expandAllMAtchedNodePopups = () => ({
type: 'GRAPH_MATCHED_NODE_ALL_EXPANDED',
});

export const saveCurrentSearchKeyword = keyword => ({
type: 'SEARCH_SAVE_CURRENT_KEYWORD',
keyword,
});
3 changes: 1 addition & 2 deletions src/DataDictionary/graph/Canvas/Canvas.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ class Canvas extends React.Component {

handleCanvasUpdate = () => {
const canvasBoundingRect = this.canvasElement.current.getBoundingClientRect();
window.canvasElem = this.canvasElement.current;
this.props.onCanvasBoundingBoxUpdate(canvasBoundingRect);
}

Expand Down Expand Up @@ -197,7 +196,7 @@ Canvas.propTypes = {

Canvas.defaultProps = {
minZoom: 0.1,
maxZoom: 5,
maxZoom: 10,
topLeftTranslateLimit: [-Infinity, -Infinity],
bottomRightTranslateLimit: [+Infinity, +Infinity],
onClickBlankSpace: () => {},
Expand Down
2 changes: 2 additions & 0 deletions src/DataDictionary/graph/DataDictionaryGraph/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ReduxGraphDrawer from '../GraphDrawer/.';
import ReduxNodeTooltip from '../NodeTooltip/.';
import ReduxNodePopup from '../NodePopup/.';
import ReduxOverlayPropertyTable from '../OverlayPropertyTable/.';
import ReduxSearchResultLayer from '../SearchResultLayer/.';

class DataDictionaryGraph extends React.Component {
render() {
Expand All @@ -19,6 +20,7 @@ class DataDictionaryGraph extends React.Component {
<ReduxNodeTooltip />
<ReduxNodePopup />
<ReduxOverlayPropertyTable />
<ReduxSearchResultLayer />
</React.Fragment>
);
}
Expand Down
23 changes: 14 additions & 9 deletions src/DataDictionary/graph/GraphCalculator/GraphCalculator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ class GraphCalculator extends React.Component {
super(props);
this.oldHighlightingNode = null;
this.oldSecondHighlightingNodeID = null;
window.dictionary = this.props.dictionary;
}

componentDidMount() {
calculateGraphLayout(
this.props.dictionary,
this.props.countsSearch,
this.props.linksSearch,
).then((layoutResult) => {
this.props.onGraphLayoutCalculated(layoutResult);
const legendItems = getAllTypes(layoutResult.nodes);
this.props.onGraphLegendCalculated(legendItems);
});
if (!this.props.layoutInitialized) {
calculateGraphLayout(
this.props.dictionary,
this.props.countsSearch,
this.props.linksSearch,
).then((layoutResult) => {
this.props.onGraphLayoutCalculated(layoutResult);
const legendItems = getAllTypes(layoutResult.nodes);
this.props.onGraphLegendCalculated(legendItems);
});
}
}

componentWillUpdate(nextProps) {
Expand Down Expand Up @@ -137,6 +140,7 @@ GraphCalculator.propTypes = {
secondHighlightingNodeID: PropTypes.string,
onPathRelatedToSecondHighlightingNodeCalculated: PropTypes.func,
onDataModelStructureCalculated: PropTypes.func,
layoutInitialized: PropTypes.bool,
};

GraphCalculator.defaultProps = {
Expand All @@ -153,6 +157,7 @@ GraphCalculator.defaultProps = {
onSecondHighlightingNodeCandidateIDsCalculated: () => {},
onPathRelatedToSecondHighlightingNodeCalculated: () => {},
onDataModelStructureCalculated: () => {},
layoutInitialized: false,
};

export default GraphCalculator;
1 change: 1 addition & 0 deletions src/DataDictionary/graph/GraphCalculator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const ReduxGraphCalculator = (() => {
nodes: state.ddgraph.nodes,
edges: state.ddgraph.edges,
secondHighlightingNodeID: state.ddgraph.secondHighlightingNodeID,
layoutInitialized: state.ddgraph.layoutInitialized,
});

const mapDispatchToProps = dispatch => ({
Expand Down
66 changes: 63 additions & 3 deletions src/DataDictionary/graph/GraphDrawer/GraphDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,43 @@ import React from 'react';
import PropTypes from 'prop-types';
import GraphNode from '../GraphNode/GraphNode';
import GraphEdge from '../GraphEdge/GraphEdge';
import { SearchResultItemShape } from '../../utils';
import './GraphDrawer.css';

class GraphDrawer extends React.Component {
constructor(props) {
super(props);
this.currentHighlightingNodeClassName = 'graph-drawer__node--current-highlighting';
this.graphDomRef = React.createRef();
this.graphNodeRefs = [];
this.nodeSVGElementInitialized = false;
}

componentDidUpdate() {
// check if need update highlightingNodeSVGElement
if (this.props.isGraphView
&& this.props.highlightingNode
&& !this.props.highlightingNodeSVGElement) {
const highlightingNodeSVGElement = this.getHighlightingNodeSVGElement();
this.props.onHighlightingNodeSVGElementUpdated(highlightingNodeSVGElement);
}

// check if need update all node's svg elements
// this only happens once, at the first time graph is rendered
if (this.props.isGraphView
&& this.props.layoutInitialized
&& !this.nodeSVGElementInitialized) {
const graphNodesSVGElements = this.props.nodes.map(node => ({
nodeID: node.id,
svgElement: this.getNodeRef(node.id).current.getSVGElement(),
}))
.reduce((acc, cur) => {
acc[cur.nodeID] = cur.svgElement;
return acc;
}, {});
this.nodeSVGElementInitialized = true;
this.props.onGraphNodesSVGElementsUpdated(graphNodesSVGElements);
}
}

onMouseOverNode = (node, e) => {
Expand All @@ -30,7 +51,11 @@ class GraphDrawer extends React.Component {
}

onClickNode = (node, e) => {
if (!this.props.highlightingNode) { // if no node is highlighted yet
if (this.props.matchedNodeIDs && this.props.matchedNodeIDs.length > 0) { // if in search mode
if (this.props.matchedNodeIDs.includes(node.id)) {
this.props.onExpandMatchedNode(node.id);
}
} else if (!this.props.highlightingNode) { // if no node is highlighted yet
const highlightingNodeSVGElement = e.currentTarget;
this.props.onClickNode(node, highlightingNodeSVGElement);
} else if (this.props.secondHighlightingNodeCandidateIDs.length > 1
Expand All @@ -48,6 +73,13 @@ class GraphDrawer extends React.Component {
return highlightingNodeSVGElement;
}

getNodeRef = (nodeID) => {
if (!this.graphNodeRefs[nodeID]) {
this.graphNodeRefs[nodeID] = React.createRef();
}
return this.graphNodeRefs[nodeID];
}

render() {
if (!this.props.layoutInitialized) return (<React.Fragment />);
const boundingBoxLength = this.props.graphBoundingBox[2][0];
Expand All @@ -71,7 +103,9 @@ class GraphDrawer extends React.Component {
this.props.edges.map((edge, i) => {
let isEdgeFaded = false;
let isEdgeHighlighted = false;
if (this.props.highlightingNode) {
if (this.props.matchedNodeIDs && this.props.matchedNodeIDs.length > 0) {
isEdgeFaded = true;
} else if (this.props.highlightingNode) {
if (this.props.secondHighlightingNodeID) {
const isEdgeAlongPathRelatedToSecondHighlightNode =
!!this.props.pathRelatedToSecondHighlightingNode
Expand Down Expand Up @@ -102,7 +136,10 @@ class GraphDrawer extends React.Component {
let isNodeFaded = false;
let isNodeClickable = true;
let isHighlightingNode = false;
if (this.props.highlightingNode) {
if (this.props.matchedNodeIDs && this.props.matchedNodeIDs.length > 0) {
isNodeFaded = !this.props.matchedNodeIDs.includes(node.id);
isNodeClickable = !isNodeFaded;
} else if (this.props.highlightingNode) {
isHighlightingNode = (this.props.highlightingNode.id === node.id);
isNodeClickable =
this.props.secondHighlightingNodeCandidateIDs.includes(node.id);
Expand All @@ -113,6 +150,19 @@ class GraphDrawer extends React.Component {
isNodeFaded = !this.props.relatedNodeIDs.includes(node.id);
}
}

// TODO: move to searcher

let matchedNodeNameIndices = [];
this.props.searchResult.forEach((item) => {
if (item.item.id === node.id) {
item.matches.forEach((matchItem) => {
if (matchItem.key === 'title') {
matchedNodeNameIndices = matchItem.indices;
}
});
}
});
return (
<GraphNode
key={node.id}
Expand All @@ -124,6 +174,8 @@ class GraphDrawer extends React.Component {
onMouseOver={e => this.onMouseOverNode(node, e)}
onMouseOut={this.onMouseOutNode}
onClick={e => this.onClickNode(node, e)}
ref={this.getNodeRef(node.id)}
matchedNodeNameIndices={matchedNodeNameIndices}
/>
);
})
Expand Down Expand Up @@ -152,6 +204,10 @@ GraphDrawer.propTypes = {
highlightingNodeSVGElement: PropTypes.object,
onHighlightingNodeSVGElementUpdated: PropTypes.func,
isGraphView: PropTypes.bool,
matchedNodeIDs: PropTypes.arrayOf(PropTypes.string),
onGraphNodesSVGElementsUpdated: PropTypes.func,
onExpandMatchedNode: PropTypes.func,
searchResult: PropTypes.arrayOf(SearchResultItemShape),
};

GraphDrawer.defaultProps = {
Expand All @@ -173,6 +229,10 @@ GraphDrawer.defaultProps = {
highlightingNodeSVGElement: null,
onHighlightingNodeSVGElementUpdated: () => {},
isGraphView: true,
matchedNodeIDs: [],
onGraphNodesSVGElementsUpdated: () => {},
onExpandMatchedNode: () => {},
searchResult: [],
};

export default GraphDrawer;
7 changes: 7 additions & 0 deletions src/DataDictionary/graph/GraphDrawer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
setHighlightingNode,
setSecondHighlightingNodeID,
setHighlightingNodeSVGElement,
setGraphNodesSVGElements,
setMatchedNodeExpandingStatus,
} from '../../action.js';
import GraphDrawer from './GraphDrawer';

Expand All @@ -20,6 +22,8 @@ const ReduxGraphDrawer = (() => {
pathRelatedToSecondHighlightingNode: state.ddgraph.pathRelatedToSecondHighlightingNode,
secondHighlightingNodeID: state.ddgraph.secondHighlightingNodeID,
isGraphView: state.ddgraph.isGraphView,
matchedNodeIDs: state.ddgraph.matchedNodeIDs,
searchResult: state.ddgraph.searchResult,
});

const mapDispatchToProps = dispatch => ({
Expand All @@ -31,6 +35,9 @@ const ReduxGraphDrawer = (() => {
onClickNodeAsSecondHighlightingNode: nodeID => dispatch(setSecondHighlightingNodeID(nodeID)),
onHighlightingNodeSVGElementUpdated: highlightingNodeSVGElement =>
dispatch(setHighlightingNodeSVGElement(highlightingNodeSVGElement)),
onGraphNodesSVGElementsUpdated: graphNodesSVGElements =>
dispatch(setGraphNodesSVGElements(graphNodesSVGElements)),
onExpandMatchedNode: nodeID => dispatch(setMatchedNodeExpandingStatus(nodeID, true)),
});

return connect(mapStateToProps, mapDispatchToProps)(GraphDrawer);
Expand Down
Loading