Skip to content

Commit 2cc0b92

Browse files
authored
Merge pull request #275 from netcreateorg/dev-bl/focus
Feature: Focus
2 parents 1fe2009 + b5e517f commit 2cc0b92

File tree

7 files changed

+416
-105
lines changed

7 files changed

+416
-105
lines changed

build/app/view/netcreate/NetCreate.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,13 @@ const FILTER = require('./components/filter/FilterEnums');
190190
// OPEN
191191
? <div id="right" style={{
192192
marginTop: '38px', padding: '0 5px', backgroundColor: '#6c757d',
193-
borderTopLeftRadius: '10px', width: 'auto'
193+
borderTopLeftRadius: '10px',
194+
paddingBottom: '25px', // avoid footer
194195
}}>
195-
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'end' }}>
196+
<div style={{
197+
display: 'flex', flexDirection: 'column', alignItems: 'end',
198+
height: '100%', overflow: 'hidden'
199+
}}>
196200
<Button onClick={this.onFilterBtnClick}
197201
style={{ width: '90px' }}
198202
>

build/app/view/netcreate/components/EdgeTable.jsx

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class EdgeTable extends UNISYS.Component {
137137
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
138138
displayUpdated(nodeEdge) {
139139
// Prevent error if `meta` info is not defined yet, or not properly imported
140-
if (!nodeEdge.meta) return;
140+
if (!nodeEdge.meta) return '';
141141

142142
var d = new Date(nodeEdge.meta.revision > 0 ? nodeEdge.meta.updated : nodeEdge.meta.created);
143143

@@ -158,11 +158,21 @@ class EdgeTable extends UNISYS.Component {
158158
updateEdgeFilterState(edges, filteredEdges) {
159159
// add highlight/filter status
160160
if (filteredEdges.length > 0) {
161-
edges = edges.map(edge => {
162-
const filteredEdge = filteredEdges.find(n => n.id === edge.id);
163-
edge.isFiltered = !filteredEdge;
164-
return edge;
165-
});
161+
// If we're transitioning from "HILIGHT/FADE" to "COLLAPSE" or "FOCUS", then we
162+
// also need to remove edges that are not in filteredEdges
163+
const FDATA = UDATA.AppState("FDATA");
164+
if (FDATA.filterAction === FILTER.ACTION.COLLAPSE || FDATA.filterAction === FILTER.ACTION.FOCUS) {
165+
edges = edges.filter(edge => {
166+
const filteredEdge = filteredEdges.find(n => n.id === edge.id);
167+
return edge;
168+
});
169+
} else {
170+
edges = edges.map(edge => {
171+
const filteredEdge = filteredEdges.find(n => n.id === edge.id);
172+
edge.isFiltered = !filteredEdge;
173+
return edge;
174+
});
175+
}
166176
}
167177
this.setState({edges});
168178
}
@@ -199,22 +209,28 @@ class EdgeTable extends UNISYS.Component {
199209
handleFilterDataUpdate(data) {
200210
if (data.edges) {
201211
const filteredEdges = data.edges;
202-
203-
// OLD METHOD: Keep a pure edges object, and apply filtering to them
204-
// this.setState({ filteredEdges }, () => {
205-
// const edges = this.sortTable(this.state.sortkey, this.state.edges);
206-
// this.updateEdgeFilterState(edges, filteredEdges);
207-
// });
208-
209-
// NEW METHOD: Just replace pure edges with filtered edges
210-
// This way edges that have been filtered out are also removed from the table
211-
this.setState({
212-
edges: filteredEdges,
213-
filteredEdges
214-
}, () => {
215-
const edges = this.sortTable(this.state.sortkey, this.state.edges);
216-
this.updateEdgeFilterState(edges, filteredEdges);
217-
});
212+
// If we're transitioning from "COLLAPSE" or "FOCUS" to "HILIGHT/FADE", then we
213+
// also need to add back in edges that are not in filteredEdges
214+
// (because "COLLAPSE" and "FOCUS" removes edges that are not matched)
215+
const FDATA = UDATA.AppState("FDATA");
216+
if (FDATA.filterAction === FILTER.ACTION.HIGHLIGHT) {
217+
const NCDATA = UDATA.AppState("NCDATA");
218+
this.setState({
219+
edges: NCDATA.edges,
220+
filteredEdges
221+
}, () => {
222+
const edges = this.sortTable(this.state.sortkey, NCDATA.edges);
223+
this.updateEdgeFilterState(edges, filteredEdges);
224+
});
225+
} else {
226+
this.setState({
227+
edges: filteredEdges,
228+
filteredEdges
229+
}, () => {
230+
const edges = this.sortTable(this.state.sortkey, filteredEdges);
231+
this.updateEdgeFilterState(edges, filteredEdges);
232+
});
233+
}
218234
}
219235
}
220236

build/app/view/netcreate/components/NodeTable.jsx

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class NodeTable extends UNISYS.Component {
129129
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
130130
displayUpdated(nodeEdge) {
131131
// Prevent error if `meta` info is not defined yet, or not properly imported
132-
if (!nodeEdge.meta) return;
132+
if (!nodeEdge.meta) return '';
133133

134134
var d = new Date(nodeEdge.meta.revision > 0 ? nodeEdge.meta.updated : nodeEdge.meta.created);
135135

@@ -142,21 +142,33 @@ class NodeTable extends UNISYS.Component {
142142
var tag = <span title={titleString}> {dateTime} </span>;
143143

144144
return tag;
145-
146145
}
147146

148147
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
149148
/// Set node filtered status based on current filteredNodes
150149
updateNodeFilterState(nodes, filteredNodes) {
151150
// set filter status
152151
if (filteredNodes.length > 0) {
153-
nodes = nodes.map(node => {
154-
const filteredNode = filteredNodes.find(n => n.id === node.id);
155-
node.isFiltered = !filteredNode; // not in filteredNode, so it's been removed
156-
return node
157-
});
152+
153+
// If we're transitioning from "HILIGHT/FADE" to "COLLAPSE" or "FOCUS", then we
154+
// also need to remove nodes that are not in filteredNodes
155+
const FDATA = UDATA.AppState("FDATA");
156+
if (FDATA.filterAction === FILTER.ACTION.COLLAPSE || FDATA.filterAction === FILTER.ACTION.FOCUS) {
157+
nodes = nodes.filter(node => {
158+
const filteredNode = filteredNodes.find(n => n.id === node.id);
159+
return filteredNode; // keep if it's in the list of filtered nodes
160+
});
161+
} else {
162+
nodes = nodes.map(node => {
163+
const filteredNode = filteredNodes.find(n => n.id === node.id);
164+
node.isFiltered = !filteredNode; // not in filteredNode, so it's been removed
165+
return node
166+
});
167+
}
168+
169+
158170
}
159-
this.setState({ nodes });
171+
this.setState({ nodes, filteredNodes });
160172
}
161173

162174
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -175,22 +187,29 @@ class NodeTable extends UNISYS.Component {
175187
handleFilterDataUpdate(data) {
176188
if (data.nodes) {
177189
const filteredNodes = data.nodes;
190+
// If we're transitioning from "COLLAPSE" or "FOCUS" to "HILIGHT/FADE", then we
191+
// also need to add back in nodes that are not in filteredNodes
192+
// (because "COLLAPSE" and "FOCUS" removes nodes that are not matched)
193+
const FDATA = UDATA.AppState("FDATA");
194+
if (FDATA.filterAction === FILTER.ACTION.HIGHLIGHT) {
195+
const NCDATA = UDATA.AppState("NCDATA");
196+
this.setState({
197+
nodes: NCDATA.nodes,
198+
filteredNodes
199+
}, () => {
200+
const nodes = this.sortTable(this.state.sortkey, NCDATA.nodes);
201+
this.updateNodeFilterState(nodes, filteredNodes);
202+
});
178203

179-
// OLD METHOD: Keep a pure nodes object, and apply filtering to them
180-
// this.setState({ filteredNodes }, () => {
181-
// const nodes = this.sortTable(this.state.sortkey, this.state.nodes);
182-
// this.updateNodeFilterState(nodes, filteredNodes);
183-
// });
184-
185-
// NEW METHOD: Just replace pure nodes with filtered nodes
186-
// This way nodes that have been filtered out are also removed from the table
187-
this.setState({
188-
nodes: filteredNodes,
189-
filteredNodes
190-
}, () => {
191-
const nodes = this.sortTable(this.state.sortkey, this.state.nodes);
192-
this.updateNodeFilterState(nodes, filteredNodes);
193-
});
204+
} else {
205+
this.setState({
206+
nodes: filteredNodes,
207+
filteredNodes
208+
}, () => {
209+
const nodes = this.sortTable(this.state.sortkey, filteredNodes);
210+
this.updateNodeFilterState(nodes, filteredNodes);
211+
});
212+
}
194213
}
195214
}
196215

@@ -450,14 +469,14 @@ render() {
450469
<Button size="sm"
451470
onClick={()=>this.setSortKey("info", nodeDefs.info.type)}
452471
>{nodeDefs.info.displayLabel} {this.sortSymbol("info")}</Button></th>
453-
<th width="9%"hidden={nodeDefs.provenance.hidden}>
454-
<Button size="sm"
455-
onClick={()=>this.setSortKey("provenance", nodeDefs.provenance.type)}
456-
>{nodeDefs.provenance.displayLabel} {this.sortSymbol("provenance")}</Button></th>
457472
<th width="25%" hidden={nodeDefs.notes.hidden}>
458473
<Button size="sm"
459474
onClick={()=>this.setSortKey("notes", nodeDefs.notes.type)}
460475
>{nodeDefs.notes.displayLabel} {this.sortSymbol("notes")}</Button></th>
476+
<th width="9%"hidden={nodeDefs.provenance.hidden}>
477+
<Button size="sm"
478+
onClick={()=>this.setSortKey("provenance", nodeDefs.provenance.type)}
479+
>{nodeDefs.provenance.displayLabel} {this.sortSymbol("provenance")}</Button></th>
461480
<th width="10%"hidden={!isLocalHost}><Button size="sm"
462481
onClick={()=>this.setSortKey("updated", FILTER.TYPES.STRING)}
463482
>Updated {this.sortSymbol("updated")}</Button></th>
@@ -485,12 +504,12 @@ render() {
485504
>{node.label}</a></td>
486505
<td hidden={nodeDefs.type.hidden}>{node.type}</td>
487506
<td hidden={nodeDefs.info.hidden}>{node.info}</td>
488-
<td hidden={nodeDefs.provenance.hidden}
489-
style={{ fontSize: '9px' }}
490-
>{node.provenance}</td>
491507
<td hidden={nodeDefs.notes.hidden}>
492508
{node.notes ? <MarkdownNote text={node.notes} /> : "" }
493509
</td>
510+
<td hidden={nodeDefs.provenance.hidden}
511+
style={{ fontSize: '9px' }}
512+
>{node.provenance}</td>
494513
<td hidden={!isLocalHost}
495514
style={{ fontSize: '9px' }}
496515
>{this.displayUpdated(node)}</td>

build/app/view/netcreate/components/filter/FilterEnums.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ FILTER.PANEL_LABEL = 'VIEWS';
55

66
// Determines whether filter action is to highlight/fade or remove (filter) nodes and edges
77
FILTER.ACTION = {};
8-
FILTER.ACTION.HIGHLIGHT = 'HIGHLIGHTING';
8+
FILTER.ACTION.HIGHLIGHT = 'FADE';
99
FILTER.ACTION.FILTER = 'FILTERING';
10-
FILTER.ACTION.COLLAPSE = 'COLLAPSING';
10+
FILTER.ACTION.COLLAPSE = 'REMOVE';
11+
FILTER.ACTION.FOCUS = 'FOCUS';
1112
FILTER.ACTION.HELP = {};
12-
FILTER.ACTION.HELP.HIGHLIGHT = 'Show (Highlight) matches, Fade others';
13+
FILTER.ACTION.HELP.HIGHLIGHT = 'Show matches, Fade others';
1314
FILTER.ACTION.HELP.FILTER = 'Shows matches, Hide (Filter) others (keep physics and degrees)';
14-
FILTER.ACTION.HELP.COLLAPSE = 'Show matches, Remove (collapse) others & recalculate sizes';
15+
FILTER.ACTION.HELP.COLLAPSE = 'Show matches, Remove others & recalculate sizes';
16+
FILTER.ACTION.HELP.FOCUS = 'Show only nodes connected to the selected node within range';
1517

1618
// Types of filters definable in template files.
1719
FILTER.TYPES = {};

build/app/view/netcreate/components/filter/FiltersPanel.jsx

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
import FILTER from './FilterEnums';
1818
import FilterGroup from './FilterGroup';
19+
import FocusFilter from './FocusFilter';
1920
import React from 'react';
20-
import StringFilter from './StringFilter';
2121
const ReactStrap = require('reactstrap');
2222

23-
const { Button, ButtonGroup, Input, Label } = ReactStrap;
23+
const { Button, ButtonGroup, Input, Label, FormGroup } = ReactStrap;
2424

2525
const UNISYS = require('unisys/client');
2626
var UDATA = null;
@@ -46,7 +46,9 @@ class FiltersPanel extends UNISYS.Component {
4646
nodes: FDATA.nodes,
4747
edges: FDATA.edges,
4848
filterAction: FILTER.ACTION.HIGHLIGHT,
49-
filterActionHelp: FILTER.ACTION.HELP.HIGHLIGHT
49+
filterActionHelp: FILTER.ACTION.HELP.HIGHLIGHT,
50+
focusSourceLabel: undefined,
51+
focusRange: undefined
5052
};
5153
UDATA.OnAppStateChange("FDATA", this.UpdateFilterDefs);
5254
} // constructor
@@ -62,7 +64,9 @@ class FiltersPanel extends UNISYS.Component {
6264
nodes: data.nodes,
6365
edges: data.edges,
6466
filterAction: data.filterAction || state.filterAction,
65-
filterActionHelp: data.filterActionHelp || state.filterActionHelp
67+
filterActionHelp: data.filterActionHelp || state.filterActionHelp,
68+
focusSourceLabel: data.focus && data.focus.sourceLabel ? `"${data.focus.sourceLabel}"` : "<nothing selected>",
69+
focusRange: data.focus && data.focus.range ? data.focus.range : undefined
6670
}
6771
});
6872
}
@@ -76,18 +80,39 @@ class FiltersPanel extends UNISYS.Component {
7680
if (filterAction === FILTER.ACTION.HIGHLIGHT) filterActionHelp = FILTER.ACTION.HELP.HIGHLIGHT;
7781
if (filterAction === FILTER.ACTION.FILTER) filterActionHelp = FILTER.ACTION.HELP.FILTER;
7882
if (filterAction === FILTER.ACTION.COLLAPSE) filterActionHelp = FILTER.ACTION.HELP.COLLAPSE;
83+
if (filterAction === FILTER.ACTION.FOCUS) filterActionHelp = FILTER.ACTION.HELP.FOCUS;
7984
this.setState({ filterAction, filterActionHelp });
8085
UDATA.LocalCall('FILTERS_UPDATE', { filterAction });
8186
}
8287

8388
render() {
84-
const { filterAction, filterActionHelp } = this.state;
89+
const { filterAction, filterActionHelp, focusRange, focusSourceLabel } = this.state;
8590
const defs = [this.state.nodes, this.state.edges];
91+
92+
let FilterControlPanel;
93+
if (filterAction === FILTER.ACTION.FOCUS) {
94+
FilterControlPanel = <FocusFilter
95+
filter={{ value: 0 }}
96+
focusSourceLabel={focusSourceLabel}
97+
focusRange={focusRange}
98+
/>;
99+
} else {
100+
FilterControlPanel = defs.map(def => <FilterGroup
101+
key={def.label}
102+
group={def.group}
103+
label={def.label}
104+
filters={def.filters}
105+
filterAction={filterAction}
106+
transparency={def.transparency}
107+
onFiltersChange={this.OnFilterChange}
108+
/>);
109+
}
110+
86111
return (
87112
<div className="filterPanel"
88113
style={{
89-
overflow: 'auto',
90-
marginTop: '6px', padding: '5px',
114+
overflow: 'hidden',
115+
margin: '6px 0', padding: '5px',
91116
display: 'flex', flexDirection: 'column',
92117
backgroundColor: '#EEE',
93118
zIndex: '2000'
@@ -102,7 +127,7 @@ class FiltersPanel extends UNISYS.Component {
102127
color: filterAction === FILTER.ACTION.HIGHLIGHT ? '#333' : '#fff',
103128
backgroundColor: filterAction === FILTER.ACTION.HIGHLIGHT ? 'transparent' : '#6c757d88'
104129
}}
105-
>Highlight</Button>
130+
>{FILTER.ACTION.HIGHLIGHT}</Button>
106131
{/* Hide "Filter" panel. We will probably remove this functionality.
107132
<Button
108133
onClick={() => this.SelectFilterAction(FILTER.ACTION.FILTER)}
@@ -123,24 +148,30 @@ class FiltersPanel extends UNISYS.Component {
123148
color: filterAction === FILTER.ACTION.COLLAPSE ? '#333' : '#fff',
124149
backgroundColor: filterAction === FILTER.ACTION.COLLAPSE ? 'transparent' : '#6c757d88'
125150
}}
126-
>Collapse</Button>
151+
>{FILTER.ACTION.COLLAPSE}</Button>
152+
<Button
153+
onClick={() => this.SelectFilterAction(FILTER.ACTION.FOCUS)}
154+
active={filterAction === FILTER.ACTION.FOCUS}
155+
outline={filterAction === FILTER.ACTION.FOCUS}
156+
disabled={filterAction === FILTER.ACTION.FOCUS}
157+
style={{
158+
color: filterAction === FILTER.ACTION.FOCUS ? '#333' : '#fff',
159+
backgroundColor: filterAction === FILTER.ACTION.FOCUS ? 'transparent' : '#6c757d88'
160+
}}
161+
>{FILTER.ACTION.FOCUS}</Button>
127162
</ButtonGroup>
128163
<Label className="small text-muted" style={{ padding: '0.5em 0 0 0.5em', marginBottom: '0' }}>
129164
{filterActionHelp}
130165
</Label>
131-
<hr/>
132-
<div style={{ display: 'flex', flexDirection: 'column', flexGrow: `1`, justifyContent: 'space-evenly' }}>
133-
{defs.map(def => <FilterGroup
134-
key={def.label}
135-
group={def.group}
136-
label={def.label}
137-
filters={def.filters}
138-
filterAction={filterAction}
139-
transparency={def.transparency}
140-
onFiltersChange={this.OnFilterChange}
141-
/>)}
166+
<div style={{
167+
display: 'flex', flexDirection: 'column', flexGrow: `1`,
168+
overflowY: 'scroll'
169+
}}>
170+
<div>
171+
{FilterControlPanel}
172+
</div>
142173
</div>
143-
<div style={{ display: 'flex', justifyContent: 'space-evenly', padding: '10px' }}>
174+
<div style={{ display: 'flex', justifyContent: 'space-evenly', padding: '5px' }}>
144175
<Button size="sm" onClick={this.OnClearBtnClick} >Clear Filters</Button>
145176
</div>
146177
</div>

0 commit comments

Comments
 (0)