@c8y/tutorial 1019.0.3 → 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.
@@ -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
- const options: EnvironmentOptions = {
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.0.3",
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.0.3",
7
- "@c8y/style": "1019.0.3",
8
- "@c8y/ng1-modules": "1019.0.3",
9
- "@c8y/ngx-components": "1019.0.3",
10
- "@c8y/client": "1019.0.3",
11
- "@c8y/bootstrap": "1019.0.3",
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="card">
4
- <div class="card-header separator">
5
- <h4 class="card-title">Device grid</h4>
6
- </div>
7
- <div class="card-block">
8
- <p>
9
- The following example features
10
- <code>DeviceGridComponent</code>
11
- and:
12
- </p>
13
- <ul>
14
- <li>displaying a filterable and sortable list of devices</li>
15
- <li>loading grid configuration from presets (columns, stored filtering and sorting)</li>
16
- <li>event handlers for: columns config changes, device query string changes</li>
17
- <li>
18
- custom validators for filters (based on
19
- <a
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 { Column, CoreModule, CustomColumn, gettext } from '@c8y/ngx-components';
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: [DeviceGridService]
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>`,