UI: Add deffinition for api usage

This commit is contained in:
ArtemDzhereleiko 2025-09-16 12:59:25 +03:00
parent 1bfb969245
commit 3d0f643e7a
8 changed files with 199 additions and 1867 deletions

View File

@ -50,6 +50,7 @@ $warning-color: #FAA405;
color: $enabled-color;
}
.mat-mdc-progress-bar {
--mdc-linear-progress-track-color: #{rgba($enabled-color, 0.06)};
--mdc-linear-progress-active-indicator-color: #{$enabled-color};
}
}
@ -58,6 +59,7 @@ $warning-color: #FAA405;
color: $disabled-color;
}
.mat-mdc-progress-bar {
--mdc-linear-progress-track-color: #{rgba($disabled-color, 0.06)};
--mdc-linear-progress-active-indicator-color: #{$disabled-color};
}
}
@ -66,6 +68,7 @@ $warning-color: #FAA405;
color: $warning-color;
}
.mat-mdc-progress-bar {
--mdc-linear-progress-track-color: #{rgba($warning-color, 0.06)};
--mdc-linear-progress-active-indicator-color: #{$warning-color};
}
}

View File

@ -20,16 +20,16 @@ import { backgroundStyle, ComponentStyle, overlayStyle } from '@shared/models/wi
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
import { DataKey, DatasourceType, widgetType } from "@shared/models/widget.models";
import { WidgetSubscriptionOptions } from "@core/api/widget-api.models";
import { formattedDataFormDatasourceData } from "@core/utils";
import { DatasourceType, widgetType } from '@shared/models/widget.models';
import { WidgetSubscriptionOptions } from '@core/api/widget-api.models';
import { formattedDataFormDatasourceData } from '@core/utils';
import { UtilsService } from "@core/services/utils.service";
import { UtilsService } from '@core/services/utils.service';
import {
ApiUsageDataKeysSettings,
apiUsageDefaultSettings,
ApiUsageWidgetSettings
} from "@home/components/widget/lib/settings/cards/api-usage-settings.component.models";
ApiUsageWidgetSettings,
getUniqueDataKeys
} from '@home/components/widget/lib/settings/cards/api-usage-settings.component.models';
@Component({
selector: 'tb-api-usage-widget',
@ -80,7 +80,7 @@ export class ApiUsageWidgetComponent implements OnInit, OnDestroy {
type: DatasourceType.entity,
name: '',
entityAliasId: this.settings.dsEntityAliasId,
dataKeys: this.getUniqueDataKeys(this.settings.dataKeys)
dataKeys: getUniqueDataKeys(this.settings.apiUsageDataKeys)
}
const apiUsageSubscriptionOptions: WidgetSubscriptionOptions = {
@ -122,7 +122,7 @@ export class ApiUsageWidgetComponent implements OnInit, OnDestroy {
}
parseApiUsages() {
this.settings.dataKeys.forEach((key) => {
this.settings.apiUsageDataKeys.forEach((key) => {
this.apiUsages.push({
label: this.utils.customTranslation(key.label, key.label),
state: key.state,
@ -134,20 +134,6 @@ export class ApiUsageWidgetComponent implements OnInit, OnDestroy {
})
}
getUniqueDataKeys(data: ApiUsageDataKeysSettings[]): DataKey[] {
const seenNames = new Set<string>();
return data
.flatMap(item => [item.status, item.maxLimit, item.current])
.filter(key => {
if (seenNames.has(key.name)) {
return false;
}
seenNames.add(key.name);
return true;
});
};
ngOnDestroy() {
if (this.contentResize$) {
this.contentResize$.disconnect();

View File

@ -17,10 +17,10 @@
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models';
import { DataKey, Widget, widgetType } from '@shared/models/widget.models';
import { Observable } from "rxjs";
import { BackgroundSettings, BackgroundType } from "@shared/models/widget-settings.models";
import { DataKeyType } from "@shared/models/telemetry/telemetry.models";
import { materialColors } from "@shared/models/material.models";
import { Observable } from 'rxjs';
import { BackgroundSettings, BackgroundType } from '@shared/models/widget-settings.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { materialColors } from '@shared/models/material.models';
export interface ApiUsageSettingsContext {
aliasController: IAliasController;
@ -33,7 +33,7 @@ export interface ApiUsageSettingsContext {
export interface ApiUsageWidgetSettings {
dsEntityAliasId: string;
dataKeys: ApiUsageDataKeysSettings[];
apiUsageDataKeys: ApiUsageDataKeysSettings[];
targetDashboardState: string;
background: BackgroundSettings;
padding: string;
@ -80,7 +80,7 @@ const generateDataKey = (label: string, status: string, maxLimit: string, curren
export const apiUsageDefaultSettings: ApiUsageWidgetSettings = {
dsEntityAliasId: '',
dataKeys: [
apiUsageDataKeys: [
generateDataKey('{i18n:api-usage.transport-messages}', 'transportApiState', 'transportMsgLimit', 'transportMsgCount'),
generateDataKey('{i18n:api-usage.transport-data-points}', 'transportApiState', 'transportDataPointsLimit', 'transportDataPointsCount'),
generateDataKey('{i18n:api-usage.rule-engine-executions}', 'ruleEngineApiState', 'ruleEngineExecutionLimit', 'ruleEngineExecutionCount'),
@ -104,3 +104,15 @@ export const apiUsageDefaultSettings: ApiUsageWidgetSettings = {
padding: '0'
};
export const getUniqueDataKeys = (data: ApiUsageDataKeysSettings[]): DataKey[] => {
const seenNames = new Set<string>();
return data
.flatMap(item => [item.status, item.maxLimit, item.current])
.filter(key => {
if (seenNames.has(key.name)) {
return false;
}
seenNames.add(key.name);
return true;
});
};

View File

@ -37,15 +37,15 @@ import {
ApiUsageDataKeysSettings,
apiUsageDefaultSettings,
ApiUsageSettingsContext
} from "@home/components/widget/lib/settings/cards/api-usage-settings.component.models";
import { deepClone } from "@core/utils";
import { Observable, of } from "rxjs";
} from '@home/components/widget/lib/settings/cards/api-usage-settings.component.models';
import { deepClone } from '@core/utils';
import { Observable, of } from 'rxjs';
import {
DataKeyConfigDialogComponent,
DataKeyConfigDialogData
} from "@home/components/widget/lib/settings/common/key/data-key-config-dialog.component";
import { MatDialog } from "@angular/material/dialog";
import { CdkDragDrop } from "@angular/cdk/drag-drop";
} from '@home/components/widget/lib/settings/common/key/data-key-config-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
@Component({
selector: 'tb-api-usage-widget-settings',
@ -82,11 +82,11 @@ export class ApiUsageWidgetSettingsComponent extends WidgetSettingsComponent {
}
protected doUpdateSettings(settingsForm: UntypedFormGroup, settings: WidgetSettings) {
settingsForm.setControl('dataKeys', this.prepareDataKeysFormArray(settings?.dataKeys), {emitEvent: false});
settingsForm.setControl('apiUsageDataKeys', this.prepareDataKeysFormArray(settings?.apiUsageDataKeys), {emitEvent: false});
}
dataKeysFormArray(): UntypedFormArray {
return this.apiUsageWidgetSettingsForm.get('dataKeys') as UntypedFormArray;
return this.apiUsageWidgetSettingsForm.get('apiUsageDataKeys') as UntypedFormArray;
}
trackByDataKey(index: number): any {
@ -104,7 +104,7 @@ export class ApiUsageWidgetSettingsComponent extends WidgetSettingsComponent {
}
removeDataKey(index: number) {
(this.apiUsageWidgetSettingsForm.get('dataKeys') as UntypedFormArray).removeAt(index);
(this.apiUsageWidgetSettingsForm.get('apiUsageDataKeys') as UntypedFormArray).removeAt(index);
}
addDataKey() {
@ -115,7 +115,7 @@ export class ApiUsageWidgetSettingsComponent extends WidgetSettingsComponent {
maxLimit: null,
current: null
};
const dataKeysArray = this.apiUsageWidgetSettingsForm.get('dataKeys') as UntypedFormArray;
const dataKeysArray = this.apiUsageWidgetSettingsForm.get('apiUsageDataKeys') as UntypedFormArray;
const dataKeyControl = this.fb.control(dataKey, [this.apiUsageDataKeyValidator()]);
dataKeysArray.push(dataKeyControl);
}
@ -131,7 +131,7 @@ export class ApiUsageWidgetSettingsComponent extends WidgetSettingsComponent {
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
dsEntityAliasId: settings?.dsEntityAliasId,
dataKeys: settings?.dataKeys,
apiUsageDataKeys: settings?.apiUsageDataKeys,
targetDashboardState: settings?.targetDashboardState,
background: settings?.background,
padding: settings.padding
@ -141,7 +141,7 @@ export class ApiUsageWidgetSettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) {
this.apiUsageWidgetSettingsForm = this.fb.group({
dsEntityAliasId: [settings?.dsEntityAliasId],
dataKeys: this.prepareDataKeysFormArray(settings?.dataKeys),
apiUsageDataKeys: this.prepareDataKeysFormArray(settings?.apiUsageDataKeys),
targetDashboardState: [settings?.targetDashboardState],
background: [settings?.background, []],
padding: [settings.padding, []]

View File

@ -0,0 +1,88 @@
///
/// Copyright © 2016-2025 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 { EntityAliases, EntityAliasInfo, getEntityAliasId } from '@shared/models/alias.models';
import { FilterInfo, Filters } from '@shared/models/query/query.models';
import { Dashboard } from '@shared/models/dashboard.models';
import { Datasource, DatasourceType, Widget } from '@shared/models/widget.models';
import { WidgetModelDefinition } from '@shared/models/widget/widget-model.definition';
import {
ApiUsageWidgetSettings,
getUniqueDataKeys
} from '@home/components/widget/lib/settings/cards/api-usage-settings.component.models';
interface AliasFilterPair {
alias?: EntityAliasInfo;
filter?: FilterInfo;
}
interface ApiUsageDatasourcesInfo {
ds?: AliasFilterPair;
}
export const ApiUsageModelDefinition: WidgetModelDefinition<ApiUsageDatasourcesInfo> = {
testWidget(widget: Widget): boolean {
if (widget?.config?.settings) {
const settings = widget.config.settings;
if (settings.apiUsageDataKeys && Array.isArray(settings.apiUsageDataKeys)) {
return true;
}
}
return false;
},
prepareExportInfo(dashboard: Dashboard, widget: Widget): ApiUsageDatasourcesInfo {
const settings: ApiUsageWidgetSettings = widget.config.settings as ApiUsageWidgetSettings;
const info: ApiUsageDatasourcesInfo = {};
if (settings.dsEntityAliasId) {
info.ds = prepareExportDataSourcesInfo(dashboard, settings.dsEntityAliasId);
}
return info;
},
updateFromExportInfo(widget: Widget, entityAliases: EntityAliases, filters: Filters, info: ApiUsageDatasourcesInfo): void {
const settings: ApiUsageWidgetSettings = widget.config.settings as ApiUsageWidgetSettings;
if (info?.ds?.alias) {
settings.dsEntityAliasId = getEntityAliasId(entityAliases, info.ds.alias);
}
},
datasources(widget: Widget): Datasource[] {
const settings: ApiUsageWidgetSettings = widget.config.settings as ApiUsageWidgetSettings;
const datasources: Datasource[] = [];
if (settings.apiUsageDataKeys?.length && settings.dsEntityAliasId) {
datasources.push({
type: DatasourceType.entity,
name: '',
entityAliasId: settings.dsEntityAliasId,
dataKeys: getUniqueDataKeys(settings.apiUsageDataKeys)
});
}
return datasources;
},
hasTimewindow(): boolean {
return false;
}
};
const prepareExportDataSourcesInfo = (dashboard: Dashboard, settings: string): AliasFilterPair => {
const aliasAndFilter: AliasFilterPair = {};
const entityAlias = dashboard.configuration.entityAliases[settings];
if (entityAlias) {
aliasAndFilter.alias = {
alias: entityAlias.alias,
filter: entityAlias.filter
};
}
return aliasAndFilter;
}

View File

@ -19,6 +19,7 @@ import { Dashboard } from '@shared/models/dashboard.models';
import { EntityAliases } from '@shared/models/alias.models';
import { Filters } from '@shared/models/query/query.models';
import { MapModelDefinition } from '@shared/models/widget/maps/map-model.definition';
import { ApiUsageModelDefinition } from '@shared/models/widget/home-widgets/api-usage-model.definition';
export interface WidgetModelDefinition<T = any> {
testWidget(widget: Widget): boolean;
@ -29,7 +30,8 @@ export interface WidgetModelDefinition<T = any> {
}
const widgetModelRegistry: WidgetModelDefinition[] = [
MapModelDefinition
MapModelDefinition,
ApiUsageModelDefinition
];
export const findWidgetModelDefinition = (widget: Widget): WidgetModelDefinition => {

File diff suppressed because it is too large Load Diff

View File

@ -9544,7 +9544,8 @@
"add-key": "Add key",
"no-key": "No key",
"delete-key": "Delete key",
"target-dashboard-state": "Target dashboard state"
"target-dashboard-state": "Target dashboard state",
"go-to-main-state": "Go to default view"
}
},
"color": {