Browse Source

UI: Menu improvements

pull/8247/head
Igor Kulikov 4 years ago
parent
commit
916faae774
  1. 6
      ui-ngx/src/app/core/http/alarm.service.ts
  2. 333
      ui-ngx/src/app/core/services/menu.service.ts
  3. 16
      ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts
  4. 2
      ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.html
  5. 2
      ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.scss
  6. 20
      ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts
  7. 6
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts
  8. 12
      ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
  9. 4
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
  10. 111
      ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts
  11. 140
      ui-ngx/src/app/modules/home/pages/alarm/alarm-routing.module.ts
  12. 21
      ui-ngx/src/app/modules/home/pages/alarm/alarm-rule-tabs.component.html
  13. 38
      ui-ngx/src/app/modules/home/pages/alarm/alarm-rule-tabs.component.ts
  14. 47
      ui-ngx/src/app/modules/home/pages/alarm/alarm-rule.component.html
  15. 63
      ui-ngx/src/app/modules/home/pages/alarm/alarm-rule.component.ts
  16. 100
      ui-ngx/src/app/modules/home/pages/alarm/alarm-rules-table-config.resolver.ts
  17. 39
      ui-ngx/src/app/modules/home/pages/alarm/alarm.module.ts
  18. 14
      ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts
  19. 12
      ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts
  20. 16
      ui-ngx/src/app/modules/home/pages/device/device-routing.module.ts
  21. 438
      ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts
  22. 2
      ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts
  23. 54
      ui-ngx/src/app/modules/home/pages/entities/entities-routing.module.ts
  24. 30
      ui-ngx/src/app/modules/home/pages/entities/entities.module.ts
  25. 14
      ui-ngx/src/app/modules/home/pages/entity-view/entity-view-routing.module.ts
  26. 54
      ui-ngx/src/app/modules/home/pages/features/features-routing.module.ts
  27. 30
      ui-ngx/src/app/modules/home/pages/features/features.module.ts
  28. 8
      ui-ngx/src/app/modules/home/pages/home-pages.module.ts
  29. 135
      ui-ngx/src/app/modules/home/pages/notification/notification-routing.module.ts
  30. 30
      ui-ngx/src/app/modules/home/pages/notification/notification.module.ts
  31. 14
      ui-ngx/src/app/modules/home/pages/ota-update/ota-update-routing.module.ts
  32. 20
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts
  33. 2
      ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts
  34. 9
      ui-ngx/src/app/modules/home/pages/vc/vc-routing.module.ts
  35. 96
      ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts
  36. 24
      ui-ngx/src/app/shared/models/alarm-rule.models.ts
  37. 7
      ui-ngx/src/app/shared/models/alarm.models.ts
  38. 4
      ui-ngx/src/app/shared/models/device.models.ts
  39. 36
      ui-ngx/src/app/shared/models/entity-type.models.ts
  40. 26
      ui-ngx/src/app/shared/models/id/alarm-rule-id.ts
  41. 1
      ui-ngx/src/app/shared/models/id/public-api.ts
  42. 1
      ui-ngx/src/app/shared/models/public-api.ts
  43. 40
      ui-ngx/src/assets/locale/locale.constant-en_US.json

6
ui-ngx/src/app/core/http/alarm.service.ts

