Browse Source

Merge branch 'develop/3.5.2' of github.com:thingsboard/thingsboard into develop/3.5.2

pull/9100/head
Andrii Shvaika 3 years ago
parent
commit
4044baba82
  1. 8
      application/src/main/data/json/system/widget_bundles/cards.json
  2. 9
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  3. 4
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  4. 3
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.html
  5. 15
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss
  6. 26
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts
  7. 1
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html
  8. 13
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss
  9. 35
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html
  10. 18
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts
  11. 121
      ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html
  12. 2
      ui-ngx/src/app/modules/home/components/widget/config/datasources.component.scss
  13. 4
      ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html
  14. 23
      ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts
  15. 20
      ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts
  16. 65
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component.html
  17. 111
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component.ts
  18. 10
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  19. 2
      ui-ngx/src/app/modules/home/pages/admin/mail-server.component.scss
  20. 20
      ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts
  21. 2
      ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-header.component.scss
  22. 1
      ui-ngx/src/app/modules/home/pages/notification/recipient/recipient-notification-dialog.component.scss
  23. 1
      ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.scss
  24. 1
      ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss
  25. 2
      ui-ngx/src/app/shared/components/button/copy-button.component.scss
  26. 10
      ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts
  27. 12
      ui-ngx/src/app/shared/components/material-icons.component.html
  28. 4
      ui-ngx/src/app/shared/components/material-icons.component.scss
  29. 1
      ui-ngx/src/app/shared/components/toggle-header.component.scss
  30. 6
      ui-ngx/src/app/shared/models/widget-settings.models.ts
  31. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  32. 48
      ui-ngx/src/form.scss
  33. 7
      ui-ngx/src/scss/constants.scss
  34. 6
      ui-ngx/src/theme.scss

8
application/src/main/data/json/system/widget_bundles/cards.json

File diff suppressed because one or more lines are too long

9
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -31,7 +31,6 @@ import {
} from '@shared/models/dashboard.models';
import { deepClone, isDefined, isDefinedAndNotNull, isString, isUndefined } from '@core/utils';
import {
DataKey,
Datasource,
datasourcesHasOnlyComparisonAggregation,
DatasourceType,
@ -484,6 +483,14 @@ export class DashboardUtilsService {
return widgetsArray;
}
public isEmptyDashboard(dashboard: Dashboard): boolean {
if (dashboard?.configuration?.widgets) {
return Object.keys(dashboard?.configuration?.widgets).length === 0;
} else {
return true;
}
}
public addWidgetToLayout(dashboard: Dashboard,
targetState: string,
targetLayout: DashboardLayoutId,

4
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -71,7 +71,6 @@ import { MediaBreakpoints } from '@shared/models/constants';
import { AuthUser } from '@shared/models/user.model';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import {
DatasourceType,
Widget,
WidgetConfig,
WidgetInfo,
@ -415,6 +414,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
this.updateLayoutSizes();
});
this.dashboardResize$.observe(this.dashboardContainer.nativeElement);
if (!this.widgetEditMode && !this.readonly && this.dashboardUtils.isEmptyDashboard(this.dashboard)) {
this.setEditMode(true, false);
}
}
private init(data: DashboardPageInitData) {

3
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.html

@ -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

15
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss

@ -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 {

26
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts

@ -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);

1
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html

@ -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">

13
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss

@ -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 {

35
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html

@ -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

18
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts

@ -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, color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }
],
createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³')
);
@ -141,7 +141,9 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
dateColor: [settings.dateColor, []],
showChart: [settings.showChart, []],
chartColor: [settings.chartColor, []],
chartUnits: [dataKey?.units, []],
chartDecimals: [dataKey?.decimals, []],
chartColor: [dataKey?.color, []],
values: [this.getValues(configData.config.datasources, keyName), []],
@ -181,7 +183,13 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo
this.widgetConfig.config.settings.dateColor = config.dateColor;
this.widgetConfig.config.settings.showChart = config.showChart;
this.widgetConfig.config.settings.chartColor = config.chartColor;
const dataKey = getDataKey(this.widgetConfig.config.datasources);
if (dataKey) {
dataKey.units = config.chartUnits;
dataKey.decimals = config.chartDecimals;
dataKey.color = config.chartColor;
}
this.setValues(config.values, this.widgetConfig.config.datasources);
@ -253,8 +261,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();
}
}

