@c8y/tutorial 1023.70.0 → 1023.75.1

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.
@@ -647,6 +647,13 @@ export default {
647
647
  description: 'An example for extendable input list.',
648
648
  scope: 'self'
649
649
  },
650
+ {
651
+ name: 'Example of inline editable input',
652
+ module: 'InputGroupEditableExampleModule',
653
+ path: './src/input-group/input-group-editable-example.module.ts',
654
+ description: 'An example for the input-group-editable pattern.',
655
+ scope: 'self'
656
+ },
650
657
  {
651
658
  name: 'Example of time picker',
652
659
  module: 'TimePickerExampleModule',
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@c8y/tutorial",
3
- "version": "1023.70.0",
3
+ "version": "1023.75.1",
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": "1023.70.0",
7
- "@c8y/ngx-components": "1023.70.0",
8
- "@c8y/client": "1023.70.0",
9
- "@c8y/bootstrap": "1023.70.0",
10
6
  "@angular/cdk": "^20.2.14",
7
+ "@c8y/bootstrap": "1023.75.1",
8
+ "@c8y/client": "1023.75.1",
9
+ "@c8y/ngx-components": "1023.75.1",
10
+ "@c8y/style": "1023.75.1",
11
+ "leaflet": "1.9.4",
11
12
  "monaco-editor": "~0.53.0",
12
13
  "ngx-bootstrap": "20.0.2",
13
- "leaflet": "1.9.4",
14
14
  "rxjs": "7.8.2"
15
15
  },