@ -70,6 +70,12 @@ export class AlarmService {
defaultHttpOptionsFromConfig(config)); defaultHttpOptionsFromConfig(config));
} }
public getAllAlarms(query: AlarmQuery,
config?: RequestConfig): Observable<PageData<AlarmInfo>> {
return this.http.get<PageData<AlarmInfo>>(`/api/alarms${query.toQuery()}`,
defaultHttpOptionsFromConfig(config));
}
public getHighestAlarmSeverity(entityId: EntityId, alarmSearchStatus: AlarmSearchStatus, alarmStatus: AlarmStatus, public getHighestAlarmSeverity(entityId: EntityId, alarmSearchStatus: AlarmSearchStatus, alarmStatus: AlarmStatus,
config?: RequestConfig): Observable<AlarmSeverity> { config?: RequestConfig): Observable<AlarmSeverity> {
let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.id}`; let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.id}`;

333
ui-ngx/src/app/core/services/menu.service.ts

@ -19,19 +19,20 @@ import { AuthService } from '../auth/auth.service';
import { select, Store } from '@ngrx/store'; import { select, Store } from '@ngrx/store';
import { AppState } from '../core.state'; import { AppState } from '../core.state';
import { getCurrentOpenedMenuSections, selectAuth, selectIsAuthenticated } from '../auth/auth.selectors'; import { getCurrentOpenedMenuSections, selectAuth, selectIsAuthenticated } from '../auth/auth.selectors';
import { take } from 'rxjs/operators'; import { filter, take } from 'rxjs/operators';
import { HomeSection, MenuSection } from '@core/services/menu.models'; import { HomeSection, MenuSection } from '@core/services/menu.models';
import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { guid } from '@core/utils'; import { guid } from '@core/utils';
import { AuthState } from '@core/auth/auth.models'; import { AuthState } from '@core/auth/auth.models';
import { Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class MenuService { export class MenuService {
currentMenuSections: Array<MenuSection>;
menuSections$: Subject<Array<MenuSection>> = new BehaviorSubject<Array<MenuSection>>([]); menuSections$: Subject<Array<MenuSection>> = new BehaviorSubject<Array<MenuSection>>([]);
homeSections$: Subject<Array<HomeSection>> = new BehaviorSubject<Array<HomeSection>>([]); homeSections$: Subject<Array<HomeSection>> = new BehaviorSubject<Array<HomeSection>>([]);
@ -45,41 +46,49 @@ export class MenuService {
} }
} }
); );
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(
() => {
this.updateOpenedMenuSections();
}
);
} }
private buildMenu() { private buildMenu() {
this.store.pipe(select(selectAuth), take(1)).subscribe( this.store.pipe(select(selectAuth), take(1)).subscribe(
(authState: AuthState) => { (authState: AuthState) => {
if (authState.authUser) { if (authState.authUser) {
let menuSections: Array<MenuSection>;
let homeSections: Array<HomeSection>; let homeSections: Array<HomeSection>;
switch (authState.authUser.authority) { switch (authState.authUser.authority) {
case Authority.SYS_ADMIN: case Authority.SYS_ADMIN:
menuSections = this.buildSysAdminMenu(authState); this.currentMenuSections = this.buildSysAdminMenu(authState);
homeSections = this.buildSysAdminHome(authState); homeSections = this.buildSysAdminHome(authState);
break; break;
case Authority.TENANT_ADMIN: case Authority.TENANT_ADMIN:
menuSections = this.buildTenantAdminMenu(authState); this.currentMenuSections = this.buildTenantAdminMenu(authState);
homeSections = this.buildTenantAdminHome(authState); homeSections = this.buildTenantAdminHome(authState);
break; break;
case Authority.CUSTOMER_USER: case Authority.CUSTOMER_USER:
menuSections = this.buildCustomerUserMenu(authState); this.currentMenuSections = this.buildCustomerUserMenu(authState);
homeSections = this.buildCustomerUserHome(authState); homeSections = this.buildCustomerUserHome(authState);
break; break;
} }
const url = this.router.url; this.updateOpenedMenuSections();
const openedMenuSections = getCurrentOpenedMenuSections(this.store); this.menuSections$.next(this.currentMenuSections);
menuSections.filter(section => section.type === 'toggle' &&
(url.startsWith(section.path) || openedMenuSections.includes(section.path))).forEach(
section => section.opened = true
);
this.menuSections$.next(menuSections);
this.homeSections$.next(homeSections); this.homeSections$.next(homeSections);
} }
} }
); );
} }
private updateOpenedMenuSections() {
const url = this.router.url;
const openedMenuSections = getCurrentOpenedMenuSections(this.store);
this.currentMenuSections.filter(section => section.type === 'toggle' &&
(url.startsWith(section.path) || openedMenuSections.includes(section.path))).forEach(
section => section.opened = true
);
}
private buildSysAdminMenu(authState: AuthState): Array<MenuSection> { private buildSysAdminMenu(authState: AuthState): Array<MenuSection> {
const sections: Array<MenuSection> = []; const sections: Array<MenuSection> = [];
sections.push( sections.push(
@ -132,7 +141,7 @@ export class MenuService {
}, },
{ {
id: guid(), id: guid(),
name: 'admin.system-settings', name: 'admin.settings',
type: 'link', type: 'link',
path: '/settings', path: '/settings',
icon: 'settings', icon: 'settings',
@ -295,31 +304,64 @@ export class MenuService {
}, },
{ {
id: guid(), id: guid(),
name: 'rulechain.rulechains', name: 'alarm.alarms',
type: 'link', type: 'link',
path: '/ruleChains', path: '/alarm',
icon: 'settings_ethernet' icon: 'notifications',
}, pages: [
{ {
id: guid(), id: guid(),
name: 'customer.customers', name: 'alarm.all-alarms',
type: 'link', type: 'link',
path: '/customers', path: '/alarm/alarms',
icon: 'supervisor_account' icon: 'notifications'
},
{
id: guid(),
name: 'alarm-rule.rules',
type: 'link',
path: '/alarm/rules',
icon: 'edit_notifications'
}
]
}, },
{ {
id: guid(), id: guid(),
name: 'asset.assets', name: 'dashboard.dashboards',
type: 'link', type: 'link',
path: '/assets', path: '/dashboards',
icon: 'domain' icon: 'dashboards'
}, },
{ {
id: guid(), id: guid(),
name: 'device.devices', name: 'entity.entities',
type: 'link', type: 'toggle',
path: '/devices', path: '/entities',
icon: 'devices_other' height: '120px',
icon: 'category',
pages: [
{
id: guid(),
name: 'device.devices',
type: 'link',
path: '/entities/devices',
icon: 'devices_other'
},
{
id: guid(),
name: 'asset.assets',
type: 'link',
path: '/entities/assets',
icon: 'domain'
},
{
id: guid(),
name: 'entity-view.entity-views',
type: 'link',
path: '/entities/entityViews',
icon: 'view_quilt'
}
]
}, },
{ {
id: guid(), id: guid(),
@ -349,36 +391,29 @@ export class MenuService {
}, },
{ {
id: guid(), id: guid(),
name: 'ota-update.ota-updates', name: 'customer.customers',
type: 'link',
path: '/otaUpdates',
icon: 'memory'
},
{
id: guid(),
name: 'entity-view.entity-views',
type: 'link', type: 'link',
path: '/entityViews', path: '/customers',
icon: 'view_quilt' icon: 'supervisor_account'
} }
); );
if (authState.edgesSupportEnabled) { if (authState.edgesSupportEnabled) {
sections.push( sections.push(
{
id: guid(),
name: 'edge.edge-instances',
type: 'link',
path: '/edgeInstances',
icon: 'router'
},
{ {
id: guid(), id: guid(),
name: 'edge.management', name: 'edge.management',
type: 'toggle', type: 'toggle',
path: '/edgeManagement', path: '/edgeManagement',
height: '40px', height: '80px',
icon: 'settings_input_antenna', icon: 'settings_input_antenna',
pages: [ pages: [
{
id: guid(),
name: 'edge.instances',
type: 'link',
path: '/edgeManagement/instances',
icon: 'router'
},
{ {
id: guid(), id: guid(),
name: 'edge.rulechain-templates', name: 'edge.rulechain-templates',
@ -393,31 +428,106 @@ export class MenuService {
sections.push( sections.push(
{ {
id: guid(), id: guid(),
name: 'widget.widget-library', name: 'feature.advanced-features',
type: 'link', type: 'toggle',
path: '/widgets-bundles', path: '/features',
icon: 'now_widgets' height: '120px',
}, icon: 'construction',
{ pages: [
id: guid(), {
name: 'dashboard.dashboards', id: guid(),
type: 'link', name: 'rulechain.rulechains',
path: '/dashboards', type: 'link',
icon: 'dashboards' path: '/features/ruleChains',
icon: 'settings_ethernet'
},
{
id: guid(),
name: 'ota-update.ota-updates',
type: 'link',
path: '/features/otaUpdates',
icon: 'memory'
},
{
id: guid(),
name: 'version-control.version-control',
type: 'link',
path: '/features/vc',
icon: 'history'
}
]
}, },
{ {
id: guid(), id: guid(),
name: 'version-control.version-control', name: 'admin.resources',
type: 'link', type: 'toggle',
path: '/vc', path: '/resources',
icon: 'history' height: '80px',
icon: 'folder',
pages: [
{
id: guid(),
name: 'widget.widget-library',
type: 'link',
path: '/resources/widgets-bundles',
icon: 'now_widgets'
},
{
id: guid(),
name: 'resource.resources-library',
type: 'link',
path: '/resources/resources-library',
icon: 'mdi:rhombus-split',
isMdiIcon: true
}
]
}, },
{ {
id: guid(), id: guid(),
name: 'audit-log.audit-logs', name: 'notification.notification-center',
type: 'link', type: 'link',
path: '/auditLogs', path: '/notification',
icon: 'track_changes' icon: 'mdi:message-badge',
isMdiIcon: true,
pages: [
{
id: guid(),
name: 'notification.inbox',
type: 'link',
path: '/notification/inbox',
icon: 'inbox'
},
{
id: guid(),
name: 'notification.sent',
type: 'link',
path: '/notification/sent',
icon: 'outbox'
},
{
id: guid(),
name: 'notification.templates',
type: 'link',
path: '/notification/templates',
icon: 'mdi:message-draw',
isMdiIcon: true
},
{
id: guid(),
name: 'notification.recipients',
type: 'link',
path: '/notification/recipients',
icon: 'contacts'
},
{
id: guid(),
name: 'notification.rules',
type: 'link',
path: '/notification/rules',
icon: 'mdi:message-cog',
isMdiIcon: true
}
]
}, },
{ {
id: guid(), id: guid(),
@ -428,41 +538,49 @@ export class MenuService {
}, },
{ {
id: guid(), id: guid(),
name: 'admin.system-settings', name: 'admin.settings',
type: 'toggle', type: 'link',
path: '/settings', path: '/settings',
height: '160px',
icon: 'settings', icon: 'settings',
pages: [ pages: [
{ {
id: guid(), id: guid(),
name: 'admin.home-settings', name: 'admin.home',
type: 'link', type: 'link',
path: '/settings/home', path: '/settings/home',
icon: 'settings_applications' icon: 'settings_applications'
}, },
{ {
id: guid(), id: guid(),
name: 'resource.resources-library', name: 'admin.repository',
type: 'link',
path: '/settings/resources-library',
icon: 'folder'
},
{
id: guid(),
name: 'admin.repository-settings',
type: 'link', type: 'link',
path: '/settings/repository', path: '/settings/repository',
icon: 'manage_history' icon: 'manage_history'
}, },
{ {
id: guid(), id: guid(),
name: 'admin.auto-commit-settings', name: 'admin.auto-commit',
type: 'link', type: 'link',
path: '/settings/auto-commit', path: '/settings/auto-commit',
icon: 'settings_backup_restore' icon: 'settings_backup_restore'
} }
] ]
},
{
id: guid(),
name: 'security.security',
type: 'link',
path: '/security-settings',
icon: 'security',
pages: [
{
id: guid(),
name: 'audit-log.audit-logs',
type: 'link',
path: '/auditLogs',
icon: 'track_changes'
}
]
} }
); );
return sections; return sections;
@ -640,24 +758,48 @@ export class MenuService {
}, },
{ {
id: guid(), id: guid(),
name: 'asset.assets', name: 'alarm.alarms',
type: 'link', type: 'link',
path: '/assets', path: '/alarms',
icon: 'domain' icon: 'notifications'
}, },
{ {
id: guid(), id: guid(),
name: 'device.devices', name: 'dashboard.dashboards',
type: 'link', type: 'link',
path: '/devices', path: '/dashboards',
icon: 'devices_other' icon: 'dashboards'
}, },
{ {
id: guid(), id: guid(),
name: 'entity-view.entity-views', name: 'entity.entities',
type: 'link', type: 'toggle',
path: '/entityViews', path: '/entities',
icon: 'view_quilt' height: '120px',
icon: 'category',
pages: [
{
id: guid(),
name: 'device.devices',
type: 'link',
path: '/entities/devices',
icon: 'devices_other'
},
{
id: guid(),
name: 'asset.assets',
type: 'link',
path: '/entities/assets',
icon: 'domain'
},
{
id: guid(),
name: 'entity-view.entity-views',
type: 'link',
path: '/entities/entityViews',
icon: 'view_quilt'
}
]
} }
); );
if (authState.edgesSupportEnabled) { if (authState.edgesSupportEnabled) {
@ -666,20 +808,11 @@ export class MenuService {
id: guid(), id: guid(),
name: 'edge.edge-instances', name: 'edge.edge-instances',
type: 'link', type: 'link',
path: '/edgeInstances', path: '/edgeManagement/instances',
icon: 'router' icon: 'router'
} }
); );
} }
sections.push(
{
id: guid(),
name: 'dashboard.dashboards',
type: 'link',
path: '/dashboards',
icon: 'dashboard'
}
);
return sections; return sections;
} }

16
ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts

@ -33,7 +33,7 @@ import {
AlarmQuery, AlarmQuery,
AlarmSearchStatus, AlarmSearchStatus,
alarmSeverityColors, alarmSeverityColors,
alarmSeverityTranslations, alarmSeverityTranslations, AlarmsMode,
alarmStatusTranslations alarmStatusTranslations
} from '@app/shared/models/alarm.models'; } from '@app/shared/models/alarm.models';
import { AlarmService } from '@app/core/http/alarm.service'; import { AlarmService } from '@app/core/http/alarm.service';
@ -48,6 +48,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { AuditLogMode } from '@shared/models/audit-log.models';
export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink> { export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink> {
@ -60,14 +61,16 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
private translate: TranslateService, private translate: TranslateService,
private datePipe: DatePipe, private datePipe: DatePipe,
private dialog: MatDialog, private dialog: MatDialog,
private alarmsMode: AlarmsMode = AlarmsMode.ALL,
public entityId: EntityId = null, public entityId: EntityId = null,
private defaultSearchStatus: AlarmSearchStatus = AlarmSearchStatus.ANY, private defaultSearchStatus: AlarmSearchStatus = AlarmSearchStatus.ANY,
private store: Store<AppState>) { private store: Store<AppState>,
pageMode = false) {
super(); super();
this.loadDataOnInit = false; this.loadDataOnInit = false;
this.tableTitle = ''; this.tableTitle = '';
this.useTimePageLink = true; this.useTimePageLink = true;
this.pageMode = false; this.pageMode = pageMode;
this.defaultTimewindowInterval = historyInterval(DAY * 30); this.defaultTimewindowInterval = historyInterval(DAY * 30);
this.detailsPanelEnabled = false; this.detailsPanelEnabled = false;
this.selectionEnabled = false; this.selectionEnabled = false;
@ -117,7 +120,12 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
fetchAlarms(pageLink: TimePageLink): Observable<PageData<AlarmInfo>> { fetchAlarms(pageLink: TimePageLink): Observable<PageData<AlarmInfo>> {
const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true); const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true);
return this.alarmService.getAlarms(query); switch (this.alarmsMode) {
case AlarmsMode.ALL:
return this.alarmService.getAllAlarms(query);
case AlarmsMode.ENTITY:
return this.alarmService.getAlarms(query);
}
} }
showAlarmDetails(entity: AlarmInfo) { showAlarmDetails(entity: AlarmInfo) {

2
ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.html

@ -15,4 +15,4 @@
limitations under the License. limitations under the License.
--> -->
<tb-entities-table [entitiesTableConfig]="alarmTableConfig"></tb-entities-table> <tb-entities-table [entitiesTableConfig]="alarmTableConfig" [ngClass]="{'tb-details-mode': detailsMode}"></tb-entities-table>

2
ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.scss

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
:host ::ng-deep { :host ::ng-deep {
tb-entities-table { tb-entities-table.tb-details-mode {
.mat-drawer-container { .mat-drawer-container {
background-color: white; background-color: white;
} }

20
ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts

@ -22,10 +22,12 @@ import { EntityId } from '@shared/models/id/entity-id';
import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { EntitiesTableComponent } from '@home/components/entity/entities-table.component';
import { DialogService } from '@core/services/dialog.service'; import { DialogService } from '@core/services/dialog.service';
import { AlarmTableConfig } from './alarm-table-config'; import { AlarmTableConfig } from './alarm-table-config';
import { AlarmSearchStatus } from '@shared/models/alarm.models'; import { AlarmSearchStatus, AlarmsMode } from '@shared/models/alarm.models';
import { AlarmService } from '@app/core/http/alarm.service'; import { AlarmService } from '@app/core/http/alarm.service';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { ActivatedRoute } from '@angular/router';
import { isDefinedAndNotNull } from '@core/utils';
@Component({ @Component({
selector: 'tb-alarm-table', selector: 'tb-alarm-table',
@ -37,6 +39,8 @@ export class AlarmTableComponent implements OnInit {
activeValue = false; activeValue = false;
dirtyValue = false; dirtyValue = false;
entityIdValue: EntityId; entityIdValue: EntityId;
alarmsMode = AlarmsMode.ENTITY;
detailsMode = true;
@Input() @Input()
set active(active: boolean) { set active(active: boolean) {
@ -71,20 +75,30 @@ export class AlarmTableComponent implements OnInit {
private translate: TranslateService, private translate: TranslateService,
private datePipe: DatePipe, private datePipe: DatePipe,
private dialog: MatDialog, private dialog: MatDialog,
private store: Store<AppState>) { private store: Store<AppState>,
private route: ActivatedRoute) {
} }
ngOnInit() { ngOnInit() {
this.dirtyValue = !this.activeValue; this.dirtyValue = !this.activeValue;
const pageMode = !!this.route.snapshot.data.isPage;
if (pageMode) {
this.detailsMode = false;
}
if (isDefinedAndNotNull(this.route.snapshot.data.alarmsMode)) {
this.alarmsMode = this.route.snapshot.data.alarmsMode;
}
this.alarmTableConfig = new AlarmTableConfig( this.alarmTableConfig = new AlarmTableConfig(
this.alarmService, this.alarmService,
this.dialogService, this.dialogService,
this.translate, this.translate,
this.datePipe, this.datePipe,
this.dialog, this.dialog,
this.alarmsMode,
this.entityIdValue, this.entityIdValue,
AlarmSearchStatus.ANY, AlarmSearchStatus.ANY,
this.store this.store,
pageMode
); );
} }

6
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts

@ -25,7 +25,7 @@ import {
Validator, Validator,
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { AlarmRule } from '@shared/models/device.models'; import { DeviceProfileAlarmRule } from '@shared/models/device.models';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { isDefinedAndNotNull } from '@core/utils'; import { isDefinedAndNotNull } from '@core/utils';
@ -71,7 +71,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
@Input() @Input()
deviceProfileId: EntityId; deviceProfileId: EntityId;
private modelValue: AlarmRule; private modelValue: DeviceProfileAlarmRule;
alarmRuleFormGroup: UntypedFormGroup; alarmRuleFormGroup: UntypedFormGroup;
@ -112,7 +112,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
} }
} }
writeValue(value: AlarmRule): void { writeValue(value: DeviceProfileAlarmRule): void {
this.modelValue = value; this.modelValue = value;
const model = this.modelValue ? { const model = this.modelValue ? {
...this.modelValue, ...this.modelValue,

12
ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts

@ -27,7 +27,7 @@ import {
Validator, Validator,
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { AlarmRule, alarmRuleValidator } from '@shared/models/device.models'; import { DeviceProfileAlarmRule, alarmRuleValidator } from '@shared/models/device.models';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models'; import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models';
@ -101,7 +101,7 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
} }
} }
writeValue(createAlarmRules: {[severity: string]: AlarmRule}): void { writeValue(createAlarmRules: {[severity: string]: DeviceProfileAlarmRule}): void {
if (this.valueChangeSubscription) { if (this.valueChangeSubscription) {
this.valueChangeSubscription.unsubscribe(); this.valueChangeSubscription.unsubscribe();
} }
@ -138,7 +138,7 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
} }
public addCreateAlarmRule() { public addCreateAlarmRule() {
const createAlarmRule: AlarmRule = { const createAlarmRule: DeviceProfileAlarmRule = {
condition: { condition: {
condition: [] condition: []
} }
@ -179,15 +179,15 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
private updateUsedSeverities() { private updateUsedSeverities() {
this.usedSeverities = []; this.usedSeverities = [];
const value: {severity: string, alarmRule: AlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value; const value: {severity: string, alarmRule: DeviceProfileAlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value;
value.forEach((rule, index) => { value.forEach((rule, index) => {
this.usedSeverities[index] = AlarmSeverity[rule.severity]; this.usedSeverities[index] = AlarmSeverity[rule.severity];
}); });
} }
private updateModel() { private updateModel() {
const value: {severity: string, alarmRule: AlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value; const value: {severity: string, alarmRule: DeviceProfileAlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value;
const createAlarmRules: {[severity: string]: AlarmRule} = {}; const createAlarmRules: {[severity: string]: DeviceProfileAlarmRule} = {};
value.forEach(v => { value.forEach(v => {
createAlarmRules[v.severity] = v.alarmRule; createAlarmRules[v.severity] = v.alarmRule;
}); });

4
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts

@ -25,7 +25,7 @@ import {
Validator, Validator,
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { AlarmRule, DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/device.models'; import { DeviceProfileAlarmRule, DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/device.models';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips'; import { MatChipInputEvent } from '@angular/material/chips';
@ -128,7 +128,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
} }
public addClearAlarmRule() { public addClearAlarmRule() {
const clearAlarmRule: AlarmRule = { const clearAlarmRule: DeviceProfileAlarmRule = {
condition: { condition: {
condition: [] condition: []
} }

111
ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts

@ -36,16 +36,9 @@ import { QueuesTableConfigResolver } from '@home/pages/admin/queue/queues-table-
import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component';
import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component'; import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component';
import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-auth-settings.component'; import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-auth-settings.component';
import { WidgetsBundlesTableConfigResolver } from '@home/pages/widget/widgets-bundles-table-config.resolver'; import { widgetsBundlesRoutes } from '@home/pages/widget/widget-library-routing.module';
import {
WidgetEditorAddDataResolver, widgetEditorBreadcumbLabelFunction,
WidgetEditorDataResolver,
WidgetsBundleResolver,
WidgetsTypesDataResolver, widgetTypesBreadcumbLabelFunction
} from '@home/pages/widget/widget-library-routing.module';
import { WidgetLibraryComponent } from '@home/pages/widget/widget-library.component';
import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component';
import { RouterTabsComponent } from '@home/components/router-tabs.component'; import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { auditLogsRoutes } from '@home/pages/audit-log/audit-log-routing.module';
@Injectable() @Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> { export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
@ -77,85 +70,7 @@ const routes: Routes = [
redirectTo: '/resources/widgets-bundles' redirectTo: '/resources/widgets-bundles'
} }
}, },
{ ...widgetsBundlesRoutes,
path: 'widgets-bundles',
data: {
breadcrumb: {
label: 'widgets-bundle.widgets-bundles',
icon: 'now_widgets'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widgets-bundle.widgets-bundles'
},
resolve: {
entitiesTableConfig: WidgetsBundlesTableConfigResolver
}
},
{
path: ':widgetsBundleId/widgetTypes',
data: {
breadcrumb: {
labelFunction: widgetTypesBreadcumbLabelFunction,
icon: 'now_widgets'
} as BreadCrumbConfig<any>
},
resolve: {
widgetsBundle: WidgetsBundleResolver
},
children: [
{
path: '',
component: WidgetLibraryComponent,
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.widget-library'
},
resolve: {
widgetsData: WidgetsTypesDataResolver
}
},
{
path: ':widgetTypeId',
component: WidgetEditorComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.editor',
breadcrumb: {
labelFunction: widgetEditorBreadcumbLabelFunction,
icon: 'insert_chart'
} as BreadCrumbConfig<WidgetEditorComponent>
},
resolve: {
widgetEditorData: WidgetEditorDataResolver
}
},
{
path: 'add/:widgetType',
component: WidgetEditorComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.editor',
breadcrumb: {
labelFunction: widgetEditorBreadcumbLabelFunction,
icon: 'insert_chart'
} as BreadCrumbConfig<WidgetEditorComponent>
},
resolve: {
widgetEditorData: WidgetEditorAddDataResolver
}
}
]
}
]
},
{ {
path: 'resources-library', path: 'resources-library',
data: { data: {
@ -202,7 +117,7 @@ const routes: Routes = [
data: { data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
breadcrumb: { breadcrumb: {
label: 'admin.system-settings', label: 'admin.settings',
icon: 'settings' icon: 'settings'
} }
}, },
@ -303,7 +218,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN], auth: [Authority.TENANT_ADMIN],
title: 'admin.home-settings', title: 'admin.home-settings',
breadcrumb: { breadcrumb: {
label: 'admin.home-settings', label: 'admin.home',
icon: 'settings_applications' icon: 'settings_applications'
} }
} }
@ -316,7 +231,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN], auth: [Authority.TENANT_ADMIN],
title: 'admin.repository-settings', title: 'admin.repository-settings',
breadcrumb: { breadcrumb: {
label: 'admin.repository-settings', label: 'admin.repository',
icon: 'manage_history' icon: 'manage_history'
} }
} }
@ -329,7 +244,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN], auth: [Authority.TENANT_ADMIN],
title: 'admin.auto-commit-settings', title: 'admin.auto-commit-settings',
breadcrumb: { breadcrumb: {
label: 'admin.auto-commit-settings', label: 'admin.auto-commit',
icon: 'settings_backup_restore' icon: 'settings_backup_restore'
} }
} }
@ -379,7 +294,7 @@ const routes: Routes = [
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
redirectTo: { redirectTo: {
SYS_ADMIN: '/security-settings/general', SYS_ADMIN: '/security-settings/general',
TENANT_ADMIN: '/security-settings/audit-logs' TENANT_ADMIN: '/security-settings/auditLogs'
} }
} }
}, },
@ -425,7 +340,8 @@ const routes: Routes = [
resolve: { resolve: {
loginProcessingUrl: OAuth2LoginProcessingUrlResolver loginProcessingUrl: OAuth2LoginProcessingUrlResolver
} }
} },
...auditLogsRoutes
] ]
} }
]; ];
@ -436,12 +352,7 @@ const routes: Routes = [
providers: [ providers: [
OAuth2LoginProcessingUrlResolver, OAuth2LoginProcessingUrlResolver,
ResourcesLibraryTableConfigResolver, ResourcesLibraryTableConfigResolver,
QueuesTableConfigResolver, QueuesTableConfigResolver
WidgetsBundlesTableConfigResolver,
WidgetsBundleResolver,
WidgetsTypesDataResolver,
WidgetEditorDataResolver,
WidgetEditorAddDataResolver
] ]
}) })
export class AdminRoutingModule { } export class AdminRoutingModule { }

140
ui-ngx/src/app/modules/home/pages/alarm/alarm-routing.module.ts

@ -0,0 +1,140 @@
///
/// 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 { Injectable, NgModule } from '@angular/core';
import { Resolve, RouterModule, Routes } from '@angular/router';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { Authority } from '@shared/models/authority.enum';
import { Observable } from 'rxjs';
import { OAuth2Service } from '@core/http/oauth2.service';
import { EntitiesTableComponent } from '@home/components/entity/entities-table.component';
import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component';
import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
import { BreadCrumbConfig } from '@shared/components/breadcrumb';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { AlarmTableComponent } from '@home/components/alarm/alarm-table.component';
import { AlarmRulesTableConfigResolver } from '@home/pages/alarm/alarm-rules-table-config.resolver';
import { AlarmsMode } from '@shared/models/alarm.models';
@Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
constructor(private oauth2Service: OAuth2Service) {
}
resolve(): Observable<string> {
return this.oauth2Service.getLoginProcessingUrl();
}
}
const routes: Routes = [
{
path: 'alarm',
component: RouterTabsComponent,
data: {
auth: [Authority.TENANT_ADMIN],
breadcrumb: {
label: 'alarm.alarms',
icon: 'notifications'
}
},
children: [
{
path: '',
children: [],
data: {
auth: [Authority.TENANT_ADMIN],
redirectTo: '/alarm/alarms'
}
},
{
path: 'alarms',
component: AlarmTableComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'alarm.all-alarms',
breadcrumb: {
label: 'alarm.all-alarms',
icon: 'notifications'
},
isPage: true,
alarmsMode: AlarmsMode.ALL
}
},
{
path: 'rules',
data: {
breadcrumb: {
label: 'alarm-rule.rules',
icon: 'edit_notifications'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'alarm-rule.alarm-rules'
},
resolve: {
entitiesTableConfig: AlarmRulesTableConfigResolver
}
},
{
path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'domain'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN],
title: 'alarm-rule.alarm-rules'
},
resolve: {
entitiesTableConfig: AlarmRulesTableConfigResolver
}
}
]
}
]
},
{
path: 'alarms',
component: AlarmTableComponent,
data: {
auth: [Authority.CUSTOMER_USER],
title: 'alarm.alarms',
breadcrumb: {
label: 'alarm.alarms',
icon: 'notifications'
},
isPage: true,
alarmsMode: AlarmsMode.ALL
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [
AlarmRulesTableConfigResolver
]
})
export class AlarmRoutingModule { }

21
ui-ngx/src/app/modules/home/pages/alarm/alarm-rule-tabs.component.html

@ -0,0 +1,21 @@
<!--
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.
-->
<mat-tab *ngIf="entity && !isEdit" #auditLogsTab="matTab"
label="{{ 'audit-log.audit-logs' | translate }}">
<tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
</mat-tab>

38
ui-ngx/src/app/modules/home/pages/alarm/alarm-rule-tabs.component.ts

@ -0,0 +1,38 @@
///
/// 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 } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { EntityTabsComponent } from '../../components/entity/entity-tabs.component';
import { AlarmRule } from '@shared/models/alarm-rule.models';
@Component({
selector: 'tb-alarm-rule-tabs',
templateUrl: './alarm-rule-tabs.component.html',
styleUrls: []
})
export class AlarmRuleTabsComponent extends EntityTabsComponent<AlarmRule> {
constructor(protected store: Store<AppState>) {
super(store);
}
ngOnInit() {
super.ngOnInit();
}
}

47
ui-ngx/src/app/modules/home/pages/alarm/alarm-rule.component.html

@ -0,0 +1,47 @@
<!--
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.
-->
<div class="tb-details-buttons" fxLayout.xs="column">
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'open')"
[fxShow]="!isEdit && !isDetailsPage">
{{'common.open-details-page' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"
[fxShow]="!hideDelete() && !isEdit">
{{'alarm-rule.delete' | translate }}
</button>
</div>
<div class="mat-padding" fxLayout="column">
<form [formGroup]="entityForm">
<fieldset [disabled]="(isLoading$ | async) || !isEdit" style="min-width: 0;">
<mat-form-field class="mat-block">
<mat-label translate>alarm-rule.name</mat-label>
<input matInput formControlName="name" required/>
<mat-error *ngIf="entityForm.get('name').hasError('required')">
{{ 'alarm-rule.name-required' | translate }}
</mat-error>
<mat-error *ngIf="entityForm.get('name').hasError('maxlength')">
{{ 'alarm-rule.name-max-length' | translate }}
</mat-error>
</mat-form-field>
</fieldset>
</form>
</div>

63
ui-ngx/src/app/modules/home/pages/alarm/alarm-rule.component.ts

@ -0,0 +1,63 @@
///
/// 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 { ChangeDetectorRef, Component, Inject, Optional } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import { EntityComponent } from '@home/components/entity/entity.component';
import { AlarmRule } from '@shared/models/alarm-rule.models';
@Component({
selector: 'tb-alarm-rule',
templateUrl: './alarm-rule.component.html',
styleUrls: []
})
export class AlarmRuleComponent extends EntityComponent<AlarmRule> {
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@Optional() @Inject('entity') protected entityValue: AlarmRule,
@Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<AlarmRule>,
protected fb: UntypedFormBuilder,
protected cd: ChangeDetectorRef) {
super(store, fb, entityValue, entitiesTableConfigValue, cd);
}
hideDelete() {
if (this.entitiesTableConfig) {
return !this.entitiesTableConfig.deleteEnabled(this.entity);
} else {
return false;
}
}
buildForm(entity: AlarmRule): UntypedFormGroup {
const form = this.fb.group(
{
name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]]
}
);
return form;
}
updateForm(entity: AlarmRule) {
this.entityForm.patchValue({name: entity.name});
}
}

100
ui-ngx/src/app/modules/home/pages/alarm/alarm-rules-table-config.resolver.ts

@ -0,0 +1,100 @@
///
/// 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 { Injectable } from '@angular/core';
import { Resolve, Router } from '@angular/router';
import {
DateEntityTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { DialogService } from '@core/services/dialog.service';
import { MatDialog } from '@angular/material/dialog';
import { ImportExportService } from '@home/components/import-export/import-export.service';
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
import { AlarmRuleComponent } from '@home/pages/alarm/alarm-rule.component';
import { AlarmRuleTabsComponent } from '@home/pages/alarm/alarm-rule-tabs.component';
import { AlarmRule } from '@shared/models/alarm-rule.models';
import { emptyPageData } from '@shared/models/page/page-data';
import { of } from 'rxjs';
@Injectable()
export class AlarmRulesTableConfigResolver implements Resolve<EntityTableConfig<AlarmRule>> {
private readonly config: EntityTableConfig<AlarmRule> = new EntityTableConfig<AlarmRule>();
constructor(private importExport: ImportExportService,
private homeDialogs: HomeDialogsService,
private translate: TranslateService,
private datePipe: DatePipe,
private dialogService: DialogService,
private router: Router,
private dialog: MatDialog) {
this.config.entityType = EntityType.ALARM_RULE;
this.config.entityComponent = AlarmRuleComponent;
this.config.entityTabsComponent = AlarmRuleTabsComponent;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.ALARM_RULE);
this.config.entityResources = entityTypeResources.get(EntityType.ALARM_RULE);
this.config.hideDetailsTabsOnEdit = false;
this.config.columns.push(
new DateEntityTableColumn<AlarmRule>('createdTime', 'common.created-time', this.datePipe, '150px'),
new EntityTableColumn<AlarmRule>('name', 'alarm-rule.name', '50%')
);
this.config.deleteEntityTitle = alarmRule => this.translate.instant('alarm-rule.delete-alarm-rule-title',
{ alarmRuleName: alarmRule.name });
this.config.deleteEntityContent = () => this.translate.instant('alarm-rule.delete-alarm-rule-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('alarm-rule.delete-alarm-rules-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('alarm-rule.delete-alarm-rules-text');
this.config.entitiesFetchFunction = pageLink => of(emptyPageData<AlarmRule>()); // TODO
this.config.loadEntity = id => of(null); // TODO
this.config.saveEntity = alarmRule => of(alarmRule); // TODO
this.config.deleteEntity = id => of(null); // TODO
this.config.onEntityAction = action => this.onAlarmRuleAction(action);
}
resolve(): EntityTableConfig<AlarmRule> {
this.config.tableTitle = this.translate.instant('alarm-rule.alarm-rules');
return this.config;
}
private openAlarmRule($event: Event, alarmRule: AlarmRule) {
if ($event) {
$event.stopPropagation();
}
const url = this.router.createUrlTree(['alarm', 'rules', alarmRule.id.id]);
this.router.navigateByUrl(url);
}
onAlarmRuleAction(action: EntityAction<AlarmRule>): boolean {
switch (action.action) {
case 'open':
this.openAlarmRule(action.event, action.entity);
return true;
}
return false;
}
}

39
ui-ngx/src/app/modules/home/pages/alarm/alarm.module.ts

@ -0,0 +1,39 @@
///
/// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { HomeDialogsModule } from '../../dialogs/home-dialogs.module';
import { HomeComponentsModule } from '@modules/home/components/home-components.module';
import { AlarmRoutingModule } from '@home/pages/alarm/alarm-routing.module';
import { AlarmRuleComponent } from '@home/pages/alarm/alarm-rule.component';
import { AlarmRuleTabsComponent } from '@home/pages/alarm/alarm-rule-tabs.component';
@NgModule({
declarations: [
AlarmRuleComponent,
AlarmRuleTabsComponent
],
imports: [
CommonModule,
SharedModule,
HomeComponentsModule,
HomeDialogsModule,
AlarmRoutingModule
]
})
export class AlarmModule { }

14
ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts

@ -25,7 +25,7 @@ import { BreadCrumbConfig } from '@shared/components/breadcrumb';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models'; import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
const routes: Routes = [ export const assetRoutes: Routes = [
{ {
path: 'assets', path: 'assets',
data: { data: {
@ -68,6 +68,18 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'assets',
pathMatch: 'full',
redirectTo: '/entities/assets'
},
{
path: 'assets/:entityId',
redirectTo: '/entities/assets/:entityId'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],

12
ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts

@ -19,7 +19,7 @@ import { RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { AuditLogTableComponent } from '@home/components/audit-log/audit-log-table.component'; import { AuditLogTableComponent } from '@home/components/audit-log/audit-log-table.component';
const routes: Routes = [ export const auditLogsRoutes: Routes = [
{ {
path: 'auditLogs', path: 'auditLogs',
component: AuditLogTableComponent, component: AuditLogTableComponent,
@ -35,8 +35,16 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'auditLogs',
redirectTo: '/security-settings/auditLogs'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule],
providers: []
}) })
export class AuditLogRoutingModule { } export class AuditLogRoutingModule { }

16
ui-ngx/src/app/modules/home/pages/device/device-routing.module.ts

@ -24,8 +24,10 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models'; import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
import { BreadCrumbConfig } from '@shared/components/breadcrumb'; import { BreadCrumbConfig } from '@shared/components/breadcrumb';
import { assetRoutes } from '@home/pages/asset/asset-routing.module';
import { entityViewRoutes } from '@home/pages/entity-view/entity-view-routing.module';
const routes: Routes = [ export const deviceRoutes: Routes = [
{ {
path: 'devices', path: 'devices',
data: { data: {
@ -68,6 +70,18 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'devices',
pathMatch: 'full',
redirectTo: '/entities/devices'
},
{
path: 'devices/:entityId',
redirectTo: '/entities/devices/:entityId'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],

438
ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts

@ -44,49 +44,28 @@ import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages
const routes: Routes = [ const routes: Routes = [
{ {
path: 'edgeInstances', path: 'edgeManagement',
data: { data: {
breadcrumb: { breadcrumb: {
label: 'edge.edge-instances', label: 'edge.management',
icon: 'router' icon: 'settings_input_antenna'
} }
}, },
children: [ children: [
{ {
path: '', path: '',
component: EntitiesTableComponent, children: [],
data: { data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.edge-instances', redirectTo: '/edgeManagement/instances'
edgesType: 'tenant'
},
resolve: {
entitiesTableConfig: EdgesTableConfigResolver
} }
}, },
{ {
path: ':entityId', path: 'instances',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction, label: 'edge.instances',
icon: 'router' icon: 'router'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.edge-instances',
edgesType: 'tenant'
},
resolve: {
entitiesTableConfig: EdgesTableConfigResolver
}
},
{
path: ':edgeId/assets',
data: {
breadcrumb: {
label: 'edge.assets',
icon: 'domain'
} }
}, },
children: [ children: [
@ -95,11 +74,11 @@ const routes: Routes = [
component: EntitiesTableComponent, component: EntitiesTableComponent,
data: { data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets', title: 'edge.edge-instances',
assetsType: 'edge' edgesType: 'tenant'
}, },
resolve: { resolve: {
entitiesTableConfig: AssetsTableConfigResolver entitiesTableConfig: EdgesTableConfigResolver
} }
}, },
{ {
@ -109,198 +88,219 @@ const routes: Routes = [
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction, labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'domain' icon: 'router'
} as BreadCrumbConfig<EntityDetailsPageComponent>, } as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets', title: 'edge.edge-instances',
assetsType: 'edge' edgesType: 'tenant'
}, },
resolve: { resolve: {
entitiesTableConfig: AssetsTableConfigResolver entitiesTableConfig: EdgesTableConfigResolver
}
}
]
},
{
path: ':edgeId/devices',
data: {
breadcrumb: {
label: 'edge.devices',
icon: 'devices_other'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.devices',
devicesType: 'edge'
},
resolve: {
entitiesTableConfig: DevicesTableConfigResolver
} }
}, },
{ {
path: ':entityId', path: ':edgeId/assets',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction, label: 'edge.assets',
icon: 'devices_other' icon: 'domain'
} as BreadCrumbConfig<EntityDetailsPageComponent>, }
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.devices',
devicesType: 'edge'
},
resolve: {
entitiesTableConfig: DevicesTableConfigResolver
}
}
]
},
{
path: ':edgeId/entityViews',
data: {
breadcrumb: {
label: 'edge.entity-views',
icon: 'view_quilt'
},
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.entity-views',
entityViewsType: 'edge'
}, },
resolve: { children: [
entitiesTableConfig: EntityViewsTableConfigResolver {
} path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets',
assetsType: 'edge'
},
resolve: {
entitiesTableConfig: AssetsTableConfigResolver
}
},
{
path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'domain'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets',
assetsType: 'edge'
},
resolve: {
entitiesTableConfig: AssetsTableConfigResolver
}
}
]
}, },
{ {
path: ':entityId', path: ':edgeId/devices',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction, label: 'edge.devices',
icon: 'devices_other' icon: 'devices_other'
} as BreadCrumbConfig<EntityDetailsPageComponent>, }
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.entity-views',
entityViewsType: 'edge'
}, },
resolve: { children: [
entitiesTableConfig: EntityViewsTableConfigResolver {
} path: '',
} component: EntitiesTableComponent,
] data: {
}, auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
{ title: 'edge.devices',
path: ':edgeId/dashboards', devicesType: 'edge'
data: { },
breadcrumb: { resolve: {
label: 'edge.dashboards', entitiesTableConfig: DevicesTableConfigResolver
icon: 'dashboard' }
} },
}, {
children: [ path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'devices_other'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.devices',
devicesType: 'edge'
},
resolve: {
entitiesTableConfig: DevicesTableConfigResolver
}
}
]
},
{ {
path: '', path: ':edgeId/entityViews',
component: EntitiesTableComponent,
data: { data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], breadcrumb: {
dashboardsType: 'edge' label: 'edge.entity-views',
}, icon: 'view_quilt'
resolve: { },
entitiesTableConfig: DashboardsTableConfigResolver
}, },
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.entity-views',
entityViewsType: 'edge'
},
resolve: {
entitiesTableConfig: EntityViewsTableConfigResolver
}
},
{
path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'devices_other'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.entity-views',
entityViewsType: 'edge'
},
resolve: {
entitiesTableConfig: EntityViewsTableConfigResolver
}
}
]
}, },
{ {
path: ':dashboardId', path: ':edgeId/dashboards',
component: DashboardPageComponent,
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: dashboardBreadcumbLabelFunction, label: 'edge.dashboards',
icon: 'dashboard' icon: 'dashboard'
} as BreadCrumbConfig<DashboardPageComponent>, }
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.dashboard',
widgetEditMode: false
}, },
resolve: { children: [
dashboard: DashboardResolver {
} path: '',
} component: EntitiesTableComponent,
] data: {
}, auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
{ dashboardsType: 'edge'
path: ':edgeId/ruleChains', },
data: { resolve: {
breadcrumb: { entitiesTableConfig: DashboardsTableConfigResolver
label: 'edge.edge-rulechains', },
icon: 'settings_ethernet' },
} {
}, path: ':dashboardId',
children: [ component: DashboardPageComponent,
{ data: {
path: '', breadcrumb: {
component: EntitiesTableComponent, labelFunction: dashboardBreadcumbLabelFunction,
data: { icon: 'dashboard'
auth: [Authority.TENANT_ADMIN], } as BreadCrumbConfig<DashboardPageComponent>,
title: 'edge.rulechains', auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
ruleChainsType: 'edge' title: 'edge.dashboard',
}, widgetEditMode: false
resolve: { },
entitiesTableConfig: RuleChainsTableConfigResolver resolve: {
} dashboard: DashboardResolver
}
}
]
}, },
{ {
path: ':ruleChainId', path: ':edgeId/ruleChains',
component: RuleChainPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: { data: {
breadcrumb: { breadcrumb: {
labelFunction: ruleChainBreadcumbLabelFunction, label: 'edge.edge-rulechains',
icon: 'settings_ethernet' icon: 'settings_ethernet'
} as BreadCrumbConfig<RuleChainPageComponent>, }
auth: [Authority.TENANT_ADMIN],
title: 'rulechain.edge-rulechain',
import: false,
ruleChainType: RuleChainType.EDGE
}, },
resolve: { children: [
ruleChain: RuleChainResolver, {
ruleChainMetaData: RuleChainMetaDataResolver, path: '',
ruleNodeComponents: RuleNodeComponentsResolver, component: EntitiesTableComponent,
tooltipster: TooltipsterResolver data: {
} auth: [Authority.TENANT_ADMIN],
title: 'edge.rulechains',
ruleChainsType: 'edge'
},
resolve: {
entitiesTableConfig: RuleChainsTableConfigResolver
}
},
{
path: ':ruleChainId',
component: RuleChainPageComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
breadcrumb: {
labelFunction: ruleChainBreadcumbLabelFunction,
icon: 'settings_ethernet'
} as BreadCrumbConfig<RuleChainPageComponent>,
auth: [Authority.TENANT_ADMIN],
title: 'rulechain.edge-rulechain',
import: false,
ruleChainType: RuleChainType.EDGE
},
resolve: {
ruleChain: RuleChainResolver,
ruleChainMetaData: RuleChainMetaDataResolver,
ruleNodeComponents: RuleNodeComponentsResolver,
tooltipster: TooltipsterResolver
}
}
]
} }
] ]
}
]
},
{
path: 'edgeManagement',
data: {
breadcrumb: {
label: 'edge.management',
icon: 'settings_input_antenna'
}
},
children: [
{
path: '',
children: [],
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
redirectTo: '/edgeManagement/ruleChains'
}
}, },
{ {
path: 'ruleChains', path: 'ruleChains',
@ -367,7 +367,63 @@ const routes: Routes = [
] ]
} }
] ]
}]; },
{
path: 'edgeInstances',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances'
},
{
path: 'edgeInstances/:entityId',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:entityId'
},
{
path: 'edgeInstances/:edgeId/assets',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:edgeId/assets'
},
{
path: 'edgeInstances/:edgeId/assets/:entityId',
redirectTo: '/edgeManagement/instances/:edgeId/assets/:entityId'
},
{
path: 'edgeInstances/:edgeId/devices',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:edgeId/devices'
},
{
path: 'edgeInstances/:edgeId/devices/:entityId',
redirectTo: '/edgeManagement/instances/:edgeId/devices/:entityId'
},
{
path: 'edgeInstances/:edgeId/entityViews',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:edgeId/entityViews'
},
{
path: 'edgeInstances/:edgeId/entityViews/:entityId',
redirectTo: '/edgeManagement/instances/:edgeId/entityViews/:entityId'
},
{
path: 'edgeInstances/:edgeId/dashboards',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:edgeId/dashboards'
},
{
path: 'edgeInstances/:edgeId/dashboards/:dashboardId',
redirectTo: '/edgeManagement/instances/:edgeId/dashboards/:dashboardId'
},
{
path: 'edgeInstances/:edgeId/ruleChains',
pathMatch: 'full',
redirectTo: '/edgeManagement/instances/:edgeId/ruleChains'
},
{
path: 'edgeInstances/:edgeId/ruleChains/:ruleChainId',
redirectTo: '/edgeManagement/instances/:edgeId/ruleChains/:ruleChainId'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],

