committed by
GitHub
30 changed files with 855 additions and 151 deletions
@ -0,0 +1,47 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 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 [formGroup]="mapActionButton" class="tb-form-table-row"> |
|||
<mat-form-field class="tb-inline-field tb-label-field min-w-32" style="flex: 1 1 40%" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}"> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
matTooltip="{{ 'widgets.maps.map-action.button-requires' | translate }}" |
|||
*ngIf="mapActionButton.hasError('invalidButtonConfig')" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
<tb-material-icon-select formControlName="icon" asBoxInput iconClearButton [color]="this.mapActionButton.get('color').value"></tb-material-icon-select> |
|||
<tb-color-input formControlName="color" asBoxInput required></tb-color-input> |
|||
<tb-widget-action-settings class="min-w-32" style="flex: 1 1 60%" |
|||
formControlName="action" |
|||
panelTitle="{{ 'widgets.maps.map-action.map-action-button' | translate }}" |
|||
[widgetType]="widgetType.latest" |
|||
[additionalWidgetActionTypes]="additionalWidgetActionTypes"> |
|||
</tb-widget-action-settings> |
|||
<div class="tb-form-table-row-cell-buttons w-10 min-w-10"> |
|||
<button type="button" |
|||
mat-icon-button |
|||
(click)="buttonRemoved.emit()" |
|||
matTooltip="{{ 'widgets.maps.map-action.remove-action-button' | translate }}" |
|||
matTooltipPosition="above"> |
|||
<mat-icon>delete</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,100 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 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, EventEmitter, forwardRef, Output } from '@angular/core'; |
|||
import { |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
FormGroup, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
ValidationErrors, |
|||
Validator |
|||
} from '@angular/forms'; |
|||
import { MapActionButtonSettings } from '@home/components/widget/lib/maps/models/map.models'; |
|||
import { WidgetAction, WidgetActionType, widgetType } from '@shared/models/widget.models'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
import { isEmptyStr } from '@core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-map-action-button-row', |
|||
templateUrl: 'map-action-button-row.component.html', |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => MapActionButtonRowComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => MapActionButtonRowComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class MapActionButtonRowComponent implements ControlValueAccessor, Validator { |
|||
|
|||
@Output() |
|||
buttonRemoved = new EventEmitter(); |
|||
|
|||
mapActionButton = this.fb.group({ |
|||
label: [''], |
|||
icon: [''], |
|||
color: [''], |
|||
action: this.fb.control<WidgetAction>(null) |
|||
}, {validators: this.validateButtonConfig()}); |
|||
|
|||
additionalWidgetActionTypes = [WidgetActionType.placeMapItem]; |
|||
readonly widgetType = widgetType; |
|||
|
|||
private propagateChange = (_val: any) => {}; |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
this.mapActionButton.valueChanges.pipe( |
|||
takeUntilDestroyed() |
|||
).subscribe(value => this.propagateChange(value)) |
|||
} |
|||
|
|||
registerOnChange(fn: any) { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(_fn: any): void { } |
|||
|
|||
setDisabledState(isDisabled: boolean) { |
|||
if (isDisabled) { |
|||
this.mapActionButton.disable({emitEvent: false}); |
|||
} else { |
|||
this.mapActionButton.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
validate(): ValidationErrors | null { |
|||
return this.mapActionButton.valid ? null : { |
|||
mapButtonAction: false |
|||
}; |
|||
} |
|||
|
|||
writeValue(value: MapActionButtonSettings) { |
|||
this.mapActionButton.patchValue(value, {emitEvent: false}); |
|||
} |
|||
|
|||
private validateButtonConfig() { |
|||
return (c: FormGroup) => { |
|||
return !c.value.icon && isEmptyStr(c.value.label) ? { |
|||
invalidButtonConfig: true |
|||
} : null; |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 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-form-panel"> |
|||
<mat-expansion-panel class="tb-settings" expanded> |
|||
<mat-expansion-panel-header> |
|||
{{ 'widgets.maps.map-action.map-action-buttons' | translate }} |
|||
</mat-expansion-panel-header> |
|||
<ng-template matExpansionPanelContent> |
|||
<div class="tb-form-table overflow-y-auto"> |
|||
<div class="tb-form-table-header no-padding-right"> |
|||
<div class="tb-form-table-header-cell min-w-32" style="flex: 1 1 40%" translate>widgets.maps.map-action.label</div> |
|||
<div class="tb-form-table-header-cell w-10 min-w-10" translate>widgets.maps.map-action.icon</div> |
|||
<div class="tb-form-table-header-cell w-10 min-w-10" translate>widgets.maps.map-action.color</div> |
|||
<div class="tb-form-table-header-cell min-w-32" style="flex: 1 1 60%" translate>widgets.maps.map-action.action</div> |
|||
<div class="tb-form-table-header-cell w-20 min-w-20 xs:w-10 xs:min-w-10"></div> |
|||
</div> |
|||
<div class="tb-form-table-body" cdkDropList cdkDropListOrientation="vertical" |
|||
[cdkDropListDisabled]="!dragEnabled" |
|||
(cdkDropListDropped)="buttonDrop($event)"> |
|||
@for (mapAction of mapActionButtonsForm.controls; track mapAction) { |
|||
<div cdkDrag [cdkDragDisabled]="!dragEnabled" class="tb-draggable-form-table-row"> |
|||
<tb-map-action-button-row class="flex-1" |
|||
[formControl]="mapAction" |
|||
(buttonRemoved)="removeButton($event)"> |
|||
</tb-map-action-button-row> |
|||
<div class="tb-form-table-row-cell-buttons"> |
|||
<button class="xs:!hidden" |
|||
[class.tb-hidden]="!dragEnabled" |
|||
mat-icon-button |
|||
type="button" |
|||
cdkDragHandle |
|||
matTooltip="{{ 'action.drag' | translate }}" |
|||
matTooltipPosition="above"> |
|||
<mat-icon>drag_indicator</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
} @empty { |
|||
<span class="tb-prompt flex items-center justify-center">{{ 'widgets.maps.map-action.no-action-buttons-configured' | translate }}</span> |
|||
} |
|||
</div> |
|||
</div> |
|||
<button type="button" mat-stroked-button color="primary" class="max-w-fit" (click)="addButton()"> |
|||
{{ 'widgets.maps.map-action.add-button' | translate }} |
|||
</button> |
|||
</ng-template> |
|||
</mat-expansion-panel> |
|||
</section> |
|||
@ -0,0 +1,107 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 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, forwardRef } from '@angular/core'; |
|||
import { |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
ValidationErrors, |
|||
Validator |
|||
} from '@angular/forms'; |
|||
import { |
|||
defaultMapActionButtonSettings, |
|||
MapActionButtonSettings |
|||
} from '@home/components/widget/lib/maps/models/map.models'; |
|||
import { CdkDragDrop } from '@angular/cdk/drag-drop'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-map-action-button-settings', |
|||
templateUrl: './map-action-buttons-settings.component.html', |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => MapActionButtonsSettingsComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => MapActionButtonsSettingsComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class MapActionButtonsSettingsComponent implements ControlValueAccessor, Validator { |
|||
|
|||
mapActionButtonsForm = this.fb.array<MapActionButtonSettings>([]); |
|||
|
|||
private propagateChange = (_val: any) => {}; |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
this.mapActionButtonsForm.valueChanges.pipe( |
|||
takeUntilDestroyed() |
|||
).subscribe(value => this.propagateChange(value)); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(_fn: any): void { } |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
if (isDisabled) { |
|||
this.mapActionButtonsForm.disable({emitEvent: false}); |
|||
} else { |
|||
this.mapActionButtonsForm.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
validate(): ValidationErrors | null { |
|||
return this.mapActionButtonsForm.valid ? null : { |
|||
mapActionButtons: false |
|||
}; |
|||
} |
|||
|
|||
writeValue(buttons: MapActionButtonSettings[] = []) { |
|||
if (buttons?.length === this.mapActionButtonsForm.length) { |
|||
this.mapActionButtonsForm.patchValue(buttons, {emitEvent: false}); |
|||
} else { |
|||
this.mapActionButtonsForm.clear({emitEvent: false}); |
|||
buttons.forEach( |
|||
button => this.mapActionButtonsForm.push(this.fb.control(button), {emitEvent: false}) |
|||
); |
|||
} |
|||
} |
|||
|
|||
get dragEnabled(): boolean { |
|||
return this.mapActionButtonsForm.length > 1; |
|||
} |
|||
|
|||
buttonDrop(event: CdkDragDrop<string[]>) { |
|||
const actionButton = this.mapActionButtonsForm.at(event.previousIndex); |
|||
this.mapActionButtonsForm.removeAt(event.previousIndex, {emitEvent: false}); |
|||
this.mapActionButtonsForm.insert(event.currentIndex, actionButton); |
|||
} |
|||
|
|||
addButton() { |
|||
this.mapActionButtonsForm.push(this.fb.control(defaultMapActionButtonSettings)); |
|||
} |
|||
|
|||
removeButton(index: number) { |
|||
this.mapActionButtonsForm.removeAt(index); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue