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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        scope.isFullscreen = false;
 | 
			
		||||
 | 
			
		||||
        scope.formProps = {
 | 
			
		||||
            isFullscreen: false,
 | 
			
		||||
            option: {
 | 
			
		||||
                formDefaults: {
 | 
			
		||||
                    startEmpty: true
 | 
			
		||||
@ -86,6 +89,10 @@ function JsonForm($compile, $templateCache, $mdColorPicker) {
 | 
			
		||||
            },
 | 
			
		||||
            onColorClick: function(event, key, 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(){
 | 
			
		||||
            if (scope.schema && scope.model) {
 | 
			
		||||
                var result = utils.validateBySchema(scope.schema, scope.model);
 | 
			
		||||
 | 
			
		||||
@ -15,4 +15,6 @@
 | 
			
		||||
    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: {
 | 
			
		||||
            loadNodes: '=',
 | 
			
		||||
            editCallbacks: '=',
 | 
			
		||||
            enableSearch: '@?',
 | 
			
		||||
            onNodeSelected: '&',
 | 
			
		||||
            onNodesInserted: '&'
 | 
			
		||||
            onNodesInserted: '&',
 | 
			
		||||
            searchCallback: '&?'
 | 
			
		||||
        },
 | 
			
		||||
        controller: NavTreeController,
 | 
			
		||||
        controllerAs: 'vm',
 | 
			
		||||
@ -55,17 +57,30 @@ function NavTreeController($scope, $element, types) {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
            .jstree(
 | 
			
		||||
                {
 | 
			
		||||
                    core: {
 | 
			
		||||
                        multiple: false,
 | 
			
		||||
                        check_callback: true,
 | 
			
		||||
                        themes: { name: 'proton', responsive: true },
 | 
			
		||||
                        data: vm.loadNodes
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
            .jstree(config);
 | 
			
		||||
 | 
			
		||||
        vm.treeElement.on("changed.jstree", function (e, data) {
 | 
			
		||||
            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.onTidy = this.onTidy.bind(this);
 | 
			
		||||
        this.onLoad = this.onLoad.bind(this);
 | 
			
		||||
        this.onToggleFull = this.onToggleFull.bind(this);
 | 
			
		||||
        var value = props.value ? props.value + '' : '';
 | 
			
		||||
        this.state = {
 | 
			
		||||
            isFull: false,
 | 
			
		||||
            value: value,
 | 
			
		||||
            focused: false
 | 
			
		||||
        };
 | 
			
		||||
@ -76,9 +78,26 @@ class ThingsboardAceEditor extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onLoad(editor) {
 | 
			
		||||
        this.aceEditor = 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() {
 | 
			
		||||
 | 
			
		||||
        const styles = reactCSS({
 | 
			
		||||
@ -108,18 +127,23 @@ class ThingsboardAceEditor extends React.Component {
 | 
			
		||||
        if (this.state.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 (
 | 
			
		||||
            <div className="tb-container">
 | 
			
		||||
            <div className={containerClass}>
 | 
			
		||||
                <label className={labelClass}>{this.props.form.title}</label>
 | 
			
		||||
                <div className="json-form-ace-editor">
 | 
			
		||||
                    <div className="title-panel">
 | 
			
		||||
                        <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={this.state.isFull ? 'Exit fullscreen' : 'Fullscreen'} onTouchTap={this.onToggleFull}/>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <AceEditor mode={this.props.mode}
 | 
			
		||||
                               height="150px"
 | 
			
		||||
                               width="300px"
 | 
			
		||||
                               height={this.state.isFull ? "100%" : "150px"}
 | 
			
		||||
                               width={this.state.isFull ? "100%" : "300px"}
 | 
			
		||||
                               theme="github"
 | 
			
		||||
                               onChange={this.onValueChanged}
 | 
			
		||||
                               onFocus={this.onFocus}
 | 
			
		||||
@ -132,10 +156,10 @@ class ThingsboardAceEditor extends React.Component {
 | 
			
		||||
                               enableBasicAutocompletion={true}
 | 
			
		||||
                               enableSnippets={true}
 | 
			
		||||
                               enableLiveAutocompletion={true}
 | 
			
		||||
                               style={this.props.form.style || {width: '100%'}}/>
 | 
			
		||||
                               style={style}/>
 | 
			
		||||
                </div>
 | 
			
		||||
                <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>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,13 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.fullscreen-form-field {
 | 
			
		||||
  .json-form-ace-editor {
 | 
			
		||||
    height: calc(100% - 60px);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.json-form-ace-editor {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ class ThingsboardArray extends React.Component {
 | 
			
		||||
            }
 | 
			
		||||
            let forms = this.props.form.items.map(function(form, index){
 | 
			
		||||
                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));
 | 
			
		||||
            arrays.push(
 | 
			
		||||
            <li key={keys[i]} className="list-group-item">
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ class ThingsboardFieldSet extends React.Component {
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,8 @@ ReactSchemaForm.propTypes = {
 | 
			
		||||
        model: React.PropTypes.object,
 | 
			
		||||
        option: React.PropTypes.object,
 | 
			
		||||
        onModelChange: React.PropTypes.func,
 | 
			
		||||
        onColorClick: React.PropTypes.func
 | 
			
		||||
        onColorClick: React.PropTypes.func,
 | 
			
		||||
        onToggleFullscreen: React.PropTypes.func
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ReactSchemaForm.defaultProps = {
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,7 @@ class ThingsboardSchemaForm extends React.Component {
 | 
			
		||||
 | 
			
		||||
        this.onChange = this.onChange.bind(this);
 | 
			
		||||
        this.onColorClick = this.onColorClick.bind(this);
 | 
			
		||||
        this.onToggleFullscreen = this.onToggleFullscreen.bind(this);
 | 
			
		||||
        this.hasConditions = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -78,7 +79,11 @@ class ThingsboardSchemaForm extends React.Component {
 | 
			
		||||
        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;
 | 
			
		||||
        let Field = this.mapper[type];
 | 
			
		||||
        if(!Field) {
 | 
			
		||||
@ -91,7 +96,7 @@ class ThingsboardSchemaForm extends React.Component {
 | 
			
		||||
                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() {
 | 
			
		||||
@ -101,11 +106,16 @@ class ThingsboardSchemaForm extends React.Component {
 | 
			
		||||
            mapper = _.merge(this.mapper, this.props.mapper);
 | 
			
		||||
        }
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
        let formClass = 'SchemaForm';
 | 
			
		||||
        if (this.props.isFullscreen) {
 | 
			
		||||
            formClass += ' SchemaFormFullscreen';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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-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 {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  bottom: -5px;
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,25 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
    vm.nodesMap = {};
 | 
			
		||||
    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() {
 | 
			
		||||
        if (vm.ctx && vm.ctx.defaultSubscription) {
 | 
			
		||||
            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) {
 | 
			
		||||
        if (vm.hierarchyId == hierarchyId) {
 | 
			
		||||
            if (vm.subscription) {
 | 
			
		||||
@ -73,12 +98,10 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    vm.onNodesInserted = onNodesInserted;
 | 
			
		||||
 | 
			
		||||
    vm.onNodeSelected = onNodeSelected;
 | 
			
		||||
 | 
			
		||||
    function initializeConfig() {
 | 
			
		||||
 | 
			
		||||
        vm.ctx.widgetActions = [ vm.searchAction ];
 | 
			
		||||
 | 
			
		||||
        var testNodeCtx = {
 | 
			
		||||
            entity: {
 | 
			
		||||
                id: {
 | 
			
		||||
@ -98,6 +121,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
        var nodeIconFunction = loadNodeCtxFunction(vm.settings.nodeIconFunction, 'nodeCtx', testNodeCtx);
 | 
			
		||||
        var nodeTextFunction = loadNodeCtxFunction(vm.settings.nodeTextFunction, '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 testNodeCtx2 = angular.copy(testNodeCtx);
 | 
			
		||||
@ -109,6 +133,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
        vm.nodeIconFunction = nodeIconFunction || defaultNodeIconFunction;
 | 
			
		||||
        vm.nodeTextFunction = nodeTextFunction || ((nodeCtx) => nodeCtx.entity.name);
 | 
			
		||||
        vm.nodeDisabledFunction = nodeDisabledFunction || (() => false);
 | 
			
		||||
        vm.nodeOpenedFunction = nodeOpenedFunction || defaultNodeOpenedFunction;
 | 
			
		||||
        vm.nodeHasChildrenFunction = nodeHasChildrenFunction || (() => true);
 | 
			
		||||
        vm.nodesSortFunction = nodesSortFunction || defaultSortFunction;
 | 
			
		||||
    }
 | 
			
		||||
@ -129,10 +154,40 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
        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() {
 | 
			
		||||
        vm.loadNodes = loadNodes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function updateSearchNodes() {
 | 
			
		||||
        if (vm.query.search != null) {
 | 
			
		||||
            vm.nodeEditCallbacks.search(vm.query.search);
 | 
			
		||||
        } else {
 | 
			
		||||
            vm.nodeEditCallbacks.clearSearch();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onNodesInserted(nodes/*, parent*/) {
 | 
			
		||||
        if (nodes) {
 | 
			
		||||
            nodes.forEach((nodeId) => {
 | 
			
		||||
@ -222,6 +277,7 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
    function prepareNodeText(node) {
 | 
			
		||||
        var nodeIcon = prepareNodeIcon(node.data.nodeCtx);
 | 
			
		||||
        var nodeText = vm.nodeTextFunction(node.data.nodeCtx);
 | 
			
		||||
        node.data.searchText = nodeText ? nodeText.replace(/<[^>]+>/g, '').toLowerCase() : "";
 | 
			
		||||
        return nodeIcon + nodeText;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -298,7 +354,8 @@ function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast
 | 
			
		||||
                        nodeCtx: nodeCtx
 | 
			
		||||
                    };
 | 
			
		||||
                    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.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) {
 | 
			
		||||
        var result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);
 | 
			
		||||
        if (result === 0) {
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,21 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.tb-has-timewindow {
 | 
			
		||||
  .tb-entities-hierarchy {
 | 
			
		||||
    md-toolbar {
 | 
			
		||||
      min-height: 60px;
 | 
			
		||||
      max-height: 60px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tb-entities-hierarchy {
 | 
			
		||||
  md-toolbar {
 | 
			
		||||
    min-height: 39px;
 | 
			
		||||
    max-height: 39px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tb-entities-nav-tree-panel {
 | 
			
		||||
    overflow-x: auto;
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
 | 
			
		||||
@ -17,12 +17,34 @@
 | 
			
		||||
-->
 | 
			
		||||
<div class="tb-absolute-fill tb-entities-hierarchy" 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">
 | 
			
		||||
            <tb-nav-tree
 | 
			
		||||
                    load-nodes="vm.loadNodes"
 | 
			
		||||
                    on-node-selected="vm.onNodeSelected(node, event)"
 | 
			
		||||
                    on-nodes-inserted="vm.onNodesInserted(nodes, parent)"
 | 
			
		||||
                    edit-callbacks="vm.nodeEditCallbacks"
 | 
			
		||||
                    enable-search="true"
 | 
			
		||||
                    search-callback="vm.searchCallback(searchText, node)"
 | 
			
		||||
            ></tb-nav-tree>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user