Merge pull request #12291 from vvlladd28/bug/notification-center/mobile-hidden-add

Fixed the missing add buttons in the notification center on mobile
This commit is contained in:
Igor Kulikov 2024-12-24 12:32:58 +02:00 committed by GitHub
commit c2048be823
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 116 additions and 415 deletions

View File

@ -46,22 +46,41 @@
</div> </div>
<span class="flex-1"></span> <span class="flex-1"></span>
<div [class.!hidden]="!addEnabled()"> <div [class.!hidden]="!addEnabled()">
<button mat-icon-button [disabled]="isLoading$ | async" <ng-container *ngIf="!entitiesTableConfig.addActionDescriptors.length; else addActions">
*ngIf="!entitiesTableConfig.addActionDescriptors.length; else addActions" <button *ngIf="!entitiesTableConfig.addAsTextButton"
mat-icon-button
[disabled]="isLoading$ | async"
(click)="addEntity($event)" (click)="addEntity($event)"
matTooltip="{{ translations.add | translate }}" matTooltip="{{ translations.add | translate }}"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button> </button>
<button *ngIf="entitiesTableConfig.addAsTextButton"
mat-stroked-button color="primary"
[disabled]="isLoading$ | async"
(click)="addEntity($event)">
<mat-icon>add</mat-icon>
{{ translations.add | translate }}
</button>
</ng-container>
<ng-template #addActions> <ng-template #addActions>
<button mat-icon-button [disabled]="isLoading$ | async" <ng-container *ngIf="entitiesTableConfig.addActionDescriptors.length === 1; else addActionsMenu">
*ngIf="entitiesTableConfig.addActionDescriptors.length === 1; else addActionsMenu" <button *ngIf="!entitiesTableConfig.addAsTextButton && entitiesTableConfig.addActionDescriptors[0].isEnabled()"
[class.!hidden]="!entitiesTableConfig.addActionDescriptors[0].isEnabled()" mat-icon-button
[disabled]="isLoading$ | async"
(click)="entitiesTableConfig.addActionDescriptors[0].onAction($event)" (click)="entitiesTableConfig.addActionDescriptors[0].onAction($event)"
matTooltip="{{ entitiesTableConfig.addActionDescriptors[0].name }}" matTooltip="{{ entitiesTableConfig.addActionDescriptors[0].name }}"
matTooltipPosition="above"> matTooltipPosition="above">
<tb-icon>{{entitiesTableConfig.addActionDescriptors[0].icon}}</tb-icon> <tb-icon>{{entitiesTableConfig.addActionDescriptors[0].icon}}</tb-icon>
</button> </button>
<button *ngIf="entitiesTableConfig.addAsTextButton && entitiesTableConfig.addActionDescriptors[0].isEnabled()"
mat-stroked-button color="primary"
[disabled]="isLoading$ | async"
(click)="entitiesTableConfig.addActionDescriptors[0].onAction($event)">
<tb-icon>{{entitiesTableConfig.addActionDescriptors[0].icon}}</tb-icon>
{{ entitiesTableConfig.addActionDescriptors[0].name }}
</button>
</ng-container>
<ng-template #addActionsMenu> <ng-template #addActionsMenu>
<button mat-icon-button [disabled]="isLoading$ | async" <button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ translations.add | translate }}" matTooltip="{{ translations.add | translate }}"

View File

@ -170,6 +170,7 @@ export class EntityTableConfig<T extends BaseData<HasId>, P extends PageLink = P
selectionEnabled = true; selectionEnabled = true;
searchEnabled = true; searchEnabled = true;
addEnabled = true; addEnabled = true;
addAsTextButton = false;
entitiesDeleteEnabled = true; entitiesDeleteEnabled = true;
detailsPanelEnabled = true; detailsPanelEnabled = true;
hideDetailsTabsOnEdit = true; hideDetailsTabsOnEdit = true;

View File

@ -57,7 +57,7 @@ export class MobileAppTableConfigResolver {
) { ) {
this.config.selectionEnabled = false; this.config.selectionEnabled = false;
this.config.entityType = EntityType.MOBILE_APP; this.config.entityType = EntityType.MOBILE_APP;
this.config.addEnabled = false; this.config.addAsTextButton = true;
this.config.entitiesDeleteEnabled = false; this.config.entitiesDeleteEnabled = false;
this.config.rowPointer = true; this.config.rowPointer = true;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.MOBILE_APP); this.config.entityTranslations = entityTypeTranslations.get(EntityType.MOBILE_APP);

View File

@ -15,12 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<div class="flex flex-full items-center justify-between"> <section class="flex items-center">
<section class="flex items-center xs:!hidden">
<div tbTruncateWithTooltip translate>mobile.applications</div> <div tbTruncateWithTooltip translate>mobile.applications</div>
<div tb-help="mobileApplication"></div> <div tb-help="mobileApplication"></div>
</section> </section>
<button mat-stroked-button color="primary" (click)="createMobile($event)">
<mat-icon>add</mat-icon>{{ 'mobile.add-application' | translate }}
</button>
</div>

View File

@ -14,5 +14,5 @@
* limitations under the License. * limitations under the License.
*/ */
:host{ :host{
width: 100000px; width: 100%;
} }

View File

@ -30,8 +30,4 @@ export class MobileAppTableHeaderComponent extends EntityTableHeaderComponent<Mo
constructor(protected store: Store<AppState>) { constructor(protected store: Store<AppState>) {
super(store); super(store);
} }
createMobile($event: Event) {
this.entitiesTableConfig.getTable().addEntity($event);
}
} }

View File

