public async render()

in src/UXClient/Components/HierarchyNavigation/HierarchyNavigation.ts [90:331]


    public async render(environmentFqdn: string, getToken: any, hierarchyNavOptions: any = {}){
        let self = this;
        this.chartOptions.setOptions(hierarchyNavOptions);
        this.getToken = getToken;
        this.environmentFqdn = environmentFqdn;
        this.resettingVariablesForEnvChange();

        let targetElement = d3.select(this.renderTarget);   
        targetElement.text(''); 
        let hierarchyNavWrapper = targetElement.append('div').attr('class', 'tsi-hierarchy-nav-wrapper');
        super.themify(hierarchyNavWrapper, this.chartOptions.theme);

        //get the most recent types to show in the context menu on instance click
        await getToken().then(token => {
            return this.server.getTimeseriesTypes(token, environmentFqdn).then((r:any) => {
                try {
                    if (r.error) {
                        throw r.error;
                    } else {
                        r.types.forEach(t => {
                            this.envTypes[t.id] = t;
                        });
                    }
                } catch (err) {
                    throw err;
                }
            }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to load types for navigation", err instanceof XMLHttpRequest ? err : null));
        }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to get token", err instanceof XMLHttpRequest ? err : null));

        //get the most recent hierarchies for reverse lookup
        await getToken().then(token => {
            return this.server.getTimeseriesHierarchies(token, environmentFqdn).then((r:any) => {
                try {
                    if (r.error) {
                        throw r.error;
                    } else {
                        r.hierarchies.forEach(h => {
                            this.envHierarchies[h.name] = h;
                        });
                    }
                } catch (err) {
                    throw err;
                }
            }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to load hierarchies for navigation", err instanceof XMLHttpRequest ? err : null));
        }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to get token", err instanceof XMLHttpRequest ? err : null));

        const selectedHierarchyId = hierarchyNavOptions.selectedHierarchyId;
        if (selectedHierarchyId) {
            if (selectedHierarchyId === HierarchySelectionValues.All || selectedHierarchyId === HierarchySelectionValues.Unparented) {
                this.selectedHierarchyName = selectedHierarchyId; //Using enum values of All and Unparented as both name and id
                this.path = [];
            } else {
                let hierarchy = Object.values(this.envHierarchies).find(h => h["id"] === selectedHierarchyId);
                if (hierarchy) {
                    this.selectedHierarchyName = hierarchy["name"];
                    this.path =  [this.selectedHierarchyName];
                }
            }
        }
        
        getToken().then(token => {
            self.server.getTimeseriesInstancesPathSearch(token, environmentFqdn, {searchString: '', path: this.path, hierarchies: {sort: {by: HierarchiesSort.CumulativeInstanceCount}, expand: {kind: HierarchiesExpand.OneLevel}, pageSize: 100}}).then((r:any) => {
                try {
                    if (r.error) {
                        throw r.error;
                    } else {
                        // hierarchy selection button
                        let hierarchySelectionWrapper = hierarchyNavWrapper.append('div').classed('tsi-hierarchy-selection-wrapper', true);
                        this.hierarchySelectorElem = hierarchySelectionWrapper.append('button').classed('tsi-hierarchy-select', true)
                            .attr("aria-haspopup", "listbox")
                            .on('click keydown', () => {
                                if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                if (this.isHierarchySelectionActive) {
                                    this.hierarchyListWrapperElem.style('display', 'none');
                                    this.isHierarchySelectionActive = false;
                                }
                                else {
                                    this.renderHierarchySelection();
                                    this.isHierarchySelectionActive = true;
                                }
                            });
                        this.hierarchySelectorElem.append('span').classed('tsi-hierarchy-name', true).text(this.selectedHierarchyName === HierarchySelectionValues.All ? this.getString("All hierarchies") 
                                                                                                            : this.selectedHierarchyName === HierarchySelectionValues.Unparented ? this.getString("Unassigned Time Series Instances") 
                                                                                                            : this.selectedHierarchyName);
                        this.hierarchySelectorElem.append('i').classed('tsi-down-caret-icon', true);
                        // hierarchy flyout list
                        this.hierarchyListWrapperElem = hierarchySelectionWrapper.append('div').classed('tsi-hierarchy-list-wrapper', true);
                        this.hierarchyListElem = this.hierarchyListWrapperElem.append('ul').classed('tsi-hierarchy-list', true).attr('role','listbox').attr("id", "tsi-hierarchy-listbox");
                        
                        // search
                        this.searchWrapperElem = hierarchyNavWrapper.append('div').classed('tsi-hierarchy-search', true);
                        let modelAutocomplete = new ModelAutocomplete(this.searchWrapperElem.node() as Element);
                        modelAutocomplete.render(
                            environmentFqdn, 
                            getToken, 
                            {
                                onInput: autocompleteOnInput, 
                                onKeydown: (event, ap) => {handleKeydown(event, ap)}, 
                                theme: hierarchyNavOptions.theme, 
                                strings: this.chartOptions.strings
                            });
                        this.viewTypesElem = this.searchWrapperElem.append('div').classed('tsi-view-types', true).attr("role", "tablist");
                        this.viewTypesElem.append('div').classed('tsi-view-type', true)
                                                .attr('title', 'Hierarchy View')
                                                .attr('tabindex', 0)
                                                .attr('arialabel', 'Hierarchy View')
                                                .attr('role', 'tab')
                                                .on('click keydown', function () {
                                                    if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                                    self.switchToSearchView(ViewType.Hierarchy);
                                                })
                                                .append('i').classed('tsi-tree-icon', true)
                                                    
                        this.viewTypesElem.append('div').classed('tsi-view-type selected', true)
                                                .attr('title', 'List View')
                                                .attr('tabindex', 0)
                                                .attr('arialabel', 'List View')
                                                .attr('role', 'tab')
                                                .attr('aria-selected', true)
                                                .on('click keydown', function () {
                                                    if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                                    self.switchToSearchView(ViewType.List);
                                                })
                                                .append('i').classed('tsi-list-icon', true)

                        // filter path
                        this.filterPathElem = hierarchyNavWrapper.append('div').classed('tsi-filter-path-wrapper', true);
                        let filterPath = this.filterPathElem.append('div').classed('tsi-filter-path', true)
                        filterPath.append('span').classed('tsi-path-list', true);
                        filterPath.append('i').classed('tsi-close-icon tsi-filter-clear', true)
                            .attr('tabindex', 0)
                            .attr('arialabel', 'Clear Path Filter')
                            .attr('title', 'Clear Path Filter')
                            .on('click keydown', function () {
                                if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                self.path = (self.selectedHierarchyName === HierarchySelectionValues.All || self.selectedHierarchyName === HierarchySelectionValues.Unparented) ? [] : [self.selectedHierarchyName];
                                self.noResultsElem.style('display', 'none');
                                self.clearAndGetResults();
                                self.clearAndHideFilterPath();
                            });

                        this.instanceLookupLoadingElem = hierarchyNavWrapper.append('div').classed('tsi-instance-lookup-loading', true);
                        this.instanceLookupLoadingElem.append('i').classed('tsi-spinner-icon', true);
                        this.instanceLookupLoadingElem.append('span').classed('tsi-lookup-instance', true);

                        // no search results
                        this.noResultsElem = hierarchyNavWrapper.append('div').classed('tsi-noResults', true).style('display', 'none');
                        let noInstancesMessage = this.noResultsElem.append('div').classed('tsi-not-found-message', true).text(this.getString("No search result")).attr("role", "alert");
                        this.searchGloballyElem = noInstancesMessage.append('a').classed('tsi-search-globally-link', true).text(this.getString("Search globally")).style('display', 'none')
                                                .attr('title', this.getString("Search globally"))
                                                .attr('tabindex', 0)
                                                .attr('arialabel', this.getString("Search globally"))
                                                .on('click keydown', function () {
                                                    if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                                    self.selectHierarchy(HierarchySelectionValues.All, false);
                                                    self.switchToSearchView(ViewType.List);
                                                    self.noResultsElem.style('display', 'none');
                                                });
                        this.noResultsElem.append('i').attr('class', 'tsi-clear')
                            .attr('title', this.getString("Dismiss"))
                            .attr("tabindex", "0").attr("role", "button")
                            .attr("aria-label", this.getString("Dismiss"))
                            .on('click keydown', function() {
                                if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                self.searchWrapperElem.select("input").node().value = "";
                                self.searchWrapperElem.select(".tsi-clear").dispatch('click');
                                self.noResultsElem.style('display', 'none');
                            });
                            
                        // could not find the reverse lookup item under the selected hierarchy
                        this.notFoundElem = hierarchyNavWrapper.append('div').classed('tsi-notFound', true).style('display', 'none');
                        let notFoundMessage = this.notFoundElem.append('div').classed('tsi-not-found-message', true).text(this.getString("Instance not found")).attr("role", "alert");
                        this.lookupGloballyElem = notFoundMessage.append('a').classed('tsi-search-globally-link', true).text(this.getString("Lookup globally")).style('display', 'none')
                                                .attr('title', this.getString("Lookup globally"))
                                                .attr('tabindex', 0)
                                                .attr('arialabel', this.getString("Lookup globally"))
                                                .on('click keydown', function () {
                                                    if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                                    self.selectHierarchy(HierarchySelectionValues.All, false);
                                                    self.showInstance(self.timeSeriesIdForLookup);
                                                });
                        this.notFoundElem.append('i').attr('class', 'tsi-clear')
                            .attr('title', this.getString("Dismiss"))
                            .attr("tabindex", "0").attr("role", "button")
                            .attr("aria-label", this.getString("Dismiss"))
                            .on('click keydown', function() {
                                if (Utils.isKeyDownAndNotEnter(d3.event)) {return; }
                                self.notFoundElem.style('display', 'none');
                            });

                        // result (hierarchy or flat list)
                        let results = hierarchyNavWrapper.append('div').classed('tsi-hierarchy-or-list-wrapper', true);
                        // hierarchy
                        this.hierarchyElem = results.append('div').classed('tsi-hierarchy', true).attr("role", "navigation").on('scroll', function(){
                            self.closeContextMenu();
                        });
                        // flat list
                        this.instanceListWrapperElem = results.append('div').classed('tsi-list', true).on('scroll', function(){
                            if (self.viewType === ViewType.List) {
                                self.closeContextMenu();
                                if (self.lastInstanceContinuationToken && (self.lastInstanceContinuationToken !== "END")) {
                                    let that = this as any;
                                    if(that.scrollTop + that.clientHeight + 50 > (self.instanceListElem.node() as any).clientHeight){
                                        if (self.lastInstanceContinuationToken === null || !self.usedInstanceSearchContinuationTokens[self.lastInstanceContinuationToken]) {
                                            self.usedInstanceSearchContinuationTokens[self.lastInstanceContinuationToken] = true
                                            self.pathSearchAndRenderResult({search: {payload: self.requestPayload(), instancesContinuationToken: self.lastInstanceContinuationToken}, render: {target: self.instanceListElem}});
                                        }
                                    }
                                }
                            }
                        });
                        this.instanceListElem = this.instanceListWrapperElem.append('div').classed('tsi-search-results', true);
                        this.pathSearchAndRenderResult({search: {payload: self.requestPayload()}, render: {target: this.hierarchyElem}});
                    }
                } catch (err) {
                    throw err;
                }
            }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to complete search", err instanceof XMLHttpRequest ? err : null));
        }).catch(err => this.chartOptions.onError("Error in hierarchy navigation", "Failed to get token", err instanceof XMLHttpRequest ? err : null));

        let autocompleteOnInput = (st, event) => {
            if(st.length === 0){
                this.searchString = st;
                (this.viewTypesElem.node() as any).style.display = 'none';
                (this.searchGloballyElem.node() as any).style.display = 'none';
                this.switchToSearchView(ViewType.Hierarchy, false);
                this.clearAndGetResults();
            }
            else {
                if (event.which === 13 || event.keyCode === 13) {
                    this.searchString = st;
                    this.switchToSearchView(ViewType.List, false);
                    this.clearAndGetResults();
                }
            }
        }

        let handleKeydown = (event, ap) => {
            if(!ap.isOpened) {
            }
        }
    }