Bug 571879 - Usability improvements in search component

- When searching over several data pools exception comes up, if a search
field does not exist in all data pools
- Autocomplete when selecting a value with the mouse
- Tooltip style changed for advanced search
- After defining a new Search, the Dropdown for the "Search filter"
shows the Empty-Search.

Signed-off-by: Joachim Zeyn <j.zeyn@peak-solution.de>
diff --git a/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.html b/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.html
index a33b8d5..12ed0ce 100644
--- a/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.html
+++ b/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.html
@@ -62,7 +62,7 @@
   <div class="row">
     <div class="col-sm">
       <label for="search-source" class="col-form-label">{{ 'search.mdm-search.lbl-search-filter' | translate }}</label>
-      <p-dropdown [options]="filters" optionLabel="name" (onChange)="onFilterChange($event)" [style]="{'width': '100%'}"></p-dropdown>
+      <p-dropdown [options]="filterModel" [(ngModel)]="selectedFilter" (onChange)="onFilterChange($event)" [style]="{'width': '100%'}"></p-dropdown>
     </div>
     <div class="col-sm">
       <label for="search-source" class="col-form-label">{{ 'search.mdm-search.lbl-source' | translate }}</label>
diff --git a/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.ts b/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.ts
index 4c16059..2d7214f 100644
--- a/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.ts
+++ b/nucleus/webclient/src/main/webapp/src/app/search/mdm-search.component.ts
@@ -49,6 +49,8 @@
   filters: SearchFilter[] = [];
   currentFilter: SearchFilter;
   filterName = '';
+  public filterModel: SelectItem[] = [];
+  public selectedFilter: string;
 
   environments: Node[];
   selectedEnvironments: Node[] = [];
@@ -147,7 +149,7 @@
       filters: SearchFilter[], definitions: SearchDefinition[]) {
     this.environments = envs;
     this.allSearchAttributes = attrs;
-    this.filters = filters;
+    this.mapFilterModel(filters);
     this.definitions = definitions;
 
     this.dropdownModel = envs.map(env => <SelectItem>{ value: env.sourceName, label: env.name });
@@ -159,8 +161,14 @@
     this.loadState();
   }
 
