@c8y/tutorial 1019.0.7 → 1019.2.4
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 +10 -5
- package/package.json +7 -7
- package/src/grids/device-grid-example/device-grid-example-configuration-strategy.ts +44 -0
- package/src/grids/device-grid-example/device-grid-example.component.html +25 -54
- package/src/grids/device-grid-example/device-grid-example.component.ts +57 -4
- package/src/grids/empty-grid-example/empty-grid-example.component.html +14 -0
- package/src/grids/empty-grid-example/empty-grid-example.component.ts +74 -0
- package/src/grids/empty-grid-example/empty-grid-example.module.ts +15 -0
- package/src/input/range-input-example.component.ts +4 -4
package/cumulocity.config.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EnvironmentOptions } from '@c8y/devkit/dist/options';
|
|
2
|
-
import { author, description, version } from './package.json';
|
|
3
2
|
import { DefinePlugin } from 'webpack';
|
|
3
|
+
import { author, description, version } from './package.json';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
export default {
|
|
6
6
|
runTime: {
|
|
7
7
|
author,
|
|
8
8
|
description,
|
|
@@ -315,6 +315,12 @@ const options: EnvironmentOptions = {
|
|
|
315
315
|
path: './src/grids/device-grid-example/device-grid-example.module.ts',
|
|
316
316
|
description: 'An example for a device data grid.'
|
|
317
317
|
},
|
|
318
|
+
{
|
|
319
|
+
name: 'Empty grid example',
|
|
320
|
+
module: 'EmptyGridExampleModule',
|
|
321
|
+
path: './src/grids/empty-grid-example/empty-grid-example.module.ts',
|
|
322
|
+
description: 'An example for an empty data grid.'
|
|
323
|
+
},
|
|
318
324
|
{
|
|
319
325
|
name: 'Right drawer hook sample',
|
|
320
326
|
module: 'RightDrawerModule',
|
|
@@ -557,6 +563,7 @@ const options: EnvironmentOptions = {
|
|
|
557
563
|
'ClientGridExampleModule',
|
|
558
564
|
'ServerGridExampleModule',
|
|
559
565
|
'DeviceGridExampleModule',
|
|
566
|
+
'EmptyGridExampleModule',
|
|
560
567
|
'TextTranslationByServiceModule',
|
|
561
568
|
'TextTranslationGettextModule',
|
|
562
569
|
'C8yDateTranslationModule',
|
|
@@ -638,6 +645,4 @@ const options: EnvironmentOptions = {
|
|
|
638
645
|
'@ngx-translate/core'
|
|
639
646
|
]
|
|
640
647
|
}
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
export default options;
|
|
648
|
+
} as const satisfies EnvironmentOptions;
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c8y/tutorial",
|
|
3
|
-
"version": "1019.
|
|
3
|
+
"version": "1019.2.4",
|
|
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/devkit": "1019.
|
|
7
|
-
"@c8y/style": "1019.
|
|
8
|
-
"@c8y/ng1-modules": "1019.
|
|
9
|
-
"@c8y/ngx-components": "1019.
|
|
10
|
-
"@c8y/client": "1019.
|
|
11
|
-
"@c8y/bootstrap": "1019.
|
|
6
|
+
"@c8y/devkit": "1019.2.4",
|
|
7
|
+
"@c8y/style": "1019.2.4",
|
|
8
|
+
"@c8y/ng1-modules": "1019.2.4",
|
|
9
|
+
"@c8y/ngx-components": "1019.2.4",
|
|
10
|
+
"@c8y/client": "1019.2.4",
|
|
11
|
+
"@c8y/bootstrap": "1019.2.4",
|
|
12
12
|
"@angular/cdk": "^16.2.11",
|
|
13
13
|
"@angular/upgrade": "^16.2.11",
|
|
14
14
|
"ngx-bootstrap": "11.0.2",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Inject, Injectable, Optional } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
AbstractConfigurationStrategy,
|
|
4
|
+
DATA_GRID_CONFIGURATION_CONTEXT,
|
|
5
|
+
DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER,
|
|
6
|
+
GridConfig,
|
|
7
|
+
GridConfigContext,
|
|
8
|
+
GridConfigContextProvider
|
|
9
|
+
} from '@c8y/ngx-components';
|
|
10
|
+
import { Observable, of } from 'rxjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A <code>DataGridConfigurationStrategy</code> gives you the flexibility to implement
|
|
14
|
+
* the desired mechanism of how data grid configuration (column order, visibility, sorting,
|
|
15
|
+
* filtering, custom columns, pagination) can be persisted.
|
|
16
|
+
*/
|
|
17
|
+
@Injectable({ providedIn: 'root' })
|
|
18
|
+
export class DeviceGridExampleConfigurationStrategy extends AbstractConfigurationStrategy {
|
|
19
|
+
constructor(
|
|
20
|
+
@Inject(DATA_GRID_CONFIGURATION_CONTEXT)
|
|
21
|
+
@Optional()
|
|
22
|
+
protected context: GridConfigContext,
|
|
23
|
+
@Inject(DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER)
|
|
24
|
+
@Optional()
|
|
25
|
+
protected contextProvider: GridConfigContextProvider
|
|
26
|
+
) {
|
|
27
|
+
super(context, contextProvider);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getConfig$(ctx?: GridConfigContext): Observable<GridConfig> {
|
|
31
|
+
const context = this.retrieveContext(ctx);
|
|
32
|
+
return context?.key
|
|
33
|
+
? of(JSON.parse(localStorage.getItem(context?.key)) as unknown as GridConfig)
|
|
34
|
+
: null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
saveConfig$(config: GridConfig, ctx?: GridConfigContext): Observable<GridConfig> {
|
|
38
|
+
const context = this.retrieveContext(ctx);
|
|
39
|
+
if (context?.key) {
|
|
40
|
+
localStorage.setItem(context.key, JSON.stringify(config));
|
|
41
|
+
}
|
|
42
|
+
return of(config);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,58 +1,29 @@
|
|
|
1
1
|
<c8y-title>Data grid examples</c8y-title>
|
|
2
2
|
|
|
3
|
-
<div class="
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
href="https://formly.dev/docs/guide/validation/#3-declaring-validation-function-and-message-within-field-definition"
|
|
21
|
-
target="_blank"
|
|
22
|
-
rel="noopener noreferrer"
|
|
23
|
-
>
|
|
24
|
-
Formly documentation
|
|
25
|
-
</a>
|
|
26
|
-
)
|
|
27
|
-
</li>
|
|
28
|
-
</ul>
|
|
29
|
-
|
|
30
|
-
<div class="form-group">
|
|
31
|
-
<label for="exampleSelect">Select a preset example</label>
|
|
32
|
-
<div class="c8y-select-wrapper">
|
|
33
|
-
<select
|
|
34
|
-
class="form-control"
|
|
35
|
-
id="exampleSelect"
|
|
36
|
-
[ngModel]="selectedExample"
|
|
37
|
-
(ngModelChange)="selectExample($event)"
|
|
38
|
-
>
|
|
39
|
-
<option
|
|
40
|
-
*ngFor="let example of examples"
|
|
41
|
-
[ngValue]="example"
|
|
42
|
-
>
|
|
43
|
-
{{ example.label }}
|
|
44
|
-
</option>
|
|
45
|
-
</select>
|
|
46
|
-
<span></span>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<c8y-device-grid
|
|
51
|
-
[title]="'Devices'"
|
|
52
|
-
[columns]="columnsInput"
|
|
53
|
-
[actionControls]="[]"
|
|
54
|
-
(onColumnsChange)="onColumnsChange($event)"
|
|
55
|
-
(onDeviceQueryStringChange)="onDeviceQueryStringChange($event)"
|
|
56
|
-
></c8y-device-grid>
|
|
3
|
+
<div class="form-group">
|
|
4
|
+
<label for="exampleSelect">Select a preset example</label>
|
|
5
|
+
<div class="c8y-select-wrapper">
|
|
6
|
+
<select
|
|
7
|
+
class="form-control"
|
|
8
|
+
id="exampleSelect"
|
|
9
|
+
[ngModel]="selectedExample"
|
|
10
|
+
(ngModelChange)="selectExample($event)"
|
|
11
|
+
>
|
|
12
|
+
<option
|
|
13
|
+
*ngFor="let example of examples"
|
|
14
|
+
[ngValue]="example"
|
|
15
|
+
>
|
|
16
|
+
{{ example.label }}
|
|
17
|
+
</option>
|
|
18
|
+
</select>
|
|
19
|
+
<span></span>
|
|
57
20
|
</div>
|
|
58
21
|
</div>
|
|
22
|
+
|
|
23
|
+
<c8y-device-grid
|
|
24
|
+
[title]="'Devices'"
|
|
25
|
+
[columns]="columnsInput"
|
|
26
|
+
[actionControls]="[]"
|
|
27
|
+
(onColumnsChange)="onColumnsChange($event)"
|
|
28
|
+
(onDeviceQueryStringChange)="onDeviceQueryStringChange($event)"
|
|
29
|
+
></c8y-device-grid>
|
|
@@ -1,19 +1,54 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
2
|
import { AbstractControl } from '@angular/forms';
|
|
3
3
|
import { RouterModule } from '@angular/router';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Column,
|
|
6
|
+
CoreModule,
|
|
7
|
+
CustomColumn,
|
|
8
|
+
DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER,
|
|
9
|
+
DATA_GRID_CONFIGURATION_STRATEGY,
|
|
10
|
+
gettext,
|
|
11
|
+
GridConfigContext,
|
|
12
|
+
GridConfigContextProvider
|
|
13
|
+
} from '@c8y/ngx-components';
|
|
5
14
|
import { DeviceGridModule, DeviceGridService } from '@c8y/ngx-components/device-grid';
|
|
6
15
|
import { FormlyFieldConfig } from '@ngx-formly/core';
|
|
7
16
|
import { find } from 'lodash-es';
|
|
17
|
+
import { DeviceGridExampleConfigurationStrategy } from './device-grid-example-configuration-strategy';
|
|
8
18
|
|
|
9
19
|
@Component({
|
|
10
20
|
selector: 'c8y-device-grid-example',
|
|
11
21
|
templateUrl: './device-grid-example.component.html',
|
|
12
22
|
standalone: true,
|
|
13
23
|
imports: [CoreModule, DeviceGridModule, RouterModule],
|
|
14
|
-
providers: [
|
|
24
|
+
providers: [
|
|
25
|
+
DeviceGridService,
|
|
26
|
+
/* Providing DATA_GRID_CONFIGURATION_STRATEGY defines how grid configuration
|
|
27
|
+
* should be persisted. You can use existing implementations like
|
|
28
|
+
* `UserPreferencesConfigurationStrategy` or implement your own.
|
|
29
|
+
*/
|
|
30
|
+
{
|
|
31
|
+
provide: DATA_GRID_CONFIGURATION_STRATEGY,
|
|
32
|
+
useClass: DeviceGridExampleConfigurationStrategy
|
|
33
|
+
},
|
|
34
|
+
/* Providing a DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER gives you the flexibility
|
|
35
|
+
* to persist configurations based on various criteria at runtime - device type,
|
|
36
|
+
* current user, group, etc.
|
|
37
|
+
* By default all configurable options in a grid are persisted. You can exlude
|
|
38
|
+
* specific options (pagination, filters, sorting, etc.) by defining `GridConfigFilter`
|
|
39
|
+
* in your context.
|
|
40
|
+
* Alternatevely, in simpler scenarios you can provide a static context
|
|
41
|
+
* with DATA_GRID_CONFIGURATION_CONTEXT and `useValue`.
|
|
42
|
+
*/
|
|
43
|
+
{
|
|
44
|
+
provide: DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER,
|
|
45
|
+
useExisting: DeviceGridExampleComponent
|
|
46
|
+
}
|
|
47
|
+
]
|
|
15
48
|
})
|
|
16
|
-
export class DeviceGridExampleComponent {
|
|
49
|
+
export class DeviceGridExampleComponent implements GridConfigContextProvider {
|
|
50
|
+
readonly withPersistedConfigExampleLabel =
|
|
51
|
+
'Standard columns with configuration persisted in local storage';
|
|
17
52
|
examples: Array<{ label: string; columns: Column[] }>;
|
|
18
53
|
selectedExample;
|
|
19
54
|
columnsInput: Column[];
|
|
@@ -23,11 +58,21 @@ export class DeviceGridExampleComponent {
|
|
|
23
58
|
this.getExampleWithStandardColumns(),
|
|
24
59
|
this.getExampleWithStandardColumnsAndSavedFilteringSorting(),
|
|
25
60
|
this.getExampleWithCustomColumnAndPredefinedFiltering(),
|
|
26
|
-
this.getExampleWithCustomColumnAndCustomValidator()
|
|
61
|
+
this.getExampleWithCustomColumnAndCustomValidator(),
|
|
62
|
+
this.getExampleWithStandardColumnsAndPersistedConfiguration()
|
|
27
63
|
];
|
|
28
64
|
this.selectExample(this.examples[0]);
|
|
29
65
|
}
|
|
30
66
|
|
|
67
|
+
getGridConfigContext(): GridConfigContext {
|
|
68
|
+
return {
|
|
69
|
+
key:
|
|
70
|
+
this.selectedExample.label === this.withPersistedConfigExampleLabel
|
|
71
|
+
? 'example-device-grid'
|
|
72
|
+
: null
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
31
76
|
getExampleWithStandardColumns() {
|
|
32
77
|
const columns = this.deviceGridService.getDefaultColumns();
|
|
33
78
|
return {
|
|
@@ -113,6 +158,14 @@ export class DeviceGridExampleComponent {
|
|
|
113
158
|
};
|
|
114
159
|
}
|
|
115
160
|
|
|
161
|
+
getExampleWithStandardColumnsAndPersistedConfiguration() {
|
|
162
|
+
const columns = this.deviceGridService.getDefaultColumns();
|
|
163
|
+
return {
|
|
164
|
+
label: this.withPersistedConfigExampleLabel,
|
|
165
|
+
columns
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
116
169
|
selectExample(example) {
|
|
117
170
|
this.selectedExample = example;
|
|
118
171
|
this.columnsInput = example.columns;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<c8y-title>Empty grid example</c8y-title>
|
|
2
|
+
|
|
3
|
+
<c8y-data-grid
|
|
4
|
+
[title]="title"
|
|
5
|
+
[columns]="columns"
|
|
6
|
+
[actionControls]="actionControls"
|
|
7
|
+
>
|
|
8
|
+
<c8y-ui-empty-state
|
|
9
|
+
icon="search"
|
|
10
|
+
title="No results to display."
|
|
11
|
+
subtitle="Refine your search terms or check your spelling."
|
|
12
|
+
[horizontal]="true"
|
|
13
|
+
></c8y-ui-empty-state>
|
|
14
|
+
</c8y-data-grid>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { RouterModule } from '@angular/router';
|
|
3
|
+
import { ActionControl, BuiltInActionType, Column, CoreModule } from '@c8y/ngx-components';
|
|
4
|
+
import { DeviceGridModule } from '@c8y/ngx-components/device-grid';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'c8y-empty-grid-example',
|
|
8
|
+
templateUrl: './empty-grid-example.component.html',
|
|
9
|
+
standalone: true,
|
|
10
|
+
imports: [CoreModule, DeviceGridModule, RouterModule]
|
|
11
|
+
})
|
|
12
|
+
export class EmptyGridExampleComponent {
|
|
13
|
+
/** This will be used as a title for the data grid. */
|
|
14
|
+
title = 'Devices';
|
|
15
|
+
/**
|
|
16
|
+
* This defines what columns will be displayed in the grid.
|
|
17
|
+
* In this example we're just displaying properties from the items from the loaded data file.
|
|
18
|
+
*/
|
|
19
|
+
columns: Column[] = [
|
|
20
|
+
{
|
|
21
|
+
name: 'id',
|
|
22
|
+
header: 'ID',
|
|
23
|
+
path: 'id',
|
|
24
|
+
filterable: true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'name',
|
|
28
|
+
header: 'Name',
|
|
29
|
+
path: 'name',
|
|
30
|
+
filterable: true
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'type',
|
|
34
|
+
header: 'Type',
|
|
35
|
+
path: 'type',
|
|
36
|
+
filterable: true
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'creationTime',
|
|
40
|
+
header: 'Creation time',
|
|
41
|
+
path: 'creationTime',
|
|
42
|
+
filterable: true
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'lastUpdated',
|
|
46
|
+
header: 'Last updated',
|
|
47
|
+
path: 'lastUpdated',
|
|
48
|
+
filterable: true
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'owner',
|
|
52
|
+
header: 'Owner',
|
|
53
|
+
path: 'owner',
|
|
54
|
+
filterable: true
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
/**
|
|
58
|
+
* Defines actions for individual rows.
|
|
59
|
+
* `type` can be one of the predefined ones, or a custom one.
|
|
60
|
+
* `callback` executes the action (based on the selected item object).
|
|
61
|
+
*/
|
|
62
|
+
actionControls: ActionControl[] = [
|
|
63
|
+
{
|
|
64
|
+
type: BuiltInActionType.Delete,
|
|
65
|
+
callback: selectedItem => this.onItemDelete(selectedItem)
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
/** Executes a delete action on the selected item. */
|
|
70
|
+
onItemDelete(selectedItem) {
|
|
71
|
+
console.log('item to delete:');
|
|
72
|
+
console.dir(selectedItem);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { NgModule } from '@angular/core';
|
|
3
|
+
import { hookRoute } from '@c8y/ngx-components';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
imports: [CommonModule],
|
|
7
|
+
providers: [
|
|
8
|
+
hookRoute({
|
|
9
|
+
path: 'grids/empty-grid-example',
|
|
10
|
+
loadComponent: () =>
|
|
11
|
+
import('./empty-grid-example.component').then(m => m.EmptyGridExampleComponent)
|
|
12
|
+
})
|
|
13
|
+
]
|
|
14
|
+
})
|
|
15
|
+
export class EmptyGridExampleModule {}
|
|
@@ -6,20 +6,20 @@ import { CoreModule } from '@c8y/ngx-components';
|
|
|
6
6
|
template: `<c8y-title> Range Input examples </c8y-title>
|
|
7
7
|
<div class="p-t-24">
|
|
8
8
|
<div class="form-group">
|
|
9
|
-
<label>Default range slider</label>
|
|
9
|
+
<label for="range1">Default range slider</label>
|
|
10
10
|
<c8y-range>
|
|
11
|
-
<input type="range" min="0" max="100" steps="1" />
|
|
11
|
+
<input id="range1" type="range" min="0" max="100" steps="1" />
|
|
12
12
|
</c8y-range>
|
|
13
13
|
</div>
|
|
14
14
|
<div class="form-group">
|
|
15
|
-
<label>Range with custom popover</label>
|
|
15
|
+
<label for="range2">Range with custom popover</label>
|
|
16
16
|
<c8y-range #range>
|
|
17
17
|
<ng-template #c8yRangeValue>
|
|
18
18
|
<div>
|
|
19
19
|
<span>The <strong>Value</strong> is: {{ range.value }}</span>
|
|
20
20
|
</div>
|
|
21
21
|
</ng-template>
|
|
22
|
-
<input type="range" min="20" max="60" steps="2" />
|
|
22
|
+
<input id="range2" type="range" min="20" max="60" steps="2" />
|
|
23
23
|
</c8y-range>
|
|
24
24
|
</div>
|
|
25
25
|
</div>`,
|