2
ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts

@ -429,7 +429,7 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
suffix = 'ruleChains'; suffix = 'ruleChains';
break; break;
} }
this.router.navigateByUrl(`edgeInstances/${edge.id.id}/${suffix}`); this.router.navigateByUrl(`edgeManagement/instances/${edge.id.id}/${suffix}`);
} }
assignToCustomer($event: Event, edgesIds: Array<EdgeId>) { assignToCustomer($event: Event, edgesIds: Array<EdgeId>) {

54
ui-ngx/src/app/modules/home/pages/entities/entities-routing.module.ts

@ -0,0 +1,54 @@
///
/// 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 { RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { NgModule } from '@angular/core';
import { deviceRoutes } from '@home/pages/device/device-routing.module';
import { assetRoutes } from '@home/pages/asset/asset-routing.module';
import { entityViewRoutes } from '@home/pages/entity-view/entity-view-routing.module';
const routes: Routes = [
{
path: 'entities',
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
breadcrumb: {
label: 'entity.entities',
icon: 'category'
}
},
children: [
{
path: '',
children: [],
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
redirectTo: '/entities/devices'
}
},
...deviceRoutes,
...assetRoutes,
...entityViewRoutes
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class EntitiesRoutingModule { }

30
ui-ngx/src/app/modules/home/pages/entities/entities.module.ts

@ -0,0 +1,30 @@
///
/// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { EntitiesRoutingModule } from '@home/pages/entities/entities-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
SharedModule,
EntitiesRoutingModule
]
})
export class EntitiesModule { }

