@c8y/ngx-components 1021.66.0 → 1021.70.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/common/bytes.pipe.d.ts +26 -10
- package/core/common/bytes.pipe.d.ts.map +1 -1
- package/echart/charts.component.d.ts +14 -3
- package/echart/charts.component.d.ts.map +1 -1
- package/esm2022/core/common/bytes.pipe.mjs +47 -18
- package/esm2022/core/data-grid/data-grid.component.mjs +3 -3
- package/esm2022/echart/charts.component.mjs +50 -3
- package/esm2022/messaging-management/api/model/backlogQuota.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespace.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespaceDetails.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespaceList.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespacePolicies.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespacePublishers.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespaceSubscribers.mjs +2 -0
- package/esm2022/messaging-management/api/model/namespaceTopics.mjs +2 -0
- package/esm2022/messaging-management/api/model/pageStatistics.mjs +2 -0
- package/esm2022/messaging-management/api/model/pageable.mjs +2 -0
- package/esm2022/messaging-management/api/model/sortable.mjs +2 -0
- package/esm2022/messaging-management/api/model/subscriber.mjs +2 -0
- package/esm2022/messaging-management/api/model/subscriberFilters.mjs +2 -0
- package/esm2022/messaging-management/api/model/subscriberList.mjs +2 -0
- package/esm2022/messaging-management/api/model/subscriberToDelete.mjs +2 -0
- package/esm2022/messaging-management/api/model/topic.mjs +2 -0
- package/esm2022/messaging-management/api/model/topicDetailFilters.mjs +2 -0
- package/esm2022/messaging-management/api/model/topicList.mjs +2 -0
- package/esm2022/messaging-management/api/model/topicListFilters.mjs +2 -0
- package/esm2022/messaging-management/api/model/topicType.mjs +9 -0
- package/esm2022/messaging-management/api/services/messaging-namespaces.service.mjs +83 -0
- package/esm2022/messaging-management/api/services/messaging-subscribers.service.mjs +55 -0
- package/esm2022/messaging-management/api/services/messaging-topics.service.mjs +48 -0
- package/esm2022/messaging-management/c8y-ngx-components-messaging-management.mjs +5 -0
- package/esm2022/messaging-management/constants.mjs +4 -0
- package/esm2022/messaging-management/index.mjs +2 -0
- package/esm2022/messaging-management/messaging/namespace-list/namespace-item/namespace-item-card/namespace-item-card.component.mjs +43 -0
- package/esm2022/messaging-management/messaging/namespace-list/namespace-item/namespace-item.component.mjs +36 -0
- package/esm2022/messaging-management/messaging/namespace-list/namespace-list.component.mjs +51 -0
- package/esm2022/messaging-management/messaging/shared/usage/usage.component.mjs +68 -0
- package/esm2022/messaging-management/messaging/topic/topic-list-view.component.mjs +81 -0
- package/esm2022/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-data-grid.service.mjs +220 -0
- package/esm2022/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-view.component.mjs +137 -0
- package/esm2022/messaging-management/messaging/topic/topics-data-grid.service.mjs +113 -0
- package/esm2022/messaging-management/messaging-management.guard.mjs +40 -0
- package/esm2022/messaging-management/messaging-management.module.mjs +72 -0
- package/esm2022/messaging-management/navigator/messaging-navigator-factory.mjs +55 -0
- package/esm2022/messaging-management/navigator/topic-details-tab.factory.mjs +33 -0
- package/esm2022/messaging-management/utils/backlog-quota-limit.pipe.mjs +32 -0
- package/esm2022/messaging-management/utils/namespace-props.mjs +23 -0
- package/esm2022/messaging-management/utils/time-to-live.pipe.mjs +122 -0
- package/esm2022/operations/device-selector/device-selector.component.mjs +5 -1
- package/esm2022/widgets/cockpit/index.mjs +3 -1
- package/esm2022/widgets/cockpit-exports/index.mjs +8 -1
- package/esm2022/widgets/definitions/index.mjs +2 -1
- package/esm2022/widgets/definitions/radial-gauge/c8y-ngx-components-widgets-definitions-radial-gauge.mjs +5 -0
- package/esm2022/widgets/definitions/radial-gauge/index.mjs +33 -0
- package/esm2022/widgets/implementations/datapoints-graph/datapoints-graph-view/datapoints-graph-widget-view.component.mjs +18 -3
- package/esm2022/widgets/implementations/info-gauge/index.mjs +2 -2
- package/esm2022/widgets/implementations/info-gauge/info-gauge-widget-config/gauge.model.mjs +295 -0
- package/esm2022/widgets/implementations/info-gauge/info-gauge-widget-config/info-gauge-widget-config.component.mjs +141 -11
- package/esm2022/widgets/implementations/info-gauge/info-gauge-widget-config/preset-preview/preset-preview.component.mjs +67 -0
- package/esm2022/widgets/implementations/info-gauge/info-gauge-widget-view/info-gauge-widget-view.component.mjs +34 -6
- package/esm2022/widgets/implementations/info-gauge/info-gauge-widget.module.mjs +9 -4
- package/esm2022/widgets/implementations/info-gauge/radial-gauge/radial-gauge.component.mjs +97 -0
- package/esm2022/widgets/implementations/info-gauge/radial-gauge/radial-gauge.service.mjs +369 -0
- package/fesm2022/c8y-ngx-components-echart.mjs +49 -2
- package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-messaging-management.mjs +1225 -0
- package/fesm2022/c8y-ngx-components-messaging-management.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-operations-device-selector.mjs +4 -0
- package/fesm2022/c8y-ngx-components-operations-device-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-cockpit-exports.mjs +7 -0
- package/fesm2022/c8y-ngx-components-widgets-cockpit-exports.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-cockpit.mjs +2 -0
- package/fesm2022/c8y-ngx-components-widgets-cockpit.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-radial-gauge.mjs +40 -0
- package/fesm2022/c8y-ngx-components-widgets-definitions-radial-gauge.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-widgets-definitions.mjs +1 -0
- package/fesm2022/c8y-ngx-components-widgets-definitions.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +17 -2
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs +991 -28
- package/fesm2022/c8y-ngx-components-widgets-implementations-info-gauge.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +49 -22
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/de.po +272 -5
- package/locales/es.po +271 -4
- package/locales/fr.po +272 -5
- package/locales/ja_JP.po +272 -5
- package/locales/ko.po +271 -4
- package/locales/locales.pot +271 -4
- package/locales/nl.po +271 -4
- package/locales/pl.po +271 -4
- package/locales/pt_BR.po +272 -5
- package/locales/zh_CN.po +271 -4
- package/locales/zh_TW.po +272 -5
- package/messaging-management/api/model/backlogQuota.d.ts +14 -0
- package/messaging-management/api/model/backlogQuota.d.ts.map +1 -0
- package/messaging-management/api/model/namespace.d.ts +13 -0
- package/messaging-management/api/model/namespace.d.ts.map +1 -0
- package/messaging-management/api/model/namespaceDetails.d.ts +8 -0
- package/messaging-management/api/model/namespaceDetails.d.ts.map +1 -0
- package/messaging-management/api/model/namespaceList.d.ts +5 -0
- package/messaging-management/api/model/namespaceList.d.ts.map +1 -0
- package/messaging-management/api/model/namespacePolicies.d.ts +10 -0
- package/messaging-management/api/model/namespacePolicies.d.ts.map +1 -0
- package/messaging-management/api/model/namespacePublishers.d.ts +4 -0
- package/messaging-management/api/model/namespacePublishers.d.ts.map +1 -0
- package/messaging-management/api/model/namespaceSubscribers.d.ts +4 -0
- package/messaging-management/api/model/namespaceSubscribers.d.ts.map +1 -0
- package/messaging-management/api/model/namespaceTopics.d.ts +5 -0
- package/messaging-management/api/model/namespaceTopics.d.ts.map +1 -0
- package/messaging-management/api/model/pageStatistics.d.ts +12 -0
- package/messaging-management/api/model/pageStatistics.d.ts.map +1 -0
- package/messaging-management/api/model/pageable.d.ts +8 -0
- package/messaging-management/api/model/pageable.d.ts.map +1 -0
- package/messaging-management/api/model/sortable.d.ts +6 -0
- package/messaging-management/api/model/sortable.d.ts.map +1 -0
- package/messaging-management/api/model/subscriber.d.ts +28 -0
- package/messaging-management/api/model/subscriber.d.ts.map +1 -0
- package/messaging-management/api/model/subscriberFilters.d.ts +13 -0
- package/messaging-management/api/model/subscriberFilters.d.ts.map +1 -0
- package/messaging-management/api/model/subscriberList.d.ts +7 -0
- package/messaging-management/api/model/subscriberList.d.ts.map +1 -0
- package/messaging-management/api/model/subscriberToDelete.d.ts +12 -0
- package/messaging-management/api/model/subscriberToDelete.d.ts.map +1 -0
- package/messaging-management/api/model/topic.d.ts +52 -0
- package/messaging-management/api/model/topic.d.ts.map +1 -0
- package/messaging-management/api/model/topicDetailFilters.d.ts +9 -0
- package/messaging-management/api/model/topicDetailFilters.d.ts.map +1 -0
- package/messaging-management/api/model/topicList.d.ts +7 -0
- package/messaging-management/api/model/topicList.d.ts.map +1 -0
- package/messaging-management/api/model/topicListFilters.d.ts +12 -0
- package/messaging-management/api/model/topicListFilters.d.ts.map +1 -0
- package/messaging-management/api/model/topicType.d.ts +8 -0
- package/messaging-management/api/model/topicType.d.ts.map +1 -0
- package/messaging-management/api/services/messaging-namespaces.service.d.ts +52 -0
- package/messaging-management/api/services/messaging-namespaces.service.d.ts.map +1 -0
- package/messaging-management/api/services/messaging-subscribers.service.d.ts +30 -0
- package/messaging-management/api/services/messaging-subscribers.service.d.ts.map +1 -0
- package/messaging-management/api/services/messaging-topics.service.d.ts +21 -0
- package/messaging-management/api/services/messaging-topics.service.d.ts.map +1 -0
- package/messaging-management/c8y-ngx-components-messaging-management.d.ts.map +1 -0
- package/messaging-management/constants.d.ts +4 -0
- package/messaging-management/constants.d.ts.map +1 -0
- package/messaging-management/index.d.ts +2 -0
- package/messaging-management/index.d.ts.map +1 -0
- package/messaging-management/messaging/namespace-list/namespace-item/namespace-item-card/namespace-item-card.component.d.ts +29 -0
- package/messaging-management/messaging/namespace-list/namespace-item/namespace-item-card/namespace-item-card.component.d.ts.map +1 -0
- package/messaging-management/messaging/namespace-list/namespace-item/namespace-item.component.d.ts +15 -0
- package/messaging-management/messaging/namespace-list/namespace-item/namespace-item.component.d.ts.map +1 -0
- package/messaging-management/messaging/namespace-list/namespace-list.component.d.ts +17 -0
- package/messaging-management/messaging/namespace-list/namespace-list.component.d.ts.map +1 -0
- package/messaging-management/messaging/shared/usage/usage.component.d.ts +40 -0
- package/messaging-management/messaging/shared/usage/usage.component.d.ts.map +1 -0
- package/messaging-management/messaging/topic/topic-list-view.component.d.ts +38 -0
- package/messaging-management/messaging/topic/topic-list-view.component.d.ts.map +1 -0
- package/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-data-grid.service.d.ts +21 -0
- package/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-data-grid.service.d.ts.map +1 -0
- package/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-view.component.d.ts +52 -0
- package/messaging-management/messaging/topic/topic-subscribers-view/topic-subscribers-view.component.d.ts.map +1 -0
- package/messaging-management/messaging/topic/topics-data-grid.service.d.ts +13 -0
- package/messaging-management/messaging/topic/topics-data-grid.service.d.ts.map +1 -0
- package/messaging-management/messaging-management.guard.d.ts +12 -0
- package/messaging-management/messaging-management.guard.d.ts.map +1 -0
- package/messaging-management/messaging-management.module.d.ts +7 -0
- package/messaging-management/messaging-management.module.d.ts.map +1 -0
- package/messaging-management/navigator/messaging-navigator-factory.d.ts +18 -0
- package/messaging-management/navigator/messaging-navigator-factory.d.ts.map +1 -0
- package/messaging-management/navigator/topic-details-tab.factory.d.ts +15 -0
- package/messaging-management/navigator/topic-details-tab.factory.d.ts.map +1 -0
- package/messaging-management/utils/backlog-quota-limit.pipe.d.ts +13 -0
- package/messaging-management/utils/backlog-quota-limit.pipe.d.ts.map +1 -0
- package/messaging-management/utils/namespace-props.d.ts +10 -0
- package/messaging-management/utils/namespace-props.d.ts.map +1 -0
- package/messaging-management/utils/time-to-live.pipe.d.ts +16 -0
- package/messaging-management/utils/time-to-live.pipe.d.ts.map +1 -0
- package/operations/device-selector/device-selector.component.d.ts.map +1 -1
- package/package.json +1 -1
- package/widgets/cockpit/index.d.ts +29 -0
- package/widgets/cockpit/index.d.ts.map +1 -1
- package/widgets/cockpit-exports/index.d.ts +6 -0
- package/widgets/cockpit-exports/index.d.ts.map +1 -1
- package/widgets/definitions/index.d.ts +1 -0
- package/widgets/definitions/index.d.ts.map +1 -1
- package/widgets/definitions/radial-gauge/c8y-ngx-components-widgets-definitions-radial-gauge.d.ts.map +1 -0
- package/widgets/definitions/radial-gauge/index.d.ts +33 -0
- package/widgets/definitions/radial-gauge/index.d.ts.map +1 -0
- package/widgets/implementations/datapoints-graph/datapoints-graph-view/datapoints-graph-widget-view.component.d.ts +2 -0
- package/widgets/implementations/datapoints-graph/datapoints-graph-view/datapoints-graph-widget-view.component.d.ts.map +1 -1
- package/widgets/implementations/info-gauge/index.d.ts +1 -1
- package/widgets/implementations/info-gauge/index.d.ts.map +1 -1
- package/widgets/implementations/info-gauge/info-gauge-widget-config/gauge.model.d.ts +339 -0
- package/widgets/implementations/info-gauge/info-gauge-widget-config/gauge.model.d.ts.map +1 -0
- package/widgets/implementations/info-gauge/info-gauge-widget-config/info-gauge-widget-config.component.d.ts +27 -7
- package/widgets/implementations/info-gauge/info-gauge-widget-config/info-gauge-widget-config.component.d.ts.map +1 -1
- package/widgets/implementations/info-gauge/info-gauge-widget-config/preset-preview/preset-preview.component.d.ts +33 -0
- package/widgets/implementations/info-gauge/info-gauge-widget-config/preset-preview/preset-preview.component.d.ts.map +1 -0
- package/widgets/implementations/info-gauge/info-gauge-widget-view/info-gauge-widget-view.component.d.ts +7 -3
- package/widgets/implementations/info-gauge/info-gauge-widget-view/info-gauge-widget-view.component.d.ts.map +1 -1
- package/widgets/implementations/info-gauge/info-gauge-widget.module.d.ts +2 -1
- package/widgets/implementations/info-gauge/info-gauge-widget.module.d.ts.map +1 -1
- package/widgets/implementations/info-gauge/radial-gauge/radial-gauge.component.d.ts +37 -0
- package/widgets/implementations/info-gauge/radial-gauge/radial-gauge.component.d.ts.map +1 -0
- package/widgets/implementations/info-gauge/radial-gauge/radial-gauge.service.d.ts +146 -0
- package/widgets/implementations/info-gauge/radial-gauge/radial-gauge.service.d.ts.map +1 -0
- package/esm2022/widgets/implementations/info-gauge/info-gauge.model.mjs +0 -2
- package/widgets/implementations/info-gauge/info-gauge.model.d.ts +0 -7
- package/widgets/implementations/info-gauge/info-gauge.model.d.ts.map +0 -1
|
@@ -0,0 +1,1225 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable, LOCALE_ID, Pipe, input, computed, Component, Input, DestroyRef, EventEmitter, ViewChild, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1$1 from '@c8y/ngx-components';
|
|
4
|
+
import { gettext, AlertService, Permissions, NavigatorNode, AppStateService, NavigatorService, IconDirective, C8yTranslatePipe, C8yTranslateModule, HeaderModule, HelpModule, BreadcrumbModule, ActionBarItemComponent, LoadingComponent, BaseColumn, DataGridModule, BytesPipe, EmptyStateComponent, EmptyStateContextDirective, ModalService, Status, DataGridComponent, C8yTranslateDirective, RelativeTimePipe, hookRoute, hookTab, hookNavigator } from '@c8y/ngx-components';
|
|
5
|
+
import * as i1 from '@c8y/client';
|
|
6
|
+
import { Service, UserService, FeatureService, ApplicationService, Paging } from '@c8y/client';
|
|
7
|
+
import { filter, map, take, switchMap, catchError, shareReplay, tap } from 'rxjs/operators';
|
|
8
|
+
import { from, BehaviorSubject, combineLatest, firstValueFrom } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
import { formatNumber, NgIf, NgClass, PercentPipe, CommonModule, DecimalPipe, AsyncPipe } from '@angular/common';
|
|
11
|
+
import * as i1$3 from '@angular/router';
|
|
12
|
+
import { RouterLink, ActivatedRoute } from '@angular/router';
|
|
13
|
+
import * as i1$2 from '@ngx-translate/core';
|
|
14
|
+
import { TranslateService } from '@ngx-translate/core';
|
|
15
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
16
|
+
import { omit } from 'lodash-es';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Currently known namespaces and their properties.
|
|
20
|
+
*/
|
|
21
|
+
const NAMESPACE_PROPS = {
|
|
22
|
+
mqtt: {
|
|
23
|
+
icon: 'c8y-device-protocols',
|
|
24
|
+
label: gettext('MQTT Service')
|
|
25
|
+
},
|
|
26
|
+
'data-broker-fwd': {
|
|
27
|
+
icon: 'c8y-data-broker',
|
|
28
|
+
label: gettext('Data Broker')
|
|
29
|
+
},
|
|
30
|
+
relnotif: {
|
|
31
|
+
icon: 'c8y-notification',
|
|
32
|
+
label: gettext('Notifications 2.0')
|
|
33
|
+
},
|
|
34
|
+
'streaming-analytics': {
|
|
35
|
+
icon: 'c8y-streaming-analytics',
|
|
36
|
+
label: gettext('Streaming Analytics')
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
class MessagingNamespacesService extends Service {
|
|
41
|
+
constructor(client) {
|
|
42
|
+
super(client);
|
|
43
|
+
this.baseUrl = '/service/messaging-management';
|
|
44
|
+
this.listUrl = 'tenants';
|
|
45
|
+
this.alertService = inject(AlertService);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get namespace list for a tenant
|
|
49
|
+
*
|
|
50
|
+
* @param tenant Tenant id
|
|
51
|
+
* @return Namespaces list
|
|
52
|
+
*/
|
|
53
|
+
async getNamespaces(tenant) {
|
|
54
|
+
const namespacesUrl = `/${this.listUrl}/${tenant}/namespaces`;
|
|
55
|
+
return this.fetch(namespacesUrl).then(res => res.json());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get namespace.
|
|
59
|
+
*
|
|
60
|
+
* @param tenant Tenant ID.
|
|
61
|
+
* @param namespace Name of namespace.
|
|
62
|
+
* @return Namespace.
|
|
63
|
+
*/
|
|
64
|
+
async getNamespace(tenant, namespace) {
|
|
65
|
+
const namespaceUrl = `/${this.listUrl}/${tenant}/namespaces/${namespace}`;
|
|
66
|
+
return this.fetch(namespaceUrl).then(res => res.json());
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get namespace policies
|
|
70
|
+
*
|
|
71
|
+
* @param tenant Tenant id
|
|
72
|
+
* @param namespace Name of namespace
|
|
73
|
+
* @return Namespaces policies
|
|
74
|
+
*/
|
|
75
|
+
async getNamespacePolicies(tenant, namespace) {
|
|
76
|
+
const policiesUrl = `/${this.listUrl}/${tenant}/namespaces/${namespace}/policies`;
|
|
77
|
+
return this.fetch(policiesUrl).then(res => res.json());
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get single namespace details
|
|
81
|
+
* @param tenant Tenant ID
|
|
82
|
+
* @param namespaceName Namespace name
|
|
83
|
+
* @return Namespace with details
|
|
84
|
+
*/
|
|
85
|
+
async getNamespaceDetails(tenant, namespaceName) {
|
|
86
|
+
const namespace = await this.getNamespace(tenant, namespaceName);
|
|
87
|
+
const policies = await this.getNamespacePolicies(tenant, namespaceName);
|
|
88
|
+
return {
|
|
89
|
+
id: namespaceName,
|
|
90
|
+
namespace,
|
|
91
|
+
policies
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get namespaces with details
|
|
96
|
+
*
|
|
97
|
+
* @param tenant Tenant ID
|
|
98
|
+
* @return Namespaces with details
|
|
99
|
+
*/
|
|
100
|
+
async getNamespacesDetails(tenant) {
|
|
101
|
+
try {
|
|
102
|
+
const { namespaces } = await this.getNamespaces(tenant);
|
|
103
|
+
return Promise.all(namespaces.map(async (namespace) => this.getNamespaceDetails(tenant, namespace.name)));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.alertService.addServerFailure(error);
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNamespacesService, deps: [{ token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
111
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNamespacesService, providedIn: 'root' }); }
|
|
112
|
+
}
|
|
113
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNamespacesService, decorators: [{
|
|
114
|
+
type: Injectable,
|
|
115
|
+
args: [{ providedIn: 'root' }]
|
|
116
|
+
}], ctorParameters: () => [{ type: i1.FetchClient }] });
|
|
117
|
+
|
|
118
|
+
const basePath = 'monitoring/messaging-service';
|
|
119
|
+
const MESSAGING_MANAGEMENT_FEATURE_KEY = 'messaging-management.api';
|
|
120
|
+
const MESSAGING_MANAGEMENT_MICROSERVICE_NAME = 'messaging-management';
|
|
121
|
+
|
|
122
|
+
class MessagingManagementGuard {
|
|
123
|
+
constructor() {
|
|
124
|
+
this.userService = inject(UserService);
|
|
125
|
+
this.featureService = inject(FeatureService);
|
|
126
|
+
this.applicationService = inject(ApplicationService);
|
|
127
|
+
this.cachedResult = null;
|
|
128
|
+
}
|
|
129
|
+
async canActivate() {
|
|
130
|
+
if (this.cachedResult !== null) {
|
|
131
|
+
return this.cachedResult;
|
|
132
|
+
}
|
|
133
|
+
const currentUser = (await this.userService.current()).data;
|
|
134
|
+
const hasRequiredRoles = this.userService.hasAnyRole(currentUser, [
|
|
135
|
+
Permissions.ROLE_TENANT_STATISTICS_READ,
|
|
136
|
+
Permissions.ROLE_TENANT_MANAGEMENT_ADMIN
|
|
137
|
+
]);
|
|
138
|
+
const featureEnabled = await this.featureService
|
|
139
|
+
.detail(MESSAGING_MANAGEMENT_FEATURE_KEY)
|
|
140
|
+
.then(({ data }) => data.active)
|
|
141
|
+
.catch(() => false);
|
|
142
|
+
const microserviceSubscribed = await this.applicationService
|
|
143
|
+
.isAvailable(MESSAGING_MANAGEMENT_MICROSERVICE_NAME)
|
|
144
|
+
.then(({ data: subscribed }) => subscribed)
|
|
145
|
+
.catch(() => false);
|
|
146
|
+
this.cachedResult = hasRequiredRoles && featureEnabled && microserviceSubscribed;
|
|
147
|
+
return this.cachedResult;
|
|
148
|
+
}
|
|
149
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
150
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementGuard, providedIn: 'root' }); }
|
|
151
|
+
}
|
|
152
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementGuard, decorators: [{
|
|
153
|
+
type: Injectable,
|
|
154
|
+
args: [{ providedIn: 'root' }]
|
|
155
|
+
}] });
|
|
156
|
+
|
|
157
|
+
const baseNode = new NavigatorNode({
|
|
158
|
+
label: gettext('Messaging service'),
|
|
159
|
+
icon: 'arrows-dotted-left-right',
|
|
160
|
+
path: 'monitoring/messaging-service',
|
|
161
|
+
priority: 100,
|
|
162
|
+
parent: {
|
|
163
|
+
label: gettext('Monitoring'),
|
|
164
|
+
icon: 'monitoring'
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
class MessagingNavigatorNodeFactory {
|
|
168
|
+
constructor() {
|
|
169
|
+
this.appState = inject(AppStateService);
|
|
170
|
+
this.navigatorService = inject(NavigatorService);
|
|
171
|
+
this.namespacesService = inject(MessagingNamespacesService);
|
|
172
|
+
this.guard = inject(MessagingManagementGuard);
|
|
173
|
+
this.currentTenantId = this.appState.currentTenant.pipe(filter(currentTenant => !!currentTenant), map(currentTenant => currentTenant.name), take(1));
|
|
174
|
+
this.navigatorNode$ = from(this.guard.canActivate()).pipe(filter(allowed => allowed), switchMap(() => this.currentTenantId), switchMap(currentTenantId => this.namespacesService.getNamespaces(currentTenantId)), map(({ namespaces }) => {
|
|
175
|
+
if (!namespaces?.length) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
namespaces.forEach(namespace => {
|
|
179
|
+
const label = NAMESPACE_PROPS[namespace.name]?.label || namespace.name;
|
|
180
|
+
const childNode = new NavigatorNode({
|
|
181
|
+
label,
|
|
182
|
+
path: `monitoring/messaging-service/namespace/${namespace.name}`,
|
|
183
|
+
icon: NAMESPACE_PROPS[namespace.name]?.icon,
|
|
184
|
+
routerLinkExact: false
|
|
185
|
+
});
|
|
186
|
+
baseNode.add(childNode);
|
|
187
|
+
});
|
|
188
|
+
return baseNode;
|
|
189
|
+
}), catchError(() => {
|
|
190
|
+
return [];
|
|
191
|
+
}), shareReplay(1));
|
|
192
|
+
}
|
|
193
|
+
get() {
|
|
194
|
+
return this.navigatorNode$;
|
|
195
|
+
}
|
|
196
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNavigatorNodeFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
197
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNavigatorNodeFactory, providedIn: 'root' }); }
|
|
198
|
+
}
|
|
199
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingNavigatorNodeFactory, decorators: [{
|
|
200
|
+
type: Injectable,
|
|
201
|
+
args: [{ providedIn: 'root' }]
|
|
202
|
+
}], ctorParameters: () => [] });
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* In case of limits in Messaging management, value of '-1' means that there is no limit.
|
|
206
|
+
*/
|
|
207
|
+
class BacklogQuotaLimitPipe {
|
|
208
|
+
constructor() {
|
|
209
|
+
this.translateService = inject(TranslateService);
|
|
210
|
+
this.locale = inject(LOCALE_ID);
|
|
211
|
+
}
|
|
212
|
+
transform(value) {
|
|
213
|
+
if (value == null || isNaN(value)) {
|
|
214
|
+
return '-';
|
|
215
|
+
}
|
|
216
|
+
else if (value === -1) {
|
|
217
|
+
return this.translateService.instant(gettext('Unlimited` backlog quota`'));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
return formatNumber(value, this.locale);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BacklogQuotaLimitPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
224
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: BacklogQuotaLimitPipe, isStandalone: true, name: "backlogQuotaLimit" }); }
|
|
225
|
+
}
|
|
226
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BacklogQuotaLimitPipe, decorators: [{
|
|
227
|
+
type: Pipe,
|
|
228
|
+
args: [{ name: 'backlogQuotaLimit', standalone: true }]
|
|
229
|
+
}] });
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Usage component displays usage information in a form of e.g. "51% used".
|
|
233
|
+
* It can be used in two ways:
|
|
234
|
+
* 1. By providing `count` and `limit` inputs, it will calculate the usage percentage.
|
|
235
|
+
* 2. By providing `percentage` input, it will use the provided percentage value.
|
|
236
|
+
* Note: `percentage` input takes precedence over `count` and `limit` inputs.
|
|
237
|
+
*/
|
|
238
|
+
class UsageComponent {
|
|
239
|
+
constructor() {
|
|
240
|
+
this.count = input(null);
|
|
241
|
+
this.limit = input(null);
|
|
242
|
+
/**
|
|
243
|
+
* Percentage of usage. Value range is from 0 to 100 (or more).
|
|
244
|
+
* For example, if 10% is used, this value should be provided as 10 (not 0.1).
|
|
245
|
+
*/
|
|
246
|
+
this.percentage = input(null);
|
|
247
|
+
/**
|
|
248
|
+
* Usage as a fraction (e.g. if 50% is used, usage value will be 0.5)
|
|
249
|
+
*/
|
|
250
|
+
this.usage = computed(() => this.percentage() != null ? this.percentage() / 100 : this.getUsage(this.count(), this.limit()));
|
|
251
|
+
this.status = computed(() => this.getStatus(this.usage()));
|
|
252
|
+
this.usageToDisplay = gettext('{{ percentageOfQuota }} used');
|
|
253
|
+
this.statusMap = {
|
|
254
|
+
danger: ['tag--danger'],
|
|
255
|
+
warning: ['tag--warning'],
|
|
256
|
+
success: ['tag--success']
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Get usage as fraction of count and limit.
|
|
261
|
+
* E.g. if count is 5 and limit is 10, returned usage will be 0.5
|
|
262
|
+
* @param count Usage count
|
|
263
|
+
* @param limit Usage limit
|
|
264
|
+
* @returns Count divided by limit or null if count or limit is null or limit is -1 (indicates no limit)
|
|
265
|
+
*/
|
|
266
|
+
getUsage(count, limit) {
|
|
267
|
+
if (count == null || limit == null || limit === -1) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
return count / limit;
|
|
271
|
+
}
|
|
272
|
+
getStatus(usage) {
|
|
273
|
+
if (usage == null) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
const percentage = usage * 100;
|
|
277
|
+
if (percentage >= 80) {
|
|
278
|
+
return 'danger';
|
|
279
|
+
}
|
|
280
|
+
else if (percentage >= 50) {
|
|
281
|
+
return 'warning';
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
return 'success';
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UsageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
288
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: UsageComponent, isStandalone: true, selector: "app-usage", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, percentage: { classPropertyName: "percentage", publicName: "percentage", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div\n class=\"tag no-pointer\"\n [ngClass]=\"statusMap[status()]\"\n *ngIf=\"usage() !== null\"\n>\n <i\n class=\"text-danger m-r-4 text-12\"\n c8yIcon=\"exclamation-circle\"\n *ngIf=\"status() === 'danger'\"\n ></i>\n <span>\n {{ usageToDisplay | translate: { percentageOfQuota: (usage() | percent: '1.0-2') } }}\n </span>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: PercentPipe, name: "percent" }] }); }
|
|
289
|
+
}
|
|
290
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UsageComponent, decorators: [{
|
|
291
|
+
type: Component,
|
|
292
|
+
args: [{ selector: 'app-usage', standalone: true, imports: [IconDirective, NgIf, NgClass, IconDirective, C8yTranslatePipe, PercentPipe], host: { class: 'd-contents' }, template: "<div\n class=\"tag no-pointer\"\n [ngClass]=\"statusMap[status()]\"\n *ngIf=\"usage() !== null\"\n>\n <i\n class=\"text-danger m-r-4 text-12\"\n c8yIcon=\"exclamation-circle\"\n *ngIf=\"status() === 'danger'\"\n ></i>\n <span>\n {{ usageToDisplay | translate: { percentageOfQuota: (usage() | percent: '1.0-2') } }}\n </span>\n</div>\n" }]
|
|
293
|
+
}] });
|
|
294
|
+
|
|
295
|
+
const DataType = {
|
|
296
|
+
publishers: 'publishers',
|
|
297
|
+
subscribers: 'subscribers',
|
|
298
|
+
topics: 'topics'
|
|
299
|
+
};
|
|
300
|
+
class NamespaceItemCardComponent {
|
|
301
|
+
constructor() {
|
|
302
|
+
this.DATA_TYPE = DataType;
|
|
303
|
+
this.ITEM_DETAILS = {
|
|
304
|
+
publishers: { icon: 'output', title: gettext('Publishers') },
|
|
305
|
+
subscribers: { icon: 'input', title: gettext('Subscribers') },
|
|
306
|
+
topics: { icon: 'day-view', title: gettext('Topics') }
|
|
307
|
+
};
|
|
308
|
+
this.topicsLimitLabel = gettext('Limit: {{ backlogQuotaLimit }}');
|
|
309
|
+
/**
|
|
310
|
+
* The label of the service (already translated).
|
|
311
|
+
*/
|
|
312
|
+
this.serviceLabel = '';
|
|
313
|
+
}
|
|
314
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceItemCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
315
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: NamespaceItemCardComponent, isStandalone: true, selector: "app-namespace-item-card", inputs: { serviceLabel: "serviceLabel", limit: "limit", dataType: "dataType", value: "value" }, host: { classAttribute: "card m-b-0 fit-w" }, ngImport: i0, template: "<div class=\"card-block text-default visible-xs text-center p-b-0\">\n <span class=\"text-12 text-uppercase text-muted\">\n {{ serviceLabel | translate }}\n </span>\n</div>\n<div\n class=\"card-block text-default p-t-sm-48\"\n [ngClass]=\"{\n 'p-b-sm-48': limit === 0\n }\"\n>\n <div class=\"d-flex fit-w a-i-center gap-8 j-c-center\">\n <i\n class=\"icon-32 c8y-icon-duocolor\"\n [c8yIcon]=\"ITEM_DETAILS[dataType].icon\"\n ></i>\n <span class=\"h1\">\n {{ value | number }}\n </span>\n <span\n class=\"a-s-baseline text-14 text-medium text-truncate\"\n title=\"{{ ITEM_DETAILS[dataType].title | translate }}\"\n >\n {{ ITEM_DETAILS[dataType].title | translate }}\n </span>\n </div>\n</div>\n<div\n class=\"card-footer d-flex gap-16 j-c-center a-i-center\"\n *ngIf=\"dataType === DATA_TYPE.topics && limit !== 0\"\n>\n <span\n class=\"tag tag--default no-pointer\"\n data-cy=\"card-limit\"\n >\n {{ topicsLimitLabel | translate: { backlogQuotaLimit: limit | backlogQuotaLimit } }}\n </span>\n <app-usage\n [count]=\"value\"\n [limit]=\"limit\"\n ></app-usage>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: C8yTranslateModule }, { kind: "pipe", type: i1$1.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "pipe", type: BacklogQuotaLimitPipe, name: "backlogQuotaLimit" }, { kind: "component", type: UsageComponent, selector: "app-usage", inputs: ["count", "limit", "percentage"] }] }); }
|
|
316
|
+
}
|
|
317
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceItemCardComponent, decorators: [{
|
|
318
|
+
type: Component,
|
|
319
|
+
args: [{ selector: 'app-namespace-item-card', standalone: true, imports: [IconDirective, C8yTranslateModule, CommonModule, BacklogQuotaLimitPipe, UsageComponent], host: { class: 'card m-b-0 fit-w' }, template: "<div class=\"card-block text-default visible-xs text-center p-b-0\">\n <span class=\"text-12 text-uppercase text-muted\">\n {{ serviceLabel | translate }}\n </span>\n</div>\n<div\n class=\"card-block text-default p-t-sm-48\"\n [ngClass]=\"{\n 'p-b-sm-48': limit === 0\n }\"\n>\n <div class=\"d-flex fit-w a-i-center gap-8 j-c-center\">\n <i\n class=\"icon-32 c8y-icon-duocolor\"\n [c8yIcon]=\"ITEM_DETAILS[dataType].icon\"\n ></i>\n <span class=\"h1\">\n {{ value | number }}\n </span>\n <span\n class=\"a-s-baseline text-14 text-medium text-truncate\"\n title=\"{{ ITEM_DETAILS[dataType].title | translate }}\"\n >\n {{ ITEM_DETAILS[dataType].title | translate }}\n </span>\n </div>\n</div>\n<div\n class=\"card-footer d-flex gap-16 j-c-center a-i-center\"\n *ngIf=\"dataType === DATA_TYPE.topics && limit !== 0\"\n>\n <span\n class=\"tag tag--default no-pointer\"\n data-cy=\"card-limit\"\n >\n {{ topicsLimitLabel | translate: { backlogQuotaLimit: limit | backlogQuotaLimit } }}\n </span>\n <app-usage\n [count]=\"value\"\n [limit]=\"limit\"\n ></app-usage>\n</div>\n" }]
|
|
320
|
+
}], propDecorators: { serviceLabel: [{
|
|
321
|
+
type: Input
|
|
322
|
+
}], limit: [{
|
|
323
|
+
type: Input
|
|
324
|
+
}], dataType: [{
|
|
325
|
+
type: Input
|
|
326
|
+
}], value: [{
|
|
327
|
+
type: Input
|
|
328
|
+
}] } });
|
|
329
|
+
|
|
330
|
+
class NamespaceItemComponent {
|
|
331
|
+
constructor() {
|
|
332
|
+
this.translateService = inject(TranslateService);
|
|
333
|
+
this.namespaceName = '';
|
|
334
|
+
this.namespaceLabel = '';
|
|
335
|
+
this.icon = '';
|
|
336
|
+
this.namespace = {};
|
|
337
|
+
this.policies = {};
|
|
338
|
+
}
|
|
339
|
+
set _namespaceName(name) {
|
|
340
|
+
this.namespaceName = name;
|
|
341
|
+
this.icon = NAMESPACE_PROPS[name]?.icon;
|
|
342
|
+
this.namespaceLabel = this.translateService.instant(NAMESPACE_PROPS[name]?.label) || name;
|
|
343
|
+
}
|
|
344
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
345
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: NamespaceItemComponent, isStandalone: true, selector: "app-namespace-item", inputs: { _namespaceName: ["namespaceName", "_namespaceName"], namespace: "namespace", policies: "policies" }, ngImport: i0, template: "<div class=\"d-flex-sm d-col-xs p-t-24 p-l-16 p-r-16 m-0 bg-level-1\">\n <div\n class=\"col-sm-3 m-b-24 col-xs-12 d-flex gap-16 text-default a-i-center j-c-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"icon\"\n ></i>\n <span class=\"tag tag--info\">{{ 'Service' | translate }}</span>\n </div>\n <span class=\"h4\">{{ namespaceLabel }}</span>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'topics'\"\n [limit]=\"namespace?.topics?.limit\"\n [value]=\"namespace?.topics?.count\"\n ></app-namespace-item-card>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'publishers'\"\n [value]=\"namespace?.publishers?.count\"\n ></app-namespace-item-card>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'subscribers'\"\n [value]=\"namespace?.subscribers?.count\"\n ></app-namespace-item-card>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: NamespaceItemCardComponent, selector: "app-namespace-item-card", inputs: ["serviceLabel", "limit", "dataType", "value"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
|
|
346
|
+
}
|
|
347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceItemComponent, decorators: [{
|
|
348
|
+
type: Component,
|
|
349
|
+
args: [{ selector: 'app-namespace-item', standalone: true, imports: [CommonModule, IconDirective, NamespaceItemCardComponent, C8yTranslatePipe], template: "<div class=\"d-flex-sm d-col-xs p-t-24 p-l-16 p-r-16 m-0 bg-level-1\">\n <div\n class=\"col-sm-3 m-b-24 col-xs-12 d-flex gap-16 text-default a-i-center j-c-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"icon\"\n ></i>\n <span class=\"tag tag--info\">{{ 'Service' | translate }}</span>\n </div>\n <span class=\"h4\">{{ namespaceLabel }}</span>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'topics'\"\n [limit]=\"namespace?.topics?.limit\"\n [value]=\"namespace?.topics?.count\"\n ></app-namespace-item-card>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'publishers'\"\n [value]=\"namespace?.publishers?.count\"\n ></app-namespace-item-card>\n </div>\n <div class=\"col-sm-3 m-b-24 col-xs-12 a-i-stretch d-flex\">\n <app-namespace-item-card\n [serviceLabel]=\"namespaceLabel\"\n [dataType]=\"'subscribers'\"\n [value]=\"namespace?.subscribers?.count\"\n ></app-namespace-item-card>\n </div>\n</div>\n" }]
|
|
350
|
+
}], propDecorators: { _namespaceName: [{
|
|
351
|
+
type: Input,
|
|
352
|
+
args: ['namespaceName']
|
|
353
|
+
}], namespace: [{
|
|
354
|
+
type: Input
|
|
355
|
+
}], policies: [{
|
|
356
|
+
type: Input
|
|
357
|
+
}] } });
|
|
358
|
+
|
|
359
|
+
class NamespaceListComponent {
|
|
360
|
+
constructor() {
|
|
361
|
+
this.alertService = inject(AlertService);
|
|
362
|
+
this.appState = inject(AppStateService);
|
|
363
|
+
this.namespacesService = inject(MessagingNamespacesService);
|
|
364
|
+
this.loading = true;
|
|
365
|
+
}
|
|
366
|
+
async ngOnInit() {
|
|
367
|
+
await this.reload();
|
|
368
|
+
}
|
|
369
|
+
async reload() {
|
|
370
|
+
this.loading = true;
|
|
371
|
+
try {
|
|
372
|
+
const currentTenantId = this.appState.currentTenant.value.name;
|
|
373
|
+
this.namespacesDetails = await this.namespacesService.getNamespacesDetails(currentTenantId);
|
|
374
|
+
}
|
|
375
|
+
catch (e) {
|
|
376
|
+
this.alertService.addServerFailure(e);
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
this.loading = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
383
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: NamespaceListComponent, isStandalone: true, selector: "app-namespace-list", ngImport: i0, template: "<c8y-title>{{ 'Messaging service' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Messaging service' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <li>\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n </li>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/monitoring/#messaging-service\"></c8y-help>\n\n<div\n class=\"interact-grid\"\n *ngIf=\"!loading; else loadingTemplate\"\n>\n <a\n class=\"card\"\n *ngFor=\"let namespace of namespacesDetails\"\n [routerLink]=\"['namespace', namespace.id]\"\n >\n <app-namespace-item\n [namespaceName]=\"namespace.id\"\n [namespace]=\"namespace.namespace\"\n ></app-namespace-item>\n </a>\n</div>\n\n<ng-template #loadingTemplate>\n <c8y-loading></c8y-loading>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "component", type: i1$1.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "ngmodule", type: HelpModule }, { kind: "component", type: i1$1.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "ngmodule", type: C8yTranslateModule }, { kind: "pipe", type: i1$1.C8yTranslatePipe, name: "translate" }, { kind: "component", type: NamespaceItemComponent, selector: "app-namespace-item", inputs: ["namespaceName", "namespace", "policies"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BreadcrumbModule }, { kind: "component", type: i1$1.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i1$1.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }] }); }
|
|
384
|
+
}
|
|
385
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NamespaceListComponent, decorators: [{
|
|
386
|
+
type: Component,
|
|
387
|
+
args: [{ selector: 'app-namespace-list', imports: [
|
|
388
|
+
CommonModule,
|
|
389
|
+
HeaderModule,
|
|
390
|
+
HelpModule,
|
|
391
|
+
C8yTranslateModule,
|
|
392
|
+
NamespaceItemComponent,
|
|
393
|
+
RouterLink,
|
|
394
|
+
BreadcrumbModule,
|
|
395
|
+
ActionBarItemComponent,
|
|
396
|
+
IconDirective,
|
|
397
|
+
LoadingComponent
|
|
398
|
+
], standalone: true, template: "<c8y-title>{{ 'Messaging service' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Messaging service' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <li>\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n </li>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/monitoring/#messaging-service\"></c8y-help>\n\n<div\n class=\"interact-grid\"\n *ngIf=\"!loading; else loadingTemplate\"\n>\n <a\n class=\"card\"\n *ngFor=\"let namespace of namespacesDetails\"\n [routerLink]=\"['namespace', namespace.id]\"\n >\n <app-namespace-item\n [namespaceName]=\"namespace.id\"\n [namespace]=\"namespace.namespace\"\n ></app-namespace-item>\n </a>\n</div>\n\n<ng-template #loadingTemplate>\n <c8y-loading></c8y-loading>\n</ng-template>\n" }]
|
|
399
|
+
}] });
|
|
400
|
+
|
|
401
|
+
class TimeToLivePipe {
|
|
402
|
+
constructor(translateService) {
|
|
403
|
+
this.translateService = translateService;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Transform time in seconds to human readable format.
|
|
407
|
+
* @param seconds time in seconds
|
|
408
|
+
* @returns human readable time period
|
|
409
|
+
*/
|
|
410
|
+
transform(seconds) {
|
|
411
|
+
if (seconds == null || isNaN(seconds)) {
|
|
412
|
+
return '-';
|
|
413
|
+
}
|
|
414
|
+
if (seconds === -1) {
|
|
415
|
+
return this.translateService.instant(gettext('Unlimited` time-to-live period`'));
|
|
416
|
+
}
|
|
417
|
+
const minutes = Math.floor(seconds / 60);
|
|
418
|
+
const hours = Math.floor(minutes / 60);
|
|
419
|
+
const days = Math.floor(hours / 24);
|
|
420
|
+
if (days >= 1) {
|
|
421
|
+
const remainingHours = hours % 24;
|
|
422
|
+
if (days === 1) {
|
|
423
|
+
if (remainingHours === 0) {
|
|
424
|
+
return this.translateService.instant(gettext('1 day'));
|
|
425
|
+
}
|
|
426
|
+
if (remainingHours === 1) {
|
|
427
|
+
return this.translateService.instant(gettext('1 day 1 hour'));
|
|
428
|
+
}
|
|
429
|
+
return this.translateService.instant(gettext('1 day {{hours}} hours'), {
|
|
430
|
+
hours: remainingHours
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
if (remainingHours === 0) {
|
|
435
|
+
return this.translateService.instant(gettext('{{days}} days'), { days });
|
|
436
|
+
}
|
|
437
|
+
if (remainingHours === 1) {
|
|
438
|
+
return this.translateService.instant(gettext('{{days}} days 1 hour'), { days });
|
|
439
|
+
}
|
|
440
|
+
return this.translateService.instant(gettext('{{days}} days {{hours}} hours'), {
|
|
441
|
+
days,
|
|
442
|
+
hours: remainingHours
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (hours > 0) {
|
|
447
|
+
const remainingMinutes = minutes % 60;
|
|
448
|
+
if (hours === 1) {
|
|
449
|
+
if (remainingMinutes === 0) {
|
|
450
|
+
return this.translateService.instant(gettext('1 hour'));
|
|
451
|
+
}
|
|
452
|
+
if (remainingMinutes === 1) {
|
|
453
|
+
return this.translateService.instant(gettext('1 hour 1 minute'));
|
|
454
|
+
}
|
|
455
|
+
return this.translateService.instant(gettext('1 hour {{minutes}} minutes'), {
|
|
456
|
+
minutes: remainingMinutes
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
if (remainingMinutes === 0) {
|
|
461
|
+
return this.translateService.instant(gettext('{{hours}} hours'), { hours });
|
|
462
|
+
}
|
|
463
|
+
if (remainingMinutes === 1) {
|
|
464
|
+
return this.translateService.instant(gettext('{{hours}} hours 1 minute'), { hours });
|
|
465
|
+
}
|
|
466
|
+
return this.translateService.instant(gettext('{{hours}} hours {{minutes}} minutes'), {
|
|
467
|
+
hours,
|
|
468
|
+
minutes: remainingMinutes
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (minutes > 0) {
|
|
473
|
+
const remainingSeconds = seconds % 60;
|
|
474
|
+
if (minutes === 1) {
|
|
475
|
+
if (remainingSeconds === 0) {
|
|
476
|
+
return this.translateService.instant(gettext('1 minute'));
|
|
477
|
+
}
|
|
478
|
+
if (remainingSeconds === 1) {
|
|
479
|
+
return this.translateService.instant(gettext('1 minute 1 second'));
|
|
480
|
+
}
|
|
481
|
+
return this.translateService.instant(gettext('1 minute {{seconds}} seconds'), {
|
|
482
|
+
seconds: remainingSeconds
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
if (remainingSeconds === 0) {
|
|
487
|
+
return this.translateService.instant(gettext('{{minutes}} minutes'), { minutes });
|
|
488
|
+
}
|
|
489
|
+
if (remainingSeconds === 1) {
|
|
490
|
+
return this.translateService.instant(gettext('{{minutes}} minutes 1 second'), {
|
|
491
|
+
minutes
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return this.translateService.instant(gettext('{{minutes}} minutes {{seconds}} seconds'), {
|
|
495
|
+
minutes,
|
|
496
|
+
seconds: remainingSeconds
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (seconds === 1) {
|
|
501
|
+
return this.translateService.instant(gettext('1 second'));
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
return this.translateService.instant(gettext('{{seconds}} seconds'), { seconds });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimeToLivePipe, deps: [{ token: i1$2.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
508
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: TimeToLivePipe, isStandalone: true, name: "timeToLive" }); }
|
|
509
|
+
}
|
|
510
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimeToLivePipe, decorators: [{
|
|
511
|
+
type: Pipe,
|
|
512
|
+
args: [{
|
|
513
|
+
name: 'timeToLive',
|
|
514
|
+
standalone: true
|
|
515
|
+
}]
|
|
516
|
+
}], ctorParameters: () => [{ type: i1$2.TranslateService }] });
|
|
517
|
+
|
|
518
|
+
class MessagingTopicsService extends Service {
|
|
519
|
+
constructor(client) {
|
|
520
|
+
super(client);
|
|
521
|
+
this.baseUrl = '/service/messaging-management';
|
|
522
|
+
this.listUrl = 'tenants';
|
|
523
|
+
}
|
|
524
|
+
async list(filter) {
|
|
525
|
+
const headers = { accept: 'application/json' };
|
|
526
|
+
const { tenant, namespace, ...params } = filter;
|
|
527
|
+
const url = `/${this.listUrl}/${tenant}/namespaces/${namespace}/topics`;
|
|
528
|
+
const res = await this.fetch(url, this.changeFetchOptions({ headers, params }, url));
|
|
529
|
+
const topicList = (await res.json());
|
|
530
|
+
const data = topicList.topics;
|
|
531
|
+
const paging = this.getPaging(topicList, filter);
|
|
532
|
+
return { res, data, paging };
|
|
533
|
+
}
|
|
534
|
+
async detail(filter) {
|
|
535
|
+
const headers = { accept: 'application/json' };
|
|
536
|
+
const { tenant, namespace, topic, type } = filter;
|
|
537
|
+
const url = `/${this.listUrl}/${tenant}/namespaces/${namespace}/topics/${topic}/types/${type}`;
|
|
538
|
+
const res = await this.fetch(url, this.changeFetchOptions({ headers }, url));
|
|
539
|
+
const data = await res.json();
|
|
540
|
+
return { res, data };
|
|
541
|
+
}
|
|
542
|
+
getPaging(topicList, filter) {
|
|
543
|
+
if (topicList.pageStatistics) {
|
|
544
|
+
const { currentPage, totalPages } = topicList.pageStatistics;
|
|
545
|
+
const statistics = {
|
|
546
|
+
...topicList.pageStatistics,
|
|
547
|
+
nextPage: currentPage < totalPages ? currentPage + 1 : null,
|
|
548
|
+
prevPage: currentPage > 1 ? currentPage - 1 : null
|
|
549
|
+
};
|
|
550
|
+
return new Paging(this, statistics, filter);
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingTopicsService, deps: [{ token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
555
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingTopicsService, providedIn: 'root' }); }
|
|
556
|
+
}
|
|
557
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingTopicsService, decorators: [{
|
|
558
|
+
type: Injectable,
|
|
559
|
+
args: [{ providedIn: 'root' }]
|
|
560
|
+
}], ctorParameters: () => [{ type: i1.FetchClient }] });
|
|
561
|
+
|
|
562
|
+
class TopicsDataGridService {
|
|
563
|
+
constructor() {
|
|
564
|
+
this.topicsService = inject(MessagingTopicsService);
|
|
565
|
+
}
|
|
566
|
+
getColumns() {
|
|
567
|
+
return [
|
|
568
|
+
this.createColumn({
|
|
569
|
+
name: 'name',
|
|
570
|
+
header: gettext('Name'),
|
|
571
|
+
path: 'name',
|
|
572
|
+
filterable: true,
|
|
573
|
+
filteringConfig: {
|
|
574
|
+
fields: [
|
|
575
|
+
{
|
|
576
|
+
key: 'name',
|
|
577
|
+
type: 'input',
|
|
578
|
+
props: {
|
|
579
|
+
label: gettext('Filter topics by partial name'),
|
|
580
|
+
placeholder: 'myTopic',
|
|
581
|
+
required: true
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
],
|
|
585
|
+
getFilter(model) {
|
|
586
|
+
return model.name;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}),
|
|
590
|
+
this.createColumn({
|
|
591
|
+
name: 'msgRateIn',
|
|
592
|
+
header: gettext('Message rate in (msg/s)'),
|
|
593
|
+
path: 'msgRateIn'
|
|
594
|
+
}),
|
|
595
|
+
this.createColumn({
|
|
596
|
+
name: 'msgRateOut',
|
|
597
|
+
header: gettext('Message rate out (msg/s)'),
|
|
598
|
+
path: 'msgRateOut'
|
|
599
|
+
}),
|
|
600
|
+
this.createColumn({
|
|
601
|
+
name: 'subscribers',
|
|
602
|
+
header: gettext('Subscribers'),
|
|
603
|
+
path: 'subscribers'
|
|
604
|
+
}),
|
|
605
|
+
this.createColumn({
|
|
606
|
+
name: 'backlogSize',
|
|
607
|
+
header: gettext('Message backlog'),
|
|
608
|
+
path: 'backlogSize'
|
|
609
|
+
}),
|
|
610
|
+
this.createColumn({
|
|
611
|
+
name: 'backlogUsagePercentage',
|
|
612
|
+
header: gettext('Used backlog'),
|
|
613
|
+
path: 'backlogUsagePercentage',
|
|
614
|
+
sortOrder: 'desc'
|
|
615
|
+
})
|
|
616
|
+
];
|
|
617
|
+
}
|
|
618
|
+
async getServerSideData(tenantId, namespaceId, dataSourceModifier) {
|
|
619
|
+
const topicFilters = this.getTopicFilters(tenantId, namespaceId, dataSourceModifier);
|
|
620
|
+
const { res, data, paging } = await this.topicsService.list(topicFilters);
|
|
621
|
+
const filteredSize = paging.totalElements;
|
|
622
|
+
const size = (await this.topicsService.list({
|
|
623
|
+
...topicFilters,
|
|
624
|
+
currentPage: 1,
|
|
625
|
+
pageSize: 1
|
|
626
|
+
})).paging.totalPages;
|
|
627
|
+
return {
|
|
628
|
+
res,
|
|
629
|
+
data,
|
|
630
|
+
paging,
|
|
631
|
+
size,
|
|
632
|
+
filteredSize
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
createColumn(columnProps) {
|
|
636
|
+
const column = new BaseColumn();
|
|
637
|
+
Object.assign(column, columnProps);
|
|
638
|
+
return column;
|
|
639
|
+
}
|
|
640
|
+
getTopicFilters(tenantId, namespaceId, dataSourceModifier) {
|
|
641
|
+
const topicFilters = {
|
|
642
|
+
tenant: tenantId,
|
|
643
|
+
namespace: namespaceId,
|
|
644
|
+
currentPage: dataSourceModifier.pagination.currentPage,
|
|
645
|
+
pageSize: dataSourceModifier.pagination.pageSize
|
|
646
|
+
};
|
|
647
|
+
return dataSourceModifier.columns.reduce((topicFilters, column) => {
|
|
648
|
+
if (column.filterable) {
|
|
649
|
+
if (column.filterPredicate) {
|
|
650
|
+
topicFilters[column.path] = column.filterPredicate;
|
|
651
|
+
}
|
|
652
|
+
if (column.externalFilterQuery) {
|
|
653
|
+
topicFilters[column.path] = column.filteringConfig.getFilter(column.externalFilterQuery);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (column.sortable && column.sortOrder) {
|
|
657
|
+
const sortPath = column.sortingConfig?.pathSortingConfigs?.[0]?.path || column.path;
|
|
658
|
+
topicFilters.sort = `${sortPath},${column.sortOrder}`;
|
|
659
|
+
}
|
|
660
|
+
return topicFilters;
|
|
661
|
+
}, topicFilters);
|
|
662
|
+
}
|
|
663
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicsDataGridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
664
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicsDataGridService, providedIn: 'root' }); }
|
|
665
|
+
}
|
|
666
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicsDataGridService, decorators: [{
|
|
667
|
+
type: Injectable,
|
|
668
|
+
args: [{ providedIn: 'root' }]
|
|
669
|
+
}] });
|
|
670
|
+
|
|
671
|
+
class TopicListViewComponent {
|
|
672
|
+
constructor() {
|
|
673
|
+
this.route = inject(ActivatedRoute);
|
|
674
|
+
this.appState = inject(AppStateService);
|
|
675
|
+
this.namespacesService = inject(MessagingNamespacesService);
|
|
676
|
+
this.topicsDataGridService = inject(TopicsDataGridService);
|
|
677
|
+
this.translateService = inject(TranslateService);
|
|
678
|
+
this.destroyRef = inject(DestroyRef);
|
|
679
|
+
this.loading$ = new BehaviorSubject(false);
|
|
680
|
+
this.refresh = new EventEmitter();
|
|
681
|
+
this.tenantId$ = this.appState.currentTenant.pipe(map(tenant => tenant.name));
|
|
682
|
+
this.namespaceId$ = this.route.params.pipe(map(params => params['namespace']));
|
|
683
|
+
this.namespaceLabel$ = this.namespaceId$.pipe(map(namespaceId => this.translateService.instant(NAMESPACE_PROPS[namespaceId].label)));
|
|
684
|
+
this.icon$ = this.namespaceId$.pipe(map(namespaceId => NAMESPACE_PROPS[namespaceId].icon));
|
|
685
|
+
this.namespaceDetails$ = combineLatest([this.tenantId$, this.namespaceId$, this.refresh]).pipe(tap(() => this.loading$.next(true)), switchMap(([tenantId, namespaceId]) => this.namespacesService.getNamespaceDetails(tenantId, namespaceId)), tap(() => this.loading$.next(false)), shareReplay(1));
|
|
686
|
+
this.tableTitle = gettext('Topics');
|
|
687
|
+
this.loadingItemsLabel = gettext('Loading topics...');
|
|
688
|
+
this.loadMoreItemsLabel = gettext('Load more topics');
|
|
689
|
+
this.noResultsMessage = gettext('No matching topics found.');
|
|
690
|
+
this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
|
|
691
|
+
this.noDataMessage = gettext('No topics to display.');
|
|
692
|
+
this.noDataSubtitle = gettext('Create new topics to monitor them here.');
|
|
693
|
+
this.columns = this.topicsDataGridService.getColumns();
|
|
694
|
+
this.pagination = {
|
|
695
|
+
pageSize: 20,
|
|
696
|
+
currentPage: 1
|
|
697
|
+
};
|
|
698
|
+
this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
|
|
699
|
+
}
|
|
700
|
+
async onDataSourceModifier(dataSourceModifier) {
|
|
701
|
+
return firstValueFrom(combineLatest([this.tenantId$, this.namespaceId$]).pipe(switchMap(([tenantId, namespaceId]) => this.topicsDataGridService.getServerSideData(tenantId, namespaceId, dataSourceModifier))));
|
|
702
|
+
}
|
|
703
|
+
ngAfterViewInit() {
|
|
704
|
+
this.route.params
|
|
705
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
706
|
+
.subscribe(() => this.refresh.emit());
|
|
707
|
+
}
|
|
708
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicListViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
709
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TopicListViewComponent, isStandalone: true, selector: "app-topic-list-view", ngImport: i0, template: "<c8y-title>{{ namespaceLabel$ | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Messaging service' | translate\"\n [path]=\"'/monitoring/messaging-service'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"namespaceLabel$ | async\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"refresh.emit()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-flex d-col\">\n <div class=\"bg-level-1 separator-bottom flex-no-shrink\">\n <div\n class=\"card-block\"\n style=\"min-height: 172px\"\n >\n <div\n class=\"col-md-4 m-b-24 col-xs-12 d-flex p-t-24 gap-16 text-default a-i-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"icon$ | async\"\n ></i>\n <span class=\"tag tag--info\">{{ 'Service' | translate }}</span>\n </div>\n <span class=\"h4 text-break-all\">{{ namespaceLabel$ | async }}</span>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend>\n {{ 'Service usage/limits' | translate }}\n </legend>\n\n <ng-container *ngIf=\"loading$ | async; else serviceUsageLimits\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #serviceUsageLimits>\n <ng-container *ngIf=\"(namespaceDetails$ | async)?.namespace as namespace\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Topics' | translate }}</label>\n <ng-container *ngIf=\"namespace?.topics?.limit !== 0\">\n <app-usage\n [count]=\"namespace?.topics?.count\"\n [limit]=\"namespace?.topics?.limit\"\n ></app-usage>\n <span class=\"m-l-16\">\n {{ namespace?.topics?.count | number }} /\n {{ namespace?.topics?.limit | backlogQuotaLimit }}\n </span>\n </ng-container>\n <ng-container *ngIf=\"namespace?.topics?.limit === 0\">\n <span class=\"m-l-16\">{{ namespace?.topics?.count | number }}</span>\n </ng-container>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Subscribers' | translate }}</label>\n <span class=\"m-l-16\">\n {{ namespace?.subscribers?.count | number }}\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Publishers' | translate }}</label>\n <span class=\"m-l-16\">\n {{ namespace?.publishers?.count | number }}\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend>{{ 'Service message backlog limits' | translate }}</legend>\n\n <ng-container *ngIf=\"loading$ | async; else serviceMessageBacklogLimits\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #serviceMessageBacklogLimits>\n <ng-container *ngIf=\"(namespaceDetails$ | async)?.policies as policies\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Backlog quota (per topic)' | translate }}\n </label>\n <span\n title=\"{{\n policies?.backlogQuota?.limit > 0\n ? (policies.backlogQuota.limit | bytes: 0 : true)\n : '-'\n }}\"\n >\n {{\n policies?.backlogQuota?.limit > 0\n ? (policies.backlogQuota.limit | bytes: 0)\n : '-'\n }}\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Backlog time to live (TTL)' | translate }}\n </label>\n <span>{{ policies?.messageTTL | timeToLive }}</span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n </div>\n </div>\n\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"tableTitle | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel | translate\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel | translate\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [refresh]=\"refresh\"\n [hideReload]=\"true\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'day-view'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n ></c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <a\n title=\"{{ context.value }}\"\n [routerLink]=\"['topic', context.item.id]\"\n >\n {{ context.value }}\n </a>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"msgRateIn\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"msgRateOut\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"subscribers\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <a\n title=\"{{ context.value | number }}\"\n [routerLink]=\"['topic', context.item.id, 'subscribers']\"\n >\n {{ context.value | number }}\n </a>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogSize\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | bytes: 2 : true }}\">\n {{ context.value | bytes: 2 }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogUsagePercentage\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value / 100 | percent: '1.0-2' }}\">\n {{ context.value / 100 | percent: '1.0-2' }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: HeaderModule }, { kind: "component", type: i1$1.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "ngmodule", type: DataGridModule }, { kind: "directive", type: i1$1.CellRendererDefDirective, selector: "[c8yCellRendererDef]" }, { kind: "directive", type: i1$1.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i1$1.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "hideReload"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: BacklogQuotaLimitPipe, name: "backlogQuotaLimit" }, { kind: "component", type: UsageComponent, selector: "app-usage", inputs: ["count", "limit", "percentage"] }, { kind: "pipe", type: BytesPipe, name: "bytes" }, { kind: "pipe", type: TimeToLivePipe, name: "timeToLive" }, { kind: "ngmodule", type: BreadcrumbModule }, { kind: "component", type: i1$1.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i1$1.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: PercentPipe, name: "percent" }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
|
|
710
|
+
}
|
|
711
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicListViewComponent, decorators: [{
|
|
712
|
+
type: Component,
|
|
713
|
+
args: [{ imports: [
|
|
714
|
+
RouterLink,
|
|
715
|
+
HeaderModule,
|
|
716
|
+
DataGridModule,
|
|
717
|
+
DecimalPipe,
|
|
718
|
+
C8yTranslatePipe,
|
|
719
|
+
BacklogQuotaLimitPipe,
|
|
720
|
+
UsageComponent,
|
|
721
|
+
BytesPipe,
|
|
722
|
+
TimeToLivePipe,
|
|
723
|
+
BreadcrumbModule,
|
|
724
|
+
LoadingComponent,
|
|
725
|
+
NgIf,
|
|
726
|
+
ActionBarItemComponent,
|
|
727
|
+
NgClass,
|
|
728
|
+
IconDirective,
|
|
729
|
+
PercentPipe,
|
|
730
|
+
EmptyStateComponent,
|
|
731
|
+
EmptyStateContextDirective,
|
|
732
|
+
AsyncPipe
|
|
733
|
+
], selector: 'app-topic-list-view', standalone: true, template: "<c8y-title>{{ namespaceLabel$ | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Messaging service' | translate\"\n [path]=\"'/monitoring/messaging-service'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"namespaceLabel$ | async\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"refresh.emit()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-flex d-col\">\n <div class=\"bg-level-1 separator-bottom flex-no-shrink\">\n <div\n class=\"card-block\"\n style=\"min-height: 172px\"\n >\n <div\n class=\"col-md-4 m-b-24 col-xs-12 d-flex p-t-24 gap-16 text-default a-i-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"icon$ | async\"\n ></i>\n <span class=\"tag tag--info\">{{ 'Service' | translate }}</span>\n </div>\n <span class=\"h4 text-break-all\">{{ namespaceLabel$ | async }}</span>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend>\n {{ 'Service usage/limits' | translate }}\n </legend>\n\n <ng-container *ngIf=\"loading$ | async; else serviceUsageLimits\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #serviceUsageLimits>\n <ng-container *ngIf=\"(namespaceDetails$ | async)?.namespace as namespace\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Topics' | translate }}</label>\n <ng-container *ngIf=\"namespace?.topics?.limit !== 0\">\n <app-usage\n [count]=\"namespace?.topics?.count\"\n [limit]=\"namespace?.topics?.limit\"\n ></app-usage>\n <span class=\"m-l-16\">\n {{ namespace?.topics?.count | number }} /\n {{ namespace?.topics?.limit | backlogQuotaLimit }}\n </span>\n </ng-container>\n <ng-container *ngIf=\"namespace?.topics?.limit === 0\">\n <span class=\"m-l-16\">{{ namespace?.topics?.count | number }}</span>\n </ng-container>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Subscribers' | translate }}</label>\n <span class=\"m-l-16\">\n {{ namespace?.subscribers?.count | number }}\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Publishers' | translate }}</label>\n <span class=\"m-l-16\">\n {{ namespace?.publishers?.count | number }}\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend>{{ 'Service message backlog limits' | translate }}</legend>\n\n <ng-container *ngIf=\"loading$ | async; else serviceMessageBacklogLimits\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #serviceMessageBacklogLimits>\n <ng-container *ngIf=\"(namespaceDetails$ | async)?.policies as policies\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Backlog quota (per topic)' | translate }}\n </label>\n <span\n title=\"{{\n policies?.backlogQuota?.limit > 0\n ? (policies.backlogQuota.limit | bytes: 0 : true)\n : '-'\n }}\"\n >\n {{\n policies?.backlogQuota?.limit > 0\n ? (policies.backlogQuota.limit | bytes: 0)\n : '-'\n }}\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Backlog time to live (TTL)' | translate }}\n </label>\n <span>{{ policies?.messageTTL | timeToLive }}</span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n </div>\n </div>\n\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"tableTitle | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel | translate\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel | translate\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [refresh]=\"refresh\"\n [hideReload]=\"true\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'day-view'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n ></c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <a\n title=\"{{ context.value }}\"\n [routerLink]=\"['topic', context.item.id]\"\n >\n {{ context.value }}\n </a>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"msgRateIn\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"msgRateOut\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"subscribers\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <a\n title=\"{{ context.value | number }}\"\n [routerLink]=\"['topic', context.item.id, 'subscribers']\"\n >\n {{ context.value | number }}\n </a>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogSize\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | bytes: 2 : true }}\">\n {{ context.value | bytes: 2 }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogUsagePercentage\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value / 100 | percent: '1.0-2' }}\">\n {{ context.value / 100 | percent: '1.0-2' }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n" }]
|
|
734
|
+
}] });
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* If the topic is persistent or not. If false, the topic is not saved and will be deleted if there are no clients.
|
|
738
|
+
*/
|
|
739
|
+
var MessagingTopicType;
|
|
740
|
+
(function (MessagingTopicType) {
|
|
741
|
+
MessagingTopicType["Persistent"] = "persistent";
|
|
742
|
+
MessagingTopicType["NonPersistent"] = "non-persistent";
|
|
743
|
+
})(MessagingTopicType || (MessagingTopicType = {}));
|
|
744
|
+
|
|
745
|
+
class MessagingSubscribersService extends Service {
|
|
746
|
+
constructor(client) {
|
|
747
|
+
super(client);
|
|
748
|
+
this.baseUrl = '/service/messaging-management';
|
|
749
|
+
this.listUrl = 'tenants';
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Get the list of subscribers for a topic.
|
|
753
|
+
*
|
|
754
|
+
* @param filter Subscriber filters.
|
|
755
|
+
*/
|
|
756
|
+
async list(filter) {
|
|
757
|
+
const headers = { accept: 'application/json' };
|
|
758
|
+
const params = omit(filter, ['tenant', 'namespace', 'topic', 'type']);
|
|
759
|
+
const url = this.getBaseUrl(filter);
|
|
760
|
+
const res = await this.fetch(url, this.changeFetchOptions({ headers, params }, url));
|
|
761
|
+
const subscriberList = (await res.json());
|
|
762
|
+
const data = subscriberList.subscribers;
|
|
763
|
+
const paging = this.getPaging(subscriberList, filter);
|
|
764
|
+
return { res, data, paging };
|
|
765
|
+
}
|
|
766
|
+
async delete(subscriberToDelete) {
|
|
767
|
+
const method = 'DELETE';
|
|
768
|
+
const url = this.getBaseUrl(subscriberToDelete) + `/${subscriberToDelete.name}`;
|
|
769
|
+
const res = await this.fetch(url, this.changeFetchOptions({ method }, url));
|
|
770
|
+
return { res, data: null };
|
|
771
|
+
}
|
|
772
|
+
getPaging(json, filter) {
|
|
773
|
+
if (json.pageStatistics) {
|
|
774
|
+
const { currentPage, totalPages } = json.pageStatistics;
|
|
775
|
+
const statistics = {
|
|
776
|
+
...json.pageStatistics,
|
|
777
|
+
nextPage: currentPage < totalPages ? currentPage + 1 : null,
|
|
778
|
+
prevPage: currentPage > 1 ? currentPage - 1 : null
|
|
779
|
+
};
|
|
780
|
+
return new Paging(this, statistics, filter);
|
|
781
|
+
}
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
getBaseUrl({ tenant, namespace, topic, type }) {
|
|
785
|
+
return `/${this.listUrl}/${tenant}/namespaces/${namespace}/topics/${topic}/types/${type}/subscribers`;
|
|
786
|
+
}
|
|
787
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingSubscribersService, deps: [{ token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
788
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingSubscribersService, providedIn: 'root' }); }
|
|
789
|
+
}
|
|
790
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingSubscribersService, decorators: [{
|
|
791
|
+
type: Injectable,
|
|
792
|
+
args: [{ providedIn: 'root' }]
|
|
793
|
+
}], ctorParameters: () => [{ type: i1.FetchClient }] });
|
|
794
|
+
|
|
795
|
+
class TopicSubscribersDataGridService {
|
|
796
|
+
constructor() {
|
|
797
|
+
this.subscribersService = inject(MessagingSubscribersService);
|
|
798
|
+
this.alertService = inject(AlertService);
|
|
799
|
+
this.modalService = inject(ModalService);
|
|
800
|
+
this.translateService = inject(TranslateService);
|
|
801
|
+
}
|
|
802
|
+
getColumns() {
|
|
803
|
+
return [
|
|
804
|
+
this.createColumn({
|
|
805
|
+
name: 'name',
|
|
806
|
+
header: gettext('Name'),
|
|
807
|
+
path: 'name',
|
|
808
|
+
filterable: true,
|
|
809
|
+
filteringConfig: {
|
|
810
|
+
fields: [
|
|
811
|
+
{
|
|
812
|
+
key: 'name',
|
|
813
|
+
type: 'input',
|
|
814
|
+
props: {
|
|
815
|
+
label: gettext('Filter subscribers by partial name'),
|
|
816
|
+
placeholder: 'mySubscriber',
|
|
817
|
+
required: true
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
getFilter(model) {
|
|
822
|
+
return model.name;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}),
|
|
826
|
+
this.createColumn({
|
|
827
|
+
name: 'activeClients',
|
|
828
|
+
header: gettext('Connected clients'),
|
|
829
|
+
path: 'activeClients'
|
|
830
|
+
}),
|
|
831
|
+
this.createColumn({
|
|
832
|
+
name: 'messageAckRate',
|
|
833
|
+
header: gettext('Acknowledgment rate (msg/s)'),
|
|
834
|
+
path: 'messageAckRate'
|
|
835
|
+
}),
|
|
836
|
+
this.createColumn({
|
|
837
|
+
name: 'lastAcknowledgeDate',
|
|
838
|
+
header: gettext('Last acknowledged'),
|
|
839
|
+
path: 'lastAcknowledgeDate',
|
|
840
|
+
sortingConfig: {
|
|
841
|
+
pathSortingConfigs: [
|
|
842
|
+
{
|
|
843
|
+
path: 'lastAcknowledgeTimestamp'
|
|
844
|
+
}
|
|
845
|
+
]
|
|
846
|
+
}
|
|
847
|
+
}),
|
|
848
|
+
this.createColumn({
|
|
849
|
+
name: 'unackMsgBacklog',
|
|
850
|
+
header: gettext('Unacknowledged messages'),
|
|
851
|
+
path: 'unackMsgBacklog'
|
|
852
|
+
}),
|
|
853
|
+
this.createColumn({
|
|
854
|
+
name: 'backlogUsagePercentage',
|
|
855
|
+
header: gettext('Used backlog'),
|
|
856
|
+
path: 'backlogUsagePercentage',
|
|
857
|
+
sortOrder: 'desc'
|
|
858
|
+
})
|
|
859
|
+
];
|
|
860
|
+
}
|
|
861
|
+
async getServerSideData(tenantId, namespaceId, topicId, topicType, dataSourceModifier) {
|
|
862
|
+
const subscriberFilters = this.getSubscriberFilters(tenantId, namespaceId, topicId, topicType, dataSourceModifier);
|
|
863
|
+
const { res, data, paging } = await this.subscribersService.list(subscriberFilters);
|
|
864
|
+
const filteredSize = paging.totalElements;
|
|
865
|
+
const size = (await this.subscribersService.list({
|
|
866
|
+
...subscriberFilters,
|
|
867
|
+
currentPage: 1,
|
|
868
|
+
pageSize: 1
|
|
869
|
+
})).paging.totalPages;
|
|
870
|
+
return {
|
|
871
|
+
res,
|
|
872
|
+
data: data.map(subscriber => ({
|
|
873
|
+
...subscriber,
|
|
874
|
+
lastAcknowledgeDate: this.getLastAcknowledgeDate(subscriber),
|
|
875
|
+
id: subscriber.name
|
|
876
|
+
})),
|
|
877
|
+
paging,
|
|
878
|
+
size,
|
|
879
|
+
filteredSize
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
async unsubscribeSubscriber(subscriber, refreshCallback) {
|
|
883
|
+
const confirmationTitle = gettext('Unsubscribe "{{ subscriberName }}"?');
|
|
884
|
+
const confirmationMessage = subscriber.activeClients > 0
|
|
885
|
+
? gettext('You are about to unsubscribe "{{ subscriberName }}" which has active clients. Do you want to proceed?')
|
|
886
|
+
: gettext('You are about to unsubscribe "{{ subscriberName }}". Do you want to proceed?');
|
|
887
|
+
try {
|
|
888
|
+
const subscriberName = subscriber.name;
|
|
889
|
+
await this.modalService.confirm(this.translateService.instant(confirmationTitle, {
|
|
890
|
+
subscriberName
|
|
891
|
+
}), this.translateService.instant(confirmationMessage, {
|
|
892
|
+
subscriberName
|
|
893
|
+
}), Status.DANGER, {
|
|
894
|
+
ok: gettext('Unsubscribe')
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
catch (e) {
|
|
898
|
+
// cancel
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
try {
|
|
902
|
+
await this.subscribersService.delete(subscriber);
|
|
903
|
+
this.alertService.success(this.translateService.instant(gettext('Subscriber "{{ subscriberName }}" unsubscribed.'), {
|
|
904
|
+
subscriberName: subscriber.name
|
|
905
|
+
}));
|
|
906
|
+
}
|
|
907
|
+
catch (error) {
|
|
908
|
+
this.alertService.addServerFailure(error);
|
|
909
|
+
}
|
|
910
|
+
refreshCallback();
|
|
911
|
+
}
|
|
912
|
+
async bulkUnsubscribeSubscribers(subscribers, refreshCallback) {
|
|
913
|
+
const anySubscriberHasActiveClients = subscribers.some(subscriber => subscriber.activeClients > 0);
|
|
914
|
+
const confirmationTitle = gettext('Unsubscribe {{ numberOfSubscribers }} subscribers?');
|
|
915
|
+
const confirmationMessage = anySubscriberHasActiveClients
|
|
916
|
+
? gettext('You are about to unsubscribe {{ numberOfSubscribers }} subscribers. Some of them have active clients. Do you want to proceed?')
|
|
917
|
+
: gettext('You are about to unsubscribe {{ numberOfSubscribers }} subscribers. Do you want to proceed?');
|
|
918
|
+
try {
|
|
919
|
+
const numberOfSubscribers = subscribers.length;
|
|
920
|
+
await this.modalService.confirm(this.translateService.instant(confirmationTitle, {
|
|
921
|
+
numberOfSubscribers
|
|
922
|
+
}), this.translateService.instant(confirmationMessage, {
|
|
923
|
+
numberOfSubscribers
|
|
924
|
+
}), Status.DANGER, {
|
|
925
|
+
ok: gettext('Unsubscribe')
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
catch (e) {
|
|
929
|
+
// cancel
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
const results = await Promise.allSettled(subscribers.map(sub => this.subscribersService
|
|
933
|
+
.delete(sub)
|
|
934
|
+
.then(() => ({
|
|
935
|
+
success: true,
|
|
936
|
+
name: sub.name
|
|
937
|
+
}))
|
|
938
|
+
.catch(error => ({
|
|
939
|
+
success: false,
|
|
940
|
+
name: sub.name,
|
|
941
|
+
error
|
|
942
|
+
}))));
|
|
943
|
+
const failed = results
|
|
944
|
+
.filter(result => result.status === 'fulfilled' && result.value.success === false)
|
|
945
|
+
.map(result => result.value);
|
|
946
|
+
const succeeded = results
|
|
947
|
+
.filter(result => result.status === 'fulfilled' && result.value.success === true)
|
|
948
|
+
.map(result => result.value);
|
|
949
|
+
if (failed.length === 0) {
|
|
950
|
+
this.alertService.success(this.translateService.instant(gettext('{{ numberOfSubscribers }} subscribers unsubscribed.'), { numberOfSubscribers: succeeded.length }));
|
|
951
|
+
}
|
|
952
|
+
else if (succeeded.length === 0) {
|
|
953
|
+
const errorMessage = this.translateService.instant(gettext('Failed to unsubscribe {{ numberOfSubscribers }} subscribers.'), {
|
|
954
|
+
numberOfSubscribers: failed.length
|
|
955
|
+
});
|
|
956
|
+
const details = `${failed.map(f => `'${f.name}': ${f.error.data.message}`).join('\n')}`;
|
|
957
|
+
this.alertService.danger(errorMessage, details);
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
// Some succeeded, some failed
|
|
961
|
+
const nonUnsubscribedSubscribers = failed.map(s => s.name).join(', ');
|
|
962
|
+
const message = this.translateService.instant(gettext(`Successfully unsubscribed {{ count }} subscribers.<br/>Failed to unsubscribe: {{ nonUnsubscribedSubscribers }}.`), { count: succeeded.length, nonUnsubscribedSubscribers });
|
|
963
|
+
const details = `${failed.map(f => `'${f.name}': ${f.error.data.message}`).join('\n')}`;
|
|
964
|
+
this.alertService.warning(message, details);
|
|
965
|
+
}
|
|
966
|
+
refreshCallback();
|
|
967
|
+
}
|
|
968
|
+
createColumn(columnProps) {
|
|
969
|
+
const column = new BaseColumn();
|
|
970
|
+
Object.assign(column, columnProps);
|
|
971
|
+
return column;
|
|
972
|
+
}
|
|
973
|
+
getSubscriberFilters(tenantId, namespaceId, topicId, topicType, dataSourceModifier) {
|
|
974
|
+
const subscriberFilters = {
|
|
975
|
+
tenant: tenantId,
|
|
976
|
+
namespace: namespaceId,
|
|
977
|
+
topic: topicId,
|
|
978
|
+
type: topicType,
|
|
979
|
+
currentPage: dataSourceModifier.pagination.currentPage,
|
|
980
|
+
pageSize: dataSourceModifier.pagination.pageSize
|
|
981
|
+
};
|
|
982
|
+
return dataSourceModifier.columns.reduce((subscriberFilters, column) => {
|
|
983
|
+
if (column.filterable) {
|
|
984
|
+
if (column.filterPredicate) {
|
|
985
|
+
subscriberFilters[column.path] = column.filterPredicate;
|
|
986
|
+
}
|
|
987
|
+
if (column.externalFilterQuery) {
|
|
988
|
+
subscriberFilters[column.path] = column.filteringConfig.getFilter(column.externalFilterQuery);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (column.sortable && column.sortOrder) {
|
|
992
|
+
const sortPath = column.sortingConfig?.pathSortingConfigs?.[0]?.path || column.path;
|
|
993
|
+
subscriberFilters.sort = `${sortPath},${column.sortOrder}`;
|
|
994
|
+
}
|
|
995
|
+
return subscriberFilters;
|
|
996
|
+
}, subscriberFilters);
|
|
997
|
+
}
|
|
998
|
+
getLastAcknowledgeDate(subscriber) {
|
|
999
|
+
const lastAcknowledgeDate = new Date(subscriber.lastAcknowledgeTimestamp);
|
|
1000
|
+
return lastAcknowledgeDate.getTime() > 0 ? lastAcknowledgeDate : null;
|
|
1001
|
+
}
|
|
1002
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicSubscribersDataGridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1003
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicSubscribersDataGridService, providedIn: 'root' }); }
|
|
1004
|
+
}
|
|
1005
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicSubscribersDataGridService, decorators: [{
|
|
1006
|
+
type: Injectable,
|
|
1007
|
+
args: [{ providedIn: 'root' }]
|
|
1008
|
+
}] });
|
|
1009
|
+
|
|
1010
|
+
class TopicSubscribersViewComponent {
|
|
1011
|
+
constructor() {
|
|
1012
|
+
this.route = inject(ActivatedRoute);
|
|
1013
|
+
this.appState = inject(AppStateService);
|
|
1014
|
+
this.namespacesService = inject(MessagingNamespacesService);
|
|
1015
|
+
this.topicsService = inject(MessagingTopicsService);
|
|
1016
|
+
this.topicSubscribersDataGridService = inject(TopicSubscribersDataGridService);
|
|
1017
|
+
this.translateService = inject(TranslateService);
|
|
1018
|
+
this.permissions = inject(Permissions);
|
|
1019
|
+
this.destroyRef = inject(DestroyRef);
|
|
1020
|
+
this.loading$ = new BehaviorSubject(false);
|
|
1021
|
+
this.refresh = new EventEmitter();
|
|
1022
|
+
this.tenantId$ = this.appState.currentTenant.pipe(map(tenant => tenant.name));
|
|
1023
|
+
this.namespaceId$ = this.route.params.pipe(map(params => params['namespace']));
|
|
1024
|
+
this.namespaceLabel$ = this.namespaceId$.pipe(map(namespaceId => this.translateService.instant(NAMESPACE_PROPS[namespaceId].label)));
|
|
1025
|
+
this.topicId$ = this.route.params.pipe(map(params => params['topic']));
|
|
1026
|
+
this.overview$ = combineLatest([this.tenantId$, this.namespaceId$, this.topicId$, this.refresh]).pipe(tap(() => this.loading$.next(true)), switchMap(async ([tenantId, namespaceId, topicId]) => ({
|
|
1027
|
+
topic: (await this.topicsService.detail({
|
|
1028
|
+
tenant: tenantId,
|
|
1029
|
+
namespace: namespaceId,
|
|
1030
|
+
topic: topicId,
|
|
1031
|
+
type: MessagingTopicType.Persistent
|
|
1032
|
+
})).data,
|
|
1033
|
+
policies: await this.namespacesService.getNamespacePolicies(tenantId, namespaceId)
|
|
1034
|
+
})), tap(() => this.loading$.next(false)), shareReplay(1));
|
|
1035
|
+
this.topicName$ = this.overview$.pipe(map(overview => overview.topic.name));
|
|
1036
|
+
this.tableTitle = gettext('Subscribers');
|
|
1037
|
+
this.loadingItemsLabel = gettext('Loading subscribers...');
|
|
1038
|
+
this.loadMoreItemsLabel = gettext('Load more subscribers');
|
|
1039
|
+
this.noResultsMessage = gettext('No matching subscribers found.');
|
|
1040
|
+
this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
|
|
1041
|
+
this.noDataMessage = gettext('No subscribers to display.');
|
|
1042
|
+
this.noDataSubtitle = gettext('Create new subscribers to monitor them here.');
|
|
1043
|
+
this.columns = this.topicSubscribersDataGridService.getColumns();
|
|
1044
|
+
this.pagination = {
|
|
1045
|
+
pageSize: 20,
|
|
1046
|
+
currentPage: 1
|
|
1047
|
+
};
|
|
1048
|
+
this.selectable = true;
|
|
1049
|
+
this.actionControls = [
|
|
1050
|
+
{
|
|
1051
|
+
type: 'unsubscribeSubscriber',
|
|
1052
|
+
icon: 'unsubscribe',
|
|
1053
|
+
text: gettext('Unsubscribe'),
|
|
1054
|
+
callback: (subscriber) => this.unsubscribeSubscriber(subscriber),
|
|
1055
|
+
showIf: () => this.permissions.hasRole(Permissions.ROLE_TENANT_MANAGEMENT_ADMIN)
|
|
1056
|
+
}
|
|
1057
|
+
];
|
|
1058
|
+
this.bulkActionControls = [
|
|
1059
|
+
{
|
|
1060
|
+
type: 'unsubscribeSubscriber',
|
|
1061
|
+
icon: 'unsubscribe',
|
|
1062
|
+
text: gettext('Unsubscribe'),
|
|
1063
|
+
callback: (subscribersNames) => this.bulkUnsubscribeSubscribers(subscribersNames),
|
|
1064
|
+
showIf: () => this.permissions.hasRole(Permissions.ROLE_TENANT_MANAGEMENT_ADMIN)
|
|
1065
|
+
}
|
|
1066
|
+
];
|
|
1067
|
+
this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
|
|
1068
|
+
}
|
|
1069
|
+
async onDataSourceModifier(dataSourceModifier) {
|
|
1070
|
+
return firstValueFrom(combineLatest([this.tenantId$, this.namespaceId$, this.topicId$]).pipe(switchMap(([tenantId, namespaceId, topicId]) => this.topicSubscribersDataGridService.getServerSideData(tenantId, namespaceId, topicId, MessagingTopicType.Persistent, dataSourceModifier))));
|
|
1071
|
+
}
|
|
1072
|
+
ngAfterViewInit() {
|
|
1073
|
+
this.refresh.emit();
|
|
1074
|
+
}
|
|
1075
|
+
async unsubscribeSubscriber(subscriber) {
|
|
1076
|
+
const tenant = await firstValueFrom(this.tenantId$);
|
|
1077
|
+
const namespace = await firstValueFrom(this.namespaceId$);
|
|
1078
|
+
const topic = await firstValueFrom(this.topicId$);
|
|
1079
|
+
this.topicSubscribersDataGridService.unsubscribeSubscriber({
|
|
1080
|
+
...subscriber,
|
|
1081
|
+
tenant,
|
|
1082
|
+
namespace,
|
|
1083
|
+
topic,
|
|
1084
|
+
type: MessagingTopicType.Persistent
|
|
1085
|
+
}, () => this.refresh.emit());
|
|
1086
|
+
}
|
|
1087
|
+
async bulkUnsubscribeSubscribers(subscribersNames) {
|
|
1088
|
+
const tenant = await firstValueFrom(this.tenantId$);
|
|
1089
|
+
const namespace = await firstValueFrom(this.namespaceId$);
|
|
1090
|
+
const topic = await firstValueFrom(this.topicId$);
|
|
1091
|
+
const allSubscribers = await firstValueFrom(this.dataGrid.dataSource.data$);
|
|
1092
|
+
const subscribers = subscribersNames.map(subscriberName => {
|
|
1093
|
+
const subscriber = allSubscribers.find(subscriber => subscriber.name === subscriberName);
|
|
1094
|
+
return {
|
|
1095
|
+
...subscriber,
|
|
1096
|
+
tenant,
|
|
1097
|
+
namespace,
|
|
1098
|
+
topic,
|
|
1099
|
+
type: MessagingTopicType.Persistent
|
|
1100
|
+
};
|
|
1101
|
+
});
|
|
1102
|
+
this.topicSubscribersDataGridService.bulkUnsubscribeSubscribers(subscribers, () => this.refresh.emit());
|
|
1103
|
+
}
|
|
1104
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicSubscribersViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1105
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TopicSubscribersViewComponent, isStandalone: true, selector: "app-topic-subscribers-view", viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-title>{{ topicName$ | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Messaging service' | translate\"\n [path]=\"'/monitoring/messaging-service'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"namespaceLabel$ | async\"\n [path]=\"'/monitoring/messaging-service/namespace/' + (namespaceId$ | async)\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"topicName$ | async\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"refresh.emit()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-flex d-col\">\n <div class=\"bg-level-1 separator-bottom flex-no-shrink\">\n <div class=\"card-block\">\n <div\n class=\"col-md-4 m-b-24 col-xs-12 d-flex p-t-24 gap-16 text-default a-i-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"'day-view'\"\n ></i>\n <span class=\"tag tag--default\">{{ 'Topic' | translate }}</span>\n </div>\n <span class=\"h4\">{{ topicName$ | async }}</span>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend translate>Topic usage</legend>\n\n <ng-container *ngIf=\"loading$ | async; else topicSummary\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #topicSummary>\n <ng-container *ngIf=\"overview$ | async as overview\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Active subscribers' | translate }}</label>\n <span class=\"m-l-16\">{{ overview.topic.activeSubscribers | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Total subscribers' | translate }}</label>\n <span class=\"m-l-16\">{{ overview.topic.subscribers | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Total unacknowledged messages' | translate }}\n </label>\n <span class=\"m-l-16\">{{ overview.topic.unackMsgBacklog | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Message rate in' | translate }}\n </label>\n <span\n class=\"m-l-16\"\n ngNonBindable\n translate\n [translateParams]=\"{\n messagesPerSecond: overview.topic.msgRateIn | number\n }\"\n >\n {{ messagesPerSecond }} msg/s\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Message rate out' | translate }}\n </label>\n <span\n class=\"m-l-16\"\n ngNonBindable\n translate\n [translateParams]=\"{\n messagesPerSecond: overview.topic.msgRateOut | number\n }\"\n >\n {{ messagesPerSecond }} msg/s\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend translate>Topic message backlog</legend>\n\n <ng-container *ngIf=\"loading$ | async; else topicBacklog\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #topicBacklog>\n <ng-container *ngIf=\"overview$ | async as overview\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label\n class=\"small m-b-0 m-r-auto\"\n translate\n >\n Backlog usage\n </label>\n <app-usage [percentage]=\"overview.topic.backlogUsagePercentage\"></app-usage>\n <span class=\"m-l-16\">{{ overview.topic.backlogSize | bytes }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label\n class=\"small m-b-0 m-r-auto\"\n translate\n >\n Backlog quota\n </label>\n <span class=\"m-l-16\">\n {{\n overview.policies.backlogQuota?.limit > 0\n ? (overview.policies.backlogQuota?.limit | bytes)\n : '-'\n }}\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n </div>\n </div>\n <c8y-data-grid\n class=\"content-fullpage d-flex d-col border-top border-bottom\"\n [title]=\"tableTitle | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel | translate\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel | translate\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [refresh]=\"refresh\"\n [hideReload]=\"true\"\n [selectable]=\"selectable\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'input'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n ></c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }}\">\n {{ context.value }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"activeClients\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"messageAckRate\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"lastAcknowledgeDate\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span\n title=\"{{ context.value }}\"\n *ngIf=\"context.value; else noLastAcknwoldegeDate\"\n >\n {{ context.value | relativeTime }}\n </span>\n <ng-template #noLastAcknwoldegeDate>–</ng-template>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"unackMsgBacklog\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogUsagePercentage\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value / 100 | percent: '1.0-2' }}\">\n {{ context.value / 100 | percent: '1.0-2' }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "ngmodule", type: DataGridModule }, { kind: "directive", type: i1$1.CellRendererDefDirective, selector: "[c8yCellRendererDef]" }, { kind: "directive", type: i1$1.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i1$1.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "hideReload"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "ngmodule", type: HeaderModule }, { kind: "component", type: i1$1.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: RelativeTimePipe, name: "relativeTime" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.PercentPipe, name: "percent" }, { kind: "pipe", type: BytesPipe, name: "bytes" }, { kind: "ngmodule", type: BreadcrumbModule }, { kind: "component", type: i1$1.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i1$1.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: UsageComponent, selector: "app-usage", inputs: ["count", "limit", "percentage"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }] }); }
|
|
1106
|
+
}
|
|
1107
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicSubscribersViewComponent, decorators: [{
|
|
1108
|
+
type: Component,
|
|
1109
|
+
args: [{ selector: 'app-topic-subscribers-view', standalone: true, imports: [
|
|
1110
|
+
DataGridModule,
|
|
1111
|
+
DecimalPipe,
|
|
1112
|
+
HeaderModule,
|
|
1113
|
+
C8yTranslateDirective,
|
|
1114
|
+
RelativeTimePipe,
|
|
1115
|
+
C8yTranslatePipe,
|
|
1116
|
+
CommonModule,
|
|
1117
|
+
BytesPipe,
|
|
1118
|
+
BreadcrumbModule,
|
|
1119
|
+
UsageComponent,
|
|
1120
|
+
ActionBarItemComponent,
|
|
1121
|
+
IconDirective,
|
|
1122
|
+
EmptyStateComponent,
|
|
1123
|
+
EmptyStateContextDirective,
|
|
1124
|
+
LoadingComponent
|
|
1125
|
+
], template: "<c8y-title>{{ topicName$ | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'monitoring'\"\n [label]=\"'Monitoring' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Messaging service' | translate\"\n [path]=\"'/monitoring/messaging-service'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"namespaceLabel$ | async\"\n [path]=\"'/monitoring/messaging-service/namespace/' + (namespaceId$ | async)\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"topicName$ | async\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <a\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"refresh.emit()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': loading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </a>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage d-flex d-col\">\n <div class=\"bg-level-1 separator-bottom flex-no-shrink\">\n <div class=\"card-block\">\n <div\n class=\"col-md-4 m-b-24 col-xs-12 d-flex p-t-24 gap-16 text-default a-i-center a-s-stretch\"\n >\n <div class=\"text-center d-col\">\n <i\n class=\"m-b-8 icon-40 c8y-icon-duocolor\"\n [c8yIcon]=\"'day-view'\"\n ></i>\n <span class=\"tag tag--default\">{{ 'Topic' | translate }}</span>\n </div>\n <span class=\"h4\">{{ topicName$ | async }}</span>\n </div>\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend translate>Topic usage</legend>\n\n <ng-container *ngIf=\"loading$ | async; else topicSummary\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #topicSummary>\n <ng-container *ngIf=\"overview$ | async as overview\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Active subscribers' | translate }}</label>\n <span class=\"m-l-16\">{{ overview.topic.activeSubscribers | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">{{ 'Total subscribers' | translate }}</label>\n <span class=\"m-l-16\">{{ overview.topic.subscribers | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Total unacknowledged messages' | translate }}\n </label>\n <span class=\"m-l-16\">{{ overview.topic.unackMsgBacklog | number }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Message rate in' | translate }}\n </label>\n <span\n class=\"m-l-16\"\n ngNonBindable\n translate\n [translateParams]=\"{\n messagesPerSecond: overview.topic.msgRateIn | number\n }\"\n >\n {{ messagesPerSecond }} msg/s\n </span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label class=\"small m-b-0 m-r-auto\">\n {{ 'Message rate out' | translate }}\n </label>\n <span\n class=\"m-l-16\"\n ngNonBindable\n translate\n [translateParams]=\"{\n messagesPerSecond: overview.topic.msgRateOut | number\n }\"\n >\n {{ messagesPerSecond }} msg/s\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n\n <div class=\"col-md-4\">\n <fieldset class=\"c8y-fieldset c8y-fieldset--lg\">\n <legend translate>Topic message backlog</legend>\n\n <ng-container *ngIf=\"loading$ | async; else topicBacklog\">\n <c8y-loading></c8y-loading>\n </ng-container>\n\n <ng-template #topicBacklog>\n <ng-container *ngIf=\"overview$ | async as overview\">\n <ul class=\"list-unstyled small animated fadeIn\">\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label\n class=\"small m-b-0 m-r-auto\"\n translate\n >\n Backlog usage\n </label>\n <app-usage [percentage]=\"overview.topic.backlogUsagePercentage\"></app-usage>\n <span class=\"m-l-16\">{{ overview.topic.backlogSize | bytes }}</span>\n </li>\n\n <li class=\"p-t-4 p-b-4 d-flex text-nowrap\">\n <label\n class=\"small m-b-0 m-r-auto\"\n translate\n >\n Backlog quota\n </label>\n <span class=\"m-l-16\">\n {{\n overview.policies.backlogQuota?.limit > 0\n ? (overview.policies.backlogQuota?.limit | bytes)\n : '-'\n }}\n </span>\n </li>\n </ul>\n </ng-container>\n </ng-template>\n </fieldset>\n </div>\n </div>\n </div>\n <c8y-data-grid\n class=\"content-fullpage d-flex d-col border-top border-bottom\"\n [title]=\"tableTitle | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel | translate\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel | translate\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [refresh]=\"refresh\"\n [hideReload]=\"true\"\n [selectable]=\"selectable\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'input'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n ></c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }}\">\n {{ context.value }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"activeClients\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"messageAckRate\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"lastAcknowledgeDate\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span\n title=\"{{ context.value }}\"\n *ngIf=\"context.value; else noLastAcknwoldegeDate\"\n >\n {{ context.value | relativeTime }}\n </span>\n <ng-template #noLastAcknwoldegeDate>–</ng-template>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"unackMsgBacklog\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | number }}\">\n {{ context.value | number }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"backlogUsagePercentage\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value / 100 | percent: '1.0-2' }}\">\n {{ context.value / 100 | percent: '1.0-2' }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n" }]
|
|
1126
|
+
}], propDecorators: { dataGrid: [{
|
|
1127
|
+
type: ViewChild,
|
|
1128
|
+
args: [DataGridComponent, { static: true }]
|
|
1129
|
+
}] } });
|
|
1130
|
+
|
|
1131
|
+
class TopicDetailsTabFactory {
|
|
1132
|
+
constructor(router) {
|
|
1133
|
+
this.router = router;
|
|
1134
|
+
}
|
|
1135
|
+
get() {
|
|
1136
|
+
const pattern = /\/namespace\/(.+)\/topic\/(.+)\/subscribers$/;
|
|
1137
|
+
const matches = this.router.url.match(pattern);
|
|
1138
|
+
if (matches) {
|
|
1139
|
+
const namespace = matches[1];
|
|
1140
|
+
const topic = matches[2];
|
|
1141
|
+
return [
|
|
1142
|
+
{
|
|
1143
|
+
path: basePath + `/namespace/${namespace}/topic/${topic}/subscribers`,
|
|
1144
|
+
priority: 500,
|
|
1145
|
+
label: gettext('Subscribers')
|
|
1146
|
+
}
|
|
1147
|
+
];
|
|
1148
|
+
}
|
|
1149
|
+
return [];
|
|
1150
|
+
}
|
|
1151
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicDetailsTabFactory, deps: [{ token: i1$3.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1152
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicDetailsTabFactory }); }
|
|
1153
|
+
}
|
|
1154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TopicDetailsTabFactory, decorators: [{
|
|
1155
|
+
type: Injectable
|
|
1156
|
+
}], ctorParameters: () => [{ type: i1$3.Router }] });
|
|
1157
|
+
|
|
1158
|
+
class MessagingManagementModule {
|
|
1159
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1160
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementModule }); }
|
|
1161
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementModule, providers: [
|
|
1162
|
+
hookRoute([
|
|
1163
|
+
{
|
|
1164
|
+
path: basePath,
|
|
1165
|
+
component: NamespaceListComponent,
|
|
1166
|
+
canActivate: [MessagingManagementGuard]
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
path: basePath + '/namespace/:namespace',
|
|
1170
|
+
component: TopicListViewComponent,
|
|
1171
|
+
canActivate: [MessagingManagementGuard]
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
path: basePath + '/namespace/:namespace/topic/:topic',
|
|
1175
|
+
redirectTo: basePath + '/namespace/:namespace/topic/:topic/subscribers',
|
|
1176
|
+
pathMatch: 'full'
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
path: basePath + '/namespace/:namespace/topic/:topic/subscribers',
|
|
1180
|
+
component: TopicSubscribersViewComponent,
|
|
1181
|
+
canActivate: [MessagingManagementGuard]
|
|
1182
|
+
}
|
|
1183
|
+
]),
|
|
1184
|
+
hookTab(TopicDetailsTabFactory),
|
|
1185
|
+
hookNavigator(MessagingNavigatorNodeFactory)
|
|
1186
|
+
] }); }
|
|
1187
|
+
}
|
|
1188
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessagingManagementModule, decorators: [{
|
|
1189
|
+
type: NgModule,
|
|
1190
|
+
args: [{
|
|
1191
|
+
providers: [
|
|
1192
|
+
hookRoute([
|
|
1193
|
+
{
|
|
1194
|
+
path: basePath,
|
|
1195
|
+
component: NamespaceListComponent,
|
|
1196
|
+
canActivate: [MessagingManagementGuard]
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
path: basePath + '/namespace/:namespace',
|
|
1200
|
+
component: TopicListViewComponent,
|
|
1201
|
+
canActivate: [MessagingManagementGuard]
|
|
1202
|
+
},
|
|
1203
|
+
{
|
|
1204
|
+
path: basePath + '/namespace/:namespace/topic/:topic',
|
|
1205
|
+
redirectTo: basePath + '/namespace/:namespace/topic/:topic/subscribers',
|
|
1206
|
+
pathMatch: 'full'
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
path: basePath + '/namespace/:namespace/topic/:topic/subscribers',
|
|
1210
|
+
component: TopicSubscribersViewComponent,
|
|
1211
|
+
canActivate: [MessagingManagementGuard]
|
|
1212
|
+
}
|
|
1213
|
+
]),
|
|
1214
|
+
hookTab(TopicDetailsTabFactory),
|
|
1215
|
+
hookNavigator(MessagingNavigatorNodeFactory)
|
|
1216
|
+
]
|
|
1217
|
+
}]
|
|
1218
|
+
}] });
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Generated bundle index. Do not edit.
|
|
1222
|
+
*/
|
|
1223
|
+
|
|
1224
|
+
export { MessagingManagementModule };
|
|
1225
|
+
//# sourceMappingURL=c8y-ngx-components-messaging-management.mjs.map
|