UI: Improve aggregated value card widget. Improve data key aggregation config form.

This commit is contained in:
Igor Kulikov 2023-08-16 17:41:05 +03:00
parent 943788f25e
commit 1422558ac6
27 changed files with 234 additions and 147 deletions

View File

@ -64,6 +64,9 @@
<tb-color-settings formControlName="color">
</tb-color-settings>
</div>
<div class="tb-arrow-field">
<mat-checkbox formControlName="showArrow"></mat-checkbox>
</div>
<div class="tb-form-table-row-cell-buttons">
<button type="button"
mat-icon-button

View File

@ -49,10 +49,10 @@
.tb-aggregation-field {
flex: 1;
min-width: 150px;
min-width: 120px;
}
.tb-units-field, .tb-decimals-field, .tb-font-field, .tb-color-field {
.tb-units-field, .tb-decimals-field, .tb-font-field, .tb-color-field, tb-arrow-field {
display: flex;
flex-direction: row;
place-content: center;
@ -69,14 +69,13 @@
min-width: 60px;
}
.tb-font-field {
width: 40px;
min-width: 40px;
}
.tb-color-field {
.tb-font-field, .tb-color-field, .tb-arrow-field {
width: 40px;
min-width: 40px;
display: none;
@media #{$mat-gt-xs} {
display: block;
}
}
.tb-units-field, .tb-decimals-field {

View File

@ -33,7 +33,7 @@ import {
ComparisonResultType,
DataKey,
DataKeyConfigMode,
DatasourceType, Widget,
DatasourceType, JsonSettingsSchema, Widget,
widgetType
} from '@shared/models/widget.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
@ -104,6 +104,14 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
return this.widgetConfigComponent.widget;
}
get latestDataKeySettingsSchema(): JsonSettingsSchema {
return this.widgetConfigComponent.modelValue?.latestDataKeySettingsSchema;
}
get latestDataKeySettingsDirective(): string {
return this.widgetConfigComponent.modelValue?.latestDataKeySettingsDirective;
}
get isEntityDatasource(): boolean {
return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType);
}
@ -124,7 +132,8 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
units: [null, []],
decimals: [null, []],
font: [null, []],
color: [null, []]
color: [null, []],
showArrow: [null, []]
});
this.keyRowFormGroup.valueChanges.subscribe(
() => this.updateModel()
@ -172,7 +181,8 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
units: value?.units,
decimals: value?.decimals,
font: settings.font,
color: settings.color
color: settings.color,
showArrow: settings.showArrow
}, {emitEvent: false}
);
this.cd.markForCheck();
@ -190,8 +200,8 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
data: {
dataKey: deepClone(this.modelValue),
dataKeyConfigMode: DataKeyConfigMode.general,
dataKeySettingsSchema: null,
dataKeySettingsDirective: null,
dataKeySettingsSchema: this.latestDataKeySettingsSchema,
dataKeySettingsDirective: this.latestDataKeySettingsDirective,
dashboard: null,
aliasController: null,
widget: this.widget,
@ -207,6 +217,11 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
}).afterClosed().subscribe((updatedDataKey) => {
if (updatedDataKey) {
this.modelValue = updatedDataKey;
const settings: AggregatedValueCardKeySettings = (this.modelValue.settings || {});
this.keyRowFormGroup.get('position').patchValue(settings.position, {emitEvent: false});
this.keyRowFormGroup.get('font').patchValue(settings.font, {emitEvent: false});
this.keyRowFormGroup.get('color').patchValue(settings.color, {emitEvent: false});
this.keyRowFormGroup.get('showArrow').patchValue(settings.showArrow, {emitEvent: false});
this.keyRowFormGroup.get('units').patchValue(this.modelValue.units, {emitEvent: false});
this.keyRowFormGroup.get('decimals').patchValue(this.modelValue.decimals, {emitEvent: false});
this.updateModel();
@ -220,6 +235,7 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn
this.modelValue.settings.position = value.position;
this.modelValue.settings.font = value.font;
this.modelValue.settings.color = value.color;
this.modelValue.settings.showArrow = value.showArrow;
this.modelValue.units = value.units;
this.modelValue.decimals = value.decimals;
this.propagateChange(this.modelValue);

View File

@ -25,6 +25,7 @@
<div class="tb-form-table-header-cell tb-decimals-header" translate>widget-config.decimals-short</div>
<div class="tb-form-table-header-cell tb-font-header" translate>widgets.aggregated-value-card.font</div>
<div class="tb-form-table-header-cell tb-color-header" translate>widgets.aggregated-value-card.color</div>
<div class="tb-form-table-header-cell tb-arrow-header" translate>widgets.aggregated-value-card.arrow</div>
<div class="tb-form-table-header-cell tb-actions-header"></div>
</div>
<div *ngIf="keysFormArray().controls.length; else noKeys" class="tb-form-table-body">

View File

@ -25,7 +25,7 @@
&.tb-aggregation-header {
flex: 1;
min-width: 150px;
min-width: 120px;
}
&.tb-units-header {
@ -38,14 +38,13 @@
min-width: 60px;
}
&.tb-font-header {
width: 40px;
min-width: 40px;
}
&.tb-color-header {
&.tb-font-header, &.tb-color-header, &.tb-arrow-header {
width: 40px;
min-width: 40px;
display: none;
@media #{$mat-gt-xs} {
display: block;
}
}
&.tb-actions-header {

View File

@ -29,7 +29,7 @@
</tb-datasources>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<div class="tb-form-row">
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.title' | translate }}
</mat-slide-toggle>
@ -48,7 +48,7 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showIcon">
{{ 'widgets.value-card.icon' | translate }}
</mat-slide-toggle>
@ -68,7 +68,7 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showSubtitle">
{{ 'widgets.aggregated-value-card.subtitle' | translate }}
</mat-slide-toggle>
@ -80,8 +80,10 @@
clearButton
[previewText]="aggregatedValueCardWidgetConfigForm.get('subtitle').value">
</tb-font-settings>
<tb-color-settings formControlName="subtitleColor">
</tb-color-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="subtitleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row column-xs">
@ -93,16 +95,27 @@
<tb-font-settings formControlName="dateFont"
[previewText]="datePreviewFn">
</tb-font-settings>
<tb-color-settings formControlName="dateColor">
</tb-color-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="dateColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showChart">
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showChart">
{{ 'widgets.aggregated-value-card.chart' | translate }}
</mat-slide-toggle>
<tb-color-settings formControlName="chartColor">
</tb-color-settings>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-unit-input class="flex" formControlName="chartUnits"></tb-unit-input>
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput formControlName="chartDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="chartColor">
</tb-color-input>
</div>
</div>
</div>
<tb-aggregated-data-keys-panel

View File

@ -90,7 +90,7 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
protected setupDefaults(configData: WidgetConfigComponentData) {
this.setupDefaultDatasource(configData, [
{ name: 'watermeter', label: 'Watermeter', type: DataKeyType.timeseries }
{ name: 'watermeter', label: 'Watermeter', type: DataKeyType.timeseries, units: 'm³', decimals: 0 }
],
createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³')
);
@ -141,6 +141,8 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
dateColor: [settings.dateColor, []],
showChart: [settings.showChart, []],
chartUnits: [dataKey?.units, []],
chartDecimals: [dataKey?.decimals, []],
chartColor: [settings.chartColor, []],
values: [this.getValues(configData.config.datasources, keyName), []],
@ -181,6 +183,13 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
this.widgetConfig.config.settings.dateColor = config.dateColor;
this.widgetConfig.config.settings.showChart = config.showChart;
const dataKey = getDataKey(this.widgetConfig.config.datasources);
if (dataKey) {
dataKey.units = config.chartUnits;
dataKey.decimals = config.chartDecimals;
}
this.widgetConfig.config.settings.chartColor = config.chartColor;
this.setValues(config.values, this.widgetConfig.config.datasources);
@ -253,8 +262,12 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
}
if (showChart) {
this.aggregatedValueCardWidgetConfigForm.get('chartUnits').enable();
this.aggregatedValueCardWidgetConfigForm.get('chartDecimals').enable();
this.aggregatedValueCardWidgetConfigForm.get('chartColor').enable();
} else {
this.aggregatedValueCardWidgetConfigForm.get('chartUnits').disable();
this.aggregatedValueCardWidgetConfigForm.get('chartDecimals').disable();
this.aggregatedValueCardWidgetConfigForm.get('chartColor').disable();
}
}

View File

@ -78,76 +78,87 @@
</tb-js-func>
</section>
<ng-container *ngIf="widgetType === widgetTypes.latest && modelValue.type === dataKeyTypes.timeseries">
<mat-form-field subscriptSizing="dynamic">
<mat-label translate>datakey.aggregation</mat-label>
<mat-select formControlName="aggregationType" style="min-width: 150px;">
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<div class="tb-hint after-fields">
{{ dataKeyFormGroup.get('aggregationType').value ? (dataKeyAggregationTypeHintTranslations.get(aggregationTypes[dataKeyFormGroup.get('aggregationType').value]) | translate) : '' }}
<section *ngIf="dataKeyFormGroup.get('aggregationType').value !== aggregationTypes.NONE">
{{ 'datakey.aggregation-type-hint-common' | translate }}
</section>
<div class="tb-form-row column">
<div class="tb-form-row space-between no-border no-padding">
<div>{{ 'datakey.aggregation' | translate }}</div>
<mat-form-field class="medium-width" subscriptSizing="dynamic" appearance="outline">
<mat-select formControlName="aggregationType">
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-hint tb-primary-fill">
{{ dataKeyFormGroup.get('aggregationType').value ? (dataKeyAggregationTypeHintTranslations.get(aggregationTypes[dataKeyFormGroup.get('aggregationType').value]) | translate) : '' }}
<section *ngIf="dataKeyFormGroup.get('aggregationType').value !== aggregationTypes.NONE">
{{ 'datakey.aggregation-type-hint-common' | translate }}
</section>
</div>
</div>
</ng-container>
</div>
<div *ngIf="dataKeyFormGroup.get('aggregationType').value && dataKeyFormGroup.get('aggregationType').value !== aggregationTypes.NONE"
class="tb-form-panel tb-slide-toggle">
class="tb-form-panel">
<div class="tb-form-panel-title" translate>datakey.delta-calculation</div>
<mat-expansion-panel class="tb-settings" [expanded]="dataKeyFormGroup.get('comparisonEnabled').value" [disabled]="!dataKeyFormGroup.get('comparisonEnabled').value">
<div class="tb-form-panel stroked tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="dataKeyFormGroup.get('comparisonEnabled').value" [disabled]="!dataKeyFormGroup.get('comparisonEnabled').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title fxLayout="column" fxLayoutAlign="center start">
<mat-panel-title fxLayout="column" fxLayoutAlign="center start" fxLayoutGap="8px">
<mat-slide-toggle class="mat-slide" formControlName="comparisonEnabled" (click)="$event.stopPropagation()">
{{ 'datakey.enable-delta-calculation' | translate }}
</mat-slide-toggle>
<mat-hint class="tb-hint" style="line-height: 15px; padding-left: 52px;">{{ 'datakey.enable-delta-calculation-hint' | translate }}</mat-hint>
<mat-hint class="tb-form-hint tb-primary-fill">{{ 'datakey.enable-delta-calculation-hint' | translate }}</mat-hint>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column" *ngIf="dataKeyFormGroup.get('comparisonEnabled').value">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.time-for-comparison</mat-label>
<mat-select formControlName="timeForComparison">
<mat-option [value]="'previousInterval'">
{{ 'widgets.chart.time-for-comparison-previous-interval' | translate }}
</mat-option>
<mat-option [value]="'days'">
{{ 'widgets.chart.time-for-comparison-days' | translate }}
</mat-option>
<mat-option [value]="'weeks'">
{{ 'widgets.chart.time-for-comparison-weeks' | translate }}
</mat-option>
<mat-option [value]="'months'">
{{ 'widgets.chart.time-for-comparison-months' | translate }}
</mat-option>
<mat-option [value]="'years'">
{{ 'widgets.chart.time-for-comparison-years' | translate }}
</mat-option>
<mat-option [value]="'customInterval'">
{{ 'widgets.chart.time-for-comparison-custom-interval' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="dataKeyFormGroup.get('timeForComparison').value === 'customInterval'" fxFlex class="mat-block">
<mat-label translate>widgets.chart.custom-interval-value</mat-label>
<input required matInput type="number" min="0" formControlName="comparisonCustomIntervalValue">
</mat-form-field>
<mat-form-field style="padding-bottom: 16px;">
<mat-label translate>datakey.delta-calculation-result</mat-label>
<mat-select formControlName="comparisonResultType" style="min-width: 150px;">
<mat-option *ngFor="let comparisonResultType of comparisonResults" [value]="comparisonResultType">
{{ comparisonResultTypeTranslations.get(comparisonResultTypes[comparisonResultType]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</section>
<ng-container *ngIf="dataKeyFormGroup.get('comparisonEnabled').value">
<div class="tb-form-row space-between">
<div>{{ 'widgets.chart.time-for-comparison' | translate }}</div>
<mat-form-field class="medium-width" subscriptSizing="dynamic" appearance="outline">
<mat-select formControlName="timeForComparison">
<mat-option [value]="'previousInterval'">
{{ 'widgets.chart.time-for-comparison-previous-interval' | translate }}
</mat-option>
<mat-option [value]="'days'">
{{ 'widgets.chart.time-for-comparison-days' | translate }}
</mat-option>
<mat-option [value]="'weeks'">
{{ 'widgets.chart.time-for-comparison-weeks' | translate }}
</mat-option>
<mat-option [value]="'months'">
{{ 'widgets.chart.time-for-comparison-months' | translate }}
</mat-option>
<mat-option [value]="'years'">
{{ 'widgets.chart.time-for-comparison-years' | translate }}
</mat-option>
<mat-option [value]="'customInterval'">
{{ 'widgets.chart.time-for-comparison-custom-interval' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="dataKeyFormGroup.get('timeForComparison').value === 'customInterval'" class="tb-form-row space-between">
<div>{{ 'widgets.chart.custom-interval-value' | translate }}</div>
<mat-form-field class="medium-width number" subscriptSizing="dynamic" appearance="outline">
<input required matInput type="number" min="0" formControlName="comparisonCustomIntervalValue">
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'datakey.delta-calculation-result' | translate }}</div>
<mat-form-field class="medium-width" subscriptSizing="dynamic" appearance="outline">
<mat-select formControlName="comparisonResultType" style="min-width: 150px;">
<mat-option *ngFor="let comparisonResultType of comparisonResults" [value]="comparisonResultType">
{{ comparisonResultTypeTranslations.get(comparisonResultTypes[comparisonResultType]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</ng-container>
</ng-template>
</mat-expansion-panel>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle"
*ngIf="(modelValue.type === dataKeyTypes.timeseries || modelValue.type === dataKeyTypes.attribute || modelValue.type === dataKeyTypes.count) && showPostProcessing">
<mat-expansion-panel class="tb-settings" [expanded]="dataKeyFormGroup.get('usePostProcessing').value" [disabled]="!dataKeyFormGroup.get('usePostProcessing').value">

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "../../../../../../theme";
@import "../../../../../../scss/constants";
.tb-datasource-list-item {
&.mat-mdc-list-item {

View File

@ -28,7 +28,7 @@
<ng-template #subtitleTpl>
<div *ngIf="showSubtitle" class="tb-aggregated-value-card-subtitle"
[style]="subtitleStyle" [style.color]="subtitleColor.color">{{ subtitle$ | async }}</div>
[style]="subtitleStyle" [style.color]="subtitleColor">{{ subtitle$ | async }}</div>
</ng-template>
<ng-template #valuesTpl>
<div *ngIf="showValues" class="tb-aggregated-value-card-values">
@ -73,7 +73,7 @@
</div>
</ng-template>
<ng-template #dateTpl>
<div *ngIf="showDate" [style]="dateStyle" [style.color]="dateColor.color" [innerHTML]="dateFormat.formatted"></div>
<div *ngIf="showDate" [style]="dateStyle" [style.color]="dateColor" [innerHTML]="dateFormat.formatted"></div>
</ng-template>
<ng-template #valueTpl let-value="value">
<div class="tb-aggregated-value-card-value" [style]="value.style" [style.color]="value.color.color">

View File

@ -36,9 +36,9 @@ import { WidgetContext } from '@home/models/widget-component.models';
import { Observable } from 'rxjs';
import {
backgroundStyle,
ColorProcessor,
ComponentStyle,
DateFormatProcessor, getDataKey,
DateFormatProcessor,
getDataKey,
getLatestSingleTsValue,
overlayStyle,
textStyle
@ -47,7 +47,7 @@ import { DatePipe } from '@angular/common';
import { TbFlot } from '@home/components/widget/lib/flot-widget';
import { TbFlotKeySettings, TbFlotSettings } from '@home/components/widget/lib/flot-widget.models';
import { DataKey } from '@shared/models/widget.models';
import { formatNumberValue, formatValue, isDefined, isNumeric } from '@core/utils';
import { formatNumberValue, formatValue, isDefined } from '@core/utils';
import { map } from 'rxjs/operators';
@Component({
@ -72,19 +72,19 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
showSubtitle = true;
subtitle$: Observable<string>;
subtitleStyle: ComponentStyle = {};
subtitleColor: ColorProcessor;
subtitleColor: string;
showValues = false;
values: {[key: string]: AggregatedValueCardValue} = {};
showChart = true;
chartColor: ColorProcessor;
chartColor: string;
showDate = true;
dateFormat: DateFormatProcessor;
dateStyle: ComponentStyle = {};
dateColor: ColorProcessor;
dateColor: string;
backgroundStyle: ComponentStyle = {};
overlayStyle: ComponentStyle = {};
@ -108,7 +108,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
const subtitle = this.settings.subtitle;
this.subtitle$ = this.ctx.registerLabelPattern(subtitle, this.subtitle$);
this.subtitleStyle = textStyle(this.settings.subtitleFont, '0.25px');
this.subtitleColor = ColorProcessor.fromSettings(this.settings.subtitleColor);
this.subtitleColor = this.settings.subtitleColor;
const dataKey = getDataKey(this.ctx.defaultSubscription.datasources);
if (dataKey?.name && this.ctx.defaultSubscription.firstDatasource?.latestDataKeys?.length) {
@ -123,7 +123,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
}
this.showChart = this.settings.showChart;
this.chartColor = ColorProcessor.fromSettings(this.settings.chartColor);
this.chartColor = this.settings.chartColor;
if (this.showChart) {
if (this.ctx.defaultSubscription.firstDatasource?.dataKeys?.length) {
this.flotDataKey = this.ctx.defaultSubscription.firstDatasource?.dataKeys[0];
@ -132,14 +132,14 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
showLines: true,
lineWidth: 2
} as TbFlotKeySettings;
this.flotDataKey.color = this.chartColor.color;
this.flotDataKey.color = this.chartColor;
}
}
this.showDate = this.settings.showDate;
this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat);
this.dateStyle = textStyle(this.settings.dateFont, '0.25px');
this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor);
this.dateColor = this.settings.dateColor;
this.backgroundStyle = backgroundStyle(this.settings.background);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
@ -188,17 +188,11 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
public onDataUpdated() {
const tsValue = getLatestSingleTsValue(this.ctx.data);
let ts;
let value;
if (tsValue) {
ts = tsValue[0];
value = tsValue[1];
}
this.subtitleColor.update(value);
this.dateColor.update(value);
if (this.showChart) {
this.chartColor.update(value);
this.flot.updateSeriesColor(this.chartColor.color);
this.flot.update();
}

View File

@ -24,7 +24,6 @@ import {
constantColor,
DateFormatSettings,
Font,
iconStyle,
lastUpdateAgoDateFormat,
textStyle
} from '@shared/models/widget-settings.models';
@ -36,13 +35,13 @@ export interface AggregatedValueCardWidgetSettings {
showSubtitle: boolean;
subtitle: string;
subtitleFont: Font;
subtitleColor: ColorSettings;
subtitleColor: string;
showDate: boolean;
dateFormat: DateFormatSettings;
dateFont: Font;
dateColor: ColorSettings;
dateColor: string;
showChart: boolean;
chartColor: ColorSettings;
chartColor: string;
background: BackgroundSettings;
}
@ -83,7 +82,8 @@ export interface AggregatedValueCardValue {
downArrow: boolean;
}
export const computeAggregatedCardValue = (dataKeys: DataKey[], keyName: string, position: AggregatedValueCardKeyPosition): AggregatedValueCardValue => {
export const computeAggregatedCardValue =
(dataKeys: DataKey[], keyName: string, position: AggregatedValueCardKeyPosition): AggregatedValueCardValue => {
const key = dataKeys.find(dataKey => ( dataKey.name === keyName && (dataKey.settings?.position === position ||
(!dataKey.settings?.position && position === AggregatedValueCardKeyPosition.center)) ));
if (key) {
@ -123,7 +123,7 @@ export const aggregatedValueCardDefaultSettings: AggregatedValueCardWidgetSettin
weight: '400',
lineHeight: '16px'
},
subtitleColor: constantColor('rgba(0, 0, 0, 0.38)'),
subtitleColor: 'rgba(0, 0, 0, 0.38)',
showDate: true,
dateFormat: lastUpdateAgoDateFormat(),
dateFont: {
@ -134,9 +134,9 @@ export const aggregatedValueCardDefaultSettings: AggregatedValueCardWidgetSettin
weight: '400',
lineHeight: '16px'
},
dateColor: constantColor('rgba(0, 0, 0, 0.38)'),
dateColor: 'rgba(0, 0, 0, 0.38)',
showChart: true,
chartColor: constantColor('rgba(0, 0, 0, 0.87)'),
chartColor: 'rgba(0, 0, 0, 0.87)',
background: {
type: BackgroundType.color,
color: '#fff',

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "../../../../../theme";
@import "../../../../../scss/constants";
:host {
.fields-group {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "../../../../../../theme";
@import "../../../../../../scss/constants";
:host ::ng-deep {
.mat-button-toggle-group.tb-notification-unread-toggle-group {

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
@import "../../../../../../scss/constants";
@import "../../../../../../theme";
:host {
form.tb-dialog-container {

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "../../../../../../theme";
@import "../../../../../../scss/constants";
:host {

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
@import "../../../../../../scss/constants";
@import "../../../../../../theme";
:host-context(.tb-fullscreen-dialog .mat-mdc-dialog-container) {
width: 820px;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "../../../../theme";
@import "../../../../scss/constants";
:host {
.mini-button {

View File

@ -18,6 +18,7 @@ import { Component, forwardRef, OnDestroy } from '@angular/core';
import { Color, ColorPickerControl } from '@iplab/ngx-color-picker';
import { Subscription } from 'rxjs';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms';
import { isString } from '@core/utils';
export enum ColorType {
hex = 'hex',
@ -87,8 +88,9 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy {
}
writeValue(value: string): void {
this.setValue = !!value;
this.control.setValueFrom(value || '#fff');
const valid = this.isValidColorValue(value);
this.setValue = valid;
this.control.setValueFrom(valid ? value : '#fff');
this.modelValue = value;
if (this.control.initType === ColorType.hexa) {
@ -101,6 +103,10 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy {
this.presentationControl.patchValue(this.presentations.indexOf(this.control.initType), {emitEvent: false});
}
private isValidColorValue(value: string): boolean {
return value && isString(value) && value.trim().length > 0;
}
private updateModel() {
const color: string = this.getValueByType(this.control.value, this.presentations[this.presentationControl.value]);
if (this.modelValue !== color) {

View File

@ -53,22 +53,24 @@
</ng-container>
</div>
</cdk-virtual-scroll-viewport>
<button *ngIf="!showAllSubject.value" class="tb-material-icons-show-more" mat-button color="primary" (click)="showAllSubject.next(true)">
{{ 'action.show-more' | translate }}
</button>
<ng-container *ngIf="notFound">
<div class="tb-no-data-available" [ngStyle]="{width: iconsPanelWidth}">
<div class="tb-no-data-bg"></div>
<div class="tb-no-data-text">{{ 'icon.no-icons-found' | translate:{iconSearch: searchIconControl.value} }}</div>
</div>
</ng-container>
<div *ngIf="iconClearButton" class="tb-material-icons-panel-buttons">
<button mat-button
<div class="tb-material-icons-panel-buttons" *ngIf="iconClearButton || !showAllSubject.value">
<button *ngIf="iconClearButton"
mat-button
color="primary"
type="button"
(click)="clearIcon()"
[disabled]="!selectedIcon">
{{ 'action.clear' | translate }}
</button>
<span fxFlex></span>
<button *ngIf="!showAllSubject.value" class="tb-material-icons-show-more" mat-button color="primary" (click)="showAllSubject.next(true)">
{{ 'action.show-more' | translate }}
</button>
</div>
</div>

View File

@ -26,7 +26,7 @@
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.87);
}
.tb-material-icons-title, .tb-material-icons-search, .tb-material-icons-show-more {
.tb-material-icons-title, .tb-material-icons-search {
width: 100%;
}
.tb-material-icons-viewport {
@ -64,6 +64,6 @@
flex-direction: row;
gap: 16px;
align-items: flex-start;
align-self: flex-start;
align-self: stretch;
}
}

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
@import "../../../theme";
@import "../../../scss/constants";
:host {

View File

@ -149,7 +149,7 @@ type ValueColorFunction = (value: any) => string;
export abstract class ColorProcessor {
static fromSettings(color: ColorSettings): ColorProcessor {
const settings = color || constantColor('rgba(0, 0, 0, 0.87)');
const settings = color || constantColor(null);
switch (settings.type) {
case ColorType.constant:
return new ConstantColorProcessor(settings);
@ -192,7 +192,7 @@ class RangeColorProcessor extends ColorProcessor {
if (this.settings.rangeList?.length && isDefinedAndNotNull(value) && isNumeric(value)) {
const num = Number(value);
for (const range of this.settings.rangeList) {
if (this.constantRange(range) && range.from === num) {
if (RangeColorProcessor.constantRange(range) && range.from === num) {
return range.color;
} else if ((!isNumber(range.from) || num >= range.from) && (!isNumber(range.to) || num < range.to)) {
return range.color;
@ -202,7 +202,7 @@ class RangeColorProcessor extends ColorProcessor {
return this.settings.color;
}
private constantRange(range: ColorRange): boolean {
private static constantRange(range: ColorRange): boolean {
return isNumber(range.from) && isNumber(range.to) && range.from === range.to;
}
}

View File

@ -5756,6 +5756,7 @@
"position-left-bottom": "Left bottom",
"font": "Font",
"color": "Color",
"arrow": "Arrow",
"display-up-down-arrow": "Display Up/Down arrow",
"add-value": "Add value",
"remove-value": "Remove value",

View File

@ -16,12 +16,16 @@
@import './scss/constants';
@mixin form-row-column($breakpoint) {
@mixin form-row-column() {
flex-direction: column;
align-items: stretch;
gap: 12px;
padding: 12px 7px 12px 16px;
}
@mixin form-row-column-breakpoint($breakpoint) {
@media #{$breakpoint} {
flex-direction: column;
align-items: stretch;
gap: 12px;
padding: 12px 7px 12px 16px;
@include form-row-column;
.mat-mdc-form-field, tb-unit-input {
width: auto;
&.medium-width {
@ -132,6 +136,16 @@
font-size: 12px;
color: #808080;
}
.tb-form-hint {
padding: 12px 16px;
font-size: var(--mdc-typography-caption-font-size, 12px);
line-height: var(--mdc-typography-caption-line-height, 20px);
font-weight: var(--mdc-typography-caption-font-weight, 400);
letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
color: rgba(0, 0, 0, 0.6);
white-space: normal;
border-radius: 6px;
}
.tb-form-row {
height: 100%;
display: flex;
@ -142,11 +156,12 @@
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 6px;
&.column {
@include form-row-column;
&-xs {
@include form-row-column($mat-xs)
@include form-row-column-breakpoint($mat-xs)
}
&-lt-md {
@include form-row-column($mat-lt-md)
@include form-row-column-breakpoint($mat-lt-md)
}
}
&.no-border {
@ -450,7 +465,7 @@
left: 0;
right: 0;
bottom: 0;
background: #305680;
background: $tb-primary-color;
mask-image: url(/assets/home/no_data_folder_bg.svg);
mask-repeat: no-repeat;
mask-size: contain;
@ -470,6 +485,23 @@
}
}
.tb-primary-fill {
position: relative;
overflow: hidden;
&:before {
display: block;
height: auto;
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: $tb-primary-color;
opacity: 0.04;
}
}
button.mat-mdc-button-base.tb-box-button, .tb-form-table-row-cell-buttons button.mat-mdc-icon-button.mat-mdc-button-base {
width: 40px;
min-width: 40px;

View File

@ -30,3 +30,10 @@ $mat-gt-xl: "screen and (min-width: 1920px)";
$mat-md-lg: "screen and (min-width: 960px) and (max-width: 1819px)";
$primary-hue-3: rgb(207, 216, 220) !default;
$tb-primary-color: #305680;
$tb-secondary-color: #527dad;
$tb-hue3-color: #a7c1de;
$tb-dark-primary-color: #9fa8da;

View File

@ -21,12 +21,6 @@
@include mat.all-component-typographies();
@include mat.core();
$tb-primary-color: #305680;
$tb-secondary-color: #527dad;
$tb-hue3-color: #a7c1de;
$tb-dark-primary-color: #9fa8da;
$tb-mat-indigo: (
50: #e8eaf6,
100: #c5cae9,