14
ui-ngx/src/app/modules/home/pages/entity-view/entity-view-routing.module.ts

@ -25,7 +25,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models'; import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
import { BreadCrumbConfig } from '@shared/components/breadcrumb'; import { BreadCrumbConfig } from '@shared/components/breadcrumb';
const routes: Routes = [ export const entityViewRoutes: Routes = [
{ {
path: 'entityViews', path: 'entityViews',
data: { data: {
@ -68,6 +68,18 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'entityViews',
pathMatch: 'full',
redirectTo: '/entities/entityViews'
},
{
path: 'entityViews/:entityId',
redirectTo: '/entities/entityViews/:entityId'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],

54
ui-ngx/src/app/modules/home/pages/features/features-routing.module.ts

@ -0,0 +1,54 @@
///
/// 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 { RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { NgModule } from '@angular/core';
import { ruleChainsRoutes } from '@home/pages/rulechain/rulechain-routing.module';
import { otaUpdatesRoutes } from '@home/pages/ota-update/ota-update-routing.module';
import { vcRoutes } from '@home/pages/vc/vc-routing.module';
const routes: Routes = [
{
path: 'features',
data: {
auth: [Authority.TENANT_ADMIN],
breadcrumb: {
label: 'feature.advanced-features',
icon: 'construction'
}
},
children: [
{
path: '',
children: [],
data: {
auth: [Authority.TENANT_ADMIN],
redirectTo: '/features/ruleChains'
}
},
...ruleChainsRoutes,
...otaUpdatesRoutes,
...vcRoutes
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class FeaturesRoutingModule { }

30
ui-ngx/src/app/modules/home/pages/features/features.module.ts

@ -0,0 +1,30 @@
///
/// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { FeaturesRoutingModule } from '@home/pages/features/features-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
SharedModule,
FeaturesRoutingModule
]
})
export class FeaturesModule { }

8
ui-ngx/src/app/modules/home/pages/home-pages.module.ts

@ -38,6 +38,10 @@ import { OtaUpdateModule } from '@home/pages/ota-update/ota-update.module';
import { VcModule } from '@home/pages/vc/vc.module'; import { VcModule } from '@home/pages/vc/vc.module';
import { AssetProfileModule } from '@home/pages/asset-profile/asset-profile.module'; import { AssetProfileModule } from '@home/pages/asset-profile/asset-profile.module';
import { ProfilesModule } from '@home/pages/profiles/profiles.module'; import { ProfilesModule } from '@home/pages/profiles/profiles.module';
import { AlarmModule } from '@home/pages/alarm/alarm.module';
import { EntitiesModule } from '@home/pages/entities/entities.module';
import { FeaturesModule } from '@home/pages/features/features.module';
import { NotificationModule } from '@home/pages/notification/notification.module';
@NgModule({ @NgModule({
exports: [ exports: [
@ -50,8 +54,12 @@ import { ProfilesModule } from '@home/pages/profiles/profiles.module';
DeviceProfileModule, DeviceProfileModule,
AssetProfileModule, AssetProfileModule,
ProfilesModule, ProfilesModule,
EntitiesModule,
FeaturesModule,
NotificationModule,
DeviceModule, DeviceModule,
AssetModule, AssetModule,
AlarmModule,
EdgeModule, EdgeModule,
EntityViewModule, EntityViewModule,
CustomerModule, CustomerModule,

135
ui-ngx/src/app/modules/home/pages/notification/notification-routing.module.ts

@ -0,0 +1,135 @@
///
/// 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 { ActivatedRoute, RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { Component, NgModule, OnInit } from '@angular/core';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { isDefinedAndNotNull } from '@core/utils';
@Component({
selector: 'tb-notification-temp-component',
template: '<div>{{text}}</div>',
styleUrls: []
})
class NotificationTempComponent implements OnInit {
text: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
if (isDefinedAndNotNull(this.route.snapshot.data.text)) {
this.text = this.route.snapshot.data.text;
}
}
}
const routes: Routes = [
{
path: 'notification',
component: RouterTabsComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
breadcrumb: {
label: 'notification.notification-center',
icon: 'mdi:message-badge'
}
},
children: [
{
path: '',
children: [],
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
redirectTo: '/notification/inbox'
}
},
{
path: 'inbox',
component: NotificationTempComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'notification.inbox',
breadcrumb: {
label: 'notification.inbox',
icon: 'inbox'
},
text: 'TODO: Implement inbox'
}
},
{
path: 'sent',
component: NotificationTempComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'notification.sent',
breadcrumb: {
label: 'notification.sent',
icon: 'outbox'
},
text: 'TODO: Implement sent'
}
},
{
path: 'templates',
component: NotificationTempComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'notification.templates',
breadcrumb: {
label: 'notification.templates',
icon: 'mdi:message-draw'
},
text: 'TODO: Implement templates'
}
},
{
path: 'recipients',
component: NotificationTempComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'notification.recipients',
breadcrumb: {
label: 'notification.recipients',
icon: 'contacts'
},
text: 'TODO: Implement recipients'
}
},
{
path: 'rules',
component: NotificationTempComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'notification.rules',
breadcrumb: {
label: 'notification.rules',
icon: 'mdi:message-cog'
},
text: 'TODO: Implement rules'
}
}
]
}
];
@NgModule({
declarations: [NotificationTempComponent],
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class NotificationRoutingModule { }

30
ui-ngx/src/app/modules/home/pages/notification/notification.module.ts

@ -0,0 +1,30 @@
///
/// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { NotificationRoutingModule } from '@home/pages/notification/notification-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
SharedModule,
NotificationRoutingModule
]
})
export class NotificationModule { }

14
ui-ngx/src/app/modules/home/pages/ota-update/ota-update-routing.module.ts

@ -24,7 +24,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models'; import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
import { BreadCrumbConfig } from '@shared/components/breadcrumb'; import { BreadCrumbConfig } from '@shared/components/breadcrumb';
const routes: Routes = [ export const otaUpdatesRoutes: Routes = [
{ {
path: 'otaUpdates', path: 'otaUpdates',
data: { data: {
@ -65,6 +65,18 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'otaUpdates',
pathMatch: 'full',
redirectTo: '/features/otaUpdates'
},
{
path: 'otaUpdates/:entityId',
redirectTo: '/features/otaUpdates/:entityId'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],

20
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts

@ -122,7 +122,7 @@ export const importRuleChainBreadcumbLabelFunction: BreadCrumbLabelFunction<Rule
return `${translate.instant('rulechain.import')}: ${component.ruleChain.name}`; return `${translate.instant('rulechain.import')}: ${component.ruleChain.name}`;
}); });
const routes: Routes = [ export const ruleChainsRoutes: Routes = [
{ {
path: 'ruleChains', path: 'ruleChains',
data: { data: {
@ -189,6 +189,24 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'ruleChains',
pathMatch: 'full',
redirectTo: '/features/ruleChains'
},
{
path: 'ruleChains/:ruleChainId',
pathMatch: 'full',
redirectTo: '/features/ruleChains/:ruleChainId'
},
{
path: 'ruleChains/ruleChain/import',
pathMatch: 'full',
redirectTo: '/features/ruleChains/ruleChain/import'
}
];
// @dynamic // @dynamic
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],

2
ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts

@ -301,7 +301,7 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
if (this.config.componentsData.ruleChainScope === 'edges') { if (this.config.componentsData.ruleChainScope === 'edges') {
this.router.navigateByUrl(`edgeManagement/ruleChains/ruleChain/import`); this.router.navigateByUrl(`edgeManagement/ruleChains/ruleChain/import`);
} else { } else {
this.router.navigateByUrl(`ruleChains/ruleChain/import`); this.router.navigateByUrl(`features/ruleChains/ruleChain/import`);
} }
} }
}); });

