48 changed files with 856 additions and 173 deletions
@ -0,0 +1,28 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host { |
||||
|
.tb-editable-switch { |
||||
|
padding-left: 10px; |
||||
|
|
||||
|
.editable-switch { |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
.editable-label { |
||||
|
margin: 5px 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host { |
||||
|
.predicate-list { |
||||
|
overflow: auto; |
||||
|
max-height: 350px; |
||||
|
.no-data-found { |
||||
|
height: 50px; |
||||
|
} |
||||
|
} |
||||
|
.filters-operation { |
||||
|
margin-top: -40px; |
||||
|
color: #666; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host ::ng-deep { |
||||
|
mat-form-field { |
||||
|
.mat-form-field-wrapper { |
||||
|
padding-bottom: 0; |
||||
|
.mat-form-field-infix { |
||||
|
border-top-width: 0.2em; |
||||
|
width: auto; |
||||
|
} |
||||
|
.mat-form-field-underline { |
||||
|
bottom: 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2020 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. |
||||
|
|
||||
|
--> |
||||
|
<div fxLayout="column" class="mat-content mat-padding"> |
||||
|
<div fxLayout="column" *ngFor="let filter of filtersInfo | keyvalue"> |
||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="start center"> |
||||
|
<mat-label fxFlex>{{filter.value.filter}}</mat-label> |
||||
|
<button mat-icon-button color="primary" |
||||
|
style="min-width: 40px;" |
||||
|
type="button" |
||||
|
(click)="editFilter(filter.key, filter.value)" |
||||
|
matTooltip="{{ 'filter.edit' | translate }}" |
||||
|
matTooltipPosition="above"> |
||||
|
<mat-icon>edit</mat-icon> |
||||
|
</button> |
||||
|
</div> |
||||
|
<mat-divider></mat-divider> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host { |
||||
|
min-width: 300px; |
||||
|
max-height: 150px; |
||||
|
overflow-x: hidden; |
||||
|
overflow-y: auto; |
||||
|
background: #fff; |
||||
|
border-radius: 4px; |
||||
|
box-shadow: |
||||
|
0 7px 8px -4px rgba(0, 0, 0, .2), |
||||
|
0 13px 19px 2px rgba(0, 0, 0, .14), |
||||
|
0 5px 24px 4px rgba(0, 0, 0, .12); |
||||
|
|
||||
|
@media (min-height: 350px) { |
||||
|
max-height: 250px; |
||||
|
} |
||||
|
|
||||
|
.mat-content { |
||||
|
background-color: #fff; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2020 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, Inject, InjectionToken } from '@angular/core'; |
||||
|
import { IAliasController } from '@core/api/widget-api.models'; |
||||
|
import { Filter, FilterInfo } from '@shared/models/query/query.models'; |
||||
|
import { MatDialog } from '@angular/material/dialog'; |
||||
|
import { FilterDialogComponent, FilterDialogData } from '@home/components/filter/filter-dialog.component'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
|
||||
|
export const FILTER_EDIT_PANEL_DATA = new InjectionToken<any>('FiltersEditPanelData'); |
||||
|
|
||||
|
export interface FiltersEditPanelData { |
||||
|
aliasController: IAliasController; |
||||
|
filtersInfo: {[filterId: string]: FilterInfo}; |
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-filters-edit-panel', |
||||
|
templateUrl: './filters-edit-panel.component.html', |
||||
|
styleUrls: ['./filters-edit-panel.component.scss'] |
||||
|
}) |
||||
|
export class FiltersEditPanelComponent { |
||||
|
|
||||
|
filtersInfo: {[filterId: string]: FilterInfo}; |
||||
|
|
||||
|
constructor(@Inject(FILTER_EDIT_PANEL_DATA) public data: FiltersEditPanelData, |
||||
|
private dialog: MatDialog) { |
||||
|
this.filtersInfo = this.data.filtersInfo; |
||||
|
} |
||||
|
|
||||
|
public editFilter(filterId: string, filter: FilterInfo) { |
||||
|
const singleFilter: Filter = {id: filterId, ...deepClone(filter)}; |
||||
|
this.dialog.open<FilterDialogComponent, FilterDialogData, |
||||
|
Filter>(FilterDialogComponent, { |
||||
|
disableClose: true, |
||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
||||
|
data: { |
||||
|
isAdd: false, |
||||
|
filters: [], |
||||
|
filter: singleFilter, |
||||
|
userMode: true |
||||
|
} |
||||
|
}).afterClosed().subscribe( |
||||
|
(result) => { |
||||
|
if (result) { |
||||
|
this.filtersInfo[result.id] = result; |
||||
|
this.data.aliasController.updateUserFilter(result); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2020 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-filters-edit" fxLayout="row" fxLayoutAlign="start center" *ngIf="hasEditableFilters"> |
||||
|
<button mat-icon-button |
||||
|
cdkOverlayOrigin #filtersEditPanelOrigin="cdkOverlayOrigin" |
||||
|
(click)="openEditMode()" |
||||
|
matTooltip="{{ 'filter.filters' | translate }}" |
||||
|
[matTooltipPosition]="tooltipPosition"> |
||||
|
<mat-icon>filter_list</mat-icon> |
||||
|
</button> |
||||
|
<span fxHide.lt-lg |
||||
|
(click)="openEditMode()" |
||||
|
matTooltip="{{ 'filter.filters' | translate }}" |
||||
|
[matTooltipPosition]="tooltipPosition"> |
||||
|
{{ 'filter.filters' | translate }} |
||||
|
</span> |
||||
|
</section> |
||||
@ -0,0 +1,36 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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 "../../../../../scss/constants"; |
||||
|
|
||||
|
:host { |
||||
|
section.tb-filters-edit { |
||||
|
min-height: 32px; |
||||
|
padding: 0 6px; |
||||
|
|
||||
|
@media #{$mat-lt-md} { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
span { |
||||
|
max-width: 200px; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
pointer-events: all; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,154 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2020 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, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; |
||||
|
import { TooltipPosition } from '@angular/material/tooltip'; |
||||
|
import { IAliasController } from '@core/api/widget-api.models'; |
||||
|
import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { Subscription } from 'rxjs'; |
||||
|
import { BreakpointObserver } from '@angular/cdk/layout'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
import { FilterInfo } from '@shared/models/query/query.models'; |
||||
|
import { |
||||
|
FILTER_EDIT_PANEL_DATA, |
||||
|
FiltersEditPanelComponent, |
||||
|
FiltersEditPanelData |
||||
|
} from '@home/components/filter/filters-edit-panel.component'; |
||||
|
import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-filters-edit', |
||||
|
templateUrl: './filters-edit.component.html', |
||||
|
styleUrls: ['./filters-edit.component.scss'] |
||||
|
}) |
||||
|
export class FiltersEditComponent implements OnInit, OnDestroy { |
||||
|
|
||||
|
aliasControllerValue: IAliasController; |
||||
|
|
||||
|
@Input() |
||||
|
set aliasController(aliasController: IAliasController) { |
||||
|
this.aliasControllerValue = aliasController; |
||||
|
this.setupAliasController(this.aliasControllerValue); |
||||
|
} |
||||
|
|
||||
|
get aliasController(): IAliasController { |
||||
|
return this.aliasControllerValue; |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
tooltipPosition: TooltipPosition = 'above'; |
||||
|
|
||||
|
@Input() disabled: boolean; |
||||
|
|
||||
|
@ViewChild('filtersEditPanelOrigin') filtersEditPanelOrigin: CdkOverlayOrigin; |
||||
|
|
||||
|
displayValue: string; |
||||
|
filtersInfo: {[filterId: string]: FilterInfo} = {}; |
||||
|
hasEditableFilters = false; |
||||
|
|
||||
|
private rxSubscriptions = new Array<Subscription>(); |
||||
|
|
||||
|
constructor(private translate: TranslateService, |
||||
|
private overlay: Overlay, |
||||
|
private breakpointObserver: BreakpointObserver, |
||||
|
private viewContainerRef: ViewContainerRef) { |
||||
|
} |
||||
|
|
||||
|
private setupAliasController(aliasController: IAliasController) { |
||||
|
this.rxSubscriptions.forEach((subscription) => { |
||||
|
subscription.unsubscribe(); |
||||
|
}); |
||||
|
this.rxSubscriptions.length = 0; |
||||
|
if (aliasController) { |
||||
|
this.rxSubscriptions.push(aliasController.filtersChanged.subscribe( |
||||
|
() => { |
||||
|
setTimeout(() => { |
||||
|
this.updateFiltersInfo(); |
||||
|
}, 0); |
||||
|
} |
||||
|
)); |
||||
|
setTimeout(() => { |
||||
|
this.updateFiltersInfo(); |
||||
|
}, 0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
} |
||||
|
|
||||
|
ngOnDestroy(): void { |
||||
|
this.rxSubscriptions.forEach((subscription) => { |
||||
|
subscription.unsubscribe(); |
||||
|
}); |
||||
|
this.rxSubscriptions.length = 0; |
||||
|
} |
||||
|
|
||||
|
openEditMode() { |
||||
|
if (this.disabled || !this.hasEditableFilters) { |
||||
|
return; |
||||
|
} |
||||
|
const position = this.overlay.position(); |
||||
|
const config = new OverlayConfig({ |
||||
|
panelClass: 'tb-filters-edit-panel', |
||||
|
backdropClass: 'cdk-overlay-transparent-backdrop', |
||||
|
hasBackdrop: true, |
||||
|
}); |
||||
|
const connectedPosition: ConnectedPosition = { |
||||
|
originX: 'start', |
||||
|
originY: 'bottom', |
||||
|
overlayX: 'start', |
||||
|
overlayY: 'top' |
||||
|
}; |
||||
|
config.positionStrategy = position.flexibleConnectedTo(this.filtersEditPanelOrigin.elementRef) |
||||
|
.withPositions([connectedPosition]); |
||||
|
const overlayRef = this.overlay.create(config); |
||||
|
overlayRef.backdropClick().subscribe(() => { |
||||
|
overlayRef.dispose(); |
||||
|
}); |
||||
|
|
||||
|
const injector = this._createFiltersEditPanelInjector( |
||||
|
overlayRef, |
||||
|
{ |
||||
|
aliasController: this.aliasController, |
||||
|
filtersInfo: deepClone(this.filtersInfo) |
||||
|
} |
||||
|
); |
||||
|
overlayRef.attach(new ComponentPortal(FiltersEditPanelComponent, this.viewContainerRef, injector)); |
||||
|
} |
||||
|
|
||||
|
private _createFiltersEditPanelInjector(overlayRef: OverlayRef, data: FiltersEditPanelData): PortalInjector { |
||||
|
const injectionTokens = new WeakMap<any, any>([ |
||||
|
[FILTER_EDIT_PANEL_DATA, data], |
||||
|
[OverlayRef, overlayRef] |
||||
|
]); |
||||
|
return new PortalInjector(this.viewContainerRef.injector, injectionTokens); |
||||
|
} |
||||
|
|
||||
|
private updateFiltersInfo() { |
||||
|
const allFilters = this.aliasController.getFilters(); |
||||
|
this.filtersInfo = {}; |
||||
|
this.hasEditableFilters = false; |
||||
|
for (const filterId of Object.keys(allFilters)) { |
||||
|
const filterInfo = this.aliasController.getFilterInfo(filterId); |
||||
|
if (filterInfo && filterInfo.editable) { |
||||
|
this.filtersInfo[filterId] = deepClone(filterInfo); |
||||
|
this.hasEditableFilters = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host ::ng-deep { |
||||
|
.entity-key { |
||||
|
mat-form-field { |
||||
|
.mat-form-field-wrapper { |
||||
|
.mat-form-field-infix { |
||||
|
width: auto; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2020 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. |
||||
|
*/ |
||||
|
:host { |
||||
|
.key-filter-list { |
||||
|
overflow: auto; |
||||
|
max-height: 300px; |
||||
|
.no-data-found { |
||||
|
height: 50px; |
||||
|
} |
||||
|
} |
||||
|
.filters-operation { |
||||
|
margin-top: -40px; |
||||
|
color: #666; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue