Merge branch 'master' into add-admin-settings-entity-type

This commit is contained in:
Viacheslav Klimov 2025-07-16 17:12:31 +03:00 committed by GitHub
commit 7a78278016
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 246 additions and 177 deletions

View File

@ -28,9 +28,9 @@
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar> </mat-progress-bar>
<div mat-dialog-content> <div mat-dialog-content>
<fieldset class="tb-form-panel no-padding no-border no-gap" [disabled]="isLoading$ | async"> <fieldset class="tb-form-panel outlined" [disabled]="isLoading$ | async">
<div class="tb-form-row column-xs align-start no-border no-gap no-padding tb-standard-fields"> <div class="flex flex-row items-start xs:flex-col xs:items-stretch">
<mat-form-field class="flex"> <mat-form-field class="flex-1" appearance="outline">
<mat-label translate>alias.name</mat-label> <mat-label translate>alias.name</mat-label>
<input matInput formControlName="alias" required> <input matInput formControlName="alias" required>
<mat-error *ngIf="entityAliasFormGroup.get('alias').hasError('required')"> <mat-error *ngIf="entityAliasFormGroup.get('alias').hasError('required')">

View File

@ -19,7 +19,7 @@
.tb-resolve-multiple-switch { .tb-resolve-multiple-switch {
padding: 18px 0 0 18px; padding: 18px 0 0 18px;
@media #{$mat-xs} { @media #{$mat-xs} {
padding: 0 0 18px 0; padding: 0 0 22px 0;
} }
} }
} }

View File

@ -38,14 +38,14 @@
<span style="min-width: 80px;"></span> <span style="min-width: 80px;"></span>
</div> </div>
</div> </div>
<fieldset [disabled]="isLoading$ | async"> <fieldset [disabled]="isLoading$ | async" class="tb-form-panel outlined">
<mat-divider></mat-divider> <mat-divider></mat-divider>
<div class="flex flex-1 flex-row items-center justify-start" <div class="flex flex-1 flex-row items-center justify-start"
formArrayName="entityAliases" formArrayName="entityAliases"
*ngFor="let entityAliasControl of entityAliasesFormArray().controls; let $index = index"> *ngFor="let entityAliasControl of entityAliasesFormArray().controls; let $index = index">
<span class="max-w-5% flex-full">{{$index + 1}}.</span> <span class="max-w-5% flex-full">{{$index + 1}}.</span>
<div class="mat-elevation-z4 tb-alias flex max-w-95% flex-full flex-row items-center justify-start"> <div class="mat-elevation-z4 tb-alias flex max-w-95% flex-full flex-row items-center justify-start">
<mat-form-field class="mat-block flex-1 gt-sm:min-w-52 gt-sm:max-w-52 gt-sm:basis-52" style="padding-top: 20px;"> <mat-form-field class="mat-block flex-1 gt-sm:min-w-52 gt-sm:max-w-52 gt-sm:basis-52" style="padding-top: 20px;" appearance="outline">
<input matInput [formControl]="entityAliasControl.get('alias')" required placeholder="{{ 'entity.alias' | translate }}"> <input matInput [formControl]="entityAliasControl.get('alias')" required placeholder="{{ 'entity.alias' | translate }}">
<mat-error *ngIf="entityAliasControl.get('alias').hasError('required')"> <mat-error *ngIf="entityAliasControl.get('alias').hasError('required')">
{{ 'entity.alias-required' | translate }} {{ 'entity.alias-required' | translate }}

View File

