@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
@@ -192,6 +192,13 @@ export default {
192
192
  description: 'A sample for simple map.',
193
193
  scope: 'self'
194
194
  },
195
+ {
196
+ name: 'Simple map with custom config',
197
+ module: 'SimpleMapCustomConfigModule',
198
+ path: './src/maps/simple-map-custom-config/simple-map-custom-config.module.ts',
199
+ description: 'A sample for simple map with custom config.',
200
+ scope: 'self'
201
+ },
195
202
  {
196
203
  name: 'Cluster map',
197
204
  module: 'ClusterMapExampleModule',
@@ -214,10 +221,17 @@ export default {
214
221
  scope: 'self'
215
222
  },
216
223
  {
217
- name: 'Preview feature',
218
- module: 'PreviewFeatureModule',
219
- path: './src/hooks/preview-feature/preview-feature.module.ts',
220
- description: 'A sample for feature preview hook.',
224
+ name: 'Default Preview feature',
225
+ module: 'PreviewFeatureDefaultModule',
226
+ path: './src/hooks/preview-feature/basic-view-default/preview-feature-default.module.ts',
227
+ description: 'A sample for default feature preview hook.',
228
+ scope: 'self'
229
+ },
230
+ {
231
+ name: 'Custom Preview feature',
232
+ module: 'PreviewFeatureCustomModule',
233
+ path: './src/hooks/preview-feature/basic-view-custom/preview-feature-custom.module.ts',
234
+ description: 'A sample for custom feature preview hook.',
221
235
  scope: 'self'
222
236
  },
223
237
  {
@@ -290,6 +304,13 @@ export default {
290
304
  description: 'A sample for tabs hook.',
291
305
  scope: 'self'
292
306
  },
307
+ {
308
+ name: 'Named router outlet',
309
+ module: 'NamedOutletModule',
310
+ path: './src/hooks/tabs/named-outlet/named-outlet.module.ts',
311
+ description: 'A sample for named router outlet and related hooks.',
312
+ scope: 'self'
313
+ },
293
314
  {
294
315
  name: 'Navigator-route',
295
316
  module: 'NavigatorRouteModule',
@@ -780,6 +801,13 @@ export default {
780
801
  description: 'This is an example for an Action added via service or factory.',
781
802
  scope: 'self'
782
803
  },
804
+ {
805
+ name: 'Hooking via service',
806
+ module: 'HookDocsModule',
807
+ path: './src/hooks/docs/hook-docs.module.ts',
808
+ description: 'This is an example for an hook docs added via module or service.',
809
+ scope: 'self'
810
+ },
783
811
  {
784
812
  name: 'Device connection status',
785
813
  module: 'DeviceConnectionStatusExampleModule',
@@ -821,6 +849,13 @@ export default {
821
849
  path: './src/hooks/widget-config/widget-config.providers.ts',
822
850
  description: 'This is an example for the bottom drawer service.',
823
851
  scope: 'self'
852
+ },
853
+ {
854
+ name: 'Widget Hook',
855
+ module: 'widgetHookProviders',
856
+ path: './src/hooks/widget/widget.providers.ts',
857
+ description: 'This is an example for the bottom drawer service.',
858
+ scope: 'self'
824
859
  }
825
860
  ]
826
861
  },
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@c8y/tutorial",
3
- "version": "1022.10.1",
3
+ "version": "1022.13.0",
4
4
  "description": "This package is used to scaffold a tutorial for Cumulocity IoT Web SDK which explains a lot of concepts.",
5
5
  "dependencies": {
6
- "@c8y/style": "1022.10.1",
7
- "@c8y/ngx-components": "1022.10.1",
8
- "@c8y/client": "1022.10.1",
9
- "@c8y/bootstrap": "1022.10.1",
6
+ "@c8y/style": "1022.13.0",
7
+ "@c8y/ngx-components": "1022.13.0",
8
+ "@c8y/client": "1022.13.0",
9
+ "@c8y/bootstrap": "1022.13.0",
10
10
  "@angular/cdk": "^19.2.18",
11
11
  "ngx-bootstrap": "19.0.2",
12
12
  "leaflet": "1.9.4",
13
13
  "rxjs": "7.8.1"
14
14
  },
15
15
  "devDependencies": {
16
- "@c8y/options": "1022.10.1",
17
- "@c8y/devkit": "1022.10.1"
16
+ "@c8y/options": "1022.13.0",
17
+ "@c8y/devkit": "1022.13.0"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@angular/common": ">=19 <20"
@@ -69,8 +69,13 @@ export class InventoryInterceptor implements HttpInterceptor {
69
69
  'has(c8y_IsDeviceGroup)': () => ({
70
70
  managedObjects: [...[...Array(5)].map(() => generateGroup())]
71
71
  }),
72
+ // generate 3 realtime devices for the map example
72
73
  'has(c8y_Position)': () => ({
73
- managedObjects: [generateRealtimeDeviceMO()]
74
+ managedObjects: [
75
+ generateRealtimeDeviceMO(),
76
+ generateRealtimeDeviceMO(),
77
+ generateRealtimeDeviceMO()
78
+ ]
74
79
  }),
75
80
  'has(c8y_IsDevice)': () => ({
76
81
  managedObjects: [...[...Array(5)].map(() => generateDevice())]
@@ -0,0 +1,62 @@
1
+ import { IFetchResponse } from '@c8y/client';
2
+ import { ApiCall, HttpHandler, HttpInterceptor } from '@c8y/ngx-components/api';
3
+ import { handleRequest } from '../utils/common';
4
+ import { Observable } from 'rxjs';
5
+
6
+ export class ProviderConfigurationsApiInterceptor implements HttpInterceptor {
7
+ configurations = [
8
+ { id: 'provider1', config: { username: 'user1', password: 'pass1' } },
9
+ { id: 'provider2', config: { username: 'user2', password: 'pass2' } }
10
+ ];
11
+
12
+ intercept(req: ApiCall, next: HttpHandler): Observable<IFetchResponse> {
13
+ return handleRequest(req, next, '/service/demo/providers/configuration', {
14
+ GET: this.mockGET.bind(this),
15
+ POST: this.mockPOST.bind(this),
16
+ PUT: this.mockPUT.bind(this),
17
+ DELETE: this.mockDELETE.bind(this)
18
+ });
19
+ }
20
+
21
+ private async mockGET(_requestDescriptor: string) {
22
+ return {
23
+ status: 200,
24
+ json: async () => this.configurations
25
+ };
26
+ }
27
+
28
+ private async mockPOST(requestDescriptor: string) {
29
+ const bodyStartIndex = requestDescriptor.indexOf('{');
30
+ const body = bodyStartIndex !== -1 ? JSON.parse(requestDescriptor.slice(bodyStartIndex)) : {};
31
+ this.configurations.push(body);
32
+ return {
33
+ status: 201,
34
+ json: async () => body
35
+ };
36
+ }
37
+
38
+ private async mockPUT(requestDescriptor: string) {
39
+ const bodyStartIndex = requestDescriptor.indexOf('{');
40
+ const body = bodyStartIndex !== -1 ? JSON.parse(requestDescriptor.slice(bodyStartIndex)) : {};
41
+ const idx = this.configurations.findIndex(c => c.id === body.id);
42
+ if (idx > -1) {
43
+ this.configurations[idx] = body;
44
+ }
45
+ return {
46
+ status: 200,
47
+ json: async () => body
48
+ };
49
+ }
50
+
51
+ private async mockDELETE(requestDescriptor: string) {
52
+ const match = requestDescriptor.match(/\/configuration\/([^/]+)/);
53
+ if (match) {
54
+ const id = match[1];
55
+ this.configurations = this.configurations.filter(c => c.id !== id);
56
+ }
57
+ return {
58
+ status: 204,
59
+ json: async () => ({})
60
+ };
61
+ }
62
+ }
@@ -0,0 +1,24 @@
1
+ import { IFetchResponse } from '@c8y/client';
2
+ import { ApiCall, HttpHandler, HttpInterceptor } from '@c8y/ngx-components/api';
3
+ import { handleRequest } from '../utils/common';
4
+ import { Observable } from 'rxjs';
5
+
6
+ export class ProviderDefinitionsApiInterceptor implements HttpInterceptor {
7
+ providers = [
8
+ { id: 'provider1', name: 'Provider One' },
9
+ { id: 'provider2', name: 'Provider Two' }
10
+ ];
11
+
12
+ intercept(req: ApiCall, next: HttpHandler): Observable<IFetchResponse> {
13
+ return handleRequest(req, next, '/service/demo/providers/definitions', {
14
+ GET: this.mockGET.bind(this)
15
+ });
16
+ }
17
+
18
+ private async mockGET(_requestDescriptor: string) {
19
+ return {
20
+ status: 200,
21
+ json: async () => this.providers
22
+ };
23
+ }
24
+ }
@@ -24,6 +24,8 @@ import { EnvironmentProviders, Provider, inject, provideAppInitializer } from '@
24
24
  import { MockService } from './mock.service';
25
25
  import { IUser } from '@c8y/client';
26
26
  import { FeatureApiInterceptor } from './global-mocks/feature-api';
27
+ import { ProviderDefinitionsApiInterceptor } from './global-mocks/provider-definitions';
28
+ import { ProviderConfigurationsApiInterceptor } from './global-mocks/provider-configuration';
27
29
 
28
30
  export function provideAPIMock() {
29
31
  return [
@@ -161,6 +163,22 @@ export function provideAPIMock() {
161
163
  } as ApiMockConfig,
162
164
  multi: true
163
165
  },
166
+ {
167
+ provide: API_MOCK_CONFIG,
168
+ useValue: {
169
+ id: 'z-global-provider-definitions-interceptor-interceptor',
170
+ mockService: ProviderDefinitionsApiInterceptor
171
+ } as ApiMockConfig,
172
+ multi: true
173
+ },
174
+ {
175
+ provide: API_MOCK_CONFIG,
176
+ useValue: {
177
+ id: 'z-global-provider-configurations-interceptor-interceptor',
178
+ mockService: ProviderConfigurationsApiInterceptor
179
+ } as ApiMockConfig,
180
+ multi: true
181
+ },
164
182
  {
165
183
  provide: RealtimeSubjectService,
166
184
  useExisting: RealtimeSubjectServiceWithMocking
@@ -1,4 +1,7 @@
1
- <div class="time-elapsed">
1
+ <div class="time-elapsed"
2
+ [attr.aria-live]="'polite'"
3
+ [attr.aria-label]="'Time remaining until next refresh' | translate"
4
+ >
2
5
  <!-- important -->
3
6
  <c8y-countdown-interval
4
7
  [countdownInterval]="10000"
@@ -36,6 +36,7 @@ export class CountdownExampleComponent implements AfterViewInit {
36
36
  }
37
37
 
38
38
  onCountdownEnded(): void {
39
+ // eslint-disable-next-line no-console
39
40
  console.log('Countdown Ended!');
40
41
 
41
42
  this.resetCountdown();
@@ -9,7 +9,7 @@ import { FormlyModule } from '@ngx-formly/core';
9
9
  selector: 'c8y-custom-element-example',
10
10
  template: `<c8y-title>Dynamic forms: Custom element</c8y-title>
11
11
  <div class="row">
12
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
12
+ <div class="col-xs-12 col-md-7 col-lg-6">
13
13
  <form class="card" [formGroup]="form" (ngSubmit)="onSubmit()">
14
14
  <div class="card-block">
15
15
  <formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
@@ -20,7 +20,7 @@ import { FormlyModule } from '@ngx-formly/core';
20
20
  </div>
21
21
  </form>
22
22
  </div>
23
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
23
+ <div class="col-xs-12 col-md-5 col-lg-6">
24
24
  <div class="card">
25
25
  <div class="card-block">
26
26
  <div class="legend form-block">Model</div>
@@ -8,7 +8,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core';
8
8
  selector: 'c8y-introduction-example',
9
9
  template: `<c8y-title>Dynamic forms: Introduction</c8y-title>
10
10
  <div class="row">
11
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
11
+ <div class="col-xs-12 col-md-7 col-lg-6">
12
12
  <form class="card" [formGroup]="form" (ngSubmit)="onSubmit()">
13
13
  <div class="card-block">
14
14
  <formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
@@ -19,7 +19,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core';
19
19
  </div>
20
20
  </form>
21
21
  </div>
22
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
22
+ <div class="col-xs-12 col-md-5 col-lg-6">
23
23
  <div class="card">
24
24
  <div class="card-block">
25
25
  <div class="legend form-block">Model</div>
@@ -1,6 +1,6 @@
1
1
  <c8y-title>Dynamic forms: JSON schema</c8y-title>
2
2
  <div class="row">
3
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
3
+ <div class="col-xs-12 col-md-7 col-lg-6">
4
4
  <form class="card" [formGroup]="form" (ngSubmit)="onSubmit()">
5
5
  <div class="card-block">
6
6
  <!-- important -->
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
  </form>
24
24
  </div>
25
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
25
+ <div class="col-xs-12 col-md-5 col-lg-6">
26
26
  <div class="card">
27
27
  <div class="card-block">
28
28
  <div class="legend form-block">Model</div>
@@ -13,7 +13,7 @@ export function ipValidator(control: AbstractControl): ValidationErrors {
13
13
  selector: 'c8y-validation-example',
14
14
  template: `<c8y-title>Dynamic forms: Validation</c8y-title>
15
15
  <div class="row">
16
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
16
+ <div class="col-xs-12 col-md-7 col-lg-6">
17
17
  <form class="card" [formGroup]="form" (ngSubmit)="onSubmit()">
18
18
  <div class="card-block">
19
19
  <formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
@@ -24,7 +24,7 @@ export function ipValidator(control: AbstractControl): ValidationErrors {
24
24
  </div>
25
25
  </form>
26
26
  </div>
27
- <div class="col-xs-12 col-sm-10 col-md-8 col-lg-6">
27
+ <div class="col-xs-12 col-md-5 col-lg-6">
28
28
  <div class="card">
29
29
  <div class="card-block">
30
30
  <div class="legend form-block">Model</div>
@@ -1,5 +1,5 @@
1
1
  import { Component } from '@angular/core';
2
- import { CoreModule, ForOfFilterPipe } from '@c8y/ngx-components';
2
+ import { CoreModule, ForOfDirective, ForOfFilterPipe, LoadMoreMode } from '@c8y/ngx-components';
3
3
  import { IManagedObject, InventoryService, IResultList } from '@c8y/client';
4
4
  import { pipe } from 'rxjs';
5
5
  import { map, tap } from 'rxjs/operators';
@@ -8,13 +8,13 @@ import { map, tap } from 'rxjs/operators';
8
8
  selector: 'c8y-for-of-example',
9
9
  templateUrl: './for-of-example.component.html',
10
10
  standalone: true,
11
- imports: [CoreModule]
11
+ imports: [CoreModule, ForOfDirective]
12
12
  })
13
13
  export class ForOfExampleComponent {
14
14
  devices: IResultList<IManagedObject>;
15
15
  filterPipe: ForOfFilterPipe = pipe(tap());
16
16
  config = {
17
- loadMore: 'auto',
17
+ loadMore: 'auto' as LoadMoreMode,
18
18
  filter: '',
19
19
  pageSize: 10,
20
20
  maxIterations: 12
@@ -6,6 +6,7 @@ import { CoreModule } from '@c8y/ngx-components';
6
6
  template: `
7
7
  <h3>Base interface</h3>
8
8
  <pre>{{ baseInterface }}</pre>
9
+ <h3>Referenced types in base interface</h3>
9
10
  <pre>{{ referencedInterfaces }}</pre>
10
11
  <h3>JSON Schema generated from ExampleInterface</h3>
11
12
  <pre>{{ schemaString }}</pre>
@@ -0,0 +1,17 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { DocLink, ExtensionFactory } from '@c8y/ngx-components';
3
+ import { Observable, of } from 'rxjs';
4
+
5
+ @Injectable()
6
+ export class DocsExampleService implements ExtensionFactory<DocLink> {
7
+ get(): Observable<DocLink[]> {
8
+ return of([
9
+ {
10
+ icon: 'c8y-icon c8y-icon-mobile-add',
11
+ type: 'doc',
12
+ url: 'https://cumulocity.com',
13
+ label: 'Doc link from service'
14
+ }
15
+ ]);
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ import { Component } from '@angular/core';
2
+ import { TitleComponent } from '@c8y/ngx-components';
3
+
4
+ @Component({
5
+ selector: 'c8y-hook-docs-example',
6
+ imports: [TitleComponent],
7
+ template: `
8
+ <c8y-title>Docs</c8y-title>
9
+ <div class="card">
10
+ <div class="card-block">
11
+ <p>This is the example of <code>hookDocs</code>.</p>
12
+ <p>See the <code>Right drawer</code> in the <code>Documentation</code> section.</p>
13
+ </div>
14
+ </div>
15
+ `
16
+ })
17
+ export class HookDocsExampleComponent {}
@@ -0,0 +1,30 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { DocLink, hookDocs, hookNavigator, hookRoute, NavigatorNode } from '@c8y/ngx-components';
3
+ import { DocsExampleService } from './docs-example.service';
4
+
5
+ @NgModule({
6
+ providers: [
7
+ hookDocs({
8
+ icon: 'c8y-icon c8y-icon-mobile-add',
9
+ type: 'doc',
10
+ url: 'https://cumulocity.com/docs/',
11
+ label: 'Doc link from hookDocs'
12
+ } as DocLink),
13
+ hookDocs(DocsExampleService),
14
+ hookRoute({
15
+ path: 'hooks/docs',
16
+ loadComponent: () =>
17
+ import('./hook-docs-example.component').then(m => m.HookDocsExampleComponent)
18
+ }),
19
+ hookNavigator(
20
+ new NavigatorNode({
21
+ priority: 100,
22
+ path: 'hooks/docs',
23
+ icon: 'document',
24
+ label: 'Docs',
25
+ parent: 'Hooks'
26
+ })
27
+ )
28
+ ]
29
+ })
30
+ export class HookDocsModule {}
@@ -1,3 +1,2 @@
1
- export * from './preview-feature.module';
2
1
  export * from './basic-view-custom/preview-feature-custom.module';
3
2
  export * from './basic-view-default/preview-feature-default.module';
@@ -0,0 +1,15 @@
1
+ <c8y-title>Named router outlet example</c8y-title>
2
+ <div
3
+ clas="d-flex"
4
+ *ngIf="tabs.length"
5
+ >
6
+ <c8y-tabs-outlet
7
+ [outletName]="'namedOutletTabs'"
8
+ [orientation]="'horizontal'"
9
+ [openFirstTab]="true"
10
+ [tabs]="tabs"
11
+ ></c8y-tabs-outlet>
12
+ <div>
13
+ <router-outlet name="namedOutlet"></router-outlet>
14
+ </div>
15
+ </div>
@@ -0,0 +1,25 @@
1
+ import { Component } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { Tab, TabsService } from '@c8y/ngx-components';
4
+ import { map } from 'rxjs';
5
+
6
+ /**
7
+ * This is a standard angular component.
8
+ */
9
+ @Component({
10
+ selector: 'tut-basic-view',
11
+ templateUrl: './basic-view.component.html',
12
+ standalone: false
13
+ })
14
+ export class BasicViewComponent {
15
+ tabs: Tab[] = [];
16
+
17
+ constructor(private tabsService: TabsService) {
18
+ this.tabsService.items$
19
+ .pipe(
20
+ map(tabs => tabs.filter(tab => tab.tabsOutlet === 'namedOutletTabs')),
21
+ takeUntilDestroyed()
22
+ )
23
+ .subscribe(tabs => (this.tabs = tabs));
24
+ }
25
+ }
@@ -0,0 +1,8 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'tut-content-a',
5
+ template: `<div>This is content for <b>Tab A</b>.</div>`,
6
+ standalone: true
7
+ })
8
+ export class ContentAComponent {}
@@ -0,0 +1,8 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'tut-content-b',
5
+ template: `<div>This is content for <b>Tab B</b>.</div>`,
6
+ standalone: true
7
+ })
8
+ export class ContentBComponent {}
@@ -0,0 +1,80 @@
1
+ import { NgModule } from '@angular/core';
2
+ import {
3
+ CoreModule,
4
+ hookNavigator,
5
+ hookRoute,
6
+ hookTab,
7
+ NavigatorNode,
8
+ NavigatorNodeData
9
+ } from '@c8y/ngx-components';
10
+ import { RouterModule } from '@angular/router';
11
+ import { ContentAComponent } from './content-a.component';
12
+ import { ContentBComponent } from './content-b.component';
13
+ import { BasicViewComponent } from './basic-view/basic-view.component';
14
+
15
+ const hooks = [
16
+ hookRoute([
17
+ {
18
+ path: 'hooks/named-outlet',
19
+ component: BasicViewComponent,
20
+ children: [
21
+ {
22
+ path: 'content-a',
23
+ component: ContentAComponent,
24
+ outlet: 'namedOutlet'
25
+ },
26
+ {
27
+ path: 'content-b',
28
+ component: ContentBComponent,
29
+ outlet: 'namedOutlet'
30
+ }
31
+ ]
32
+ }
33
+ ]),
34
+ hookTab([
35
+ {
36
+ label: 'Tab A',
37
+ icon: 'web-design',
38
+ priority: 20,
39
+ featureId: 'A',
40
+ path: [
41
+ {
42
+ outlets: {
43
+ ['namedOutlet']: 'content-a'
44
+ }
45
+ }
46
+ ],
47
+ tabsOutlet: 'namedOutletTabs'
48
+ },
49
+ {
50
+ label: 'Tab B',
51
+ icon: 'web-design',
52
+ priority: 10,
53
+ featureId: 'B',
54
+ path: [
55
+ {
56
+ outlets: {
57
+ ['namedOutlet']: 'content-b'
58
+ }
59
+ }
60
+ ],
61
+ tabsOutlet: 'namedOutletTabs'
62
+ }
63
+ ]),
64
+ hookNavigator(
65
+ new NavigatorNode({
66
+ priority: 55,
67
+ path: 'hooks/named-outlet',
68
+ icon: 'name-tag',
69
+ label: 'Named router outlet',
70
+ parent: 'Hooks'
71
+ } as NavigatorNodeData)
72
+ )
73
+ ];
74
+
75
+ @NgModule({
76
+ declarations: [BasicViewComponent],
77
+ imports: [RouterModule, ContentAComponent, ContentBComponent, CoreModule],
78
+ providers: [...hooks]
79
+ })
80
+ export class NamedOutletModule {}
@@ -3,9 +3,7 @@ import { NavigatorNode, hookNavigator, hookRoute, hookTab } from '@c8y/ngx-compo
3
3
  import { ExampleTabFactory } from './tab';
4
4
 
5
5
  export const hooks = [
6
- // important
7
6
  hookTab(ExampleTabFactory),
8
- // /important
9
7
  hookRoute([
10
8
  {
11
9
  path: 'hooks/tabs',
@@ -0,0 +1,13 @@
1
+ import { Component } from '@angular/core';
2
+ import { CoreModule } from '@c8y/ngx-components';
3
+ import { ContextDashboardModule } from '@c8y/ngx-components/context-dashboard';
4
+ import { CommonModule } from '@angular/common';
5
+
6
+ @Component({
7
+ selector: 'tut-context-dashboard',
8
+ template: `<c8y-title>Context dashboard</c8y-title>
9
+ <c8y-context-dashboard name="example-widget" [canDelete]="false"></c8y-context-dashboard> `,
10
+ standalone: true,
11
+ imports: [ContextDashboardModule, CoreModule, CommonModule]
12
+ })
13
+ export class ContextDashboardComponent {}
@@ -0,0 +1,18 @@
1
+ import { hookNavigator, hookRoute, NavigatorNode } from '@c8y/ngx-components';
2
+
3
+ export const widgetHookProviders = [
4
+ hookRoute({
5
+ path: 'hooks/widget',
6
+ loadComponent: () =>
7
+ import('./context-dashboard.component').then(m => m.ContextDashboardComponent)
8
+ }),
9
+ hookNavigator(
10
+ new NavigatorNode({
11
+ priority: 75,
12
+ path: 'hooks/widget',
13
+ icon: 'edit',
14
+ label: 'Widget',
15
+ parent: 'Hooks'
16
+ })
17
+ )
18
+ ];
@@ -13,7 +13,24 @@ import { referenceWidgetDefinition } from '../widget-config.providers';
13
13
  */
14
14
  @Component({
15
15
  selector: 'tut-basic-widget-config-hook-view',
16
- templateUrl: './basic-edit.component.html',
16
+ template: `<div class="card">
17
+ <div class="card-block">
18
+ <c8y-widget-config-section
19
+ *ngFor="let section of widgetConfigService.currentSections$ | async; let i = index"
20
+ [section]="section"
21
+ ></c8y-widget-config-section>
22
+ </div>
23
+
24
+ <div class="card-block">
25
+ <label>The configuration is:</label>
26
+ <code>
27
+ <pre>
28
+ {{ widgetConfigService.currentConfig$ | async | json }}
29
+ </pre
30
+ >
31
+ </code>
32
+ </div>
33
+ </div>`,
17
34
  standalone: true,
18
35
  imports: [CoreModule, CommonModule, WidgetConfigSectionComponent, AsyncPipe, JsonPipe]
19
36
  })