@c8y/ngx-components 1023.14.186 → 1023.14.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { output, inject, Component, Injectable, Pipe, input, signal, ViewChild } from '@angular/core';
2
+ import { output, inject, Component, Injectable, Pipe, input, signal, computed, ViewChild } from '@angular/core';
3
+ import { toSignal } from '@angular/core/rxjs-interop';
3
4
  import { gettext } from '@c8y/ngx-components/gettext';
4
5
  import * as i2 from '@c8y/ngx-components';
5
6
  import { ValidationPattern, ChangeIconComponent, FormGroupComponent, MessagesComponent, MessageDirective, C8yTranslatePipe, DocsService, NavigatorService, sortByPriority, DashboardChildComponent, AppSwitcherService, AppHrefPipe, HumanizeAppNamePipe, AppIconComponent, EmptyStateComponent, IconDirective, FormsModule, ListGroupModule, DynamicFormsModule, C8yTranslateModule, ModalService, InterAppService, SupportedApps, Status, DashboardComponent } from '@c8y/ngx-components';
@@ -13,12 +14,12 @@ import * as i4$1 from 'ngx-bootstrap/collapse';
13
14
  import { CollapseModule } from 'ngx-bootstrap/collapse';
14
15
  import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
15
16
  import * as i1 from '@angular/forms';
16
- import { FormBuilder, Validators, ReactiveFormsModule, FormsModule as FormsModule$1 } from '@angular/forms';
17
+ import { FormBuilder, Validators, ReactiveFormsModule, NgForm, ControlContainer } from '@angular/forms';
17
18
  import { IconSelectorService } from '@c8y/ngx-components/icon-selector';
18
19
  import { combineLatest, of, take, firstValueFrom, Subject, switchMap as switchMap$1, lastValueFrom, forkJoin } from 'rxjs';
19
20
  import { isEmpty } from 'lodash';
20
- import { map, switchMap, combineLatestWith, debounceTime, takeUntil } from 'rxjs/operators';
21
- import { ContextDashboardService, WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
21
+ import { map, switchMap, combineLatestWith } from 'rxjs/operators';
22
+ import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
22
23
  import * as i3 from '@angular/cdk/drag-drop';
23
24
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
24
25
  import { TranslateService } from '@ngx-translate/core';
@@ -537,7 +538,7 @@ class QuickLinksWidgetViewComponent {
537
538
  : this.dashboardChild['data']?.name;
538
539
  }
539
540
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: QuickLinksWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
540
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: QuickLinksWidgetViewComponent, isStandalone: true, selector: "c8y-quick-links-widget-view", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isPreview: { classPropertyName: "isPreview", publicName: "isPreview", isSignal: true, isRequired: false, transformFunction: null } }, providers: [AppHrefPipe, HumanizeAppNamePipe, RelativeUrlParserPipe], ngImport: i0, template: "@let links = config().links;\n@let pointerNoneStylesPreview = isPreview() ? { 'pointer-events': 'none' } : null;\n\n@if (config().displayOption === DisplayOption.GRID) {\n @if (links?.length) {\n <div class=\"card-group-block interact-grid border-top m-b-0\">\n @for (link of links; track link) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"card card--btn pointer\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n [ngClass]=\"{\n disabled: isPreview()\n }\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-card\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.newTab && !isPreview()) {\n <div\n class=\"card-actions showOnHover\"\n title=\"{{ 'Open in new tab' | translate }}\"\n >\n <span class=\"dropdown-toggle c8y-dropdown\">\n <i c8yIcon=\"external-link\"></i>\n </span>\n </div>\n }\n\n <div class=\"card-block text-center\">\n <div class=\"icon-32\">\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n </div>\n <small class=\"text-muted\">\n {{ linkLabel }}\n </small>\n </div>\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n} @else {\n @if (links?.length) {\n <div class=\"separator-top\">\n @for (link of links; track link) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"d-flex a-i-center btn-clean gap-8 p-16 text-truncate separator-bottom\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-list-item\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor icon-24\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n\n <span\n class=\"text-truncate\"\n [title]=\"linkLabel\"\n >\n {{ linkLabel }}\n </span>\n @if (link.newTab) {\n <i\n class=\"text-muted m-l-auto showOnHover\"\n [c8yIcon]=\"'external-link'\"\n title=\"{{ 'Open in new tab' | translate }}\"\n ></i>\n }\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: RelativeUrlParserPipe, name: "relativeUrlParser" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
541
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: QuickLinksWidgetViewComponent, isStandalone: true, selector: "c8y-quick-links-widget-view", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isPreview: { classPropertyName: "isPreview", publicName: "isPreview", isSignal: true, isRequired: false, transformFunction: null } }, providers: [AppHrefPipe, HumanizeAppNamePipe, RelativeUrlParserPipe], ngImport: i0, template: "@let links = config().links;\n@let pointerNoneStylesPreview = isPreview() ? { 'pointer-events': 'none' } : null;\n\n@if (config().displayOption === DisplayOption.GRID) {\n @if (links?.length) {\n <div class=\"card-group-block interact-grid border-top m-b-0\">\n @for (link of links; track $index) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"card card--btn pointer\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n [ngClass]=\"{\n disabled: isPreview()\n }\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-card\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.newTab && !isPreview()) {\n <div\n class=\"card-actions showOnHover\"\n title=\"{{ 'Open in new tab' | translate }}\"\n >\n <span class=\"dropdown-toggle c8y-dropdown\">\n <i c8yIcon=\"external-link\"></i>\n </span>\n </div>\n }\n\n <div class=\"card-block text-center\">\n <div class=\"icon-32\">\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n </div>\n <small class=\"text-muted\">\n {{ linkLabel }}\n </small>\n </div>\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n} @else {\n @if (links?.length) {\n <div class=\"separator-top\">\n @for (link of links; track $index) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"d-flex a-i-center btn-clean gap-8 p-16 text-truncate separator-bottom\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-list-item\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor icon-24\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n\n <span\n class=\"text-truncate\"\n [title]=\"linkLabel\"\n >\n {{ linkLabel }}\n </span>\n @if (link.newTab) {\n <i\n class=\"text-muted m-l-auto showOnHover\"\n [c8yIcon]=\"'external-link'\"\n title=\"{{ 'Open in new tab' | translate }}\"\n ></i>\n }\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: RelativeUrlParserPipe, name: "relativeUrlParser" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
541
542
  }
