@c8y/ngx-components 1023.68.7 → 1023.71.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.
Files changed (72) hide show
  1. package/ai/agent-chat/index.d.ts +235 -75
  2. package/ai/agent-chat/index.d.ts.map +1 -1
  3. package/ai/ai-chat/index.d.ts +176 -26
  4. package/ai/ai-chat/index.d.ts.map +1 -1
  5. package/ai/index.d.ts +309 -75
  6. package/ai/index.d.ts.map +1 -1
  7. package/asset-properties/index.d.ts.map +1 -1
  8. package/echart/index.d.ts +4 -0
  9. package/echart/index.d.ts.map +1 -1
  10. package/echart/models/index.d.ts +2 -0
  11. package/echart/models/index.d.ts.map +1 -1
  12. package/events/events-timeline/index.d.ts +3 -2
  13. package/events/events-timeline/index.d.ts.map +1 -1
  14. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +680 -242
  15. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
  16. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +343 -44
  17. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
  18. package/fesm2022/c8y-ngx-components-ai.mjs +187 -75
  19. package/fesm2022/c8y-ngx-components-ai.mjs.map +1 -1
  20. package/fesm2022/c8y-ngx-components-asset-properties.mjs +11 -5
  21. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  22. package/fesm2022/{c8y-ngx-components-computed-asset-properties-alarm-count-config.component-B2cy8gI7.mjs → c8y-ngx-components-computed-asset-properties-alarm-count-config.component-CPLDClTp.mjs} +3 -3
  23. package/fesm2022/{c8y-ngx-components-computed-asset-properties-alarm-count-config.component-B2cy8gI7.mjs.map → c8y-ngx-components-computed-asset-properties-alarm-count-config.component-CPLDClTp.mjs.map} +1 -1
  24. package/fesm2022/{c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-BYHnA-5R.mjs → c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-9be_iMQg.mjs} +30 -13
  25. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-9be_iMQg.mjs.map +1 -0
  26. package/fesm2022/{c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-C4oL39m8.mjs → c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-B2em01_W.mjs} +3 -3
  27. package/fesm2022/c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-B2em01_W.mjs.map +1 -0
  28. package/fesm2022/{c8y-ngx-components-computed-asset-properties-event-count-config.component-DGwm6_C9.mjs → c8y-ngx-components-computed-asset-properties-event-count-config.component-CQuGa1RI.mjs} +3 -3
  29. package/fesm2022/c8y-ngx-components-computed-asset-properties-event-count-config.component-CQuGa1RI.mjs.map +1 -0
  30. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-BxfCjbYY.mjs → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-CkmurxJv.mjs} +5 -5
  31. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-BxfCjbYY.mjs.map → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-CkmurxJv.mjs.map} +1 -1
  32. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-CTK9zNUh.mjs +86 -0
  33. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-CTK9zNUh.mjs.map +1 -0
  34. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -1
  35. package/fesm2022/c8y-ngx-components-device-shell.mjs +1 -1
  36. package/fesm2022/c8y-ngx-components-device-shell.mjs.map +1 -1
  37. package/fesm2022/c8y-ngx-components-echart-models.mjs.map +1 -1
  38. package/fesm2022/c8y-ngx-components-echart.mjs +39 -18
  39. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  40. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs +5 -2
  41. package/fesm2022/c8y-ngx-components-events-events-timeline.mjs.map +1 -1
  42. package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs +5 -2
  43. package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs.map +1 -1
  44. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs +106 -4
  45. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs.map +1 -1
  46. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +14 -122
  47. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
  48. package/fesm2022/c8y-ngx-components.mjs +9 -5
  49. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  50. package/index.d.ts +2 -1
  51. package/index.d.ts.map +1 -1
  52. package/locales/de.po +88 -35
  53. package/locales/es.po +87 -34
  54. package/locales/fr.po +87 -34
  55. package/locales/ja_JP.po +87 -35
  56. package/locales/ko.po +88 -35
  57. package/locales/locales.pot +83 -30
  58. package/locales/nl.po +88 -35
  59. package/locales/pl.po +88 -35
  60. package/locales/pt_BR.po +87 -34
  61. package/locales/zh_CN.po +88 -35
  62. package/locales/zh_TW.po +88 -35
  63. package/operations/operations-timeline/index.d.ts +3 -2
  64. package/operations/operations-timeline/index.d.ts.map +1 -1
  65. package/package.json +1 -1
  66. package/widgets/implementations/html-widget/index.d.ts +11 -50
  67. package/widgets/implementations/html-widget/index.d.ts.map +1 -1
  68. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-BYHnA-5R.mjs.map +0 -1
  69. package/fesm2022/c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-C4oL39m8.mjs.map +0 -1
  70. package/fesm2022/c8y-ngx-components-computed-asset-properties-event-count-config.component-DGwm6_C9.mjs.map +0 -1
  71. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-C1cuxN3L.mjs +0 -92
  72. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-C1cuxN3L.mjs.map +0 -1
@@ -16,19 +16,22 @@ class EventsTimelineComponent {
16
16
  this.eventsService = eventsService;
17
17
  this.sourceId = input.required(...(ngDevMode ? [{ debugName: "sourceId" }] : []));
18
18
  this.filterPipe = pipe(tap());
19
+ this.loadMoreMode = 'auto';
19
20
  this.footerTemplates = [];
20
21
  this.propertiesToHide = [];
21
22
  }
