@c8y/tutorial 1022.10.1 → 1022.13.0

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.
Files changed (52) hide show
  1. package/cumulocity.config.ts +39 -4
  2. package/package.json +7 -7
  3. package/src/__mocks/global-mocks/inventory.interceptor.ts +6 -1
  4. package/src/__mocks/global-mocks/provider-configuration.ts +62 -0
  5. package/src/__mocks/global-mocks/provider-definitions.ts +24 -0
  6. package/src/__mocks/index.ts +18 -0
  7. package/src/countdown/countdown-example.component.html +4 -1
  8. package/src/countdown/countdown-example.component.ts +1 -0
  9. package/src/dynamic-forms/custom-element-example/custom-element-example.component.ts +2 -2
  10. package/src/dynamic-forms/introduction-example/introduction-example.component.ts +2 -2
  11. package/src/dynamic-forms/json-schema-example/json-schema-example.component.html +2 -2
  12. package/src/dynamic-forms/validation-example/validation-example.component.ts +2 -2
  13. package/src/for-of-directive/for-of-example.component.ts +3 -3
  14. package/src/generate-json-schema/generate-json-schema.component.ts +1 -0
  15. package/src/hooks/docs/docs-example.service.ts +17 -0
  16. package/src/hooks/docs/hook-docs-example.component.ts +17 -0
  17. package/src/hooks/docs/hook-docs.module.ts +30 -0
  18. package/src/hooks/preview-feature/index.ts +0 -1
  19. package/src/hooks/tabs/named-outlet/basic-view/basic-view.component.html +15 -0
  20. package/src/hooks/tabs/named-outlet/basic-view/basic-view.component.ts +25 -0
  21. package/src/hooks/tabs/named-outlet/content-a.component.ts +8 -0
  22. package/src/hooks/tabs/named-outlet/content-b.component.ts +8 -0
  23. package/src/hooks/tabs/named-outlet/named-outlet.module.ts +80 -0
  24. package/src/hooks/tabs/tabs.module.ts +0 -2
  25. package/src/hooks/widget/context-dashboard.component.ts +13 -0
  26. package/src/hooks/widget/widget.providers.ts +18 -0
  27. package/src/hooks/widget-config/basic-view/basic-edit.component.ts +18 -1
  28. package/src/hooks/widget-config/widget-config.providers.ts +0 -3
  29. package/src/input-group/extendable-input-list-example.component.ts +19 -3
  30. package/src/lazy-widget/lazy-widget-config/lazy-widget-config.component.ts +19 -3
  31. package/src/list/list/list-check/list-check.component.html +1 -1
  32. package/src/maps/cluster-map/cluster-map-example.component.html +31 -10
  33. package/src/maps/cluster-map/cluster-map-example.component.ts +7 -2
  34. package/src/maps/cluster-map-root-node/cluster-map-root-node-example.component.html +13 -17
  35. package/src/maps/map-popup/map-popup-example.component.html +4 -4
  36. package/src/maps/simple-map/simple-map-example.component.html +8 -5
  37. package/src/maps/simple-map/simple-map-example.module.ts +1 -1
  38. package/src/maps/simple-map-custom-config/map-layer.service.ts +50 -0
  39. package/src/maps/simple-map-custom-config/simple-map-custom-config.component.html +27 -0
  40. package/src/maps/simple-map-custom-config/simple-map-custom-config.component.ts +16 -0
  41. package/src/maps/simple-map-custom-config/simple-map-custom-config.module.ts +35 -0
  42. package/src/pattern-messages/pattern-messages-array.ts +20 -0
  43. package/src/pattern-messages/pattern-messages-factory.ts +18 -0
  44. package/src/pattern-messages/pattern-messages-single.ts +10 -0
  45. package/src/popconfirm/pop-confirm-example.component.ts +5 -2
  46. package/src/quick-link/quick-link-example.component.ts +0 -3
  47. package/src/realtime/realtime-tutorial.component.html +39 -30
  48. package/src/selector/alarm-event-selector-example/alarm-event-selector.component.ts +19 -15
  49. package/src/selector/data-points-export-selector-example/datapoints-export-selector.component.ts +11 -15
  50. package/src/translations/text-translation/gettext-translation/text-translation-gettext.component.ts +8 -6
  51. package/src/hooks/preview-feature/preview-feature.module.ts +0 -11
  52. package/src/hooks/widget-config/basic-view/basic-edit.component.html +0 -18