542
543
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: QuickLinksWidgetViewComponent, decorators: [{
543
544
  type: Component,
@@ -548,7 +549,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
548
549
  EmptyStateComponent,
549
550
  IconDirective,
550
551
  C8yTranslatePipe
551
- ], providers: [AppHrefPipe, HumanizeAppNamePipe, RelativeUrlParserPipe], template: "@let links = config().links;\n@let pointerNoneStylesPreview = isPreview() ? { 'pointer-events': 'none' } : null;\n\n@if (config().displayOption === DisplayOption.GRID) {\n @if (links?.length) {\n <div class=\"card-group-block interact-grid border-top m-b-0\">\n @for (link of links; track link) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"card card--btn pointer\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n [ngClass]=\"{\n disabled: isPreview()\n }\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-card\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.newTab && !isPreview()) {\n <div\n class=\"card-actions showOnHover\"\n title=\"{{ 'Open in new tab' | translate }}\"\n >\n <span class=\"dropdown-toggle c8y-dropdown\">\n <i c8yIcon=\"external-link\"></i>\n </span>\n </div>\n }\n\n <div class=\"card-block text-center\">\n <div class=\"icon-32\">\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n </div>\n <small class=\"text-muted\">\n {{ linkLabel }}\n </small>\n </div>\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n} @else {\n @if (links?.length) {\n <div class=\"separator-top\">\n @for (link of links; track link) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"d-flex a-i-center btn-clean gap-8 p-16 text-truncate separator-bottom\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-list-item\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor icon-24\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n\n <span\n class=\"text-truncate\"\n [title]=\"linkLabel\"\n >\n {{ linkLabel }}\n </span>\n @if (link.newTab) {\n <i\n class=\"text-muted m-l-auto showOnHover\"\n [c8yIcon]=\"'external-link'\"\n title=\"{{ 'Open in new tab' | translate }}\"\n ></i>\n }\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n}\n" }]
552
+ ], providers: [AppHrefPipe, HumanizeAppNamePipe, RelativeUrlParserPipe], template: "@let links = config().links;\n@let pointerNoneStylesPreview = isPreview() ? { 'pointer-events': 'none' } : null;\n\n@if (config().displayOption === DisplayOption.GRID) {\n @if (links?.length) {\n <div class=\"card-group-block interact-grid border-top m-b-0\">\n @for (link of links; track $index) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"card card--btn pointer\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n [ngClass]=\"{\n disabled: isPreview()\n }\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-card\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.newTab && !isPreview()) {\n <div\n class=\"card-actions showOnHover\"\n title=\"{{ 'Open in new tab' | translate }}\"\n >\n <span class=\"dropdown-toggle c8y-dropdown\">\n <i c8yIcon=\"external-link\"></i>\n </span>\n </div>\n }\n\n <div class=\"card-block text-center\">\n <div class=\"icon-32\">\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n </div>\n <small class=\"text-muted\">\n {{ linkLabel }}\n </small>\n </div>\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n} @else {\n @if (links?.length) {\n <div class=\"separator-top\">\n @for (link of links; track $index) {\n @let linkLabel = config().translateLinkLabels ? (link.label | translate) : link.label;\n <a\n class=\"d-flex a-i-center btn-clean gap-8 p-16 text-truncate separator-bottom\"\n [ngStyle]=\"pointerNoneStylesPreview\"\n [title]=\"linkLabel\"\n data-cy=\"c8y-quick-links-widget-view--quick-link-list-item\"\n [attr.role]=\"isPreview() ? null : 'button'\"\n [target]=\"!isPreview() && link.newTab ? '_blank' : '_self'\"\n [attr.rel]=\"isPreview() ? null : 'noopener noreferrer'\"\n [attr.href]=\"isPreview() ? null : (link.url | relativeUrlParser)\"\n >\n @if (link.icon) {\n <i\n class=\"c8y-icon-duocolor icon-24\"\n [c8yIcon]=\"link.icon\"\n ></i>\n } @else {\n <c8y-app-icon\n [name]=\"link.app.name\"\n [app]=\"link.app\"\n [contextPath]=\"link.app.contextPath\"\n ></c8y-app-icon>\n }\n\n <span\n class=\"text-truncate\"\n [title]=\"linkLabel\"\n >\n {{ linkLabel }}\n </span>\n @if (link.newTab) {\n <i\n class=\"text-muted m-l-auto showOnHover\"\n [c8yIcon]=\"'external-link'\"\n title=\"{{ 'Open in new tab' | translate }}\"\n ></i>\n }\n </a>\n }\n </div>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n}\n" }]
552
553
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], isPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "isPreview", required: false }] }] } });
553
554
 