-  loadState() {
+  mapFilterModel(filters: SearchFilter[]) {
+    this.filters = filters;
+    this.filters.push(this.filterService.EMPTY_FILTER);
+    this.filterModel = this.filters.map(filter => <SelectItem>{ value: filter.name,
+      label: (filter.name != this.filterService.NO_FILTER_NAME ? filter.name : this.translateService.instant(filter.name)) });
+  }
 
+  loadState() {
     this.results = deserialize(SearchResult, sessionStorage.getItem('mdm-search.searchResult')) || new SearchResult();
     this.selectFilter(deserialize(SearchFilter, sessionStorage.getItem('mdm-search.currentFilter')) || this.filterService.EMPTY_FILTER);
     this.isAdvancedSearchActive = !('false' === sessionStorage.getItem('mdm-search.isAdvancedSearchActive'));
@@ -208,10 +216,9 @@
 
   loadFilters() {
     this.filters = [];
-    this.filterService.getFilters().pipe(
-      defaultIfEmpty([this.currentFilter]))
+    this.filterService.getFilters().pipe()
       .subscribe(
-        filters => this.filters = this.filters.concat(filters),
+        filters => this.mapFilterModel(filters),
         error => this.notificationService.notifyError(
           this.translateService.instant('search.mdm-search.err-cannot-load-search-filter'), error)
       );
@@ -296,11 +303,12 @@
   }
 
   onFilterChange(e: any) {
-    this.selectFilter(e.value);
+    this.selectFilter(this.filters.find(filter => e.value === filter.name));
   }
 
   selectFilter(filter: SearchFilter) {
     this.currentFilter = classToClass(filter);
+    this.selectedFilter = this.currentFilter.name;
     this.selectedEnvs = this.currentFilter.environments;
     this.updateSearchAttributesForCurrentResultType();
     this.selectedEnvironmentsChanged();
@@ -400,7 +408,7 @@
     this.editSearchFieldsComponent.show(conditions).subscribe(
       conds => {
         if (!conditions) {
-          let filter = new SearchFilter(this.filterService.NEW_FILTER_NAME, this.currentFilter.environments, 'Test', '', conds);
+          let filter = new SearchFilter(this.filterService.NO_FILTER_NAME, this.currentFilter.environments, 'Test', '', conds);
           this.selectFilter(filter);
         }
         this.currentFilter.conditions = conds;
diff --git a/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.html b/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.html
index bca6d1b..1b403b6 100644
--- a/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.html
+++ b/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.html
@@ -51,7 +51,7 @@
         (onBlur)="onAutocompleteBlur($event, multi)"
         [style]="{ 'width': '100%'}"
         [inputStyle]="{ 'width': '100%' }"
-        pTooltip="{{ 'search.search-condition.multi-value-input' | translate }}" tooltipPosition="top">
+        pTooltip="{{ 'search.search-condition.multi-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip">
       </p-autoComplete>
     </div>
     <p-autoComplete #first *ngIf="!isHandlingMultipleValues"
@@ -68,7 +68,7 @@
       (onBlur)="onAutocompleteBlur($event, first)"
       [style]="{ 'width': isBinaryOperator ? 'calc(50% - 1.5rem)' : '100%'}"
       [inputStyle]="{ 'width': '100%' }"
-      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top">
+      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip">
     </p-autoComplete>
     <ng-container *ngIf="isBinaryOperator">
       <span style="width: 3rem; text-align: center; display: inline-block;">{{'search.search-condition.and' | translate}}</span>
@@ -86,7 +86,7 @@
         (onBlur)="onAutocompleteBlur($event, second)"
         [style]="{ 'width': 'calc(50% - 1.5rem)'}"
         [inputStyle]="{ 'width': '100%' }"
-        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top">
+        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip">
       </p-autoComplete>
     </ng-container>
   </ng-container>
@@ -103,7 +103,7 @@
       [disabled]="disabled"
       [style]="{ 'width': isBinaryOperator ? 'calc(50% - 1.5rem)' : '100%' }"
       [inputStyle]="{ 'width': 'calc(100% - 2.2rem)' }"
-      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top">
+      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip">
     </p-calendar>
     <ng-container *ngIf="isBinaryOperator">
       <span style="width: 3rem; text-align: center; display: inline-block;">{{'search.search-condition.and' | translate}}</span>
@@ -118,7 +118,7 @@
         [disabled]="disabled"
         [style]="{ 'width': 'calc(50% - 1.5rem)' }"
         [inputStyle]="{ 'width': 'calc(100% - 2.2rem)' }"
-        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top">
+        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip">
       </p-calendar>
     </ng-container>
   </ng-container>
@@ -128,7 +128,7 @@
       [disabled]="disabled"
       [(ngModel)]="stringValueStart"
       (input)="setValue($event)"
-      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top"
+      pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" showDelay=1000 tooltipStyleClass="tooltip"
       [ngStyle]="{ 'width': isBinaryOperator ? 'calc(50% - 1.5rem)' : '100%' }">
     <ng-container *ngIf="isBinaryOperator">
       <span style="width: 3rem; text-align: center; display: inline-block;">{{'search.search-condition.and' | translate}}</span>
@@ -136,7 +136,7 @@
         [disabled]="disabled"
         [(ngModel)]="stringValueEnd"
         (input)="setValue($event)"
-        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="top"
+        pTooltip="{{ 'search.search-condition.single-value-input' | translate }}" tooltipPosition="bottom" tooltipStyleClass="tooltip"
         [ngStyle]="{'width':'calc(50% - 1.5rem)'}">
     </ng-container>
   </ng-container>
diff --git a/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.ts b/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.ts
index e3f4c74..19d91e6 100644
--- a/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.ts
+++ b/nucleus/webclient/src/main/webapp/src/app/search/search-condition.component.ts
@@ -111,6 +111,9 @@
         }
         autoComplete.selectItem(this.lastQuery);
         this.lastQuery = '';
+      } else if (hl != undefined && this.displayedSuggestions.find(s => s === hl) != undefined) {
+        autoComplete.selectItem(this.displayedSuggestions.find(s => s === hl));
+        this.lastQuery = '';
       }
       autoComplete.highlightOption = undefined;
     } else {
diff --git a/nucleus/webclient/src/main/webapp/src/app/search/search.service.ts b/nucleus/webclient/src/main/webapp/src/app/search/search.service.ts
index 0c9ef1d..6f786cc 100644
--- a/nucleus/webclient/src/main/webapp/src/app/search/search.service.ts
+++ b/nucleus/webclient/src/main/webapp/src/app/search/search.service.ts
@@ -246,7 +246,7 @@
   }
 
   convert(envs: string[], conditions: Condition[], attr: { [env: string]: SearchAttribute[] }, fullTextQuery: string): Filter[] {
-    return envs.map(e => this.convertEnv(e, conditions, attr[e], fullTextQuery));
+    return envs.map(e => this.convertEnv(e, conditions, attr[e], fullTextQuery)).filter(e => e != undefined);
   }
 
   convertEnv(env: string, conditions: Condition[], attrs: SearchAttribute[], fullTextQuery: string): Filter {
@@ -261,15 +261,23 @@
             return '';
           }
         } else {
-          return c.value.map(value => c.type + '.' + c.attribute + ' ' + this.adjustOperator(OperatorUtil.toFilterString(c.operator),
-            this.getValueType(c, attrs)) + ' ' + this.quoteValue(value, this.getValueType(c, attrs))).join(c.operator === Operator.NOT_EQUALS ? ' and ' : ' or ')
+          const valueType = this.getValueType(c, attrs);
+          if (valueType.length > 0) {
+            return c.value.map(value => c.type + '.' + c.attribute + ' ' + this.adjustOperator(OperatorUtil.toFilterString(c.operator),
+            valueType) + ' ' + this.quoteValue(value, valueType)).join(c.operator === Operator.NOT_EQUALS ? ' and ' : ' or ')
+
+          } else {
+            return '';
+          }
         }
       })
       .filter(c => c.length > 0)
       .map(c => '( ' + c + ' )')
       .join(' and ');
 
