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) {
}
}
}