554
555
  class QuickLinksWidgetConfigListComponent {
@@ -560,8 +561,13 @@ class QuickLinksWidgetConfigListComponent {
560
561
  this.iconSelector = inject(IconSelectorService);
561
562
  }
562
563
  drop(event) {
564
+ const formArray = this.quickLinksFormArray();
565
+ // Reorder through the FormArray API so the same control instances are preserved
566
+ // (stable `@for` identity) and value/validity/valueChanges stay in sync for the preview.
567
+ const control = formArray.at(event.previousIndex);
568
+ formArray.removeAt(event.previousIndex);
569
+ formArray.insert(event.currentIndex, control);
563
570
  moveItemInArray(this.config().links, event.previousIndex, event.currentIndex);
564
- moveItemInArray(this.quickLinksFormArray().controls, event.previousIndex, event.currentIndex);
565
571
  }
566
572
  async changeLinkIcon(linkForm) {
567
573
  try {
@@ -613,7 +619,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
613
619
  class QuickLinksWidgetConfigComponent {
614
620
  constructor() {
615
621
  this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
616
- this.selectedDisplayOption = DEFAULT_DISPLAY_OPTION_VALUE;
617
622
  this.appsNameChanged = signal([], ...(ngDevMode ? [{ debugName: "appsNameChanged" }] : []));
618
623
  this.addLinkIsCollapsed = true;
619
624
  this.destroy$ = new Subject();
@@ -626,9 +631,26 @@ class QuickLinksWidgetConfigComponent {
626
631
  this.humanizeAppNamePipe = inject(HumanizeAppNamePipe);
627
632
  this.interAppService = inject(InterAppService);
628
633
  this.formBuilder = inject(FormBuilder);
629
- this.contextDashboardService = inject(ContextDashboardService);
630
634
  this.translateService = inject(TranslateService);
631
635
  this.widgetConfigService = inject(WidgetConfigService);
636
+ this.form = inject(NgForm);
637
+ this.quickLinksForm = this.initForm();
638
+ /** Live snapshot of the config form value; single source of truth for the preview. */
639
+ this.formValue = toSignal(this.quickLinksForm.valueChanges, {
640
+ initialValue: this.quickLinksForm.getRawValue()
641
+ });
642
+ /**
643
+ * Preview config derived purely from the form. Recomputes automatically on any
644
+ * form change (links, order, display option, translate toggle) — no manual refresh.
645
+ */
646
+ this.previewConfig = computed(() => {
647
+ const value = this.formValue();
648
+ return {
649
+ links: (value?.quickLinks ?? []),
650
+ displayOption: (value?.displayOption ?? DEFAULT_DISPLAY_OPTION_VALUE),
651
+ translateLinkLabels: value?.translateLinkLabels ?? false
652
+ };
653
+ }, ...(ngDevMode ? [{ debugName: "previewConfig" }] : []));
632
654
  }
633
655
  set previewSet(template) {
634
656
  if (template) {
@@ -640,12 +662,19 @@ class QuickLinksWidgetConfigComponent {
640
662
  get quickLinksFormArray() {
641
663
  return this.quickLinksForm.get('quickLinks');
642
664
  }
665
+ get displayOptionControl() {
666
+ return this.quickLinksForm.get('displayOption');
667
+ }
668
+ get translateLinkLabelsControl() {
669
+ return this.quickLinksForm.get('translateLinkLabels');
670
+ }
643
671
  ngOnInit() {
644
672
  this.onInitConfig();
645
673
  }
646
674
  ngOnDestroy() {
647
675
  this.destroy$.next();
648
676
  this.destroy$.complete();
677
+ this.form.form.removeControl('quickLinks');
649
678
  }
650
679
  getQuickLinks() {
651
680
  return this.quickLinksForm.getRawValue().quickLinks;
@@ -669,10 +698,15 @@ class QuickLinksWidgetConfigComponent {
669
698
  this.config().links = this.getQuickLinks();
670
699
  }
671
700
  async onBeforeSave(config) {
701
+ if (!this.quickLinksForm.valid) {
702
+ return false;
703
+ }
672
704
  try {
673
705
  await this.confirmAppIconChanges();
706
+ const { displayOption, translateLinkLabels } = this.quickLinksForm.getRawValue();
674
707
  config.links = this.getQuickLinks();
675
- config.displayOption = this.selectedDisplayOption;
708
+ config.displayOption = displayOption;
709
+ config.translateLinkLabels = translateLinkLabels;
676
710
  return true;
677
711
  }
678
712
  catch {
@@ -688,7 +722,7 @@ class QuickLinksWidgetConfigComponent {
688
722
  .subscribe(quickLinks => (this.config().links = quickLinks));
689
723
  }
690
724
  resetLinks() {
691
- this.quickLinksForm = this.initForm();
725
+ this.quickLinksFormArray.clear();
692
726
  this.assignLinksToConfig();
693
727
  this.config().links.forEach(link => this.addQuickLink(link));
694
728
  }
@@ -697,18 +731,14 @@ class QuickLinksWidgetConfigComponent {
697
731
  if (!this.config().links) {
698
732
  this.assignLinksToConfig();
699
733
  }
734
+ this.quickLinksForm.patchValue({
735
+ displayOption: this.config().displayOption ?? DEFAULT_DISPLAY_OPTION_VALUE,
736
+ translateLinkLabels: this.config().translateLinkLabels ?? false
737
+ });
700
738
  this.config().links.forEach(link => this.addQuickLink(link));
701
- if (!this.config().displayOption) {
702
- this.config().displayOption = this.selectedDisplayOption;
703
- return;
704
- }
705
- this.selectedDisplayOption = this.config().displayOption;
706
739
  }
707
740
  setupQuickLinksForm() {
708
- this.quickLinksForm = this.initForm();
709
- this.quickLinksForm.statusChanges
710
- .pipe(debounceTime(30), takeUntil(this.destroy$))
711
- .subscribe(status => (this.contextDashboardService.formDisabled$ = of(status === 'INVALID')));
741
+ this.form.form.addControl('quickLinks', this.quickLinksForm);
712
742
  }
713
743
  async confirmAppIconChanges() {
714
744
  if (this.appsNameChanged().length > 0) {
@@ -724,11 +754,13 @@ class QuickLinksWidgetConfigComponent {
724
754
  }
725
755
  initForm() {
726
756
  return this.formBuilder.group({
757
+ displayOption: [DEFAULT_DISPLAY_OPTION_VALUE],
758
+ translateLinkLabels: [false],
727
759
  quickLinks: this.formBuilder.array([])
728
760
  });
729
761
  }
730
762
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: QuickLinksWidgetConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
731
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: QuickLinksWidgetConfigComponent, isStandalone: true, selector: "c8y-quick-links-widget-config", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DashboardChildComponent, DashboardComponent], viewQueries: [{ propertyName: "previewSet", first: true, predicate: ["quickLinksPreview"], descendants: true }], ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'General' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <label class=\"m-b-0 text-label-small\">{{ 'Display as' | translate }}</label>\n <div class=\"c8y-select-wrapper form-group-sm\">\n <select\n class=\"form-control\"\n title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n [(ngModel)]=\"selectedDisplayOption\"\n >\n <option [value]=\"DisplayOption.GRID\">\n {{ DisplayOption.GRID | translate }}\n </option>\n <option [value]=\"DisplayOption.LIST\">\n {{ DisplayOption.LIST | translate }}\n </option>\n </select>\n </div>\n <label\n class=\"c8y-checkbox m-l-auto\"\n title=\"{{ 'Translate labels if possible' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [(ngModel)]=\"config().translateLinkLabels\"\n />\n <span></span>\n <span>{{ 'Translate labels if possible' | translate }}</span>\n </label>\n </div>\n</fieldset>\n\n<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Links' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Add a quick link' | translate }}\"\n type=\"button\"\n (click)=\"addLinkIsCollapsed = !addLinkIsCollapsed\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add a quick link' | translate }}\n </button>\n\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Reset links' | translate }}\"\n [popover]=\"confirmPopover\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [outsideClick]=\"true\"\n #pop=\"bs-popover\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n {{ 'Reset links' | translate }}\n </button>\n <ng-template #confirmPopover>\n <p class=\"m-b-8\">\n {{\n 'Resetting links removes all custom links and resets the widget to its default state.'\n | translate\n }}\n </p>\n <button\n class=\"btn btn-default btn-sm\"\n (click)=\"pop.hide()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"resetLinks(); pop.hide()\"\n >\n {{ 'Reset links' | translate }}\n </button>\n </ng-template>\n </div>\n <div\n class=\"collapse bg.component\"\n #collapse=\"bs-collapse\"\n [collapse]=\"addLinkIsCollapsed\"\n [isAnimated]=\"true\"\n >\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Add a quick link' | translate }}</legend>\n <c8y-quick-links-widget-config-add-link\n class=\"d-block p-b-16 p-l-8 p-r-8\"\n (onQuickLinkCreated)=\"addQuickLink($event); addLinkIsCollapsed = true\"\n (onCancel)=\"addLinkIsCollapsed = true\"\n ></c8y-quick-links-widget-config-add-link>\n </fieldset>\n </div>\n\n @if (config().links.length) {\n <c8y-quick-links-widget-config-list\n class=\"separator-top\"\n [quickLinksForm]=\"quickLinksForm\"\n [config]=\"config()\"\n [quickLinksFormArray]=\"quickLinksFormArray\"\n [appsNameChanged]=\"appsNameChanged\"\n ></c8y-quick-links-widget-config-list>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display' | translate\"\n [horizontal]=\"true\"\n >\n <div>\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Reset links' | translate }}\"\n type=\"button\"\n (click)=\"resetLinks()\"\n translate\n >\n Reset links\n </button>\n </div>\n </c8y-ui-empty-state>\n }\n</fieldset>\n\n<ng-template #quickLinksPreview>\n <c8y-quick-links-widget-view\n [config]=\"{\n links: getQuickLinks(),\n displayOption: selectedDisplayOption,\n translateLinkLabels: config().translateLinkLabels\n }\"\n [isPreview]=\"true\"\n ></c8y-quick-links-widget-view>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: QuickLinksWidgetConfigAddLinkComponent, selector: "c8y-quick-links-widget-config-add-link", outputs: ["onQuickLinkCreated", "onCancel"] }, { kind: "component", type: QuickLinksWidgetViewComponent, selector: "c8y-quick-links-widget-view", inputs: ["config", "isPreview"] }, { kind: "component", type: QuickLinksWidgetConfigListComponent, selector: "c8y-quick-links-widget-config-list", inputs: ["quickLinksForm", "config", "quickLinksFormArray", "appsNameChanged"] }, { kind: "ngmodule", type: C8yTranslateModule }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i4$1.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
763
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: QuickLinksWidgetConfigComponent, isStandalone: true, selector: "c8y-quick-links-widget-config", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, providers: [DashboardChildComponent, DashboardComponent], viewQueries: [{ propertyName: "previewSet", first: true, predicate: ["quickLinksPreview"], descendants: true }], ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'General' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <label class=\"m-b-0 text-label-small\">{{ 'Display as' | translate }}</label>\n <div class=\"c8y-select-wrapper form-group-sm\">\n <select\n class=\"form-control\"\n title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n [formControl]=\"displayOptionControl\"\n >\n <option [value]=\"DisplayOption.GRID\">\n {{ DisplayOption.GRID | translate }}\n </option>\n <option [value]=\"DisplayOption.LIST\">\n {{ DisplayOption.LIST | translate }}\n </option>\n </select>\n </div>\n <label\n class=\"c8y-checkbox m-l-auto\"\n title=\"{{ 'Translate labels if possible' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [formControl]=\"translateLinkLabelsControl\"\n />\n <span></span>\n <span>{{ 'Translate labels if possible' | translate }}</span>\n </label>\n </div>\n</fieldset>\n\n<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Links' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Add a quick link' | translate }}\"\n type=\"button\"\n (click)=\"addLinkIsCollapsed = !addLinkIsCollapsed\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add a quick link' | translate }}\n </button>\n\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Reset links' | translate }}\"\n [popover]=\"confirmPopover\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [outsideClick]=\"true\"\n #pop=\"bs-popover\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n {{ 'Reset links' | translate }}\n </button>\n <ng-template #confirmPopover>\n <p class=\"m-b-8\">\n {{\n 'Resetting links removes all custom links and resets the widget to its default state.'\n | translate\n }}\n </p>\n <button\n class=\"btn btn-default btn-sm\"\n (click)=\"pop.hide()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"resetLinks(); pop.hide()\"\n >\n {{ 'Reset links' | translate }}\n </button>\n </ng-template>\n </div>\n <div\n class=\"collapse bg.component\"\n #collapse=\"bs-collapse\"\n [collapse]=\"addLinkIsCollapsed\"\n [isAnimated]=\"true\"\n >\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Add a quick link' | translate }}</legend>\n <c8y-quick-links-widget-config-add-link\n class=\"d-block p-b-16 p-l-8 p-r-8\"\n (onQuickLinkCreated)=\"addQuickLink($event); addLinkIsCollapsed = true\"\n (onCancel)=\"addLinkIsCollapsed = true\"\n ></c8y-quick-links-widget-config-add-link>\n </fieldset>\n </div>\n\n @if (config().links.length) {\n <c8y-quick-links-widget-config-list\n class=\"separator-top\"\n [quickLinksForm]=\"quickLinksForm\"\n [config]=\"config()\"\n [quickLinksFormArray]=\"quickLinksFormArray\"\n [appsNameChanged]=\"appsNameChanged\"\n ></c8y-quick-links-widget-config-list>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display' | translate\"\n [horizontal]=\"true\"\n >\n <div>\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Reset links' | translate }}\"\n type=\"button\"\n (click)=\"resetLinks()\"\n translate\n >\n Reset links\n </button>\n </div>\n </c8y-ui-empty-state>\n }\n</fieldset>\n\n<ng-template #quickLinksPreview>\n <c8y-quick-links-widget-view\n [config]=\"previewConfig()\"\n [isPreview]=\"true\"\n ></c8y-quick-links-widget-view>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i1$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: QuickLinksWidgetConfigAddLinkComponent, selector: "c8y-quick-links-widget-config-add-link", outputs: ["onQuickLinkCreated", "onCancel"] }, { kind: "component", type: QuickLinksWidgetViewComponent, selector: "c8y-quick-links-widget-view", inputs: ["config", "isPreview"] }, { kind: "component", type: QuickLinksWidgetConfigListComponent, selector: "c8y-quick-links-widget-config-list", inputs: ["quickLinksForm", "config", "quickLinksFormArray", "appsNameChanged"] }, { kind: "ngmodule", type: C8yTranslateModule }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i4$1.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
732
764
  }
733
765
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: QuickLinksWidgetConfigComponent, decorators: [{
734
766
  type: Component,
@@ -741,10 +773,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
741
773
  QuickLinksWidgetConfigListComponent,
742
774
  C8yTranslateModule,
743
775
  EmptyStateComponent,
744
- FormsModule$1,
776
+ ReactiveFormsModule,
745
777
  IconDirective,
746
778
  CollapseModule
747
- ], providers: [DashboardChildComponent, DashboardComponent], template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'General' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <label class=\"m-b-0 text-label-small\">{{ 'Display as' | translate }}</label>\n <div class=\"c8y-select-wrapper form-group-sm\">\n <select\n class=\"form-control\"\n title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n [(ngModel)]=\"selectedDisplayOption\"\n >\n <option [value]=\"DisplayOption.GRID\">\n {{ DisplayOption.GRID | translate }}\n </option>\n <option [value]=\"DisplayOption.LIST\">\n {{ DisplayOption.LIST | translate }}\n </option>\n </select>\n </div>\n <label\n class=\"c8y-checkbox m-l-auto\"\n title=\"{{ 'Translate labels if possible' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [(ngModel)]=\"config().translateLinkLabels\"\n />\n <span></span>\n <span>{{ 'Translate labels if possible' | translate }}</span>\n </label>\n </div>\n</fieldset>\n\n<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Links' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Add a quick link' | translate }}\"\n type=\"button\"\n (click)=\"addLinkIsCollapsed = !addLinkIsCollapsed\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add a quick link' | translate }}\n </button>\n\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Reset links' | translate }}\"\n [popover]=\"confirmPopover\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [outsideClick]=\"true\"\n #pop=\"bs-popover\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n {{ 'Reset links' | translate }}\n </button>\n <ng-template #confirmPopover>\n <p class=\"m-b-8\">\n {{\n 'Resetting links removes all custom links and resets the widget to its default state.'\n | translate\n }}\n </p>\n <button\n class=\"btn btn-default btn-sm\"\n (click)=\"pop.hide()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"resetLinks(); pop.hide()\"\n >\n {{ 'Reset links' | translate }}\n </button>\n </ng-template>\n </div>\n <div\n class=\"collapse bg.component\"\n #collapse=\"bs-collapse\"\n [collapse]=\"addLinkIsCollapsed\"\n [isAnimated]=\"true\"\n >\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Add a quick link' | translate }}</legend>\n <c8y-quick-links-widget-config-add-link\n class=\"d-block p-b-16 p-l-8 p-r-8\"\n (onQuickLinkCreated)=\"addQuickLink($event); addLinkIsCollapsed = true\"\n (onCancel)=\"addLinkIsCollapsed = true\"\n ></c8y-quick-links-widget-config-add-link>\n </fieldset>\n </div>\n\n @if (config().links.length) {\n <c8y-quick-links-widget-config-list\n class=\"separator-top\"\n [quickLinksForm]=\"quickLinksForm\"\n [config]=\"config()\"\n [quickLinksFormArray]=\"quickLinksFormArray\"\n [appsNameChanged]=\"appsNameChanged\"\n ></c8y-quick-links-widget-config-list>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display' | translate\"\n [horizontal]=\"true\"\n >\n <div>\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Reset links' | translate }}\"\n type=\"button\"\n (click)=\"resetLinks()\"\n translate\n >\n Reset links\n </button>\n </div>\n </c8y-ui-empty-state>\n }\n</fieldset>\n\n<ng-template #quickLinksPreview>\n <c8y-quick-links-widget-view\n [config]=\"{\n links: getQuickLinks(),\n displayOption: selectedDisplayOption,\n translateLinkLabels: config().translateLinkLabels\n }\"\n [isPreview]=\"true\"\n ></c8y-quick-links-widget-view>\n</ng-template>\n" }]
779
+ ], providers: [DashboardChildComponent, DashboardComponent], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'General' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <label class=\"m-b-0 text-label-small\">{{ 'Display as' | translate }}</label>\n <div class=\"c8y-select-wrapper form-group-sm\">\n <select\n class=\"form-control\"\n title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n [formControl]=\"displayOptionControl\"\n >\n <option [value]=\"DisplayOption.GRID\">\n {{ DisplayOption.GRID | translate }}\n </option>\n <option [value]=\"DisplayOption.LIST\">\n {{ DisplayOption.LIST | translate }}\n </option>\n </select>\n </div>\n <label\n class=\"c8y-checkbox m-l-auto\"\n title=\"{{ 'Translate labels if possible' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [formControl]=\"translateLinkLabelsControl\"\n />\n <span></span>\n <span>{{ 'Translate labels if possible' | translate }}</span>\n </label>\n </div>\n</fieldset>\n\n<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Links' | translate }}</legend>\n <div class=\"d-flex a-i-center gap-8 p-b-8\">\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Add a quick link' | translate }}\"\n type=\"button\"\n (click)=\"addLinkIsCollapsed = !addLinkIsCollapsed\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add a quick link' | translate }}\n </button>\n\n <button\n class=\"btn btn-clean btn-sm\"\n title=\"{{ 'Reset links' | translate }}\"\n [popover]=\"confirmPopover\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [outsideClick]=\"true\"\n #pop=\"bs-popover\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n {{ 'Reset links' | translate }}\n </button>\n <ng-template #confirmPopover>\n <p class=\"m-b-8\">\n {{\n 'Resetting links removes all custom links and resets the widget to its default state.'\n | translate\n }}\n </p>\n <button\n class=\"btn btn-default btn-sm\"\n (click)=\"pop.hide()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"resetLinks(); pop.hide()\"\n >\n {{ 'Reset links' | translate }}\n </button>\n </ng-template>\n </div>\n <div\n class=\"collapse bg.component\"\n #collapse=\"bs-collapse\"\n [collapse]=\"addLinkIsCollapsed\"\n [isAnimated]=\"true\"\n >\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Add a quick link' | translate }}</legend>\n <c8y-quick-links-widget-config-add-link\n class=\"d-block p-b-16 p-l-8 p-r-8\"\n (onQuickLinkCreated)=\"addQuickLink($event); addLinkIsCollapsed = true\"\n (onCancel)=\"addLinkIsCollapsed = true\"\n ></c8y-quick-links-widget-config-add-link>\n </fieldset>\n </div>\n\n @if (config().links.length) {\n <c8y-quick-links-widget-config-list\n class=\"separator-top\"\n [quickLinksForm]=\"quickLinksForm\"\n [config]=\"config()\"\n [quickLinksFormArray]=\"quickLinksFormArray\"\n [appsNameChanged]=\"appsNameChanged\"\n ></c8y-quick-links-widget-config-list>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"DEFAULT_QUICK_LINK_ICON\"\n [title]=\"'No quick links to display' | translate\"\n [horizontal]=\"true\"\n >\n <div>\n <button\n class=\"btn btn-primary m-t-16\"\n title=\"{{ 'Reset links' | translate }}\"\n type=\"button\"\n (click)=\"resetLinks()\"\n translate\n >\n Reset links\n </button>\n </div>\n </c8y-ui-empty-state>\n }\n</fieldset>\n\n<ng-template #quickLinksPreview>\n <c8y-quick-links-widget-view\n [config]=\"previewConfig()\"\n [isPreview]=\"true\"\n ></c8y-quick-links-widget-view>\n</ng-template>\n" }]
748
780
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], previewSet: [{
749
781
  type: ViewChild,
750
782
  args: ['quickLinksPreview']