9
ui-ngx/src/app/modules/home/pages/vc/vc-routing.module.ts

@ -20,7 +20,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { VersionControlComponent } from '@home/components/vc/version-control.component'; import { VersionControlComponent } from '@home/components/vc/version-control.component';
const routes: Routes = [ export const vcRoutes: Routes = [
{ {
path: 'vc', path: 'vc',
component: VersionControlComponent, component: VersionControlComponent,
@ -36,6 +36,13 @@ const routes: Routes = [
} }
]; ];
const routes: Routes = [
{
path: 'vc',
redirectTo: '/features/vc'
}
];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],

96
ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts

@ -27,8 +27,8 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import { WidgetService } from '@core/http/widget.service'; import { WidgetService } from '@core/http/widget.service';
import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component'; import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { detailsToWidgetInfo, toWidgetInfo, WidgetInfo } from '@home/models/widget-component.models'; import { detailsToWidgetInfo, WidgetInfo } from '@home/models/widget-component.models';
import { widgetType, WidgetType, WidgetTypeDetails } from '@app/shared/models/widget.models'; import { widgetType, WidgetTypeDetails } from '@app/shared/models/widget.models';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { WidgetsData } from '@home/models/dashboard-component.models'; import { WidgetsData } from '@home/models/dashboard-component.models';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
@ -120,7 +120,89 @@ export const widgetTypesBreadcumbLabelFunction: BreadCrumbLabelFunction<any> = (
export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction<WidgetEditorComponent> = export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction<WidgetEditorComponent> =
((route, translate, component) => component ? component.widget.widgetName : ''); ((route, translate, component) => component ? component.widget.widgetName : '');
export const routes: Routes = [ export const widgetsBundlesRoutes: Routes = [
{
path: 'widgets-bundles',
data: {
breadcrumb: {
label: 'widgets-bundle.widgets-bundles',
icon: 'now_widgets'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widgets-bundle.widgets-bundles'
},
resolve: {
entitiesTableConfig: WidgetsBundlesTableConfigResolver
}
},
{
path: ':widgetsBundleId/widgetTypes',
data: {
breadcrumb: {
labelFunction: widgetTypesBreadcumbLabelFunction,
icon: 'now_widgets'
} as BreadCrumbConfig<any>
},
resolve: {
widgetsBundle: WidgetsBundleResolver
},
children: [
{
path: '',
component: WidgetLibraryComponent,
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.widget-library'
},
resolve: {
widgetsData: WidgetsTypesDataResolver
}
},
{
path: ':widgetTypeId',
component: WidgetEditorComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.editor',
breadcrumb: {
labelFunction: widgetEditorBreadcumbLabelFunction,
icon: 'insert_chart'
} as BreadCrumbConfig<WidgetEditorComponent>
},
resolve: {
widgetEditorData: WidgetEditorDataResolver
}
},
{
path: 'add/:widgetType',
component: WidgetEditorComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
title: 'widget.editor',
breadcrumb: {
labelFunction: widgetEditorBreadcumbLabelFunction,
icon: 'insert_chart'
} as BreadCrumbConfig<WidgetEditorComponent>
},
resolve: {
widgetEditorData: WidgetEditorAddDataResolver
}
}
]
}
]
},
];
const routes: Routes = [
{ {
path: 'widgets-bundles', path: 'widgets-bundles',
pathMatch: 'full', pathMatch: 'full',
@ -146,6 +228,12 @@ export const routes: Routes = [
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],
providers: [] providers: [
WidgetsBundlesTableConfigResolver,
WidgetsBundleResolver,
WidgetsTypesDataResolver,
WidgetEditorDataResolver,
WidgetEditorAddDataResolver
]
}) })
export class WidgetLibraryRoutingModule { } export class WidgetLibraryRoutingModule { }