22
23
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: EventsTimelineComponent, deps: [{ token: i1.EventRealtimeService }, { token: i2.EventsService }], target: i0.ɵɵFactoryTarget.Component }); }
23
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: EventsTimelineComponent, isStandalone: true, selector: "c8y-events-timeline", inputs: { events: { classPropertyName: "events", publicName: "events", isSignal: false, isRequired: false, transformFunction: null }, sourceId: { classPropertyName: "sourceId", publicName: "sourceId", isSignal: true, isRequired: true, transformFunction: null }, filterPipe: { classPropertyName: "filterPipe", publicName: "filterPipe", isSignal: false, isRequired: false, transformFunction: null }, bodyTemplate: { classPropertyName: "bodyTemplate", publicName: "bodyTemplate", isSignal: false, isRequired: false, transformFunction: null }, footerTemplates: { classPropertyName: "footerTemplates", publicName: "footerTemplates", isSignal: false, isRequired: false, transformFunction: null }, propertiesToHide: { classPropertyName: "propertiesToHide", publicName: "propertiesToHide", isSignal: false, isRequired: false, transformFunction: null } }, providers: [EventRealtimeService], ngImport: i0, template: "@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() }\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i1.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i1.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i1.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i1.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: i1.ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "ngmodule", type: CollapseModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: i3.JsonPipe, name: "json" }, { kind: "pipe", type: i3.DatePipe, name: "date" }, { kind: "pipe", type: i3.KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i1.HumanizePipe, name: "humanize" }] }); }
24
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: EventsTimelineComponent, isStandalone: true, selector: "c8y-events-timeline", inputs: { events: { classPropertyName: "events", publicName: "events", isSignal: false, isRequired: false, transformFunction: null }, sourceId: { classPropertyName: "sourceId", publicName: "sourceId", isSignal: true, isRequired: true, transformFunction: null }, filterPipe: { classPropertyName: "filterPipe", publicName: "filterPipe", isSignal: false, isRequired: false, transformFunction: null }, loadMoreMode: { classPropertyName: "loadMoreMode", publicName: "loadMoreMode", isSignal: false, isRequired: false, transformFunction: null }, bodyTemplate: { classPropertyName: "bodyTemplate", publicName: "bodyTemplate", isSignal: false, isRequired: false, transformFunction: null }, footerTemplates: { classPropertyName: "footerTemplates", publicName: "footerTemplates", isSignal: false, isRequired: false, transformFunction: null }, propertiesToHide: { classPropertyName: "propertiesToHide", publicName: "propertiesToHide", isSignal: false, isRequired: false, transformFunction: null } }, providers: [EventRealtimeService], ngImport: i0, template: "@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() };\n loadMore: loadMoreMode\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i1.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i1.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i1.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i1.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: i1.ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "ngmodule", type: CollapseModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: i3.JsonPipe, name: "json" }, { kind: "pipe", type: i3.DatePipe, name: "date" }, { kind: "pipe", type: i3.KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i1.HumanizePipe, name: "humanize" }] }); }
24
25
  }
25
26
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: EventsTimelineComponent, decorators: [{
26
27
  type: Component,
27
- args: [{ selector: 'c8y-events-timeline', imports: [CommonModule, CoreModule, CollapseModule, TooltipModule], providers: [EventRealtimeService], template: "@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() }\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n" }]
28
+ args: [{ selector: 'c8y-events-timeline', imports: [CommonModule, CoreModule, CollapseModule, TooltipModule], providers: [EventRealtimeService], template: "@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() };\n loadMore: loadMoreMode\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n" }]
28
29
  }], ctorParameters: () => [{ type: i1.EventRealtimeService }, { type: i2.EventsService }], propDecorators: { events: [{
29
30
  type: Input
30
31
  }], sourceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceId", required: true }] }], filterPipe: [{
31
32
  type: Input
33
+ }], loadMoreMode: [{
34
+ type: Input
32
35
  }], bodyTemplate: [{
33
36
  type: Input
34
37
  }], footerTemplates: [{
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-events-events-timeline.mjs","sources":["../../events/events-timeline/events-timeline.component.ts","../../events/events-timeline/events-timeline.component.html","../../events/events-timeline/c8y-ngx-components-events-events-timeline.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, input, Input, TemplateRef } from '@angular/core';\nimport { IEvent, IResultList } from '@c8y/client';\nimport { CoreModule, EventRealtimeService, ForOfFilterPipe } from '@c8y/ngx-components';\nimport { EventsService } from '@c8y/ngx-components/events';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { pipe } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\n@Component({\n selector: 'c8y-events-timeline',\n templateUrl: 'events-timeline.component.html',\n imports: [CommonModule, CoreModule, CollapseModule, TooltipModule],\n providers: [EventRealtimeService]\n})\nexport class EventsTimelineComponent<B, F> {\n @Input()\n events: IResultList<IEvent>;\n\n sourceId = input.required<string | number>();\n\n @Input()\n filterPipe: ForOfFilterPipe<IEvent> = pipe(tap());\n\n @Input()\n bodyTemplate: TemplateRef<B>;\n\n @Input()\n footerTemplates: Array<TemplateRef<F>> = [];\n\n @Input()\n propertiesToHide: string[] = [];\n\n constructor(\n public realtime: EventRealtimeService,\n public eventsService: EventsService\n ) {}\n}\n","@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() }\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-events-events-timeline.mjs","sources":["../../events/events-timeline/events-timeline.component.ts","../../events/events-timeline/events-timeline.component.html","../../events/events-timeline/c8y-ngx-components-events-events-timeline.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, input, Input, TemplateRef } from '@angular/core';\nimport { IEvent, IResultList } from '@c8y/client';\nimport {\n CoreModule,\n EventRealtimeService,\n ForOfFilterPipe,\n LoadMoreMode\n} from '@c8y/ngx-components';\nimport { EventsService } from '@c8y/ngx-components/events';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { pipe } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\n@Component({\n selector: 'c8y-events-timeline',\n templateUrl: 'events-timeline.component.html',\n imports: [CommonModule, CoreModule, CollapseModule, TooltipModule],\n providers: [EventRealtimeService]\n})\nexport class EventsTimelineComponent<B, F> {\n @Input()\n events: IResultList<IEvent>;\n\n sourceId = input.required<string | number>();\n\n @Input()\n filterPipe: ForOfFilterPipe<IEvent> = pipe(tap());\n\n @Input()\n loadMoreMode: LoadMoreMode = 'auto';\n\n @Input()\n bodyTemplate: TemplateRef<B>;\n\n @Input()\n footerTemplates: Array<TemplateRef<F>> = [];\n\n @Input()\n propertiesToHide: string[] = [];\n\n constructor(\n public realtime: EventRealtimeService,\n public eventsService: EventsService\n ) {}\n}\n","@if (!events?.data || !events?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'online'\"\n [title]=\"'No recent events found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let event of events;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId() };\n loadMore: loadMoreMode\n \"\n >\n {{ event.creationTime | date: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i [c8yIcon]=\"'online'\"></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div data-cy=\"c8y-events-timeline--body-template\">\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n } @else {\n <small>{{ event.text }}</small>\n }\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of eventsService.getStandardKeys(event) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ event[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of eventsService.getNonStandardKeys(event, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ event[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: event }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;MAqBa,uBAAuB,CAAA;IAqBlC,WAAA,CACS,QAA8B,EAC9B,aAA4B,EAAA;QAD5B,IAAA,CAAA,QAAQ,GAAR,QAAQ;QACR,IAAA,CAAA,aAAa,GAAb,aAAa;AAnBtB,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAC,QAAQ,mDAAmB;AAG5C,QAAA,IAAA,CAAA,UAAU,GAA4B,IAAI,CAAC,GAAG,EAAE,CAAC;QAGjD,IAAA,CAAA,YAAY,GAAiB,MAAM;QAMnC,IAAA,CAAA,eAAe,GAA0B,EAAE;QAG3C,IAAA,CAAA,gBAAgB,GAAa,EAAE;IAK5B;+GAxBQ,uBAAuB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,aAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,UAAA,EAAA,kBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,SAAA,EAFvB,CAAC,oBAAoB,CAAC,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECnBnC,y8EAkFA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDhEY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,UAAU,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,qBAAA,EAAA,uBAAA,EAAA,qBAAA,EAAA,oBAAA,EAAA,gBAAA,EAAA,uBAAA,EAAA,kBAAA,EAAA,2BAAA,EAAA,gCAAA,EAAA,6BAAA,EAAA,oCAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,cAAA,EAAA,yBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,cAAA,EAAA,OAAA,EAAA,WAAA,EAAA,YAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,yBAAA,EAAA,QAAA,EAAA,yCAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,yBAAA,EAAA,QAAA,EAAA,yCAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,cAAc,8BAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,UAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,IAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,UAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAGtD,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBANnC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,OAAA,EAEtB,CAAC,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,CAAC,EAAA,SAAA,EACvD,CAAC,oBAAoB,CAAC,EAAA,QAAA,EAAA,y8EAAA,EAAA;;sBAGhC;;sBAKA;;sBAGA;;sBAGA;;sBAGA;;sBAGA;;;AEvCH;;AAEG;;;;"}
@@ -14,12 +14,13 @@ class OperationsTimelineComponent {
14
14
  this.realtime = realtime;
15
15
  this.operationsService = operationsService;
16
16
  this.filterPipe = pipe(tap());
17
+ this.loadMoreMode = 'auto';
17
18
  this.footerTemplates = [];
18
19
  this.propertiesToHide = [];
19
20
  this.OPERATION_STATUS_OPTIONS_MAP = OPERATION_STATUS_OPTIONS_MAP;
20
21
  }