16
16
  "devDependencies": {
17
- "@c8y/options": "1023.70.0",
18
- "@c8y/devkit": "1023.70.0"
17
+ "@c8y/devkit": "1023.75.1",
18
+ "@c8y/options": "1023.75.1"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "@angular/common": ">=20 <21"
@@ -0,0 +1,263 @@
1
+ import { Component } from '@angular/core';
2
+ import {
3
+ AbstractControl,
4
+ AsyncValidatorFn,
5
+ FormControl,
6
+ ValidationErrors,
7
+ ValidatorFn,
8
+ Validators
9
+ } from '@angular/forms';
10
+ import { CoreModule, InputGroupEditableComponent } from '@c8y/ngx-components';
11
+ import { Observable, map, timer } from 'rxjs';
12
+
13
+ @Component({
14
+ selector: 'c8y-input-group-editable-example',
15
+ template: `
16
+ <c8y-title>Inline editable input</c8y-title>
17
+ <div class="container-fluid p-24">
18
+ <!-- SIZES -->
19
+ <h4 class="text-medium m-b-24">Sizes</h4>
20
+ <div class="row m-b-24">
21
+ <div class="col-sm-4">
22
+ <p class="text-label-small">Default</p>
23
+ <c8y-input-group-editable
24
+ ariaLabel="Default size"
25
+ [(ngModel)]="sizeDefault"
26
+ ></c8y-input-group-editable>
27
+ </div>
28
+ <div class="col-sm-4">
29
+ <p class="text-label-small">Small (size="sm")</p>
30
+ <c8y-input-group-editable
31
+ size="sm"
32
+ ariaLabel="Small size"
33
+ [(ngModel)]="sizeSm"
34
+ ></c8y-input-group-editable>
35
+ </div>
36
+ <div class="col-sm-4">
37
+ <p class="text-label-small">Large (size="lg")</p>
38
+ <c8y-input-group-editable
39
+ size="lg"
40
+ ariaLabel="Large size"
41
+ [(ngModel)]="sizeLg"
42
+ ></c8y-input-group-editable>
43
+ </div>
44
+ </div>
45
+
46
+ <hr />
47
+
48
+ <!-- BINDING PATTERNS -->
49
+ <h4 class="text-medium m-b-24">Binding patterns</h4>
50
+ <div class="row m-b-24">
51
+ <div class="col-sm-4">
52
+ <p class="text-label-small">Two-way [(ngModel)]</p>
53
+ <c8y-input-group-editable
54
+ ariaLabel="Two-way ngModel"
55
+ [(ngModel)]="bindingTwoWay"
56
+ ></c8y-input-group-editable>
57
+ <small class="text-muted">Value: {{ bindingTwoWay }}</small>
58
+ </div>
59
+ <div class="col-sm-4">
60
+ <p class="text-label-small">[ngModel] and (ngModelChange)</p>
61
+ <c8y-input-group-editable
62
+ ariaLabel="One-way ngModel with ngModelChange"
63
+ [ngModel]="bindingOneWay"
64
+ (ngModelChange)="bindingOneWay = $event"
65
+ ></c8y-input-group-editable>
66
+ <small class="text-muted">Value: {{ bindingOneWay }}</small>
67
+ </div>
68
+ <div class="col-sm-4">
69
+ <p class="text-label-small">[formControl]</p>
70
+ <c8y-input-group-editable
71
+ ariaLabel="Form control binding"
72
+ [formControl]="bindingFormControl"
73
+ ></c8y-input-group-editable>
74
+ <small class="text-muted">Value: {{ bindingFormControl.value }}</small>
75
+ <p class="text-muted m-t-4">
76
+ <small
77
+ >Use <code>formControlName</code> the same way inside a <code>FormGroup</code>.</small
78
+ >
79
+ </p>
80
+ </div>
81
+ </div>
82
+
83
+ <hr />
84
+
85
+ <!-- OUTPUTS -->
86
+ <h4 class="text-medium m-b-24">Outputs — (save) and (cancel)</h4>
87
+ <div class="row m-b-24">
88
+ <div class="col-sm-6">
89
+ <p class="text-label-small">Tracking last action alongside [(ngModel)]</p>
90
+ <c8y-input-group-editable
91
+ ariaLabel="Field with save and cancel outputs"
92
+ [(ngModel)]="outputsModel"
93
+ (save)="onSave($event)"
94
+ (cancel)="onCancel()"
95
+ ></c8y-input-group-editable>
96
+ <div class="m-t-8">
97
+ <small class="d-block text-muted"
98
+ >Last action: <strong>{{ lastAction || '—' }}</strong></small
99
+ >
100
+ <small class="d-block text-muted"
101
+ >Last saved value: <strong>{{ lastSavedValue || '—' }}</strong></small
102
+ >
103
+ </div>
104
+ </div>
105
+ </div>
106
+
107
+ <hr />
108
+
109
+ <!-- PLACEHOLDER AND NAME -->
110
+ <h4 class="text-medium m-b-24">Placeholder and name</h4>
111
+ <div class="row m-b-24">
112
+ <div class="col-sm-4">
113
+ <p class="text-label-small">Empty field with placeholder</p>
114
+ <c8y-input-group-editable
115
+ placeholder="e.g. My device"
116
+ name="device-name"
117
+ ariaLabel="Device name"
118
+ [(ngModel)]="placeholderModel"
119
+ ></c8y-input-group-editable>
120
+ </div>
121
+ </div>
122
+
123
+ <hr />
124
+
125
+ <!-- SYNC VALIDATION -->
126
+ <h4 class="text-medium m-b-24">Validation — synchronous</h4>
127
+ <div class="row m-b-24">
128
+ <div class="col-sm-4">
129
+ <p class="text-label-small">Template-driven (required, minlength)</p>
130
+ <c8y-input-group-editable
131
+ required
132
+ minlength="3"
133
+ ariaLabel="Template-driven validation"
134
+ [(ngModel)]="validTplModel"
135
+ ></c8y-input-group-editable>
136
+ </div>
137
+ <div class="col-sm-4">
138
+ <p class="text-label-small">[validators] input — no spaces</p>
139
+ <c8y-input-group-editable
140
+ ariaLabel="Validators input"
141
+ [(ngModel)]="validatorsModel"
142
+ [validators]="noSpacesValidator"
143
+ >
144
+ <c8y-message
145
+ name="noSpaces"
146
+ [text]="'Spaces are not allowed.' | translate"
147
+ ></c8y-message>
148
+ </c8y-input-group-editable>
149
+ </div>
150
+ <div class="col-sm-4">
151
+ <p class="text-label-small">[formControl] and &lt;c8y-message&gt;</p>
152
+ <c8y-input-group-editable
153
+ ariaLabel="FormControl with custom messages"
154
+ [formControl]="validFormControl"
155
+ >
156
+ <c8y-message
157
+ name="required"
158
+ [text]="'This field is required.' | translate"
159
+ ></c8y-message>
160
+ <c8y-message
161
+ name="minlength"
162
+ [text]="'Minimum 3 characters required.' | translate"
163
+ ></c8y-message>
164
+ </c8y-input-group-editable>
165
+ </div>
166
+ </div>
167
+
168
+ <hr />
169
+
170
+ <!-- ASYNC VALIDATION -->
171
+ <h4 class="text-medium m-b-24">Validation — asynchronous</h4>
172
+ <div class="row m-b-24">
173
+ <div class="col-sm-4">
174
+ <p class="text-label-small">[asyncValidators] — try typing "taken"</p>
175
+ <c8y-input-group-editable
176
+ ariaLabel="Async uniqueness validation"
177
+ [formControl]="asyncFormControl"
178
+ [asyncValidators]="uniquenessValidator"
179
+ >
180
+ <c8y-message
181
+ name="notUnique"
182
+ [text]="'This name is already taken.' | translate"
183
+ ></c8y-message>
184
+ </c8y-input-group-editable>
185
+ </div>
186
+ </div>
187
+
188
+ <hr />
189
+
190
+ <!-- DISABLED STATE -->
191
+ <h4 class="text-medium m-b-24">Disabled state</h4>
192
+ <div class="row m-b-24">
193
+ <div class="col-sm-4">
194
+ <p class="text-label-small">disabled attribute</p>
195
+ <c8y-input-group-editable
196
+ disabled
197
+ ariaLabel="Disabled field"
198
+ [(ngModel)]="disabledModel"
199
+ ></c8y-input-group-editable>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ `,
204
+ standalone: true,
205
+ imports: [CoreModule, InputGroupEditableComponent]
206
+ })
207
+ export class InputGroupEditableExampleComponent {
208
+ // Sizes
209
+ sizeDefault = 'Default size';
210
+ sizeSm = 'Small size';
211
+ sizeLg = 'Large size';
212
+
213
+ // Binding patterns
214
+ bindingTwoWay = 'Two-way binding';
215
+ bindingOneWay = 'One-way binding';
216
+ readonly bindingFormControl = new FormControl('Form control value', { nonNullable: true });
217
+
218
+ // Outputs
219
+ outputsModel = 'Edit and save or cancel';
220
+ lastAction = '';
221
+ lastSavedValue = '';
222
+
223
+ // Placeholder and name
224
+ placeholderModel = '';
225
+
226
+ // Sync validation — template-driven (required + minlength attributes)
227
+ validTplModel = 'min 3 chars required';
228
+
229
+ // Sync validation — [validators] input
230
+ validatorsModel = 'NoSpacesAllowed';
231
+
232
+ // Sync validation — [formControl] with custom <c8y-message> children
233
+ readonly validFormControl = new FormControl('min 3 chars required', {
234
+ validators: [Validators.required, Validators.minLength(3)],
235
+ nonNullable: true
236
+ });
237
+
238
+ // Disabled state
239
+ disabledModel = 'Read-only value';
240
+
241
+ // Async validation — simulates a server-side uniqueness check
242
+ readonly asyncFormControl = new FormControl('available', { nonNullable: true });
243
+
244
+ readonly noSpacesValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null =>
245
+ /\s/.test(control.value) ? { noSpaces: true } : null;
246
+ readonly uniquenessValidator: AsyncValidatorFn = (
247
+ control: AbstractControl
248
+ ): Observable<ValidationErrors | null> => {
249
+ const takenNames = ['taken', 'admin', 'root'];
250
+ return timer(800).pipe(
251
+ map(() => (takenNames.includes(control.value?.toLowerCase()) ? { notUnique: true } : null))
252
+ );
253
+ };
254
+
255
+ onSave(value: string): void {
256
+ this.lastAction = 'Saved';
257
+ this.lastSavedValue = value;
258
+ }
259
+
260
+ onCancel(): void {
261
+ this.lastAction = 'Cancelled';
262
+ }
263
+ }
@@ -0,0 +1,25 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { NavigatorNode, hookNavigator, hookRoute } from '@c8y/ngx-components';
4
+
5
+ @NgModule({
6
+ imports: [CommonModule],
7
+ providers: [
8
+ hookRoute({
9
+ path: 'input-group-editable',
10
+ loadComponent: () =>
11
+ import('./input-group-editable-example.component').then(
12
+ m => m.InputGroupEditableExampleComponent
13
+ )
14
+ }),
15
+ hookNavigator(
16
+ new NavigatorNode({
17
+ path: '/input-group-editable',
18
+ label: 'Inline editable input',
19
+ icon: 'hand-o-right',
20
+ priority: 5
21
+ })
22
+ )
23
+ ]
24
+ })
25
+ export class InputGroupEditableExampleModule {}