@c8y/tutorial 1022.34.0 → 1022.44.3

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 (19) hide show
  1. package/cumulocity.config.ts +28 -0
  2. package/package.json +7 -7
  3. package/src/editor/editor-css-sample/editor-css-sample.component.html +31 -0
  4. package/src/editor/editor-css-sample/editor-css-sample.component.ts +31 -0
  5. package/src/editor/editor-css-sample/index.ts +14 -0
  6. package/src/editor/editor-json-sample/editor-json-sample.component.html +23 -0
  7. package/src/editor/editor-json-sample/editor-json-sample.component.ts +63 -0
  8. package/src/editor/editor-json-sample/index.ts +14 -0
  9. package/src/grids/server-grid-example/last-updated-data-grid-column/last-updated.data-grid-column.ts +2 -1
  10. package/src/selector/asset-selector-example/miller-columns-options/asset-selector-miller-example.component.ts +2 -1
  11. package/src/selector/asset-selector-example/tree-options/asset-selector-tree-example.component.ts +2 -1
  12. package/src/selector/properties-selector-computed-properties/alarm-count-config.component.ts +76 -0
  13. package/src/selector/properties-selector-computed-properties/alarm-count-last-week-computed-property.ts +56 -0
  14. package/src/selector/properties-selector-computed-properties/index.ts +4 -0
  15. package/src/selector/properties-selector-drawer-example/properties-selector-drawer.component.ts +1 -0
  16. package/src/translations/dynamic-form-translation/dynamic-form-translation.component.ts +2 -1
  17. package/src/translations/text-translation/gettext-translation/text-translation-gettext.component.ts +2 -1
  18. package/src/translations/text-translation/service-translation/text-translation-by-service.component.ts +2 -1
  19. package/tsconfig.app.json +1 -0
@@ -724,6 +724,13 @@ export default {
724
724
  description: 'An introduction to properties selector example- drawer usage.',
725
725
  scope: 'self'
726
726
  },
727
+ {
728
+ name: 'Properties selector- computed properties',
729
+ module: 'computedAssetPropertiesProvidersExample',
730
+ path: './src/selector/properties-selector-computed-properties/index.ts',
731
+ description: 'Hookable computed property example.',
732
+ scope: 'self'
733
+ },
727
734
  {
728
735
  name: 'Introduction to asset selector device child',
729
736
  module: 'AssetSingleSelectModule',
@@ -877,6 +884,27 @@ export default {
877
884
  path: './src/hooks/widget/widget.providers.ts',
878
885
  description: 'This is an example for the bottom drawer service.',
879
886
  scope: 'self'
887
+ },
888
+ {
889
+ name: 'Computed asset properties',
890
+ module: 'computedAssetPropertiesProviders',
891
+ path: '@c8y/ngx-components/computed-asset-properties',
892
+ description: 'Set of predefined computed asset properties.',
893
+ scope: 'self'
894
+ },
895
+ {
896
+ name: 'Editor JSON sample',
897
+ module: 'editorJSONSampleProviders',
898
+ path: './src/editor/editor-json-sample/index.ts',
899
+ description: 'This is an example for editing JSON via the editor component.',
900
+ scope: 'self'
901
+ },
902
+ {
903
+ name: 'Editor CSS sample',
904
+ module: 'editorCSSSampleProviders',
905
+ path: './src/editor/editor-css-sample/index.ts',
906
+ description: 'This is an example for editing CSS via the editor component.',
907
+ scope: 'self'
880
908
  }
881
909
  ]
882
910
  },
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@c8y/tutorial",
3
- "version": "1022.34.0",
3
+ "version": "1022.44.3",
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.34.0",
7
- "@c8y/ngx-components": "1022.34.0",
8
- "@c8y/client": "1022.34.0",
9
- "@c8y/bootstrap": "1022.34.0",
6
+ "@c8y/style": "1022.44.3",
7
+ "@c8y/ngx-components": "1022.44.3",
8
+ "@c8y/client": "1022.44.3",
9
+ "@c8y/bootstrap": "1022.44.3",
10
10
  "@angular/cdk": "^19.2.19",
