Merge branch 'rc' of github.com:thingsboard/thingsboard into rc

This commit is contained in:
Igor Kulikov 2025-04-01 17:44:10 +03:00
commit 7de5ddaaa7
22 changed files with 128 additions and 109 deletions

View File

@ -135,8 +135,8 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
showIcon: [{ value: this.action.showIcon ?? true, disabled: true}, []],
icon: [this.action.icon, Validators.required],
buttonColor: [{ value: this.action.buttonColor ?? this.defaultIconColor, disabled: true}, []],
buttonFillColor: [{ value: this.action.buttonFillColor ?? '#3F52DD', disabled: true}, []],
buttonBorderColor: [{ value: this.action.buttonBorderColor ?? '#3F52DD', disabled: true}, []],
buttonFillColor: [{ value: this.action.buttonFillColor ?? '#305680', disabled: true}, []],
buttonBorderColor: [{ value: this.action.buttonBorderColor ?? '#0000001F', disabled: true}, []],
customButtonStyle: [{ value: this.action.customButtonStyle ?? {}, disabled: true}, []],
useShowWidgetActionFunction: [this.action.useShowWidgetActionFunction],
showWidgetActionFunction: [this.action.showWidgetActionFunction || 'return true;'],
@ -146,7 +146,7 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
if (this.widgetActionFormGroup.get('actionSourceId').value === 'headerButton') {
this.widgetActionFormGroup.get('buttonType').enable({emitEvent: false});
this.widgetActionFormGroup.get('buttonColor').enable({emitEvent: false});
this.widgetHeaderButtonValidators();
this.widgetHeaderButtonValidators(true);
}
this.widgetActionFormGroup.get('actionSourceId').valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
@ -162,7 +162,7 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
if (value === 'headerButton') {
this.widgetActionFormGroup.get('buttonType').enable({emitEvent: false});
this.widgetActionFormGroup.get('buttonColor').enable({emitEvent: false});
this.widgetHeaderButtonValidators();
this.widgetHeaderButtonValidators(true);
} else {
this.widgetActionFormGroup.get('buttonType').disable({emitEvent: false});
this.widgetActionFormGroup.get('showIcon').disable({emitEvent: false});
@ -190,8 +190,17 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
});
}
widgetHeaderButtonValidators() {
private widgetHeaderButtonValidators(ignoreUpdatedButtonColor = false) {
const buttonType = this.widgetActionFormGroup.get('buttonType').value;
if (!ignoreUpdatedButtonColor) {
if ([WidgetHeaderActionButtonType.raised, WidgetHeaderActionButtonType.flat, WidgetHeaderActionButtonType.miniFab].includes(buttonType)) {
this.widgetActionFormGroup.get('buttonColor').patchValue('#ffffff', {emitEvent: false});
} else if ([WidgetHeaderActionButtonType.stroked].includes(buttonType)) {
this.widgetActionFormGroup.get('buttonColor').patchValue('#305680', {emitEvent: false});
} else {
this.widgetActionFormGroup.get('buttonColor').patchValue(this.defaultIconColor, {emitEvent: false});
}
}
this.widgetActionFormGroup.get('showIcon').disable({emitEvent: false});
this.widgetActionFormGroup.get('buttonFillColor').disable({emitEvent: false});
this.widgetActionFormGroup.get('buttonBorderColor').disable({emitEvent: false});

View File

@ -793,7 +793,7 @@ export class TbTimeSeriesChart {
}
} else {
if (!axis.option.name) {
axis.option.name = axis.settings.label;
axis.option.name = this.ctx.utilsService.customTranslation(axis.settings.label, axis.settings.label);
result.changed = true;
}
const nameGap = size;

View File

@ -95,7 +95,7 @@
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-form-row space-between column-xs">
<div class="fixed-title-width">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="fixed-title-width !min-w-30">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="flex flex-row items-center justify-start gap-2">
<div class="tb-small-label" translate>widgets.table.page-step-increment</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
@ -113,7 +113,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-divider vertical></mat-divider>
<mat-divider vertical class="xs:hidden"></mat-divider>
<div class="tb-small-label" translate>widgets.table.page-step-count</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="pageStepCount" type="number" min="1" max="100" step="1" required

View File

@ -66,6 +66,12 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
};
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize;
this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement);
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
this.alarmsTableWidgetSettingsForm = this.fb.group({
alarmsTitle: [settings.alarmsTitle, []],
@ -86,14 +92,11 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
pageStepCount: [settings.pageStepCount ?? 3, [Validators.min(1), Validators.max(100),
Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement ?? settings.defaultPageSize,
[Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement, [Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
defaultSortOrder: [settings.defaultSortOrder, []],
useRowStyleFunction: [settings.useRowStyleFunction, []],
rowStyleFunction: [settings.rowStyleFunction, [Validators.required]]
});
this.pageStepSizeValues = buildPageStepSizeValues(this.alarmsTableWidgetSettingsForm.get('pageStepCount').value,
this.alarmsTableWidgetSettingsForm.get('pageStepIncrement').value);
}
protected validatorTriggers(): string[] {

View File

@ -62,7 +62,7 @@
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-form-row space-between column-xs">
<div class="fixed-title-width">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="fixed-title-width !min-w-30">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="flex flex-row items-center justify-start gap-2">
<div class="tb-small-label" translate>widgets.table.page-step-increment</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
@ -80,7 +80,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-divider vertical></mat-divider>
<mat-divider vertical class="xs:hidden"></mat-divider>
<div class="tb-small-label" translate>widgets.table.page-step-count</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="pageStepCount" type="number" min="1" max="100" step="1" required

View File

@ -62,6 +62,12 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
};
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize;
this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement);
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
// For backward compatibility
const dateFormat = settings.dateFormat;
@ -83,15 +89,12 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
pageStepCount: [settings.pageStepCount ?? 3, [Validators.min(1), Validators.max(100),
Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement ?? settings.defaultPageSize,
[Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement, [Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
hideEmptyLines: [settings.hideEmptyLines, []],
disableStickyHeader: [settings.disableStickyHeader, []],
useRowStyleFunction: [settings.useRowStyleFunction, []],
rowStyleFunction: [settings.rowStyleFunction, [Validators.required]]
});
this.pageStepSizeValues = buildPageStepSizeValues(this.timeseriesTableWidgetSettingsForm.get('pageStepCount').value,
this.timeseriesTableWidgetSettingsForm.get('pageStepIncrement').value);
}
protected validatorTriggers(): string[] {

View File

@ -105,6 +105,17 @@ export class TimeSeriesChartWidgetSettingsComponent extends WidgetSettingsCompon
const params = widgetConfig.typeParameters as any;
if (isDefinedAndNotNull(params.chartType)) {
this.chartType = params.chartType;
} else {
this.chartType = TimeSeriesChartType.default;
}
if (this.timeSeriesChartWidgetSettingsForm) {
const isStateChartType = this.chartType === TimeSeriesChartType.state;
const hasStatesControl = this.timeSeriesChartWidgetSettingsForm.contains('states');
if (isStateChartType && !hasStatesControl) {
this.timeSeriesChartWidgetSettingsForm.addControl('states', this.fb.control(widgetConfig.config.settings.states), { emitEvent: false });
} else if (!isStateChartType && hasStatesControl) {
this.timeSeriesChartWidgetSettingsForm.removeControl('states', { emitEvent: false });
}
}
}

View File

@ -37,7 +37,7 @@
<div translate>widget-config.action</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<mat-select required formControlName="type" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let actionType of widgetActionTypes" [value]="actionType">
<mat-option *ngFor="let actionType of actionTypes()" [value]="actionType">
{{ widgetActionTypeTranslations.get(widgetActionType[actionType]) | translate }}
</mat-option>
</mat-select>

View File

@ -26,7 +26,7 @@ import {
ValidatorFn,
Validators
} from '@angular/forms';
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { Component, computed, ElementRef, forwardRef, input, Input, OnInit, ViewChild } from '@angular/core';
import {
MapItemType,
mapItemTypeTranslationMap,
@ -102,19 +102,16 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali
@Input()
actionNames: string[];
@Input()
set additionalWidgetActionTypes(value: WidgetActionType[]) {
if (this.widgetActionFormGroup && !widgetActionTypes.includes(this.widgetActionFormGroup.get('type').value)) {
this.widgetActionFormGroup.get('type').setValue(WidgetActionType.doNothing);
}
if (value?.length) {
this.widgetActionTypes = widgetActionTypes.concat(value);
} else {
this.widgetActionTypes = widgetActionTypes;
}
}
additionalWidgetActionTypes = input<WidgetActionType[]>(null);
actionTypes = computed(() => {
const predefinedActionTypes = widgetActionTypes;
if (this.additionalWidgetActionTypes()?.length) {
return predefinedActionTypes.concat(this.additionalWidgetActionTypes());
}
return predefinedActionTypes;
});
widgetActionTypes = widgetActionTypes;
widgetActionTypeTranslations = widgetActionTypeTranslationMap;
widgetActionType = WidgetActionType;
@ -191,9 +188,6 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali
).subscribe(() => {
this.widgetActionUpdated();
});
if (this.additionalWidgetActionTypes) {
this.widgetActionTypes = this.widgetActionTypes.concat(this.additionalWidgetActionTypes);
}
}
writeValue(widgetAction?: WidgetAction): void {

View File

@ -33,7 +33,7 @@ import {
Validators
} from '@angular/forms';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { AdditionalMapDataSourceSettings } from '@shared/models/widget/maps/map.models';
import { AdditionalMapDataSourceSettings, updateDataKeyToNewDsType } from '@shared/models/widget/maps/map.models';
import { DataKey, DatasourceType, datasourceTypeTranslationMap, widgetType } from '@shared/models/widget.models';
import { EntityType } from '@shared/models/entity-type.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
@ -156,7 +156,7 @@ export class AdditionalMapDataSourceRowComponent implements ControlValueAccessor
const dataKeys: DataKey[] = this.dataSourceFormGroup.get('dataKeys').value;
if (dataKeys?.length) {
for (const key of dataKeys) {
updateModel = this.updateDataKeyToNewDsType(key, newDsType) || updateModel;
updateModel = updateDataKeyToNewDsType(key, newDsType) || updateModel;
}
if (updateModel) {
this.dataSourceFormGroup.get('dataKeys').patchValue(dataKeys, {emitEvent: false});
@ -168,21 +168,6 @@ export class AdditionalMapDataSourceRowComponent implements ControlValueAccessor
}
}
private updateDataKeyToNewDsType(dataKey: DataKey, newDsType: DatasourceType): boolean {
if (newDsType === DatasourceType.function) {
if (dataKey.type !== DataKeyType.function) {
dataKey.type = DataKeyType.function;
return true;
}
} else {
if (dataKey.type === DataKeyType.function) {
dataKey.type = DataKeyType.attribute;
return true;
}
}
return false;
}
private updateValidators() {
const dsType: DatasourceType = this.dataSourceFormGroup.get('dsType').value;
if (dsType === DatasourceType.function) {

View File

@ -31,7 +31,8 @@ import {
pathDecoratorSymbolTranslationMap,
PolygonsDataLayerSettings,
ShapeDataLayerSettings,
TripsDataLayerSettings
TripsDataLayerSettings,
updateDataKeyToNewDsType
} from '@shared/models/widget/maps/map.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -294,23 +295,23 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
case 'trips':
case 'markers':
const xKey: DataKey = this.dataLayerFormGroup.get('xKey').value;
if (this.updateDataKeyToNewDsType(xKey, newDsType, this.dataLayerType === 'trips')) {
if (updateDataKeyToNewDsType(xKey, newDsType, this.dataLayerType === 'trips')) {
this.dataLayerFormGroup.get('xKey').patchValue(xKey, {emitEvent: false});
}
const yKey: DataKey = this.dataLayerFormGroup.get('yKey').value;
if (this.updateDataKeyToNewDsType(yKey, newDsType, this.dataLayerType === 'trips')) {
if (updateDataKeyToNewDsType(yKey, newDsType, this.dataLayerType === 'trips')) {
this.dataLayerFormGroup.get('yKey').patchValue(yKey, {emitEvent: false});
}
break;
case 'polygons':
const polygonKey: DataKey = this.dataLayerFormGroup.get('polygonKey').value;
if (this.updateDataKeyToNewDsType(polygonKey, newDsType)) {
if (updateDataKeyToNewDsType(polygonKey, newDsType)) {
this.dataLayerFormGroup.get('polygonKey').patchValue(polygonKey, {emitEvent: false});
}
break;
case 'circles':
const circleKey: DataKey = this.dataLayerFormGroup.get('circleKey').value;
if (this.updateDataKeyToNewDsType(circleKey, newDsType)) {
if (updateDataKeyToNewDsType(circleKey, newDsType)) {
this.dataLayerFormGroup.get('circleKey').patchValue(circleKey, {emitEvent: false});
}
break;
@ -319,7 +320,7 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
if (additionalDataKeys?.length) {
let updated = false;
for (const key of additionalDataKeys) {
updated = this.updateDataKeyToNewDsType(key, newDsType) || updated;
updated = updateDataKeyToNewDsType(key, newDsType) || updated;
}
if (updated) {
this.dataLayerFormGroup.get('additionalDataKeys').patchValue(additionalDataKeys, {emitEvent: false});
@ -328,21 +329,6 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.updateValidators();
}
private updateDataKeyToNewDsType(dataKey: DataKey, newDsType: DatasourceType, timeSeries = false): boolean {
if (newDsType === DatasourceType.function) {
if (dataKey.type !== DataKeyType.function) {
dataKey.type = DataKeyType.function;
return true;
}
} else {
if (dataKey.type === DataKeyType.function) {
dataKey.type = timeSeries ? DataKeyType.timeseries : DataKeyType.attribute;
return true;
}
}
return false;
}
private updateValidators() {
const dsType: DatasourceType = this.dataLayerFormGroup.get('dsType').value;
if (dsType === DatasourceType.function) {

View File

@ -41,7 +41,8 @@ import {
MapType,
MarkersDataLayerSettings,
PolygonsDataLayerSettings,
TripsDataLayerSettings
TripsDataLayerSettings,
updateDataKeyToNewDsType
} from '@shared/models/widget/maps/map.models';
import { DataKey, DatasourceType, datasourceTypeTranslationMap, widgetType } from '@shared/models/widget.models';
import { EntityType } from '@shared/models/entity-type.models';
@ -271,26 +272,26 @@ export class MapDataLayerRowComponent implements ControlValueAccessor, OnInit {
case 'trips':
case 'markers':
const xKey: DataKey = this.dataLayerFormGroup.get('xKey').value;
if (this.updateDataKeyToNewDsType(xKey, newDsType, this.dataLayerType === 'trips')) {
if (updateDataKeyToNewDsType(xKey, newDsType, this.dataLayerType === 'trips')) {
this.dataLayerFormGroup.get('xKey').patchValue(xKey, {emitEvent: false});
updateModel = true;
}
const yKey: DataKey = this.dataLayerFormGroup.get('yKey').value;
if (this.updateDataKeyToNewDsType(yKey, newDsType, this.dataLayerType === 'trips')) {
if (updateDataKeyToNewDsType(yKey, newDsType, this.dataLayerType === 'trips')) {
this.dataLayerFormGroup.get('yKey').patchValue(yKey, {emitEvent: false});
updateModel = true;
}
break;
case 'polygons':
const polygonKey: DataKey = this.dataLayerFormGroup.get('polygonKey').value;
if (this.updateDataKeyToNewDsType(polygonKey, newDsType)) {
if (updateDataKeyToNewDsType(polygonKey, newDsType)) {
this.dataLayerFormGroup.get('polygonKey').patchValue(polygonKey, {emitEvent: false});
updateModel = true;
}
break;
case 'circles':
const circleKey: DataKey = this.dataLayerFormGroup.get('circleKey').value;
if (this.updateDataKeyToNewDsType(circleKey, newDsType)) {
if (updateDataKeyToNewDsType(circleKey, newDsType)) {
this.dataLayerFormGroup.get('circleKey').patchValue(circleKey, {emitEvent: false});
updateModel = true;
}
@ -302,21 +303,6 @@ export class MapDataLayerRowComponent implements ControlValueAccessor, OnInit {
}
}
private updateDataKeyToNewDsType(dataKey: DataKey, newDsType: DatasourceType, timeSeries = false): boolean {
if (newDsType === DatasourceType.function) {
if (dataKey.type !== DataKeyType.function) {
dataKey.type = DataKeyType.function;
return true;
}
} else {
if (dataKey.type === DataKeyType.function) {
dataKey.type = timeSeries ? DataKeyType.timeseries : DataKeyType.attribute;
return true;
}
}
return false;
}
private updateValidators() {
const dsType: DatasourceType = this.dataLayerFormGroup.get('dsType').value;
if (dsType === DatasourceType.function) {

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core';
import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import {
ControlValueAccessor,
NG_VALIDATORS,
@ -70,7 +70,7 @@ import { MatDialog } from '@angular/material/dialog';
}
]
})
export class MapSettingsComponent implements OnInit, ControlValueAccessor, Validator {
export class MapSettingsComponent implements OnInit, ControlValueAccessor, Validator, OnChanges {
mapControlPositions = mapControlPositions;
@ -205,6 +205,23 @@ export class MapSettingsComponent implements OnInit, ControlValueAccessor, Valid
}
}
ngOnChanges(changes: SimpleChanges) {
if (changes.trip) {
const tripChange = changes.trip;
if (!tripChange.firstChange && tripChange.currentValue !== tripChange.previousValue) {
if (this.trip) {
this.dataLayerMode = 'trips'
this.mapSettingsFormGroup.addControl('trips', this.fb.control(this.modelValue.trips), {emitEvent: false});
this.mapSettingsFormGroup.addControl('tripTimeline', this.fb.control(this.modelValue.tripTimeline), {emitEvent: false});
} else {
this.dataLayerMode = 'markers';
this.mapSettingsFormGroup.removeControl('trips', {emitEvent: false});
this.mapSettingsFormGroup.removeControl('tripTimeline', {emitEvent: false});
}
}
}
}
writeValue(value: MapSetting): void {
this.modelValue = value;
this.mapSettingsFormGroup.patchValue(

View File

@ -49,7 +49,7 @@
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-form-row space-between column-xs">
<div class="fixed-title-width">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="fixed-title-width !min-w-30">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="flex flex-row items-center justify-start gap-2">
<div class="tb-small-label" translate>widgets.table.page-step-increment</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
@ -67,7 +67,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-divider vertical></mat-divider>
<mat-divider vertical class="xs:hidden"></mat-divider>
<div class="tb-small-label" translate>widgets.table.page-step-count</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="pageStepCount" type="number" min="1" max="100" step="1" required

View File

@ -105,6 +105,12 @@ export class PersistentTableWidgetSettingsComponent extends WidgetSettingsCompon
};
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize;
this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement);
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
this.persistentTableWidgetSettingsForm = this.fb.group({
enableFilter: [settings.enableFilter, []],
@ -117,13 +123,10 @@ export class PersistentTableWidgetSettingsComponent extends WidgetSettingsCompon
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
pageStepCount: [settings.pageStepCount ?? 3, [Validators.min(1), Validators.max(100),
Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement ?? settings.defaultPageSize,
[Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement, [Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
defaultSortOrder: [settings.defaultSortOrder, []],
displayColumns: [settings.displayColumns, [Validators.required]]
});
this.pageStepSizeValues = buildPageStepSizeValues(this.persistentTableWidgetSettingsForm.get('pageStepCount').value,
this.persistentTableWidgetSettingsForm.get('pageStepIncrement').value);
}
public validateSettings(): boolean {

View File

@ -92,7 +92,7 @@
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-form-row space-between column-xs">
<div class="fixed-title-width">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="fixed-title-width !min-w-30">{{ 'widgets.table.page-step-settings' | translate }}</div>
<div class="flex flex-row items-center justify-start gap-2">
<div class="tb-small-label" translate>widgets.table.page-step-increment</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
@ -110,7 +110,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-divider vertical></mat-divider>
<mat-divider vertical class="xs:hidden"></mat-divider>
<div class="tb-small-label" translate>widgets.table.page-step-count</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="pageStepCount" type="number" min="1" max="100" step="1" required

View File

@ -64,6 +64,12 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen
};
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize;
this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement);
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
this.entitiesTableWidgetSettingsForm = this.fb.group({
entitiesTitle: [settings.entitiesTitle, []],
@ -82,14 +88,11 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
pageStepCount: [settings.pageStepCount ?? 3, [Validators.min(1), Validators.max(100),
Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement ?? settings.defaultPageSize,
[Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
pageStepIncrement: [settings.pageStepIncrement, [Validators.min(1), Validators.required, Validators.pattern(/^\d*$/)]],
defaultSortOrder: [settings.defaultSortOrder, []],
useRowStyleFunction: [settings.useRowStyleFunction, []],
rowStyleFunction: [settings.rowStyleFunction, [Validators.required]]
});
this.pageStepSizeValues = buildPageStepSizeValues(this.entitiesTableWidgetSettingsForm.get('pageStepCount').value,
this.entitiesTableWidgetSettingsForm.get('pageStepIncrement').value);
}
protected validatorTriggers(): string[] {

View File

@ -47,6 +47,8 @@ export class MapWidgetSettingsComponent extends WidgetSettingsComponent {
const params = widgetConfig.typeParameters as any;
if (isDefinedAndNotNull(params.trip)) {
this.trip = params.trip === true;
} else {
this.trip = false;
}
}

View File

@ -141,7 +141,7 @@ export const loadModuleMarkdownSourceCode = (http: HttpClient, translate: Transl
let sourceCode = `<div class="flex flex-col !pl-4"><h6>${resource.title}</h6><small>${translate.instant('js-func.source-code')}</small></div>\n\n`;
return loadFunctionModuleSource(http, resource.link).pipe(
map((source) => {
sourceCode += '```javascript\n{:code-style="margin-left: -16px; margin-right: -16px;"}\n' + source + '\n```';
sourceCode += '```javascript\n{:code-style="margin-left: -16px; margin-right: -16px; max-height: 65vh;"}\n' + source + '\n```';
return sourceCode;
}),
catchError(err => {

View File

@ -1182,6 +1182,21 @@ export const parseCenterPosition = (position: string | [number, number]): [numbe
return [0, 0];
}
export const updateDataKeyToNewDsType = (dataKey: DataKey | null, newDsType: DatasourceType, timeSeries = false): boolean => {
if (newDsType === DatasourceType.function) {
if (dataKey && dataKey.type !== DataKeyType.function) {
dataKey.type = DataKeyType.function;
return true;
}
} else {
if (dataKey?.type === DataKeyType.function) {
dataKey.type = timeSeries ? DataKeyType.timeseries : DataKeyType.attribute;
return true;
}
}
return false;
}
export const mergeMapDatasources = (target: TbMapDatasource[], source: TbMapDatasource[]): TbMapDatasource[] => {
const appendDatasources: TbMapDatasource[] = [];
for (const sourceDs of source) {

View File

@ -360,9 +360,10 @@
}
}
.tb-small-label {
display: flex;
align-items: center;
height: 40px;
font-size: 14px;
line-height: 40px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.38);
}

View File

@ -102,6 +102,7 @@ module.exports = {
minWidth: {
'7.5': '1.875rem',
'25': '6.25rem',
'30': '7.5rem',
'37.5': '9.375rem',
'62.5': '15.625rem',
'72.5': '18.125rem',