@ -32,7 +32,6 @@ import { DatePipe } from '@angular/common';
import { MobileAppService } from '@core/http/mobile-app.service'; import { MobileAppService } from '@core/http/mobile-app.service';
import { finalize, map, skip, take, takeUntil } from 'rxjs/operators'; import { finalize, map, skip, take, takeUntil } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { import {
MobileBundleDialogComponent, MobileBundleDialogComponent,
@ -45,7 +44,7 @@ import {
import { select, Store } from '@ngrx/store'; import { select, Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { selectUserSettingsProperty } from '@core/auth/auth.selectors'; import { selectUserSettingsProperty } from '@core/auth/auth.selectors';
import { forkJoin, of } from 'rxjs'; import { forkJoin, Observable, of, switchMap } from 'rxjs';
@Injectable() @Injectable()
export class MobileBundleTableConfigResolver { export class MobileBundleTableConfigResolver {
@ -64,16 +63,17 @@ export class MobileBundleTableConfigResolver {
) { ) {
this.config.selectionEnabled = false; this.config.selectionEnabled = false;
this.config.entityType = EntityType.MOBILE_APP_BUNDLE; this.config.entityType = EntityType.MOBILE_APP_BUNDLE;
this.config.addEnabled = false; this.config.addAsTextButton = true;
this.config.rowPointer = true; this.config.rowPointer = true;
this.config.detailsPanelEnabled = false; this.config.detailsPanelEnabled = false;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.MOBILE_APP_BUNDLE); this.config.entityTranslations = entityTypeTranslations.get(EntityType.MOBILE_APP_BUNDLE);
this.config.entityResources = entityTypeResources.get(EntityType.MOBILE_APP_BUNDLE); this.config.entityResources = entityTypeResources.get(EntityType.MOBILE_APP_BUNDLE);
this.config.headerComponent = MobileBundleTableHeaderComponent; this.config.headerComponent = MobileBundleTableHeaderComponent;
this.config.onEntityAction = action => this.onBundleAction(action);
this.config.addDialogStyle = {width: '850px', maxHeight: '100vh'}; this.config.addDialogStyle = {width: '850px', maxHeight: '100vh'};
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.addEntity = () => this.editBundle(null, true);
this.config.columns.push( this.config.columns.push(
new DateEntityTableColumn<MobileAppBundleInfo>('createdTime', 'common.created-time', this.datePipe, '170px'), new DateEntityTableColumn<MobileAppBundleInfo>('createdTime', 'common.created-time', this.datePipe, '170px'),
new EntityTableColumn<MobileAppBundleInfo>('title', 'mobile.title', '25%'), new EntityTableColumn<MobileAppBundleInfo>('title', 'mobile.title', '25%'),
@ -114,15 +114,28 @@ export class MobileBundleTableConfigResolver {
if (!this.openingEditDialog) { if (!this.openingEditDialog) {
this.openingEditDialog = true; this.openingEditDialog = true;
this.mobileAppService.getMobileAppBundleInfoById(bundle.id.id).pipe( this.mobileAppService.getMobileAppBundleInfoById(bundle.id.id).pipe(
switchMap(appBundleInfo => this.editBundle(appBundleInfo)),
takeUntil(this.router.events.pipe(skip(1))), takeUntil(this.router.events.pipe(skip(1))),
finalize(() => {this.openingEditDialog = false;}) finalize(() => {this.openingEditDialog = false;})
).subscribe( ).subscribe((res) => {
appBundleInfo => this.editBundle($event, appBundleInfo) if (res) {
); this.config.updateData();
}
});
} }
return true; return true;
}; };
this.config.entityAdded = (bundle) => {
this.store.pipe(select(selectUserSettingsProperty('notDisplayConfigurationAfterAddMobileBundle'))).pipe(
take(1)
).subscribe((settings: boolean) => {
if(!settings) {
this.configurationApp(null, bundle, true);
}
});
}
this.config.cellActionDescriptors = this.configureCellActions(); this.config.cellActionDescriptors = this.configureCellActions();
} }
@ -141,11 +154,8 @@ export class MobileBundleTableConfigResolver {
]; ];
} }
private editBundle($event: Event, bundle: MobileAppBundleInfo, isAdd = false) { private editBundle(bundle: MobileAppBundleInfo, isAdd = false): Observable<MobileAppBundleInfo> {
if ($event) { return this.dialog.open<MobileBundleDialogComponent, MobileBundleDialogData,
$event.stopPropagation();
}
this.dialog.open<MobileBundleDialogComponent, MobileBundleDialogData,
MobileAppBundleInfo>(MobileBundleDialogComponent, { MobileAppBundleInfo>(MobileBundleDialogComponent, {
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
@ -153,33 +163,7 @@ export class MobileBundleTableConfigResolver {
isAdd, isAdd,
bundle bundle
} }
}).afterClosed() }).afterClosed();
.subscribe((res) => {
if (res) {
if (!isAdd) {
this.config.updateData();
} else {
this.store.pipe(select(selectUserSettingsProperty('notDisplayConfigurationAfterAddMobileBundle'))).pipe(
take(1)
).subscribe((settings: boolean) => {
if (!settings) {
this.configurationApp(null, res, true);
} else {
this.config.updateData();
}
});
}
}
});
}
private onBundleAction(action: EntityAction<MobileAppBundleInfo>): boolean {
switch (action.action) {
case 'add':
this.editBundle(action.event, action.entity, true);
return true;
}
return false;
} }
private configurationApp($event: Event, entity: MobileAppBundleInfo, afterAdd = false) { private configurationApp($event: Event, entity: MobileAppBundleInfo, afterAdd = false) {

View File

@ -15,12 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<div class="flex flex-full items-center justify-between"> <section class="flex items-center">
<section class="flex items-center xs:!hidden">
<div tbTruncateWithTooltip translate>mobile.bundles</div> <div tbTruncateWithTooltip translate>mobile.bundles</div>
<div tb-help="mobileBundle"></div> <div tb-help="mobileBundle"></div>
</section> </section>
<button mat-stroked-button color="primary" (click)="createBundle($event)">
<mat-icon>add</mat-icon>{{ 'mobile.add-bundle' | translate }}
</button>
</div>

View File

@ -14,5 +14,5 @@
* limitations under the License. * limitations under the License.
*/ */
:host{ :host{
width: 100000px; width: 100%;
} }

View File

@ -30,8 +30,4 @@ export class MobileBundleTableHeaderComponent extends EntityTableHeaderComponent
constructor(protected store: Store<AppState>) { constructor(protected store: Store<AppState>) {
super(store); super(store);
} }
createBundle($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
} }

View File

@ -26,15 +26,12 @@ import { SentNotificationDialogComponent } from '@home/pages/notification/sent/s
import { import {
RecipientNotificationDialogComponent RecipientNotificationDialogComponent
} from '@home/pages/notification/recipient/recipient-notification-dialog.component'; } from '@home/pages/notification/recipient/recipient-notification-dialog.component';
import { RecipientTableHeaderComponent } from '@home/pages/notification/recipient/recipient-table-header.component';
import { import {
TemplateNotificationDialogComponent TemplateNotificationDialogComponent
} from '@home/pages/notification/template/template-notification-dialog.component'; } from '@home/pages/notification/template/template-notification-dialog.component';
import { TemplateTableHeaderComponent } from '@home/pages/notification/template/template-table-header.component';
import { EscalationFormComponent } from '@home/pages/notification/rule/escalation-form.component'; import { EscalationFormComponent } from '@home/pages/notification/rule/escalation-form.component';
import { EscalationsComponent } from '@home/pages/notification/rule/escalations.component'; import { EscalationsComponent } from '@home/pages/notification/rule/escalations.component';
import { RuleNotificationDialogComponent } from '@home/pages/notification/rule/rule-notification-dialog.component'; import { RuleNotificationDialogComponent } from '@home/pages/notification/rule/rule-notification-dialog.component';
import { RuleTableHeaderComponent } from '@home/pages/notification/rule/rule-table-header.component';
import { NotificationSettingsComponent } from '@home/pages/notification/settings/notification-settings.component'; import { NotificationSettingsComponent } from '@home/pages/notification/settings/notification-settings.component';
import { import {
NotificationSettingFormComponent NotificationSettingFormComponent
@ -53,13 +50,10 @@ import {
SentErrorDialogComponent, SentErrorDialogComponent,
SentNotificationDialogComponent, SentNotificationDialogComponent,
RecipientNotificationDialogComponent, RecipientNotificationDialogComponent,
RecipientTableHeaderComponent,
TemplateNotificationDialogComponent, TemplateNotificationDialogComponent,
TemplateTableHeaderComponent,
EscalationFormComponent, EscalationFormComponent,
EscalationsComponent, EscalationsComponent,
RuleNotificationDialogComponent, RuleNotificationDialogComponent,
RuleTableHeaderComponent,
NotificationSettingsComponent, NotificationSettingsComponent,
NotificationSettingFormComponent, NotificationSettingFormComponent,
NotificationTemplateConfigurationComponent, NotificationTemplateConfigurationComponent,

View File

@ -30,12 +30,11 @@ import {
RecipientNotificationDialogData RecipientNotificationDialogData
} from '@home/pages/notification/recipient/recipient-notification-dialog.component'; } from '@home/pages/notification/recipient/recipient-notification-dialog.component';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { RecipientTableHeaderComponent } from '@home/pages/notification/recipient/recipient-table-header.component';
import { ActivatedRouteSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import { Observable } from 'rxjs';
@Injectable() @Injectable()
export class RecipientTableConfigResolver { export class RecipientTableConfigResolver {
@ -50,12 +49,14 @@ export class RecipientTableConfigResolver {
this.config.entityType = EntityType.NOTIFICATION_TARGET; this.config.entityType = EntityType.NOTIFICATION_TARGET;
this.config.detailsPanelEnabled = false; this.config.detailsPanelEnabled = false;
this.config.addEnabled = false; this.config.addAsTextButton = true;
this.config.rowPointer = true; this.config.rowPointer = true;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_TARGET); this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_TARGET);
this.config.entityResources = {} as EntityTypeResource<NotificationTarget>; this.config.entityResources = {} as EntityTypeResource<NotificationTarget>;
this.config.addEntity = () => this.editTarget(null, true);
this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationTargets(pageLink); this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationTargets(pageLink);
this.config.deleteEntityTitle = target => this.translate.instant('notification.delete-recipient-title', {recipientName: target.name}); this.config.deleteEntityTitle = target => this.translate.instant('notification.delete-recipient-title', {recipientName: target.name});
@ -67,13 +68,15 @@ export class RecipientTableConfigResolver {
this.config.cellActionDescriptors = this.configureCellActions(); this.config.cellActionDescriptors = this.configureCellActions();
this.config.headerComponent = RecipientTableHeaderComponent;
this.config.onEntityAction = action => this.onTargetAction(action);
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, target) => { this.config.handleRowClick = ($event, target) => {
this.editTarget($event, target); $event?.stopPropagation();
this.editTarget(target).subscribe((res) => {
if (res) {
this.config.updateData();
}
});
return true; return true;
}; };
@ -89,7 +92,7 @@ export class RecipientTableConfigResolver {
); );
} }
resolve(route: ActivatedRouteSnapshot): EntityTableConfig<NotificationTarget> { resolve(_route: ActivatedRouteSnapshot): EntityTableConfig<NotificationTarget> {
return this.config; return this.config;
} }
@ -97,11 +100,8 @@ export class RecipientTableConfigResolver {
return []; return [];
} }
private editTarget($event: Event, target: NotificationTarget, isAdd = false) { private editTarget(target: NotificationTarget, isAdd = false): Observable<NotificationTarget> {
if ($event) { return this.dialog.open<RecipientNotificationDialogComponent, RecipientNotificationDialogData,
$event.stopPropagation();
}
this.dialog.open<RecipientNotificationDialogComponent, RecipientNotificationDialogData,
NotificationTarget>(RecipientNotificationDialogComponent, { NotificationTarget>(RecipientNotificationDialogComponent, {
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
@ -109,20 +109,6 @@ export class RecipientTableConfigResolver {
isAdd, isAdd,
target target
} }
}).afterClosed() }).afterClosed();
.subscribe((res) => {
if (res) {
this.config.updateData();
}
});
}
private onTargetAction(action: EntityAction<NotificationTarget>): boolean {
switch (action.action) {
case 'add':
this.editTarget(action.event, action.entity, true);
return true;
}
return false;
} }
} }

