UI: Implement navigation widget settings form
This commit is contained in:
		
							parent
							
								
									aebe4c5b20
								
							
						
					
					
						commit
						03ddc2c378
					
				@ -19,8 +19,9 @@
 | 
			
		||||
        "templateHtml": "<tb-navigation-cards-widget [ctx]=\"ctx\"></tb-navigation-cards-widget>",
 | 
			
		||||
        "templateCss": "/*#widget-container {\n    overflow-y: auto;\n    box-sizing: content-box !important;\n    cursor: auto;\n}*/\n\n#widget-container #container {\n    overflow-y: auto;\n    box-sizing: content-box;\n    cursor: auto;\n}",
 | 
			
		||||
        "controllerScript": "self.onInit = function() {\n    self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onResize = function() {\n    self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onDestroy = function() {\n}\n",
 | 
			
		||||
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"filterType\": {\n                \"title\": \"Filter type\",\n                \"type\": \"string\",\n                \"default\": \"all\"\n            },\n            \"filter\": {\n                \"title\": \"Items\",\n                \"type\": \"array\"\n            }\n        },\n        \"required\": []\n    },\n    \"form\": [\n        {\n            \"key\": \"filterType\",\n            \"type\": \"radios\",\n            \"direction\": \"row\",\n            \"titleMap\": [\n                {\n                    \"value\": \"all\",\n                    \"name\": \"All items\"\n                },\n                {\n                    \"value\": \"include\",\n                    \"name\": \"Include items\"\n                },\n                                {\n                    \"value\": \"exclude\",\n                    \"name\": \"Exclude items\"\n                }\n            ]\n        },\n        {\n            \"key\": \"filter\",\n            \"type\": \"rc-select\",\n            \"condition\": \"model.filterType !== 'all'\",\n            \"tags\": true,\n            \"placeholder\": \"Enter urls to filter\",\n            \"items\": [{\"value\": \"/devices\", \"label\": \"/devices\"}, {\"value\": \"/assets\", \"label\": \"/assets\"}, {\"value\": \"/deviceProfiles\", \"label\": \"/deviceProfiles\"}]\n        }\n    ]\n}\n",
 | 
			
		||||
        "settingsSchema": "",
 | 
			
		||||
        "dataKeySettingsSchema": "{}\n",
 | 
			
		||||
        "settingsDirective": "tb-navigation-cards-widget-settings",
 | 
			
		||||
        "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"filterType\":\"all\"},\"title\":\"Navigation cards\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
@ -37,10 +38,11 @@
 | 
			
		||||
        "templateHtml": "<tb-navigation-card-widget [ctx]=\"ctx\"></tb-navigation-card-widget>",
 | 
			
		||||
        "templateCss": "",
 | 
			
		||||
        "controllerScript": "self.onInit = function() {\n\n}\n\n\nself.onDestroy = function() {\n}\n",
 | 
			
		||||
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"name\": {\n                \"title\": \"Title\",\n                \"type\": \"string\",\n                \"default\": \"{i18n:device.devices}\"\n            },\n            \"icon\": {\n                \"title\": \"icon\",\n                \"type\": \"string\",\n                \"default\": \"devices_other\"\n            },\n            \"path\": {\n                \"title\": \"Navigation path\",\n                \"type\": \"string\",\n                \"default\": \"/devices\"\n            }\n        },\n        \"required\": [\"name\", \"icon\", \"path\"]\n    },\n    \"form\": [\n        \"name\",\n        {\n            \"key\": \"icon\",\n            \"type\": \"icon\"\n        },\n        \"path\"\n    ]\n}\n",
 | 
			
		||||
        "settingsSchema": "",
 | 
			
		||||
        "dataKeySettingsSchema": "{}\n",
 | 
			
		||||
        "settingsDirective": "tb-navigation-card-widget-settings",
 | 
			
		||||
        "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(255,255,255,0.87)\",\"padding\":\"8px\",\"settings\":{\"name\":\"{i18n:device.devices}\",\"icon\":\"devices_other\",\"path\":\"/devices\"},\"title\":\"Navigation card\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<section class="tb-widget-settings" [formGroup]="navigationCardWidgetSettingsForm" fxLayout="column">
 | 
			
		||||
  <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
    <mat-label translate>widgets.navigation.title</mat-label>
 | 
			
		||||
    <input required matInput formControlName="name">
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <tb-material-icon-select fxFlex
 | 
			
		||||
                           iconClearButton
 | 
			
		||||
                           required
 | 
			
		||||
                           formControlName="icon">
 | 
			
		||||
  </tb-material-icon-select>
 | 
			
		||||
  <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
    <mat-label translate>widgets.navigation.navigation-path</mat-label>
 | 
			
		||||
    <input required matInput formControlName="path">
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
</section>
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
 | 
			
		||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-navigation-card-widget-settings',
 | 
			
		||||
  templateUrl: './navigation-card-widget-settings.component.html',
 | 
			
		||||
  styleUrls: ['./../widget-settings.scss']
 | 
			
		||||
})
 | 
			
		||||
export class NavigationCardWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
 | 
			
		||||
  navigationCardWidgetSettingsForm: FormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: FormBuilder) {
 | 
			
		||||
    super(store);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected settingsForm(): FormGroup {
 | 
			
		||||
    return this.navigationCardWidgetSettingsForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {
 | 
			
		||||
      name: '{i18n:device.devices}',
 | 
			
		||||
      icon: 'devices_other',
 | 
			
		||||
      path: '/devices'
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
    this.navigationCardWidgetSettingsForm = this.fb.group({
 | 
			
		||||
      name: [settings.name, [Validators.required]],
 | 
			
		||||
      icon: [settings.icon, [Validators.required]],
 | 
			
		||||
      path: [settings.path, [Validators.required]]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<section class="tb-widget-settings" [formGroup]="navigationCardsWidgetSettingsForm" fxLayout="column">
 | 
			
		||||
  <section style="margin-bottom: 16px;">
 | 
			
		||||
    <div class="mat-caption" style="margin: -8px 0 8px;" translate>widgets.navigation.filter-type</div>
 | 
			
		||||
    <mat-radio-group formControlName="filterType" fxLayoutGap="16px">
 | 
			
		||||
      <mat-radio-button [value]="'all'">{{ 'widgets.navigation.filter-type-all' | translate }}</mat-radio-button>
 | 
			
		||||
      <mat-radio-button [value]="'include'">{{ 'widgets.navigation.filter-type-include' | translate }}</mat-radio-button>
 | 
			
		||||
      <mat-radio-button [value]="'exclude'">{{ 'widgets.navigation.filter-type-exclude' | translate }}</mat-radio-button>
 | 
			
		||||
    </mat-radio-group>
 | 
			
		||||
  </section>
 | 
			
		||||
  <mat-form-field [fxShow]="navigationCardsWidgetSettingsForm.get('filterType').value !== 'all'" fxFlex class="mat-block" floatLabel="always">
 | 
			
		||||
    <mat-label translate>widgets.navigation.items</mat-label>
 | 
			
		||||
    <mat-chip-list #filterItemsChipList>
 | 
			
		||||
      <mat-chip *ngFor="let filterItem of navigationCardsWidgetSettingsForm.get('filter').value"
 | 
			
		||||
                [removable]="true" (removed)="onFilterItemRemoved(filterItem)">
 | 
			
		||||
        {{ filterItem }}
 | 
			
		||||
        <mat-icon matChipRemove>cancel</mat-icon>
 | 
			
		||||
      </mat-chip>
 | 
			
		||||
      <input matInput type="text" placeholder="{{ 'widgets.navigation.enter-urls-to-filter' | translate }}"
 | 
			
		||||
             style="max-width: 200px;"
 | 
			
		||||
             #filterItemInput
 | 
			
		||||
             (focusin)="onFilterItemInputFocus()"
 | 
			
		||||
             matAutocompleteOrigin
 | 
			
		||||
             #origin="matAutocompleteOrigin"
 | 
			
		||||
             (input)="filterItemInputChange.next(filterItemInput.value)"
 | 
			
		||||
             [matAutocompleteConnectedTo]="origin"
 | 
			
		||||
             [matAutocomplete]="filterItemAutocomplete"
 | 
			
		||||
             [matChipInputFor]="filterItemsChipList"
 | 
			
		||||
             [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
 | 
			
		||||
             (matChipInputTokenEnd)="addFilterItemFromChipInput($event)">
 | 
			
		||||
    </mat-chip-list>
 | 
			
		||||
    <mat-autocomplete #filterItemAutocomplete="matAutocomplete"
 | 
			
		||||
                      class="tb-autocomplete"
 | 
			
		||||
                      (optionSelected)="filterItemSelected($event)">
 | 
			
		||||
      <mat-option *ngFor="let filterItem of filteredFilterItems | async" [value]="filterItem">
 | 
			
		||||
        <span [innerHTML]="filterItem | highlight:filterItemSearchText"></span>
 | 
			
		||||
      </mat-option>
 | 
			
		||||
    </mat-autocomplete>
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
</section>
 | 
			
		||||
@ -0,0 +1,156 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component, ElementRef, ViewChild } from '@angular/core';
 | 
			
		||||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
 | 
			
		||||
import { FormBuilder, FormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { MatChipInputEvent, MatChipList } from '@angular/material/chips';
 | 
			
		||||
import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
 | 
			
		||||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
 | 
			
		||||
import { Observable, of, Subject } from 'rxjs';
 | 
			
		||||
import { map, mergeMap, share, startWith } from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-navigation-cards-widget-settings',
 | 
			
		||||
  templateUrl: './navigation-cards-widget-settings.component.html',
 | 
			
		||||
  styleUrls: ['./../widget-settings.scss']
 | 
			
		||||
})
 | 
			
		||||
export class NavigationCardsWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
 | 
			
		||||
  @ViewChild('filterItemsChipList') filterItemsChipList: MatChipList;
 | 
			
		||||
  @ViewChild('filterItemAutocomplete') filterItemAutocomplete: MatAutocomplete;
 | 
			
		||||
  @ViewChild('filterItemInput') filterItemInput: ElementRef<HTMLInputElement>;
 | 
			
		||||
 | 
			
		||||
  filterItems: Array<string> = ['/devices', '/assets', '/deviceProfiles'];
 | 
			
		||||
 | 
			
		||||
  separatorKeysCodes = [ENTER, COMMA, SEMICOLON];
 | 
			
		||||
 | 
			
		||||
  navigationCardsWidgetSettingsForm: FormGroup;
 | 
			
		||||
 | 
			
		||||
  filteredFilterItems: Observable<Array<string>>;
 | 
			
		||||
 | 
			
		||||
  filterItemSearchText = '';
 | 
			
		||||
 | 
			
		||||
  filterItemInputChange = new Subject<string>();
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: FormBuilder) {
 | 
			
		||||
    super(store);
 | 
			
		||||
    this.filteredFilterItems = this.filterItemInputChange
 | 
			
		||||
      .pipe(
 | 
			
		||||
        startWith(''),
 | 
			
		||||
        map((value) => value ? value : ''),
 | 
			
		||||
        mergeMap(name => this.fetchFilterItems(name) ),
 | 
			
		||||
        share()
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected settingsForm(): FormGroup {
 | 
			
		||||
    return this.navigationCardsWidgetSettingsForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {
 | 
			
		||||
      filterType: 'all',
 | 
			
		||||
      filter: []
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
    this.navigationCardsWidgetSettingsForm = this.fb.group({
 | 
			
		||||
      filterType: [settings.filterType, []],
 | 
			
		||||
      filter: [settings.filter, []]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected validatorTriggers(): string[] {
 | 
			
		||||
    return ['filterType'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected updateValidators(emitEvent: boolean) {
 | 
			
		||||
    const filterType: string = this.navigationCardsWidgetSettingsForm.get('filterType').value;
 | 
			
		||||
    if (filterType === 'all') {
 | 
			
		||||
      this.navigationCardsWidgetSettingsForm.get('filter').disable();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.navigationCardsWidgetSettingsForm.get('filter').enable();
 | 
			
		||||
    }
 | 
			
		||||
    this.navigationCardsWidgetSettingsForm.get('filter').updateValueAndValidity({emitEvent});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fetchFilterItems(searchText?: string): Observable<Array<string>> {
 | 
			
		||||
    this.filterItemSearchText = searchText;
 | 
			
		||||
    let result = [...this.filterItems];
 | 
			
		||||
    if (this.filterItemSearchText && this.filterItemSearchText.length) {
 | 
			
		||||
      result.unshift(this.filterItemSearchText);
 | 
			
		||||
      result = result.filter(item => item.includes(this.filterItemSearchText));
 | 
			
		||||
    }
 | 
			
		||||
    return of(result);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private addFilterItem(filterItem: string): boolean {
 | 
			
		||||
    if (filterItem) {
 | 
			
		||||
      const filterItems: string[] = this.navigationCardsWidgetSettingsForm.get('filter').value;
 | 
			
		||||
      const index = filterItems.indexOf(filterItem);
 | 
			
		||||
      if (index === -1) {
 | 
			
		||||
        filterItems.push(filterItem);
 | 
			
		||||
        this.navigationCardsWidgetSettingsForm.get('filter').setValue(filterItems);
 | 
			
		||||
        this.navigationCardsWidgetSettingsForm.get('filter').markAsDirty();
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onFilterItemRemoved(filterItem: string): void {
 | 
			
		||||
    const filterItems: string[] = this.navigationCardsWidgetSettingsForm.get('filter').value;
 | 
			
		||||
    const index = filterItems.indexOf(filterItem);
 | 
			
		||||
    if (index > -1) {
 | 
			
		||||
      filterItems.splice(index, 1);
 | 
			
		||||
      this.navigationCardsWidgetSettingsForm.get('filter').setValue(filterItems);
 | 
			
		||||
      this.navigationCardsWidgetSettingsForm.get('filter').markAsDirty();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onFilterItemInputFocus() {
 | 
			
		||||
    this.filterItemInputChange.next(this.filterItemInput.nativeElement.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  addFilterItemFromChipInput(event: MatChipInputEvent): void {
 | 
			
		||||
    const value = event.value;
 | 
			
		||||
    if ((value || '').trim()) {
 | 
			
		||||
      const filterItem = value.trim();
 | 
			
		||||
      if (this.addFilterItem(filterItem)) {
 | 
			
		||||
        this.clearFilterItemInput('');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterItemSelected(event: MatAutocompleteSelectedEvent): void {
 | 
			
		||||
    this.addFilterItem(event.option.value);
 | 
			
		||||
    this.clearFilterItemInput('');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clearFilterItemInput(value: string = '') {
 | 
			
		||||
    this.filterItemInput.nativeElement.value = value;
 | 
			
		||||
    this.filterItemInputChange.next(null);
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      this.filterItemInput.nativeElement.blur();
 | 
			
		||||
      this.filterItemInput.nativeElement.focus();
 | 
			
		||||
    }, 0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -163,6 +163,12 @@ import {
 | 
			
		||||
import {
 | 
			
		||||
  GpioPanelWidgetSettingsComponent
 | 
			
		||||
} from '@home/components/widget/lib/settings/gpio/gpio-panel-widget-settings.component';
 | 
			
		||||
import {
 | 
			
		||||
  NavigationCardWidgetSettingsComponent
 | 
			
		||||
} from '@home/components/widget/lib/settings/navigation/navigation-card-widget-settings.component';
 | 
			
		||||
import {
 | 
			
		||||
  NavigationCardsWidgetSettingsComponent
 | 
			
		||||
} from '@home/components/widget/lib/settings/navigation/navigation-cards-widget-settings.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -223,7 +229,9 @@ import {
 | 
			
		||||
    GatewayEventsWidgetSettingsComponent,
 | 
			
		||||
    GpioItemComponent,
 | 
			
		||||
    GpioControlWidgetSettingsComponent,
 | 
			
		||||
    GpioPanelWidgetSettingsComponent
 | 
			
		||||
    GpioPanelWidgetSettingsComponent,
 | 
			
		||||
    NavigationCardWidgetSettingsComponent,
 | 
			
		||||
    NavigationCardsWidgetSettingsComponent
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@ -288,7 +296,9 @@ import {
 | 
			
		||||
    GatewayEventsWidgetSettingsComponent,
 | 
			
		||||
    GpioItemComponent,
 | 
			
		||||
    GpioControlWidgetSettingsComponent,
 | 
			
		||||
    GpioPanelWidgetSettingsComponent
 | 
			
		||||
    GpioPanelWidgetSettingsComponent,
 | 
			
		||||
    NavigationCardWidgetSettingsComponent,
 | 
			
		||||
    NavigationCardsWidgetSettingsComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class WidgetSettingsModule {
 | 
			
		||||
@ -338,5 +348,7 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
 | 
			
		||||
  'tb-gateway-config-single-device-widget-settings': GatewayConfigSingleDeviceWidgetSettingsComponent,
 | 
			
		||||
  'tb-gateway-events-widget-settings': GatewayEventsWidgetSettingsComponent,
 | 
			
		||||
  'tb-gpio-control-widget-settings': GpioControlWidgetSettingsComponent,
 | 
			
		||||
  'tb-gpio-panel-widget-settings': GpioPanelWidgetSettingsComponent
 | 
			
		||||
  'tb-gpio-panel-widget-settings': GpioPanelWidgetSettingsComponent,
 | 
			
		||||
  'tb-navigation-card-widget-settings': NavigationCardWidgetSettingsComponent,
 | 
			
		||||
  'tb-navigation-cards-widget-settings': NavigationCardsWidgetSettingsComponent
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -16,9 +16,15 @@
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div fxLayout="row" [formGroup]="materialIconFormGroup">
 | 
			
		||||
  <mat-icon (click)="openIconDialog()">{{materialIconFormGroup.get('icon').value}}</mat-icon>
 | 
			
		||||
  <mat-icon class="icon-value" (click)="openIconDialog()">{{materialIconFormGroup.get('icon').value}}</mat-icon>
 | 
			
		||||
  <mat-form-field fxFlex>
 | 
			
		||||
    <mat-label translate>icon.icon</mat-label>
 | 
			
		||||
    <input matInput formControlName="icon" (mousedown)="openIconDialog()">
 | 
			
		||||
    <input [required]="required" matInput formControlName="icon" (mousedown)="openIconDialog()">
 | 
			
		||||
    <button *ngIf="iconClearButton"
 | 
			
		||||
            type="button"
 | 
			
		||||
            matSuffix mat-button mat-icon-button aria-label="Clear"
 | 
			
		||||
            (click)="clear()">
 | 
			
		||||
      <mat-icon class="material-icons">close</mat-icon>
 | 
			
		||||
    </button>
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
:host {
 | 
			
		||||
  .mat-icon {
 | 
			
		||||
  .mat-icon.icon-value {
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
    margin: 8px 4px 4px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
 | 
			
		||||
import { DialogService } from '@core/services/dialog.service';
 | 
			
		||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-material-icon-select',
 | 
			
		||||
@ -38,6 +39,27 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit
 | 
			
		||||
  @Input()
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  private iconClearButtonValue: boolean;
 | 
			
		||||
  get iconClearButton(): boolean {
 | 
			
		||||
    return this.iconClearButtonValue;
 | 
			
		||||
  }
 | 
			
		||||
  @Input()
 | 
			
		||||
  set iconClearButton(value: boolean) {
 | 
			
		||||
    const newVal = coerceBooleanProperty(value);
 | 
			
		||||
    if (this.iconClearButtonValue !== newVal) {
 | 
			
		||||
      this.iconClearButtonValue = newVal;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private requiredValue: boolean;
 | 
			
		||||
  get required(): boolean {
 | 
			
		||||
    return this.requiredValue;
 | 
			
		||||
  }
 | 
			
		||||
  @Input()
 | 
			
		||||
  set required(value: boolean) {
 | 
			
		||||
    this.requiredValue = coerceBooleanProperty(value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private modelValue: string;
 | 
			
		||||
 | 
			
		||||
  private propagateChange = null;
 | 
			
		||||
@ -104,4 +126,8 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clear() {
 | 
			
		||||
    this.materialIconFormGroup.get('icon').patchValue(null, {emitEvent: true});
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3615,6 +3615,16 @@
 | 
			
		||||
            "no-labels": "No labels configured",
 | 
			
		||||
            "add-label": "Add label"
 | 
			
		||||
        },
 | 
			
		||||
        "navigation": {
 | 
			
		||||
            "title": "Title",
 | 
			
		||||
            "navigation-path": "Navigation path",
 | 
			
		||||
            "filter-type": "Filter type",
 | 
			
		||||
            "filter-type-all": "All items",
 | 
			
		||||
            "filter-type-include": "Include items",
 | 
			
		||||
            "filter-type-exclude": "Exclude items",
 | 
			
		||||
            "items": "Items",
 | 
			
		||||
            "enter-urls-to-filter": "Enter urls to filter..."
 | 
			
		||||
        },
 | 
			
		||||
        "persistent-table": {
 | 
			
		||||
            "rpc-id": "RPC ID",
 | 
			
		||||
            "message-type": "Message type",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user