@@ -36,7 +36,6 @@ export const widgetConfigHookProviders = [
36
36
  })
37
37
  ),
38
38
  hookComponent(referenceWidgetDefinition),
39
- // important
40
39
  hookWidgetConfig({
41
40
  widgetId: 'reference.component',
42
41
  label: 'An additional Configuration for the simple component',
@@ -47,7 +46,6 @@ export const widgetConfigHookProviders = [
47
46
  m => m.AdditionalConfigComponent
48
47
  )
49
48
  }),
50
-
51
49
  hookWidgetConfig({
52
50
  widgetId: 'reference.component',
53
51
  label: 'The default asset selector.',
@@ -55,5 +53,4 @@ export const widgetConfigHookProviders = [
55
53
  loadComponent: () =>
56
54
  import('@c8y/ngx-components/context-dashboard').then(m => m.WidgetAssetSelectorComponent)
57
55
  })
58
- // /important
59
56
  ];
@@ -9,15 +9,20 @@ import { CoreModule, FormsModule } from '@c8y/ngx-components';
9
9
  <ul class="list-unstyled p-t-16" c8yInputGroupListContainer>
10
10
  <li class="m-b-8" *ngFor="let item of items; let i = index; trackBy: trackByFn">
11
11
  <c8y-input-group-list
12
+ [attr.aria-label]="'Input group-' + (i + 1)"
12
13
  [index]="i"
13
- (onAdd)="add()"
14
- (onRemove)="remove($event)"
14
+ (onAdd)="add(); announceChange('Item added')"
15
+ (onRemove)="remove(i); announceChange('Item removed')"
15
16
  [minus]="items.length > 1"
16
17
  >
17
18
  <c8y-form-group class="form-group--tooltip-validation">
19
+ <label class="sr-only" [attr.for]="'extendable-input-' + i"
20
+ >List item {{ i + 1 }}</label
21
+ >
18
22
  <input
19
23
  class="form-control"
20
- placeholder="{{ 'e.g.' }} placeholder"
24
+ [attr.aria-label]="'List item-' + (i + 1)"
25
+ placeholder="e.g. placeholder"
21
26
  type="text"
22
27
  [required]="true"
23
28
  [(ngModel)]="items[i]"
@@ -26,12 +31,15 @@ import { CoreModule, FormsModule } from '@c8y/ngx-components';
26
31
  </c8y-input-group-list>
27
32
  </li>
28
33
  </ul>
34
+ <!-- aria-live region for screen reader announcements -->
35
+ <div class="sr-only" aria-live="polite" #liveRegion>{{ liveMessage }}</div>
29
36
  </div>`,
30
37
  standalone: true,
31
38
  imports: [CoreModule, FormsModule, CommonModule]
32
39
  })
33
40
  export class ExtendableInputListExampleComponent {
34
41
  items: string[] = [];
42
+ liveMessage = '';
35
43
 
36
44
  ngOnInit() {
37
45
  this.add();
@@ -48,4 +56,12 @@ export class ExtendableInputListExampleComponent {
48
56
  remove(index) {
49
57
  this.items.splice(index, 1);
50
58
  }
59
+
60
+ announceChange(message: string) {
61
+ this.liveMessage = message;
62
+ // Optionally clear the message after a short delay for repeated announcements
63
+ setTimeout(() => {
64
+ this.liveMessage = '';
65
+ }, 1000);
66
+ }
51
67
  }
@@ -1,13 +1,29 @@
1
- import { Component, Input } from '@angular/core';
1
+ import { Component, Input, TemplateRef, ViewChild } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
+ import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
3
4
  import { WidgetConfig } from '../widget-config.model';
5
+ import { LazyWidgetViewComponent } from '../lazy-widget-view';
4
6
 
5
7
  @Component({
6
8
  selector: 'tutorial-lazy-widget-config',
7
- template: `<p>This widget's configuration component/module is only loaded when needed.</p>`,
9
+ template: `<p>This widget's configuration component/module is only loaded when needed.</p>
10
+ <ng-template #lazyWidgetPreview>
11
+ <tutorial-lazy-widget-view></tutorial-lazy-widget-view>
12
+ </ng-template>`,
8
13
  standalone: true,