View File

@ -1,24 +0,0 @@
<!--
Copyright © 2016-2024 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.
-->
<div class="flex flex-full flex-row items-center justify-end">
<button mat-stroked-button color="primary" (click)="createTarget($event)">
<div class="flex flex-row items-center justify-start">
<mat-icon>add</mat-icon>{{ 'notification.add-recipients' | translate }}
</div>
</button>
</div>

View File

@ -1,18 +0,0 @@
/**
* Copyright © 2016-2024 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.
*/
:host{
width: 10000px;
}

View File

@ -1,38 +0,0 @@
///
/// Copyright © 2016-2024 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 } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationTarget } from '@shared/models/notification.models';
@Component({
selector: 'tb-recipient-table-header',
templateUrl: './recipient-table-header.component.html',
styleUrls: ['recipient-table-header.component.scss']
})
export class RecipientTableHeaderComponent extends EntityTableHeaderComponent<NotificationTarget> {
constructor(protected store: Store<AppState>) {
super(store);
}
createTarget($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

View File

@ -26,8 +26,6 @@ import { NotificationRule, TriggerTypeTranslationMap } from '@shared/models/noti
import { NotificationService } from '@core/http/notification.service'; import { NotificationService } from '@core/http/notification.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { RuleTableHeaderComponent } from '@home/pages/notification/rule/rule-table-header.component';
import { import {
RuleNotificationDialogComponent, RuleNotificationDialogComponent,
RuleNotificationDialogData RuleNotificationDialogData
@ -36,6 +34,7 @@ import { ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import { Observable } from 'rxjs';
@Injectable() @Injectable()
export class RuleTableConfigResolver { export class RuleTableConfigResolver {
@ -50,12 +49,14 @@ export class RuleTableConfigResolver {
this.config.entityType = EntityType.NOTIFICATION_RULE; this.config.entityType = EntityType.NOTIFICATION_RULE;
this.config.detailsPanelEnabled = false; this.config.detailsPanelEnabled = false;
this.config.addEnabled = false; this.config.addAsTextButton = true;
this.config.rowPointer = true; this.config.rowPointer = true;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_RULE); this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_RULE);
this.config.entityResources = {} as EntityTypeResource<NotificationRule>; this.config.entityResources = {} as EntityTypeResource<NotificationRule>;
this.config.addEntity = () => this.editRule(null, null, true);
this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationRules(pageLink); this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationRules(pageLink);
this.config.deleteEntityTitle = rule => this.translate.instant('notification.delete-rule-title', {ruleName: rule.name}); this.config.deleteEntityTitle = rule => this.translate.instant('notification.delete-rule-title', {ruleName: rule.name});
@ -65,13 +66,15 @@ export class RuleTableConfigResolver {
this.config.deleteEntity = id => this.notificationService.deleteNotificationRule(id.id); this.config.deleteEntity = id => this.notificationService.deleteNotificationRule(id.id);
this.config.cellActionDescriptors = this.configureCellActions(); this.config.cellActionDescriptors = this.configureCellActions();
this.config.headerComponent = RuleTableHeaderComponent;
this.config.onEntityAction = action => this.onTargetAction(action);
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, rule) => { this.config.handleRowClick = ($event, rule) => {
this.editRule($event, rule); this.editRule($event, rule).subscribe((res) => {
if (res) {
this.config.updateData();
}
});
return true; return true;
}; };
@ -88,7 +91,7 @@ export class RuleTableConfigResolver {
); );
} }
resolve(route: ActivatedRouteSnapshot): EntityTableConfig<NotificationRule> { resolve(_route: ActivatedRouteSnapshot): EntityTableConfig<NotificationRule> {
return this.config; return this.config;
} }
@ -110,11 +113,9 @@ export class RuleTableConfigResolver {
}]; }];
} }
private editRule($event: Event, rule: NotificationRule, isAdd = false, isCopy = false) { private editRule($event: Event, rule: NotificationRule, isAdd = false, isCopy = false): Observable<NotificationRule> {
if ($event) { $event?.stopPropagation();
$event.stopPropagation(); return this.dialog.open<RuleNotificationDialogComponent, RuleNotificationDialogData,
}
this.dialog.open<RuleNotificationDialogComponent, RuleNotificationDialogData,
NotificationRule>(RuleNotificationDialogComponent, { NotificationRule>(RuleNotificationDialogComponent, {
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
@ -123,21 +124,7 @@ export class RuleTableConfigResolver {
isCopy, isCopy,
rule rule
} }
}).afterClosed() }).afterClosed();
.subscribe((res) => {
if (res) {
this.config.updateData();
}
});
}
private onTargetAction(action: EntityAction<NotificationRule>): boolean {
switch (action.action) {
case 'add':
this.editRule(action.event, action.entity, true);
return true;
}
return false;
} }
private toggleEnableMode($event: Event, rule: NotificationRule): void { private toggleEnableMode($event: Event, rule: NotificationRule): void {

View File

@ -1,24 +0,0 @@
<!--
Copyright © 2016-2024 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.
-->
<div class="flex flex-full flex-row items-center justify-end">
<button mat-stroked-button color="primary" (click)="createTarget($event)">
<div class="flex flex-row items-center justify-start">
<mat-icon>add</mat-icon>{{ 'notification.add-rule' | translate }}
</div>
</button>
</div>

View File

@ -1,18 +0,0 @@
/**
* Copyright © 2016-2024 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.
*/
:host{
width: 10000px;
}

View File

@ -1,38 +0,0 @@
///
/// Copyright © 2016-2024 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 } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationRule } from '@shared/models/notification.models';
@Component({
selector: 'tb-rule-table-header',
templateUrl: './rule-table-header.component.html',
styleUrls: ['rule-table-header.component.scss']
})
export class RuleTableHeaderComponent extends EntityTableHeaderComponent<NotificationRule> {
constructor(protected store: Store<AppState>) {
super(store);
}
createTarget($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

View File

@ -24,17 +24,16 @@ import { EntityType, EntityTypeResource, entityTypeTranslations } from '@shared/
import { Direction } from '@shared/models/page/sort-order'; import { Direction } from '@shared/models/page/sort-order';
import { NotificationTemplate, NotificationTemplateTypeTranslateMap } from '@shared/models/notification.models'; import { NotificationTemplate, NotificationTemplateTypeTranslateMap } from '@shared/models/notification.models';
import { NotificationService } from '@core/http/notification.service'; import { NotificationService } from '@core/http/notification.service';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { import {
TemplateNotificationDialogComponent, TemplateNotificationDialogComponent,
TemplateNotificationDialogData TemplateNotificationDialogData
} from '@home/pages/notification/template/template-notification-dialog.component'; } from '@home/pages/notification/template/template-notification-dialog.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { TemplateTableHeaderComponent } from '@home/pages/notification/template/template-table-header.component';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot } from '@angular/router';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { Observable } from 'rxjs';
@Injectable() @Injectable()
export class TemplateTableConfigResolver { export class TemplateTableConfigResolver {
@ -48,12 +47,14 @@ export class TemplateTableConfigResolver {
this.config.entityType = EntityType.NOTIFICATION_TEMPLATE; this.config.entityType = EntityType.NOTIFICATION_TEMPLATE;
this.config.detailsPanelEnabled = false; this.config.detailsPanelEnabled = false;
this.config.addEnabled = false; this.config.addAsTextButton = true;
this.config.rowPointer = true; this.config.rowPointer = true;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_TEMPLATE); this.config.entityTranslations = entityTypeTranslations.get(EntityType.NOTIFICATION_TEMPLATE);
this.config.entityResources = {} as EntityTypeResource<NotificationTemplate>; this.config.entityResources = {} as EntityTypeResource<NotificationTemplate>;
this.config.addEntity = () => this.editTemplate(null, null, true);
this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationTemplates(pageLink); this.config.entitiesFetchFunction = pageLink => this.notificationService.getNotificationTemplates(pageLink);
this.config.deleteEntityTitle = template => this.translate.instant('notification.delete-template-title', {templateName: template.name}); this.config.deleteEntityTitle = template => this.translate.instant('notification.delete-template-title', {templateName: template.name});
@ -64,13 +65,14 @@ export class TemplateTableConfigResolver {
this.config.cellActionDescriptors = this.configureCellActions(); this.config.cellActionDescriptors = this.configureCellActions();
this.config.headerComponent = TemplateTableHeaderComponent;
this.config.onEntityAction = action => this.onTemplateAction(action);
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, template) => { this.config.handleRowClick = ($event, template) => {
this.editTemplate($event, template); this.editTemplate($event, template).subscribe((res) => {
if (res) {
this.config.updateData();
}
});
return true; return true;
}; };
@ -82,7 +84,7 @@ export class TemplateTableConfigResolver {
); );
} }
resolve(route: ActivatedRouteSnapshot): EntityTableConfig<NotificationTemplate> { resolve(_route: ActivatedRouteSnapshot): EntityTableConfig<NotificationTemplate> {
return this.config; return this.config;
} }
@ -97,11 +99,9 @@ export class TemplateTableConfigResolver {
]; ];
} }
private editTemplate($event: Event, template: NotificationTemplate, isAdd = false, isCopy = false) { private editTemplate($event: Event, template: NotificationTemplate, isAdd = false, isCopy = false): Observable<NotificationTemplate> {
if ($event) { $event?.stopPropagation();
$event.stopPropagation(); return this.dialog.open<TemplateNotificationDialogComponent, TemplateNotificationDialogData,
}
this.dialog.open<TemplateNotificationDialogComponent, TemplateNotificationDialogData,
NotificationTemplate>(TemplateNotificationDialogComponent, { NotificationTemplate>(TemplateNotificationDialogComponent, {
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
@ -110,21 +110,6 @@ export class TemplateTableConfigResolver {
isCopy, isCopy,
template template
} }
}).afterClosed() }).afterClosed();
.subscribe((res) => {
if (res) {
this.config.updateData();
} }
});
}
private onTemplateAction(action: EntityAction<NotificationTemplate>): boolean {
switch (action.action) {
case 'add':
this.editTemplate(action.event, action.entity, true);
return true;
}
return false;
}
} }

