@c8y/tutorial 1023.48.0 → 1023.48.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.
@@ -899,6 +899,13 @@ export default {
899
899
  description: 'This is an example for the bottom drawer service.',
900
900
  scope: 'self'
901
901
  },
902
+ {
903
+ name: 'Bottom drawer stacked',
904
+ module: 'bottomDrawerStackedExampleModuleProviders',
905
+ path: './src/bottom-drawer-stacked/bottom-drawer-stacked.providers.ts',
906
+ description: 'This is an example for multiple bottom drawers.',
907
+ scope: 'self'
908
+ },
902
909
  {
903
910
  name: 'Widget Config Hook',
904
911
  module: 'widgetConfigHookProviders',
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@c8y/tutorial",
3
- "version": "1023.48.0",
3
+ "version": "1023.48.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": "1023.48.0",
7
- "@c8y/ngx-components": "1023.48.0",
8
- "@c8y/client": "1023.48.0",
9
- "@c8y/bootstrap": "1023.48.0",
6
+ "@c8y/style": "1023.48.3",
7
+ "@c8y/ngx-components": "1023.48.3",
8
+ "@c8y/client": "1023.48.3",
9
+ "@c8y/bootstrap": "1023.48.3",
10
10
  "@angular/cdk": "^20.2.14",
11
11
  "monaco-editor": "~0.53.0",
12
12
  "ngx-bootstrap": "20.0.2",
@@ -14,8 +14,8 @@
14
14
  "rxjs": "7.8.2"
15
15
  },
