Add search to Entities Hierarchy widget. Improve widget advanced forms: add fullscreen button for area fields.
This commit is contained in:
parent
0d933cf065
commit
f671d81ce4
File diff suppressed because one or more lines are too long
@ -71,7 +71,10 @@ function JsonForm($compile, $templateCache, $mdColorPicker) {
|
|||||||
$compile(element.contents())(childScope);
|
$compile(element.contents())(childScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.isFullscreen = false;
|
||||||
|
|
||||||
scope.formProps = {
|
scope.formProps = {
|
||||||
|
isFullscreen: false,
|
||||||
option: {
|
option: {
|
||||||
formDefaults: {
|
formDefaults: {
|
||||||
startEmpty: true
|
startEmpty: true
|
||||||
@ -86,6 +89,10 @@ function JsonForm($compile, $templateCache, $mdColorPicker) {
|
|||||||
},
|
},
|
||||||
onColorClick: function(event, key, val) {
|
onColorClick: function(event, key, val) {
|
||||||
scope.showColorPicker(event, val);
|
scope.showColorPicker(event, val);
|
||||||
|
},
|
||||||
|
onToggleFullscreen: function() {
|
||||||
|
scope.isFullscreen = !scope.isFullscreen;
|
||||||
|
scope.formProps.isFullscreen = scope.isFullscreen;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,6 +123,8 @@ function JsonForm($compile, $templateCache, $mdColorPicker) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.onFullscreenChanged = function() {}
|
||||||
|
|
||||||
scope.validate = function(){
|
scope.validate = function(){
|
||||||
if (scope.schema && scope.model) {
|
if (scope.schema && scope.model) {
|
||||||
var result = utils.validateBySchema(scope.schema, scope.model);
|
var result = utils.validateBySchema(scope.schema, scope.model);
|
||||||
|
|||||||
@ -15,4 +15,6 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<react-component name="ReactSchemaForm" props="formProps" watch-depth="value"></react-component>
|
<div style="background: #fff;" tb-expand-fullscreen="isFullscreen" hide-expand-button="true" fullscreen-zindex="100" on-fullscreen-changed="onFullscreenChanged()">
|
||||||
|
<react-component name="ReactSchemaForm" props="formProps" watch-depth="value"></react-component>
|
||||||
|
</div>
|
||||||
|
|||||||
@ -33,8 +33,10 @@ function NavTree() {
|
|||||||
bindToController: {
|
bindToController: {
|
||||||
loadNodes: '=',
|
loadNodes: '=',
|
||||||
editCallbacks: '=',
|
editCallbacks: '=',
|
||||||
|
enableSearch: '@?',
|
||||||
onNodeSelected: '&',
|
onNodeSelected: '&',
|
||||||
onNodesInserted: '&'
|
onNodesInserted: '&',
|
||||||
|
searchCallback: '&?'
|
||||||
},
|
},
|
||||||
controller: NavTreeController,
|
controller: NavTreeController,
|
||||||
controllerAs: 'vm',
|
controllerAs: 'vm',
|
||||||
@ -55,17 +57,30 @@ function NavTreeController($scope, $element, types) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function initTree() {
|
function initTree() {
|
||||||
|
var config = {
|
||||||
|
core: {
|
||||||
|
multiple: false,
|
||||||
|
check_callback: true,
|
||||||
|
themes: { name: 'proton', responsive: true },
|
||||||
|
data: vm.loadNodes
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vm.enableSearch) {
|
||||||
|
config.plugins = ["search"];
|
||||||
|
config.search = {
|
||||||
|
case_sensitive: false,
|
||||||
|
show_only_matches: true,
|
||||||
|
show_only_matches_children: false,
|
||||||
|
search_leaves_only: false
|
||||||
|
};
|
||||||
|
if (vm.searchCallback) {
|
||||||
|
config.search.search_callback = (searchText, node) => vm.searchCallback({searchText: searchText, node: node});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vm.treeElement = angular.element('.tb-nav-tree-container', $element)
|
vm.treeElement = angular.element('.tb-nav-tree-container', $element)
|
||||||
.jstree(
|
.jstree(config);
|
||||||
{
|
|
||||||
core: {
|
|
||||||
multiple: false,
|
|
||||||
check_callback: true,
|
|
||||||
themes: { name: 'proton', responsive: true },
|
|
||||||
data: vm.loadNodes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
vm.treeElement.on("changed.jstree", function (e, data) {
|
vm.treeElement.on("changed.jstree", function (e, data) {
|
||||||
if (vm.onNodeSelected) {
|
if (vm.onNodeSelected) {
|
||||||
@ -180,6 +195,12 @@ function NavTreeController($scope, $element, types) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
vm.editCallbacks.search = (searchText) => {
|
||||||
|
vm.treeElement.jstree('search', searchText);
|
||||||
|
};
|
||||||
|
vm.editCallbacks.clearSearch = () => {
|
||||||
|
vm.treeElement.jstree('clear_search');
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,8 +34,10 @@ class ThingsboardAceEditor extends React.Component {
|
|||||||
this.onFocus = this.onFocus.bind(this);
|
this.onFocus = this.onFocus.bind(this);
|
||||||
this.onTidy = this.onTidy.bind(this);
|
this.onTidy = this.onTidy.bind(this);
|
||||||
this.onLoad = this.onLoad.bind(this);
|
this.onLoad = this.onLoad.bind(this);
|
||||||
|
this.onToggleFull = this.onToggleFull.bind(this);
|
||||||
var value = props.value ? props.value + '' : '';
|
var value = props.value ? props.value + '' : '';
|
||||||
this.state = {
|
this.state = {
|
||||||
|
isFull: false,
|
||||||
value: value,
|
value: value,
|
||||||
focused: false
|
focused: false
|
||||||
};
|
};
|
||||||
@ -76,9 +78,26 @@ class ThingsboardAceEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoad(editor) {
|
onLoad(editor) {
|
||||||
|
this.aceEditor = editor;
|
||||||
fixAceEditor(editor);
|
fixAceEditor(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onToggleFull() {
|
||||||
|
this.setState({ isFull: !this.state.isFull });
|
||||||
|
this.props.onToggleFullscreen();
|
||||||
|
this.updateAceEditorSize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
if (this.updateAceEditorSize) {
|
||||||
|
if (this.aceEditor) {
|
||||||
|
this.aceEditor.resize();
|
||||||
|
this.aceEditor.renderer.updateFull();
|
||||||
|
}
|
||||||
|
this.updateAceEditorSize = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const styles = reactCSS({
|
const styles = reactCSS({
|
||||||
@ -108,18 +127,23 @@ class ThingsboardAceEditor extends React.Component {
|
|||||||
if (this.state.focused) {
|
if (this.state.focused) {
|
||||||
labelClass += " tb-focused";
|
labelClass += " tb-focused";
|
||||||
}
|
}
|
||||||
|
var containerClass = "tb-container";
|
||||||
|
var style = this.props.form.style || {width: '100%'};
|
||||||
|
if (this.state.isFull) {
|
||||||
|
containerClass += " fullscreen-form-field";
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="tb-container">
|
<div className={containerClass}>
|
||||||
<label className={labelClass}>{this.props.form.title}</label>
|
<label className={labelClass}>{this.props.form.title}</label>
|
||||||
<div className="json-form-ace-editor">
|
<div className="json-form-ace-editor">
|
||||||
<div className="title-panel">
|
<div className="title-panel">
|
||||||
<label>{this.props.mode}</label>
|
<label>{this.props.mode}</label>
|
||||||
<FlatButton style={ styles.tidyButtonStyle } className="tidy-button" label={'Tidy'} onTouchTap={this.onTidy}/>
|
<FlatButton style={ styles.tidyButtonStyle } className="tidy-button" label={'Tidy'} onTouchTap={this.onTidy}/>
|
||||||
|
<FlatButton style={ styles.tidyButtonStyle } className="tidy-button" label={this.state.isFull ? 'Exit fullscreen' : 'Fullscreen'} onTouchTap={this.onToggleFull}/>
|
||||||
</div>
|
</div>
|
||||||
<AceEditor mode={this.props.mode}
|
<AceEditor mode={this.props.mode}
|
||||||
height="150px"
|
height={this.state.isFull ? "100%" : "150px"}
|
||||||
width="300px"
|
width={this.state.isFull ? "100%" : "300px"}
|
||||||
theme="github"
|
theme="github"
|
||||||
onChange={this.onValueChanged}
|
onChange={this.onValueChanged}
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
@ -132,10 +156,10 @@ class ThingsboardAceEditor extends React.Component {
|
|||||||
enableBasicAutocompletion={true}
|
enableBasicAutocompletion={true}
|
||||||
enableSnippets={true}
|
enableSnippets={true}
|
||||||
enableLiveAutocompletion={true}
|
enableLiveAutocompletion={true}
|
||||||
style={this.props.form.style || {width: '100%'}}/>
|
style={style}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="json-form-error"
|
<div className="json-form-error"
|
||||||
style={{opacity: this.props.valid ? '0' : '1'}}>{this.props.error}</div>
|
style={{opacity: this.props.valid ? '0' : '1'}}>{this.props.error}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.fullscreen-form-field {
|
||||||
|
.json-form-ace-editor {
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.json-form-ace-editor {
|
.json-form-ace-editor {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@ -131,7 +131,7 @@ class ThingsboardArray extends React.Component {
|
|||||||
}
|
}
|
||||||
let forms = this.props.form.items.map(function(form, index){
|
let forms = this.props.form.items.map(function(form, index){
|
||||||
var copy = this.copyWithIndex(form, i);
|
var copy = this.copyWithIndex(form, i);
|
||||||
return this.props.builder(copy, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.mapper, this.props.builder);
|
return this.props.builder(copy, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
arrays.push(
|
arrays.push(
|
||||||
<li key={keys[i]} className="list-group-item">
|
<li key={keys[i]} className="list-group-item">
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class ThingsboardFieldSet extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let forms = this.props.form.items.map(function(form, index){
|
let forms = this.props.form.items.map(function(form, index){
|
||||||
return this.props.builder(form, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.mapper, this.props.builder);
|
return this.props.builder(form, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -50,7 +50,8 @@ ReactSchemaForm.propTypes = {
|
|||||||
model: React.PropTypes.object,
|
model: React.PropTypes.object,
|
||||||
option: React.PropTypes.object,
|
option: React.PropTypes.object,
|
||||||
onModelChange: React.PropTypes.func,
|
onModelChange: React.PropTypes.func,
|
||||||
onColorClick: React.PropTypes.func
|
onColorClick: React.PropTypes.func,
|
||||||
|
onToggleFullscreen: React.PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactSchemaForm.defaultProps = {
|
ReactSchemaForm.defaultProps = {
|
||||||
|
|||||||
@ -63,6 +63,7 @@ class ThingsboardSchemaForm extends React.Component {
|
|||||||
|
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.onColorClick = this.onColorClick.bind(this);
|
this.onColorClick = this.onColorClick.bind(this);
|
||||||
|
this.onToggleFullscreen = this.onToggleFullscreen.bind(this);
|
||||||
this.hasConditions = false;
|
this.hasConditions = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +79,11 @@ class ThingsboardSchemaForm extends React.Component {
|
|||||||
this.props.onColorClick(event, key, val);
|
this.props.onColorClick(event, key, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder(form, model, index, onChange, onColorClick, mapper) {
|
onToggleFullscreen() {
|
||||||
|
this.props.onToggleFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder(form, model, index, onChange, onColorClick, onToggleFullscreen, mapper) {
|
||||||
var type = form.type;
|
var type = form.type;
|
||||||
let Field = this.mapper[type];
|
let Field = this.mapper[type];
|
||||||
if(!Field) {
|
if(!Field) {
|
||||||
@ -91,7 +96,7 @@ class ThingsboardSchemaForm extends React.Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <Field model={model} form={form} key={index} onChange={onChange} onColorClick={onColorClick} mapper={mapper} builder={this.builder}/>
|
return <Field model={model} form={form} key={index} onChange={onChange} onColorClick={onColorClick} onToggleFullscreen={onToggleFullscreen} mapper={mapper} builder={this.builder}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -101,11 +106,16 @@ class ThingsboardSchemaForm extends React.Component {
|
|||||||
mapper = _.merge(this.mapper, this.props.mapper);
|
mapper = _.merge(this.mapper, this.props.mapper);
|
||||||
}
|
}
|
||||||
let forms = merged.map(function(form, index) {
|
let forms = merged.map(function(form, index) {
|
||||||
return this.builder(form, this.props.model, index, this.onChange, this.onColorClick, mapper);
|
return this.builder(form, this.props.model, index, this.onChange, this.onColorClick, this.onToggleFullscreen, mapper);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
let formClass = 'SchemaForm';
|
||||||
|
if (this.props.isFullscreen) {
|
||||||
|
formClass += ' SchemaFormFullscreen';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{width: '100%'}} className='SchemaForm'>{forms}</div>
|
<div style={{width: '100%'}} className={formClass}>{forms}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,24 @@ $swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default;
|
|||||||
$input-label-float-offset: 6px !default;
|
$input-label-float-offset: 6px !default;
|
||||||
$input-label-float-scale: .75 !default;
|
$input-label-float-scale: .75 !default;
|
||||||
|
|
||||||
|
.SchemaForm {
|
||||||
|
&.SchemaFormFullscreen {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> div:not(.fullscreen-form-field) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div.fullscreen-form-field {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.json-form-error {
|
.json-form-error {
|
||||||
position: relative;
|
position: relative;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
|
|||||||
@ -54,6 +54,25 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
vm.nodesMap = {};
|
vm.nodesMap = {};
|
||||||
vm.pendingUpdateNodeTasks = {};
|
vm.pendingUpdateNodeTasks = {};
|
||||||
|
|
||||||
|
vm.query = {
|
||||||
|
search: null
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.searchAction = {
|
||||||
|
name: 'action.search',
|
||||||
|
show: true,
|
||||||
|
onAction: function() {
|
||||||
|
vm.enterFilterMode();
|
||||||
|
},
|
||||||
|
icon: 'search'
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.onNodesInserted = onNodesInserted;
|
||||||
|
vm.onNodeSelected = onNodeSelected;
|
||||||
|
vm.enterFilterMode = enterFilterMode;
|
||||||
|
vm.exitFilterMode = exitFilterMode;
|
||||||
|
vm.searchCallback = searchCallback;
|
||||||
|
|
||||||
$scope.$watch('vm.ctx', function() {
|
$scope.$watch('vm.ctx', function() {
|
||||||
if (vm.ctx && vm.ctx.defaultSubscription) {
|
if (vm.ctx && vm.ctx.defaultSubscription) {
|
||||||
vm.settings = vm.ctx.settings;
|
vm.settings = vm.ctx.settings;
|
||||||
@ -65,6 +84,12 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.$watch("vm.query.search", function(newVal, prevVal) {
|
||||||
|
if (!angular.equals(newVal, prevVal) && vm.query.search != null) {
|
||||||
|
updateSearchNodes();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$scope.$on('entities-hierarchy-data-updated', function(event, hierarchyId) {
|
$scope.$on('entities-hierarchy-data-updated', function(event, hierarchyId) {
|
||||||
if (vm.hierarchyId == hierarchyId) {
|
if (vm.hierarchyId == hierarchyId) {
|
||||||
if (vm.subscription) {
|
if (vm.subscription) {
|
||||||
@ -73,12 +98,10 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.onNodesInserted = onNodesInserted;
|
|
||||||
|
|
||||||
vm.onNodeSelected = onNodeSelected;
|
|
||||||
|
|
||||||
function initializeConfig() {
|
function initializeConfig() {
|
||||||
|
|
||||||
|
vm.ctx.widgetActions = [ vm.searchAction ];
|
||||||
|
|
||||||
var testNodeCtx = {
|
var testNodeCtx = {
|
||||||
entity: {
|
entity: {
|
||||||
id: {
|
id: {
|
||||||
@ -98,6 +121,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
var nodeIconFunction = loadNodeCtxFunction(vm.settings.nodeIconFunction, 'nodeCtx', testNodeCtx);
|
var nodeIconFunction = loadNodeCtxFunction(vm.settings.nodeIconFunction, 'nodeCtx', testNodeCtx);
|
||||||
var nodeTextFunction = loadNodeCtxFunction(vm.settings.nodeTextFunction, 'nodeCtx', testNodeCtx);
|
var nodeTextFunction = loadNodeCtxFunction(vm.settings.nodeTextFunction, 'nodeCtx', testNodeCtx);
|
||||||
var nodeDisabledFunction = loadNodeCtxFunction(vm.settings.nodeDisabledFunction, 'nodeCtx', testNodeCtx);
|
var nodeDisabledFunction = loadNodeCtxFunction(vm.settings.nodeDisabledFunction, 'nodeCtx', testNodeCtx);
|
||||||
|
var nodeOpenedFunction = loadNodeCtxFunction(vm.settings.nodeOpenedFunction, 'nodeCtx', testNodeCtx);
|
||||||
var nodeHasChildrenFunction = loadNodeCtxFunction(vm.settings.nodeHasChildrenFunction, 'nodeCtx', testNodeCtx);
|
var nodeHasChildrenFunction = loadNodeCtxFunction(vm.settings.nodeHasChildrenFunction, 'nodeCtx', testNodeCtx);
|
||||||
|
|
||||||
var testNodeCtx2 = angular.copy(testNodeCtx);
|
var testNodeCtx2 = angular.copy(testNodeCtx);
|
||||||
@ -109,6 +133,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
vm.nodeIconFunction = nodeIconFunction || defaultNodeIconFunction;
|
vm.nodeIconFunction = nodeIconFunction || defaultNodeIconFunction;
|
||||||
vm.nodeTextFunction = nodeTextFunction || ((nodeCtx) => nodeCtx.entity.name);
|
vm.nodeTextFunction = nodeTextFunction || ((nodeCtx) => nodeCtx.entity.name);
|
||||||
vm.nodeDisabledFunction = nodeDisabledFunction || (() => false);
|
vm.nodeDisabledFunction = nodeDisabledFunction || (() => false);
|
||||||
|
vm.nodeOpenedFunction = nodeOpenedFunction || defaultNodeOpenedFunction;
|
||||||
vm.nodeHasChildrenFunction = nodeHasChildrenFunction || (() => true);
|
vm.nodeHasChildrenFunction = nodeHasChildrenFunction || (() => true);
|
||||||
vm.nodesSortFunction = nodesSortFunction || defaultSortFunction;
|
vm.nodesSortFunction = nodesSortFunction || defaultSortFunction;
|
||||||
}
|
}
|
||||||
@ -129,10 +154,40 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
return nodeCtxFunction;
|
return nodeCtxFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enterFilterMode () {
|
||||||
|
vm.query.search = '';
|
||||||
|
vm.ctx.hideTitlePanel = true;
|
||||||
|
$timeout(()=>{
|
||||||
|
angular.element(vm.ctx.$container).find('.searchInput').focus();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitFilterMode () {
|
||||||
|
vm.query.search = null;
|
||||||
|
updateSearchNodes();
|
||||||
|
vm.ctx.hideTitlePanel = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchCallback (searchText, node) {
|
||||||
|
var theNode = vm.nodesMap[node.id];
|
||||||
|
if (theNode && theNode.data.searchText) {
|
||||||
|
return theNode.data.searchText.includes(searchText.toLowerCase());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function updateDatasources() {
|
function updateDatasources() {
|
||||||
vm.loadNodes = loadNodes;
|
vm.loadNodes = loadNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSearchNodes() {
|
||||||
|
if (vm.query.search != null) {
|
||||||
|
vm.nodeEditCallbacks.search(vm.query.search);
|
||||||
|
} else {
|
||||||
|
vm.nodeEditCallbacks.clearSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onNodesInserted(nodes/*, parent*/) {
|
function onNodesInserted(nodes/*, parent*/) {
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
nodes.forEach((nodeId) => {
|
nodes.forEach((nodeId) => {
|
||||||
@ -222,6 +277,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
function prepareNodeText(node) {
|
function prepareNodeText(node) {
|
||||||
var nodeIcon = prepareNodeIcon(node.data.nodeCtx);
|
var nodeIcon = prepareNodeIcon(node.data.nodeCtx);
|
||||||
var nodeText = vm.nodeTextFunction(node.data.nodeCtx);
|
var nodeText = vm.nodeTextFunction(node.data.nodeCtx);
|
||||||
|
node.data.searchText = nodeText ? nodeText.replace(/<[^>]+>/g, '').toLowerCase() : "";
|
||||||
return nodeIcon + nodeText;
|
return nodeIcon + nodeText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +354,8 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
nodeCtx: nodeCtx
|
nodeCtx: nodeCtx
|
||||||
};
|
};
|
||||||
node.state = {
|
node.state = {
|
||||||
disabled: vm.nodeDisabledFunction(node.data.nodeCtx)
|
disabled: vm.nodeDisabledFunction(node.data.nodeCtx),
|
||||||
|
opened: vm.nodeOpenedFunction(node.data.nodeCtx)
|
||||||
};
|
};
|
||||||
node.text = prepareNodeText(node);
|
node.text = prepareNodeText(node);
|
||||||
node.children = vm.nodeHasChildrenFunction(node.data.nodeCtx);
|
node.children = vm.nodeHasChildrenFunction(node.data.nodeCtx);
|
||||||
@ -459,6 +516,10 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function defaultNodeOpenedFunction(nodeCtx) {
|
||||||
|
return nodeCtx.level <= 4;
|
||||||
|
}
|
||||||
|
|
||||||
function defaultSortFunction(nodeCtx1, nodeCtx2) {
|
function defaultSortFunction(nodeCtx1, nodeCtx2) {
|
||||||
var result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);
|
var result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);
|
||||||
if (result === 0) {
|
if (result === 0) {
|
||||||
|
|||||||
@ -14,7 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.tb-has-timewindow {
|
||||||
|
.tb-entities-hierarchy {
|
||||||
|
md-toolbar {
|
||||||
|
min-height: 60px;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tb-entities-hierarchy {
|
.tb-entities-hierarchy {
|
||||||
|
md-toolbar {
|
||||||
|
min-height: 39px;
|
||||||
|
max-height: 39px;
|
||||||
|
}
|
||||||
|
|
||||||
.tb-entities-nav-tree-panel {
|
.tb-entities-nav-tree-panel {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@ -17,12 +17,34 @@
|
|||||||
-->
|
-->
|
||||||
<div class="tb-absolute-fill tb-entities-hierarchy" layout="column">
|
<div class="tb-absolute-fill tb-entities-hierarchy" layout="column">
|
||||||
<div ng-show="vm.showData" flex class="tb-absolute-fill" layout="column">
|
<div ng-show="vm.showData" flex class="tb-absolute-fill" layout="column">
|
||||||
|
<md-toolbar class="md-table-toolbar md-default" ng-show="vm.query.search != null">
|
||||||
|
<div class="md-toolbar-tools">
|
||||||
|
<md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}">
|
||||||
|
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon>
|
||||||
|
<md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}">
|
||||||
|
{{'entity.search' | translate}}
|
||||||
|
</md-tooltip>
|
||||||
|
</md-button>
|
||||||
|
<md-input-container flex>
|
||||||
|
<label> </label>
|
||||||
|
<input ng-model="vm.query.search" class="searchInput" placeholder="{{'entity.search' | translate}}"/>
|
||||||
|
</md-input-container>
|
||||||
|
<md-button class="md-icon-button" aria-label="Close" ng-click="vm.exitFilterMode()">
|
||||||
|
<md-icon aria-label="Close" class="material-icons">close</md-icon>
|
||||||
|
<md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}">
|
||||||
|
{{ 'action.close' | translate }}
|
||||||
|
</md-tooltip>
|
||||||
|
</md-button>
|
||||||
|
</div>
|
||||||
|
</md-toolbar>
|
||||||
<div flex class="tb-entities-nav-tree-panel">
|
<div flex class="tb-entities-nav-tree-panel">
|
||||||
<tb-nav-tree
|
<tb-nav-tree
|
||||||
load-nodes="vm.loadNodes"
|
load-nodes="vm.loadNodes"
|
||||||
on-node-selected="vm.onNodeSelected(node, event)"
|
on-node-selected="vm.onNodeSelected(node, event)"
|
||||||
on-nodes-inserted="vm.onNodesInserted(nodes, parent)"
|
on-nodes-inserted="vm.onNodesInserted(nodes, parent)"
|
||||||
edit-callbacks="vm.nodeEditCallbacks"
|
edit-callbacks="vm.nodeEditCallbacks"
|
||||||
|
enable-search="true"
|
||||||
|
search-callback="vm.searchCallback(searchText, node)"
|
||||||
></tb-nav-tree>
|
></tb-nav-tree>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user