11
11
  "monaco-editor": "~0.52.2",
12
12
  "ngx-bootstrap": "19.0.2",
@@ -14,8 +14,8 @@
14
14
  "rxjs": "7.8.1"
15
15
  },
16
16
  "devDependencies": {
17
- "@c8y/options": "1022.34.0",
18
- "@c8y/devkit": "1022.34.0"
17
+ "@c8y/options": "1022.44.3",
18
+ "@c8y/devkit": "1022.44.3"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "@angular/common": ">=19 <20"
@@ -0,0 +1,31 @@
1
+ <form
2
+ class="d-contents"
3
+ [formGroup]="form"
4
+ >
5
+ <c8y-form-group class="d-col fit-h">
6
+ <label
7
+ for="cssEditor"
8
+ translate
9
+ >
10
+ CSS Editor (with validation)
11
+ </label>
12
+ <c8y-editor
13
+ class="flex-grow"
14
+ name="cssEditor"
15
+ [editorOptions]="{ language: 'css' }"
16
+ [formControlName]="'cssEditor'"
17
+ monacoEditorMarkerValidator
18
+ ></c8y-editor>
19
+ <c8y-messages [helpMessage]="''"></c8y-messages>
20
+ </c8y-form-group>
21
+
22
+ @if (form.valid) {
23
+ <p class="d-flex a-i-center">
24
+ <i class="dlt-c8y-icon-ok text-success icon-20 m-r-4"></i> Form is valid.
25
+ </p>
26
+ } @else {
27
+ <p class="d-flex a-i-center">
28
+ <i class="dlt-c8y-icon-exclamation-circle text-danger icon-20 m-r-4"></i> Form is invalid.
29
+ </p>
30
+ }
31
+ </form>
@@ -0,0 +1,31 @@
1
+ import { Component, ViewChild } from '@angular/core';
2
+ import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
3
+ import { FormGroupComponent, MessagesComponent } from '@c8y/ngx-components';
4
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
5
+
6
+ @Component({
7
+ selector: 'c8y-editor-css-sample',
8
+ templateUrl: './editor-css-sample.component.html',
9
+ standalone: true,
10
+ imports: [
11
+ EditorComponent,
12
+ MessagesComponent,
13
+ FormGroupComponent,
14
+ ReactiveFormsModule,
15
+ MonacoEditorMarkerValidatorDirective
16
+ ],
17
+ host: {
18
+ class: 'd-col fit-w',
19
+ style: 'height: 400px'
20
+ }
21
+ })
22
+ export class EditorCSSSampleComponent {
23
+ form: FormGroup;
24
+ @ViewChild(EditorComponent) editorComponent!: EditorComponent;
25
+
26
+ constructor() {
27
+ this.form = new FormGroup({
28
+ cssEditor: new FormControl('.test { display: none; }')
29
+ });
30
+ }
31
+ }
@@ -0,0 +1,14 @@
1
+ import { hookNavigator, hookRoute } from '@c8y/ngx-components';
2
+
3
+ export const editorCSSSampleProviders = [
4
+ hookRoute({
5
+ path: 'editor-css-sample',
6
+ loadComponent: () =>
7
+ import('./editor-css-sample.component').then(c => c.EditorCSSSampleComponent)
8
+ }),
9
+ hookNavigator({
10
+ label: 'Editor CSS sample',
11
+ icon: 'code',
12
+ path: 'editor-css-sample'
13
+ })
14
+ ];
@@ -0,0 +1,23 @@
1
+ <form [formGroup]="form" class="d-contents">
2
+ <c8y-form-group class="d-col fit-h">
3
+ <label for="jsonEditor" translate>JSON Editor (with JSON schema validation)</label>
4
+ <c8y-editor
5
+ class="flex-grow"
6
+ name="jsonEditor"
7
+ [formControlName]="'jsonEditor'"
8
+ (editorInit)="assignSchema()"
9
+ monacoEditorMarkerValidator
10
+ ></c8y-editor>
11
+ <c8y-messages [helpMessage]="''"></c8y-messages>
12
+ </c8y-form-group>
13
+
14
+ @if (form.valid) {
15
+ <p class="d-flex a-i-center">
16
+ <i class="dlt-c8y-icon-ok text-success icon-20 m-r-4"></i> Form is valid.
17
+ </p>
18
+ } @else {
19
+ <p class="d-flex a-i-center">
20
+ <i class="dlt-c8y-icon-exclamation-circle text-danger icon-20 m-r-4"></i> Form is invalid.
21
+ </p>
22
+ }
23
+ </form>
@@ -0,0 +1,63 @@
1
+ import { Component, ViewChild } from '@angular/core';
2
+ import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
3
+ import { FormGroupComponent, MessagesComponent } from '@c8y/ngx-components';
4
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
5
+
6
+ @Component({
7
+ selector: 'c8y-editor-json-sample',
8
+ templateUrl: './editor-json-sample.component.html',
9
+ standalone: true,
10
+ imports: [
11
+ EditorComponent,
12
+ MessagesComponent,
13
+ FormGroupComponent,
14
+ ReactiveFormsModule,
15
+ MonacoEditorMarkerValidatorDirective
16
+ ],
17
+ host: {
18
+ class: 'd-col fit-w',
19
+ style: 'height: 400px'
20
+ }
21
+ })
22
+ export class EditorJsonSampleComponent {
23
+ form: FormGroup;
24
+ @ViewChild(EditorComponent) editorComponent!: EditorComponent;
25
+
26
+ constructor() {
27
+ this.form = new FormGroup({
28
+ jsonEditor: new FormControl(
29
+ JSON.stringify({ name: 'John Doe', age: 30, email: 'john.doe@example.com' }, undefined, 2)
30
+ )
31
+ });
32
+ }
33
+
34
+ assignSchema() {
35
+ const schema = {
36
+ $schema: 'http://json-schema.org/draft-07/schema#',
37
+ type: 'object',
38
+ properties: {
39
+ name: {
40
+ type: 'string',
41
+ description: 'Name of the person'
42
+ },
43
+ age: {
44
+ type: 'integer',
45
+ description: 'Age of the person',
46
+ minimum: 0
47
+ },
48
+ email: {
49
+ type: 'string',
50
+ format: 'email',
51
+ description: 'Email address of the person'
52
+ }
53
+ },
54
+ required: ['name', 'age']
55
+ } as const;
56
+ this.editorComponent.monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
57
+ validate: true,
58
+ schemas: [{ schema, fileMatch: ['*'], uri: 'editor-json-sample' }],
59
+ enableSchemaRequest: false,
60
+ allowComments: false
61
+ });
62
+ }
63
+ }
@@ -0,0 +1,14 @@
1
+ import { hookNavigator, hookRoute } from '@c8y/ngx-components';
2
+
3
+ export const editorJSONSampleProviders = [
4
+ hookRoute({
5
+ path: 'editor-json-sample',
6
+ loadComponent: () =>
7
+ import('./editor-json-sample.component').then(c => c.EditorJsonSampleComponent)
8
+ }),
9
+ hookNavigator({
10
+ label: 'Editor JSON sample',
11
+ icon: 'code',
12
+ path: 'editor-json-sample'
13
+ })
14
+ ];
@@ -1,5 +1,6 @@
1
1
  import { FormGroup } from '@angular/forms';
