Browse Source

UI: Menu improvements

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

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

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

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

@ -15,4 +15,4 @@
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.
*/
:host ::ng-deep {
tb-entities-table {
tb-entities-table.tb-details-mode {
.mat-drawer-container {
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 { DialogService } from '@core/services/dialog.service';
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 { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { ActivatedRoute } from '@angular/router';
import { isDefinedAndNotNull } from '@core/utils';
@Component({
selector: 'tb-alarm-table',
@ -37,6 +39,8 @@ export class AlarmTableComponent implements OnInit {
activeValue = false;
dirtyValue = false;
entityIdValue: EntityId;
alarmsMode = AlarmsMode.ENTITY;
detailsMode = true;
@Input()
set active(active: boolean) {
@ -71,20 +75,30 @@ export class AlarmTableComponent implements OnInit {
private translate: TranslateService,
private datePipe: DatePipe,
private dialog: MatDialog,
private store: Store<AppState>) {
private store: Store<AppState>,
private route: ActivatedRoute) {
}
ngOnInit() {
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.alarmService,
this.dialogService,
this.translate,
this.datePipe,
this.dialog,
this.alarmsMode,
this.entityIdValue,
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,
Validators
} from '@angular/forms';
import { AlarmRule } from '@shared/models/device.models';
import { DeviceProfileAlarmRule } from '@shared/models/device.models';
import { MatDialog } from '@angular/material/dialog';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { isDefinedAndNotNull } from '@core/utils';
@ -71,7 +71,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
@Input()
deviceProfileId: EntityId;
private modelValue: AlarmRule;
private modelValue: DeviceProfileAlarmRule;
alarmRuleFormGroup: UntypedFormGroup;
@ -112,7 +112,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
}
}
writeValue(value: AlarmRule): void {
writeValue(value: DeviceProfileAlarmRule): void {
this.modelValue = value;
const model = 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,
Validators
} 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 { Subscription } from 'rxjs';
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) {
this.valueChangeSubscription.unsubscribe();
}
@ -138,7 +138,7 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
}
public addCreateAlarmRule() {
const createAlarmRule: AlarmRule = {
const createAlarmRule: DeviceProfileAlarmRule = {
condition: {
condition: []
}
@ -179,15 +179,15 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
private updateUsedSeverities() {
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) => {
this.usedSeverities[index] = AlarmSeverity[rule.severity];
});
}
private updateModel() {
const value: {severity: string, alarmRule: AlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value;
const createAlarmRules: {[severity: string]: AlarmRule} = {};
const value: {severity: string, alarmRule: DeviceProfileAlarmRule}[] = this.createAlarmRulesFormGroup.get('createAlarmRules').value;
const createAlarmRules: {[severity: string]: DeviceProfileAlarmRule} = {};
value.forEach(v => {
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,
Validators
} 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 { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
@ -128,7 +128,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
}
public addClearAlarmRule() {
const clearAlarmRule: AlarmRule = {
const clearAlarmRule: DeviceProfileAlarmRule = {
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 { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-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 {
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 { widgetsBundlesRoutes } from '@home/pages/widget/widget-library-routing.module';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { auditLogsRoutes } from '@home/pages/audit-log/audit-log-routing.module';
@Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
@ -77,85 +70,7 @@ const routes: Routes = [
redirectTo: '/resources/widgets-bundles'
}
},
{
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
}
}
]
}
]
},
...widgetsBundlesRoutes,
{
path: 'resources-library',
data: {
@ -202,7 +117,7 @@ const routes: Routes = [
data: {
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
breadcrumb: {
label: 'admin.system-settings',
label: 'admin.settings',
icon: 'settings'
}
},
@ -303,7 +218,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN],
title: 'admin.home-settings',
breadcrumb: {
label: 'admin.home-settings',
label: 'admin.home',
icon: 'settings_applications'
}
}
@ -316,7 +231,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN],
title: 'admin.repository-settings',
breadcrumb: {
label: 'admin.repository-settings',
label: 'admin.repository',
icon: 'manage_history'
}
}
@ -329,7 +244,7 @@ const routes: Routes = [
auth: [Authority.TENANT_ADMIN],
title: 'admin.auto-commit-settings',
breadcrumb: {
label: 'admin.auto-commit-settings',
label: 'admin.auto-commit',
icon: 'settings_backup_restore'
}
}
@ -379,7 +294,7 @@ const routes: Routes = [
auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
redirectTo: {
SYS_ADMIN: '/security-settings/general',
TENANT_ADMIN: '/security-settings/audit-logs'
TENANT_ADMIN: '/security-settings/auditLogs'
}
}
},
@ -425,7 +340,8 @@ const routes: Routes = [
resolve: {
loginProcessingUrl: OAuth2LoginProcessingUrlResolver
}
}
},
...auditLogsRoutes
]
}
];
@ -436,12 +352,7 @@ const routes: Routes = [
providers: [
OAuth2LoginProcessingUrlResolver,
ResourcesLibraryTableConfigResolver,
QueuesTableConfigResolver,
WidgetsBundlesTableConfigResolver,
WidgetsBundleResolver,
WidgetsTypesDataResolver,
WidgetEditorDataResolver,
WidgetEditorAddDataResolver
QueuesTableConfigResolver
]
})
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 { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
const routes: Routes = [
export const assetRoutes: Routes = [
{
path: 'assets',
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({
imports: [RouterModule.forChild(routes)],
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 { AuditLogTableComponent } from '@home/components/audit-log/audit-log-table.component';
const routes: Routes = [
export const auditLogsRoutes: Routes = [
{
path: 'auditLogs',
component: AuditLogTableComponent,
@ -35,8 +35,16 @@ const routes: Routes = [
}
];
const routes: Routes = [
{
path: 'auditLogs',
redirectTo: '/security-settings/auditLogs'
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
exports: [RouterModule],
providers: []
})
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 { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models';
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',
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({
imports: [RouterModule.forChild(routes)],
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 = [
{
path: 'edgeInstances',
path: 'edgeManagement',
data: {
breadcrumb: {
label: 'edge.edge-instances',
icon: 'router'
label: 'edge.management',
icon: 'settings_input_antenna'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
children: [],
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.edge-instances',
edgesType: 'tenant'
},
resolve: {
entitiesTableConfig: EdgesTableConfigResolver
redirectTo: '/edgeManagement/instances'
}
},
{
path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
path: 'instances',
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
label: 'edge.instances',
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: [
@ -95,11 +74,11 @@ const routes: Routes = [
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets',
assetsType: 'edge'
title: 'edge.edge-instances',
edgesType: 'tenant'
},
resolve: {
entitiesTableConfig: AssetsTableConfigResolver
entitiesTableConfig: EdgesTableConfigResolver
}
},
{
@ -109,198 +88,219 @@ const routes: Routes = [
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
icon: 'domain'
icon: 'router'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.assets',
assetsType: 'edge'
title: 'edge.edge-instances',
edgesType: 'tenant'
},
resolve: {
entitiesTableConfig: AssetsTableConfigResolver
}
}
]
},
{
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
entitiesTableConfig: EdgesTableConfigResolver
}
},
{
path: ':entityId',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
path: ':edgeId/assets',
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: ':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'
label: 'edge.assets',
icon: 'domain'
}
},
resolve: {
entitiesTableConfig: EntityViewsTableConfigResolver
}
children: [
{
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',
component: EntityDetailsPageComponent,
canDeactivate: [ConfirmOnExitGuard],
path: ':edgeId/devices',
data: {
breadcrumb: {
labelFunction: entityDetailsPageBreadcrumbLabelFunction,
label: 'edge.devices',
icon: 'devices_other'
} as BreadCrumbConfig<EntityDetailsPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.entity-views',
entityViewsType: 'edge'
}
},
resolve: {
entitiesTableConfig: EntityViewsTableConfigResolver
}
}
]
},
{
path: ':edgeId/dashboards',
data: {
breadcrumb: {
label: 'edge.dashboards',
icon: 'dashboard'
}
},
children: [
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.devices',
devicesType: 'edge'
},
resolve: {
entitiesTableConfig: DevicesTableConfigResolver
}
},
{
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: '',
component: EntitiesTableComponent,
path: ':edgeId/entityViews',
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
dashboardsType: 'edge'
},
resolve: {
entitiesTableConfig: DashboardsTableConfigResolver
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: {
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',
component: DashboardPageComponent,
path: ':edgeId/dashboards',
data: {
breadcrumb: {
labelFunction: dashboardBreadcumbLabelFunction,
label: 'edge.dashboards',
icon: 'dashboard'
} as BreadCrumbConfig<DashboardPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.dashboard',
widgetEditMode: false
}
},
resolve: {
dashboard: DashboardResolver
}
}
]
},
{
path: ':edgeId/ruleChains',
data: {
breadcrumb: {
label: 'edge.edge-rulechains',
icon: 'settings_ethernet'
}
},
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN],
title: 'edge.rulechains',
ruleChainsType: 'edge'
},
resolve: {
entitiesTableConfig: RuleChainsTableConfigResolver
}
children: [
{
path: '',
component: EntitiesTableComponent,
data: {
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
dashboardsType: 'edge'
},
resolve: {
entitiesTableConfig: DashboardsTableConfigResolver
},
},
{
path: ':dashboardId',
component: DashboardPageComponent,
data: {
breadcrumb: {
labelFunction: dashboardBreadcumbLabelFunction,
icon: 'dashboard'
} as BreadCrumbConfig<DashboardPageComponent>,
auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
title: 'edge.dashboard',
widgetEditMode: false
},
resolve: {
dashboard: DashboardResolver
}
}
]
},
{
path: ':ruleChainId',
component: RuleChainPageComponent,
canDeactivate: [ConfirmOnExitGuard],
path: ':edgeId/ruleChains',
data: {
breadcrumb: {
labelFunction: ruleChainBreadcumbLabelFunction,
label: 'edge.edge-rulechains',
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
}
children: [
{
path: '',
component: EntitiesTableComponent,
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',
@ -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({
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';
break;
}
this.router.navigateByUrl(`edgeInstances/${edge.id.id}/${suffix}`);
this.router.navigateByUrl(`edgeManagement/instances/${edge.id.id}/${suffix}`);
}
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 { BreadCrumbConfig } from '@shared/components/breadcrumb';
const routes: Routes = [
export const entityViewRoutes: Routes = [
{
path: 'entityViews',
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({
imports: [RouterModule.forChild(routes)],
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 { AssetProfileModule } from '@home/pages/asset-profile/asset-profile.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({
exports: [
@ -50,8 +54,12 @@ import { ProfilesModule } from '@home/pages/profiles/profiles.module';
DeviceProfileModule,
AssetProfileModule,
ProfilesModule,
EntitiesModule,
FeaturesModule,
NotificationModule,
DeviceModule,
AssetModule,
AlarmModule,
EdgeModule,
EntityViewModule,
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 { BreadCrumbConfig } from '@shared/components/breadcrumb';
const routes: Routes = [
export const otaUpdatesRoutes: Routes = [
{
path: 'otaUpdates',
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({
imports: [RouterModule.forChild(routes)],
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}`;
});
const routes: Routes = [
export const ruleChainsRoutes: Routes = [
{
path: 'ruleChains',
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
@NgModule({
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') {
this.router.navigateByUrl(`edgeManagement/ruleChains/ruleChain/import`);
} 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 { VersionControlComponent } from '@home/components/vc/version-control.component';
const routes: Routes = [
export const vcRoutes: Routes = [
{
path: 'vc',
component: VersionControlComponent,
@ -36,6 +36,13 @@ const routes: Routes = [
}
];
const routes: Routes = [
{
path: 'vc',
redirectTo: '/features/vc'
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
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 { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component';
import { map } from 'rxjs/operators';
import { detailsToWidgetInfo, toWidgetInfo, WidgetInfo } from '@home/models/widget-component.models';
import { widgetType, WidgetType, WidgetTypeDetails } from '@app/shared/models/widget.models';
import { detailsToWidgetInfo, WidgetInfo } from '@home/models/widget-component.models';
import { widgetType, WidgetTypeDetails } from '@app/shared/models/widget.models';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { WidgetsData } from '@home/models/dashboard-component.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
@ -120,7 +120,89 @@ export const widgetTypesBreadcumbLabelFunction: BreadCrumbLabelFunction<any> = (
export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction<WidgetEditorComponent> =
((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',
pathMatch: 'full',
@ -146,6 +228,12 @@ export const routes: Routes = [
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: []
providers: [
WidgetsBundlesTableConfigResolver,
WidgetsBundleResolver,
WidgetsTypesDataResolver,
WidgetEditorDataResolver,
WidgetEditorAddDataResolver
]
})
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 { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models';
export enum AlarmsMode {
ALL,
ENTITY
}
export enum AlarmSeverity {
CRITICAL = 'CRITICAL',
MAJOR = 'MAJOR',
@ -218,7 +223,7 @@ export class AlarmQuery {
}
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();
if (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;
}
export interface AlarmRule {
interface AlarmRule {
condition: AlarmCondition;
alarmDetails?: string;
dashboardId?: DashboardId;
schedule?: AlarmSchedule;
}
export { AlarmRule as DeviceProfileAlarmRule };
export function alarmRuleValidator(control: AbstractControl): ValidationErrors | null {
const alarmRule: AlarmRule = control.value;
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',
ASSET_PROFILE = 'ASSET_PROFILE',
ALARM = 'ALARM',
ALARM_RULE = 'ALARM_RULE',
RULE_CHAIN = 'RULE_CHAIN',
RULE_NODE = 'RULE_NODE',
EDGE = 'EDGE',
@ -251,12 +252,25 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
typePlural: 'entity.type-alarms',
list: 'entity.list-of-alarms',
nameStartsWith: 'entity.alarm-name-starts-with',
details: 'dashboard.dashboard-details',
details: 'alarm.alarm-details',
noEntities: 'alarm.no-alarms-prompt',
search: 'alarm.search',
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,
{
@ -388,6 +402,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
helpLinkId: 'assets'
}
],
[
EntityType.ALARM_RULE,
{
helpLinkId: 'alarmRules'
}
],
[
EntityType.EDGE,
{
@ -445,15 +465,15 @@ export const baseDetailsPageByEntityType = new Map<EntityType, string>([
[EntityType.CUSTOMER, '/customers'],
[EntityType.USER, '/users'],
[EntityType.DASHBOARD, '/dashboards'],
[EntityType.ASSET, '/assets'],
[EntityType.DEVICE, '/devices'],
[EntityType.ASSET, '/entities/assets'],
[EntityType.DEVICE, '/entities/devices'],
[EntityType.DEVICE_PROFILE, '/profiles/deviceProfiles'],
[EntityType.ASSET_PROFILE, '/profiles/assetProfiles'],
[EntityType.RULE_CHAIN, '/ruleChains'],
[EntityType.EDGE, '/edgeInstances'],
[EntityType.ENTITY_VIEW, '/entityViews'],
[EntityType.TB_RESOURCE, '/settings/resources-library'],
[EntityType.OTA_PACKAGE, '/otaUpdates'],
[EntityType.RULE_CHAIN, '/features/ruleChains'],
[EntityType.EDGE, '/edgeManagement/instances'],
[EntityType.ENTITY_VIEW, '/entities/entityViews'],
[EntityType.TB_RESOURCE, '/resources/resources-library'],
[EntityType.OTA_PACKAGE, '/features/otaUpdates'],
[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-rule-id';
export * from './asset-id';
export * from './audit-log-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 './time/time.models';
export * from './alarm.models';
export * from './alarm-rule.models';
export * from './alias.models';
export * from './asset.models';
export * from './audit-log.models';

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

@ -76,9 +76,11 @@
"none": "None"
},
"admin": {
"settings": "Settings",
"general": "General",
"general-settings": "General Settings",
"home-settings": "Home Settings",
"home": "Home",
"outgoing-mail": "Mail Server",
"outgoing-mail-settings": "Outgoing Mail Server Settings",
"system-settings": "System Settings",
@ -325,6 +327,7 @@
"queue-processing-strategy": "Processing strategy",
"queue-configuration": "Queue configuration",
"repository-settings": "Repository settings",
"repository": "Repository",
"repository-url": "Repository URL",
"repository-url-required": "Repository URL is required.",
"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-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": "Auto-commit",
"auto-commit-entities": "Auto-commit entities",
"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?",
@ -412,6 +416,7 @@
"alarm": {
"alarm": "Alarm",
"alarms": "Alarms",
"all-alarms": "All alarms",
"select-alarm": "Select alarm",
"no-alarms-matching": "No alarms matching '{{entity}}' were found.",
"alarm-required": "Alarm is required",
@ -479,6 +484,23 @@
"any-type": "Any type",
"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": {
"add": "Add alias",
"edit": "Edit alias",
@ -1706,6 +1728,7 @@
"edge": {
"edge": "Edge",
"edge-instances": "Edge instances",
"instances": "Instances",
"edge-file": "Edge file",
"name-max-length": "Name 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}}'",
"type-alarm": "Alarm",
"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}}'",
"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-rulechains": "Rule chains",
"list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }",
@ -2295,6 +2322,9 @@
"file": "Extensions file",
"invalid-file-error": "Invalid extension file"
},
"feature": {
"advanced-features": "Advanced features"
},
"filter": {
"add": "Add filter",
"edit": "Edit filter",
@ -2676,6 +2706,14 @@
"copy-code": "Click to copy",
"copied": "Copied!"
},
"notification": {
"notification-center": "Notification center",
"inbox": "Inbox",
"sent": "Sent",
"templates": "Templates",
"recipients": "Recipients",
"rules": "Rules"
},
"ota-update": {
"add": "Add package",
"assign-firmware": "Assigned firmware",

Loading…
Cancel
Save