View File

@ -1,24 +0,0 @@
<!--
Copyright © 2016-2024 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.
-->
<div class="flex flex-full flex-row items-center justify-end">
<button mat-stroked-button color="primary" (click)="createTemplate($event)">
<div class="flex flex-row items-center justify-start">
<mat-icon>add</mat-icon>{{ 'notification.add-template' | translate }}
</div>
</button>
</div>

View File

@ -1,18 +0,0 @@
/**
* Copyright © 2016-2024 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.
*/
:host{
width: 10000px;
}

View File

@ -1,38 +0,0 @@
///
/// Copyright © 2016-2024 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 } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationTemplate } from '@shared/models/notification.models';
@Component({
selector: 'tb-template-table-header',
templateUrl: './template-table-header.component.html',
styleUrls: ['template-table-header.component.scss']
})
export class TemplateTableHeaderComponent extends EntityTableHeaderComponent<NotificationTemplate> {
constructor(protected store: Store<AppState>) {
super(store);
}
createTemplate($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

View File

@ -403,7 +403,8 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
list: 'entity.list-of-notification-rules', list: 'entity.list-of-notification-rules',
noEntities: 'notification.no-rules-notification', noEntities: 'notification.no-rules-notification',
search: 'notification.search-rules', search: 'notification.search-rules',
selectedEntities: 'notification.selected-rules' selectedEntities: 'notification.selected-rules',
add: 'notification.add-rule'
} }
], ],
[ [
@ -414,7 +415,8 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
list: 'entity.list-of-notification-targets', list: 'entity.list-of-notification-targets',
noEntities: 'notification.no-recipients-notification', noEntities: 'notification.no-recipients-notification',
search: 'notification.search-recipients', search: 'notification.search-recipients',
selectedEntities: 'notification.selected-recipients' selectedEntities: 'notification.selected-recipients',
add: 'notification.add-recipients'
} }
], ],
[ [
@ -425,7 +427,8 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
list: 'entity.list-of-notification-templates', list: 'entity.list-of-notification-templates',
noEntities: 'notification.no-notification-templates', noEntities: 'notification.no-notification-templates',
search: 'notification.search-templates', search: 'notification.search-templates',
selectedEntities: 'notification.selected-template' selectedEntities: 'notification.selected-template',
add: 'notification.add-template'
} }
], ],
[ [