9
- imports: [CommonModule]
14
+ imports: [CommonModule, LazyWidgetViewComponent]
10
15
  })
11
16
  export class LazyWidgetConfigComponent {
12
17
  @Input() config: WidgetConfig;
18
+
19
+ @ViewChild('lazyWidgetPreview', { static: true })
20
+ set previewMapSet(template: TemplateRef<any>) {
21
+ if (template) {
22
+ this.widgetConfigService.setPreview(template);
23
+ return;
24
+ }
25
+ this.widgetConfigService.setPreview(null);
26
+ }
27
+
28
+ constructor(private widgetConfigService: WidgetConfigService) {}
13
29
  }
@@ -30,7 +30,7 @@
30
30
  class="btn-clean"
31
31
  (click)="li.collapsed = !li.collapsed"
32
32
  >
33
- {{ device.name || '-' }} {{ totalLoaded }}
33
+ {{ device.name || '-' }}
34
34
  </button>
35
35
  <c8y-li-action
36
36
  icon="delete"
@@ -1,6 +1,6 @@
1
1
  <c8y-title>Cluster map example</c8y-title>
2
- <div class="d-flex p-16">
3
- <div class="d-flex d-col j-c-center p-16">
2
+ <div class="d-flex">
3
+ <div class="d-flex d-col j-c-center p-r-16" style="width: 280px;">
4
4
  <button
5
5
  class="btn btn-default btn-block"
6
6
  (click)="setRandomZoomLevel()"
@@ -9,9 +9,23 @@
9
9
  </button>
10
10
  <button
11
11
  class="btn btn-default btn-block"
12
- (click)="setCenter()"
12
+ (click)="setCenterNY()"
13
+ *ngIf="40.7128 !== config.center[0] || -74.006 !== config.center[1]"
13
14
  >
14
- Set map to Düsseldorf
15
+ Change center to New York
16
+ </button>
17
+ <button
18
+ class="btn btn-default btn-block"
19
+ (click)="setCenterDus()"
20
+ *ngIf="51.23544 !== config.center[0] || 6.79599 !== config.center[1]"
21
+ >
22
+ Change center to Düsseldorf
23
+ </button>
24
+ <button
25
+ class="btn btn-default btn-block"
26
+ (click)="map.center()"
27
+ >
28
+ Go back to defined center
15
29
  </button>
16
30
  <button
17
31
  class="btn btn-default btn-block"
@@ -37,12 +51,19 @@
37
51
  >
38
52
  Show cluster color
39
53
  </button>
54
+ <button
55
+ class="btn btn-default btn-block"
56
+ (click)="showMapStatus = !showMapStatus"
57
+ >
58
+ Show map status
59
+ </button>
40
60
  </div>
41
61
  <!-- important -->
42
- <div style="height: 350px; width: 100%; position: relative;">
62
+ <div class="flex-grow p-relative a-s-stretch">
43
63
  <c8y-map-status
44
64
  [clusterMap]="map"
45
65
  [(config)]="config"
66
+ *ngIf="showMapStatus"
46
67
  ></c8y-map-status>
47
68
  <c8y-cluster-map
48
69
  #map
@@ -51,10 +72,10 @@
51
72
  ></c8y-cluster-map>
52
73
  </div>
53
74
  <!-- /important -->
54
- <code
55
- class="a-s-stretch p-16"
56
- style="width: 200px"
75
+ <div
76
+ class="a-s-stretch p-16 d-col bg-info-light"
77
+ style="width: 320px; height: 420px;"
57
78
  >
58
- <pre>{{ config | json }} </pre>
59
- </code>
79
+ <pre class="flex-grow">{{ config | json }} </pre>
80
+ </div>
60
81
  </div>
