@c8y/tutorial 1022.35.1 → 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.
- package/cumulocity.config.ts +28 -0
- package/package.json +7 -7
- package/src/editor/editor-css-sample/editor-css-sample.component.html +31 -0
- package/src/editor/editor-css-sample/editor-css-sample.component.ts +31 -0
- package/src/editor/editor-css-sample/index.ts +14 -0
- package/src/editor/editor-json-sample/editor-json-sample.component.html +23 -0
- package/src/editor/editor-json-sample/editor-json-sample.component.ts +63 -0
- package/src/editor/editor-json-sample/index.ts +14 -0
- package/src/grids/server-grid-example/last-updated-data-grid-column/last-updated.data-grid-column.ts +2 -1
- package/src/selector/asset-selector-example/miller-columns-options/asset-selector-miller-example.component.ts +2 -1
- package/src/selector/asset-selector-example/tree-options/asset-selector-tree-example.component.ts +2 -1
- package/src/selector/properties-selector-computed-properties/alarm-count-config.component.ts +76 -0
- package/src/selector/properties-selector-computed-properties/alarm-count-last-week-computed-property.ts +56 -0
- package/src/selector/properties-selector-computed-properties/index.ts +4 -0
- package/src/selector/properties-selector-drawer-example/properties-selector-drawer.component.ts +1 -0
- package/src/translations/dynamic-form-translation/dynamic-form-translation.component.ts +2 -1
- package/src/translations/text-translation/gettext-translation/text-translation-gettext.component.ts +2 -1
- package/src/translations/text-translation/service-translation/text-translation-by-service.component.ts +2 -1
- package/tsconfig.app.json +1 -0
package/cumulocity.config.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
7
|
-
"@c8y/ngx-components": "1022.
|
|
8
|
-
"@c8y/client": "1022.
|
|
9
|
-
"@c8y/bootstrap": "1022.
|
|
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.
|
|
18
|
-
"@c8y/devkit": "1022.
|
|
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
|
+
];
|
package/src/grids/server-grid-example/last-updated-data-grid-column/last-updated.data-grid-column.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FormGroup } from '@angular/forms';
|
|
2
|
-
import {
|
|
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
|
/**
|
|
@@ -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
|
+
}
|
|
@@ -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 {
|
|
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',
|
package/src/translations/text-translation/gettext-translation/text-translation-gettext.component.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
-
import {
|
|
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 {
|
|
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({
|