@ -15,8 +15,8 @@
limitations under the License. limitations under the License.
--> -->
<div [formGroup]="entityFilterFormGroup" class="tb-entity-filter flex flex-col"> <div [formGroup]="entityFilterFormGroup" class="tb-entity-filter">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>alias.filter-type</mat-label> <mat-label translate>alias.filter-type</mat-label>
<mat-select required formControlName="type"> <mat-select required formControlName="type">
<mat-option *ngFor="let type of aliasFilterTypes" [value]="type"> <mat-option *ngFor="let type of aliasFilterTypes" [value]="type">
@ -30,18 +30,21 @@
<section class="flex flex-col" [formGroup]="filterFormGroup" [ngSwitch]="entityFilterFormGroup.get('type').value"> <section class="flex flex-col" [formGroup]="filterFormGroup" [ngSwitch]="entityFilterFormGroup.get('type').value">
<ng-template [ngSwitchCase]="aliasFilterType.singleEntity"> <ng-template [ngSwitchCase]="aliasFilterType.singleEntity">
<tb-entity-select required <tb-entity-select required
appearance="outline"
useAliasEntityTypes="true" useAliasEntityTypes="true"
formControlName="singleEntity"> formControlName="singleEntity">
</tb-entity-select> </tb-entity-select>
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.entityList"> <ng-template [ngSwitchCase]="aliasFilterType.entityList">
<tb-entity-type-select required <tb-entity-type-select required
appearance="outline"
showLabel showLabel
useAliasEntityTypes="true" useAliasEntityTypes="true"
[allowedEntityTypes]="listEntityTypes" [allowedEntityTypes]="listEntityTypes"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>
<tb-entity-list required <tb-entity-list required
appearance="outline"
labelText="{{'entity.entity-list' | translate}}" labelText="{{'entity.entity-list' | translate}}"
[entityType]="filterFormGroup.get('entityType').value" [entityType]="filterFormGroup.get('entityType').value"
formControlName="entityList"> formControlName="entityList">
@ -49,12 +52,13 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.entityName"> <ng-template [ngSwitchCase]="aliasFilterType.entityName">
<tb-entity-type-select required <tb-entity-type-select required
appearance="outline"
showLabel showLabel
useAliasEntityTypes="true" useAliasEntityTypes="true"
[allowedEntityTypes]="listEntityTypes" [allowedEntityTypes]="listEntityTypes"
formControlName="entityType"> formControlName="entityType">
</tb-entity-type-select> </tb-entity-type-select>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>entity.name-starts-with</mat-label> <mat-label translate>entity.name-starts-with</mat-label>
<mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;" <mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;"
matTooltip="{{'entity.help-text' | translate }}">help</mat-icon> matTooltip="{{'entity.help-text' | translate }}">help</mat-icon>
@ -66,6 +70,7 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.entityType"> <ng-template [ngSwitchCase]="aliasFilterType.entityType">
<tb-entity-type-select required <tb-entity-type-select required
appearance="outline"
showLabel showLabel
useAliasEntityTypes="true" useAliasEntityTypes="true"
[allowedEntityTypes]="listEntityTypes" [allowedEntityTypes]="listEntityTypes"
@ -73,14 +78,14 @@
</tb-entity-type-select> </tb-entity-type-select>
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.stateEntity"> <ng-template [ngSwitchCase]="aliasFilterType.stateEntity">
<mat-form-field floatLabel="always" class="mat-block"> <mat-form-field floatLabel="always" class="mat-block" appearance="outline">
<mat-label translate>alias.state-entity-parameter-name</mat-label> <mat-label translate>alias.state-entity-parameter-name</mat-label>
<input matInput formControlName="stateEntityParamName" <input matInput formControlName="stateEntityParamName"
placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"> placeholder="{{ 'alias.default-entity-parameter-name' | translate }}">
</mat-form-field> </mat-form-field>
<div class="flex flex-col"> <div class="tb-form-panel stroked no-padding-bottom">
<label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label> <div class="tb-form-panel-title tb-normal">{{ 'alias.default-state-entity' | translate }}</div>
<tb-entity-select class="flex-1" <tb-entity-select appearance="outline"
useAliasEntityTypes="true" useAliasEntityTypes="true"
formControlName="defaultStateEntity"> formControlName="defaultStateEntity">
</tb-entity-select> </tb-entity-select>
@ -88,10 +93,13 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.assetType"> <ng-template [ngSwitchCase]="aliasFilterType.assetType">
<tb-entity-subtype-list required <tb-entity-subtype-list required
floatLabel="always"
appearance="outline"
label="{{ 'asset.asset-types' | translate }}"
[entityType]="entityType.ASSET" [entityType]="entityType.ASSET"
formControlName="assetTypes"> formControlName="assetTypes">
</tb-entity-subtype-list> </tb-entity-subtype-list>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>asset.name-starts-with</mat-label> <mat-label translate>asset.name-starts-with</mat-label>
<mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;" <mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;"
matTooltip="{{'asset.help-text' | translate }}">help</mat-icon> matTooltip="{{'asset.help-text' | translate }}">help</mat-icon>
@ -100,10 +108,13 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.deviceType"> <ng-template [ngSwitchCase]="aliasFilterType.deviceType">
<tb-entity-subtype-list required <tb-entity-subtype-list required
floatLabel="always"
appearance="outline"
label="{{ 'device.device-types' | translate }}"
[entityType]="entityType.DEVICE" [entityType]="entityType.DEVICE"
formControlName="deviceTypes"> formControlName="deviceTypes">
</tb-entity-subtype-list> </tb-entity-subtype-list>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>device.name-starts-with</mat-label> <mat-label translate>device.name-starts-with</mat-label>
<mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;" <mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;"
matTooltip="{{'device.help-text' | translate }}">help</mat-icon> matTooltip="{{'device.help-text' | translate }}">help</mat-icon>
@ -112,10 +123,13 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.entityViewType"> <ng-template [ngSwitchCase]="aliasFilterType.entityViewType">
<tb-entity-subtype-list required <tb-entity-subtype-list required
floatLabel="always"
appearance="outline"
label="{{ 'entity-view.entity-view-types' | translate }}"
[entityType]="entityType.ENTITY_VIEW" [entityType]="entityType.ENTITY_VIEW"
formControlName="entityViewTypes"> formControlName="entityViewTypes">
</tb-entity-subtype-list> </tb-entity-subtype-list>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>entity-view.name-starts-with</mat-label> <mat-label translate>entity-view.name-starts-with</mat-label>
<mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;" <mat-icon class="mat-primary" aria-hidden="false" aria-label="help-icon" matSuffix style="cursor:pointer;"
matTooltip="{{'entity-view.help-text' | translate }}">help</mat-icon> matTooltip="{{'entity-view.help-text' | translate }}">help</mat-icon>
@ -124,36 +138,51 @@
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.edgeType"> <ng-template [ngSwitchCase]="aliasFilterType.edgeType">
<tb-entity-subtype-list required <tb-entity-subtype-list required
floatLabel="always"
appearance="outline"
label="{{ 'edge.edge-types' | translate }}"
[entityType]="entityType.EDGE" [entityType]="entityType.EDGE"
formControlName="edgeTypes"> formControlName="edgeTypes">
</tb-entity-subtype-list> </tb-entity-subtype-list>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block" appearance="outline">
<mat-label translate>edge.name-starts-with</mat-label> <mat-label translate>edge.name-starts-with</mat-label>
<input matInput formControlName="edgeNameFilter"> <input matInput formControlName="edgeNameFilter">
</mat-form-field> </mat-form-field>
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.relationsQuery"> <ng-template [ngSwitchCase]="aliasFilterType.relationsQuery">
<section class="tb-form-panel no-border no-padding"> <section class="tb-form-panel no-border no-padding">
<div class="tb-form-panel stroked no-gap"> <div class="tb-form-panel stroked" [class.no-padding-bottom]="!filterFormGroup.get('rootStateEntity').value">
<div class="tb-form-panel-title" translate>alias.root-entity</div> <div class="tb-form-panel-title" translate>alias.root-entity</div>
<mat-slide-toggle class="mat-slide margin" formControlName="rootStateEntity"> <mat-slide-toggle class="mat-slide" formControlName="rootStateEntity">
{{ 'alias.root-state-entity' | translate }} {{ 'alias.root-state-entity' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div *ngIf="filterFormGroup.get('rootStateEntity').value" class="tb-form-panel no-border no-padding no-gap"> @if (filterFormGroup.get('rootStateEntity').value) {
<mat-form-field> <div class="tb-form-panel no-border no-padding no-gap">
<mat-label translate>alias.state-entity-parameter-name</mat-label> <mat-form-field floatLabel="always" class="mat-block" appearance="outline">
<input matInput formControlName="stateEntityParamName"> <mat-label translate>alias.state-entity-parameter-name</mat-label>
</mat-form-field> <input matInput formControlName="stateEntityParamName"
<tb-entity-select useAliasEntityTypes="true" formControlName="defaultStateEntity"> placeholder="{{ 'alias.default-entity-parameter-name' | translate }}">
</mat-form-field>
<div class="tb-form-panel stroked no-padding-bottom">
<div class="tb-form-panel-title tb-normal">{{ 'alias.default-state-entity' | translate }}</div>
<tb-entity-select appearance="outline"
useAliasEntityTypes="true"
formControlName="defaultStateEntity">
</tb-entity-select>
</div>
</div>
} @else {
<tb-entity-select required
appearance="outline"
useAliasEntityTypes="true"
formControlName="rootEntity">
</tb-entity-select> </tb-entity-select>
</div> }
<tb-entity-select *ngIf="!filterFormGroup.get('rootStateEntity').value" </div>
required <div class="tb-form-panel stroked">
useAliasEntityTypes="true" <div class="tb-form-panel-title" translate>alias.query-options</div>
formControlName="rootEntity"> <div class="flex flex-row gap-4">
</tb-entity-select> <mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<div class="tb-form-row no-border no-padding tb-standard-fields">
<mat-form-field class="flex">
<mat-label translate>relation.direction</mat-label> <mat-label translate>relation.direction</mat-label>
<mat-select required formControlName="direction"> <mat-select required formControlName="direction">
<mat-option *ngFor="let type of directionTypes" [value]="type"> <mat-option *ngFor="let type of directionTypes" [value]="type">
@ -161,7 +190,7 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="flex" floatLabel="always"> <mat-form-field class="flex-1" floatLabel="always" appearance="outline" subscriptSizing="dynamic">
<mat-label translate>alias.max-relation-level</mat-label> <mat-label translate>alias.max-relation-level</mat-label>
<input matInput <input matInput
type="number" type="number"
@ -172,7 +201,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<mat-slide-toggle *ngIf="filterFormGroup.get('maxLevel').value > 1 || !filterFormGroup.get('maxLevel').value" <mat-slide-toggle *ngIf="filterFormGroup.get('maxLevel').value > 1 || !filterFormGroup.get('maxLevel').value"
class="mat-slide" formControlName="fetchLastLevelOnly"> class="mat-slide" formControlName="fetchLastLevelOnly">
{{ 'alias.last-level-relation' | translate }} {{ 'alias.last-level-relation' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
</div> </div>
@ -191,98 +220,113 @@
entityFilterFormGroup.get('type').value === aliasFilterType.edgeSearchQuery || entityFilterFormGroup.get('type').value === aliasFilterType.edgeSearchQuery ||
entityFilterFormGroup.get('type').value === aliasFilterType.entityViewSearchQuery ? entityFilterFormGroup.get('type').value === aliasFilterType.entityViewSearchQuery ?
entityFilterFormGroup.get('type').value : ''"> entityFilterFormGroup.get('type').value : ''">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label> <section class="tb-form-panel no-border no-padding">
<section class="tb-root-state-entity-switch flex flex-row items-center justify-start" style="padding-left: 0;"> <div class="tb-form-panel stroked" [class.no-padding-bottom]="!filterFormGroup.get('rootStateEntity').value">
<mat-slide-toggle class="root-state-entity-switch" <div class="tb-form-panel-title" translate>alias.root-entity</div>
formControlName="rootStateEntity"> <mat-slide-toggle class="mat-slide" formControlName="rootStateEntity">
</mat-slide-toggle> {{ 'alias.root-state-entity' | translate }}
<label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
</section>
<div class="flex flex-1 flex-row" *ngIf="!filterFormGroup.get('rootStateEntity').value">
<tb-entity-select class="flex-1"
required
useAliasEntityTypes="true"
formControlName="rootEntity">
</tb-entity-select>
</div>
<div class="flex flex-1 flex-col gt-sm:flex-row" *ngIf="filterFormGroup.get('rootStateEntity').value">
<mat-form-field floatLabel="always" class="mat-block" style="margin-top: 24px; padding-right: 8px;">
<mat-label translate>alias.state-entity-parameter-name</mat-label>
<input matInput formControlName="stateEntityParamName"
placeholder="{{ 'alias.default-entity-parameter-name' | translate }}">
</mat-form-field>
<div class="flex flex-1 flex-col">
<label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
<tb-entity-select class="flex-1"
useAliasEntityTypes="true"
formControlName="defaultStateEntity">
</tb-entity-select>
</div>
</div>
<div class="flex flex-1 flex-row">
<section class="tb-root-state-entity-switch flex flex-row items-center justify-start" style="padding-left: 0;">
<mat-slide-toggle class="root-state-entity-switch"
formControlName="fetchLastLevelOnly">
</mat-slide-toggle> </mat-slide-toggle>
<label class="tb-small root-state-entity-label" translate>alias.last-level-relation</label> @if (filterFormGroup.get('rootStateEntity').value) {
</section> <div class="tb-form-panel no-border no-padding no-gap">
</div> <mat-form-field floatLabel="always" class="mat-block" appearance="outline">
<div class="flex flex-1 flex-row gap-2 xs:flex-col"> <mat-label translate>alias.state-entity-parameter-name</mat-label>
<mat-form-field class="mat-block" style="min-width: 100px;"> <input matInput formControlName="stateEntityParamName"
<mat-label translate>relation.direction</mat-label> placeholder="{{ 'alias.default-entity-parameter-name' | translate }}">
<mat-select required formControlName="direction"> </mat-form-field>
<mat-option *ngFor="let type of directionTypes" [value]="type"> <div class="tb-form-panel stroked no-padding-bottom">
{{ directionTypeTranslations.get(directionTypeEnum[type]) | translate }} <div class="tb-form-panel-title tb-normal">{{ 'alias.default-state-entity' | translate }}</div>
</mat-option> <tb-entity-select appearance="outline"
</mat-select> useAliasEntityTypes="true"
</mat-form-field> formControlName="defaultStateEntity">
<mat-form-field floatLabel="always" class="mat-block flex-1"> </tb-entity-select>
<mat-label translate>alias.max-relation-level</mat-label> </div>
<input matInput </div>
type="number" } @else {
min="1" <tb-entity-select required
step="1" appearance="outline"
placeholder="{{ 'alias.unlimited-level' | translate }}" useAliasEntityTypes="true"
formControlName="maxLevel"> formControlName="rootEntity">
</mat-form-field> </tb-entity-select>
</div> }
<div class="mat-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-type</div> </div>
<tb-relation-type-autocomplete <div class="tb-form-panel stroked">
class="flex-1" <div class="tb-form-panel-title" translate>alias.query-options</div>
formControlName="relationType"> <div class="flex flex-row gap-4">
</tb-relation-type-autocomplete> <mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
</ng-template> <mat-label translate>relation.direction</mat-label>
<ng-template [ngSwitchCase]="aliasFilterType.assetSearchQuery"> <mat-select required formControlName="direction">
<div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>asset.asset-types</div> <mat-option *ngFor="let type of directionTypes" [value]="type">
<tb-entity-subtype-list {{ directionTypeTranslations.get(directionTypeEnum[type]) | translate }}
required </mat-option>
[entityType]="entityType.ASSET" </mat-select>
formControlName="assetTypes"> </mat-form-field>
</tb-entity-subtype-list> <mat-form-field class="flex-1" floatLabel="always" appearance="outline" subscriptSizing="dynamic">
</ng-template> <mat-label translate>alias.max-relation-level</mat-label>
<ng-template [ngSwitchCase]="aliasFilterType.deviceSearchQuery"> <input matInput
<div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>device.device-types</div> type="number"
<tb-entity-subtype-list min="1"
required step="1"
[entityType]="entityType.DEVICE" placeholder="{{ 'alias.unlimited-level' | translate }}"
formControlName="deviceTypes"> formControlName="maxLevel">
</tb-entity-subtype-list> </mat-form-field>
</ng-template> </div>
<ng-template [ngSwitchCase]="aliasFilterType.edgeSearchQuery"> <mat-slide-toggle *ngIf="filterFormGroup.get('maxLevel').value > 1 || !filterFormGroup.get('maxLevel').value"
<div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>edge.edge-types</div> class="mat-slide" formControlName="fetchLastLevelOnly">
<tb-entity-subtype-list {{ 'alias.last-level-relation' | translate }}
required </mat-slide-toggle>
[entityType]="entityType.EDGE" </div>
formControlName="edgeTypes"> <div class="tb-form-panel stroked no-padding-bottom">
</tb-entity-subtype-list> <div class="tb-form-panel-title" translate>relation.relation-filter</div>
</ng-template> <tb-relation-type-autocomplete
<ng-template [ngSwitchCase]="aliasFilterType.entityViewSearchQuery"> appearance="outline"
<div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>entity-view.entity-view-types</div> subscriptSizing="dynamic"
<tb-entity-subtype-list formControlName="relationType">
required </tb-relation-type-autocomplete>
[entityType]="entityType.ENTITY_VIEW" <ng-container [ngSwitch]="entityFilterFormGroup.get('type').value">
formControlName="entityViewTypes"> <ng-template [ngSwitchCase]="aliasFilterType.assetSearchQuery">
</tb-entity-subtype-list> <tb-entity-subtype-list
required
floatLabel="always"
appearance="outline"
label="{{ 'asset.asset-types' | translate }}"
[entityType]="entityType.ASSET"
formControlName="assetTypes">
</tb-entity-subtype-list>
</ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.deviceSearchQuery">
<tb-entity-subtype-list
required
floatLabel="always"
appearance="outline"
label="{{ 'device.device-types' | translate }}"
[entityType]="entityType.DEVICE"
formControlName="deviceTypes">
</tb-entity-subtype-list>
</ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.edgeSearchQuery">
<tb-entity-subtype-list
required
floatLabel="always"
appearance="outline"
label="{{ 'edge.edge-types' | translate }}"
[entityType]="entityType.EDGE"
formControlName="edgeTypes">
</tb-entity-subtype-list>
</ng-template>
<ng-template [ngSwitchCase]="aliasFilterType.entityViewSearchQuery">
<tb-entity-subtype-list
required
floatLabel="always"
appearance="outline"
label="{{ 'entity-view.entity-view-types' | translate }}"
[entityType]="entityType.ENTITY_VIEW"
formControlName="entityViewTypes">
</tb-entity-subtype-list>
</ng-template>
</ng-container>
</div>
</section>
</ng-template> </ng-template>
</section> </section>
</div> </div>

View File

@ -15,25 +15,7 @@
*/ */
:host { :host {
.tb-entity-filter { .tb-entity-filter {
#relationsQueryFilter { display: flex;
padding-top: 20px; flex-direction: column;
tb-entity-select {
min-height: 92px;
}
}
.tb-root-state-entity-switch {
padding-left: 10px;
padding-bottom: 10px;
.root-state-entity-switch {
margin: 0;
}
.root-state-entity-label {
margin: 5px 0 5px 10px;
}
}
} }
} }

View File

@ -31,21 +31,5 @@
} }
} }
} }
.tb-entity-select {
@media screen and (min-width: 599px) {
display: flex;
flex-direction: row;
gap: 16px;
}
tb-entity-type-select {
flex: 1;
}
tb-entity-autocomplete {
flex: 1;
mat-form-field {
width: 100% !important;
}
}
}
} }
} }

