in src/UXClient/Components/ModelSearch/ModelSearch.ts [35:206]
public render(environmentFqdn: string, getToken: any, hierarchyData: any, chartOptions: any){
this.chartOptions.setOptions(chartOptions);
let self = this;
let continuationToken, searchText;
let targetElement = d3.select(this.renderTarget);
targetElement.html('');
this.wrapper = targetElement.append('div').attr('class', 'tsi-modelSearchWrapper');
super.themify(this.wrapper, this.chartOptions.theme);
let inputWrapper = this.wrapper.append("div")
.attr("class", "tsi-modelSearchInputWrapper");
let autocompleteOnInput = (st, event) => {
self.usedContinuationTokens = {};
// blow results away if no text
if(st.length === 0){
searchText = st;
self.instanceResults.html('');
self.currentResultIndex= -1;
(hierarchyElement.node() as any).style.display = 'block';
(showMore.node() as any).style.display = 'none';
noResults.style('display', 'none');
}
else if (event.which === 13 || event.keyCode === 13) {
(hierarchyElement.node() as any).style.display = 'none';
self.instanceResults.html('');
self.currentResultIndex = -1;
noResults.style('display', 'none');
searchInstances(st);
searchText = st;
}
}
let modelAutocomplete = new ModelAutocomplete(inputWrapper.node());
modelAutocomplete.render(environmentFqdn, getToken, {onInput: autocompleteOnInput, onKeydown: (event, ap) => {this.handleKeydown(event, ap)}, ...chartOptions});
var ap = modelAutocomplete.ap;
let results = this.wrapper.append('div')
.attr("class", "tsi-modelSearchResults").on('scroll', function(){
self.closeContextMenu();
let that = this as any;
if(that.scrollTop + that.clientHeight + 150 > (self.instanceResults.node() as any).clientHeight && searchText.length !== 0){
searchInstances(searchText, continuationToken);
}
})
let noResults = results.append('div').text(this.getString('No results')).classed('tsi-noResults', true).style('display', 'none');
let instanceResultsWrapper = results.append('div').attr('class', 'tsi-modelSearchInstancesWrapper')
this.instanceResults = instanceResultsWrapper.append('div').attr('class', 'tsi-modelSearchInstances');
let showMore = instanceResultsWrapper.append('div').attr('class', 'tsi-showMore').text(this.getString('Show more') + '...').on('click', () => searchInstances(searchText, continuationToken)).style('display', 'none');
let hierarchyElement = this.wrapper.append('div')
.attr("class", "tsi-hierarchyWrapper");
let hierarchy = new Hierarchy(hierarchyElement.node() as any);
hierarchy.render(hierarchyData, {...this.chartOptions, withContextMenu: true});
let searchInstances = (searchText, ct = null) => {
var self = this;
if(ct === 'END')
return;
if(ct === null || !self.usedContinuationTokens[ct]){
self.usedContinuationTokens[ct] = true;
getToken().then(token => {
self.server.getTimeseriesInstancesSearch(token, environmentFqdn, searchText, ct).then((r: any) => {
let instances;
if (Array.isArray(r.instances)) {
continuationToken = r.instancesContinuationToken;
instances = r.instances;
} else { //new search api with the support of hierarchy navigation
if (r.instances.hasOwnProperty('hits')) {
instances = r.instances.hits;
continuationToken = r.instances.hits.continuationToken;
}
}
if(!continuationToken)
continuationToken = 'END';
(showMore.node() as any).style.display = continuationToken !== 'END' ? 'block' : 'none';
if(instances.length == 0){
noResults.style('display', 'block');
}
else{
noResults.style('display', 'none');
}
instances.forEach(i => {
let handleClick = (elt, wrapperMousePos, eltMousePos, fromKeyboard = false) => {
self.closeContextMenu();
if(self.clickedInstance != elt){
self.clickedInstance = elt;
i.type = self.types.filter(t => {
return t.name.replace(/\s/g, '') === (i.highlights.type ? i.highlights.type.split('<hit>').join('').split('</hit>').join('').replace(/\s/g, '') : i.highlights.typeName.split('<hit>').join('').split('</hit>').join('').replace(/\s/g, ''));
})[0];
let contextMenuActions = self.chartOptions.onInstanceClick(i);
self.contextMenu = self.wrapper.append('div');
if(!Array.isArray(contextMenuActions)){
contextMenuActions = [contextMenuActions];
}
let totalActionCount = contextMenuActions.map(cma => Object.keys(cma).length).reduce((p,c) => p + c, 0);
let currentActionIndex = 0
contextMenuActions.forEach((cma, cmaGroupIdx) => {
Object.keys(cma).forEach((k, kIdx, kArray) => {
let localActionIndex = currentActionIndex;
self.contextMenu.append('div').text(k).on('click', cma[k]).on('keydown', function(){
let evt = d3.event;
if(evt.keyCode === 13){
this.click();
}
if(evt.keyCode === 13 || evt.keyCode === 37){
self.closeContextMenu();
let results = self.instanceResults.selectAll('.tsi-modelResultWrapper')
results.nodes()[self.currentResultIndex].focus();
}
if(evt.keyCode === 40 && (localActionIndex + 1 < totalActionCount)){ // down
self.contextMenu.node().children[localActionIndex + 1 + cmaGroupIdx + (kIdx === (kArray.length - 1) ? 1 : 0)].focus();
}
if(evt.keyCode === 38 && localActionIndex > 0){ // up
self.contextMenu.node().children[localActionIndex - 1 + cmaGroupIdx - (kIdx === 0 ? 1 : 0)].focus();
}
}).attr('tabindex', '0');
currentActionIndex++;
});
self.contextMenu.append('div').classed('tsi-break', true);
})
self.contextMenu.attr('style', () => `top: ${wrapperMousePos - eltMousePos}px`);
self.contextMenu.classed('tsi-modelSearchContextMenu', true);
d3.select(elt).classed('tsi-resultSelected', true);
if(self.contextMenu.node().children.length > 0 && fromKeyboard){
self.contextMenu.node().children[0].focus();
}
}
else{
self.clickedInstance = null;
}
}
this.instanceResults.append('div').html(self.getInstanceHtml(i)) // known unsafe usage of .html
.on('click', function() {
let mouseWrapper = d3.mouse(self.wrapper.node());
let mouseElt = d3.mouse(this as any);
handleClick(this, mouseWrapper[1], mouseElt[1]);
})
.on('keydown', () => {
let evt = d3.event;
if(evt.keyCode === 13){
let resultsNodes = this.instanceResults.selectAll('.tsi-modelResultWrapper').nodes();
let height = 0;
for(var i = 0; i < this.currentResultIndex; i++) {
height += resultsNodes[0].clientHeight;
}
handleClick(this.instanceResults.select('.tsi-modelResultWrapper:focus').node(), height - results.node().scrollTop + 48, 0, true);
}
self.handleKeydown(evt, ap);
}).attr('tabindex', '0').classed('tsi-modelResultWrapper', true);
})
})
})
}
}
getToken().then(token => {
this.server.getTimeseriesHierarchies(token, environmentFqdn).then((r: any) => {
this.hierarchies = r.hierarchies;
})
})
// get types
getToken().then(token => {
this.server.getTimeseriesTypes(token, environmentFqdn).then((r: any) => {
this.types = r.types;
})
})
}