21
22
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: OperationsTimelineComponent, deps: [{ token: i1.OperationRealtimeService }, { token: i2.OperationsService }], target: i0.ɵɵFactoryTarget.Component }); }
22
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: OperationsTimelineComponent, isStandalone: true, selector: "c8y-operations-timeline", inputs: { operations: "operations", sourceId: "sourceId", filterPipe: "filterPipe", bodyTemplate: "bodyTemplate", footerTemplates: "footerTemplates", propertiesToHide: "propertiesToHide" }, ngImport: i0, template: "@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId }\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n", dependencies: [{ kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: HumanizePipe, name: "humanize" }] }); }
23
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: OperationsTimelineComponent, isStandalone: true, selector: "c8y-operations-timeline", inputs: { operations: "operations", sourceId: "sourceId", filterPipe: "filterPipe", loadMoreMode: "loadMoreMode", bodyTemplate: "bodyTemplate", footerTemplates: "footerTemplates", propertiesToHide: "propertiesToHide" }, ngImport: i0, template: "@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId };\n loadMore: loadMoreMode\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n", dependencies: [{ kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: HumanizePipe, name: "humanize" }] }); }
23
24
  }
24
25
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: OperationsTimelineComponent, decorators: [{
25
26
  type: Component,
@@ -42,13 +43,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
42
43
  KeyValuePipe,
43
44
  C8yTranslatePipe,
44
45
  HumanizePipe
45
- ], template: "@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId }\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n" }]
46
+ ], template: "@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId };\n loadMore: loadMoreMode\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n" }]
46
47
  }], ctorParameters: () => [{ type: i1.OperationRealtimeService }, { type: i2.OperationsService }], propDecorators: { operations: [{
47
48
  type: Input
48
49
  }], sourceId: [{
49
50
  type: Input
50
51
  }], filterPipe: [{
51
52
  type: Input
53
+ }], loadMoreMode: [{
54
+ type: Input
52
55
  }], bodyTemplate: [{
53
56
  type: Input
54
57
  }], footerTemplates: [{
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-operations-operations-timeline.mjs","sources":["../../operations/operations-timeline/operations-timeline.component.ts","../../operations/operations-timeline/operations-timeline.component.html","../../operations/operations-timeline/operations-timeline.module.ts","../../operations/operations-timeline/c8y-ngx-components-operations-operations-timeline.ts"],"sourcesContent":["import { JsonPipe, KeyValuePipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport { Component, Input, TemplateRef } from '@angular/core';\nimport { IOperation, IResultList } from '@c8y/client';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n DatePipe,\n EmptyStateComponent,\n ForOfDirective,\n ForOfFilterPipe,\n HumanizePipe,\n IconDirective,\n ListGroupComponent,\n ListItemBodyComponent,\n ListItemCollapseComponent,\n ListItemComponent,\n ListItemIconComponent,\n ListItemTimelineComponent,\n OperationRealtimeService\n} from '@c8y/ngx-components';\nimport {\n OPERATION_STATUS_OPTIONS_MAP,\n OperationsService,\n OperationStatusOptionsMapShared\n} from '@c8y/ngx-components/operations/shared';\nimport { TooltipDirective } from 'ngx-bootstrap/tooltip';\nimport { pipe } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\n@Component({\n selector: 'c8y-operations-timeline',\n templateUrl: 'operations-timeline.component.html',\n imports: [\n EmptyStateComponent,\n ListGroupComponent,\n ForOfDirective,\n ListItemTimelineComponent,\n ListItemComponent,\n ListItemIconComponent,\n IconDirective,\n TooltipDirective,\n NgClass,\n ListItemBodyComponent,\n NgTemplateOutlet,\n ListItemCollapseComponent,\n C8yTranslateDirective,\n JsonPipe,\n DatePipe,\n KeyValuePipe,\n C8yTranslatePipe,\n HumanizePipe\n ]\n})\nexport class OperationsTimelineComponent<B, F> {\n @Input()\n operations: IResultList<IOperation>;\n\n @Input()\n sourceId: string;\n\n @Input()\n filterPipe: ForOfFilterPipe<IOperation> = pipe(tap());\n\n @Input()\n bodyTemplate: TemplateRef<B>;\n\n @Input()\n footerTemplates: Array<TemplateRef<F>> = [];\n\n @Input()\n propertiesToHide: string[] = [];\n\n OPERATION_STATUS_OPTIONS_MAP: OperationStatusOptionsMapShared = OPERATION_STATUS_OPTIONS_MAP;\n\n constructor(\n public realtime: OperationRealtimeService,\n public operationsService: OperationsService\n ) {}\n}\n","@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId }\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n","import { NgModule } from '@angular/core';\nimport { OperationsTimelineComponent } from './operations-timeline.component';\n\n/**\n * @deprecated Use `OperationsTimelineComponent` as a standalone component instead.\n */\n@NgModule({\n imports: [OperationsTimelineComponent],\n exports: [OperationsTimelineComponent]\n})\nexport class OperationsTimelineModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;MAqDa,2BAA2B,CAAA;IAqBtC,WAAA,CACS,QAAkC,EAClC,iBAAoC,EAAA;QADpC,IAAA,CAAA,QAAQ,GAAR,QAAQ;QACR,IAAA,CAAA,iBAAiB,GAAjB,iBAAiB;AAf1B,QAAA,IAAA,CAAA,UAAU,GAAgC,IAAI,CAAC,GAAG,EAAE,CAAC;QAMrD,IAAA,CAAA,eAAe,GAA0B,EAAE;QAG3C,IAAA,CAAA,gBAAgB,GAAa,EAAE;QAE/B,IAAA,CAAA,4BAA4B,GAAoC,4BAA4B;IAKzF;+GAxBQ,2BAA2B,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,wBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA3B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,2BAA2B,iRCrDxC,4zGA0GA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDzEI,mBAAmB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACnB,kBAAkB,EAAA,QAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,cAAc,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,qBAAA,EAAA,uBAAA,EAAA,qBAAA,EAAA,oBAAA,EAAA,gBAAA,EAAA,uBAAA,EAAA,kBAAA,EAAA,2BAAA,EAAA,gCAAA,EAAA,6BAAA,EAAA,oCAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,cAAA,EAAA,yBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACd,yBAAyB,oFACzB,iBAAiB,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,cAAA,EAAA,OAAA,EAAA,WAAA,EAAA,YAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,qBAAqB,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACrB,aAAa,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACb,gBAAgB,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,SAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,YAAA,EAAA,OAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,kBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,SAAA,EAAA,UAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,OAAO,oFACP,qBAAqB,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACrB,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,yBAAyB,EAAA,QAAA,EAAA,yCAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACzB,qBAAqB,EAAA,QAAA,EAAA,6BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EACrB,QAAQ,wCACR,QAAQ,EAAA,IAAA,EAAA,SAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EACR,YAAY,EAAA,IAAA,EAAA,UAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EACZ,gBAAgB,6CAChB,YAAY,EAAA,IAAA,EAAA,UAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAGH,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBAxBvC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,EAAA,OAAA,EAE1B;wBACP,mBAAmB;wBACnB,kBAAkB;wBAClB,cAAc;wBACd,yBAAyB;wBACzB,iBAAiB;wBACjB,qBAAqB;wBACrB,aAAa;wBACb,gBAAgB;wBAChB,OAAO;wBACP,qBAAqB;wBACrB,gBAAgB;wBAChB,yBAAyB;wBACzB,qBAAqB;wBACrB,QAAQ;wBACR,QAAQ;wBACR,YAAY;wBACZ,gBAAgB;wBAChB;AACD,qBAAA,EAAA,QAAA,EAAA,4zGAAA,EAAA;;sBAGA;;sBAGA;;sBAGA;;sBAGA;;sBAGA;;sBAGA;;;AElEH;;AAEG;MAKU,wBAAwB,CAAA;+GAAxB,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;gHAAxB,wBAAwB,EAAA,OAAA,EAAA,CAHzB,2BAA2B,CAAA,EAAA,OAAA,EAAA,CAC3B,2BAA2B,CAAA,EAAA,CAAA,CAAA;AAE1B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,YAHzB,2BAA2B,CAAA,EAAA,CAAA,CAAA;;4FAG1B,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBAJpC,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,OAAO,EAAE,CAAC,2BAA2B,CAAC;oBACtC,OAAO,EAAE,CAAC,2BAA2B;AACtC,iBAAA;;;ACTD;;AAEG;;;;"}
1
+ {"version":3,"file":"c8y-ngx-components-operations-operations-timeline.mjs","sources":["../../operations/operations-timeline/operations-timeline.component.ts","../../operations/operations-timeline/operations-timeline.component.html","../../operations/operations-timeline/operations-timeline.module.ts","../../operations/operations-timeline/c8y-ngx-components-operations-operations-timeline.ts"],"sourcesContent":["import { JsonPipe, KeyValuePipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport { Component, Input, TemplateRef } from '@angular/core';\nimport { IOperation, IResultList } from '@c8y/client';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n DatePipe,\n EmptyStateComponent,\n ForOfDirective,\n ForOfFilterPipe,\n HumanizePipe,\n IconDirective,\n ListGroupComponent,\n ListItemBodyComponent,\n ListItemCollapseComponent,\n ListItemComponent,\n ListItemIconComponent,\n ListItemTimelineComponent,\n LoadMoreMode,\n OperationRealtimeService\n} from '@c8y/ngx-components';\nimport {\n OPERATION_STATUS_OPTIONS_MAP,\n OperationsService,\n OperationStatusOptionsMapShared\n} from '@c8y/ngx-components/operations/shared';\nimport { TooltipDirective } from 'ngx-bootstrap/tooltip';\nimport { pipe } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\n@Component({\n selector: 'c8y-operations-timeline',\n templateUrl: 'operations-timeline.component.html',\n imports: [\n EmptyStateComponent,\n ListGroupComponent,\n ForOfDirective,\n ListItemTimelineComponent,\n ListItemComponent,\n ListItemIconComponent,\n IconDirective,\n TooltipDirective,\n NgClass,\n ListItemBodyComponent,\n NgTemplateOutlet,\n ListItemCollapseComponent,\n C8yTranslateDirective,\n JsonPipe,\n DatePipe,\n KeyValuePipe,\n C8yTranslatePipe,\n HumanizePipe\n ]\n})\nexport class OperationsTimelineComponent<B, F> {\n @Input()\n operations: IResultList<IOperation>;\n\n @Input()\n sourceId: string;\n\n @Input()\n filterPipe: ForOfFilterPipe<IOperation> = pipe(tap());\n\n @Input()\n loadMoreMode: LoadMoreMode = 'auto';\n\n @Input()\n bodyTemplate: TemplateRef<B>;\n\n @Input()\n footerTemplates: Array<TemplateRef<F>> = [];\n\n @Input()\n propertiesToHide: string[] = [];\n\n OPERATION_STATUS_OPTIONS_MAP: OperationStatusOptionsMapShared = OPERATION_STATUS_OPTIONS_MAP;\n\n constructor(\n public realtime: OperationRealtimeService,\n public operationsService: OperationsService\n ) {}\n}\n","@if (!operations?.data || !operations?.data?.length) {\n <c8y-ui-empty-state\n [icon]=\"'c8y-energy'\"\n [title]=\"'No recent operations found.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n}\n\n<c8y-list-group>\n <c8y-li-timeline\n *c8yFor=\"\n let op of operations;\n pipe: filterPipe;\n realtime: realtime;\n realtimeOptions: { entityOrId: sourceId };\n loadMore: loadMoreMode\n \"\n >\n {{ op.creationTime | c8yDate: 'medium' }}\n\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].icon\"\n [tooltip]=\"op.status | translate\"\n container=\"body\"\n [ngClass]=\"OPERATION_STATUS_OPTIONS_MAP[op.status].styleClass\"\n [delay]=\"500\"\n ></i>\n </c8y-li-icon>\n\n <c8y-li-body>\n <div class=\"d-flex text-break-word\">\n <div>\n {{ op.status | translate }}\n <br class=\"visible-xs visible-sm\" />\n\n @if (bodyTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"bodyTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n } @else {\n <small>{{ op.description }}</small>\n }\n </div>\n\n @if (op.status === 'PENDING') {\n <div class=\"m-l-auto showOnHover\">\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.aria-label]=\"'Cancel operation' | translate\"\n tooltip=\"{{ 'Cancel operation' | translate }}\"\n placement=\"left\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); operationsService.cancel(op)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n }\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse #collapseEl>\n <div\n class=\"legend form-block\"\n translate\n >\n Details\n </div>\n\n <ul class=\"list-unstyled small\">\n @for (prop of operationsService.getStandardKeys(op) | keyvalue; track prop.key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ prop.value | translate }}\n </label>\n <span class=\"m-l-auto text-break-word\">\n {{ op[prop.key] | translate }}\n </span>\n </li>\n }\n\n @for (key of operationsService.getNonStandardKeys(op, propertiesToHide); track key) {\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom\">\n <label class=\"small m-b-0 m-r-8 a-s-start\">\n {{ key | humanize | translate }}\n </label>\n <span class=\"m-l-auto text-code\">\n {{ op[key] | json }}\n </span>\n </li>\n }\n </ul>\n\n @for (footer of footerTemplates; track footer) {\n <ng-container\n [ngTemplateOutlet]=\"footer\"\n [ngTemplateOutletContext]=\"{ $implicit: op }\"\n ></ng-container>\n }\n </c8y-li-collapse>\n </c8y-li>\n </c8y-li-timeline>\n</c8y-list-group>\n","import { NgModule } from '@angular/core';\nimport { OperationsTimelineComponent } from './operations-timeline.component';\n\n/**\n * @deprecated Use `OperationsTimelineComponent` as a standalone component instead.\n */\n@NgModule({\n imports: [OperationsTimelineComponent],\n exports: [OperationsTimelineComponent]\n})\nexport class OperationsTimelineModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -8,8 +8,10 @@ import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
8
8
  import { map, combineLatest, from, first } from 'rxjs';
9
9
  import { HTML_AGENT } from '@c8y/ngx-components/ai/agents/html';
10
10
 
11
+ // Treat as "production" when run from Jest
12
+ const mode = (typeof __MODE__ !== 'undefined' ? __MODE__ : 'production');
11
13
  const HTML_WIDGET_AGENT_DEFINITIONS = {
12
- snapshot: __MODE__ === 'development',
14
+ snapshot: mode === 'development',
13
15
  label: gettext('HTML Widget Code assistant'),
14
16
  definition: HTML_AGENT
15
17
  };
@@ -18,21 +20,28 @@ class AIHtmlWidgetConfigFactory {
18
20
  constructor() {
19
21
  this.betaPreviewService = inject(PreviewService);
20
22
  this.aiService = inject(AIService);
23
+ /** The root injector (nb: components cannot be injected from here). */
21
24
  this.injector = inject(Injector);
25
+ this.codeTag = 'c8y-code-extract';
26
+ this.codeToolName = 'c8y-html-widget-code';
27
+ this.queryToolName = 'cumulocity-api-request';
22
28
  this.widgetConfigService = inject(WidgetConfigService);
23
29
  this.aiWidgetConfigDefinition = {
24
30
  widgetId: defaultWidgetIds.HTML,
25
31
  label: gettext('AI Code Assistant'),
26
32
  loadComponent: () => import('@c8y/ngx-components/ai/agent-chat').then(m => m.WidgetAiChatSectionComponent),
27
33
  initialState: {
34
+ // configuration to pass to WidgetAiChatSectionComponent
28
35
  agent: HTML_WIDGET_AGENT_DEFINITIONS,
29
- title: gettext('I’m your AI Code Assistant, here to help you build powerful widgets for your dashboard.'),
30
- welcomeText: gettext('Describe the widget you want or select one of the options below to get started.'),
36
+ chatConfig: {
37
+ title: gettext('I’m your AI Code Assistant, here to help you build powerful widgets for your dashboard.'),
38
+ welcomeText: gettext('Describe the widget you want or select one of the options below to get started.')
39
+ },
40
+ loadComponentConfig: this.loadWidgetAiChatComponentConfig.bind(this),
31
41
  variables: this.widgetConfigService.currentConfig$.pipe(map((htmlWidgetConfig) => ({
32
42
  currentHtmlWidgetCode: htmlWidgetConfig?.config?.code || '',
33
43
  c8yContext: htmlWidgetConfig?.device || {}
34
44
  }))),
35
- loadRenderStepComponent: () => import('@c8y/ngx-components/widgets/implementations/html-widget').then(m => m.HtmlAiChatFeedbackComponent),
36
45
  suggestions: [
37
46
  {
38
47
  label: gettext('Measurement widget'),
@@ -63,6 +72,99 @@ class AIHtmlWidgetConfigFactory {
63
72
  return [];
64
73
  }));
65
74
  }
75
+ async loadWidgetAiChatComponentConfig(componentInjector) {
76
+ const { HtmlWidgetConfigService, HtmlAiChatToolDetailsComponent } = await import('@c8y/ngx-components/widgets/implementations/html-widget');
77
+ const htmlWidgetConfigService = componentInjector.get(HtmlWidgetConfigService);
78
+ return {
79
+ preprocessAgentMessage: (message, changed) => this.preprocessAgentMessage(message, changed, htmlWidgetConfigService),
80
+ assistantMessageDisplayConfig: {
81
+ toolDetailsComponent: toolCallPart => {
82
+ if (toolCallPart.toolName === this.codeToolName) {
83
+ return HtmlAiChatToolDetailsComponent;
84
+ }
85
+ return undefined;
86
+ },
87
+ toolCallConfig: {
88
+ [this.queryToolName]: {
89
+ executingLabel: gettext('Analyzing query…'),
90
+ completedLabel: gettext('Query analyzed')
91
+ },
92
+ [this.codeToolName]: {
93
+ executingLabel: gettext('Creating widget…'),
94
+ completedLabel: gettext('Widget created')
95
+ }
96
+ },
97
+ // To match current behaviour and to help with development, for now we show the JSON for all tool calls
98
+ showDefaultToolDetails: 'all'
99
+ }
100
+ };
101
+ }
102
+ applyCurrentCode(code, htmlWidgetConfigService) {
103
+ const newConfig = {
104
+ code: code,
105
+ css: '',
106
+ devMode: true,
107
+ legacy: false,
108
+ options: { advancedSecurity: false, cssEncapsulation: false }
109
+ };
110
+ htmlWidgetConfigService.configChanged$.next(newConfig);
111
+ htmlWidgetConfigService.widgetConfigService.updateConfig({ config: newConfig });
112
+ }
113
+ preprocessAgentMessage(message, changedPart, htmlWidgetConfigService) {
114
+ // Rewrite HTML content generated by the agent in as text content as if it had come from a tool call
115
+ if (!message.steps?.length)
116
+ return message;
117
+ const step = message.steps[message.steps.length - 1];
118
+ const codeToolIndex = step.toolCalls?.findIndex(tc => tc.toolName === this.codeToolName);
119
+ const codeTool = step.toolCalls?.[codeToolIndex];
120
+ if (codeTool && codeTool.type !== 'tool-result') {
121
+ // A code update tool call is in progress - accumulate text into input
122
+ const input = `${codeTool.input?.code || ''}${step.text}`;
123
+ codeTool.input.code = input;
124
+ step.text = '';
125
+ const closeIdx = input.indexOf(`</${this.codeTag}>`);
126
+ if (closeIdx !== -1) {
127
+ // Found closing tag - convert to result and start new step
128
+ const beforeClose = input.substring(0, closeIdx);
129
+ const afterClose = input.substring(closeIdx + `</${this.codeTag}>`.length);
130
+ codeTool.input.code = beforeClose;
131
+ codeTool.type = 'tool-result';
132
+ // Move it from calls to results
133
+ step.toolCalls = [];
134
+ step.toolResults = [{ ...codeTool }];
135
+ // Always create a new (fake) step after this (just like a real AI), to keep any future text and code update calls separate from this one
136
+ message.steps.push({ type: 'text', text: afterClose });
137
+ // Since this is a fake tool call not a real one, the tool result callback won't trigger so do this manually
138
+ this.applyCurrentCode(codeTool.input.code, htmlWidgetConfigService);
139
+ }
140
+ else {
141
+ // Replace with a new instance so that change detections works
142
+ step.toolCalls[codeToolIndex] = { ...codeTool };
143
+ }
144
+ }
145
+ else if (step.text) {
146
+ // No in-progress code tag, so check for one
147
+ const openIdx = step.text.indexOf(`<${this.codeTag}>`);
148
+ if (openIdx !== -1) {
149
+ const afterOpen = step.text.substring(openIdx + `<${this.codeTag}>`.length);
150
+ step.text = step.text.substring(0, openIdx);
151
+ // Start a new "step" to keep it separate and simple
152
+ message.steps.push({
153
+ type: 'text',
154
+ text: '',
155
+ toolCalls: [
156
+ {
157
+ type: 'tool-input-streaming',
158
+ toolName: this.codeToolName,
159
+ toolCallId: this.codeToolName + message.steps.length, // add step number just to ensure uniqueness
160
+ input: { code: afterOpen }
161
+ }
162
+ ]
163
+ });
164
+ }
165
+ }
166
+ return message;
167
+ }
66
168
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AIHtmlWidgetConfigFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
67
169
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AIHtmlWidgetConfigFactory, providedIn: 'root' }); }
68
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs","sources":["../../widgets/definitions/html-widget-ai-config/html-widget-agent.definitions.ts","../../widgets/definitions/html-widget-ai-config/ai-html-widget-config.factory.ts","../../widgets/definitions/html-widget-ai-config/index.ts","../../widgets/definitions/html-widget-ai-config/c8y-ngx-components-widgets-definitions-html-widget-ai-config.ts"],"sourcesContent":["import type { ClientAgentDefinition } from '@c8y/ngx-components/ai';\nimport { HTML_AGENT } from '@c8y/ngx-components/ai/agents/html';\nimport { gettext } from '@c8y/ngx-components/gettext';\n\ndeclare const __MODE__: 'development' | 'production';\n\nexport const HTML_WIDGET_AGENT_DEFINITIONS: ClientAgentDefinition = {\n snapshot: __MODE__ === 'development',\n label: gettext('HTML Widget Code assistant'),\n definition: HTML_AGENT\n};\n","import { inject, Injectable, Injector } from '@angular/core';\nimport { ExtensionFactory, PreviewService } from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AIService } from '@c8y/ngx-components/ai';\nimport type { WidgetAiChatSectionComponent } from '@c8y/ngx-components/ai/agent-chat';\nimport type { WidgetConfigSectionDefinition } from '@c8y/ngx-components/context-dashboard';\nimport { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';\nimport { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';\nimport { combineLatest, first, from, map, Observable } from 'rxjs';\nimport { HTML_WIDGET_AGENT_DEFINITIONS } from './html-widget-agent.definitions';\nimport type { HtmlWidgetConfig } from '@c8y/ngx-components/widgets/implementations/html-widget';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class AIHtmlWidgetConfigFactory implements ExtensionFactory<WidgetConfigSectionDefinition> {\n private readonly betaPreviewService = inject(PreviewService);\n private readonly aiService = inject(AIService);\n private readonly injector = inject(Injector);\n private readonly widgetConfigService = inject(WidgetConfigService);\n private readonly aiWidgetConfigDefinition: WidgetConfigSectionDefinition<WidgetAiChatSectionComponent> =\n {\n widgetId: defaultWidgetIds.HTML,\n label: gettext('AI Code Assistant'),\n loadComponent: () =>\n import('@c8y/ngx-components/ai/agent-chat').then(m => m.WidgetAiChatSectionComponent),\n initialState: {\n agent: HTML_WIDGET_AGENT_DEFINITIONS,\n title: gettext(\n 'I’m your AI Code Assistant, here to help you build powerful widgets for your dashboard.'\n ),\n welcomeText: gettext(\n 'Describe the widget you want or select one of the options below to get started.'\n ),\n\n variables: this.widgetConfigService.currentConfig$.pipe(\n map((htmlWidgetConfig: HtmlWidgetConfig) => ({\n currentHtmlWidgetCode: htmlWidgetConfig?.config?.code || '',\n c8yContext: htmlWidgetConfig?.device || {}\n }))\n ),\n\n loadRenderStepComponent: () =>\n import('@c8y/ngx-components/widgets/implementations/html-widget').then(\n m => m.HtmlAiChatFeedbackComponent\n ),\n\n suggestions: [\n {\n label: gettext('Measurement widget'),\n prompt: gettext('Create a widget that shows the current measurement of this device.')\n },\n {\n label: gettext('Device status widget'),\n prompt: gettext('Create a widget that shows the status of my devices.')\n },\n {\n label: gettext('Critical alarm widget'),\n prompt: gettext('Create a widget that shows all critical alarms.')\n }\n ]\n },\n priority: 100,\n injector: this.injector\n };\n\n get(): Observable<WidgetConfigSectionDefinition[]> {\n return combineLatest([\n from(this.aiService.getAgentHealth()),\n this.betaPreviewService.getState$('ui.html-widget.v2').pipe(first())\n ]).pipe(\n map(([aiHealthCheck, state]) => {\n if (state && aiHealthCheck.isProviderConfigured) {\n return [this.aiWidgetConfigDefinition];\n }\n return [];\n })\n );\n }\n}\n","import { hookWidgetConfig } from '@c8y/ngx-components/context-dashboard';\nimport { AIHtmlWidgetConfigFactory } from './ai-html-widget-config.factory';\n\nexport const htmlWidgetAIChatProviders = [hookWidgetConfig(AIHtmlWidgetConfigFactory)];\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs","sources":["../../widgets/definitions/html-widget-ai-config/html-widget-agent.definitions.ts","../../widgets/definitions/html-widget-ai-config/ai-html-widget-config.factory.ts","../../widgets/definitions/html-widget-ai-config/index.ts","../../widgets/definitions/html-widget-ai-config/c8y-ngx-components-widgets-definitions-html-widget-ai-config.ts"],"sourcesContent":["import type { ClientAgentDefinition } from '@c8y/ngx-components/ai';\nimport { HTML_AGENT } from '@c8y/ngx-components/ai/agents/html';\nimport { gettext } from '@c8y/ngx-components/gettext';\n\ndeclare const __MODE__: 'development' | 'production' | undefined;\n\n// Treat as \"production\" when run from Jest\nconst mode = (typeof __MODE__ !== 'undefined' ? __MODE__ : 'production') as\n | 'development'\n | 'production';\n\nexport const HTML_WIDGET_AGENT_DEFINITIONS: ClientAgentDefinition = {\n snapshot: mode === 'development',\n label: gettext('HTML Widget Code assistant'),\n definition: HTML_AGENT\n};\n","import { inject, Injectable, Injector } from '@angular/core';\nimport { ExtensionFactory, PreviewService } from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport {\n AIMessage,\n AIService,\n AIStreamResponse,\n WidgetAiChatSectionComponentConfig,\n ToolCallPart\n} from '@c8y/ngx-components/ai';\nimport { WidgetAiChatSectionComponent } from '@c8y/ngx-components/ai/agent-chat';\nimport type { WidgetConfigSectionDefinition } from '@c8y/ngx-components/context-dashboard';\nimport { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';\nimport { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';\nimport { combineLatest, first, from, map, Observable } from 'rxjs';\nimport { HTML_WIDGET_AGENT_DEFINITIONS } from './html-widget-agent.definitions';\nimport type {\n HtmlWidgetConfig,\n HtmlWidgetConfigService\n} from '@c8y/ngx-components/widgets/implementations/html-widget';\n\ntype CodeChangeToolCall = ToolCallPart<{ code: string }>;\n\n@Injectable({\n providedIn: 'root'\n})\nexport class AIHtmlWidgetConfigFactory implements ExtensionFactory<WidgetConfigSectionDefinition> {\n private readonly betaPreviewService = inject(PreviewService);\n private readonly aiService = inject(AIService);\n /** The root injector (nb: components cannot be injected from here). */\n private readonly injector = inject(Injector);\n\n private readonly codeTag = 'c8y-code-extract';\n private readonly codeToolName = 'c8y-html-widget-code';\n private readonly queryToolName = 'cumulocity-api-request';\n private readonly widgetConfigService = inject(WidgetConfigService);\n\n private readonly aiWidgetConfigDefinition: WidgetConfigSectionDefinition<WidgetAiChatSectionComponent> =\n {\n widgetId: defaultWidgetIds.HTML,\n label: gettext('AI Code Assistant'),\n loadComponent: () =>\n import('@c8y/ngx-components/ai/agent-chat').then(m => m.WidgetAiChatSectionComponent),\n initialState: {\n // configuration to pass to WidgetAiChatSectionComponent\n agent: HTML_WIDGET_AGENT_DEFINITIONS,\n chatConfig: {\n title: gettext(\n 'I’m your AI Code Assistant, here to help you build powerful widgets for your dashboard.'\n ),\n welcomeText: gettext(\n 'Describe the widget you want or select one of the options below to get started.'\n )\n },\n\n loadComponentConfig: this.loadWidgetAiChatComponentConfig.bind(this),\n\n variables: this.widgetConfigService.currentConfig$.pipe(\n map((htmlWidgetConfig: HtmlWidgetConfig) => ({\n currentHtmlWidgetCode: htmlWidgetConfig?.config?.code || '',\n c8yContext: htmlWidgetConfig?.device || {}\n }))\n ),\n\n suggestions: [\n {\n label: gettext('Measurement widget'),\n prompt: gettext('Create a widget that shows the current measurement of this device.')\n },\n {\n label: gettext('Device status widget'),\n prompt: gettext('Create a widget that shows the status of my devices.')\n },\n {\n label: gettext('Critical alarm widget'),\n prompt: gettext('Create a widget that shows all critical alarms.')\n }\n ]\n },\n priority: 100,\n injector: this.injector\n };\n\n get(): Observable<WidgetConfigSectionDefinition[]> {\n return combineLatest([\n from(this.aiService.getAgentHealth()),\n this.betaPreviewService.getState$('ui.html-widget.v2').pipe(first())\n ]).pipe(\n map(([aiHealthCheck, state]) => {\n if (state && aiHealthCheck.isProviderConfigured) {\n return [this.aiWidgetConfigDefinition];\n }\n return [];\n })\n );\n }\n\n private async loadWidgetAiChatComponentConfig(\n componentInjector: Injector\n ): Promise<WidgetAiChatSectionComponentConfig> {\n const { HtmlWidgetConfigService, HtmlAiChatToolDetailsComponent } = await import(\n '@c8y/ngx-components/widgets/implementations/html-widget'\n );\n const htmlWidgetConfigService = componentInjector.get(HtmlWidgetConfigService);\n\n return {\n preprocessAgentMessage: (message, changed) =>\n this.preprocessAgentMessage(message, changed, htmlWidgetConfigService),\n\n assistantMessageDisplayConfig: {\n toolDetailsComponent: toolCallPart => {\n if (toolCallPart.toolName === this.codeToolName) {\n return HtmlAiChatToolDetailsComponent;\n }\n return undefined;\n },\n\n toolCallConfig: {\n [this.queryToolName]: {\n executingLabel: gettext('Analyzing query…'),\n completedLabel: gettext('Query analyzed')\n },\n [this.codeToolName]: {\n executingLabel: gettext('Creating widget…'),\n completedLabel: gettext('Widget created')\n }\n },\n // To match current behaviour and to help with development, for now we show the JSON for all tool calls\n showDefaultToolDetails: 'all'\n }\n };\n }\n\n private applyCurrentCode(code: string, htmlWidgetConfigService: HtmlWidgetConfigService) {\n const newConfig = {\n code: code,\n css: '',\n devMode: true,\n legacy: false,\n options: { advancedSecurity: false, cssEncapsulation: false }\n };\n htmlWidgetConfigService.configChanged$.next(newConfig);\n htmlWidgetConfigService.widgetConfigService.updateConfig({ config: newConfig });\n }\n\n protected preprocessAgentMessage(\n message: AIMessage,\n changedPart: AIStreamResponse['changedPart'],\n htmlWidgetConfigService: HtmlWidgetConfigService\n ): AIMessage {\n // Rewrite HTML content generated by the agent in as text content as if it had come from a tool call\n\n if (!message.steps?.length) return message;\n\n const step = message.steps[message.steps.length - 1];\n const codeToolIndex = step.toolCalls?.findIndex(tc => tc.toolName === this.codeToolName);\n const codeTool = step.toolCalls?.[codeToolIndex] as CodeChangeToolCall | undefined;\n\n if (codeTool && codeTool.type !== 'tool-result') {\n // A code update tool call is in progress - accumulate text into input\n const input = `${codeTool.input?.code || ''}${step.text}`;\n codeTool.input.code = input;\n step.text = '';\n\n const closeIdx = input.indexOf(`</${this.codeTag}>`);\n if (closeIdx !== -1) {\n // Found closing tag - convert to result and start new step\n const beforeClose = input.substring(0, closeIdx);\n const afterClose = input.substring(closeIdx + `</${this.codeTag}>`.length);\n\n codeTool.input.code = beforeClose;\n codeTool.type = 'tool-result';\n // Move it from calls to results\n step.toolCalls = [];\n step.toolResults = [{ ...codeTool }];\n\n // Always create a new (fake) step after this (just like a real AI), to keep any future text and code update calls separate from this one\n message.steps.push({ type: 'text', text: afterClose });\n\n // Since this is a fake tool call not a real one, the tool result callback won't trigger so do this manually\n this.applyCurrentCode(codeTool.input.code, htmlWidgetConfigService);\n } else {\n // Replace with a new instance so that change detections works\n step.toolCalls[codeToolIndex] = { ...codeTool };\n }\n } else if (step.text) {\n // No in-progress code tag, so check for one\n const openIdx = step.text.indexOf(`<${this.codeTag}>`);\n if (openIdx !== -1) {\n const afterOpen = step.text.substring(openIdx + `<${this.codeTag}>`.length);\n step.text = step.text.substring(0, openIdx);\n\n // Start a new \"step\" to keep it separate and simple\n message.steps.push({\n type: 'text',\n text: '',\n toolCalls: [\n {\n type: 'tool-input-streaming',\n toolName: this.codeToolName,\n toolCallId: this.codeToolName + message.steps.length, // add step number just to ensure uniqueness\n input: { code: afterOpen }\n } satisfies CodeChangeToolCall\n ]\n });\n }\n }\n\n return message;\n }\n}\n","import { hookWidgetConfig } from '@c8y/ngx-components/context-dashboard';\nimport { AIHtmlWidgetConfigFactory } from './ai-html-widget-config.factory';\n\nexport const htmlWidgetAIChatProviders = [hookWidgetConfig(AIHtmlWidgetConfigFactory)];\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}