@@ -13,13 +13,18 @@ import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
13
13
  export class ClusterMapExampleComponent {
14
14
  config: ClusterMapConfig = { center: defaultMapConfig.center, zoomLevel: 4 };
15
15
  showClusterColor = false;
16
+ showMapStatus = true;
16
17
 
17
18
  setRandomZoomLevel() {
18
19
  this.config = { ...this.config, zoomLevel: Math.floor(1 + Math.random() * 11) };
19
20
  }
20
21
 
21
- setCenter() {
22
- this.config = { ...this.config, center: defaultMapConfig.center };
22
+ setCenterNY() {
23
+ this.config = { ...this.config, center: [40.7128, -74.006] };
24
+ }
25
+
26
+ setCenterDus() {
27
+ this.config = { ...this.config, center: [51.23544, 6.79599] };
23
28
  }
24
29
 
25
30
  changeIcon() {
@@ -1,7 +1,7 @@
1
1
  <c8y-title>Cluster map with root node</c8y-title>
2
2
 
3
- <div class="d-flex p-16">
4
- <div class="d-flex d-col j-c-center p-16" style="min-width: 150px;">
3
+ <div class="d-flex">
4
+ <div class="d-flex d-col" style="width: 280px;">
5
5
  <c8y-asset-selector
6
6
  [(ngModel)]="rootNode"
7
7
  [config]="{
@@ -9,10 +9,12 @@
9
9
  groupsOnly: false
10
10
  }"
11
11
  (change)="resetConfig()"
12
+ class="bg-level-1 min-height-0"
13
+ style="height: 420px;"
12
14
  ></c8y-asset-selector>
13
15
  </div>
14
16
  <!-- important -->
15
- <div style="height: 350px; width: 100%; position: relative;">
17
+ <div class="flex-grow p-relative a-s-stretch">
16
18
  <c8y-map-status
17
19
  [clusterMap]="map"
18
20
  [(config)]="followConfig"
@@ -36,19 +38,13 @@
36
38
  </c8y-cluster-map>
37
39
  </div>
38
40
  <!-- /important -->
39
- <code
40
- class="a-s-stretch p-16"
41
- style="width: 200px"
41
+ <div
42
+ class="a-s-stretch p-16 d-col bg-info-light"
43
+ style="width: 320px; height: 420px;"
42
44
  >
43
- RootNode:
44
- <code>
45
- <pre style="max-height: 120px">{{ rootNode | json }} </pre>
46
- </code>
47
- <br />
48
- <br />
49
- Config:
50
- <code>
51
- <pre style="max-height: 120px">{{ followConfig | json }} </pre>
52
- </code>
53
- </code>
45
+ <label>RootNode</label>
46
+ <pre style="height: 120px">{{ rootNode | json }} </pre>
47
+ <label>Config</label>
48
+ <pre class="flex-grow">{{ followConfig | json }} </pre>
49
+ </div>
54
50
  </div>
@@ -1,7 +1,7 @@
1
1
  <c8y-title>Map with popup example</c8y-title>
2
2
 
3
- <div class="d-flex p-16">
4
- <div class="d-flex d-col j-c-center p-16">
3
+ <div class="d-flex">
4
+ <div class="d-flex d-col j-c-center p-r-16" style="width: 280px; height: 420px;">
5
5
  <button
6
6
  class="btn btn-primary btn-block"
7
7
  (click)="showFirstPopup()"
@@ -16,13 +16,13 @@
16
16
  </button>
17
17
  </div>
18
18
  <!-- important -->
19
- <div style="height: 350px; width: 100%">
19
+ <div class="flex-grow p-relative a-s-stretch">
20
20
  <c8y-map
21
21
  [assets]="exampleDevices"
22
22
  [config]="config"
23
23
  >
24
24
  <div *c8yMapPopup="let context">
25
- Hello World from:
25
+ <b>Hello World from:</b>
26
26
  <br />
27
27
  name: {{ context.name }}
28
28
  <br />
@@ -1,7 +1,7 @@
1
1
  <c8y-title>Simple map example</c8y-title>
2
2
 
3
- <div class="d-flex p-16">
4
- <div class="d-flex d-col j-c-center p-16">
3
+ <div class="d-flex">
4
+ <div class="d-flex d-col j-c-center p-r-16" style="width: 280px;">
5
5
  <button
6
6
  class="btn btn-default btn-block"
7
7
  (click)="changeDevices()"
@@ -46,14 +46,17 @@
46
46
  </button>
47
47
  </div>
48
48
  <!-- important -->
49
- <div style="height: 350px; width: 100%;">
49
+ <div class="flex-grow p-relative a-s-stretch">
50
50
  <c8y-map
51
51
  [assets]="exampleDevices"
52
52
  [config]="config"
53
53
  ></c8y-map>
54
54
  </div>
55
55
  <!-- /important -->
56
- <code style="width: 200px;" class="a-s-stretch p-16">
56
+ <div
57
+ class="a-s-stretch p-16 d-col bg-info-light"
58
+ style="width: 320px; height: 420px;"
59
+ >
57
60
  <pre>{{ config | json }} </pre>
58
- </code>
61
+ </div>
59
62
  </div>
@@ -1,5 +1,5 @@
1
- import { NgModule } from '@angular/core';
2
1
  import { CommonModule } from '@angular/common';
2
+ import { NgModule } from '@angular/core';
3
3
  import { NavigatorNode, hookNavigator, hookRoute } from '@c8y/ngx-components';
4
4
 
5
5
  @NgModule({
@@ -0,0 +1,50 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { defaultLayer } from '@c8y/ngx-components/map';
3
+ import { MapTileLayer } from '@c8y/options';
4
+ import { BehaviorSubject, Observable } from 'rxjs';
5
+
6
+ @Injectable({
7
+ providedIn: 'root'
8
+ })
9
+ export class MapLayerService implements CumulocityServiceRegistry.MapTileLayerProvider {
10
+ maps$ = new BehaviorSubject<MapTileLayer[]>([defaultLayer]);
11
+
12
+ getMapTileLayers$(): Observable<MapTileLayer[]> {
13
+ return this.maps$;
14
+ }
15
+
16
+ overridesDefaultLayer(): boolean {
17
+ return true;
18
+ }
19
+
20
+ changeLayer(name: 'Carto' | 'OpenTopo') {
21
+ if (name === 'Carto') {
22
+ this.maps$.next([
23
+ {
24
+ layerUrl: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
25
+ label: 'Carto',
26
+ priority: 1000,
27
+ options: {
28
+ maxZoom: 12
29
+ }
30
+ }
31
+ ]);
32
+ } else if (name === 'OpenTopo') {
33
+ this.maps$.next([
34
+ {
35
+ layerUrl: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
36
+ label: 'OpenTopo',
37
+ priority: 1000,
38
+ options: {
39
+ maxZoom: 17,
40
+ minZoom: 0
41
+ }
42
+ }
43
+ ]);
44
+ }
45
+ }
46
+
47
+ revert() {
48
+ this.maps$.next([defaultLayer]);
49
+ }
50
+ }
@@ -0,0 +1,27 @@
1
+ <c8y-title>Simple map with custom config</c8y-title>
2
+
3
+ <div class="d-flex">
4
+ <div class="d-flex d-col j-c-center p-r-16" style="width: 280px; height: 420px">
5
+ <button
6
+ class="btn btn-default btn-block"
7
+ (click)="mapLayerService?.changeLayer('Carto')"
8
+ >
9
+ Change to Carto layer
10
+ </button>
11
+ <button
12
+ class="btn btn-default btn-block"
13
+ (click)="mapLayerService?.changeLayer('OpenTopo')"
14
+ >
15
+ Change to OpenTopo layer
16
+ </button>
17
+ <button
18
+ class="btn btn-default btn-block"
19
+ (click)="mapLayerService?.revert()"
20
+ >
21
+ Change to default
22
+ </button>
23
+ </div>
24
+ <div class="flex-grow p-relative a-s-stretch">
25
+ <c8y-map></c8y-map>
26
+ </div>
27
+ </div>
@@ -0,0 +1,16 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, inject } from '@angular/core';
3
+ import { CoreModule } from '@c8y/ngx-components';
4
+ import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
5
+ import { MapModule } from '@c8y/ngx-components/map';
6
+ import { MapLayerService } from './map-layer.service';
7
+
8
+ @Component({
9
+ selector: 'c8y-simple-map-custom-config',
10
+ templateUrl: './simple-map-custom-config.component.html',
11
+ standalone: true,
12
+ imports: [CommonModule, MapModule, CoreModule, AssetSelectorModule]
13
+ })
14
+ export class SimpleMapCustomConfigComponent {
15
+ mapLayerService = inject(MapLayerService);
16
+ }
@@ -0,0 +1,35 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { NgModule } from '@angular/core';
3
+ import {
4
+ HookProviderTypes,
5
+ NavigatorNode,
6
+ hookNavigator,
7
+ hookRoute,
8
+ hookService
9
+ } from '@c8y/ngx-components';
10
+ import { MapLayerService } from './map-layer.service';
11
+
12
+ @NgModule({
13
+ imports: [CommonModule],
14
+ providers: [
15
+ MapLayerService,
16
+ hookService('mapTileLayerHook', MapLayerService, {
17
+ providerType: HookProviderTypes.ExistingProvider
18
+ }),
19
+ hookRoute({
20
+ path: 'maps/simple-with-custom-config',
21
+ loadComponent: () =>
22
+ import('./simple-map-custom-config.component').then(m => m.SimpleMapCustomConfigComponent)
23
+ }),
24
+ hookNavigator(
25
+ new NavigatorNode({
26
+ priority: 30,
27
+ path: 'maps/simple-with-custom-config',
28
+ icon: 'map-editing',
29
+ label: 'Simple map with custom config',
30
+ parent: 'Map examples'
31
+ })
32
+ )
33
+ ]
34
+ })
35
+ export class SimpleMapCustomConfigModule {}
@@ -0,0 +1,20 @@
1
+ import { hookPatternMessages } from '@c8y/ngx-components';
2
+
3
+ hookPatternMessages([
4
+ {
5
+ '^Alarm: (.+) is active$': {
6
+ gettext: 'Active alarm for {{alarmType}} detected',
7
+ placeholders: {
8
+ alarmType: '$1'
9
+ }
10
+ }
11
+ },
12
+ {
13
+ '^User (.+) has logged in$': {
14
+ gettext: 'Welcome, {{username}}!',
15
+ placeholders: {
16
+ username: '$1'
17
+ }
18
+ }
19
+ }
20
+ ]);
@@ -0,0 +1,18 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { ExtensionFactory, hookPatternMessages, PatternMessages } from '@c8y/ngx-components';
3
+
4
+ @Injectable()
5
+ export class MyPatternMessagesFactory implements ExtensionFactory<PatternMessages> {
6
+ get() {
7
+ return {
8
+ '^Firmware update for (.+) completed$': {
9
+ gettext: 'Firmware update finished for device: {{deviceName}}',
10
+ placeholders: {
11
+ deviceName: '$1'
12
+ }
13
+ }
14
+ };
15
+ }
16
+ }
17
+
18
+ hookPatternMessages(MyPatternMessagesFactory);
@@ -0,0 +1,10 @@
1
+ import { hookPatternMessages } from '@c8y/ngx-components';
2
+
3
+ hookPatternMessages({
4
+ '^Alarm: (.+) is active$': {
5
+ gettext: 'Active alarm for {{alarmType}} detected',
6
+ placeholders: {
7
+ alarmType: '$1'
8
+ }
9
+ }
10
+ });
@@ -11,10 +11,11 @@ import {
11
11
  @Component({
12
12
  selector: 'pop-confirm-example',
13
13
  template: `<c8y-title>Popover confirm</c8y-title>
14
- <div class="p-24">
14
+ <div class="p-24 d-inline-block">
15
15
  <button
16
16
  class="btn btn-dot btn-dot--danger m-l-auto"
17
17
  title="{{ 'Delete' | translate }}"
18
+ [attr.aria-label]="'Delete' | translate"
18
19
  type="button"
19
20
  (click)="triggerPopover(poConfirm)"
20
21
  >
@@ -46,7 +47,9 @@ export class PopConfirmExampleComponent {
46
47
 
47
48
  async triggerPopover(poConfirm: PopoverConfirmComponent): Promise<void> {
48
49
  // to set the message
49
- poConfirm.message = gettext('This action is irreversible.');
50
+ poConfirm.message = gettext(
51
+ 'Are you sure you want to delete this item? This action is irreversible.'
52
+ );
50
53
  try {
51
54
  const remove = await poConfirm.show(this.confirmRemoveColumnButtons);
52
55
  if (!remove) {
@@ -8,9 +8,6 @@ import { CoreModule, DocLink, DocsService, gettext, QuickLinkModule } from '@c8y
8
8
  class="btn-clean card text-pre-normal"
9
9
  *ngFor="let link of quickLinks"
10
10
  (click)="link.click ? link.click() : false"
11
- c8yProductExperience
12
- [actionName]="'welcomeWidgetClicked'"
13
- [actionData]="{ link: link.label }"
14
11
  >
15
12
  <c8y-quick-link [icon]="link.icon" [label]="link.label"></c8y-quick-link>
16
13
  </button>`,
@@ -1,8 +1,8 @@
1
1
  <c8y-title>Realtime</c8y-title>
2
2
 
3
3
  <c8y-action-bar-item itemClass="navbar-form" placement="right">
4
- <div class="form-group">
5
- <label for="bufferSizeOptions" translate>Maximum buffer size of notifications</label>
4
+ <div class="d-flex a-i-center">
5
+ <label class="m-0 p-r-4" for="bufferSizeOptions" translate>Maximum buffer size of notifications</label>
6
6
  <div class="c8y-select-wrapper">
7
7
  <select
8
8
  id="bufferSizeOptions"
@@ -15,38 +15,47 @@
15
15
  </div>
16
16
  </c8y-action-bar-item>
17
17
 
18
- <div class="card">
19
- <div class="card-block">
20
- <ul>
21
- <li *ngFor="let service of services">
22
- <c8y-realtime-btn [service]="service.instance" [title]="'Toggle ' + service.className" [label]="service.className"></c8y-realtime-btn>
23
- </li>
24
- </ul>
25
- <p>
26
- Below you can find the latest {{ bufferSize }} notifications received from your tenant.
27
- </p>
28
- </div>
29
- </div>
30
-
31
- <ng-container *ngIf="(allAPIsRealtime$ | async) as notificationBuffer; else waiting">
32
- <ng-container *ngIf="notificationBuffer.length; else waiting">
33
- <div class="card" *ngFor="let realtimeItem of notificationBuffer; let i = index">
18
+ <div class="row">
19
+ <div class="col-md-6">
20
+ <div class="card">
34
21
  <div class="card-header separator">
35
- <h4 class="card-title">{{ i + 1 }}. RealtimeMessage in buffer</h4>
36
- </div>
37
- <div class="card-block">
38
- <pre><code>{{ realtimeItem | json }}</code></pre>
22
+ <h4>Realtime services</h4>
39
23
  </div>
24
+ <c8y-list-group>
25
+ <c8y-li *ngFor="let service of services">
26
+ <c8y-realtime-btn [service]="service.instance" [title]="'Toggle ' + service.className" [label]="service.className"></c8y-realtime-btn>
27
+ </c8y-li>
28
+ </c8y-list-group>
40
29
  </div>
41
- </ng-container>
42
- </ng-container>
30
+ </div>
31
+ <div class="col-md-6">
32
+ <ng-container *ngIf="(allAPIsRealtime$ | async) as notificationBuffer; else waiting">
33
+ <ng-container *ngIf="notificationBuffer.length; else waiting">
34
+ <div class="card">
35
+ <div class="card-header separator">
36
+ <h4 class="card-title">Latest {{ bufferSize }} notifications received </h4>
37
+ </div>
38
+ <div class="inner-scroll" style="height: 312px;">
39
+ <div class="card-block">
40
+ <div [ngClass]="{'separator-top p-t-16': i > 0}" *ngFor="let realtimeItem of notificationBuffer; let i = index">
41
+ <p class="m-b-8"><strong>{{ i + 1 }}. RealtimeMessage in buffer</strong></p>
42
+ <pre><code>{{ realtimeItem | json }}</code></pre>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </ng-container>
48
+ </ng-container>
43
49
 
44
- <ng-template #waiting>
45
- <div class="card">
46
- <div class="card-header separator">
47
- <h4 class="card-title"><i c8yIcon="spinner" class="icon-spin"></i> Waiting for the first notification to be received.</h4>
48
- </div>
50
+ <ng-template #waiting>
51
+ <div class="card">
52
+ <div class="card-block">
53
+ <c8y-loading></c8y-loading>
54
+ Waiting for the first notification to be received.
55
+ </div>
56
+ </div>
57
+ </ng-template>
49
58
  </div>
50
- </ng-template>
59
+ </div>
51
60
 
52
61