121
ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html

@ -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">

2
ui-ngx/src/app/modules/home/components/widget/config/datasources.component.scss

@ -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 {

4
ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html

@ -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">

23
ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts

@ -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,18 @@ 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;
showDate = true;
dateFormat: DateFormatProcessor;
dateStyle: ComponentStyle = {};
dateColor: ColorProcessor;
dateColor: string;
backgroundStyle: ComponentStyle = {};
overlayStyle: ComponentStyle = {};
@ -108,7 +107,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 +122,6 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
}
this.showChart = this.settings.showChart;
this.chartColor = ColorProcessor.fromSettings(this.settings.chartColor);
if (this.showChart) {
if (this.ctx.defaultSubscription.firstDatasource?.dataKeys?.length) {
this.flotDataKey = this.ctx.defaultSubscription.firstDatasource?.dataKeys[0];
@ -132,14 +130,13 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit
showLines: true,
lineWidth: 2
} as TbFlotKeySettings;
this.flotDataKey.color = this.chartColor.color;
}
}
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 +185,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();
}

20
ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts

@ -24,7 +24,6 @@ import {
constantColor,
DateFormatSettings,
Font,
iconStyle,
lastUpdateAgoDateFormat,
textStyle
} from '@shared/models/widget-settings.models';
@ -36,13 +35,12 @@ 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;
background: BackgroundSettings;
}
@ -83,7 +81,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 +122,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 +133,8 @@ 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)'),
background: {
type: BackgroundType.color,
color: '#fff',
@ -164,7 +162,7 @@ export const aggregatedValueCardDefaultKeySettings: AggregatedValueCardKeySettin
export const createDefaultAggregatedValueLatestDataKeys = (keyName: string, units): DataKey[] => [
{
name: keyName, label: keyName, type: DataKeyType.timeseries, units, decimals: 0,
name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals: 0,
aggregationType: AggregationType.NONE,
settings: {
position: AggregatedValueCardKeyPosition.center,
@ -181,7 +179,7 @@ export const createDefaultAggregatedValueLatestDataKeys = (keyName: string, unit
} as AggregatedValueCardKeySettings
},
{
name: keyName, label: 'Delta percent ' + keyName, type: DataKeyType.timeseries, units: '%', decimals: 0,
name: keyName, label: 'Delta percent', type: DataKeyType.timeseries, units: '%', decimals: 0,
aggregationType: AggregationType.AVG,
comparisonEnabled: true,
timeForComparison: 'previousInterval',
@ -210,7 +208,7 @@ export const createDefaultAggregatedValueLatestDataKeys = (keyName: string, unit
} as AggregatedValueCardKeySettings
},
{
name: keyName, label: 'Delta absolute ' + keyName, type: DataKeyType.timeseries, units, decimals: 1,
name: keyName, label: 'Delta absolute', type: DataKeyType.timeseries, units, decimals: 1,
aggregationType: AggregationType.AVG,
comparisonEnabled: true,
timeForComparison: 'previousInterval',

65
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component.html

@ -0,0 +1,65 @@
<!--
Copyright © 2016-2023 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.
-->
<ng-container [formGroup]="aggregatedValueCardWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.aggregated-value-card.aggregated-value-card-style</div>
<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>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="subtitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="subtitleFont"
clearButton
[previewText]="aggregatedValueCardWidgetSettingsForm.get('subtitle').value">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="subtitleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showDate">
{{ 'widgets.value-card.date' | translate }}
</mat-slide-toggle>
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-date-format-select fxFlex formControlName="dateFormat"></tb-date-format-select>
<tb-font-settings formControlName="dateFont"
[previewText]="datePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="dateColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showChart">
{{ 'widgets.aggregated-value-card.chart' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

111
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component.ts

@ -0,0 +1,111 @@
///
/// Copyright © 2016-2023 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, Injector } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
import { aggregatedValueCardDefaultSettings } from '@home/components/widget/lib/cards/aggregated-value-card.models';
@Component({
selector: 'tb-aggregated-value-card-widget-settings',
templateUrl: './aggregated-value-card-widget-settings.component.html',
styleUrls: []
})
export class AggregatedValueCardWidgetSettingsComponent extends WidgetSettingsComponent {
aggregatedValueCardWidgetSettingsForm: UntypedFormGroup;
datePreviewFn = this._datePreviewFn.bind(this);
constructor(protected store: Store<AppState>,
private $injector: Injector,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.aggregatedValueCardWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {...aggregatedValueCardDefaultSettings};
}
protected onSettingsSet(settings: WidgetSettings) {
this.aggregatedValueCardWidgetSettingsForm = this.fb.group({
showSubtitle: [settings.showSubtitle, []],
subtitle: [settings.subtitle, []],
subtitleFont: [settings.subtitleFont, []],
subtitleColor: [settings.subtitleColor, []],
showDate: [settings.showDate, []],
dateFormat: [settings.dateFormat, []],
dateFont: [settings.dateFont, []],
dateColor: [settings.dateColor, []],
showChart: [settings.showChart, []],
background: [settings.background, []]
});
}
protected validatorTriggers(): string[] {
return ['showSubtitle', 'showDate'];
}
protected updateValidators(emitEvent: boolean) {
const showSubtitle: boolean = this.aggregatedValueCardWidgetSettingsForm.get('showSubtitle').value;
const showDate: boolean = this.aggregatedValueCardWidgetSettingsForm.get('showDate').value;
if (showSubtitle) {
this.aggregatedValueCardWidgetSettingsForm.get('subtitle').enable();
this.aggregatedValueCardWidgetSettingsForm.get('subtitleFont').enable();
this.aggregatedValueCardWidgetSettingsForm.get('subtitleColor').enable();
} else {
this.aggregatedValueCardWidgetSettingsForm.get('subtitle').disable();
this.aggregatedValueCardWidgetSettingsForm.get('subtitleFont').disable();
this.aggregatedValueCardWidgetSettingsForm.get('subtitleColor').disable();
}
if (showDate) {
this.aggregatedValueCardWidgetSettingsForm.get('dateFormat').enable();
this.aggregatedValueCardWidgetSettingsForm.get('dateFont').enable();
this.aggregatedValueCardWidgetSettingsForm.get('dateColor').enable();
} else {
this.aggregatedValueCardWidgetSettingsForm.get('dateFormat').disable();
this.aggregatedValueCardWidgetSettingsForm.get('dateFont').disable();
this.aggregatedValueCardWidgetSettingsForm.get('dateColor').disable();
}
this.aggregatedValueCardWidgetSettingsForm.get('subtitle').updateValueAndValidity({emitEvent});
this.aggregatedValueCardWidgetSettingsForm.get('subtitleFont').updateValueAndValidity({emitEvent});
this.aggregatedValueCardWidgetSettingsForm.get('subtitleColor').updateValueAndValidity({emitEvent});
this.aggregatedValueCardWidgetSettingsForm.get('dateFormat').updateValueAndValidity({emitEvent});
this.aggregatedValueCardWidgetSettingsForm.get('dateFont').updateValueAndValidity({emitEvent});
this.aggregatedValueCardWidgetSettingsForm.get('dateColor').updateValueAndValidity({emitEvent});
}
private _datePreviewFn(): string {
const dateFormat: DateFormatSettings = this.aggregatedValueCardWidgetSettingsForm.get('dateFormat').value;
const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat);
processor.update(Date.now());
return processor.formatted;
}
}

10
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -270,6 +270,9 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings
import {
AggregatedValueCardKeySettingsComponent
} from '@home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component';
import {
AggregatedValueCardWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component';
@NgModule({
declarations: [
@ -370,7 +373,8 @@ import {
DocLinksWidgetSettingsComponent,
QuickLinksWidgetSettingsComponent,
ValueCardWidgetSettingsComponent,
AggregatedValueCardKeySettingsComponent
AggregatedValueCardKeySettingsComponent,
AggregatedValueCardWidgetSettingsComponent
],
imports: [
CommonModule,
@ -476,7 +480,8 @@ import {
DocLinksWidgetSettingsComponent,
QuickLinksWidgetSettingsComponent,
ValueCardWidgetSettingsComponent,
AggregatedValueCardKeySettingsComponent
AggregatedValueCardKeySettingsComponent,
AggregatedValueCardWidgetSettingsComponent
]
})
export class WidgetSettingsModule {
@ -548,4 +553,5 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-quick-links-widget-settings': QuickLinksWidgetSettingsComponent,
'tb-value-card-widget-settings': ValueCardWidgetSettingsComponent,
'tb-aggregated-value-card-key-settings': AggregatedValueCardKeySettingsComponent,
'tb-aggregated-value-card-widget-settings': AggregatedValueCardWidgetSettingsComponent
};

2
ui-ngx/src/app/modules/home/pages/admin/mail-server.component.scss

@ -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 {

20
ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts

@ -103,9 +103,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
this.config.deleteEntitiesContent = () => this.translate.instant('dashboard.delete-dashboards-text');
this.config.loadEntity = id => this.dashboardService.getDashboard(id.id);
this.config.saveEntity = dashboard => {
return this.dashboardService.saveDashboard(dashboard as Dashboard);
};
this.config.saveEntity = dashboard => this.dashboardService.saveDashboard(dashboard as Dashboard);
this.config.onEntityAction = action => this.onDashboardAction(action);
this.config.detailsReadonly = () => (this.config.componentsData.dashboardScope === 'customer_user' ||
this.config.componentsData.dashboardScope === 'edge_customer_user');
@ -118,6 +116,10 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
}
return true;
};
this.config.entityAdded = dashboard => {
this.openDashboard(null, dashboard);
};
}
resolve(route: ActivatedRouteSnapshot): Observable<EntityTableConfig<DashboardInfo | Dashboard>> {
@ -178,13 +180,9 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
if (dashboardScope === 'tenant') {
columns.push(
new EntityTableColumn<DashboardInfo>('customersTitle', 'dashboard.assignedToCustomers',
'50%', entity => {
return getDashboardAssignedCustomersText(entity);
}, () => ({}), false),
'50%', entity => getDashboardAssignedCustomersText(entity), () => ({}), false),
new EntityTableColumn<DashboardInfo>('dashboardIsPublic', 'dashboard.public', '60px',
entity => {
return checkBoxCell(isPublicDashboard(entity));
}, () => ({}), false),
entity => checkBoxCell(isPublicDashboard(entity)), () => ({}), false),
);
}
return columns;
@ -269,7 +267,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
{
name: this.translate.instant('edge.unassign-from-edge'),
icon: 'assignment_return',
isEnabled: (entity) => true,
isEnabled: () => true,
onAction: ($event, entity) => this.unassignFromEdge($event, entity)
}
);
@ -383,7 +381,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
}
}
importDashboard($event: Event) {
importDashboard(_$event: Event) {
this.importExport.importDashboard().subscribe(
(dashboard) => {
if (dashboard) {

2
ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-header.component.scss

@ -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 {

1
ui-ngx/src/app/modules/home/pages/notification/recipient/recipient-notification-dialog.component.scss

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

1
ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.scss

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

1
ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss

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

2
ui-ngx/src/app/shared/components/button/copy-button.component.scss

@ -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 {

10
ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts

@ -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) {

12
ui-ngx/src/app/shared/components/material-icons.component.html

@ -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>

4
ui-ngx/src/app/shared/components/material-icons.component.scss

@ -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;
}
}

1
ui-ngx/src/app/shared/components/toggle-header.component.scss

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

6
ui-ngx/src/app/shared/models/widget-settings.models.ts

@ -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;
}
}

4
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -5769,11 +5769,13 @@
"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",
"no-values": "No values configured",
"aggregation": "Aggregation"
"aggregation": "Aggregation",
"aggregated-value-card-style": "Aggregated value card style"
},
"table": {
"common-table-settings": "Common Table Settings",

48
ui-ngx/src/form.scss

@ -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;

7
ui-ngx/src/scss/constants.scss

@ -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;

6
ui-ngx/src/theme.scss

@ -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,

Loading…
Cancel
Save