2
- import { BaseColumn, ColumnConfig, gettext } from '@c8y/ngx-components';
2
+ import { gettext } from '@c8y/ngx-components/gettext';
3
+ import { BaseColumn, ColumnConfig } from '@c8y/ngx-components';
3
4
  import { LastUpdatedCellRendererComponent } from './last-updated.cell-renderer.component';
4
5
 
5
6
  /**
@@ -66,7 +66,8 @@ export class AssetSelectorMillerExampleComponent {
66
66
  showFilter: false,
67
67
  showUnassignedDevices: false,
68
68
  singleColumn: false,
69
- label: 'Asset selection'
69
+ label: 'Asset selection',
70
+ showSelected: true
70
71
  };
71
72
 
72
73
  reloadComponent() {
@@ -64,7 +64,8 @@ export class AssetSelectorTreeExampleComponent {
64
64
  search: false,
65
65
  showChildDevices: false,
66
66
  showUnassignedDevices: false,
67
- label: 'Asset selection'
67
+ label: 'Asset selection',
68
+ showSelected: true
68
69
  };
69
70
 
70
71
  reloadComponent() {
@@ -0,0 +1,76 @@
1
+ import { Component, inject, Input, OnInit } from '@angular/core';
2
+ import {
3
+ ControlContainer,
4
+ FormBuilder,
5
+ NgForm,
6
+ ReactiveFormsModule,
7
+ Validators
8
+ } from '@angular/forms';
9
+ import { C8yTranslatePipe, CommonModule, CoreModule } from '@c8y/ngx-components';
10
+ import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector';
11
+ import { Observable } from 'rxjs';
12
+ import { AlarmCountLastWeekConfig } from './alarm-count-last-week-computed-property';
13
+
14
+ @Component({
15
+ selector: 'c8y-alarm-count-config',
16
+ template: `
17
+ <form class="row d-flex-md" [formGroup]="formGroup">
18
+ <div class="col-md-6">
19
+ <c8y-form-group class="m-b-16">
20
+ <label [title]="'Alarm type' | translate" translate> Alarm type </label>
21
+ <input
22
+ class="form-control"
23
+ placeholder="{{ 'e.g.' | translate }} c8y_UnavailabilityAlarm"
24
+ name="type"
25
+ type="string"
26
+ formControlName="type"
27
+ />
28
+ <c8y-messages
29
+ [show]="formGroup.controls?.type?.touched && formGroup?.controls?.type?.errors"
30
+ ></c8y-messages>
31
+ </c8y-form-group>
32
+ </div>
33
+ </form>
34
+ `,
35
+ imports: [
36
+ CoreModule,
37
+ DatapointSelectorModule,
38
+ CommonModule,
39
+ C8yTranslatePipe,
40
+ ReactiveFormsModule
41
+ ],
42
+ viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
43
+ })
44
+ export class ComputedPropertyAlarmCountConfigComponent implements OnInit {
45
+ @Input() config?: AlarmCountLastWeekConfig;
46
+ formGroup: ReturnType<ComputedPropertyAlarmCountConfigComponent['createForm']>;
47
+
48
+ private formBuilder = inject(FormBuilder);
49
+ private form = inject(NgForm);
50
+
51
+ ngOnInit() {
52
+ this.initForm();
53
+ }
54
+
55
+ onBeforeSave(
56
+ config?: AlarmCountLastWeekConfig
57
+ ): boolean | Promise<boolean> | Observable<boolean> {
58
+ if (this.formGroup.valid) {
59
+ Object.assign(config, this.formGroup.value);
60
+ return true;
61
+ }
62
+ return false;
63
+ }
64
+
65
+ private initForm(): void {
66
+ this.formGroup = this.createForm();
67
+ this.form.form.addControl('config', this.formGroup);
68
+ this.formGroup.patchValue(this.config);
69
+ }
70
+
71
+ private createForm() {
72
+ return this.formBuilder.group({
73
+ type: ['', [Validators.required]]
74
+ });
75
+ }
76
+ }
@@ -0,0 +1,56 @@
1
+ import { inject, Injector } from '@angular/core';
2
+ import { AlarmQueryFilter, AlarmService, IManagedObject } from '@c8y/client';
3
+ import { ComputedPropertyDefinition } from '@c8y/ngx-components/asset-properties';
4
+
5
+ export type AlarmCountLastWeekConfig = {
6
+ type: string;
7
+ };
8
+
9
+ export const alarmCountLastWeek: ComputedPropertyDefinition<
10
+ ['device', 'group', 'asset'],
11
+ AlarmCountLastWeekConfig
12
+ > = {
13
+ name: 'alarmCountLastWeek',
14
+ contextType: ['device', 'group', 'asset'],
15
+ prop: {
16
+ c8y_JsonSchema: {
17
+ properties: {
18
+ alarmCountLastWeek: {
19
+ label: 'Alarm count last week',
20
+ type: 'number'
21
+ }
22
+ }
23
+ },
24
+ name: 'alarmCountLastWeek',
25
+ label: 'Alarm count last week',
26
+ type: 'number',
27
+ config: { type: '' } as AlarmCountLastWeekConfig,
28
+ computed: true,
29
+ isEditable: false,
30
+ isStandardProperty: true
31
+ },
32
+ loadConfigComponent: () =>
33
+ import('./alarm-count-config.component').then(m => m.ComputedPropertyAlarmCountConfigComponent),
34
+ value: ({ config, context }) => alarmCountValue(config, context)
35
+ };
36
+
37
+ async function alarmCountValue(
38
+ config: AlarmCountLastWeekConfig,
39
+ asset: IManagedObject
40
+ ): Promise<number> {
41
+ const injector = inject(Injector);
42
+ const alarmService = injector.get(AlarmService);
43
+ const sevenDaysAgo = new Date();
44
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 8);
45
+
46
+ const filters: AlarmQueryFilter = {
47
+ source: asset.id,
48
+ dateFrom: sevenDaysAgo.toISOString(),
49
+ type: config.type,
50
+ pageSize: 1,
51
+ withTotalElements: true
52
+ };
53
+
54
+ const resp = await alarmService.list(filters);
55
+ return resp?.paging?.totalElements || 0;
56
+ }
@@ -0,0 +1,4 @@
1
+ import { hookComputedProperty } from '@c8y/ngx-components/asset-properties';
2
+ import { alarmCountLastWeek } from './alarm-count-last-week-computed-property';
3
+
4
+ export const computedAssetPropertiesProvidersExample = [hookComputedProperty([alarmCountLastWeek])];
@@ -22,6 +22,7 @@ import { JsonPipe } from '@angular/common';
22
22
  <div class="card">
23
23
  <div class="card-inner-scroll d-flex d-col bg-component" style="height: 490px">
24
24
  <c8y-asset-selector
25
+ class="bg-inherit"
25
26
  [(ngModel)]="model"
26
27
  [config]="{
27
28
  groupsSelectable: true,
@@ -1,7 +1,8 @@
1
1
  import { Component } from '@angular/core';
2
2
  import { FormGroup } from '@angular/forms';
3
3
  import { FormlyFieldConfig } from '@ngx-formly/core';
4
- import { CoreModule, DynamicFormsModule, gettext } from '@c8y/ngx-components';
4
+ import { gettext } from '@c8y/ngx-components/gettext';
5
+ import { CoreModule, DynamicFormsModule } from '@c8y/ngx-components';
5
6
 
6
7
  @Component({
7
8
  selector: 'dynamic-form-translation',
@@ -1,5 +1,6 @@
1
1
  import { Component } from '@angular/core';
2
- import { CoreModule, gettext } from '@c8y/ngx-components';
2
+ import { gettext } from '@c8y/ngx-components/gettext';
3
+ import { CoreModule } from '@c8y/ngx-components';
3
4
 
4
5
  @Component({
5
6
  selector: 'text-translation-gettext',
@@ -1,5 +1,6 @@
1
1
  import { Component } from '@angular/core';
2
- import { CoreModule, gettext } from '@c8y/ngx-components';
2
+ import { gettext } from '@c8y/ngx-components/gettext';
3
+ import { CoreModule } from '@c8y/ngx-components';
3
4
  import { TranslateService } from '@ngx-translate/core';
4
5
 
5
6
  @Component({
package/tsconfig.app.json CHANGED
@@ -17,5 +17,6 @@
17
17
  ],
18
18
  "exclude": [
19
19
  "../ngx-components/dist",
20
+ "../ngx-components/**/*.spec.ts",
20
21
  ]
21
22
  }