24
ui-ngx/src/app/shared/models/alarm-rule.models.ts

@ -0,0 +1,24 @@
///
/// 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 { BaseData } from '@shared/models/base-data';
import { TenantId } from '@shared/models/id/tenant-id';
import { AlarmRuleId } from '@shared/models/id/alarm-rule-id';
export interface AlarmRule extends BaseData<AlarmRuleId> {
tenantId: TenantId;
name: string;
}

7
ui-ngx/src/app/shared/models/alarm.models.ts

@ -24,6 +24,11 @@ import { EntityType } from '@shared/models/entity-type.models';
import { CustomerId } from '@shared/models/id/customer-id'; import { CustomerId } from '@shared/models/id/customer-id';
import { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models'; import { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models';
export enum AlarmsMode {
ALL,
ENTITY
}
export enum AlarmSeverity { export enum AlarmSeverity {
CRITICAL = 'CRITICAL', CRITICAL = 'CRITICAL',
MAJOR = 'MAJOR', MAJOR = 'MAJOR',
@ -218,7 +223,7 @@ export class AlarmQuery {
} }
public toQuery(): string { public toQuery(): string {
let query = `/${this.affectedEntityId.entityType}/${this.affectedEntityId.id}`; let query = this.affectedEntityId ? `/${this.affectedEntityId.entityType}/${this.affectedEntityId.id}` : '';
query += this.pageLink.toQuery(); query += this.pageLink.toQuery();
if (this.searchStatus) { if (this.searchStatus) {
query += `&searchStatus=${this.searchStatus}`; query += `&searchStatus=${this.searchStatus}`;

4
ui-ngx/src/app/shared/models/device.models.ts

@ -498,13 +498,15 @@ export interface CustomTimeSchedulerItem{
endsOn: number; endsOn: number;
} }
export interface AlarmRule { interface AlarmRule {
condition: AlarmCondition; condition: AlarmCondition;
alarmDetails?: string; alarmDetails?: string;
dashboardId?: DashboardId; dashboardId?: DashboardId;
schedule?: AlarmSchedule; schedule?: AlarmSchedule;
} }
export { AlarmRule as DeviceProfileAlarmRule };
export function alarmRuleValidator(control: AbstractControl): ValidationErrors | null { export function alarmRuleValidator(control: AbstractControl): ValidationErrors | null {
const alarmRule: AlarmRule = control.value; const alarmRule: AlarmRule = control.value;
return alarmRuleValid(alarmRule) ? null : {alarmRule: true}; return alarmRuleValid(alarmRule) ? null : {alarmRule: true};

36
ui-ngx/src/app/shared/models/entity-type.models.ts

@ -28,6 +28,7 @@ export enum EntityType {
DEVICE_PROFILE = 'DEVICE_PROFILE', DEVICE_PROFILE = 'DEVICE_PROFILE',
ASSET_PROFILE = 'ASSET_PROFILE', ASSET_PROFILE = 'ASSET_PROFILE',
ALARM = 'ALARM', ALARM = 'ALARM',
ALARM_RULE = 'ALARM_RULE',
RULE_CHAIN = 'RULE_CHAIN', RULE_CHAIN = 'RULE_CHAIN',
RULE_NODE = 'RULE_NODE', RULE_NODE = 'RULE_NODE',
EDGE = 'EDGE', EDGE = 'EDGE',
@ -251,12 +252,25 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
typePlural: 'entity.type-alarms', typePlural: 'entity.type-alarms',
list: 'entity.list-of-alarms', list: 'entity.list-of-alarms',
nameStartsWith: 'entity.alarm-name-starts-with', nameStartsWith: 'entity.alarm-name-starts-with',
details: 'dashboard.dashboard-details', details: 'alarm.alarm-details',
noEntities: 'alarm.no-alarms-prompt', noEntities: 'alarm.no-alarms-prompt',
search: 'alarm.search', search: 'alarm.search',
selectedEntities: 'alarm.selected-alarms' selectedEntities: 'alarm.selected-alarms'
} }
], ],
[
EntityType.ALARM_RULE,
{
type: 'entity.type-alarm-rule',
typePlural: 'entity.type-alarm-rules',
list: 'entity.list-of-alarm-rules',
nameStartsWith: 'entity.alarm-rule-name-starts-with',
details: 'alarm-rule.alarm-rule-details',
noEntities: 'alarm-rule.no-alarm-rules-prompt',
search: 'alarm-rule.search',
selectedEntities: 'alarm-rule.selected-alarm-rules'
}
],
[ [
EntityType.API_USAGE_STATE, EntityType.API_USAGE_STATE,
{ {
@ -388,6 +402,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
helpLinkId: 'assets' helpLinkId: 'assets'
} }
], ],
[
EntityType.ALARM_RULE,
{
helpLinkId: 'alarmRules'
}
],
[ [
EntityType.EDGE, EntityType.EDGE,
{ {
@ -445,15 +465,15 @@ export const baseDetailsPageByEntityType = new Map<EntityType, string>([
[EntityType.CUSTOMER, '/customers'], [EntityType.CUSTOMER, '/customers'],
[EntityType.USER, '/users'], [EntityType.USER, '/users'],
[EntityType.DASHBOARD, '/dashboards'], [EntityType.DASHBOARD, '/dashboards'],
[EntityType.ASSET, '/assets'], [EntityType.ASSET, '/entities/assets'],
[EntityType.DEVICE, '/devices'], [EntityType.DEVICE, '/entities/devices'],
[EntityType.DEVICE_PROFILE, '/profiles/deviceProfiles'], [EntityType.DEVICE_PROFILE, '/profiles/deviceProfiles'],
[EntityType.ASSET_PROFILE, '/profiles/assetProfiles'], [EntityType.ASSET_PROFILE, '/profiles/assetProfiles'],
[EntityType.RULE_CHAIN, '/ruleChains'], [EntityType.RULE_CHAIN, '/features/ruleChains'],
[EntityType.EDGE, '/edgeInstances'], [EntityType.EDGE, '/edgeManagement/instances'],
[EntityType.ENTITY_VIEW, '/entityViews'], [EntityType.ENTITY_VIEW, '/entities/entityViews'],
[EntityType.TB_RESOURCE, '/settings/resources-library'], [EntityType.TB_RESOURCE, '/resources/resources-library'],
[EntityType.OTA_PACKAGE, '/otaUpdates'], [EntityType.OTA_PACKAGE, '/features/otaUpdates'],
[EntityType.QUEUE, '/settings/queues'] [EntityType.QUEUE, '/settings/queues']
]); ]);

26
ui-ngx/src/app/shared/models/id/alarm-rule-id.ts

@ -0,0 +1,26 @@
///
/// 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 { EntityId } from './entity-id';
import { EntityType } from '@shared/models/entity-type.models';
export class AlarmRuleId implements EntityId {
entityType = EntityType.ALARM_RULE;
id: string;
constructor(id: string) {
this.id = id;
}
}

1
ui-ngx/src/app/shared/models/id/public-api.ts

@ -15,6 +15,7 @@
/// ///
export * from './alarm-id'; export * from './alarm-id';
export * from './alarm-rule-id';
export * from './asset-id'; export * from './asset-id';
export * from './audit-log-id'; export * from './audit-log-id';
export * from './customer-id'; export * from './customer-id';

1
ui-ngx/src/app/shared/models/public-api.ts

@ -19,6 +19,7 @@ export * from './page/public-api';
export * from './telemetry/telemetry.models'; export * from './telemetry/telemetry.models';
export * from './time/time.models'; export * from './time/time.models';
export * from './alarm.models'; export * from './alarm.models';
export * from './alarm-rule.models';
export * from './alias.models'; export * from './alias.models';
export * from './asset.models'; export * from './asset.models';
export * from './audit-log.models'; export * from './audit-log.models';

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

@ -76,9 +76,11 @@
"none": "None" "none": "None"
}, },
"admin": { "admin": {
"settings": "Settings",
"general": "General", "general": "General",
"general-settings": "General Settings", "general-settings": "General Settings",
"home-settings": "Home Settings", "home-settings": "Home Settings",
"home": "Home",
"outgoing-mail": "Mail Server", "outgoing-mail": "Mail Server",
"outgoing-mail-settings": "Outgoing Mail Server Settings", "outgoing-mail-settings": "Outgoing Mail Server Settings",
"system-settings": "System Settings", "system-settings": "System Settings",
@ -325,6 +327,7 @@
"queue-processing-strategy": "Processing strategy", "queue-processing-strategy": "Processing strategy",
"queue-configuration": "Queue configuration", "queue-configuration": "Queue configuration",
"repository-settings": "Repository settings", "repository-settings": "Repository settings",
"repository": "Repository",
"repository-url": "Repository URL", "repository-url": "Repository URL",
"repository-url-required": "Repository URL is required.", "repository-url-required": "Repository URL is required.",
"default-branch": "Default branch name", "default-branch": "Default branch name",
@ -346,6 +349,7 @@
"delete-repository-settings-title": "Are you sure you want to delete repository settings?", "delete-repository-settings-title": "Are you sure you want to delete repository settings?",
"delete-repository-settings-text": "Be careful, after the confirmation the repository settings will be removed and version control feature will be unavailable.", "delete-repository-settings-text": "Be careful, after the confirmation the repository settings will be removed and version control feature will be unavailable.",
"auto-commit-settings": "Auto-commit settings", "auto-commit-settings": "Auto-commit settings",
"auto-commit": "Auto-commit",
"auto-commit-entities": "Auto-commit entities", "auto-commit-entities": "Auto-commit entities",
"no-auto-commit-entities-prompt": "No entities configured for auto-commit", "no-auto-commit-entities-prompt": "No entities configured for auto-commit",
"delete-auto-commit-settings-title": "Are you sure you want to delete auto-commit settings?", "delete-auto-commit-settings-title": "Are you sure you want to delete auto-commit settings?",
@ -412,6 +416,7 @@
"alarm": { "alarm": {
"alarm": "Alarm", "alarm": "Alarm",
"alarms": "Alarms", "alarms": "Alarms",
"all-alarms": "All alarms",
"select-alarm": "Select alarm", "select-alarm": "Select alarm",
"no-alarms-matching": "No alarms matching '{{entity}}' were found.", "no-alarms-matching": "No alarms matching '{{entity}}' were found.",
"alarm-required": "Alarm is required", "alarm-required": "Alarm is required",
@ -479,6 +484,23 @@
"any-type": "Any type", "any-type": "Any type",
"search-propagated-alarms": "Search propagated alarms" "search-propagated-alarms": "Search propagated alarms"
}, },
"alarm-rule": {
"rules": "Rules",
"alarm-rule": "Alarm rule",
"alarm-rules": "Alarm rules",
"name": "Name",
"name-required": "Name is required.",
"name-max-length": "Name should be less than 256",
"delete": "Delete",
"alarm-rule-details": "Alarm rule details",
"no-alarm-rules-prompt": "No alarm rules found",
"search": "Search alarm rules",
"selected-alarm-rules": "{ count, plural, 1 {1 alarm rule} other {# alarm rules} } selected",
"delete-alarm-rule-title": "Are you sure you want to delete the alarm rule '{{alarmRuleName}}'?",
"delete-alarm-rule-text": "Be careful, after the confirmation the alarm rule and all related data will become unrecoverable.",
"delete-alarm-rules-title": "Are you sure you want to delete { count, plural, 1 {1 alarm rule} other {# alarm rules} }?",
"delete-alarm-rules-text": "Be careful, after the confirmation all selected alarm rules will be removed and all related data will become unrecoverable."
},
"alias": { "alias": {
"add": "Add alias", "add": "Add alias",
"edit": "Edit alias", "edit": "Edit alias",
@ -1706,6 +1728,7 @@
"edge": { "edge": {
"edge": "Edge", "edge": "Edge",
"edge-instances": "Edge instances", "edge-instances": "Edge instances",
"instances": "Instances",
"edge-file": "Edge file", "edge-file": "Edge file",
"name-max-length": "Name should be less than 256", "name-max-length": "Name should be less than 256",
"label-max-length": "Label should be less than 256", "label-max-length": "Label should be less than 256",
@ -1929,8 +1952,12 @@
"dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'",
"type-alarm": "Alarm", "type-alarm": "Alarm",
"type-alarms": "Alarms", "type-alarms": "Alarms",
"list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", "list-of-alarms": "{ count, plural, 1 {One alarm} other {List of # alarms} }",
"alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'", "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'",
"type-alarm-rule": "Alarm rule",
"type-alarm-rules": "Alarm rules",
"list-of-alarm-rules": "{ count, plural, 1 {One alarm rule} other {List of # alarm rules} }",
"alarm-rule-name-starts-with": "Alarm rules whose names start with '{{prefix}}'",
"type-rulechain": "Rule chain", "type-rulechain": "Rule chain",
"type-rulechains": "Rule chains", "type-rulechains": "Rule chains",
"list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }",
@ -2295,6 +2322,9 @@
"file": "Extensions file", "file": "Extensions file",
"invalid-file-error": "Invalid extension file" "invalid-file-error": "Invalid extension file"
}, },
"feature": {
"advanced-features": "Advanced features"
},
"filter": { "filter": {
"add": "Add filter", "add": "Add filter",
"edit": "Edit filter", "edit": "Edit filter",
@ -2676,6 +2706,14 @@
"copy-code": "Click to copy", "copy-code": "Click to copy",
"copied": "Copied!" "copied": "Copied!"
}, },
"notification": {
"notification-center": "Notification center",
"inbox": "Inbox",
"sent": "Sent",
"templates": "Templates",
"recipients": "Recipients",
"rules": "Rules"
},
"ota-update": { "ota-update": {
"add": "Add package", "add": "Add package",
"assign-firmware": "Assigned firmware", "assign-firmware": "Assigned firmware",

Loading…
Cancel
Save