View File

@ -15,8 +15,8 @@
limitations under the License. limitations under the License.
--> -->
<section class="tb-datasource-section" [formGroup]="datasourceFormGroup"> <section class="tb-datasource-section tb-form-panel outlined" [formGroup]="datasourceFormGroup">
<mat-form-field *ngIf="!basicMode" class="tb-datasource-type" hideRequiredMarker> <mat-form-field *ngIf="!basicMode" class="tb-datasource-type" hideRequiredMarker appearance="outline">
<mat-label translate>widget-config.datasource-type</mat-label> <mat-label translate>widget-config.datasource-type</mat-label>
<mat-select formControlName="type"> <mat-select formControlName="type">
<mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType"> <mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType">
@ -44,18 +44,20 @@
<tb-entity-autocomplete *ngIf="datasourceFormGroup.get('type').value === datasourceType.device" <tb-entity-autocomplete *ngIf="datasourceFormGroup.get('type').value === datasourceType.device"
[required]="!datasourcesOptional" [required]="!datasourcesOptional"
[entityType]="entityType.DEVICE" [entityType]="entityType.DEVICE"
appearance="outline"
formControlName="deviceId"> formControlName="deviceId">
</tb-entity-autocomplete> </tb-entity-autocomplete>
<tb-entity-alias-select <tb-entity-alias-select
*ngIf="datasourceFormGroup.get('type').value !== datasourceType.device" *ngIf="datasourceFormGroup.get('type').value !== datasourceType.device"
[showLabel]="true" [showLabel]="true"
appearance="outline"
[tbRequired]="!entityAliasOptional" [tbRequired]="!entityAliasOptional"
[aliasController]="aliasController" [aliasController]="aliasController"
formControlName="entityAliasId" formControlName="entityAliasId"
[callbacks]="entityAliasSelectCallbacks"> [callbacks]="entityAliasSelectCallbacks">
</tb-entity-alias-select> </tb-entity-alias-select>
<mat-form-field *ngIf="!hideDatasourceLabel && [datasourceType.entityCount, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)" <mat-form-field *ngIf="!hideDatasourceLabel && [datasourceType.entityCount, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)"
class="flex-1"> class="flex-1" appearance="outline">
<input matInput <input matInput
placeholder="{{ 'datasource.label' | translate }}" placeholder="{{ 'datasource.label' | translate }}"
formControlName="name"> formControlName="name">
@ -64,6 +66,7 @@
</section> </section>
<section *ngIf="!hideDataKeys" class="flex flex-1 flex-col items-stretch justify-start"> <section *ngIf="!hideDataKeys" class="flex flex-1 flex-col items-stretch justify-start">
<tb-data-keys class="tb-data-keys flex-1" <tb-data-keys class="tb-data-keys flex-1"
appearance="outline"
[widgetType]="widgetType" [widgetType]="widgetType"
[datasourceType]="datasourceFormGroup.get('type').value" [datasourceType]="datasourceFormGroup.get('type').value"
[hideDataKeyLabel]="hideDataKeyLabel" [hideDataKeyLabel]="hideDataKeyLabel"
@ -86,6 +89,7 @@
formControlName="dataKeys"> formControlName="dataKeys">
</tb-data-keys> </tb-data-keys>
<tb-data-keys *ngIf="hasAdditionalLatestDataKeys" class="tb-data-keys flex-1" <tb-data-keys *ngIf="hasAdditionalLatestDataKeys" class="tb-data-keys flex-1"
appearance="outline"
[widgetType]="widgetTypes.latest" [widgetType]="widgetTypes.latest"
[datasourceType]="datasourceFormGroup.get('type').value" [datasourceType]="datasourceFormGroup.get('type').value"
[hideDataKeyLabel]="hideDataKeyLabel" [hideDataKeyLabel]="hideDataKeyLabel"
@ -109,6 +113,7 @@
</section> </section>
<tb-filter-select <tb-filter-select
*ngIf="(!basicMode || displayDatasourceFilterForBasicMode) && ![datasourceType.function].includes(datasourceFormGroup.get('type').value)" *ngIf="(!basicMode || displayDatasourceFilterForBasicMode) && ![datasourceType.function].includes(datasourceFormGroup.get('type').value)"
appearance="outline"
[showLabel]="true" [showLabel]="true"
[aliasController]="aliasController" [aliasController]="aliasController"
formControlName="filterId" formControlName="filterId"