16
16
  "devDependencies": {
17
- "@c8y/options": "1023.48.0",
18
- "@c8y/devkit": "1023.48.0"
17
+ "@c8y/options": "1023.48.3",
18
+ "@c8y/devkit": "1023.48.3"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "@angular/common": ">=20 <21"
@@ -5,7 +5,9 @@ import { generateResponse, handleRequest } from '../utils/common';
5
5
  import { generateDashboard } from '../../__mocks/utils/generators/managedObjects';
6
6
 
7
7
  export class ContextDashboardInterceptor implements HttpInterceptor {
8
- dashboard = generateDashboard();
8
+ dashboard = generateDashboard({
9
+ device: { id: '12345', name: 'Demo Sensor Device' }
10
+ });
9
11
 
10
12
  intercept(req: ApiCall, next: HttpHandler): Observable<IFetchResponse> {
11
13
  return handleRequest(req, next, 'inventory/managedObjects', {
@@ -172,10 +172,10 @@ export function generateDashboard({
172
172
  _x: 3,
173
173
  _y: 0,
174
174
  id: id,
175
- title: 'Hello',
175
+ title: 'Demo Widget Example',
176
176
  _width: 6,
177
177
  config: {
178
- text: 'Welcome to a context dashboard'
178
+ text: 'This text is configured via the widget settings. Click the edit button to change it!'
179
179
  },
180
180
  _height: 6
181
181
  }
@@ -0,0 +1,39 @@
1
+ <div class="card-header separator">
2
+ <span
3
+ class="h4 card-title"
4
+ id="drawerTitle"
5
+ >
6
+ {{ title }}
7
+ </span>
8
+ </div>
9
+ <div class="inner-scroll flex-grow">
10
+ <div class="card-block">
11
+ <p>Bottom drawer content</p>
12
+ <button
13
+ class="btn btn-primary"
14
+ (click)="openTopDrawer()"
15
+ >
16
+ Open bottom drawer via service
17
+ </button>
18
+ </div>
19
+ </div>
20
+ <div class="card-footer text-center p-24 separator flex-no-shrink">
21
+ <button
22
+ class="btn btn-default"
23
+ [disabled]="isDisabled"
24
+ >
25
+ This button is disabled, as the inital state defines it.
26
+ </button>
27
+ <button
28
+ class="btn btn-default"
29
+ (click)="cancel()"
30
+ >
31
+ Cancel
32
+ </button>
33
+ <button
34
+ class="btn btn-primary"
35
+ (click)="save()"
36
+ >
37
+ Save
38
+ </button>
39
+ </div>
@@ -0,0 +1,78 @@
1
+ import { Component, inject, OnInit, OnDestroy, HostListener } from '@angular/core';
2
+ import { BottomDrawerRef, BottomDrawerService } from '@c8y/ngx-components';
3
+ import { Subject } from 'rxjs';
4
+ import { takeUntil } from 'rxjs/operators';
5
+ import { BottomDrawerContentTopExampleComponent } from './bottom-drawer-content-top-example.component';
6
+
7
+ @Component({
8
+ selector: 'tut-bottom-drawer-content-example',
9
+ templateUrl: './bottom-drawer-content-example.component.html',
10
+ standalone: true,
11
+ host: {
12
+ class: 'd-contents'
13
+ }
14
+ })
15
+ export class BottomDrawerContentExampleComponent implements OnInit, OnDestroy {
16
+ bottomDrawerRef = inject(BottomDrawerRef);
17
+ isDisabled = false;
18
+ title = 'First bottom drawer title';
19
+ destroy$: Subject<boolean> = new Subject<boolean>();
20
+
21
+ result: Promise<string> = new Promise((resolve, reject) => {
22
+ this._save = resolve;
23
+ this._cancel = reject;
24
+ });
25
+
26
+ private _save: (value: string) => void;
27
+ private _cancel: (reason?: any) => void;
28
+ bottomDrawerService = inject(BottomDrawerService);
29
+
30
+ @HostListener('document:keydown.escape', ['$event'])
31
+ async onEscapePress(event: Event) {
32
+ if (this.bottomDrawerService.isTop(this.bottomDrawerRef)) {
33
+ event.preventDefault();
34
+ await this.bottomDrawerRef.close();
35
+ console.log(
36
+ 'Escape pressed- first bottom drawer closed, handled by BottomDrawerContentExampleComponent'
37
+ );
38
+ }
39
+ }
40
+
41
+ ngOnInit() {
42
+ this.bottomDrawerRef.onClosed$.pipe(takeUntil(this.destroy$)).subscribe(() => {
43
+ this._cancel('Drawer closed');
44
+ });
45
+ }
46
+
47
+ async openTopDrawer() {
48
+ const drawer = this.bottomDrawerService.openDrawer(BottomDrawerContentTopExampleComponent, {
49
+ initialState: {
50
+ // place here any content you want to pass to the component
51
+ isDisabled: true
52
+ },
53
+ disableClickOutside: true
54
+ // closeOnEscape is true by default
55
+ });
56
+
57
+ try {
58
+ const _resultOf = await drawer.instance.result;
59
+ } catch (ex) {
60
+ //
61
+ }
62
+ }
63
+
64
+ ngOnDestroy() {
65
+ this.destroy$.next(true);
66
+ this.destroy$.complete();
67
+ }
68
+
69
+ cancel() {
70
+ this._cancel('User canceled');
71
+ this.bottomDrawerRef.close();
72
+ }
73
+
74
+ save() {
75
+ this._save('Value to pass back.');
76
+ this.bottomDrawerRef.close();
77
+ }
78
+ }
@@ -0,0 +1,33 @@
1
+ <div class="card-header separator">
2
+ <span
3
+ class="h4 card-title"
4
+ id="drawerTitle"
5
+ >
6
+ {{ title }}
7
+ </span>
8
+ </div>
9
+ <div class="inner-scroll flex-grow">
10
+ <div class="card-block">
11
+ <p>Bottom drawer content</p>
12
+ </div>
13
+ </div>
14
+ <div class="card-footer text-center p-24 separator flex-no-shrink">
15
+ <button
16
+ class="btn btn-default"
17
+ [disabled]="isDisabled"
18
+ >
19
+ This button is disabled, as the inital state defines it.
20
+ </button>
21
+ <button
22
+ class="btn btn-default"
23
+ (click)="cancel()"
24
+ >
25
+ Cancel
26
+ </button>
27
+ <button
28
+ class="btn btn-primary"
29
+ (click)="save()"
30
+ >
31
+ Save
32
+ </button>
33
+ </div>
@@ -0,0 +1,48 @@
1
+ import { Component, inject, OnInit, OnDestroy } from '@angular/core';
2
+ import { BottomDrawerRef } from '@c8y/ngx-components';
3
+ import { Subject } from 'rxjs';
4
+ import { takeUntil } from 'rxjs/operators';
5
+
6
+ @Component({
7
+ selector: 'tut-bottom-drawer-content-top-example',
8
+ templateUrl: './bottom-drawer-content-top-example.component.html',
9
+ standalone: true,
10
+ host: {
11
+ class: 'd-contents'
12
+ }
13
+ })
14
+ export class BottomDrawerContentTopExampleComponent implements OnInit, OnDestroy {
15
+ bottomDrawerRef = inject(BottomDrawerRef);
16
+ isDisabled = false;
17
+ title = 'Second bottom drawer title';
18
+ destroy$: Subject<boolean> = new Subject<boolean>();
19
+
20
+ result: Promise<string> = new Promise((resolve, reject) => {
21
+ this._save = resolve;
22
+ this._cancel = reject;
23
+ });
24
+
25
+ private _save: (value: string) => void;
26
+ private _cancel: (reason?: any) => void;
27
+
28
+ ngOnInit() {
29
+ this.bottomDrawerRef.onClosed$.pipe(takeUntil(this.destroy$)).subscribe(() => {
30
+ this._cancel('Top drawer closed');
31
+ });
32
+ }
33
+
34
+ ngOnDestroy() {
35
+ this.destroy$.next(true);
36
+ this.destroy$.unsubscribe();
37
+ }
38
+
39
+ cancel() {
40
+ this._cancel('User canceled');
41
+ this.bottomDrawerRef.close();
42
+ }
43
+
44
+ save() {
45
+ this._save('Value to pass back.');
46
+ this.bottomDrawerRef.close();
47
+ }
48
+ }
@@ -0,0 +1,7 @@
1
+ <button
2
+ class="btn btn-primary"
3
+ (click)="openDrawer()"
4
+ [disabled]="isOpen"
5
+ >
6
+ Open bottom drawer via service
7
+ </button>
@@ -0,0 +1,35 @@
1
+ import { Component, inject } from '@angular/core';
2
+ import { AlertService, BottomDrawerService, CoreModule } from '@c8y/ngx-components';
3
+ import { BottomDrawerContentExampleComponent } from './bottom-drawer-content-example.component';
4
+
5
+ @Component({
6
+ selector: 'tut-bottom-drawer-stacked-example',
7
+ templateUrl: './bottom-drawer-stacked-example.component.html',
8
+ standalone: true,
9
+ imports: [CoreModule]
10
+ })
11
+ export class BottomDrawerStackedExampleComponent {
12
+ bottomDrawerService = inject(BottomDrawerService);
13
+ alertService = inject(AlertService);
14
+ isOpen = false;
15
+
16
+ async openDrawer() {
17
+ this.isOpen = true;
18
+ const drawer = this.bottomDrawerService.openDrawer(BottomDrawerContentExampleComponent, {
19
+ initialState: {
20
+ // place here any content you want to pass to the component
21
+ isDisabled: true
22
+ },
23
+ disableClickOutside: true,
24
+ closeOnEscape: false // BottomDrawerContentExampleComponent will handle Escape key on its own
25
+ });
26
+
27
+ try {
28
+ const resultOf = await drawer.instance.result;
29
+ this.alertService.success(resultOf);
30
+ } catch (ex) {
31
+ this.alertService.danger('Canceled as of: ' + ex);
32
+ }
33
+ this.isOpen = false;
34
+ }
35
+ }
@@ -0,0 +1,19 @@
1
+ import { NavigatorNode, hookNavigator, hookRoute } from '@c8y/ngx-components';
2
+
3
+ export const bottomDrawerStackedExampleModuleProviders = [
4
+ hookRoute({
5
+ path: 'bottom-drawer-stacked',
6
+ loadComponent: () =>
7
+ import('./bottom-drawer-stacked-example.component').then(
8
+ m => m.BottomDrawerStackedExampleComponent
9
+ )
10
+ }),
11
+ hookNavigator(
12
+ new NavigatorNode({
13
+ label: 'Bottom drawer stacked',
14
+ path: '/bottom-drawer-stacked',
15
+ icon: 'th-list',
16
+ priority: 0
17
+ })
18
+ )
19
+ ];
@@ -17,6 +17,14 @@ import { ContextDashboardModule } from '@c8y/ngx-components/context-dashboard';
17
17
  imports: [ContextDashboardModule, CoreModule, CommonModule]
18
18
  })
19
19
  export class WidgetGuideContextDashboardComponent {
20
+ /**
21
+ * Default widgets shown when no dashboard exists in the backend.
22
+ *
23
+ * Note: In the codex environment, the mock interceptor at
24
+ * `packages/tutorial/src/__mocks/utils/generators/managedObjects.ts`
25
+ * returns a fake dashboard, so these defaults are not used.
26
+ * If you change these values, also update `generateDashboard()` in the mock.
27
+ */
20
28
  defaultWidgets: Widget[] = [
21
29
  {
22
30
  _x: 3,
@@ -25,10 +33,10 @@ export class WidgetGuideContextDashboardComponent {
25
33
  _height: 6,
26
34
  componentId: 'angular.widget.demo',
27
35
  config: {
28
- text: 'Welcome to a context dashboard'
36
+ text: 'This text is configured via the widget settings. Click the edit button to change it!'
29
37
  },
30
- title: 'Hello',
31
- id: 'some_unique_id'
38
+ title: 'Demo Widget Example1',
39
+ id: 'demo_widget_example'
32
40
  }
33
41
  ];
34
42
  }
@@ -1,13 +1,27 @@
1
- import { Component, Input } from '@angular/core';
2
- import { ControlContainer, NgForm, FormsModule } from '@angular/forms';
1
+ import { AsyncPipe } from '@angular/common';
3
2
  import {
4
- DynamicComponent,
5
- OnBeforeSave,
6
- AlertService,
7
- FormGroupComponent
8
- } from '@c8y/ngx-components';
9
- import { omit } from 'lodash';
10
- import { JsonPipe } from '@angular/common';
3
+ Component,
4
+ DestroyRef,
5
+ inject,
6
+ Input,
7
+ OnInit,
8
+ TemplateRef,
9
+ ViewChild
10
+ } from '@angular/core';
11
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
12
+ import {
13
+ ControlContainer,
14
+ FormBuilder,
15
+ FormControl,
16
+ FormGroup,
17
+ NgForm,
18
+ ReactiveFormsModule,
19
+ Validators
20
+ } from '@angular/forms';
21
+ import { AlertService, DynamicComponent, FormGroupComponent } from '@c8y/ngx-components';
22
+ import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
23
+ import { BehaviorSubject } from 'rxjs';
24
+ import { WidgetDemo } from './demo-widget.component';
11
25
  import { WidgetConfig } from './widget-config.model';
12
26
 
13
27
  @Component({
@@ -16,75 +30,64 @@ import { WidgetConfig } from './widget-config.model';
16
30
  <div class="form-group">
17
31
  <c8y-form-group>
18
32
  <label>Text</label>
19
- <textarea
20
- style="width: 100%"
21
- name="text"
22
- [(ngModel)]="config.text"
23
- [required]="true"
24
- ></textarea>
33
+ <textarea style="width: 100%" [formControl]="formGroup.controls.text"></textarea>
25
34
  </c8y-form-group>
26
-
27
- <label
28
- >Configuration
29
- <button class="btn btn-primary btn-xs" type="button" (click)="more = !more">
30
- {{ more ? 'Hide' : 'Show' }} settings
31
- </button></label
32
- >
33
- <pre><code>{{ clean(config, more) | json }}</code></pre>
34
35
  </div>
36
+
37
+ <ng-template #widgetPreview>
38
+ <c8y-widget-demo [config]="config$ | async"></c8y-widget-demo>
39
+ </ng-template>
35
40
  `,
36
- // We connect our parent Form to this form (for disabling the save button)
37
- // you can also enable the button by using ContextServiceDashboard.formDisabled
38
- // property instead (by default it is enabled).
39
41
  viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
40
42
  standalone: true,
41
- imports: [FormGroupComponent, FormsModule, JsonPipe]
43
+ imports: [FormGroupComponent, ReactiveFormsModule, WidgetDemo, AsyncPipe]
42
44
  })
43
- export class WidgetConfigDemo implements DynamicComponent, OnBeforeSave {
44
- /**
45
- * The configuration which is shared between configuration component and display component.
46
- * Should be searilzabled to allow to save it to the API. The config is saved automatically
47
- * to the API on "save"-button hit. The onBeforeSave handler can be used to change this behavior,
48
- * or to manipulate the object.
49
- *
50
- * Note: The dashboard itself adds certain properties. As such, some properties are not allowed (e.g. device or settings)
51
- */
45
+ export class WidgetConfigDemo implements DynamicComponent, OnInit {
46
+ /** Configuration passed by the dashboard framework. */
52
47
  @Input() config: WidgetConfig = {};
53
48
 
54
- /**
55
- * An internal component property used to hide/show settings.
56
- */
57
- more = false;
49
+ /** Reactive form group for the widget configuration. */
50
+ formGroup: FormGroup<{ text: FormControl<string | null> }>;
58
51
 
59
- /**
60
- * Default Angular DI can be used, to use additional services.
61
- */
62
- constructor(private alert: AlertService) {}
52
+ /** Emits config changes for the preview template. */
53
+ config$ = new BehaviorSubject<WidgetConfig>({});
63
54
 
64
- /**
65
- * This example onBeforeSave handler cancels the saving, if the text is only a white-space.
66
- */
67
- onBeforeSave(config: any): boolean {
68
- if (config.text.trim() === '') {
69
- this.alert.warning('Please enter a valid text.');
70
- return false;
71
- }
72
- this.config.widgetInstanceGlobalTimeContext = true;
73
- this.config.canDecoupleGlobalTimeContext = true;
74
- return true;
75
- }
55
+ private readonly alert = inject(AlertService);
56
+ private readonly widgetConfigService = inject(WidgetConfigService);
57
+ private readonly formBuilder = inject(FormBuilder);
58
+ private readonly form = inject(NgForm);
59
+ private readonly destroyRef = inject(DestroyRef);
76
60
 
77
- /**
78
- * Used to hide/show config settings on toggle.
79
- */
80
- clean(config, more) {
81
- if (more) {
82
- return config;
83
- }
84
- return omit(config, 'settings');
61
+ @ViewChild('widgetPreview')
62
+ set preview(template: TemplateRef<any>) {
63
+ this.widgetConfigService.setPreview(template ?? null);
85
64
  }
86
65
 
87
- selectionChanged(e) {
88
- console.log(e);
66
+ ngOnInit(): void {
67
+ // Create form with initial values from config
68
+ this.formGroup = this.formBuilder.group({
69
+ text: [this.config?.text || '', Validators.required]
70
+ });
71
+
72
+ // Register form with parent NgForm for validation
73
+ this.form.form.addControl('widgetConfig', this.formGroup);
74
+
75
+ // Initialize preview
76
+ this.config$.next(this.config);
77
+
78
+ // Update preview when form values change
79
+ this.formGroup.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {
80
+ this.config$.next({ ...this.config, ...value });
81
+ });
82
+
83
+ // Register save callback - validates and merges form values into config
84
+ this.widgetConfigService.addOnBeforeSave(config => {
85
+ if (this.formGroup.invalid) {
86
+ this.alert.warning('Please enter a valid text.');
87
+ return false;
88
+ }
89
+ Object.assign(config, this.formGroup.value);
90
+ return true;
91
+ });
89
92
  }
90
93
  }
@@ -1,65 +1,55 @@
1
- import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
2
- import { gettext } from '@c8y/ngx-components/gettext';
1
+ import { Component, computed, input, OnInit } from '@angular/core';
3
2
  import {
4
3
  DismissAlertStrategy,
5
4
  DynamicComponentAlert,
6
- DynamicComponentAlertAggregator,
7
- DatePipe
5
+ DynamicComponentAlertAggregator
8
6
  } from '@c8y/ngx-components';
9
- import { NgIf } from '@angular/common';
10
7
  import { WidgetConfig } from './widget-config.model';
11
8
 
12
9
  @Component({
13
10
  selector: 'c8y-widget-demo',
14
11
  template: `
15
12
  <div class="p-16">
16
- <h1>Hi I'm a widget from angular</h1>
17
- <p class="text">Text from config object: {{ config?.text || 'No text' }}</p>
18
- <small>My context is: {{ config?.device?.name || 'No context' }}</small
19
- ><br />
20
- <ng-container *ngIf="config?.date?.length === 2">
21
- My time context is:
22
- <ul>
23
- <li>from: {{ (config?.date[0] | c8yDate) || 'No time context' }}</li>
24
- <li>To: {{ (config?.date[1] | c8yDate) || 'No time context' }}</li>
25
- </ul>
26
- </ng-container>
27
- <button class="btn btn-default" (click)="addAlert()">Add warning alert</button>
13
+ <h1>Demo Widget</h1>
14
+ <p class="text">{{ displayText() }}</p>
15
+ @if (deviceName()) {
16
+ <small>Device: {{ deviceName() }}</small>
17
+ }
18
+ <div class="m-t-16">
19
+ <button class="btn btn-default btn-sm" (click)="showAlert()">Show alert</button>
20
+ </div>
28
21
  </div>
29
22
  `,
30
23
  styles: [
31
24
  `
32
25
  .text {
33
- font-size: 2em;
26
+ font-size: 1.5em;
27
+ color: var(--c8y-brand-primary);
34
28
  }
35
29
  `
36
30
  ],
37
- standalone: true,
38
- imports: [NgIf, DatePipe]
31
+ standalone: true
39
32
  })
40
- export class WidgetDemo implements OnChanges {
41
- @Input() config: WidgetConfig;
42
- alerts: DynamicComponentAlertAggregator;
33
+ export class WidgetDemo implements OnInit {
34
+ readonly config = input<WidgetConfig>();
43
35
 
44
- ngOnInit() {
45
- this.alerts.setAlertGroupDismissStrategy(
46
- 'warning',
47
- DismissAlertStrategy.TEMPORARY_OR_PERMANENT
48
- );
49
- }
36
+ /** Computed signal for display text with fallback */
37
+ readonly displayText = computed(() => this.config()?.text || 'No text configured');
38
+
39
+ /** Computed signal for device name */
40
+ readonly deviceName = computed(() => this.config()?.device?.name);
41
+
42
+ /** Set by the dashboard framework - used to display alerts on the widget */
43
+ alerts: DynamicComponentAlertAggregator;
50
44
 
51
- ngOnChanges(changes: SimpleChanges): void {
52
- if (!changes['config']?.firstChange && changes['config']?.currentValue.date) {
53
- console.log('Global time context changed:', this.config.date);
54
- }
45
+ ngOnInit(): void {
46
+ // Enable dismissible alerts for warning type
47
+ this.alerts?.setAlertGroupDismissStrategy('warning', DismissAlertStrategy.TEMPORARY);
55
48
  }
56
49
 
57
- addAlert() {
58
- this.alerts.addAlerts(
59
- new DynamicComponentAlert({
60
- type: 'warning',
61
- text: gettext('Operation not supported by this device.')
62
- })
50
+ showAlert(): void {
51
+ this.alerts?.addAlerts(
52
+ new DynamicComponentAlert({ type: 'warning', text: 'This is a dismissible demo alert!' })
63
53
  );
64
54
  }
65
55
  }
@@ -4,36 +4,17 @@ import { WidgetConfigDemo } from './demo-widget-config.component';
4
4
 
5
5
  export function provideDemoWidget() {
6
6
  return [
7
- /**
8
- * This demo widget provides an example on how
9
- * to use the hookWidget. The component itself
10
- * is implemented in the dashboard on the
11
- * ../hello/hello.component.html by using the
12
- * dynamic-component tag.
13
- */
14
7
  hookWidget({
15
8
  id: 'angular.widget.demo',
16
- label: 'My angular widget',
17
- description: 'This is a description from angular',
9
+ label: 'Demo Widget',
10
+ description: 'A simple demo widget showing text and device context',
18
11
  component: WidgetDemo,
19
12
  configComponent: WidgetConfigDemo,
20
13
  errorStrategy: DynamicComponentErrorStrategy.OVERLAY_ERROR,
21
- /** new Angular-Dashboard definition */
22
14
  data: {
23
15
  schema: () => import('c8y-schema-loader?interfaceName=WidgetConfig!./widget-config.model'),
24
- // The settings object can be used to configure the configComponent
25
16
  settings: {
26
- noNewWidgets: false, // Set this to true, to don't allow adding new widgets.
27
- ng1: {
28
- options: {
29
- noDeviceTarget: false, // Set this to true to hide the AngularJS device selector.
30
- groupsSelectable: false // Set this, if not only devices should be selectable.
31
- }
32
- }
33
- },
34
- // Settings that are attached to the display component (in this case: WidgetDemo)
35
- displaySettings: {
36
- globalTimeContext: true // Set this to true, to add a global time context binding
17
+ noNewWidgets: false
37
18
  }
38
19
  }
39
20
  })
@@ -1,3 +1,6 @@
1
- import { GlobalTimeContextWidgetConfig } from '@c8y/ngx-components';
1
+ import { IIdentified, IManagedObject } from '@c8y/client';
2
2
 
3
- export type WidgetConfig = GlobalTimeContextWidgetConfig & { [key: string]: any };
3
+ export interface WidgetConfig {
4
+ text?: string;
5
+ device?: IIdentified & Partial<IManagedObject>;
6
+ }