-    return new Filter(env, filterString, fullTextQuery);
+    if (filterString.length != 0 || fullTextQuery.length != 0) {
+      return new Filter(env, filterString, fullTextQuery);
+    }
   }
 
   public convertToCondition(source: string, filter: string) {
@@ -288,7 +296,8 @@
   }
 
   getValueType(c: Condition, attrs: SearchAttribute[]) {
-    return attrs.find(a => a.boType === c.type && a.attrName === c.attribute).valueType;
+    let suchAttr = attrs.find(a => a.boType === c.type && a.attrName === c.attribute);
+    return suchAttr === undefined ? '' : suchAttr.valueType;
   }
   adjustOperator(operator: string, valueType: string) {
     if (valueType.toLowerCase() === 'string') {
diff --git a/nucleus/webclient/src/main/webapp/src/styles.css b/nucleus/webclient/src/main/webapp/src/styles.css
index 9774092..ce29810 100644
--- a/nucleus/webclient/src/main/webapp/src/styles.css
+++ b/nucleus/webclient/src/main/webapp/src/styles.css
@@ -229,3 +229,10 @@
   display: inline-block;
   vertical-align: top;
 }
+.tooltip.ui-tooltip .ui-tooltip-text {
+  background-color: white;
+  color: darkslategray;
+  border: 1px solid black;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 12px;
+}