View File

@ -20,6 +20,7 @@
height: auto; height: auto;
display: block; display: block;
padding: 0; padding: 0;
overflow: visible;
} }
&.tb-draggable { &.tb-draggable {
&.cdk-drag-preview { &.cdk-drag-preview {

View File

@ -21,7 +21,7 @@
[class.tb-chips]="inlineField" [class.tb-chips]="inlineField"
[class.flex]="inlineField" [class.flex]="inlineField"
[subscriptSizing]="inlineField ? 'dynamic' : subscriptSizing"> [subscriptSizing]="inlineField ? 'dynamic' : subscriptSizing">
<mat-label *ngIf="!inlineField && labelText">{{ labelText }}</mat-label> <mat-label *ngIf="labelText">{{ labelText }}</mat-label> <mat-label *ngIf="!inlineField && labelText">{{ labelText }}</mat-label>
<mat-chip-grid #chipList formControlName="entities"> <mat-chip-grid #chipList formControlName="entities">
<mat-chip-row <mat-chip-row
*ngFor="let entity of entities" *ngFor="let entity of entities"

View File

@ -15,9 +15,11 @@
limitations under the License. limitations under the License.
--> -->
<div [formGroup]="entitySelectFormGroup"> <div [formGroup]="entitySelectFormGroup" class="flex flex-row gap-4 xs:flex-col xs:gap-0">
<tb-entity-type-select <tb-entity-type-select
*ngIf="displayEntityTypeSelect" *ngIf="displayEntityTypeSelect"
class="flex-1"
[appearance]="appearance"
[showLabel]="true" [showLabel]="true"
[required]="required" [required]="required"
[useAliasEntityTypes]="useAliasEntityTypes" [useAliasEntityTypes]="useAliasEntityTypes"
@ -27,6 +29,8 @@
</tb-entity-type-select> </tb-entity-type-select>
<tb-entity-autocomplete <tb-entity-autocomplete
*ngIf="modelValue.entityType && !entityTypeNullUUID.has(modelValue.entityType)" *ngIf="modelValue.entityType && !entityTypeNullUUID.has(modelValue.entityType)"
class="flex-1"
[appearance]="appearance"
[required]="required" [required]="required"
[entityType]="modelValue.entityType" [entityType]="modelValue.entityType"
formControlName="entityId"> formControlName="entityId">

View File

@ -25,6 +25,7 @@ import { EntityId } from '@shared/models/id/entity-id';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { coerceBoolean } from '@shared/decorators/coercion'; import { coerceBoolean } from '@shared/decorators/coercion';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatFormFieldAppearance } from '@angular/material/form-field';
@Component({ @Component({
selector: 'tb-entity-select', selector: 'tb-entity-select',
@ -58,6 +59,9 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte
@Input() @Input()
additionEntityTypes: {[entityType in string]: string} = {}; additionEntityTypes: {[entityType in string]: string} = {};
@Input()
appearance: MatFormFieldAppearance = 'fill';
displayEntityTypeSelect: boolean; displayEntityTypeSelect: boolean;
AliasEntityType = AliasEntityType; AliasEntityType = AliasEntityType;

View File

@ -17,9 +17,9 @@
--> -->
<fieldset class="tb-help-popup-button-container" *ngIf="!textMode"> <fieldset class="tb-help-popup-button-container" *ngIf="!textMode">
<div #toggleHelpButton <div #toggleHelpButton
class="tb-toggle-help-popup-button"
matTooltip="{{ helpIconTooltip }}" matTooltip="{{ helpIconTooltip }}"
matTooltipPosition="above" matTooltipPosition="above"
style="border-radius: 50%"
(click)="toggleHelp()"> (click)="toggleHelp()">
<button mat-icon-button <button mat-icon-button
[disabled]="disabled()" [disabled]="disabled()"
@ -36,6 +36,7 @@
</fieldset> </fieldset>
<fieldset class="tb-help-popup-button-container" [class.hint-button]="hintMode" *ngIf="textMode"> <fieldset class="tb-help-popup-button-container" [class.hint-button]="hintMode" *ngIf="textMode">
<div #toggleHelpTextButton <div #toggleHelpTextButton
class="tb-toggle-help-popup-text-button"
(click)="toggleHelp()"> (click)="toggleHelp()">
<button mat-button <button mat-button
[disabled]="disabled()" [disabled]="disabled()"

View File

@ -28,6 +28,11 @@
z-index: 1; z-index: 1;
} }
.tb-toggle-help-popup-button {
border-radius: 50%;
line-height: normal;
}
.tb-help-popup-button { .tb-help-popup-button {
position: relative; position: relative;
.mat-mdc-progress-spinner { .mat-mdc-progress-spinner {

View File

@ -17,9 +17,10 @@
import { import {
Component, Component,
ElementRef, ElementRef,
Input, OnChanges, Input,
OnDestroy, OnChanges,
Renderer2, SimpleChanges, Renderer2,
SimpleChanges,
ViewChild, ViewChild,
ViewContainerRef, ViewContainerRef,
ViewEncapsulation ViewEncapsulation
@ -38,7 +39,7 @@ import { TranslateService } from '@ngx-translate/core';
styleUrls: ['./help-popup.component.scss'], styleUrls: ['./help-popup.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class HelpPopupComponent implements OnChanges, OnDestroy { export class HelpPopupComponent implements OnChanges {
@ViewChild('toggleHelpButton', {read: ElementRef, static: false}) toggleHelpButton: ElementRef; @ViewChild('toggleHelpButton', {read: ElementRef, static: false}) toggleHelpButton: ElementRef;
@ViewChild('toggleHelpTextButton', {read: ElementRef, static: false}) toggleHelpTextButton: ElementRef; @ViewChild('toggleHelpTextButton', {read: ElementRef, static: false}) toggleHelpTextButton: ElementRef;
@ -93,7 +94,7 @@ export class HelpPopupComponent implements OnChanges, OnDestroy {
private translate: TranslateService) { private translate: TranslateService) {
} }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(_changes: SimpleChanges): void {
if (isDefinedAndNotNull(this.triggerText)) { if (isDefinedAndNotNull(this.triggerText)) {
this.triggerSafeHtml = this.sanitizer.bypassSecurityTrustHtml(this.triggerText); this.triggerSafeHtml = this.sanitizer.bypassSecurityTrustHtml(this.triggerText);
} else { } else {
@ -124,8 +125,4 @@ export class HelpPopupComponent implements OnChanges, OnDestroy {
this.helpPopupStyle); this.helpPopupStyle);
} }
} }
ngOnDestroy(): void {
}
} }

View File

@ -721,6 +721,7 @@
"state-entity-parameter-name": "State entity parameter name", "state-entity-parameter-name": "State entity parameter name",
"default-state-entity": "Default state entity", "default-state-entity": "Default state entity",
"default-entity-parameter-name": "By default", "default-entity-parameter-name": "By default",
"query-options": "Query options",
"max-relation-level": "Max relation level", "max-relation-level": "Max relation level",
"unlimited-level": "Unlimited level", "unlimited-level": "Unlimited level",
"state-entity": "Dashboard state entity", "state-entity": "Dashboard state entity",
@ -4367,6 +4368,7 @@
"add-relation-filter": "Add relation filter", "add-relation-filter": "Add relation filter",
"any-relation": "Any relation", "any-relation": "Any relation",
"relation-filters": "Relation filters", "relation-filters": "Relation filters",
"relation-filter": "Relation filter",
"additional-info": "Additional info (JSON)", "additional-info": "Additional info (JSON)",
"invalid-additional-info": "Unable to parse additional info json.", "invalid-additional-info": "Unable to parse additional info json.",
"no-relations-text": "No relations found", "no-relations-text": "No relations found",

View File

@ -163,6 +163,9 @@
.tb-form-panel-title { .tb-form-panel-title {
font-weight: 500; font-weight: 500;
font-size: 16px; font-size: 16px;
&.tb-normal {
font-weight: normal;
}
&.tb-required::after { &.tb-required::after {
font-size: 13px; font-size: 13px;
@ -819,4 +822,41 @@
} }
} }
} }
.tb-form-panel.outlined {
--mdc-outlined-text-field-outline-color: rgba(0,0,0,0.12);
--mdc-outlined-text-field-container-shape: 6px;
--mat-form-field-trailing-icon-color: rgba(0, 0, 0, 0.56);
box-shadow: none;
gap: 0;
padding-bottom: 0;
&:not(.stroked) {
border-radius: 0;
}
&:not(.mat-padding,.padding) {
padding: 0;
}
& > .tb-form-panel-title {
margin-bottom: 16px;
}
.tb-form-panel {
@media #{$mat-xs} {
gap: 16px;
}
}
.tb-form-row {
height: 56px;
margin-bottom: 22px;
&.disabled {
border-color: var(--mdc-outlined-text-field-disabled-outline-color);
color: var(--mdc-outlined-text-field-disabled-input-text-color);
}
}
}
} }