@c8y/tutorial 1021.4.3 → 1021.6.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.
@@ -1,6 +1,6 @@
1
1
  import { ConfigurationOptions } from '@c8y/devkit';
2
2
  import { DefinePlugin } from 'webpack';
3
- import { author, description, version, name } from './package.json';
3
+ import { author, description, name, version } from './package.json';
4
4
 
5
5
  export default {
6
6
  runTime: {
@@ -261,6 +261,13 @@ export default {
261
261
  description: 'A sample for wizard hook.',
262
262
  scope: 'self'
263
263
  },
264
+ {
265
+ name: 'Service hook Codex sample',
266
+ module: 'ServiceHookCodexSampleModule',
267
+ path: './src/hooks/service/service-hook-codex-sample.module.ts',
268
+ description: 'A sample for hookService.',
269
+ scope: 'self'
270
+ },
264
271
  {
265
272
  name: 'Stepper',
266
273
  module: 'StepperHookModule',
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@c8y/tutorial",
3
- "version": "1021.4.3",
3
+ "version": "1021.6.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": "1021.4.3",
7
- "@c8y/ngx-components": "1021.4.3",
8
- "@c8y/client": "1021.4.3",
9
- "@c8y/bootstrap": "1021.4.3",
6
+ "@c8y/style": "1021.6.0",
7
+ "@c8y/ngx-components": "1021.6.0",
8
+ "@c8y/client": "1021.6.0",
9
+ "@c8y/bootstrap": "1021.6.0",
10
10
  "@angular/cdk": "^18.2.10",
11
11
  "ngx-bootstrap": "18.0.0",
12
12
  "leaflet": "1.9.4",
13
13
  "rxjs": "^7.8.1"
14
14
  },
15
15
  "devDependencies": {
16
- "@c8y/options": "1021.4.3",
17
- "@c8y/devkit": "1021.4.3"
16
+ "@c8y/options": "1021.6.0",
17
+ "@c8y/devkit": "1021.6.0"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@angular/common": ">=18 <19"
@@ -0,0 +1,44 @@
1
+ <c8y-title>Sharing a service between plugins</c8y-title>
2
+ <div class="card-block">
3
+ <p>
4
+ A service instance can be used by components that need to communicate to each other or share a
5
+ common state. If these two components originate from different code bases, e.g. are deployed via
6
+ plugin-ins, then
7
+ <code>hookService</code>
8
+ comes as a way for such a shared service to be injected. The service interface might be declared
9
+ in a shared library known at compile time.
10
+ </p>
11
+ <p>
12
+ This example showcases two component instances that share a counter service. The counter service
13
+ interface is declared in the
14
+ <code>counder.model</code>
15
+ module which may be declared in a common library shared between plug-ins in a real world case.
16
+ The
17
+ <code>CounterHookModule</code>
18
+ leverages
19
+ <code>hookService</code>
20
+ to inject a service instance. This can happen in a plugin or in a shell application.
21
+ </p>
22
+ </div>
23
+ <div class="card-group">
24
+ <div class="col-md-6">
25
+ <div class="card">
26
+ <div class="card-header separator">
27
+ <p class="card-title">Component A</p>
28
+ </div>
29
+ <div class="card-block">
30
+ <c8y-dynamic-component componentId="counter.component"></c8y-dynamic-component>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <div class="col-md-6">
35
+ <div class="card">
36
+ <div class="card-header separator">
37
+ <p class="card-title">Component B</p>
38
+ </div>
39
+ <div class="card-block">
40
+ <c8y-dynamic-component componentId="counter.component"></c8y-dynamic-component>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
@@ -0,0 +1,13 @@
1
+ import { Component } from '@angular/core';
2
+ import { CoreModule } from '@c8y/ngx-components';
3
+
4
+ /**
5
+ * This is the component that hosts the Service demo view.
6
+ */
7
+ @Component({
8
+ selector: 'tut-basic-component-hook-view',
9
+ templateUrl: './basic-view.component.html',
10
+ standalone: true,
11
+ imports: [CoreModule]
12
+ })
13
+ export class BasicViewComponent {}
@@ -0,0 +1,15 @@
1
+ <p>
2
+ Hello there! I am a simple component added from a plugin by
3
+ <code>hookComponent</code>
4
+ . I use a shared counter service that has been provided in another plugin and injected by
5
+ <code>hookService</code>
6
+ .
7
+ </p>
8
+ <button
9
+ class="btn btn-default m-t-16"
10
+ type="button"
11
+ (click)="counter.count()"
12
+ >
13
+ Click to increment counter
14
+ <span class="badge badge-system">{{ counter.counter }}</span>
15
+ </button>
@@ -0,0 +1,21 @@
1
+ import { Component } from '@angular/core';
2
+ import { ServiceRegistry } from '@c8y/ngx-components';
3
+ import { ICounterService } from '../counter/counter.model';
4
+
5
+ @Component({
6
+ selector: 'tut-counter-component',
7
+ templateUrl: './counter.component.html',
8
+ standalone: true
9
+ })
10
+ export class CounterComponent {
11
+ counter: ICounterService;
12
+
13
+ constructor(registry: ServiceRegistry) {
14
+ /**
15
+ * To retrieve an instance of a service injected by `hookService` you can use ServiceRegistry.get(key) method.
16
+ * It will return all injected service instances in a type-safe manner if there is a typed extension key declared.
17
+ * For an example of such declaration check the declarations in `counter/counter.model.ts`.
18
+ */
19
+ this.counter = registry.get('counter').at(0);
20
+ }
21
+ }
@@ -0,0 +1,3 @@
1
+ export * from './basic-view.component';
2
+ export * from './counter.component';
3
+ export * from './service-hook.module';
@@ -0,0 +1,29 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { NavigatorNode, hookComponent, hookNavigator, hookRoute } from '@c8y/ngx-components';
3
+
4
+ @NgModule({
5
+ providers: [
6
+ /* Hook the Service hook demo view */
7
+ hookRoute({
8
+ path: 'hooks/service',
9
+ loadComponent: () => import('./basic-view.component').then(m => m.BasicViewComponent)
10
+ }),
11
+ hookNavigator(
12
+ new NavigatorNode({
13
+ priority: 40,
14
+ path: 'hooks/service',
15
+ icon: 'gears',
16
+ label: 'Service',
17
+ parent: 'Hooks'
18
+ })
19
+ ),
20
+ /* Hook a client component for the service provided via `hookService` */
21
+ hookComponent({
22
+ id: 'counter.component',
23
+ label: 'Counter component',
24
+ description: 'This component can count',
25
+ loadComponent: () => import('./counter.component').then(m => m.CounterComponent)
26
+ })
27
+ ]
28
+ })
29
+ export class ServiceHookModule {}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Declare the contract of the service that will be injected via `hookService` in an interface.
3
+ * This interface will be used also to bind a type to the key used for providing and retrieving the service.
4
+ * This interface should be declared in a module that is shared between modules that use the service and those that implement and inject it.
5
+ */
6
+ export interface ICounterService {
7
+ /**
8
+ * Current counter state.
9
+ */
10
+ counter: number;
11
+ /**
12
+ * Increment counter value.
13
+ */
14
+ count: () => void;
15
+ }
16
+
17
+ declare global {
18
+ /**
19
+ * The `CumulocityServiceRegistry` namespaces is declared in `@c8y/ngx-components` as part of the global scope.
20
+ * This allows you to augment the service registry by adding your typed extension keys.
21
+ */
22
+ // eslint-disable-next-line @typescript-eslint/no-namespace
23
+ namespace CumulocityServiceRegistry {
24
+ interface ExtensionKeys {
25
+ /**
26
+ * The extension key used for injecting and retrieving hooked services.
27
+ * To provide a service with a key provide the service using `hookService`:
28
+ *
29
+ * ```typescript
30
+ * @NgModule({
31
+ * providers: [hookService('counter', CounterService)]
32
+ * })
33
+ * ```
34
+ *
35
+ * In your client code you can use `ServiceRegistry` to retrieve an instance of the injected service:
36
+ * ```typescript
37
+ * ServiceRegistry.get(key)
38
+ * ```
39
+ */
40
+ counter: ICounterService;
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,13 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { hookService } from '@c8y/ngx-components';
3
+ import { CounterService } from './counter.service';
4
+
5
+ @NgModule({
6
+ /**
7
+ * To provide a service using `hookService`, you pass a key that clients will use to retrieve the service instance.
8
+ * By extending the `ExtensionKeys` interface in the `CumulocityServiceRegistry` namespace, you declare the key for your service.
9
+ * `hookService` then enforces type safety, ensuring only services that implement the corresponding interface can be provided for that key.
10
+ */
11
+ providers: [hookService('counter', CounterService)]
12
+ })
13
+ export class CounterHookModule {}
@@ -0,0 +1,10 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { ICounterService } from './counter.model';
3
+
4
+ @Injectable({ providedIn: 'root' })
5
+ export class CounterService implements ICounterService {
6
+ counter = 0;
7
+ count() {
8
+ this.counter++;
9
+ }
10
+ }
@@ -0,0 +1,13 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { ServiceHookModule } from './client/service-hook.module';
3
+ import { CounterHookModule } from './counter/counter.module';
4
+
5
+ @NgModule({
6
+ imports: [ServiceHookModule, CounterHookModule]
7
+ })
8
+ /**
9
+ * `codex-tutorial-example` component supports a single module only, hence the module providing the service (CounterHookModule)
10
+ * and the one consuming the service (ServiceHookModule) need to be combined in a single module.
11
+ * In the general case, both modules above can be added as remotes separately.
12
+ */
13
+ export class ServiceHookCodexSampleModule {}
@@ -19,4 +19,14 @@
19
19
  [properties]="specifiedPackageVersionProperties"
20
20
  ></c8y-properties-list>
21
21
  <!-- /important -->
22
+
23
+ <!-- important -->
24
+ <c8y-properties-list
25
+ [title]="'Properties with no parse enabled'"
26
+ [data]="[]"
27
+ [emptyLabel]="'--'"
28
+ [noParse]="true"
29
+ [properties]="customPropertiesNoParse"
30
+ ></c8y-properties-list>
31
+ <!-- /important -->
22
32
  </div>
@@ -94,4 +94,25 @@ export class PropertiesListExampleComponent {
94
94
  key: 'custom'
95
95
  }
96
96
  ];
97
+
98
+ readonly customPropertiesNoParse: PropertiesListItem[] = [
99
+ {
100
+ label: 'String property',
101
+ key: 'string',
102
+ value: this.customData.string,
103
+ type: 'string'
104
+ },
105
+ {
106
+ label: 'Number property',
107
+ key: 'number',
108
+ value: this.customData.number,
109
+ type: 'string'
110
+ },
111
+ {
112
+ label: 'Array property',
113
+ key: 'array',
114
+ value: this.customData.array,
115
+ type: 'array'
116
+ }
117
+ ];
97
118
  }