@acorex/modules 19.3.5 → 19.3.8

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 (37) hide show
  1. package/dashboard-management/lib/features/home-dashboard/dashboard-home/home-dashboard.d.ts +40 -9
  2. package/dashboard-management/lib/features/home-dashboard/dashboard-home/home-dashboard.store.d.ts +40 -1
  3. package/dashboard-management/lib/features/home-dashboard/dashboard-popups/add-dashboard-popup.d.ts +7 -7
  4. package/dashboard-management/lib/features/home-dashboard/dashboard-popups/dashboard-popup.service.d.ts +1 -0
  5. package/dashboard-management/lib/features/home-dashboard/widget-wrapper/dashboard-widget-wrapper.d.ts +2 -1
  6. package/dashboard-management/lib/features/shared/widgets/bar-chart/bar-chart-widget.component.d.ts +4 -3
  7. package/dashboard-management/lib/features/shared/widgets/donut-chart/donut-chart-widget.component.d.ts +4 -3
  8. package/dashboard-management/lib/features/shared/widgets/gauge-chart/gauge-chart-widget.component.d.ts +3 -2
  9. package/dashboard-management/lib/features/shared/widgets/line-chart/line-chart-widget.component.d.ts +1 -0
  10. package/dashboard-management/lib/features/shared/widgets/weather/weather-widget.component.d.ts +5 -0
  11. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-VeeGJcyl.mjs → acorex-modules-auth-acorex-modules-auth-bj5xztse.mjs} +9 -9
  12. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-VeeGJcyl.mjs.map → acorex-modules-auth-acorex-modules-auth-bj5xztse.mjs.map} +1 -1
  13. package/fesm2022/{acorex-modules-auth-app-chooser.component-IhAQfHJU.mjs → acorex-modules-auth-app-chooser.component-BOL3VzC1.mjs} +2 -2
  14. package/fesm2022/{acorex-modules-auth-app-chooser.component-IhAQfHJU.mjs.map → acorex-modules-auth-app-chooser.component-BOL3VzC1.mjs.map} +1 -1
  15. package/fesm2022/{acorex-modules-auth-login.module-B8qqaCq8.mjs → acorex-modules-auth-login.module-C1AoXhCI.mjs} +4 -4
  16. package/fesm2022/{acorex-modules-auth-login.module-B8qqaCq8.mjs.map → acorex-modules-auth-login.module-C1AoXhCI.mjs.map} +1 -1
  17. package/fesm2022/{acorex-modules-auth-master.layout-egA9357P.mjs → acorex-modules-auth-master.layout-vuHfrDxu.mjs} +2 -2
  18. package/fesm2022/{acorex-modules-auth-master.layout-egA9357P.mjs.map → acorex-modules-auth-master.layout-vuHfrDxu.mjs.map} +1 -1
  19. package/fesm2022/{acorex-modules-auth-password.component-BimdcHXP.mjs → acorex-modules-auth-password.component-C71v2x71.mjs} +2 -2
  20. package/fesm2022/{acorex-modules-auth-password.component-BimdcHXP.mjs.map → acorex-modules-auth-password.component-C71v2x71.mjs.map} +1 -1
  21. package/fesm2022/{acorex-modules-auth-password.component-BMWDHmu6.mjs → acorex-modules-auth-password.component-Dtcz95NV.mjs} +2 -2
  22. package/fesm2022/{acorex-modules-auth-password.component-BMWDHmu6.mjs.map → acorex-modules-auth-password.component-Dtcz95NV.mjs.map} +1 -1
  23. package/fesm2022/{acorex-modules-auth-routes-BYT58dkA.mjs → acorex-modules-auth-routes-lJgHFaQR.mjs} +2 -2
  24. package/fesm2022/{acorex-modules-auth-routes-BYT58dkA.mjs.map → acorex-modules-auth-routes-lJgHFaQR.mjs.map} +1 -1
  25. package/fesm2022/{acorex-modules-auth-two-factor.module-B_g4P4is.mjs → acorex-modules-auth-two-factor.module-C9SfEHF7.mjs} +2 -2
  26. package/fesm2022/{acorex-modules-auth-two-factor.module-B_g4P4is.mjs.map → acorex-modules-auth-two-factor.module-C9SfEHF7.mjs.map} +1 -1
  27. package/fesm2022/{acorex-modules-auth-user-sessions.component-DvYAh9cg.mjs → acorex-modules-auth-user-sessions.component-CCsoLecU.mjs} +4 -4
  28. package/fesm2022/acorex-modules-auth-user-sessions.component-CCsoLecU.mjs.map +1 -0
  29. package/fesm2022/acorex-modules-auth.mjs +1 -1
  30. package/fesm2022/acorex-modules-dashboard-management.mjs +1308 -1302
  31. package/fesm2022/acorex-modules-dashboard-management.mjs.map +1 -1
  32. package/fesm2022/acorex-modules-notification-management.mjs +11 -11
  33. package/fesm2022/acorex-modules-notification-management.mjs.map +1 -1
  34. package/fesm2022/acorex-modules-security-management.mjs +1 -1
  35. package/fesm2022/acorex-modules-security-management.mjs.map +1 -1
  36. package/package.json +9 -9
  37. package/fesm2022/acorex-modules-auth-user-sessions.component-DvYAh9cg.mjs.map +0 -1
@@ -3,7 +3,7 @@ import { createAllQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXP_HOME
3
3
  import * as i3$1 from '@acorex/platform/layout/builder';
4
4
  import { AXPWidgetsCatalog, AXPValueWidgetComponent, cloneProperty, AXPWidgetGroupEnum, AXPLayoutWidgetComponent, AXPLayoutBuilderModule, AXPWidgetRendererDirective } from '@acorex/platform/layout/builder';
5
5
  import { AXMEntityCrudServiceImpl, AXPEntityService, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
6
- import { AXP_APPEARANCE_PROPERTY_GROUP, AXP_STYLING_PROPERTY_GROUP, AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty, AXP_DATA_PROPERTY_GROUP, AXP_COLOR_PROPERTY, AXPWidgetsModule } from '@acorex/platform/widgets';
6
+ import { AXP_APPEARANCE_PROPERTY_GROUP, AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty, AXP_DATA_PROPERTY_GROUP, AXP_COLOR_PROPERTY, AXPWidgetsModule } from '@acorex/platform/widgets';
7
7
  import * as i0 from '@angular/core';
8
8
  import { Injectable, inject, Injector, computed, ChangeDetectionStrategy, Component, ChangeDetectorRef, signal, viewChild, ElementRef, HostListener, output, InjectionToken, effect, HostBinding, NgModule, input, contentChild, afterNextRender, model, ViewEncapsulation } from '@angular/core';
9
9
  import { AXBarChartComponent } from '@acorex/charts/bar-chart';
@@ -38,14 +38,14 @@ import { AXCheckBoxModule } from '@acorex/components/check-box';
38
38
  import { AXImageModule } from '@acorex/components/image';
39
39
  import { AXLabelModule } from '@acorex/components/label';
40
40
  import { AXTabsModule } from '@acorex/components/tabs';
41
- import * as i6 from '@acorex/core/translation';
41
+ import * as i2$3 from '@acorex/core/translation';
42
42
  import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
43
43
  import { HttpClient, HttpClientModule } from '@angular/common/http';
44
44
  import { AXPopupService } from '@acorex/components/popup';
45
45
  import { AXP_GLOBAL_SEARCH_CONFIG_TOKEN } from '@acorex/modules/common';
46
46
  import { AXPDataGenerator, AXPPlatformScope } from '@acorex/platform/core';
47
47
  import { AXPWorkflowService } from '@acorex/platform/workflow';
48
- import { Router, ActivatedRoute } from '@angular/router';
48
+ import { ActivatedRoute, Router } from '@angular/router';
49
49
  import { AXBreadcrumbsModule } from '@acorex/components/breadcrumbs';
50
50
  import { AXButtonGroupModule } from '@acorex/components/button-group';
51
51
  import { AXDialogService } from '@acorex/components/dialog';
@@ -55,12 +55,14 @@ import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
55
55
  import { AXPWidgetPropertyViewerComponent, AXPWidgetPickerService, AXPDesignerService } from '@acorex/platform/layout/designer';
56
56
  import { AXPBasePageComponent, AXPPageLayoutComponent, AXPBasePage } from '@acorex/platform/themes/default';
57
57
  import { AXPLayoutThemeService, AXPThemeLayoutBlockComponent } from '@acorex/platform/themes/shared';
58
- import * as i2$3 from '@acorex/components/loading';
58
+ import * as i2$4 from '@acorex/components/loading';
59
59
  import { AXLoadingModule } from '@acorex/components/loading';
60
60
  import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
61
61
  import { AXBasePageComponent } from '@acorex/components/page';
62
62
  import * as i7 from '@acorex/components/select-box';
63
63
  import { AXSelectBoxModule } from '@acorex/components/select-box';
64
+ import * as i8 from '@acorex/components/switch';
65
+ import { AXSwitchModule } from '@acorex/components/switch';
64
66
  import * as i3$3 from '@acorex/components/text-box';
65
67
  import { AXTextBoxModule } from '@acorex/components/text-box';
66
68
  import { AXMOrganizationManagementRoleEntityService } from '@acorex/modules/organization-management';
@@ -452,20 +454,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
452
454
  */
453
455
  class AXPBarChartWidgetViewComponent extends AXPValueWidgetComponent {
454
456
  constructor() {
455
- super(...arguments);
457
+ super();
456
458
  this.barChartData = computed(() => this.getValue());
457
459
  this.barChartOptions = computed(() => this.options());
460
+ this.setOptions({
461
+ ...this.options(),
462
+ showXAxis: true,
463
+ showYAxis: true,
464
+ barWidth: 80,
465
+ cornerRadius: 4,
466
+ showGrid: true,
467
+ showDataLabels: false,
468
+ showTooltip: true,
469
+ animationEasing: 'cubic-out',
470
+ animationDuration: 800,
471
+ });
458
472
  }
459
473
  handleBarClick(event) {
460
474
  //console.log(event);
461
475
  }
462
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPBarChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
476
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPBarChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
463
477
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AXPBarChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-bar-chart [data]=\"barChartData()\" [options]=\"barChartOptions()\" (barClick)=\"handleBarClick($event)\"></ax-bar-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXBarChartComponent, selector: "ax-bar-chart", inputs: ["data", "options"], outputs: ["barClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
464
478
  }
465
479
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPBarChartWidgetViewComponent, decorators: [{
466
480
  type: Component,
467
481
  args: [{ imports: [AXBarChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-bar-chart [data]=\"barChartData()\" [options]=\"barChartOptions()\" (barClick)=\"handleBarClick($event)\"></ax-bar-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
468
- }] });
482
+ }], ctorParameters: () => [] });
469
483
 
470
484
  var barChartWidget_component = /*#__PURE__*/Object.freeze({
471
485
  __proto__: null,
@@ -496,7 +510,7 @@ const AXPBarChartWidget = {
496
510
  // ====== Chart Title ======
497
511
  {
498
512
  name: 'title',
499
- title: 'Chart Title',
513
+ title: '@dashboard:widgets.bar-chart.chart-title',
500
514
  group: AXP_APPEARANCE_PROPERTY_GROUP,
501
515
  schema: {
502
516
  defaultValue: '',
@@ -512,64 +526,10 @@ const AXPBarChartWidget = {
512
526
  },
513
527
  visible: true,
514
528
  },
515
- // ====== Layout & Dimensions ======
516
- {
517
- name: 'width',
518
- title: 'Width',
519
- group: AXP_STYLING_PROPERTY_GROUP,
520
- schema: {
521
- defaultValue: null,
522
- dataType: 'number',
523
- interface: {
524
- name: 'width',
525
- path: 'options.width',
526
- type: AXPWidgetsCatalog.number,
527
- options: {
528
- minValue: 0,
529
- maxValue: 1200,
530
- },
531
- },
532
- },
533
- visible: true,
534
- },
535
- {
536
- name: 'height',
537
- title: 'Height',
538
- group: AXP_STYLING_PROPERTY_GROUP,
539
- schema: {
540
- defaultValue: 300,
541
- dataType: 'number',
542
- interface: {
543
- name: 'height',
544
- path: 'options.height',
545
- type: AXPWidgetsCatalog.number,
546
- options: {
547
- minValue: 0,
548
- maxValue: 800,
549
- },
550
- },
551
- },
552
- visible: true,
553
- },
554
529
  // ====== X Axis Settings ======
555
- {
556
- name: 'showXAxis',
557
- title: 'Show X Axis',
558
- group: AXP_APPEARANCE_PROPERTY_GROUP,
559
- schema: {
560
- defaultValue: true,
561
- dataType: 'boolean',
562
- interface: {
563
- name: 'showXAxis',
564
- path: 'options.showXAxis',
565
- type: AXPWidgetsCatalog.toggle,
566
- },
567
- },
568
- visible: true,
569
- },
570
530
  {
571
531
  name: 'xAxisLabel',
572
- title: 'X Axis Label',
532
+ title: '@dashboard:widgets.bar-chart.x-axis-label',
573
533
  group: AXP_APPEARANCE_PROPERTY_GROUP,
574
534
  schema: {
575
535
  defaultValue: '',
@@ -583,24 +543,9 @@ const AXPBarChartWidget = {
583
543
  visible: true,
584
544
  },
585
545
  // ====== Y Axis Settings ======
586
- {
587
- name: 'showYAxis',
588
- title: 'Show Y Axis',
589
- group: AXP_APPEARANCE_PROPERTY_GROUP,
590
- schema: {
591
- defaultValue: true,
592
- dataType: 'boolean',
593
- interface: {
594
- name: 'showYAxis',
595
- path: 'options.showYAxis',
596
- type: AXPWidgetsCatalog.toggle,
597
- },
598
- },
599
- visible: true,
600
- },
601
546
  {
602
547
  name: 'yAxisLabel',
603
- title: 'Y Axis Label',
548
+ title: '@dashboard:widgets.bar-chart.y-axis-label',
604
549
  group: AXP_APPEARANCE_PROPERTY_GROUP,
605
550
  schema: {
606
551
  defaultValue: '',
@@ -613,145 +558,218 @@ const AXPBarChartWidget = {
613
558
  },
614
559
  visible: true,
615
560
  },
561
+ /* Commented out properties
562
+ // ====== Layout & Dimensions ======
563
+ {
564
+ name: 'width',
565
+ title: '@dashboard:widgets.bar-chart.width',
566
+ group: AXP_STYLING_PROPERTY_GROUP,
567
+ schema: {
568
+ defaultValue: null,
569
+ dataType: 'number',
570
+ interface: {
571
+ name: 'width',
572
+ path: 'options.width',
573
+ type: AXPWidgetsCatalog.number,
574
+ options: {
575
+ minValue: 0,
576
+ maxValue: 1200,
577
+ },
578
+ },
579
+ },
580
+ visible: true,
581
+ },
582
+ {
583
+ name: 'height',
584
+ title: '@dashboard:widgets.bar-chart.height',
585
+ group: AXP_STYLING_PROPERTY_GROUP,
586
+ schema: {
587
+ defaultValue: 300,
588
+ dataType: 'number',
589
+ interface: {
590
+ name: 'height',
591
+ path: 'options.height',
592
+ type: AXPWidgetsCatalog.number,
593
+ options: {
594
+ minValue: 0,
595
+ maxValue: 800,
596
+ },
597
+ },
598
+ },
599
+ visible: true,
600
+ },
601
+ // ====== X Axis Settings ======
602
+ {
603
+ name: 'showXAxis',
604
+ title: '@dashboard:widgets.bar-chart.show-x-axis',
605
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
606
+ schema: {
607
+ defaultValue: true,
608
+ dataType: 'boolean',
609
+ interface: {
610
+ name: 'showXAxis',
611
+ path: 'options.showXAxis',
612
+ type: AXPWidgetsCatalog.toggle,
613
+ },
614
+ },
615
+ visible: true,
616
+ },
617
+ // ====== Y Axis Settings ======
618
+ {
619
+ name: 'showYAxis',
620
+ title: '@dashboard:widgets.bar-chart.show-y-axis',
621
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
622
+ schema: {
623
+ defaultValue: true,
624
+ dataType: 'boolean',
625
+ interface: {
626
+ name: 'showYAxis',
627
+ path: 'options.showYAxis',
628
+ type: AXPWidgetsCatalog.toggle,
629
+ },
630
+ },
631
+ visible: true,
632
+ },
616
633
  // ====== Bar Appearance ======
617
634
  {
618
- name: 'barWidth',
619
- title: 'Bar Width',
620
- group: AXP_APPEARANCE_PROPERTY_GROUP,
621
- schema: {
622
- defaultValue: 80,
623
- dataType: 'number',
624
- interface: {
625
- name: 'barWidth',
626
- path: 'options.barWidth',
627
- type: AXPWidgetsCatalog.number,
628
- options: {
629
- placeholder: '1-100',
630
- minValue: 1,
631
- maxValue: 100,
632
- },
633
- },
635
+ name: 'barWidth',
636
+ title: '@dashboard:widgets.bar-chart.bar-width',
637
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
638
+ schema: {
639
+ defaultValue: 80,
640
+ dataType: 'number',
641
+ interface: {
642
+ name: 'barWidth',
643
+ path: 'options.barWidth',
644
+ type: AXPWidgetsCatalog.number,
645
+ options: {
646
+ placeholder: '1-100',
647
+ minValue: 1,
648
+ maxValue: 100,
649
+ },
634
650
  },
635
- visible: true,
651
+ },
652
+ visible: true,
636
653
  },
637
654
  {
638
- name: 'cornerRadius',
639
- title: 'Corner Radius',
640
- group: AXP_APPEARANCE_PROPERTY_GROUP,
641
- schema: {
642
- defaultValue: 4,
643
- dataType: 'number',
644
- interface: {
645
- name: 'cornerRadius',
646
- path: 'options.cornerRadius',
647
- type: AXPWidgetsCatalog.number,
648
- options: {
649
- placeholder: '0-20',
650
- minValue: 0,
651
- maxValue: 20,
652
- },
653
- },
655
+ name: 'cornerRadius',
656
+ title: '@dashboard:widgets.bar-chart.corner-radius',
657
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
658
+ schema: {
659
+ defaultValue: 4,
660
+ dataType: 'number',
661
+ interface: {
662
+ name: 'cornerRadius',
663
+ path: 'options.cornerRadius',
664
+ type: AXPWidgetsCatalog.number,
665
+ options: {
666
+ placeholder: '0-20',
667
+ minValue: 0,
668
+ maxValue: 20,
669
+ },
654
670
  },
655
- visible: true,
671
+ },
672
+ visible: true,
656
673
  },
657
674
  // ====== Grid Settings ======
658
675
  {
659
- name: 'showGrid',
660
- title: 'Show Grid Lines',
661
- group: AXP_APPEARANCE_PROPERTY_GROUP,
662
- schema: {
663
- defaultValue: true,
664
- dataType: 'boolean',
665
- interface: {
666
- name: 'showGrid',
667
- path: 'options.showGrid',
668
- type: AXPWidgetsCatalog.toggle,
669
- },
676
+ name: 'showGrid',
677
+ title: '@dashboard:widgets.bar-chart.show-grid',
678
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
679
+ schema: {
680
+ defaultValue: true,
681
+ dataType: 'boolean',
682
+ interface: {
683
+ name: 'showGrid',
684
+ path: 'options.showGrid',
685
+ type: AXPWidgetsCatalog.toggle,
670
686
  },
671
- visible: true,
687
+ },
688
+ visible: true,
672
689
  },
673
690
  {
674
- name: 'showDataLabels',
675
- title: 'Show Data Labels',
676
- group: AXP_APPEARANCE_PROPERTY_GROUP,
677
- schema: {
678
- defaultValue: true,
679
- dataType: 'boolean',
680
- interface: {
681
- name: 'showDataLabels',
682
- path: 'options.showDataLabels',
683
- type: AXPWidgetsCatalog.toggle,
684
- },
691
+ name: 'showDataLabels',
692
+ title: '@dashboard:widgets.bar-chart.show-data-labels',
693
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
694
+ schema: {
695
+ defaultValue: true,
696
+ dataType: 'boolean',
697
+ interface: {
698
+ name: 'showDataLabels',
699
+ path: 'options.showDataLabels',
700
+ type: AXPWidgetsCatalog.toggle,
685
701
  },
686
- visible: true,
702
+ },
703
+ visible: true,
687
704
  },
688
705
  // ====== Tooltip Settings ======
689
706
  {
690
- name: 'showTooltip',
691
- title: 'Show Tooltip',
692
- group: AXP_APPEARANCE_PROPERTY_GROUP,
693
- schema: {
694
- defaultValue: true,
695
- dataType: 'boolean',
696
- interface: {
697
- name: 'showTooltip',
698
- path: 'options.showTooltip',
699
- type: AXPWidgetsCatalog.toggle,
700
- },
707
+ name: 'showTooltip',
708
+ title: '@dashboard:widgets.bar-chart.show-tooltip',
709
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
710
+ schema: {
711
+ defaultValue: true,
712
+ dataType: 'boolean',
713
+ interface: {
714
+ name: 'showTooltip',
715
+ path: 'options.showTooltip',
716
+ type: AXPWidgetsCatalog.toggle,
701
717
  },
702
- visible: true,
718
+ },
719
+ visible: true,
703
720
  },
704
721
  // ====== Animation Settings ======
705
722
  {
706
- name: 'animationEasing',
707
- title: 'Animation Easing',
708
- group: AXP_APPEARANCE_PROPERTY_GROUP,
709
- schema: {
710
- defaultValue: 'cubic-out',
711
- dataType: 'string',
712
- interface: {
713
- name: 'animationEasing',
714
- path: 'options.animationEasing',
715
- type: AXPWidgetsCatalog.select,
716
- options: {
717
- dataSource: [
718
- { value: 'linear', text: 'Linear' },
719
- { value: 'ease', text: 'Ease' },
720
- { value: 'ease-in', text: 'Ease In' },
721
- { value: 'ease-out', text: 'Ease Out' },
722
- { value: 'ease-in-out', text: 'Ease In Out' },
723
- { value: 'cubic', text: 'Cubic' },
724
- { value: 'cubic-in', text: 'Cubic In' },
725
- { value: 'cubic-out', text: 'Cubic Out' },
726
- { value: 'cubic-in-out', text: 'Cubic In Out' },
727
- ],
728
- textField: 'text',
729
- valueField: 'value',
730
- },
731
- },
723
+ name: 'animationEasing',
724
+ title: '@dashboard:widgets.bar-chart.animation-easing',
725
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
726
+ schema: {
727
+ defaultValue: 'cubic-out',
728
+ dataType: 'string',
729
+ interface: {
730
+ name: 'animationEasing',
731
+ path: 'options.animationEasing',
732
+ type: AXPWidgetsCatalog.select,
733
+ options: {
734
+ dataSource: [
735
+ { value: 'linear', text: 'Linear' },
736
+ { value: 'ease', text: 'Ease' },
737
+ { value: 'ease-in', text: 'Ease In' },
738
+ { value: 'ease-out', text: 'Ease Out' },
739
+ { value: 'ease-in-out', text: 'Ease In Out' },
740
+ { value: 'cubic', text: 'Cubic' },
741
+ { value: 'cubic-in', text: 'Cubic In' },
742
+ { value: 'cubic-out', text: 'Cubic Out' },
743
+ { value: 'cubic-in-out', text: 'Cubic In Out' },
744
+ ],
745
+ textField: 'text',
746
+ valueField: 'value',
747
+ },
732
748
  },
733
- visible: true,
749
+ },
750
+ visible: true,
734
751
  },
735
752
  {
736
- name: 'animationDuration',
737
- title: 'Animation Duration',
738
- group: AXP_APPEARANCE_PROPERTY_GROUP,
739
- schema: {
740
- defaultValue: 800,
741
- dataType: 'number',
742
- interface: {
743
- name: 'animationDuration',
744
- path: 'options.animationDuration',
745
- type: AXPWidgetsCatalog.number,
746
- options: {
747
- placeholder: '0-2000',
748
- minValue: 0,
749
- maxValue: 2000,
750
- },
751
- },
753
+ name: 'animationDuration',
754
+ title: '@dashboard:widgets.bar-chart.animation-duration',
755
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
756
+ schema: {
757
+ defaultValue: 800,
758
+ dataType: 'number',
759
+ interface: {
760
+ name: 'animationDuration',
761
+ path: 'options.animationDuration',
762
+ type: AXPWidgetsCatalog.number,
763
+ options: {
764
+ placeholder: '0-2000',
765
+ minValue: 0,
766
+ maxValue: 2000,
767
+ },
752
768
  },
753
- visible: true,
769
+ },
770
+ visible: true,
754
771
  },
772
+ */
755
773
  ],
756
774
  components: {
757
775
  view: {
@@ -803,7 +821,7 @@ class AXPClockCalendarWidgetViewComponent extends AXPValueWidgetComponent {
803
821
  this.showDayOfWeek = computed(() => this.options()?.showDayOfWeek !== false);
804
822
  this.use24Hour = computed(() => this.options()?.use24Hour === true);
805
823
  this.showSeconds = computed(() => this.options()?.showSeconds !== false);
806
- this.dateFormat = computed(() => this.options()?.dateFormat?.id ?? 'dd MMM yyyy');
824
+ this.dateFormat = computed(() => this.options()?.dateFormat?.id ?? 'DD MMM YYYY');
807
825
  this.timezone = computed(() => this.options()?.timezone?.id ?? 'local');
808
826
  // protected readonly showTimezoneIndicator: Signal<boolean> = computed(() => this.timezone() !== 'local');
809
827
  this.displayTimezone = computed(() => {
@@ -893,11 +911,11 @@ class AXPClockCalendarWidgetViewComponent extends AXPValueWidgetComponent {
893
911
  return days[this.currentDate.getDay()];
894
912
  }
895
913
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
896
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPClockCalendarWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXDecoratorModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
914
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPClockCalendarWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format: 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format: 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i2.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXDecoratorModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
897
915
  }
898
916
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPClockCalendarWidgetViewComponent, decorators: [{
899
917
  type: Component,
900
- args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, AXTagModule, AXDecoratorModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format : 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format : 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"] }]
918
+ args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, AXTagModule, AXDecoratorModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"axp-clock-calendar-container\">\n <!-- Timezone indicator (only shown when not local) -->\n <!-- @if (showTimezoneIndicator()) {\n <div class=\"axp-clock-calendar-timezone-badge\"><i class=\"fa-solid fa-globe\"></i> {{ displayTimezone() }}</div>\n } -->\n\n <!-- Day of week display -->\n @if (showDayOfWeek()) {\n <div class=\"axp-clock-calendar-day-label\">{{ getDayOfWeek() }}</div>\n }\n\n <div class=\"axp-clock-calendar-content\">\n <!-- Digital Clock Display -->\n @if (showDigitalClock()) {\n <div class=\"axp-clock-calendar-digital-clock\">\n {{ currentTime | format: 'datetime' : timeFormat() | async }}\n </div>\n }\n\n <!-- Analog Clock Display -->\n @if (showAnalogClock()) {\n <div class=\"axp-clock-calendar-analog-clock\">\n <!-- Hour markers -->\n @for (hour of clockHours; track hour) {\n <div\n class=\"axp-clock-calendar-hour-marker\"\n [style.transform]=\"'rotate(' + hour * 30 + 'deg) translateY(-80px)'\"\n ></div>\n }\n\n <!-- Clock Numbers -->\n <div class=\"axp-clock-calendar-numbers-container\">\n @for (hour of clockHourNumbers; track hour) {\n <div\n class=\"axp-clock-calendar-hour-number\"\n [style.transform]=\"'rotate(' + hour.angle + 'deg) translateY(-82px)'\"\n >\n <span [style.transform]=\"'rotate(' + -hour.angle + 'deg)'\">{{ hour.number }}</span>\n </div>\n }\n </div>\n\n <!-- Clock Hands -->\n <div class=\"axp-clock-calendar-hands-container\">\n <div class=\"axp-clock-calendar-hour-hand\" [style.transform]=\"'rotate(' + hourRotation + 'deg)'\"></div>\n <div class=\"axp-clock-calendar-minute-hand\" [style.transform]=\"'rotate(' + minuteRotation + 'deg)'\"></div>\n @if (showSeconds()) {\n <div class=\"axp-clock-calendar-second-hand\" [style.transform]=\"'rotate(' + secondRotation + 'deg)'\"></div>\n }\n <div class=\"axp-clock-calendar-center-dot\"></div>\n </div>\n </div>\n }\n\n <!-- Date Display -->\n @if (showDate()) {\n <div class=\"axp-clock-calendar-date-display\">\n <i class=\"fa-regular fa-calendar\"></i>\n {{ currentDate | format: 'datetime' : dateFormat() | async }}\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.axp-clock-calendar-container{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;padding:1rem;position:relative;overflow:hidden;box-shadow:var(--ax-shadow-sm);background-color:var(--ax-surface-color);color:var(--ax-text-color)}.axp-clock-calendar-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;position:relative}.axp-clock-calendar-timezone-badge{position:absolute;top:.5rem;right:.5rem;font-size:.75rem;padding:.25rem;border-radius:1rem;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-timezone-badge:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-timezone-badge{display:flex;align-items:center;gap:.25rem}.axp-clock-calendar-timezone-badge i{font-size:.75rem}.axp-clock-calendar-day-label{font-size:.9rem;font-weight:600;text-transform:uppercase;letter-spacing:.05rem;margin-bottom:.25rem}.axp-clock-calendar-digital-clock{font-size:1.5rem;font-weight:500;letter-spacing:.05rem;font-family:monospace;padding:.5rem .75rem;border-radius:.25rem}.axp-clock-calendar-analog-clock{position:relative;border-radius:50%;border-width:1px;border-color:rgba(23,23,23,.5)}.axp-clock-calendar-analog-clock:is(.ax-dark *){border-color:rgba(245,245,245,.5)}.axp-clock-calendar-analog-clock{display:flex;align-items:center;justify-content:center;background:var(--ax-surface-color);width:min(180px,100%);height:0;padding-bottom:min(180px,100%);margin:.5rem auto;min-width:120px;min-height:120px;box-shadow:var(--ax-shadow-sm)}.axp-clock-calendar-hands-container,.axp-clock-calendar-numbers-container{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.axp-clock-calendar-hour-marker{position:absolute;left:50%;top:50%;width:2px;height:4%;margin-left:-1px;border-radius:1px;background-color:var(--ax-text-muted);transform-origin:50% 0}.axp-clock-calendar-hour-number{position:absolute;left:50%;top:50%;transform-origin:50% 0;font-size:clamp(.7rem,2.5vw,.9rem);font-weight:600;color:var(--ax-text-color)}.axp-clock-calendar-hour-number span{display:block}.axp-clock-calendar-hour-hand{position:absolute;top:50%;left:50%;width:4px;height:25%;margin-left:-2px;background-color:rgba(23,23,23,.75)}.axp-clock-calendar-hour-hand:is(.ax-dark *){background-color:rgba(245,245,245,.75)}.axp-clock-calendar-hour-hand{transform-origin:50% 0;border-radius:3px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-minute-hand{position:absolute;top:50%;left:50%;width:3px;height:38%;margin-left:-1.5px;background-color:rgba(23,23,23,.5)}.axp-clock-calendar-minute-hand:is(.ax-dark *){background-color:rgba(245,245,245,.5)}.axp-clock-calendar-minute-hand{transform-origin:50% 0;border-radius:2px;box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-second-hand{position:absolute;top:50%;left:50%;width:2px;height:42%;margin-left:-1px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-500),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-400),var(--tw-bg-opacity, 1))}.axp-clock-calendar-second-hand{transform-origin:50% 0;border-radius:1px;box-shadow:0 0 3px rgba(0,0,0,.2)}.axp-clock-calendar-center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;border-radius:50%;margin-top:-5px;margin-left:-5px;background-color:#d81159;border:2px solid var(--ax-surface-color);box-shadow:0 0 4px rgba(0,0,0,.3)}.axp-clock-calendar-date-display{display:flex;align-items:center;gap:.5rem;font-size:.85rem;padding:.25rem .6rem;border-radius:.25rem;background-color:var(--ax-surface-hover);color:var(--ax-text-color)}.axp-clock-calendar-date-display i{font-size:.85rem;opacity:.7}\n"] }]
901
919
  }] });
902
920
 
903
921
  var clockCalendarWidget_component = /*#__PURE__*/Object.freeze({
@@ -932,10 +950,10 @@ const AXP_TIMEZONE_OPTIONS = [
932
950
  * Common date format options for the widget configuration
933
951
  */
934
952
  const AXP_DATE_FORMAT_OPTIONS = [
935
- { id: 'dd MMM yyyy', title: '31 Dec 2023' },
936
- { id: 'MMM dd, yyyy', title: 'Dec 31, 2023' },
937
- { id: 'dd/MM/yyyy', title: '31/12/2023' },
938
- { id: 'MM/dd/yyyy', title: '12/31/2023' },
953
+ { id: 'DD MMM YYYY', title: '31 Dec 2023' },
954
+ { id: 'MMM DD, YYYY', title: 'Dec 31, 2023' },
955
+ { id: 'DD/MM/YYYY', title: '31/12/2023' },
956
+ { id: 'MM/DD/YYYY', title: '12/31/2023' },
939
957
  ];
940
958
 
941
959
  const AXPClockCalendarWidget = {
@@ -949,7 +967,7 @@ const AXPClockCalendarWidget = {
949
967
  // ====== Title ======
950
968
  {
951
969
  name: 'title',
952
- title: 'Chart Title',
970
+ title: '@dashboard:widgets.clock-calendar.chart-title',
953
971
  group: AXP_APPEARANCE_PROPERTY_GROUP,
954
972
  schema: {
955
973
  defaultValue: '',
@@ -968,7 +986,7 @@ const AXPClockCalendarWidget = {
968
986
  // ====== Display Settings ======
969
987
  {
970
988
  name: 'displayLayout',
971
- title: 'Display Layout',
989
+ title: '@dashboard:widgets.clock-calendar.display-layout',
972
990
  group: AXP_APPEARANCE_PROPERTY_GROUP,
973
991
  schema: {
974
992
  dataType: 'string',
@@ -990,7 +1008,7 @@ const AXPClockCalendarWidget = {
990
1008
  },
991
1009
  {
992
1010
  name: 'showDate',
993
- title: 'Show Date',
1011
+ title: '@dashboard:widgets.clock-calendar.show-date',
994
1012
  group: AXP_APPEARANCE_PROPERTY_GROUP,
995
1013
  schema: {
996
1014
  defaultValue: true,
@@ -1005,7 +1023,7 @@ const AXPClockCalendarWidget = {
1005
1023
  },
1006
1024
  {
1007
1025
  name: 'showDayOfWeek',
1008
- title: 'Show Day of Week',
1026
+ title: '@dashboard:widgets.clock-calendar.show-day-of-week',
1009
1027
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1010
1028
  schema: {
1011
1029
  defaultValue: true,
@@ -1021,7 +1039,7 @@ const AXPClockCalendarWidget = {
1021
1039
  // ====== Time Format Settings ======
1022
1040
  {
1023
1041
  name: 'use24Hour',
1024
- title: 'Use 24 Hour Format',
1042
+ title: '@dashboard:widgets.clock-calendar.use-24-hour',
1025
1043
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
1026
1044
  schema: {
1027
1045
  defaultValue: false,
@@ -1036,7 +1054,7 @@ const AXPClockCalendarWidget = {
1036
1054
  },
1037
1055
  {
1038
1056
  name: 'showSeconds',
1039
- title: 'Show Seconds',
1057
+ title: '@dashboard:widgets.clock-calendar.show-seconds',
1040
1058
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
1041
1059
  schema: {
1042
1060
  defaultValue: true,
@@ -1066,10 +1084,10 @@ const AXPClockCalendarWidget = {
1066
1084
  // },
1067
1085
  {
1068
1086
  name: 'dateFormat',
1069
- title: 'Date Format',
1087
+ title: '@dashboard:widgets.clock-calendar.date-format',
1070
1088
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
1071
1089
  schema: {
1072
- defaultValue: 'dd MMM yyyy',
1090
+ defaultValue: 'DD MMM YYYY',
1073
1091
  dataType: 'string',
1074
1092
  interface: {
1075
1093
  name: 'dateFormat',
@@ -1084,7 +1102,7 @@ const AXPClockCalendarWidget = {
1084
1102
  },
1085
1103
  {
1086
1104
  name: 'timezone',
1087
- title: 'Timezone',
1105
+ title: '@dashboard:widgets.clock-calendar.timezone',
1088
1106
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
1089
1107
  schema: {
1090
1108
  defaultValue: 'local',
@@ -1124,20 +1142,31 @@ const AXPClockCalendarWidget = {
1124
1142
  */
1125
1143
  class AXPDonutChartWidgetViewComponent extends AXPValueWidgetComponent {
1126
1144
  constructor() {
1127
- super(...arguments);
1145
+ super();
1128
1146
  this.donutChartData = computed(() => this.getValue());
1129
1147
  this.donutChartOptions = computed(() => this.options());
1148
+ this.setOptions({
1149
+ ...this.options(),
1150
+ width: 300,
1151
+ height: 300,
1152
+ showDataLabels: false,
1153
+ donutWidth: 35,
1154
+ cornerRadius: 4,
1155
+ showTooltip: true,
1156
+ animationEasing: 'cubic-out',
1157
+ animationDuration: 800,
1158
+ });
1130
1159
  }
1131
1160
  handleDonutChartSegmentClick(event) {
1132
1161
  //console.log(event);
1133
1162
  }
1134
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPDonutChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1163
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPDonutChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1135
1164
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AXPDonutChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-donut-chart\n [data]=\"donutChartData()\"\n [options]=\"donutChartOptions()\"\n (segmentClick)=\"handleDonutChartSegmentClick($event)\"\n></ax-donut-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXDonutChartComponent, selector: "ax-donut-chart", inputs: ["data", "options"], outputs: ["segmentClick", "segmentHover"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1136
1165
  }
1137
1166
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPDonutChartWidgetViewComponent, decorators: [{
1138
1167
  type: Component,
1139
1168
  args: [{ imports: [AXDonutChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-donut-chart\n [data]=\"donutChartData()\"\n [options]=\"donutChartOptions()\"\n (segmentClick)=\"handleDonutChartSegmentClick($event)\"\n></ax-donut-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
1140
- }] });
1169
+ }], ctorParameters: () => [] });
1141
1170
 
1142
1171
  var donutChartWidget_component = /*#__PURE__*/Object.freeze({
1143
1172
  __proto__: null,
@@ -1157,7 +1186,7 @@ const AXPDonutChartWidget = {
1157
1186
  // ====== Chart Title ======
1158
1187
  {
1159
1188
  name: 'title',
1160
- title: 'Chart Title',
1189
+ title: '@dashboard:widgets.donut-chart.chart-title',
1161
1190
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1162
1191
  schema: {
1163
1192
  defaultValue: '',
@@ -1173,100 +1202,101 @@ const AXPDonutChartWidget = {
1173
1202
  },
1174
1203
  visible: true,
1175
1204
  },
1205
+ /* Commented out properties
1176
1206
  // ====== Size & Layout ======
1177
1207
  {
1178
- name: 'width',
1179
- title: 'Width',
1180
- group: AXP_STYLING_PROPERTY_GROUP,
1181
- schema: {
1182
- defaultValue: 300,
1183
- dataType: 'number',
1184
- interface: {
1185
- name: 'width',
1186
- path: 'options.width',
1187
- type: AXPWidgetsCatalog.number,
1188
- options: {
1189
- minValue: 200,
1190
- maxValue: 1200,
1191
- },
1192
- },
1208
+ name: 'width',
1209
+ title: '@dashboard:widgets.donut-chart.width',
1210
+ group: AXP_STYLING_PROPERTY_GROUP,
1211
+ schema: {
1212
+ defaultValue: 300,
1213
+ dataType: 'number',
1214
+ interface: {
1215
+ name: 'width',
1216
+ path: 'options.width',
1217
+ type: AXPWidgetsCatalog.number,
1218
+ options: {
1219
+ minValue: 200,
1220
+ maxValue: 1200,
1221
+ },
1193
1222
  },
1194
- visible: true,
1223
+ },
1224
+ visible: true,
1195
1225
  },
1196
1226
  {
1197
- name: 'height',
1198
- title: 'Height',
1199
- group: AXP_STYLING_PROPERTY_GROUP,
1200
- schema: {
1201
- defaultValue: 300,
1202
- dataType: 'number',
1203
- interface: {
1204
- name: 'height',
1205
- path: 'options.height',
1206
- type: AXPWidgetsCatalog.number,
1207
- options: {
1208
- minValue: 200,
1209
- maxValue: 800,
1210
- },
1211
- },
1227
+ name: 'height',
1228
+ title: '@dashboard:widgets.donut-chart.height',
1229
+ group: AXP_STYLING_PROPERTY_GROUP,
1230
+ schema: {
1231
+ defaultValue: 300,
1232
+ dataType: 'number',
1233
+ interface: {
1234
+ name: 'height',
1235
+ path: 'options.height',
1236
+ type: AXPWidgetsCatalog.number,
1237
+ options: {
1238
+ minValue: 200,
1239
+ maxValue: 800,
1240
+ },
1212
1241
  },
1213
- visible: true,
1242
+ },
1243
+ visible: true,
1214
1244
  },
1215
1245
  // ====== Donut Appearance ======
1216
1246
  {
1217
- name: 'showDataLabels',
1218
- title: 'Show Data Labels',
1219
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1220
- schema: {
1221
- defaultValue: true,
1222
- dataType: 'boolean',
1223
- interface: {
1224
- name: 'showDataLabels',
1225
- path: 'options.showDataLabels',
1226
- type: AXPWidgetsCatalog.toggle,
1227
- },
1247
+ name: 'showDataLabels',
1248
+ title: '@dashboard:widgets.donut-chart.show-data-labels',
1249
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1250
+ schema: {
1251
+ defaultValue: true,
1252
+ dataType: 'boolean',
1253
+ interface: {
1254
+ name: 'showDataLabels',
1255
+ path: 'options.showDataLabels',
1256
+ type: AXPWidgetsCatalog.toggle,
1228
1257
  },
1229
- visible: true,
1258
+ },
1259
+ visible: true,
1230
1260
  },
1231
1261
  {
1232
- name: 'donutWidth',
1233
- title: 'Donut Width',
1234
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1235
- schema: {
1236
- defaultValue: 35,
1237
- dataType: 'number',
1238
- interface: {
1239
- name: 'donutWidth',
1240
- path: 'options.donutWidth',
1241
- type: AXPWidgetsCatalog.number,
1242
- options: {
1243
- placeholder: '10-80',
1244
- minValue: 10,
1245
- maxValue: 80,
1246
- },
1247
- },
1262
+ name: 'donutWidth',
1263
+ title: '@dashboard:widgets.donut-chart.donut-width',
1264
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1265
+ schema: {
1266
+ defaultValue: 35,
1267
+ dataType: 'number',
1268
+ interface: {
1269
+ name: 'donutWidth',
1270
+ path: 'options.donutWidth',
1271
+ type: AXPWidgetsCatalog.number,
1272
+ options: {
1273
+ placeholder: '10-80',
1274
+ minValue: 10,
1275
+ maxValue: 80,
1276
+ },
1248
1277
  },
1249
- visible: true,
1278
+ },
1279
+ visible: true,
1250
1280
  },
1251
1281
  {
1252
- name: 'cornerRadius',
1253
- title: 'Corner Radius',
1254
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1255
- schema: {
1256
- defaultValue: 4,
1257
- dataType: 'number',
1258
- interface: {
1259
- name: 'cornerRadius',
1260
- path: 'options.cornerRadius',
1261
- type: AXPWidgetsCatalog.number,
1262
- options: {
1263
- placeholder: '0-20',
1264
- minValue: 0,
1265
- maxValue: 20,
1266
- },
1267
- },
1282
+ name: 'cornerRadius',
1283
+ title: '@dashboard:widgets.donut-chart.corner-radius',
1284
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1285
+ schema: {
1286
+ defaultValue: 4,
1287
+ dataType: 'number',
1288
+ interface: {
1289
+ name: 'cornerRadius',
1290
+ path: 'options.cornerRadius',
1291
+ type: AXPWidgetsCatalog.number,
1292
+ options: {
1293
+ placeholder: '0-20',
1294
+ minValue: 0,
1295
+ maxValue: 20,
1296
+ },
1268
1297
  },
1269
- visible: true,
1298
+ },
1299
+ visible: true,
1270
1300
  },
1271
1301
  // ====== Legend ======
1272
1302
  // {
@@ -1304,71 +1334,72 @@ const AXPDonutChartWidget = {
1304
1334
  // },
1305
1335
  // ====== Tooltip ======
1306
1336
  {
1307
- name: 'showTooltip',
1308
- title: 'Show Tooltip',
1309
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1310
- schema: {
1311
- defaultValue: true,
1312
- dataType: 'boolean',
1313
- interface: {
1314
- name: 'showTooltip',
1315
- path: 'options.showTooltip',
1316
- type: AXPWidgetsCatalog.toggle,
1317
- },
1337
+ name: 'showTooltip',
1338
+ title: '@dashboard:widgets.donut-chart.show-tooltip',
1339
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1340
+ schema: {
1341
+ defaultValue: true,
1342
+ dataType: 'boolean',
1343
+ interface: {
1344
+ name: 'showTooltip',
1345
+ path: 'options.showTooltip',
1346
+ type: AXPWidgetsCatalog.toggle,
1318
1347
  },
1319
- visible: true,
1348
+ },
1349
+ visible: true,
1320
1350
  },
1321
1351
  // ====== Animation Settings ======
1322
1352
  {
1323
- name: 'animationEasing',
1324
- title: 'Animation Easing',
1325
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1326
- schema: {
1327
- defaultValue: 'cubic-out',
1328
- dataType: 'string',
1329
- interface: {
1330
- name: 'animationEasing',
1331
- path: 'options.animationEasing',
1332
- type: AXPWidgetsCatalog.select,
1333
- options: {
1334
- dataSource: [
1335
- { value: 'linear', text: 'Linear' },
1336
- { value: 'ease', text: 'Ease' },
1337
- { value: 'ease-in', text: 'Ease In' },
1338
- { value: 'ease-out', text: 'Ease Out' },
1339
- { value: 'ease-in-out', text: 'Ease In Out' },
1340
- { value: 'cubic', text: 'Cubic' },
1341
- { value: 'cubic-in', text: 'Cubic In' },
1342
- { value: 'cubic-out', text: 'Cubic Out' },
1343
- { value: 'cubic-in-out', text: 'Cubic In Out' },
1344
- ],
1345
- textField: 'text',
1346
- valueField: 'value',
1347
- },
1348
- },
1353
+ name: 'animationEasing',
1354
+ title: '@dashboard:widgets.donut-chart.animation-easing',
1355
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1356
+ schema: {
1357
+ defaultValue: 'cubic-out',
1358
+ dataType: 'string',
1359
+ interface: {
1360
+ name: 'animationEasing',
1361
+ path: 'options.animationEasing',
1362
+ type: AXPWidgetsCatalog.select,
1363
+ options: {
1364
+ dataSource: [
1365
+ { value: 'linear', text: 'Linear' },
1366
+ { value: 'ease', text: 'Ease' },
1367
+ { value: 'ease-in', text: 'Ease In' },
1368
+ { value: 'ease-out', text: 'Ease Out' },
1369
+ { value: 'ease-in-out', text: 'Ease In Out' },
1370
+ { value: 'cubic', text: 'Cubic' },
1371
+ { value: 'cubic-in', text: 'Cubic In' },
1372
+ { value: 'cubic-out', text: 'Cubic Out' },
1373
+ { value: 'cubic-in-out', text: 'Cubic In Out' },
1374
+ ],
1375
+ textField: 'text',
1376
+ valueField: 'value',
1377
+ },
1349
1378
  },
1350
- visible: true,
1379
+ },
1380
+ visible: true,
1351
1381
  },
1352
1382
  {
1353
- name: 'animationDuration',
1354
- title: 'Animation Duration',
1355
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1356
- schema: {
1357
- defaultValue: 800,
1358
- dataType: 'number',
1359
- interface: {
1360
- name: 'animationDuration',
1361
- path: 'options.animationDuration',
1362
- type: AXPWidgetsCatalog.number,
1363
- options: {
1364
- placeholder: '0-2000',
1365
- minValue: 0,
1366
- maxValue: 2000,
1367
- },
1368
- },
1383
+ name: 'animationDuration',
1384
+ title: '@dashboard:widgets.donut-chart.animation-duration',
1385
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1386
+ schema: {
1387
+ defaultValue: 800,
1388
+ dataType: 'number',
1389
+ interface: {
1390
+ name: 'animationDuration',
1391
+ path: 'options.animationDuration',
1392
+ type: AXPWidgetsCatalog.number,
1393
+ options: {
1394
+ placeholder: '0-2000',
1395
+ minValue: 0,
1396
+ maxValue: 2000,
1397
+ },
1369
1398
  },
1370
- visible: true,
1399
+ },
1400
+ visible: true,
1371
1401
  },
1402
+ */
1372
1403
  ],
1373
1404
  components: {
1374
1405
  view: {
@@ -1393,17 +1424,29 @@ const AXPDonutChartWidget = {
1393
1424
  */
1394
1425
  class AXPGaugeChartWidgetViewComponent extends AXPValueWidgetComponent {
1395
1426
  constructor() {
1396
- super(...arguments);
1427
+ super();
1397
1428
  this.gaugeChartValue = computed(() => this.getValue());
1398
1429
  this.gaugeChartOptions = computed(() => this.options());
1430
+ this.setOptions({
1431
+ ...this.options(),
1432
+ width: null,
1433
+ height: 300,
1434
+ minValue: 0,
1435
+ maxValue: 100,
1436
+ showTooltip: true,
1437
+ gaugeWidth: 30,
1438
+ cornerRadius: 4,
1439
+ animationEasing: 'cubic-out',
1440
+ animationDuration: 800,
1441
+ });
1399
1442
  }
1400
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1443
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1401
1444
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AXPGaugeChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-gauge-chart [value]=\"gaugeChartValue()\" [options]=\"gaugeChartOptions()\"></ax-gauge-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXGaugeChartComponent, selector: "ax-gauge-chart", inputs: ["value", "options"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1402
1445
  }
1403
1446
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPGaugeChartWidgetViewComponent, decorators: [{
1404
1447
  type: Component,
1405
1448
  args: [{ imports: [AXGaugeChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-gauge-chart [value]=\"gaugeChartValue()\" [options]=\"gaugeChartOptions()\"></ax-gauge-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
1406
- }] });
1449
+ }], ctorParameters: () => [] });
1407
1450
 
1408
1451
  var gaugeChartWidget_component = /*#__PURE__*/Object.freeze({
1409
1452
  __proto__: null,
@@ -1422,7 +1465,7 @@ const AXPGaugeChartWidget = {
1422
1465
  // ====== Chart Title ======
1423
1466
  {
1424
1467
  name: 'title',
1425
- title: 'Chart Title',
1468
+ title: '@dashboard:widgets.gauge-chart.chart-title',
1426
1469
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1427
1470
  schema: {
1428
1471
  defaultValue: '',
@@ -1438,201 +1481,203 @@ const AXPGaugeChartWidget = {
1438
1481
  },
1439
1482
  visible: true,
1440
1483
  },
1441
- // ====== Layout & Dimensions ======
1484
+ // ====== Label Display ======
1442
1485
  {
1443
- name: 'width',
1444
- title: 'Width',
1445
- group: AXP_STYLING_PROPERTY_GROUP,
1486
+ name: 'label',
1487
+ title: '@dashboard:widgets.gauge-chart.label',
1488
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1446
1489
  schema: {
1447
- defaultValue: null,
1448
- dataType: 'number',
1490
+ defaultValue: '',
1491
+ dataType: 'string',
1449
1492
  interface: {
1450
- name: 'width',
1451
- path: 'options.width',
1452
- type: AXPWidgetsCatalog.number,
1453
- options: {
1454
- placeholder: '1-1200',
1455
- minValue: 1,
1456
- maxValue: 1200,
1457
- },
1493
+ name: 'label',
1494
+ path: 'options.label',
1495
+ type: AXPWidgetsCatalog.text,
1458
1496
  },
1459
1497
  },
1460
1498
  visible: true,
1461
1499
  },
1500
+ /* Commented out properties
1501
+ // ====== Layout & Dimensions ======
1462
1502
  {
1463
- name: 'height',
1464
- title: 'Height',
1465
- group: AXP_STYLING_PROPERTY_GROUP,
1466
- schema: {
1467
- defaultValue: 300,
1468
- dataType: 'number',
1469
- interface: {
1470
- name: 'height',
1471
- path: 'options.height',
1472
- type: AXPWidgetsCatalog.number,
1473
- options: {
1474
- placeholder: '1-800',
1475
- minValue: 1,
1476
- maxValue: 800,
1477
- },
1478
- },
1503
+ name: 'width',
1504
+ title: '@dashboard:widgets.gauge-chart.width',
1505
+ group: AXP_STYLING_PROPERTY_GROUP,
1506
+ schema: {
1507
+ defaultValue: null,
1508
+ dataType: 'number',
1509
+ interface: {
1510
+ name: 'width',
1511
+ path: 'options.width',
1512
+ type: AXPWidgetsCatalog.number,
1513
+ options: {
1514
+ placeholder: '1-1200',
1515
+ minValue: 1,
1516
+ maxValue: 1200,
1517
+ },
1479
1518
  },
1480
- visible: true,
1519
+ },
1520
+ visible: true,
1481
1521
  },
1482
- // ====== Gauge Configuration ======
1483
1522
  {
1484
- name: 'minValue',
1485
- title: 'Minimum Value',
1486
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1487
- schema: {
1488
- defaultValue: 0,
1489
- dataType: 'number',
1490
- interface: {
1491
- name: 'minValue',
1492
- path: 'options.minValue',
1493
- type: AXPWidgetsCatalog.number,
1494
- },
1523
+ name: 'height',
1524
+ title: '@dashboard:widgets.gauge-chart.height',
1525
+ group: AXP_STYLING_PROPERTY_GROUP,
1526
+ schema: {
1527
+ defaultValue: 300,
1528
+ dataType: 'number',
1529
+ interface: {
1530
+ name: 'height',
1531
+ path: 'options.height',
1532
+ type: AXPWidgetsCatalog.number,
1533
+ options: {
1534
+ placeholder: '1-800',
1535
+ minValue: 1,
1536
+ maxValue: 800,
1537
+ },
1495
1538
  },
1496
- visible: true,
1539
+ },
1540
+ visible: true,
1497
1541
  },
1542
+ // ====== Gauge Configuration ======
1498
1543
  {
1499
- name: 'maxValue',
1500
- title: 'Maximum Value',
1501
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1502
- schema: {
1503
- defaultValue: 100,
1504
- dataType: 'number',
1505
- interface: {
1506
- name: 'maxValue',
1507
- path: 'options.maxValue',
1508
- type: AXPWidgetsCatalog.number,
1509
- },
1544
+ name: 'minValue',
1545
+ title: '@dashboard:widgets.gauge-chart.min-value',
1546
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1547
+ schema: {
1548
+ defaultValue: 0,
1549
+ dataType: 'number',
1550
+ interface: {
1551
+ name: 'minValue',
1552
+ path: 'options.minValue',
1553
+ type: AXPWidgetsCatalog.number,
1510
1554
  },
1511
- visible: true,
1555
+ },
1556
+ visible: true,
1512
1557
  },
1513
- // ====== Gauge Appearance ======
1514
1558
  {
1515
- name: 'showTooltip',
1516
- title: 'Show Tooltip',
1517
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1518
- schema: {
1519
- defaultValue: true,
1520
- dataType: 'boolean',
1521
- interface: {
1522
- name: 'showTooltip',
1523
- path: 'options.showTooltip',
1524
- type: AXPWidgetsCatalog.toggle,
1525
- },
1559
+ name: 'maxValue',
1560
+ title: '@dashboard:widgets.gauge-chart.max-value',
1561
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1562
+ schema: {
1563
+ defaultValue: 100,
1564
+ dataType: 'number',
1565
+ interface: {
1566
+ name: 'maxValue',
1567
+ path: 'options.maxValue',
1568
+ type: AXPWidgetsCatalog.number,
1526
1569
  },
1527
- visible: true,
1570
+ },
1571
+ visible: true,
1528
1572
  },
1573
+ // ====== Gauge Appearance ======
1529
1574
  {
1530
- name: 'gaugeWidth',
1531
- title: 'Gauge Width',
1532
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1533
- schema: {
1534
- defaultValue: 30,
1535
- dataType: 'number',
1536
- interface: {
1537
- name: 'gaugeWidth',
1538
- path: 'options.gaugeWidth',
1539
- type: AXPWidgetsCatalog.number,
1540
- options: {
1541
- placeholder: '1-100',
1542
- minValue: 1,
1543
- maxValue: 100,
1544
- },
1545
- },
1575
+ name: 'showTooltip',
1576
+ title: '@dashboard:widgets.gauge-chart.show-tooltip',
1577
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1578
+ schema: {
1579
+ defaultValue: true,
1580
+ dataType: 'boolean',
1581
+ interface: {
1582
+ name: 'showTooltip',
1583
+ path: 'options.showTooltip',
1584
+ type: AXPWidgetsCatalog.toggle,
1546
1585
  },
1547
- visible: true,
1586
+ },
1587
+ visible: true,
1548
1588
  },
1549
1589
  {
1550
- name: 'cornerRadius',
1551
- title: 'Corner Radius',
1552
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1553
- schema: {
1554
- defaultValue: 4,
1555
- dataType: 'number',
1556
- interface: {
1557
- name: 'cornerRadius',
1558
- path: 'options.cornerRadius',
1559
- type: AXPWidgetsCatalog.number,
1560
- options: {
1561
- placeholder: '1-20',
1562
- minValue: 0,
1563
- maxValue: 20,
1564
- },
1565
- },
1590
+ name: 'gaugeWidth',
1591
+ title: '@dashboard:widgets.gauge-chart.gauge-width',
1592
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1593
+ schema: {
1594
+ defaultValue: 30,
1595
+ dataType: 'number',
1596
+ interface: {
1597
+ name: 'gaugeWidth',
1598
+ path: 'options.gaugeWidth',
1599
+ type: AXPWidgetsCatalog.number,
1600
+ options: {
1601
+ placeholder: '1-100',
1602
+ minValue: 1,
1603
+ maxValue: 100,
1604
+ },
1566
1605
  },
1567
- visible: true,
1606
+ },
1607
+ visible: true,
1568
1608
  },
1569
- // ====== Label Display ======
1570
1609
  {
1571
- name: 'label',
1572
- title: 'Label Text',
1573
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1574
- schema: {
1575
- defaultValue: '',
1576
- dataType: 'string',
1577
- interface: {
1578
- name: 'label',
1579
- path: 'options.label',
1580
- type: AXPWidgetsCatalog.text,
1581
- },
1610
+ name: 'cornerRadius',
1611
+ title: '@dashboard:widgets.gauge-chart.corner-radius',
1612
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1613
+ schema: {
1614
+ defaultValue: 4,
1615
+ dataType: 'number',
1616
+ interface: {
1617
+ name: 'cornerRadius',
1618
+ path: 'options.cornerRadius',
1619
+ type: AXPWidgetsCatalog.number,
1620
+ options: {
1621
+ placeholder: '1-20',
1622
+ minValue: 0,
1623
+ maxValue: 20,
1624
+ },
1582
1625
  },
1583
- visible: true,
1626
+ },
1627
+ visible: true,
1584
1628
  },
1585
1629
  // ====== Animation Settings ======
1586
1630
  {
1587
- name: 'animationEasing',
1588
- title: 'Animation Easing',
1589
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1590
- schema: {
1591
- defaultValue: 'cubic-out',
1592
- dataType: 'string',
1593
- interface: {
1594
- name: 'animationEasing',
1595
- path: 'options.animationEasing',
1596
- type: AXPWidgetsCatalog.select,
1597
- options: {
1598
- dataSource: [
1599
- { value: 'linear', text: 'Linear' },
1600
- { value: 'ease', text: 'Ease' },
1601
- { value: 'ease-in', text: 'Ease In' },
1602
- { value: 'ease-out', text: 'Ease Out' },
1603
- { value: 'ease-in-out', text: 'Ease In Out' },
1604
- { value: 'cubic', text: 'Cubic' },
1605
- { value: 'cubic-in', text: 'Cubic In' },
1606
- { value: 'cubic-out', text: 'Cubic Out' },
1607
- { value: 'cubic-in-out', text: 'Cubic In Out' },
1608
- ],
1609
- textField: 'text',
1610
- valueField: 'value',
1611
- },
1612
- },
1631
+ name: 'animationEasing',
1632
+ title: '@dashboard:widgets.gauge-chart.animation-easing',
1633
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1634
+ schema: {
1635
+ defaultValue: 'cubic-out',
1636
+ dataType: 'string',
1637
+ interface: {
1638
+ name: 'animationEasing',
1639
+ path: 'options.animationEasing',
1640
+ type: AXPWidgetsCatalog.select,
1641
+ options: {
1642
+ dataSource: [
1643
+ { value: 'linear', text: 'Linear' },
1644
+ { value: 'ease', text: 'Ease' },
1645
+ { value: 'ease-in', text: 'Ease In' },
1646
+ { value: 'ease-out', text: 'Ease Out' },
1647
+ { value: 'ease-in-out', text: 'Ease In Out' },
1648
+ { value: 'cubic', text: 'Cubic' },
1649
+ { value: 'cubic-in', text: 'Cubic In' },
1650
+ { value: 'cubic-out', text: 'Cubic Out' },
1651
+ { value: 'cubic-in-out', text: 'Cubic In Out' },
1652
+ ],
1653
+ textField: 'text',
1654
+ valueField: 'value',
1655
+ },
1613
1656
  },
1614
- visible: true,
1657
+ },
1658
+ visible: true,
1615
1659
  },
1616
1660
  {
1617
- name: 'animationDuration',
1618
- title: 'Animation Duration',
1619
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1620
- schema: {
1621
- defaultValue: 800,
1622
- dataType: 'number',
1623
- interface: {
1624
- name: 'animationDuration',
1625
- path: 'options.animationDuration',
1626
- type: AXPWidgetsCatalog.number,
1627
- options: {
1628
- placeholder: '0-2000',
1629
- minValue: 0,
1630
- maxValue: 2000,
1631
- },
1632
- },
1661
+ name: 'animationDuration',
1662
+ title: '@dashboard:widgets.gauge-chart.animation-duration',
1663
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1664
+ schema: {
1665
+ defaultValue: 800,
1666
+ dataType: 'number',
1667
+ interface: {
1668
+ name: 'animationDuration',
1669
+ path: 'options.animationDuration',
1670
+ type: AXPWidgetsCatalog.number,
1671
+ options: {
1672
+ placeholder: '0-2000',
1673
+ minValue: 0,
1674
+ maxValue: 2000,
1675
+ },
1633
1676
  },
1634
- visible: true,
1677
+ },
1678
+ visible: true,
1635
1679
  },
1680
+ */
1636
1681
  ],
1637
1682
  components: {
1638
1683
  view: {
@@ -1657,20 +1702,37 @@ const AXPGaugeChartWidget = {
1657
1702
  */
1658
1703
  class AXPLineChartWidgetViewComponent extends AXPValueWidgetComponent {
1659
1704
  constructor() {
1660
- super(...arguments);
1705
+ super();
1661
1706
  this.lineChartData = computed(() => this.getValue());
1662
1707
  this.lineChartOptions = computed(() => this.options());
1708
+ this.setOptions({
1709
+ ...this.options(),
1710
+ showXAxis: true,
1711
+ showYAxis: true,
1712
+ yAxisStartsAtZero: true,
1713
+ showGrid: true,
1714
+ showVerticalGrid: true,
1715
+ lineWidth: 2,
1716
+ smoothLine: true,
1717
+ showPoints: true,
1718
+ pointRadius: 4,
1719
+ fillOpacity: 80,
1720
+ showTooltip: true,
1721
+ showCrosshair: true,
1722
+ animationEasing: 'cubic-out',
1723
+ animationDuration: 800,
1724
+ });
1663
1725
  }
1664
1726
  handleLineChartPointClick(event) {
1665
1727
  //console.log(event);
1666
1728
  }
1667
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPLineChartWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1729
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPLineChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1668
1730
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AXPLineChartWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<ax-line-chart\n (pointClick)=\"handleLineChartPointClick($event)\"\n [data]=\"lineChartData()\"\n [options]=\"lineChartOptions()\"\n></ax-line-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: AXLineChartComponent, selector: "ax-line-chart", inputs: ["data", "options"], outputs: ["pointClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1669
1731
  }
1670
1732
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPLineChartWidgetViewComponent, decorators: [{
1671
1733
  type: Component,
1672
1734
  args: [{ standalone: true, imports: [AXLineChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ax-line-chart\n (pointClick)=\"handleLineChartPointClick($event)\"\n [data]=\"lineChartData()\"\n [options]=\"lineChartOptions()\"\n></ax-line-chart>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
1673
- }] });
1735
+ }], ctorParameters: () => [] });
1674
1736
 
1675
1737
  var lineChartWidget_component = /*#__PURE__*/Object.freeze({
1676
1738
  __proto__: null,
@@ -1690,7 +1752,7 @@ const AXPLineChartWidget = {
1690
1752
  // ====== Chart Title ======
1691
1753
  {
1692
1754
  name: 'title',
1693
- title: 'Chart Title',
1755
+ title: '@dashboard:widgets.line-chart.chart-title',
1694
1756
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1695
1757
  schema: {
1696
1758
  defaultValue: '',
@@ -1706,64 +1768,10 @@ const AXPLineChartWidget = {
1706
1768
  },
1707
1769
  visible: true,
1708
1770
  },
1709
- // ====== Layout & Dimensions ======
1710
- {
1711
- name: 'width',
1712
- title: 'Width',
1713
- group: AXP_STYLING_PROPERTY_GROUP,
1714
- schema: {
1715
- defaultValue: null,
1716
- dataType: 'number',
1717
- interface: {
1718
- name: 'width',
1719
- path: 'options.width',
1720
- type: AXPWidgetsCatalog.number,
1721
- options: {
1722
- minValue: 0,
1723
- maxValue: 1200,
1724
- },
1725
- },
1726
- },
1727
- visible: true,
1728
- },
1729
- {
1730
- name: 'height',
1731
- title: 'Height',
1732
- group: AXP_STYLING_PROPERTY_GROUP,
1733
- schema: {
1734
- defaultValue: 300,
1735
- dataType: 'number',
1736
- interface: {
1737
- name: 'height',
1738
- path: 'options.height',
1739
- type: AXPWidgetsCatalog.number,
1740
- options: {
1741
- minValue: 0,
1742
- maxValue: 800,
1743
- },
1744
- },
1745
- },
1746
- visible: true,
1747
- },
1748
1771
  // ====== Axis Settings ======
1749
- {
1750
- name: 'showXAxis',
1751
- title: 'Show X Axis',
1752
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1753
- schema: {
1754
- defaultValue: true,
1755
- dataType: 'boolean',
1756
- interface: {
1757
- name: 'showXAxis',
1758
- path: 'options.showXAxis',
1759
- type: AXPWidgetsCatalog.toggle,
1760
- },
1761
- },
1762
- visible: true,
1763
- },
1764
1772
  {
1765
1773
  name: 'xAxisLabel',
1766
- title: 'X Axis Label',
1774
+ title: '@dashboard:widgets.line-chart.x-axis-label',
1767
1775
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1768
1776
  schema: {
1769
1777
  defaultValue: '',
@@ -1776,24 +1784,9 @@ const AXPLineChartWidget = {
1776
1784
  },
1777
1785
  visible: true,
1778
1786
  },
1779
- {
1780
- name: 'showYAxis',
1781
- title: 'Show Y Axis',
1782
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1783
- schema: {
1784
- defaultValue: true,
1785
- dataType: 'boolean',
1786
- interface: {
1787
- name: 'showYAxis',
1788
- path: 'options.showYAxis',
1789
- type: AXPWidgetsCatalog.toggle,
1790
- },
1791
- },
1792
- visible: true,
1793
- },
1794
1787
  {
1795
1788
  name: 'yAxisLabel',
1796
- title: 'Y Axis Label',
1789
+ title: '@dashboard:widgets.line-chart.y-axis-label',
1797
1790
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1798
1791
  schema: {
1799
1792
  defaultValue: '',
@@ -1807,238 +1800,315 @@ const AXPLineChartWidget = {
1807
1800
  visible: true,
1808
1801
  },
1809
1802
  {
1810
- name: 'yAxisStartsAtZero',
1811
- title: 'Y Axis Starts At Zero',
1803
+ name: 'fillArea',
1804
+ title: '@dashboard:widgets.line-chart.fill-area',
1812
1805
  group: AXP_APPEARANCE_PROPERTY_GROUP,
1813
1806
  schema: {
1814
- defaultValue: true,
1807
+ defaultValue: false,
1815
1808
  dataType: 'boolean',
1816
1809
  interface: {
1817
- name: 'yAxisStartsAtZero',
1818
- path: 'options.yAxisStartsAtZero',
1810
+ name: 'fillArea',
1811
+ path: 'options.fillArea',
1819
1812
  type: AXPWidgetsCatalog.toggle,
1820
1813
  },
1821
1814
  },
1822
1815
  visible: true,
1823
1816
  },
1817
+ /* Commented out properties
1818
+ // ====== Layout & Dimensions ======
1824
1819
  {
1825
- name: 'showGrid',
1826
- title: 'Show Grid Lines',
1827
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1828
- schema: {
1829
- defaultValue: true,
1830
- dataType: 'boolean',
1831
- interface: {
1832
- name: 'showGrid',
1833
- path: 'options.showGrid',
1834
- type: AXPWidgetsCatalog.toggle,
1835
- },
1820
+ name: 'width',
1821
+ title: '@dashboard:widgets.line-chart.width',
1822
+ group: AXP_STYLING_PROPERTY_GROUP,
1823
+ schema: {
1824
+ defaultValue: null,
1825
+ dataType: 'number',
1826
+ interface: {
1827
+ name: 'width',
1828
+ path: 'options.width',
1829
+ type: AXPWidgetsCatalog.number,
1830
+ options: {
1831
+ minValue: 0,
1832
+ maxValue: 1200,
1833
+ },
1836
1834
  },
1837
- visible: true,
1835
+ },
1836
+ visible: true,
1838
1837
  },
1839
1838
  {
1840
- name: 'showVerticalGrid',
1841
- title: 'Show Vertical Grid',
1842
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1843
- schema: {
1844
- defaultValue: true,
1845
- dataType: 'boolean',
1846
- interface: {
1847
- name: 'showVerticalGrid',
1848
- path: 'options.showVerticalGrid',
1849
- type: AXPWidgetsCatalog.toggle,
1850
- },
1839
+ name: 'height',
1840
+ title: '@dashboard:widgets.line-chart.height',
1841
+ group: AXP_STYLING_PROPERTY_GROUP,
1842
+ schema: {
1843
+ defaultValue: 300,
1844
+ dataType: 'number',
1845
+ interface: {
1846
+ name: 'height',
1847
+ path: 'options.height',
1848
+ type: AXPWidgetsCatalog.number,
1849
+ options: {
1850
+ minValue: 0,
1851
+ maxValue: 800,
1852
+ },
1851
1853
  },
1852
- visible: true,
1854
+ },
1855
+ visible: true,
1853
1856
  },
1854
- // ====== Line Appearance ======
1857
+
1858
+ // ====== Axis Settings ======
1855
1859
  {
1856
- name: 'lineWidth',
1857
- title: 'Line Width',
1858
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1859
- schema: {
1860
- defaultValue: 2,
1861
- dataType: 'number',
1862
- interface: {
1863
- name: 'lineWidth',
1864
- path: 'options.lineWidth',
1865
- type: AXPWidgetsCatalog.number,
1866
- options: {
1867
- placeholder: '1-10',
1868
- minValue: 1,
1869
- maxValue: 10,
1870
- },
1871
- },
1860
+ name: 'showXAxis',
1861
+ title: '@dashboard:widgets.line-chart.show-x-axis',
1862
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1863
+ schema: {
1864
+ defaultValue: true,
1865
+ dataType: 'boolean',
1866
+ interface: {
1867
+ name: 'showXAxis',
1868
+ path: 'options.showXAxis',
1869
+ type: AXPWidgetsCatalog.toggle,
1872
1870
  },
1873
- visible: true,
1871
+ },
1872
+ visible: true,
1874
1873
  },
1875
1874
  {
1876
- name: 'smoothLine',
1877
- title: 'Smooth Line',
1878
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1879
- schema: {
1880
- defaultValue: true,
1881
- dataType: 'boolean',
1882
- interface: {
1883
- name: 'smoothLine',
1884
- path: 'options.smoothLine',
1885
- type: AXPWidgetsCatalog.toggle,
1886
- },
1875
+ name: 'showYAxis',
1876
+ title: '@dashboard:widgets.line-chart.show-y-axis',
1877
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1878
+ schema: {
1879
+ defaultValue: true,
1880
+ dataType: 'boolean',
1881
+ interface: {
1882
+ name: 'showYAxis',
1883
+ path: 'options.showYAxis',
1884
+ type: AXPWidgetsCatalog.toggle,
1887
1885
  },
1888
- visible: true,
1886
+ },
1887
+ visible: true,
1889
1888
  },
1890
1889
  {
1891
- name: 'showPoints',
1892
- title: 'Show Points',
1893
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1894
- schema: {
1895
- defaultValue: true,
1896
- dataType: 'boolean',
1897
- interface: {
1898
- name: 'showPoints',
1899
- path: 'options.showPoints',
1900
- type: AXPWidgetsCatalog.toggle,
1901
- },
1890
+ name: 'yAxisStartsAtZero',
1891
+ title: '@dashboard:widgets.line-chart.y-axis-starts-at-zero',
1892
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1893
+ schema: {
1894
+ defaultValue: true,
1895
+ dataType: 'boolean',
1896
+ interface: {
1897
+ name: 'yAxisStartsAtZero',
1898
+ path: 'options.yAxisStartsAtZero',
1899
+ type: AXPWidgetsCatalog.toggle,
1902
1900
  },
1903
- visible: true,
1901
+ },
1902
+ visible: true,
1904
1903
  },
1904
+
1905
1905
  {
1906
- name: 'pointRadius',
1907
- title: 'Point Size',
1908
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1909
- schema: {
1910
- defaultValue: 4,
1911
- dataType: 'number',
1912
- interface: {
1913
- name: 'pointRadius',
1914
- path: 'options.pointRadius',
1915
- type: AXPWidgetsCatalog.number,
1916
- options: {
1917
- placeholder: '1-10',
1918
- minValue: 1,
1919
- maxValue: 10,
1920
- },
1921
- },
1906
+ name: 'showGrid',
1907
+ title: '@dashboard:widgets.line-chart.show-grid',
1908
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1909
+ schema: {
1910
+ defaultValue: true,
1911
+ dataType: 'boolean',
1912
+ interface: {
1913
+ name: 'showGrid',
1914
+ path: 'options.showGrid',
1915
+ type: AXPWidgetsCatalog.toggle,
1916
+ },
1917
+ },
1918
+ visible: true,
1919
+ },
1920
+ {
1921
+ name: 'showVerticalGrid',
1922
+ title: '@dashboard:widgets.line-chart.show-vertical-grid',
1923
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1924
+ schema: {
1925
+ defaultValue: true,
1926
+ dataType: 'boolean',
1927
+ interface: {
1928
+ name: 'showVerticalGrid',
1929
+ path: 'options.showVerticalGrid',
1930
+ type: AXPWidgetsCatalog.toggle,
1931
+ },
1932
+ },
1933
+ visible: true,
1934
+ },
1935
+
1936
+ // ====== Line Appearance ======
1937
+ {
1938
+ name: 'lineWidth',
1939
+ title: '@dashboard:widgets.line-chart.line-width',
1940
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1941
+ schema: {
1942
+ defaultValue: 2,
1943
+ dataType: 'number',
1944
+ interface: {
1945
+ name: 'lineWidth',
1946
+ path: 'options.lineWidth',
1947
+ type: AXPWidgetsCatalog.number,
1948
+ options: {
1949
+ placeholder: '1-10',
1950
+ minValue: 1,
1951
+ maxValue: 10,
1952
+ },
1953
+ },
1954
+ },
1955
+ visible: true,
1956
+ },
1957
+ {
1958
+ name: 'smoothLine',
1959
+ title: '@dashboard:widgets.line-chart.smooth-line',
1960
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1961
+ schema: {
1962
+ defaultValue: true,
1963
+ dataType: 'boolean',
1964
+ interface: {
1965
+ name: 'smoothLine',
1966
+ path: 'options.smoothLine',
1967
+ type: AXPWidgetsCatalog.toggle,
1922
1968
  },
1923
- visible: true,
1969
+ },
1970
+ visible: true,
1924
1971
  },
1925
1972
  {
1926
- name: 'fillArea',
1927
- title: 'Fill Area',
1928
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1929
- schema: {
1930
- defaultValue: false,
1931
- dataType: 'boolean',
1932
- interface: {
1933
- name: 'fillArea',
1934
- path: 'options.fillArea',
1935
- type: AXPWidgetsCatalog.toggle,
1936
- },
1973
+ name: 'showPoints',
1974
+ title: '@dashboard:widgets.line-chart.show-points',
1975
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1976
+ schema: {
1977
+ defaultValue: true,
1978
+ dataType: 'boolean',
1979
+ interface: {
1980
+ name: 'showPoints',
1981
+ path: 'options.showPoints',
1982
+ type: AXPWidgetsCatalog.toggle,
1937
1983
  },
1938
- visible: true,
1984
+ },
1985
+ visible: true,
1939
1986
  },
1940
1987
  {
1941
- name: 'fillOpacity',
1942
- title: 'Fill Opacity',
1943
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1944
- schema: {
1945
- defaultValue: 10,
1946
- dataType: 'number',
1947
- interface: {
1948
- name: 'fillOpacity',
1949
- path: 'options.fillOpacity',
1950
- type: AXPWidgetsCatalog.number,
1951
- options: {
1952
- placeholder: '0-100',
1953
- minValue: 0,
1954
- maxValue: 100,
1955
- },
1956
- },
1988
+ name: 'pointRadius',
1989
+ title: '@dashboard:widgets.line-chart.point-radius',
1990
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
1991
+ schema: {
1992
+ defaultValue: 4,
1993
+ dataType: 'number',
1994
+ interface: {
1995
+ name: 'pointRadius',
1996
+ path: 'options.pointRadius',
1997
+ type: AXPWidgetsCatalog.number,
1998
+ options: {
1999
+ placeholder: '1-10',
2000
+ minValue: 1,
2001
+ maxValue: 10,
2002
+ },
1957
2003
  },
1958
- visible: true,
2004
+ },
2005
+ visible: true,
1959
2006
  },
2007
+ {
2008
+ name: 'fillOpacity',
2009
+ title: '@dashboard:widgets.line-chart.fill-opacity',
2010
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
2011
+ schema: {
2012
+ defaultValue: 80,
2013
+ dataType: 'number',
2014
+ interface: {
2015
+ name: 'fillOpacity',
2016
+ path: 'options.fillOpacity',
2017
+ type: AXPWidgetsCatalog.number,
2018
+ options: {
2019
+ placeholder: '1-100',
2020
+ minValue: 1,
2021
+ maxValue: 100,
2022
+ },
2023
+ },
2024
+ },
2025
+ visible: true,
2026
+ },
2027
+
1960
2028
  // ====== Tooltip Settings ======
1961
2029
  {
1962
- name: 'showTooltip',
1963
- title: 'Show Tooltip',
1964
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1965
- schema: {
1966
- defaultValue: true,
1967
- dataType: 'boolean',
1968
- interface: {
1969
- name: 'showTooltip',
1970
- path: 'options.showTooltip',
1971
- type: AXPWidgetsCatalog.toggle,
1972
- },
2030
+ name: 'showTooltip',
2031
+ title: '@dashboard:widgets.line-chart.show-tooltip',
2032
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
2033
+ schema: {
2034
+ defaultValue: true,
2035
+ dataType: 'boolean',
2036
+ interface: {
2037
+ name: 'showTooltip',
2038
+ path: 'options.showTooltip',
2039
+ type: AXPWidgetsCatalog.toggle,
1973
2040
  },
1974
- visible: true,
2041
+ },
2042
+ visible: true,
1975
2043
  },
1976
2044
  {
1977
- name: 'showCrosshair',
1978
- title: 'Show Crosshair',
1979
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1980
- schema: {
1981
- defaultValue: false,
1982
- dataType: 'boolean',
1983
- interface: {
1984
- name: 'showCrosshair',
1985
- path: 'options.showCrosshair',
1986
- type: AXPWidgetsCatalog.toggle,
1987
- },
2045
+ name: 'showCrosshair',
2046
+ title: '@dashboard:widgets.line-chart.show-crosshair',
2047
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
2048
+ schema: {
2049
+ defaultValue: true,
2050
+ dataType: 'boolean',
2051
+ interface: {
2052
+ name: 'showCrosshair',
2053
+ path: 'options.showCrosshair',
2054
+ type: AXPWidgetsCatalog.toggle,
1988
2055
  },
1989
- visible: true,
2056
+ },
2057
+ visible: true,
1990
2058
  },
2059
+
1991
2060
  // ====== Animation Settings ======
1992
2061
  {
1993
- name: 'animationEasing',
1994
- title: 'Animation Easing',
1995
- group: AXP_APPEARANCE_PROPERTY_GROUP,
1996
- schema: {
1997
- defaultValue: 'cubic-out',
1998
- dataType: 'string',
1999
- interface: {
2000
- name: 'animationEasing',
2001
- path: 'options.animationEasing',
2002
- type: AXPWidgetsCatalog.select,
2003
- options: {
2004
- dataSource: [
2005
- { value: 'linear', text: 'Linear' },
2006
- { value: 'ease', text: 'Ease' },
2007
- { value: 'ease-in', text: 'Ease In' },
2008
- { value: 'ease-out', text: 'Ease Out' },
2009
- { value: 'ease-in-out', text: 'Ease In Out' },
2010
- { value: 'cubic', text: 'Cubic' },
2011
- { value: 'cubic-in', text: 'Cubic In' },
2012
- { value: 'cubic-out', text: 'Cubic Out' },
2013
- { value: 'cubic-in-out', text: 'Cubic In Out' },
2014
- ],
2015
- textField: 'text',
2016
- valueField: 'value',
2017
- },
2018
- },
2062
+ name: 'animationEasing',
2063
+ title: '@dashboard:widgets.line-chart.animation-easing',
2064
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
2065
+ schema: {
2066
+ defaultValue: 'cubic-out',
2067
+ dataType: 'string',
2068
+ interface: {
2069
+ name: 'animationEasing',
2070
+ path: 'options.animationEasing',
2071
+ type: AXPWidgetsCatalog.select,
2072
+ options: {
2073
+ dataSource: [
2074
+ { value: 'linear', text: 'Linear' },
2075
+ { value: 'ease', text: 'Ease' },
2076
+ { value: 'ease-in', text: 'Ease In' },
2077
+ { value: 'ease-out', text: 'Ease Out' },
2078
+ { value: 'ease-in-out', text: 'Ease In Out' },
2079
+ { value: 'cubic', text: 'Cubic' },
2080
+ { value: 'cubic-in', text: 'Cubic In' },
2081
+ { value: 'cubic-out', text: 'Cubic Out' },
2082
+ { value: 'cubic-in-out', text: 'Cubic In Out' },
2083
+ ],
2084
+ textField: 'text',
2085
+ valueField: 'value',
2086
+ },
2019
2087
  },
2020
- visible: true,
2088
+ },
2089
+ visible: true,
2021
2090
  },
2022
2091
  {
2023
- name: 'animationDuration',
2024
- title: 'Animation Duration',
2025
- group: AXP_APPEARANCE_PROPERTY_GROUP,
2026
- schema: {
2027
- defaultValue: 800,
2028
- dataType: 'number',
2029
- interface: {
2030
- name: 'animationDuration',
2031
- path: 'options.animationDuration',
2032
- type: AXPWidgetsCatalog.number,
2033
- options: {
2034
- placeholder: '0-2000',
2035
- minValue: 0,
2036
- maxValue: 2000,
2037
- },
2038
- },
2092
+ name: 'animationDuration',
2093
+ title: '@dashboard:widgets.line-chart.animation-duration',
2094
+ group: AXP_APPEARANCE_PROPERTY_GROUP,
2095
+ schema: {
2096
+ defaultValue: 800,
2097
+ dataType: 'number',
2098
+ interface: {
2099
+ name: 'animationDuration',
2100
+ path: 'options.animationDuration',
2101
+ type: AXPWidgetsCatalog.number,
2102
+ options: {
2103
+ placeholder: '0-2000',
2104
+ minValue: 0,
2105
+ maxValue: 2000,
2106
+ },
2039
2107
  },
2040
- visible: true,
2108
+ },
2109
+ visible: true,
2041
2110
  },
2111
+ */
2042
2112
  ],
2043
2113
  components: {
2044
2114
  view: {
@@ -2047,12 +2117,12 @@ const AXPLineChartWidget = {
2047
2117
  },
2048
2118
  meta: {
2049
2119
  dimensions: {
2050
- width: 5,
2051
- height: 6,
2120
+ width: 3,
2121
+ height: 4,
2052
2122
  minWidth: 2,
2053
2123
  minHeight: 2,
2054
2124
  maxWidth: 6,
2055
- maxHeight: 7,
2125
+ maxHeight: 6,
2056
2126
  },
2057
2127
  },
2058
2128
  };
@@ -2150,7 +2220,17 @@ const AXPStickyNoteWidget = {
2150
2220
  groups: [AXPWidgetGroupEnum.DashboardWidget],
2151
2221
  type: 'dashboard',
2152
2222
  icon: 'fa-light fa-sticky-note',
2153
- properties: [AXP_DATA_PATH_PROPERTY, AXP_BG_COLOR_PROPERTY, plainTextDefaultProperty()],
2223
+ properties: [
2224
+ AXP_DATA_PATH_PROPERTY,
2225
+ {
2226
+ ...AXP_BG_COLOR_PROPERTY,
2227
+ title: '@dashboard:widgets.sticky-note.background-color',
2228
+ },
2229
+ {
2230
+ ...plainTextDefaultProperty(),
2231
+ title: '@dashboard:widgets.sticky-note.note-text',
2232
+ },
2233
+ ],
2154
2234
  components: {
2155
2235
  view: {
2156
2236
  component: () => Promise.resolve().then(function () { return stickyNoteWidget_component; }).then((c) => c.AXPStickyNoteWidgetViewComponent),
@@ -2263,7 +2343,7 @@ class AXPTaskListWidgetViewComponent extends AXPValueWidgetComponent {
2263
2343
  return 'Tomorrow';
2264
2344
  if (diffDays < 7)
2265
2345
  return this.datePipe.transform(dateObj, 'EEE') || '';
2266
- return this.datePipe.transform(dateObj, 'MM/dd/yyyy') || '';
2346
+ return this.datePipe.transform(dateObj, 'MM/DD/YYYY') || '';
2267
2347
  }
2268
2348
  getPriorityColor(priority) {
2269
2349
  if (!priority)
@@ -2291,7 +2371,7 @@ class AXPTaskListWidgetViewComponent extends AXPValueWidgetComponent {
2291
2371
  return Math.floor(diffMs / (1000 * 60 * 60 * 24));
2292
2372
  }
2293
2373
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPTaskListWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2294
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2374
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPTaskListWidgetViewComponent, isStandalone: true, selector: "ng-component", outputs: { taskClick: "taskClick", taskCompleted: "taskCompleted" }, providers: [DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3 ax-rounded-lg task-item\"\n [class.priority-high]=\"task.priority === 'high'\"\n [class.priority-medium]=\"task.priority === 'medium'\"\n [class.priority-low]=\"task.priority === 'low'\"\n [class.ax-bg-surface]=\"task.completed\"\n >\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0 ax-mt-1 task-checkbox\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6 class=\"ax-font-medium ax-truncate ax-pb-1\" [title]=\"task.title\" [class.task-completed]=\"task.completed\">\n {{ task.title }}\n </h6>\n @if (showPriority() && task.priority) {\n <ax-badge\n [color]=\"getPriorityColor(task.priority)\"\n [text]=\"task.priority\"\n size=\"sm\"\n class=\"ax-ml-1 ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-2 ax-text-xs ax-text-gray-500\">\n @if (showDate() && task.dueDate) {\n <span\n class=\"ax-flex ax-items-center ax-gap-1 due-date\"\n [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\"\n [class.overdue]=\"getDaysDifference(task.dueDate) < 0\"\n >\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n }\n @if (showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n @if (task.assignedTo.image) {\n <ax-icon class=\"ax-bg-primary-100 ax-text-primary-500 ax-rounded-full ax-p-1\">\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n } @else {\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n }\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-item{border-radius:8px;transition:all .2s ease-in-out;border-left:3px solid transparent}.task-item:hover{background-color:rgba(var(--ax-sys-color-on-surface),.1);transform:translateY(-2px);box-shadow:0 2px 8px rgba(0,0,0,.05)}.task-item.priority-high{border-left-color:rgb(var(--ax-sys-color-danger-500))}.task-item.priority-medium{border-left-color:rgb(var(--ax-sys-color-warning-500))}.task-item.priority-low{border-left-color:rgb(var(--ax-sys-color-success-500))}.task-item:active{transform:translateY(0);box-shadow:0 1px 3px rgba(0,0,0,.05)}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary);opacity:.7;transition:all .3s ease}.category-header{position:relative}.category-header:after{content:\"\";position:absolute;bottom:-8px;left:0;width:40px;height:3px;background-color:var(--ax-primary-500);border-radius:3px;transition:width .3s ease}.category-header:hover:after{width:60px}.empty-state{animation:fadeIn .5s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.task-checkbox ::ng-deep .ax-checkbox{transition:all .2s ease}.task-checkbox ::ng-deep .ax-checkbox:hover{transform:scale(1.1)}.due-date.overdue{animation:pulse 2s infinite}@keyframes pulse{0%{opacity:.7}50%{opacity:1}to{opacity:.7}}.ax-space-y-2>*{animation:slideInRight .3s ease forwards;opacity:0}.ax-space-y-2>*:nth-child(1){animation-delay:.05s}.ax-space-y-2>*:nth-child(2){animation-delay:.1s}.ax-space-y-2>*:nth-child(3){animation-delay:.15s}.ax-space-y-2>*:nth-child(4){animation-delay:.2s}.ax-space-y-2>*:nth-child(5){animation-delay:.25s}.ax-space-y-2>*:nth-child(6){animation-delay:.3s}.ax-space-y-2>*:nth-child(7){animation-delay:.35s}.ax-space-y-2>*:nth-child(8){animation-delay:.4s}.ax-space-y-2>*:nth-child(9){animation-delay:.45s}.ax-space-y-2>*:nth-child(10){animation-delay:.5s}@keyframes slideInRight{0%{opacity:0;transform:translate(10px)}to{opacity:1;transform:translate(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXAvatarModule }, { kind: "ngmodule", type: AXImageModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2295
2375
  }
2296
2376
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPTaskListWidgetViewComponent, decorators: [{
2297
2377
  type: Component,
@@ -2306,7 +2386,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
2306
2386
  AXCheckBoxModule,
2307
2387
  AXLabelModule,
2308
2388
  AXTranslationModule,
2309
- ], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-p-4\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3\">\n <h3 class=\"ax-text-lg ax-font-semibold\">{{ 'widget.tasklist.title' | translate | async }}</h3>\n <div class=\"ax-flex ax-gap-2\">\n @if(getPendingTaskCount() > 0){\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('widget.tasklist.pending' | translate | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n } @if(getCompletedTaskCount() > 0){\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('widget.tasklist.completed' | translate | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-2\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-3\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-2 ax-h-5\">\n <h4 class=\"ax-font-medium ax-text-gray-700\">{{ category }}</h4>\n @if(getCategoryTaskCount(category)){\n <ax-badge [text]=\"getCategoryTaskCount(category).toString()\" [color]=\"'primary'\" size=\"sm\"></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n } } @else {\n <!-- Uncategorized Tasks -->\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-12 ax-px-4 ax-text-gray-400\">\n <ax-icon class=\"ax-text-4xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center\">{{ 'widget.tasklist.noTasks' | translate | async }}</p>\n </div>\n } }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div class=\"ax-flex ax-gap-3 ax-items-center ax-py-2 ax-border-b ax-border-gray-100 last:ax-border-0\">\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6\n class=\"ax-font-semibold ax-truncate ax-pb-1\"\n [class.ax-line-through]=\"task.completed\"\n [class.ax-text-gray-400]=\"task.completed\"\n >\n {{ task.title }}\n </h6>\n @if(showPriority() && task.priority) {\n <ax-badge [color]=\"getPriorityColor(task.priority)\" [text]=\"task.priority\" size=\"sm\" class=\"ax-ml-1\"></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-1 ax-text-xs ax-text-gray-500\">\n @if(showDate() && task.dueDate) {\n <span class=\"ax-flex ax-items-center ax-gap-1\" [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\">\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n } @if(showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary)}\n"] }]
2389
+ ], providers: [DatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-size-full ax-p-4 ax-flex ax-flex-col\">\n <!-- Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <h3 class=\"ax-text-lg ax-font-semibold ax-flex ax-items-center ax-gap-2\">\n <ax-icon class=\"ax-text-primary-500\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n {{ 'tasklist.title' | translate: { scope: 'dashboard' } | async }}\n </h3>\n <div class=\"ax-flex ax-gap-2\">\n @if (getPendingTaskCount() > 0) {\n <ax-badge\n [text]=\"getPendingTaskCount() + ' ' + ('tasklist.pending' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'warning'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n @if (getCompletedTaskCount() > 0) {\n <ax-badge\n [text]=\"getCompletedTaskCount() + ' ' + ('tasklist.completed' | translate: { scope: 'dashboard' } | async)\"\n [color]=\"'success'\"\n size=\"sm\"\n class=\"ax-ml-1\"\n >\n </ax-badge>\n }\n </div>\n </div>\n\n <!-- Task List -->\n <div class=\"ax-space-y-4 ax-my-4 ax-px-1 ax-overflow-auto ax-grow\">\n @if (showCategories() && hasCategories()) {\n <!-- Categorized Tasks -->\n @for (category of getCategories(); track category) {\n <div class=\"ax-mb-5\">\n <!-- Category Header -->\n <div class=\"ax-flex ax-justify-between ax-items-center ax-mb-3 ax-h-5\">\n <h4 class=\"ax-font-medium category-header\">{{ category }}</h4>\n @if (getCategoryTaskCount(category)) {\n <ax-badge\n [text]=\"getCategoryTaskCount(category).toString()\"\n [color]=\"'primary'\"\n size=\"sm\"\n class=\"ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n <!-- Tasks in Category -->\n <div class=\"ax-space-y-2\">\n @for (task of getTasksByCategory(category); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n }\n </div>\n </div>\n }\n } @else {\n <!-- Uncategorized Tasks -->\n <div class=\"ax-space-y-2\">\n @for (task of taskItems(); track task.id) {\n <ng-container\n [ngTemplateOutlet]=\"taskItemTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: task }\"\n ></ng-container>\n } @empty {\n <!-- Empty State -->\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-py-14 ax-px-4 ax-text-gray-400 empty-state\"\n >\n <ax-icon class=\"ax-text-5xl ax-mb-3 ax-text-gray-300\">\n <i class=\"fa-light fa-clipboard-list-check\"></i>\n </ax-icon>\n <p class=\"ax-text-center ax-font-medium\">\n {{ 'tasklist.noTasks' | translate: { scope: 'dashboard' } | async }}\n </p>\n <p class=\"ax-text-center ax-text-sm ax-mt-2\">\n {{ 'tasklist.addTask' | translate: { scope: 'dashboard' } | async }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Task Item Template -->\n<ng-template #taskItemTemplateRef let-task>\n <div\n class=\"ax-flex ax-gap-3 ax-items-start ax-p-3 ax-rounded-lg task-item\"\n [class.priority-high]=\"task.priority === 'high'\"\n [class.priority-medium]=\"task.priority === 'medium'\"\n [class.priority-low]=\"task.priority === 'low'\"\n [class.ax-bg-surface]=\"task.completed\"\n >\n <!-- Checkbox -->\n <ax-check-box\n class=\"ax-flex-shrink-0 ax-mt-1 task-checkbox\"\n [value]=\"task.completed\"\n [disabled]=\"!allowMarkComplete()\"\n (valueChange)=\"onTaskCompletionChange(task, $event)\"\n >\n </ax-check-box>\n\n <!-- Task Details -->\n <div class=\"ax-overflow-hidden ax-grow ax-text-start\" (click)=\"onTaskClick(task)\">\n <!-- Title and Priority -->\n <div class=\"ax-flex ax-items-center ax-gap-2\">\n <h6 class=\"ax-font-medium ax-truncate ax-pb-1\" [title]=\"task.title\" [class.task-completed]=\"task.completed\">\n {{ task.title }}\n </h6>\n @if (showPriority() && task.priority) {\n <ax-badge\n [color]=\"getPriorityColor(task.priority)\"\n [text]=\"task.priority\"\n size=\"sm\"\n class=\"ax-ml-1 ax-rounded-full\"\n ></ax-badge>\n }\n </div>\n\n <!-- Metadata -->\n <div class=\"ax-flex ax-flex-wrap ax-gap-x-3 ax-gap-y-1 ax-mt-2 ax-text-xs ax-text-gray-500\">\n @if (showDate() && task.dueDate) {\n <span\n class=\"ax-flex ax-items-center ax-gap-1 due-date\"\n [class.ax-text-danger-500]=\"getDaysDifference(task.dueDate) < 0\"\n [class.overdue]=\"getDaysDifference(task.dueDate) < 0\"\n >\n <ax-icon><i class=\"fa-light fa-calendar\"></i></ax-icon>\n {{ formatDueDate(task.dueDate) }}\n </span>\n }\n @if (showAssignee() && task.assignedTo) {\n <span class=\"ax-flex ax-items-center ax-gap-1\">\n @if (task.assignedTo.image) {\n <ax-icon class=\"ax-bg-primary-100 ax-text-primary-500 ax-rounded-full ax-p-1\">\n <i class=\"fa-light fa-user\"></i>\n </ax-icon>\n } @else {\n <ax-icon><i class=\"fa-light fa-user\"></i></ax-icon>\n }\n {{ task.assignedTo.name }}\n </span>\n }\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:block;height:100%;width:100%}.task-item{border-radius:8px;transition:all .2s ease-in-out;border-left:3px solid transparent}.task-item:hover{background-color:rgba(var(--ax-sys-color-on-surface),.1);transform:translateY(-2px);box-shadow:0 2px 8px rgba(0,0,0,.05)}.task-item.priority-high{border-left-color:rgb(var(--ax-sys-color-danger-500))}.task-item.priority-medium{border-left-color:rgb(var(--ax-sys-color-warning-500))}.task-item.priority-low{border-left-color:rgb(var(--ax-sys-color-success-500))}.task-item:active{transform:translateY(0);box-shadow:0 1px 3px rgba(0,0,0,.05)}.task-completed{text-decoration:line-through;color:var(--ax-text-secondary);opacity:.7;transition:all .3s ease}.category-header{position:relative}.category-header:after{content:\"\";position:absolute;bottom:-8px;left:0;width:40px;height:3px;background-color:var(--ax-primary-500);border-radius:3px;transition:width .3s ease}.category-header:hover:after{width:60px}.empty-state{animation:fadeIn .5s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.task-checkbox ::ng-deep .ax-checkbox{transition:all .2s ease}.task-checkbox ::ng-deep .ax-checkbox:hover{transform:scale(1.1)}.due-date.overdue{animation:pulse 2s infinite}@keyframes pulse{0%{opacity:.7}50%{opacity:1}to{opacity:.7}}.ax-space-y-2>*{animation:slideInRight .3s ease forwards;opacity:0}.ax-space-y-2>*:nth-child(1){animation-delay:.05s}.ax-space-y-2>*:nth-child(2){animation-delay:.1s}.ax-space-y-2>*:nth-child(3){animation-delay:.15s}.ax-space-y-2>*:nth-child(4){animation-delay:.2s}.ax-space-y-2>*:nth-child(5){animation-delay:.25s}.ax-space-y-2>*:nth-child(6){animation-delay:.3s}.ax-space-y-2>*:nth-child(7){animation-delay:.35s}.ax-space-y-2>*:nth-child(8){animation-delay:.4s}.ax-space-y-2>*:nth-child(9){animation-delay:.45s}.ax-space-y-2>*:nth-child(10){animation-delay:.5s}@keyframes slideInRight{0%{opacity:0;transform:translate(10px)}to{opacity:1;transform:translate(0)}}\n"] }]
2310
2390
  }] });
2311
2391
 
2312
2392
  var tasklistWidget_component = /*#__PURE__*/Object.freeze({
@@ -2326,7 +2406,7 @@ const AXPTaskListWidget = {
2326
2406
  // ====== Title ======
2327
2407
  {
2328
2408
  name: 'title',
2329
- title: 'Chart Title',
2409
+ title: '@dashboard:widgets.task-list.chart-title',
2330
2410
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2331
2411
  schema: {
2332
2412
  defaultValue: '',
@@ -2345,7 +2425,7 @@ const AXPTaskListWidget = {
2345
2425
  // Display options
2346
2426
  {
2347
2427
  name: 'maxItems',
2348
- title: 'Max Items',
2428
+ title: '@dashboard:widgets.task-list.max-items',
2349
2429
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2350
2430
  schema: {
2351
2431
  defaultValue: 10,
@@ -2364,7 +2444,7 @@ const AXPTaskListWidget = {
2364
2444
  },
2365
2445
  {
2366
2446
  name: 'showDate',
2367
- title: 'Show Date',
2447
+ title: '@dashboard:widgets.task-list.show-date',
2368
2448
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2369
2449
  schema: {
2370
2450
  defaultValue: true,
@@ -2379,7 +2459,7 @@ const AXPTaskListWidget = {
2379
2459
  },
2380
2460
  {
2381
2461
  name: 'showAssignee',
2382
- title: 'Show Assignee',
2462
+ title: '@dashboard:widgets.task-list.show-assignee',
2383
2463
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2384
2464
  schema: {
2385
2465
  defaultValue: true,
@@ -2394,7 +2474,7 @@ const AXPTaskListWidget = {
2394
2474
  },
2395
2475
  {
2396
2476
  name: 'groupByCategory',
2397
- title: 'Group by Category',
2477
+ title: '@dashboard:widgets.task-list.group-by-category',
2398
2478
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2399
2479
  schema: {
2400
2480
  defaultValue: true,
@@ -2409,7 +2489,7 @@ const AXPTaskListWidget = {
2409
2489
  },
2410
2490
  {
2411
2491
  name: 'showPriority',
2412
- title: 'Show Priority',
2492
+ title: '@dashboard:widgets.task-list.show-priority',
2413
2493
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2414
2494
  schema: {
2415
2495
  defaultValue: true,
@@ -2424,7 +2504,7 @@ const AXPTaskListWidget = {
2424
2504
  },
2425
2505
  {
2426
2506
  name: 'allowMarkComplete',
2427
- title: 'Allow Complete',
2507
+ title: '@dashboard:widgets.task-list.allow-complete',
2428
2508
  group: AXP_APPEARANCE_PROPERTY_GROUP,
2429
2509
  schema: {
2430
2510
  defaultValue: true,
@@ -2445,7 +2525,7 @@ const AXPTaskListWidget = {
2445
2525
  },
2446
2526
  meta: {
2447
2527
  dimensions: {
2448
- width: 5,
2528
+ width: 3,
2449
2529
  height: 7,
2450
2530
  minWidth: 3,
2451
2531
  minHeight: 4,
@@ -3080,8 +3160,7 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
3080
3160
  setTimeout(() => this.cdr.detectChanges());
3081
3161
  },
3082
3162
  error: (error) => {
3083
- this.hasError.set(true);
3084
- this.errorMessage.set(error.message || 'Failed to load weather data. Please try again.');
3163
+ this.handleError(error);
3085
3164
  this.isLoading.set(false);
3086
3165
  this.isForecastLoading.set(false);
3087
3166
  this.cdr.detectChanges();
@@ -3102,8 +3181,7 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
3102
3181
  setTimeout(() => this.cdr.detectChanges());
3103
3182
  },
3104
3183
  error: (error) => {
3105
- this.hasError.set(true);
3106
- this.errorMessage.set(error.message || 'Failed to load weather data. Please try again.');
3184
+ this.handleError(error);
3107
3185
  this.isLoading.set(false);
3108
3186
  this.cdr.detectChanges();
3109
3187
  },
@@ -3208,7 +3286,11 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
3208
3286
  */
3209
3287
  getConditionName(conditionId) {
3210
3288
  const condition = this.weatherService.getCondition(conditionId);
3211
- return condition?.name || 'Unknown';
3289
+ if (!condition?.name)
3290
+ return 'weather.conditions.sunny';
3291
+ // Convert condition name to lowercase and replace spaces with hyphens
3292
+ const formattedName = condition.name.toLowerCase().replace(/\s+/g, '-');
3293
+ return `weather.conditions.${formattedName}`;
3212
3294
  }
3213
3295
  /**
3214
3296
  * Gets the color for a weather condition
@@ -3226,22 +3308,60 @@ class AXPWeatherWidgetViewComponent extends AXPValueWidgetComponent {
3226
3308
  cleanupChart() {
3227
3309
  this.clearRefreshTimer();
3228
3310
  }
3311
+ handleError(error) {
3312
+ console.error('Weather widget error:', error);
3313
+ this.hasError.set(true);
3314
+ // Check if it's a network error
3315
+ if (error.status === 0) {
3316
+ this.errorMessage.set('weather.error.network');
3317
+ return;
3318
+ }
3319
+ // Check if it's an API error
3320
+ if (error.status >= 400 && error.status < 500) {
3321
+ this.errorMessage.set('weather.error.api');
3322
+ return;
3323
+ }
3324
+ // Default error message
3325
+ this.errorMessage.set('weather.error.general');
3326
+ }
3327
+ getTemperatureUnit() {
3328
+ return this.temperatureUnit() === '°C' ? 'weather.units.celsius' : 'weather.units.fahrenheit';
3329
+ }
3330
+ getWindSpeedUnit() {
3331
+ return this.windSpeedUnit() === 'km/h' ? 'weather.units.kmh' : 'weather.units.mph';
3332
+ }
3333
+ getDayName(date) {
3334
+ const today = new Date();
3335
+ const tomorrow = new Date(today);
3336
+ tomorrow.setDate(tomorrow.getDate() + 1);
3337
+ if (date.toDateString() === today.toDateString()) {
3338
+ return 'weather.days.today';
3339
+ }
3340
+ if (date.toDateString() === tomorrow.toDateString()) {
3341
+ return 'weather.days.tomorrow';
3342
+ }
3343
+ const days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
3344
+ return `weather.days.${days[date.getDay()]}`;
3345
+ }
3346
+ parseDate(dateStr) {
3347
+ return new Date(dateStr);
3348
+ }
3229
3349
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPWeatherWidgetViewComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3230
3350
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPWeatherWidgetViewComponent, isStandalone: true, selector: "ng-component", providers: [
3231
3351
  {
3232
3352
  provide: AXPWeatherApiAbstract,
3233
3353
  useClass: AXPWeatherApiService,
3234
3354
  },
3235
- ], viewQueries: [{ propertyName: "containerEl", first: true, predicate: ["containerElement"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading weather data...</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Retry</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">{{ getCurrentCondition() }}</div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{ temperatureUnit() }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Humidity</div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Wind</div>\n <div class=\"axp-weather-detail-value\">{{ getWindSpeed() }} {{ windSpeedUnit() }}</div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span>Forecast</span>\n </h3>\n <!-- <div class=\"axp-weather-scroll-indicator\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div> -->\n </div>\n <!-- Loading indicator for forecast -->\n @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading forecast...</span>\n </div>\n }\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">{{ day.day }}</div>\n <div class=\"axp-weather-forecast-icon\" title=\"{{ getConditionName(day.condition) }}\">\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF }}\u00B0\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF }}\u00B0\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>Last updated: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'Refresh weather data'\"\n title=\"Refresh weather data\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Refresh</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>No weather data available</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Load Data</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;border-radius:8px;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1.5rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-top:auto;margin-bottom:1rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:80px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.875rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: HttpClientModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3355
+ ], viewQueries: [{ propertyName: "containerEl", first: true, predicate: ["containerElement"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-bottom:.5rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: HttpClientModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3236
3356
  }
3237
3357
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPWeatherWidgetViewComponent, decorators: [{
3238
3358
  type: Component,
3239
- args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, HttpClientModule], providers: [
3359
+ args: [{ standalone: true, imports: [CommonModule, AXDateTimeModule, AXFormatModule, HttpClientModule, AXTranslationModule], providers: [
3240
3360
  {
3241
3361
  provide: AXPWeatherApiAbstract,
3242
3362
  useClass: AXPWeatherApiService,
3243
3363
  },
3244
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading weather data...</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Retry</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">{{ getCurrentCondition() }}</div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{ temperatureUnit() }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Humidity</div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">Wind</div>\n <div class=\"axp-weather-detail-value\">{{ getWindSpeed() }} {{ windSpeedUnit() }}</div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span>Forecast</span>\n </h3>\n <!-- <div class=\"axp-weather-scroll-indicator\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div> -->\n </div>\n <!-- Loading indicator for forecast -->\n @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading forecast...</span>\n </div>\n }\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">{{ day.day }}</div>\n <div class=\"axp-weather-forecast-icon\" title=\"{{ getConditionName(day.condition) }}\">\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF }}\u00B0\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF }}\u00B0\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>Last updated: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'Refresh weather data'\"\n title=\"Refresh weather data\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Refresh</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>No weather data available</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>Load Data</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;border-radius:8px;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1.5rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-top:auto;margin-bottom:1rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:80px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.875rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"] }]
3364
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Weather Widget Component Template -->\n<div class=\"axp-weather-container\" #containerElement>\n <!-- Loading indicator -->\n @if (isLoading()) {\n <div class=\"axp-weather-loading-overlay\">\n <div class=\"axp-weather-loading-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n </div>\n }\n\n <!-- Error message -->\n @if (hasError()) {\n <div class=\"axp-weather-error-overlay\">\n <div class=\"axp-weather-error-message\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage() | translate: { scope: 'dashboard' } | async }}</span>\n <button class=\"axp-weather-retry-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.retry' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Weather content - only show when we have data -->\n @if (weatherData()) {\n <!-- Background decorations based on weather condition -->\n <div class=\"axp-weather-background-decorations\">\n <div class=\"axp-weather-decoration\" [ngClass]=\"weatherData()?.current?.condition?.toLowerCase()\"></div>\n <div class=\"axp-weather-gradient-overlay\"></div>\n </div>\n\n <div class=\"axp-weather-inner\">\n <!-- Location information section -->\n <div class=\"axp-weather-location-info\">\n <div class=\"axp-weather-location-icon\">\n <i class=\"fa-solid fa-location-dot\"></i>\n </div>\n <div class=\"axp-weather-location-text\">\n <h2 class=\"axp-weather-location-name\">{{ city() }}</h2>\n </div>\n </div>\n\n <!-- Current weather conditions section -->\n <div class=\"axp-weather-current-weather\">\n <!-- Weather icon and condition name -->\n @if (showCurrentCondition()) {\n <div class=\"axp-weather-condition\">\n <div class=\"axp-weather-icon-wrapper\">\n <div class=\"axp-weather-icon\">\n <i\n [class]=\"getConditionIcon(weatherData()?.current?.condition || '')\"\n [style.color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></i>\n </div>\n <div\n class=\"axp-weather-icon-glow\"\n [style.background-color]=\"getConditionColor(weatherData()?.current?.condition || '')\"\n ></div>\n </div>\n <div class=\"axp-weather-condition-name\">\n {{ getCurrentCondition() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n }\n\n <!-- Temperature display -->\n @if (showTemperature()) {\n <div class=\"axp-weather-temperature\">\n <span class=\"axp-weather-temperature-value\">{{ getCurrentTemperature() }}</span>\n <span class=\"axp-weather-temperature-unit\">{{\n getTemperatureUnit() | translate: { scope: 'dashboard' } | async\n }}</span>\n </div>\n }\n </div>\n\n <!-- Weather details section (humidity and wind) -->\n @if (showHumidity() || showWind()) {\n <div class=\"axp-weather-details\">\n <!-- Humidity information -->\n @if (showHumidity()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-droplet\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.humidity' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">{{ getHumidity() }}%</div>\n </div>\n </div>\n }\n\n <!-- Wind speed information -->\n @if (showWind()) {\n <div class=\"axp-weather-detail-item\">\n <div class=\"axp-weather-detail-icon\">\n <i class=\"fa-solid fa-wind\"></i>\n </div>\n <div class=\"axp-weather-detail-info\">\n <div class=\"axp-weather-detail-label\">\n {{ 'weather.wind' | translate: { scope: 'dashboard' } | async }}\n </div>\n <div class=\"axp-weather-detail-value\">\n {{ getWindSpeed() }} {{ getWindSpeedUnit() | translate: { scope: 'dashboard' } | async }}\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Weather forecast section -->\n @if (showForecast() && weatherData()?.forecast) {\n <div class=\"axp-weather-forecast\">\n <div class=\"axp-weather-forecast-header\">\n <h3 class=\"axp-weather-forecast-title\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n <span class=\"ax-px-1\">{{ 'weather.forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </h3>\n </div>\n <!-- Loading indicator for forecast -->\n <!-- @if (isForecastLoading()) {\n <div class=\"axp-weather-forecast-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>{{ 'weather.loading-forecast' | translate: { scope: 'dashboard' } | async }}</span>\n </div>\n } -->\n <!-- Scrollable forecast days display -->\n <div class=\"axp-weather-forecast-items\">\n @for (day of displayedForecast(); track day.day) {\n <div class=\"axp-weather-forecast-day\">\n <div class=\"axp-weather-forecast-day-name\">\n {{ getDayName(parseDate(day.date)) | translate: { scope: 'dashboard' } | async }}\n </div>\n <div\n class=\"axp-weather-forecast-icon\"\n [title]=\"getConditionName(day.condition) | translate: { scope: 'dashboard' } | async\"\n >\n <i [class]=\"getConditionIcon(day.condition)\" [style.color]=\"getConditionColor(day.condition)\"></i>\n </div>\n <div class=\"axp-weather-forecast-temps\">\n <span class=\"axp-weather-forecast-low\">\n {{ temperatureUnit() === '\u00B0C' ? day.minTempC : day.minTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n <span class=\"axp-weather-forecast-high\">\n {{ temperatureUnit() === '\u00B0C' ? day.maxTempC : day.maxTempF\n }}{{ getTemperatureUnit() | translate: { scope: 'dashboard' } | async }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Last updated timestamp -->\n <div class=\"axp-weather-last-updated\">\n <span>{{ 'weather.last-updated' | translate: { scope: 'dashboard' } | async }}: {{ getLastUpdated() }}</span>\n </div>\n\n <!-- Manual refresh button -->\n <div class=\"axp-weather-refresh-action\">\n <button\n class=\"axp-weather-refresh-button\"\n (click)=\"refreshWeather()\"\n [attr.aria-label]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n [title]=\"'weather.refresh' | translate: { scope: 'dashboard' } | async\"\n >\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.refresh' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n </div>\n } @else if (!isLoading() && !hasError()) {\n <!-- No data state (not loading, no error) -->\n <div class=\"axp-weather-no-data-state\">\n <i class=\"fa-solid fa-cloud-sun\"></i>\n <p>{{ 'weather.no-data' | translate: { scope: 'dashboard' } | async }}</p>\n <button class=\"axp-weather-refresh-button\" (click)=\"refreshWeather()\">\n <i class=\"fa-solid fa-sync-alt\"></i>\n <span>{{ 'weather.load-data' | translate: { scope: 'dashboard' } | async }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%;--primary-gradient-start: #2196f3;--primary-gradient-end: #1976d2;--shadow-color: rgba(0, 0, 0, .2);--glass-bg: rgba(255, 255, 255, .15);--glass-border: rgba(255, 255, 255, .2);--text-primary: rgba(255, 255, 255, .95);--text-secondary: rgba(255, 255, 255, .75);--transition-speed: .3s}.axp-weather-container{width:100%;height:100%;overflow:hidden;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.1);color:#fff;min-height:300px;background-color:#2c3e50}.axp-weather-loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(44,62,80,.85);display:flex;justify-content:center;align-items:center;z-index:100}.axp-weather-loading-spinner{text-align:center}.axp-weather-loading-spinner i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-loading-spinner span{display:block;color:#fff;font-size:1rem}.axp-weather-error-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(189,54,47,.85);display:flex;justify-content:center;align-items:center}.axp-weather-error-message{text-align:center;padding:1rem}.axp-weather-error-message i{font-size:2.5rem;color:#fff;margin-bottom:.5rem}.axp-weather-error-message span{display:block;color:#fff;font-size:1.1rem;margin-bottom:1rem}.axp-weather-error-message .axp-weather-retry-button{color:#bd362f;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-error-message .axp-weather-retry-button:hover{transform:translateY(-1px)}.axp-weather-no-data-state{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:2rem;text-align:center}.axp-weather-no-data-state i{font-size:3rem;margin-bottom:1rem;color:rgba(255,255,255,.8)}.axp-weather-no-data-state p{margin-bottom:1.5rem;font-size:1.1rem}.axp-weather-no-data-state .axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:1rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-no-data-state .axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-background-decorations{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.axp-weather-decoration{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center}.axp-weather-decoration.sunny{background:linear-gradient(135deg,#ff7e00,#f7d358)}.axp-weather-decoration.partlyCloudy{background:linear-gradient(135deg,#7ba2e7,#b4d2f7)}.axp-weather-decoration.cloudy{background:linear-gradient(135deg,#717e8c,#919eab)}.axp-weather-decoration.rain{background:linear-gradient(135deg,#6a8caf,#567a9e)}.axp-weather-decoration.snow{background:linear-gradient(135deg,#99b3cc,#c6d4e1)}.axp-weather-decoration.thunder{background:linear-gradient(135deg,#425777,#2c3e50)}.axp-weather-decoration.mist{background:linear-gradient(135deg,#94a3b8,#cbd5e1)}.axp-weather-gradient-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.5))}.axp-weather-inner{position:relative;z-index:2;height:100%;padding:1.5rem;display:flex;flex-direction:column;justify-content:space-between}.axp-weather-location-info{display:flex;align-items:center;margin-bottom:1.5rem}.axp-weather-location-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,.2);border-radius:50%;margin-right:.75rem}.axp-weather-location-icon i{color:#fff}.axp-weather-location-name{margin:0;font-size:1.5rem;font-weight:500;text-shadow:1px 1px 3px rgba(0,0,0,.2);text-transform:capitalize}.axp-weather-current-weather{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap}.axp-weather-condition{display:flex;flex-direction:column;align-items:center}.axp-weather-icon-wrapper{position:relative;margin-bottom:.5rem}.axp-weather-icon{position:relative;z-index:2}.axp-weather-icon i{font-size:2.75rem;filter:drop-shadow(0 0 8px rgba(0,0,0,.3))}.axp-weather-icon-glow{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:45px;height:45px;border-radius:50%;filter:blur(15px);opacity:.75}.axp-weather-condition-name{font-size:1.1rem;text-align:center;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.axp-weather-temperature{display:flex;align-items:flex-start;text-shadow:1px 1px 3px rgba(0,0,0,.3)}.axp-weather-temperature-value{font-size:3.5rem;font-weight:500;line-height:1}.axp-weather-temperature-unit{font-size:1.5rem;margin-top:.25rem}.axp-weather-details{display:flex;flex-wrap:wrap;gap:1.5rem;margin-bottom:1rem;padding:1rem;background-color:rgba(0,0,0,.15);border-radius:8px}.axp-weather-detail-item{display:flex;align-items:center;flex:1;min-width:120px}.axp-weather-detail-icon{width:40px;height:40px;border-radius:50%;background-color:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:.75rem}.axp-weather-detail-icon i{font-size:1.25rem}.axp-weather-detail-info{display:flex;padding-inline:.25rem;flex-direction:column}.axp-weather-detail-label{font-size:.875rem;color:rgba(255,255,255,.8);margin-bottom:.25rem}.axp-weather-detail-value{font-size:1.125rem;font-weight:500}.axp-weather-forecast{margin-bottom:.5rem;background-color:rgba(0,0,0,.15);border-radius:8px;padding:1rem}.axp-weather-forecast-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.axp-weather-forecast-title{margin:0;font-size:1.125rem;font-weight:500;display:flex;align-items:center}.axp-weather-forecast-title i{margin-right:.5rem;opacity:.8}.axp-weather-scroll-indicator{color:rgba(255,255,255,.6)}.axp-weather-forecast-items{display:flex;overflow-x:auto;gap:.75rem;padding-bottom:.5rem}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.3);border-radius:4px}.axp-weather-forecast-items::-webkit-scrollbar-track{background-color:rgba(0,0,0,.1);border-radius:4px}.axp-weather-forecast-day{min-width:90px;display:flex;flex-direction:column;align-items:center;padding:.75rem .5rem;background-color:rgba(255,255,255,.1);border-radius:6px;transition:all .3s ease}.axp-weather-forecast-day:hover{background-color:rgba(255,255,255,.15);transform:translateY(-2px)}.axp-weather-forecast-day-name{font-size:.875rem;margin-bottom:.5rem;font-weight:500}.axp-weather-forecast-icon{font-size:1.5rem;margin-bottom:.5rem}.axp-weather-forecast-icon i{filter:drop-shadow(0 0 5px rgba(0,0,0,.2))}.axp-weather-forecast-temps{display:flex;flex-direction:row;gap:.75rem;align-items:center;font-size:.775rem}.axp-weather-last-updated{text-align:center;font-size:.75rem;opacity:.7;margin-bottom:.5rem}.axp-weather-refresh-action{text-align:center}.axp-weather-refresh-button{background-color:rgba(255,255,255,.2);color:#fff;border:none;border-radius:4px;padding:.5rem 1rem;font-size:.875rem;cursor:pointer;transition:all .3s ease;display:inline-flex;align-items:center;gap:.5rem}.axp-weather-refresh-button:hover{background-color:rgba(255,255,255,.3);transform:translateY(-1px)}.axp-weather-refresh-button i{font-size:.875rem}@media (max-width: 576px){.axp-weather-inner{padding:.8rem;gap:.4rem}.axp-weather-location-name{font-size:1.1rem;padding-inline:.25rem}.axp-weather-temperature{font-size:2.5rem}.axp-weather-temperature-unit{font-size:1.1rem}.axp-weather-weather-details{flex-direction:column;gap:.5rem}.axp-weather-forecast-items{flex-wrap:nowrap;overflow-x:auto;padding-bottom:.5rem;margin:0 -.4rem;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scrollbar-width:thin;mask-image:linear-gradient(to right,#000 95%,rgba(0,0,0,0));-webkit-mask-image:linear-gradient(to right,rgb(0,0,0) 95%,rgba(0,0,0,0))}.axp-weather-forecast-items::-webkit-scrollbar{height:4px}.axp-weather-forecast-items::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,.2);border-radius:4px}.axp-weather-forecast-day{min-width:60px;flex:0 0 auto;padding:.4rem .6rem}.axp-weather-forecast-day-name{font-size:.7rem}.axp-weather-forecast-icon{padding:.3rem;height:1.6rem}.axp-weather-forecast-temps{font-size:.7rem}.axp-weather-scroll-indicator{display:block}}:host-context(.theme-dark){--glass-bg: rgba(0, 0, 0, .3);--glass-border: rgba(255, 255, 255, .1)}\n"] }]
3245
3365
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
3246
3366
 
3247
3367
  var weatherWidget_component = /*#__PURE__*/Object.freeze({
@@ -3264,7 +3384,7 @@ const AXPWeatherWidget = {
3264
3384
  /* Location Settings */
3265
3385
  {
3266
3386
  name: 'city',
3267
- title: 'City',
3387
+ title: '@dashboard:widgets.weather.city',
3268
3388
  group: AXP_DATA_PROPERTY_GROUP,
3269
3389
  schema: {
3270
3390
  defaultValue: 'New York',
@@ -3340,7 +3460,7 @@ const AXPWeatherWidget = {
3340
3460
  // },
3341
3461
  {
3342
3462
  name: 'showHumidity',
3343
- title: 'Show Humidity',
3463
+ title: '@dashboard:widgets.weather.show-humidity',
3344
3464
  group: AXP_APPEARANCE_PROPERTY_GROUP,
3345
3465
  schema: {
3346
3466
  defaultValue: true,
@@ -3355,7 +3475,7 @@ const AXPWeatherWidget = {
3355
3475
  },
3356
3476
  {
3357
3477
  name: 'showWind',
3358
- title: 'Show Wind Speed',
3478
+ title: '@dashboard:widgets.weather.show-wind',
3359
3479
  group: AXP_APPEARANCE_PROPERTY_GROUP,
3360
3480
  schema: {
3361
3481
  defaultValue: true,
@@ -3370,7 +3490,7 @@ const AXPWeatherWidget = {
3370
3490
  },
3371
3491
  {
3372
3492
  name: 'showForecast',
3373
- title: 'Show Forecast',
3493
+ title: '@dashboard:widgets.weather.show-forecast',
3374
3494
  group: AXP_APPEARANCE_PROPERTY_GROUP,
3375
3495
  schema: {
3376
3496
  defaultValue: true,
@@ -3385,7 +3505,7 @@ const AXPWeatherWidget = {
3385
3505
  },
3386
3506
  {
3387
3507
  name: 'forecastDays',
3388
- title: 'Forecast Days',
3508
+ title: '@dashboard:widgets.weather.forecast-days',
3389
3509
  group: AXP_APPEARANCE_PROPERTY_GROUP,
3390
3510
  schema: {
3391
3511
  defaultValue: 5,
@@ -3406,7 +3526,7 @@ const AXPWeatherWidget = {
3406
3526
  /* Units Settings */
3407
3527
  {
3408
3528
  name: 'temperatureUnit',
3409
- title: 'Temperature Unit',
3529
+ title: '@dashboard:widgets.weather.temperature-unit',
3410
3530
  group: AXP_DATA_PROPERTY_GROUP,
3411
3531
  schema: {
3412
3532
  defaultValue: '°C',
@@ -3424,7 +3544,7 @@ const AXPWeatherWidget = {
3424
3544
  },
3425
3545
  {
3426
3546
  name: 'windSpeedUnit',
3427
- title: 'Wind Speed Unit',
3547
+ title: '@dashboard:widgets.weather.wind-speed-unit',
3428
3548
  group: AXP_DATA_PROPERTY_GROUP,
3429
3549
  schema: {
3430
3550
  defaultValue: 'km/h',
@@ -3443,7 +3563,7 @@ const AXPWeatherWidget = {
3443
3563
  /* Refresh Settings */
3444
3564
  {
3445
3565
  name: 'autoRefresh',
3446
- title: 'Auto Refresh',
3566
+ title: '@dashboard:widgets.weather.auto-refresh',
3447
3567
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
3448
3568
  schema: {
3449
3569
  defaultValue: true,
@@ -3458,7 +3578,7 @@ const AXPWeatherWidget = {
3458
3578
  },
3459
3579
  {
3460
3580
  name: 'refreshInterval',
3461
- title: 'Refresh Interval (minutes)',
3581
+ title: '@dashboard:widgets.weather.refresh-interval',
3462
3582
  group: AXP_BEHAVIOR_PROPERTY_GROUP,
3463
3583
  schema: {
3464
3584
  defaultValue: 15,
@@ -3505,7 +3625,7 @@ class AXPDashboardShortcutWidgetViewComponent extends AXPLayoutWidgetComponent {
3505
3625
  super.ngOnInit();
3506
3626
  if (!this.color()) {
3507
3627
  this.setOptions({
3508
- color: AXPDataGenerator.color()
3628
+ color: AXPDataGenerator.color(),
3509
3629
  });
3510
3630
  }
3511
3631
  }
@@ -3531,8 +3651,8 @@ class AXPDashboardShortcutWidgetViewComponent extends AXPLayoutWidgetComponent {
3531
3651
  title: result.title,
3532
3652
  description: result.description,
3533
3653
  icon: result.icon,
3534
- command: result.command
3535
- }
3654
+ command: result.command,
3655
+ },
3536
3656
  });
3537
3657
  }
3538
3658
  }
@@ -3558,56 +3678,68 @@ class AXPDashboardShortcutWidgetViewComponent extends AXPLayoutWidgetComponent {
3558
3678
  }
3559
3679
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPDashboardShortcutWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3560
3680
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXPDashboardShortcutWidgetViewComponent, isStandalone: true, selector: "ng-component", host: { properties: { "style": "this.__style", "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
3561
- @if(item()) {
3562
- <div
3681
+ @if (item()) {
3682
+ <div
3563
3683
  class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
3564
- (click)="executeCommand()">
3684
+ (click)="executeCommand()"
3685
+ >
3565
3686
  <div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
3566
3687
  <i [class]="item().icon + ' ax-text-3xl'"></i>
3567
3688
  <span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
3568
- @if(item().description) {
3569
- <span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
3689
+ @if (item().description) {
3690
+ <span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{
3691
+ item().description! | translate | async
3692
+ }}</span>
3570
3693
  }
3571
3694
  </div>
3572
3695
  } @else {
3573
- <div
3574
- (click)="setCommand()"
3575
- class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
3696
+ <div
3697
+ (click)="setCommand()"
3698
+ class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden"
3699
+ >
3576
3700
  <div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
3577
3701
  <i class="fa-light fa-plus ax-text-3xl"></i>
3578
- <span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
3702
+ <span class="ax-text-xl ax-font-semibold">{{
3703
+ '@dashboard:widgets.dashboard-shortcut.add-shortcut' | translate | async
3704
+ }}</span>
3579
3705
  </div>
3580
3706
  }
3581
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3707
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3582
3708
  }
3583
3709
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXPDashboardShortcutWidgetViewComponent, decorators: [{
3584
3710
  type: Component,
3585
3711
  args: [{
3586
3712
  template: `
3587
- @if(item()) {
3588
- <div
3713
+ @if (item()) {
3714
+ <div
3589
3715
  class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden "
3590
- (click)="executeCommand()">
3716
+ (click)="executeCommand()"
3717
+ >
3591
3718
  <div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/10 ax-transition-opacity"></div>
3592
3719
  <i [class]="item().icon + ' ax-text-3xl'"></i>
3593
3720
  <span class="ax-text-xl ax-font-semibold">{{ item().title | translate | async }}</span>
3594
- @if(item().description) {
3595
- <span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{ item().description! | translate | async }}</span>
3721
+ @if (item().description) {
3722
+ <span class="ax-text-sm ax-opacity-90 ax-text-center ax-px-2">{{
3723
+ item().description! | translate | async
3724
+ }}</span>
3596
3725
  }
3597
3726
  </div>
3598
3727
  } @else {
3599
- <div
3600
- (click)="setCommand()"
3601
- class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden">
3728
+ <div
3729
+ (click)="setCommand()"
3730
+ class="ax-group ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-3 ax-w-full ax-h-full ax-relative ax-overflow-hidden"
3731
+ >
3602
3732
  <div class="ax-absolute ax-inset-0 ax-bg-black/0 hover:ax-bg-black/5 ax-transition-opacity"></div>
3603
3733
  <i class="fa-light fa-plus ax-text-3xl"></i>
3604
- <span class="ax-text-xl ax-font-semibold">Add Shortcut</span>
3734
+ <span class="ax-text-xl ax-font-semibold">{{
3735
+ '@dashboard:widgets.dashboard-shortcut.add-shortcut' | translate | async
3736
+ }}</span>
3605
3737
  </div>
3606
3738
  }
3607
3739
  `,
3608
3740
  standalone: true,
3609
3741
  changeDetection: ChangeDetectionStrategy.OnPush,
3610
- imports: [CommonModule, AXTranslationModule]
3742
+ imports: [CommonModule, AXTranslationModule],
3611
3743
  }]
3612
3744
  }], propDecorators: { __style: [{
3613
3745
  type: HostBinding,
@@ -3623,15 +3755,18 @@ var dashboardShortcutWidgetView_component = /*#__PURE__*/Object.freeze({
3623
3755
  });
3624
3756
 
3625
3757
  const AXPDashboardShortcutWidget = {
3626
- name: "dashboard-shortcut",
3627
- title: "Shortcut",
3758
+ name: 'dashboard-shortcut',
3759
+ title: 'Shortcut',
3628
3760
  description: 'Quick access to your key features.',
3629
3761
  type: 'view',
3630
3762
  categories: [AXP_WIDGETS_UTILITY_CATEGORY],
3631
3763
  groups: [AXPWidgetGroupEnum.DashboardWidget],
3632
- icon: "fa-light fa-link",
3764
+ icon: 'fa-light fa-link',
3633
3765
  properties: [
3634
- AXP_COLOR_PROPERTY
3766
+ {
3767
+ ...AXP_COLOR_PROPERTY,
3768
+ title: '@dashboard:widgets.dashboard-shortcut.color',
3769
+ },
3635
3770
  ],
3636
3771
  meta: {
3637
3772
  dimensions: {
@@ -3647,7 +3782,7 @@ const AXPDashboardShortcutWidget = {
3647
3782
  view: {
3648
3783
  component: () => Promise.resolve().then(function () { return dashboardShortcutWidgetView_component; }).then((c) => c.AXPDashboardShortcutWidgetViewComponent),
3649
3784
  },
3650
- }
3785
+ },
3651
3786
  };
3652
3787
 
3653
3788
  class AXMMenuProvider {
@@ -3843,6 +3978,7 @@ class AXMDashboardWidgetWrapperComponent {
3843
3978
  });
3844
3979
  });
3845
3980
  this.hasConfiguration = input(true);
3981
+ this.isLocked = input(false);
3846
3982
  this.isDropdownOpen = signal(false);
3847
3983
  }
3848
3984
  #init;
@@ -3863,11 +3999,11 @@ class AXMDashboardWidgetWrapperComponent {
3863
3999
  console.log('Dropdown event:', event);
3864
4000
  }
3865
4001
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMDashboardWidgetWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3866
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMDashboardWidgetWrapperComponent, isStandalone: true, selector: "axm-dashboard-widget-wrapper", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, hasConfiguration: { classPropertyName: "hasConfiguration", publicName: "hasConfiguration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onDelete: "onDelete", onConfiguration: "onConfiguration", onValueChanged: "onValueChanged", onOptionsChanged: "onOptionsChanged" }, queries: [{ propertyName: "widget", first: true, predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"ax-relative ax-size-full ax-flex ax-flex-col ax-group ax-overflow-hidden\">\n <!-- Action button - stays absolute -->\n <div\n class=\"ax-p-[0.6125rem] ax-absolute ax-top-0 ax-end-0 ax-z-[99] ax-invisible group-hover:ax-visible\"\n [class.!ax-visible]=\"isDropdownOpen()\"\n >\n <ax-button class=\"ax-sm\" [look]=\"'blank'\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-ellipsis-vertical\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel (onOpened)=\"isDropdownOpen.set(true)\" (onClosed)=\"isDropdownOpen.set(false)\">\n <ng-container *translate=\"let t\">\n <ax-button-item-list (onItemClick)=\"handleOnItemClick($event)\">\n @if(hasConfiguration()){\n <ax-button-item\n [data]=\"'configuration'\"\n [text]=\"(t('configuration', { scope: 'dashboard' }) | async) || 'configuration'\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-divider></ax-divider>\n }\n <ax-button-item\n [data]=\"'delete'\"\n [text]=\"(t('delete', { scope: 'dashboard' }) | async) || 'delete'\"\n color=\"danger\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ng-container>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n\n <!-- Title section -->\n @if(title()) {\n <div class=\"ax-ps-5 ax-pe-8 ax-py-3 ax-border-b\">\n <h3 class=\"ax-text-start ax-text-lg ax-font-medium ax-truncate\">{{title()}}</h3>\n </div>\n }\n\n <!-- Content section -->\n <div class=\"ax-overflow-auto ax-h-full\">\n <ng-content></ng-content>\n </div>\n</section>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3$2.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i6.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4002
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMDashboardWidgetWrapperComponent, isStandalone: true, selector: "axm-dashboard-widget-wrapper", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, hasConfiguration: { classPropertyName: "hasConfiguration", publicName: "hasConfiguration", isSignal: true, isRequired: false, transformFunction: null }, isLocked: { classPropertyName: "isLocked", publicName: "isLocked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onDelete: "onDelete", onConfiguration: "onConfiguration", onValueChanged: "onValueChanged", onOptionsChanged: "onOptionsChanged" }, queries: [{ propertyName: "widget", first: true, predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"ax-relative ax-size-full ax-flex ax-flex-col ax-group ax-overflow-hidden\">\n <!-- Action button - stays absolute -->\n @if(!isLocked()) {\n <div\n class=\"ax-p-[0.6125rem] ax-absolute ax-top-0 ax-end-0 ax-z-[99] ax-invisible group-hover:ax-visible md:group-hover:ax-visible\"\n [class.!ax-visible]=\"isDropdownOpen()\"\n (touchstart)=\"isDropdownOpen.set(true)\"\n >\n <ax-button class=\"ax-sm ax-main-button\" [look]=\"'blank'\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-ellipsis-vertical\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel (onOpened)=\"isDropdownOpen.set(true)\" (onClosed)=\"isDropdownOpen.set(false)\">\n <ng-container *translate=\"let t\">\n <ax-button-item-list (onItemClick)=\"handleOnItemClick($event)\">\n @if(hasConfiguration()){\n <ax-button-item\n [data]=\"'configuration'\"\n [text]=\"(t('configuration', { scope: 'dashboard' }) | async) || 'configuration'\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-divider></ax-divider>\n }\n <ax-button-item [data]=\"'delete'\" [text]=\"(t('delete') | async) || 'delete'\" color=\"danger\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ng-container>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n }\n\n <!-- Title section -->\n @if(title()) {\n <div class=\"ax-ps-5 ax-pe-8 ax-py-3 ax-border-b\">\n <h3 class=\"ax-text-start ax-text-lg ax-font-medium ax-truncate\">{{title()}}</h3>\n </div>\n }\n\n <!-- Content section -->\n <div class=\"ax-overflow-auto ax-h-full\">\n <ng-content></ng-content>\n </div>\n</section>\n", styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3$2.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i2$3.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3867
4003
  }
3868
4004
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMDashboardWidgetWrapperComponent, decorators: [{
3869
4005
  type: Component,
3870
- args: [{ selector: 'axm-dashboard-widget-wrapper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXButtonModule, AXDecoratorModule, AXDropdownModule, AXTranslationModule, CommonModule], standalone: true, template: "<section class=\"ax-relative ax-size-full ax-flex ax-flex-col ax-group ax-overflow-hidden\">\n <!-- Action button - stays absolute -->\n <div\n class=\"ax-p-[0.6125rem] ax-absolute ax-top-0 ax-end-0 ax-z-[99] ax-invisible group-hover:ax-visible\"\n [class.!ax-visible]=\"isDropdownOpen()\"\n >\n <ax-button class=\"ax-sm\" [look]=\"'blank'\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-ellipsis-vertical\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel (onOpened)=\"isDropdownOpen.set(true)\" (onClosed)=\"isDropdownOpen.set(false)\">\n <ng-container *translate=\"let t\">\n <ax-button-item-list (onItemClick)=\"handleOnItemClick($event)\">\n @if(hasConfiguration()){\n <ax-button-item\n [data]=\"'configuration'\"\n [text]=\"(t('configuration', { scope: 'dashboard' }) | async) || 'configuration'\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-divider></ax-divider>\n }\n <ax-button-item\n [data]=\"'delete'\"\n [text]=\"(t('delete', { scope: 'dashboard' }) | async) || 'delete'\"\n color=\"danger\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ng-container>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n\n <!-- Title section -->\n @if(title()) {\n <div class=\"ax-ps-5 ax-pe-8 ax-py-3 ax-border-b\">\n <h3 class=\"ax-text-start ax-text-lg ax-font-medium ax-truncate\">{{title()}}</h3>\n </div>\n }\n\n <!-- Content section -->\n <div class=\"ax-overflow-auto ax-h-full\">\n <ng-content></ng-content>\n </div>\n</section>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
4006
+ args: [{ selector: 'axm-dashboard-widget-wrapper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXButtonModule, AXDecoratorModule, AXDropdownModule, AXTranslationModule, CommonModule], standalone: true, template: "<section class=\"ax-relative ax-size-full ax-flex ax-flex-col ax-group ax-overflow-hidden\">\n <!-- Action button - stays absolute -->\n @if(!isLocked()) {\n <div\n class=\"ax-p-[0.6125rem] ax-absolute ax-top-0 ax-end-0 ax-z-[99] ax-invisible group-hover:ax-visible md:group-hover:ax-visible\"\n [class.!ax-visible]=\"isDropdownOpen()\"\n (touchstart)=\"isDropdownOpen.set(true)\"\n >\n <ax-button class=\"ax-sm ax-main-button\" [look]=\"'blank'\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-ellipsis-vertical\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel (onOpened)=\"isDropdownOpen.set(true)\" (onClosed)=\"isDropdownOpen.set(false)\">\n <ng-container *translate=\"let t\">\n <ax-button-item-list (onItemClick)=\"handleOnItemClick($event)\">\n @if(hasConfiguration()){\n <ax-button-item\n [data]=\"'configuration'\"\n [text]=\"(t('configuration', { scope: 'dashboard' }) | async) || 'configuration'\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n <ax-divider></ax-divider>\n }\n <ax-button-item [data]=\"'delete'\" [text]=\"(t('delete') | async) || 'delete'\" color=\"danger\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-trash-can\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </ng-container>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n }\n\n <!-- Title section -->\n @if(title()) {\n <div class=\"ax-ps-5 ax-pe-8 ax-py-3 ax-border-b\">\n <h3 class=\"ax-text-start ax-text-lg ax-font-medium ax-truncate\">{{title()}}</h3>\n </div>\n }\n\n <!-- Content section -->\n <div class=\"ax-overflow-auto ax-h-full\">\n <ng-content></ng-content>\n </div>\n</section>\n", styles: [":host{display:block;width:100%;height:100%}\n"] }]
3871
4007
  }] });
3872
4008
 
3873
4009
  const path = 'home:dashboard:';
@@ -3880,7 +4016,6 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3880
4016
  constructor() {
3881
4017
  super(...arguments);
3882
4018
  this.scope = RootConfig.config.i18n;
3883
- this.isAdmin = false;
3884
4019
  this.roleService = inject(AXMOrganizationManagementRoleEntityService);
3885
4020
  this.sessionService = inject(AXPSessionService);
3886
4021
  this.title = model('');
@@ -3888,6 +4023,7 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3888
4023
  this.selectedRoleIds = model([]);
3889
4024
  this.isDisabled = model(false);
3890
4025
  this.isLocked = model(false);
4026
+ this.isAdmin = model(false);
3891
4027
  this.roles = [];
3892
4028
  }
3893
4029
  get isValid() {
@@ -3897,14 +4033,20 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3897
4033
  // Set initial values from input data
3898
4034
  this.title.set(this.data?.title || '');
3899
4035
  this.description.set(this.data?.description || '');
3900
- this.selectedRoleIds.set(this.data?.roleIds || []);
3901
4036
  this.isDisabled.set(this.data?.isDeleted || false);
3902
4037
  this.isLocked.set(this.data?.locked || false);
4038
+ this.isAdmin.set(this.data?.isAdmin || false);
3903
4039
  // Load roles if admin
3904
- if (this.isAdmin) {
4040
+ if (this.isAdmin()) {
3905
4041
  try {
3906
4042
  const result = await this.roleService.query({ skip: 0, take: 100 });
3907
- this.roles = result.items || [];
4043
+ if (result.items && result.items.length > 0) {
4044
+ this.roles = result.items.map((i) => ({
4045
+ id: i.id,
4046
+ title: i.title,
4047
+ }));
4048
+ }
4049
+ this.selectedRoleIds.set(this.roles.filter((i) => this.data?.roleIds?.includes(i.id)).map((i) => i.id));
3908
4050
  }
3909
4051
  catch (error) {
3910
4052
  console.error('Error loading roles:', error);
@@ -3916,10 +4058,10 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3916
4058
  this.close({
3917
4059
  title: this.title()?.trim(),
3918
4060
  description: this.description()?.trim(),
3919
- roleIds: this.isAdmin ? this.selectedRoleIds() : undefined,
3920
- isDeleted: this.isAdmin ? this.isDisabled() : undefined,
3921
- locked: this.isAdmin ? this.isLocked() : undefined,
3922
- scope: this.isAdmin ? 'T' : 'U',
4061
+ roleIds: this.isAdmin() ? this.selectedRoleIds() : undefined,
4062
+ isDeleted: this.isAdmin() ? this.isDisabled() : undefined,
4063
+ locked: this.isAdmin() ? this.isLocked() : undefined,
4064
+ scope: this.isAdmin() ? 'T' : 'U',
3923
4065
  createdBy: this.sessionService.user?.id,
3924
4066
  createdAt: new Date(),
3925
4067
  updatedBy: this.sessionService.user?.id,
@@ -3928,7 +4070,7 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3928
4070
  });
3929
4071
  }
3930
4072
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMAddDashboardPopup, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3931
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMAddDashboardPopup, isStandalone: true, selector: "ng-component", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, selectedRoleIds: { classPropertyName: "selectedRoleIds", publicName: "selectedRoleIds", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, isLocked: { classPropertyName: "isLocked", publicName: "isLocked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { title: "titleChange", description: "descriptionChange", selectedRoleIds: "selectedRoleIdsChange", isDisabled: "isDisabledChange", isLocked: "isLockedChange" }, usesInheritance: true, ngImport: i0, template: `
4073
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: AXMAddDashboardPopup, isStandalone: true, selector: "ng-component", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, selectedRoleIds: { classPropertyName: "selectedRoleIds", publicName: "selectedRoleIds", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, isLocked: { classPropertyName: "isLocked", publicName: "isLocked", isSignal: true, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { title: "titleChange", description: "descriptionChange", selectedRoleIds: "selectedRoleIdsChange", isDisabled: "isDisabledChange", isLocked: "isLockedChange", isAdmin: "isAdminChange" }, usesInheritance: true, ngImport: i0, template: `
3932
4074
  <div class="ax-card-body ax-p-4">
3933
4075
  <div class="ax-flex ax-flex-col ax-gap-2 ax-pb-4">
3934
4076
  <p class="ax-font-semibold">{{ 'title' | translate | async }}</p>
@@ -3940,7 +4082,7 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3940
4082
  </ax-text-box>
3941
4083
  </div>
3942
4084
 
3943
- @if (isAdmin) {
4085
+ @if (isAdmin()) {
3944
4086
  <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
3945
4087
  <p class="ax-font-semibold">{{ 'roles' | translate: { scope } | async }}</p>
3946
4088
  <ax-select-box
@@ -3955,14 +4097,16 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3955
4097
  </ax-select-box>
3956
4098
  </div>
3957
4099
 
3958
- <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
3959
- <p class="ax-font-semibold">{{ 'disable' | translate: { scope } | async }}</p>
3960
- <ax-check-box [(ngModel)]="isDisabled" name="isDisabled"></ax-check-box>
3961
- </div>
4100
+ <div class="ax-grid grid-cols-2 ax-grid-flow-col ax-gap-8 ax-mt-4">
4101
+ <div class="ax-flex ax-flex-row ax-items-center ax-gap-2">
4102
+ <p class="ax-font-semibold">{{ 'disable' | translate: { scope } | async }}</p>
4103
+ <ax-switch [(ngModel)]="isDisabled" name="isDisabled"></ax-switch>
4104
+ </div>
3962
4105
 
3963
- <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
3964
- <p class="ax-font-semibold">{{ 'lock' | translate: { scope } | async }}</p>
3965
- <ax-check-box [(ngModel)]="isLocked" name="isLocked"></ax-check-box>
4106
+ <div class="ax-flex ax-flex-row ax-items-center ax-gap-2">
4107
+ <p class="ax-font-semibold">{{ 'lock' | translate: { scope } | async }}</p>
4108
+ <ax-switch [(ngModel)]="isLocked" name="isLocked"></ax-switch>
4109
+ </div>
3966
4110
  </div>
3967
4111
  }
3968
4112
  </div>
@@ -3982,7 +4126,7 @@ class AXMAddDashboardPopup extends AXBasePageComponent {
3982
4126
  </ax-button>
3983
4127
  </ax-suffix>
3984
4128
  </ax-footer>
3985
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i3$3.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }] }); }
4129
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i3$3.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2$3.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSwitchModule }, { kind: "component", type: i8.AXSwitchComponent, selector: "ax-switch", inputs: ["disabled", "readonly", "color", "tabIndex", "value", "name", "isLoading"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged", "readonlyChange", "disabledChange"] }] }); }
3986
4130
  }
3987
4131
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMAddDashboardPopup, decorators: [{
3988
4132
  type: Component,
@@ -3999,7 +4143,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
3999
4143
  </ax-text-box>
4000
4144
  </div>
4001
4145
 
4002
- @if (isAdmin) {
4146
+ @if (isAdmin()) {
4003
4147
  <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
4004
4148
  <p class="ax-font-semibold">{{ 'roles' | translate: { scope } | async }}</p>
4005
4149
  <ax-select-box
@@ -4014,14 +4158,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
4014
4158
  </ax-select-box>
4015
4159
  </div>
4016
4160
 
4017
- <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
4018
- <p class="ax-font-semibold">{{ 'disable' | translate: { scope } | async }}</p>
4019
- <ax-check-box [(ngModel)]="isDisabled" name="isDisabled"></ax-check-box>
4020
- </div>
4161
+ <div class="ax-grid grid-cols-2 ax-grid-flow-col ax-gap-8 ax-mt-4">
4162
+ <div class="ax-flex ax-flex-row ax-items-center ax-gap-2">
4163
+ <p class="ax-font-semibold">{{ 'disable' | translate: { scope } | async }}</p>
4164
+ <ax-switch [(ngModel)]="isDisabled" name="isDisabled"></ax-switch>
4165
+ </div>
4021
4166
 
4022
- <div class="ax-flex ax-flex-col ax-gap-2 ax-mt-4">
4023
- <p class="ax-font-semibold">{{ 'lock' | translate: { scope } | async }}</p>
4024
- <ax-check-box [(ngModel)]="isLocked" name="isLocked"></ax-check-box>
4167
+ <div class="ax-flex ax-flex-row ax-items-center ax-gap-2">
4168
+ <p class="ax-font-semibold">{{ 'lock' | translate: { scope } | async }}</p>
4169
+ <ax-switch [(ngModel)]="isLocked" name="isLocked"></ax-switch>
4170
+ </div>
4025
4171
  </div>
4026
4172
  }
4027
4173
  </div>
@@ -4051,7 +4197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
4051
4197
  CommonModule,
4052
4198
  AXTranslationModule,
4053
4199
  AXSelectBoxModule,
4054
- AXCheckBoxModule,
4200
+ AXSwitchModule,
4055
4201
  ],
4056
4202
  standalone: true,
4057
4203
  }]
@@ -4120,6 +4266,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
4120
4266
  class AXMDashboardPopupService {
4121
4267
  constructor() {
4122
4268
  this.popupService = inject(AXPopupService);
4269
+ this.translateService = inject(AXTranslationService);
4123
4270
  }
4124
4271
  async generateDashboardLayout(data, isAdmin) {
4125
4272
  // Add isAdmin to the data object
@@ -4129,8 +4276,8 @@ class AXMDashboardPopupService {
4129
4276
  size: 'sm',
4130
4277
  draggable: true,
4131
4278
  hasBackdrop: true,
4132
- title: 'Dashboard Info',
4133
- data: dashboardData,
4279
+ title: await this.translateService.translateAsync('dashboard-info', { scope: 'dashboard' }),
4280
+ data: { data: dashboardData },
4134
4281
  });
4135
4282
  if (!result.data) {
4136
4283
  return;
@@ -4147,7 +4294,7 @@ class AXMDashboardPopupService {
4147
4294
  size: 'sm',
4148
4295
  draggable: true,
4149
4296
  hasBackdrop: true,
4150
- title: 'Widget Configuration',
4297
+ title: await this.translateService.translateAsync('widget-configuration', { scope: 'dashboard' }),
4151
4298
  data: { widget },
4152
4299
  });
4153
4300
  if (!result.data) {
@@ -4167,106 +4314,119 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
4167
4314
  args: [{ providedIn: 'root' }]
4168
4315
  }] });
4169
4316
 
4317
+ // Helper functions
4318
+ const createInitialState = () => ({
4319
+ dashboards: [],
4320
+ allDashboards: [],
4321
+ currentDashboardId: null,
4322
+ isAdmin: false,
4323
+ dashboardsOption: {
4324
+ float: false,
4325
+ cellHeight: 75,
4326
+ gap: 5,
4327
+ minRow: 9,
4328
+ column: 12,
4329
+ responsiveLayout: [
4330
+ { column: 12, width: 2048 },
4331
+ { column: 6, width: 768 },
4332
+ { column: 1, width: 480 },
4333
+ ],
4334
+ },
4335
+ isLoading: false,
4336
+ });
4337
+ const modelToDashboardLayout = (model) => ({
4338
+ id: model.id || '',
4339
+ title: model.title,
4340
+ description: model.description,
4341
+ widgets: model.widgets || [],
4342
+ roleIds: model.roleIds,
4343
+ isDeleted: model.isDeleted,
4344
+ locked: model.locked,
4345
+ createdAt: model.createdAt,
4346
+ updatedAt: model.updatedAt,
4347
+ createdBy: model.createdBy,
4348
+ updatedBy: model.updatedBy,
4349
+ scope: model.scope,
4350
+ });
4351
+ const dashboardLayoutToModel = (layout) => ({
4352
+ id: layout.id,
4353
+ name: layout.title,
4354
+ title: layout.title,
4355
+ description: layout.description || '',
4356
+ widgets: layout.widgets,
4357
+ roleIds: layout.roleIds,
4358
+ isDeleted: layout.isDeleted,
4359
+ locked: layout.locked,
4360
+ createdAt: layout.createdAt,
4361
+ updatedAt: layout.updatedAt,
4362
+ createdBy: layout.createdBy,
4363
+ updatedBy: layout.updatedBy,
4364
+ scope: layout.scope,
4365
+ });
4170
4366
  // Create the SignalStore
4171
4367
  const AXMDashboardStore = signalStore({ providedIn: 'root' },
4172
4368
  // Initial State Definition
4173
- withState(() => {
4174
- // Define initial empty state
4175
- const state = {
4176
- dashboards: [],
4177
- allDashboards: [],
4178
- currentDashboardId: null,
4179
- isAdmin: false,
4180
- dashboardsOption: {
4181
- float: true,
4182
- cellHeight: 75,
4183
- gap: 5,
4184
- minRow: 9,
4185
- column: 12,
4186
- responsiveLayout: [
4187
- { column: 12, width: 2048 },
4188
- { column: 6, width: 768 },
4189
- { column: 1, width: 480 },
4190
- ],
4191
- },
4192
- isLoading: false,
4193
- };
4194
- return state;
4195
- }),
4369
+ withState(() => createInitialState()),
4196
4370
  // Computed Properties
4197
- withComputed((state, sessionService = inject(AXPSessionService)) => ({
4198
- currentDashboard: computed(() => {
4199
- return state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId()) || null;
4200
- }),
4201
- isAdmin: computed(() => {
4202
- return state.isAdmin();
4203
- }),
4204
- allDashboards: computed(() => {
4205
- return state.allDashboards();
4206
- }),
4207
- dashboardsOption: computed(() => {
4371
+ withComputed((state, sessionService = inject(AXPSessionService), layoutThemeService = inject(AXPLayoutThemeService)) => ({
4372
+ selectedDashboard: computed(() => state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId()) || null),
4373
+ isUserAdmin: computed(() => state.isAdmin()),
4374
+ availableDashboards: computed(() => state.allDashboards()),
4375
+ currentLayoutOptions: computed(() => {
4208
4376
  const currentDashboard = state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId());
4209
4377
  const baseOptions = state.dashboardsOption();
4210
- // If no current dashboard, return base options
4211
- if (!currentDashboard) {
4378
+ if (!currentDashboard)
4212
4379
  return baseOptions;
4380
+ if (!layoutThemeService.isDesktopDevice()) {
4381
+ return { ...baseOptions, disableDrag: true, disableResize: true };
4213
4382
  }
4214
- // If admin, no restrictions
4215
- if (state.isAdmin()) {
4383
+ if (baseOptions.disableDrag !== undefined && baseOptions.disableResize !== undefined) {
4216
4384
  return baseOptions;
4217
4385
  }
4218
- // Check if dashboard is locked
4219
4386
  if (currentDashboard.locked === true) {
4220
- return {
4221
- ...baseOptions,
4222
- disableDrag: true,
4223
- disableResize: true,
4224
- };
4387
+ return { ...baseOptions, disableDrag: true, disableResize: true };
4225
4388
  }
4226
- // Get user role
4389
+ if (state.isAdmin())
4390
+ return baseOptions;
4227
4391
  const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4228
- // Check if user has role in dashboard
4229
4392
  const hasRoleIds = currentDashboard.roleIds && Array.isArray(currentDashboard.roleIds) && currentDashboard.roleIds.length > 0;
4230
4393
  const hasUserRole = userRole && hasRoleIds && currentDashboard.roleIds?.includes(userRole);
4231
- // If user is not admin, has role in dashboard, and dashboard has scope 'T', disable drag and resize
4232
4394
  if (!state.isAdmin() && hasUserRole && currentDashboard.scope === 'T') {
4233
- return {
4234
- ...baseOptions,
4235
- disableDrag: true,
4236
- disableResize: true,
4237
- };
4395
+ return { ...baseOptions, disableDrag: true, disableResize: true };
4238
4396
  }
4239
- // Otherwise, return base options
4240
4397
  return baseOptions;
4241
4398
  }),
4242
- canConfigureWidget: computed(() => {
4243
- return (widget) => {
4244
- const currentDashboard = state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId());
4245
- if (!currentDashboard)
4246
- return true;
4247
- // If admin, always allow configuration
4248
- if (state.isAdmin())
4249
- return widget.node?.options?.['hasConfiguration'] ?? true;
4250
- // If dashboard is locked, no configuration allowed
4251
- if (currentDashboard.locked === true) {
4252
- return false;
4253
- }
4254
- // Get user role
4255
- const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4256
- // Check if user has role in dashboard
4257
- const hasRoleIds = currentDashboard.roleIds && Array.isArray(currentDashboard.roleIds) && currentDashboard.roleIds.length > 0;
4258
- const hasUserRole = userRole && hasRoleIds && currentDashboard.roleIds?.includes(userRole);
4259
- // If user is not admin, has role in dashboard, and dashboard has scope 'T', disable configuration
4260
- if (hasUserRole && currentDashboard.scope === 'T') {
4261
- return false;
4262
- }
4263
- // Otherwise, use the widget's configuration value or default to true
4399
+ canConfigureWidget: computed(() => (widget) => {
4400
+ const currentDashboard = state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId());
4401
+ if (!currentDashboard)
4402
+ return true;
4403
+ if (state.isAdmin())
4264
4404
  return widget.node?.options?.['hasConfiguration'] ?? true;
4265
- };
4405
+ if (currentDashboard.locked === true)
4406
+ return false;
4407
+ const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4408
+ const hasRoleIds = currentDashboard.roleIds && Array.isArray(currentDashboard.roleIds) && currentDashboard.roleIds.length > 0;
4409
+ const hasUserRole = userRole && hasRoleIds && currentDashboard.roleIds?.includes(userRole);
4410
+ if (hasUserRole && currentDashboard.scope === 'T')
4411
+ return false;
4412
+ return widget.node?.options?.['hasConfiguration'] ?? true;
4413
+ }),
4414
+ isWidgetLocked: computed(() => (widget) => {
4415
+ const currentDashboard = state.dashboards().find((dashboard) => dashboard.id === state.currentDashboardId());
4416
+ if (!currentDashboard)
4417
+ return false;
4418
+ if (currentDashboard.locked === true)
4419
+ return true;
4420
+ if (state.isAdmin())
4421
+ return false;
4422
+ const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4423
+ const hasRoleIds = currentDashboard.roleIds && Array.isArray(currentDashboard.roleIds) && currentDashboard.roleIds.length > 0;
4424
+ const hasUserRole = userRole && hasRoleIds && currentDashboard.roleIds?.includes(userRole);
4425
+ return hasUserRole && currentDashboard.scope === 'T';
4266
4426
  }),
4267
4427
  })),
4268
4428
  // Methods for State Management
4269
- withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogService = inject(AXDialogService), translationService = inject(AXTranslationService), widgetPickerService = inject(AXPWidgetPickerService), dashboardService = inject(AXMDashboardService), settingService = inject(AXPSettingService), sessionService = inject(AXPSessionService)) => {
4429
+ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogService = inject(AXDialogService), translationService = inject(AXTranslationService), widgetPickerService = inject(AXPWidgetPickerService), dashboardService = inject(AXMDashboardService), settingService = inject(AXPSettingService), sessionService = inject(AXPSessionService), layoutThemeService = inject(AXPLayoutThemeService)) => {
4270
4430
  // Load dashboards from service - runs on init via effect
4271
4431
  effect(() => {
4272
4432
  loadDashboards();
@@ -4275,126 +4435,112 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4275
4435
  async function loadDashboards() {
4276
4436
  try {
4277
4437
  patchState(store, { isLoading: true });
4278
- // Get dashboards from service using query method
4279
4438
  const result = await dashboardService.query({ skip: 0, take: 100 });
4280
4439
  const dashboardModels = result.items || [];
4281
- // Convert dashboard models to AXPDashboardLayout
4282
4440
  const dashboards = dashboardModels.map(modelToDashboardLayout);
4283
- // Get current dashboard from settings
4284
4441
  const currentDashboardId = await settingService
4285
4442
  .scope(AXPPlatformScope.User)
4286
4443
  .get(AXPHomeDashboardSetting.CurrentDashboard);
4287
4444
  let newCurrentDashboardId = null;
4288
4445
  if (dashboards.length > 0) {
4289
- // Check if currentDashboardId exists and is valid
4290
4446
  const dashboardExists = currentDashboardId && dashboards.some((d) => d.id === currentDashboardId);
4291
- if (dashboardExists) {
4292
- newCurrentDashboardId = currentDashboardId;
4293
- }
4294
- else {
4295
- // If current dashboard is not valid or not set, use the first one
4296
- newCurrentDashboardId = dashboards[0].id;
4297
- // Save to user settings
4447
+ newCurrentDashboardId = dashboardExists ? currentDashboardId : dashboards[0].id;
4448
+ if (!dashboardExists) {
4298
4449
  settingService
4299
4450
  .scope(AXPPlatformScope.User)
4300
4451
  .set(AXPHomeDashboardSetting.CurrentDashboard, newCurrentDashboardId);
4301
4452
  }
4302
4453
  }
4303
- // First, update the state with all dashboards
4304
4454
  patchState(store, {
4305
4455
  allDashboards: dashboards,
4306
- dashboards: dashboards, // Initially set all dashboards
4456
+ dashboards: dashboards,
4307
4457
  isLoading: false,
4308
4458
  currentDashboardId: newCurrentDashboardId,
4309
4459
  });
4310
- // After state is updated, apply filtering if needed
4311
- if (store.isAdmin() !== undefined) {
4312
- // We need to use the method from the return object, so we'll call it later
4313
- }
4314
4460
  }
4315
4461
  catch (error) {
4316
4462
  console.error('Error loading dashboards:', error);
4317
4463
  patchState(store, { isLoading: false });
4318
4464
  }
4319
4465
  }
4320
- // Convert entity model to dashboard layout
4321
- function modelToDashboardLayout(model) {
4322
- return {
4323
- id: model.id || '',
4324
- title: model.title,
4325
- description: model.description,
4326
- widgets: model.widgets || [],
4327
- roleIds: model.roleIds,
4328
- isDeleted: model.isDeleted,
4329
- locked: model.locked,
4330
- createdAt: model.createdAt,
4331
- updatedAt: model.updatedAt,
4332
- createdBy: model.createdBy,
4333
- updatedBy: model.updatedBy,
4334
- scope: model.scope,
4335
- };
4336
- }
4337
- // Convert dashboard layout to entity model
4338
- function dashboardLayoutToModel(layout) {
4339
- return {
4340
- id: layout.id,
4341
- name: layout.title,
4342
- title: layout.title,
4343
- description: layout.description || '',
4344
- widgets: layout.widgets,
4345
- roleIds: layout.roleIds,
4346
- isDeleted: layout.isDeleted,
4347
- locked: layout.locked,
4348
- createdAt: layout.createdAt,
4349
- updatedAt: layout.updatedAt,
4350
- createdBy: layout.createdBy,
4351
- updatedBy: layout.updatedBy,
4352
- scope: layout.scope,
4353
- };
4354
- }
4355
4466
  return {
4356
- // Set current dashboard
4357
4467
  setCurrentDashboard(dashboardId) {
4358
4468
  patchState(store, { currentDashboardId: dashboardId });
4359
4469
  settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting.CurrentDashboard, dashboardId);
4360
4470
  },
4361
- // Add a new dashboard
4362
4471
  async addDashboard() {
4363
4472
  try {
4364
- const newDashboard = await dashboardPopup.generateDashboardLayout({}, store.isAdmin());
4473
+ const newDashboard = await dashboardPopup.generateDashboardLayout({}, store.isUserAdmin());
4365
4474
  if (!newDashboard)
4366
4475
  return;
4367
- // Add creation and update metadata
4368
4476
  const userId = sessionService.user?.id;
4369
4477
  const now = new Date();
4370
- newDashboard.createdBy = userId;
4371
- newDashboard.createdAt = now;
4372
- newDashboard.updatedBy = userId;
4373
- newDashboard.updatedAt = now;
4374
- newDashboard.scope = store.isAdmin() ? 'T' : 'U';
4375
- // Create dashboard model and save to service
4376
- const dashboardModel = dashboardLayoutToModel(newDashboard);
4478
+ const dashboardWithMetadata = {
4479
+ ...newDashboard,
4480
+ createdBy: userId,
4481
+ createdAt: now,
4482
+ updatedBy: userId,
4483
+ updatedAt: now,
4484
+ scope: store.isUserAdmin() ? 'T' : 'U',
4485
+ widgets: [],
4486
+ };
4487
+ const dashboardModel = dashboardLayoutToModel(dashboardWithMetadata);
4377
4488
  const createdDashboardId = await dashboardService.insertOne(dashboardModel);
4378
- newDashboard.id = createdDashboardId;
4379
- newDashboard.widgets = [];
4380
- // Update both allDashboards and dashboards states
4381
- const updatedAllDashboards = [...store.allDashboards(), newDashboard];
4382
- const updatedDashboards = [...store.dashboards(), newDashboard];
4489
+ dashboardWithMetadata.id = createdDashboardId;
4490
+ const updatedAllDashboards = [...store.availableDashboards(), dashboardWithMetadata];
4491
+ const updatedDashboards = [...store.dashboards(), dashboardWithMetadata];
4383
4492
  patchState(store, {
4384
4493
  allDashboards: updatedAllDashboards,
4385
4494
  dashboards: updatedDashboards,
4386
- currentDashboardId: newDashboard.id,
4495
+ currentDashboardId: dashboardWithMetadata.id,
4387
4496
  });
4388
- // Save current dashboard to settings
4389
- settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting.CurrentDashboard, newDashboard.id);
4497
+ settingService
4498
+ .scope(AXPPlatformScope.User)
4499
+ .set(AXPHomeDashboardSetting.CurrentDashboard, dashboardWithMetadata.id);
4390
4500
  }
4391
4501
  catch (error) {
4392
4502
  console.error('Error adding dashboard:', error);
4393
4503
  }
4394
4504
  },
4395
- // Add a widget to the current dashboard
4505
+ async editDashboard() {
4506
+ const currentDashboard = store.selectedDashboard();
4507
+ if (!currentDashboard)
4508
+ return;
4509
+ try {
4510
+ const editedDashboard = await dashboardPopup.generateDashboardLayout({
4511
+ title: currentDashboard.title,
4512
+ description: currentDashboard.description,
4513
+ roleIds: currentDashboard.roleIds,
4514
+ scope: currentDashboard.scope,
4515
+ }, store.isUserAdmin());
4516
+ if (!editedDashboard)
4517
+ return;
4518
+ const userId = sessionService.user?.id;
4519
+ const now = new Date();
4520
+ const updatedDashboard = {
4521
+ ...currentDashboard,
4522
+ ...editedDashboard,
4523
+ updatedBy: userId,
4524
+ updatedAt: now,
4525
+ };
4526
+ await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4527
+ const updatedAllDashboards = store
4528
+ .availableDashboards()
4529
+ .map((d) => (d.id === updatedDashboard.id ? updatedDashboard : d));
4530
+ const updatedDashboards = store
4531
+ .dashboards()
4532
+ .map((d) => (d.id === updatedDashboard.id ? updatedDashboard : d));
4533
+ patchState(store, {
4534
+ allDashboards: updatedAllDashboards,
4535
+ dashboards: updatedDashboards,
4536
+ });
4537
+ }
4538
+ catch (error) {
4539
+ console.error('Error editing dashboard:', error);
4540
+ }
4541
+ },
4396
4542
  async addWidget() {
4397
- if (!store.currentDashboardId()) {
4543
+ if (!store.selectedDashboard()) {
4398
4544
  console.warn('No current dashboard selected');
4399
4545
  return;
4400
4546
  }
@@ -4402,57 +4548,43 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4402
4548
  const widgets = await widgetPickerService.showPicker({
4403
4549
  groups: [AXPWidgetGroupEnum.DashboardWidget],
4404
4550
  });
4405
- //remove meta from widgets //TODO TEMPORARY FIX
4406
- const filteredWidgets = widgets.map(({ __meta__, ...rest }) => rest);
4407
- if (filteredWidgets[0]?.type === 'sticky-note') {
4408
- if (!filteredWidgets[0].options) {
4409
- filteredWidgets[0].options = {};
4551
+ const filteredWidgets = widgets.map(({ __meta__, ...rest }) => {
4552
+ const widget = rest;
4553
+ if (widget.type === 'sticky-note' && !widget.options) {
4554
+ widget.options = { hasConfiguration: false };
4410
4555
  }
4411
- filteredWidgets[0].options.hasConfiguration = false;
4412
- }
4413
- filteredWidgets.forEach((widget) => {
4414
4556
  const randomId = AXPDataGenerator.uuid();
4415
- widget.name = widget?.type + '-' + randomId;
4416
- widget.path = widget?.type + '-' + randomId;
4417
- });
4418
- // Step 2: Convert the selected widgets into AXPDashboardWidgetData format
4419
- const convertedWidgets = filteredWidgets.map((widget) => {
4420
- const id = AXPDataGenerator.uuid();
4421
- return {
4422
- config: {
4423
- height: widget?.meta?.dimensions?.height ?? 2,
4424
- width: widget?.meta?.dimensions?.width ?? 2,
4425
- minHeight: widget?.meta?.dimensions?.minHeight,
4426
- minWidth: widget?.meta?.dimensions?.minWidth,
4427
- maxHeight: widget?.meta?.dimensions?.maxHeight,
4428
- maxWidth: widget?.meta?.dimensions?.maxWidth,
4429
- id,
4430
- },
4431
- node: { ...widget, name: id },
4432
- };
4433
- });
4434
- // Step 3: Update the dashboards
4435
- const updatedDashboards = store.dashboards().map((dashboard) => {
4436
- if (dashboard.id === store.currentDashboardId()) {
4437
- return {
4438
- ...dashboard,
4439
- widgets: [...dashboard.widgets, ...convertedWidgets],
4440
- };
4441
- }
4442
- return dashboard;
4557
+ widget.name = `${widget.type}-${randomId}`;
4558
+ widget.path = `${widget.type}-${randomId}`;
4559
+ return widget;
4443
4560
  });
4444
- // Step 4: Save the updated dashboard to the service
4445
- const currentDashboard = updatedDashboards.find((d) => d.id === store.currentDashboardId());
4446
- if (currentDashboard) {
4447
- await dashboardService.updateOne(currentDashboard.id, dashboardLayoutToModel(currentDashboard));
4448
- }
4561
+ const convertedWidgets = filteredWidgets.map((widget) => ({
4562
+ config: {
4563
+ height: widget?.meta?.dimensions?.height ?? 2,
4564
+ width: widget?.meta?.dimensions?.width ?? 2,
4565
+ minHeight: widget?.meta?.dimensions?.minHeight,
4566
+ minWidth: widget?.meta?.dimensions?.minWidth,
4567
+ maxHeight: widget?.meta?.dimensions?.maxHeight,
4568
+ maxWidth: widget?.meta?.dimensions?.maxWidth,
4569
+ id: AXPDataGenerator.uuid(),
4570
+ },
4571
+ node: { ...widget, name: widget.name },
4572
+ }));
4573
+ const currentDashboard = store.selectedDashboard();
4574
+ const updatedDashboard = {
4575
+ ...currentDashboard,
4576
+ widgets: [...currentDashboard.widgets, ...convertedWidgets],
4577
+ };
4578
+ await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4579
+ const updatedDashboards = store
4580
+ .dashboards()
4581
+ .map((d) => (d.id === updatedDashboard.id ? updatedDashboard : d));
4449
4582
  patchState(store, { dashboards: updatedDashboards });
4450
4583
  }
4451
4584
  catch (error) {
4452
4585
  console.error('Error adding widget:', error);
4453
4586
  }
4454
4587
  },
4455
- // Remove a dashboard
4456
4588
  async removeDashboard(id) {
4457
4589
  if (!id) {
4458
4590
  console.warn('No dashboard ID provided for removal');
@@ -4461,17 +4593,13 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4461
4593
  try {
4462
4594
  const dialogResult = await dialogService.confirm(await translationService.translateAsync('workflow.warning'), await translationService.translateAsync('workflow.confirm-delete'), 'danger', 'horizontal');
4463
4595
  if (dialogResult.result) {
4464
- // Delete from service
4465
4596
  await dashboardService.deleteOne(id);
4466
- // Remove the dashboard from both state arrays
4467
- const updatedAllDashboards = store.allDashboards().filter((dashboard) => dashboard.id !== id);
4597
+ const updatedAllDashboards = store.availableDashboards().filter((dashboard) => dashboard.id !== id);
4468
4598
  const updatedDashboards = store.dashboards().filter((dashboard) => dashboard.id !== id);
4469
- // Update state and select a new current dashboard if needed
4470
4599
  let newCurrentDashboardId = store.currentDashboardId();
4471
4600
  if (id === store.currentDashboardId()) {
4472
4601
  newCurrentDashboardId =
4473
4602
  updatedDashboards.length > 0 ? updatedDashboards[updatedDashboards.length - 1].id : null;
4474
- // Save to settings if we changed the current dashboard
4475
4603
  if (newCurrentDashboardId) {
4476
4604
  settingService
4477
4605
  .scope(AXPPlatformScope.User)
@@ -4489,7 +4617,6 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4489
4617
  console.error('Error removing dashboard:', error);
4490
4618
  }
4491
4619
  },
4492
- // Remove a widget from a dashboard
4493
4620
  async removeWidget(dashboardId, widgetId) {
4494
4621
  const currentDashboard = store.dashboards().find((d) => d.id === dashboardId);
4495
4622
  if (!currentDashboard)
@@ -4498,88 +4625,56 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4498
4625
  ...currentDashboard,
4499
4626
  widgets: currentDashboard.widgets.filter((widget) => widget.config.id !== widgetId),
4500
4627
  };
4501
- // Save to service
4502
4628
  await dashboardService.updateOne(dashboardId, dashboardLayoutToModel(updatedDashboard));
4503
- // Update local state
4504
4629
  const updatedDashboards = store
4505
4630
  .dashboards()
4506
4631
  .map((dashboard) => (dashboard.id === dashboardId ? updatedDashboard : dashboard));
4507
4632
  patchState(store, { dashboards: updatedDashboards });
4508
4633
  },
4509
- // Handle configuration changes
4510
4634
  async handleConfigChange(dashboard) {
4511
- // Save to service
4512
4635
  await dashboardService.updateOne(dashboard.id, dashboardLayoutToModel(dashboard));
4513
- // Update local state
4514
4636
  const updatedDashboards = store.dashboards().map((d) => (d.id === dashboard.id ? dashboard : d));
4515
4637
  patchState(store, {
4516
4638
  dashboards: updatedDashboards,
4517
4639
  currentDashboardId: dashboard.id,
4518
4640
  });
4519
- // Save current dashboard to settings
4520
4641
  settingService.scope(AXPPlatformScope.User).set(AXPHomeDashboardSetting.CurrentDashboard, dashboard.id);
4521
4642
  },
4522
- // Handle grid layout changes
4523
4643
  async onGridChange(event) {
4524
- if (!store.currentDashboard()) {
4525
- console.warn('No current dashboard for grid change');
4644
+ if (!layoutThemeService.isDesktopDevice() || !store.selectedDashboard())
4526
4645
  return;
4527
- }
4528
- // Extract nodes from the event and remove the `element` property
4529
4646
  const nodes = event.nodes.map(({ element, ...rest }) => rest);
4530
- // Update the current dashboard
4531
- const currentDashboard = store.currentDashboard();
4647
+ const currentDashboard = store.selectedDashboard();
4532
4648
  const updatedWidgets = currentDashboard.widgets.map((widget) => {
4533
4649
  const updatedNode = nodes.find((node) => node.id === widget.config.id);
4534
- if (updatedNode) {
4535
- return {
4536
- ...widget,
4537
- config: updatedNode,
4538
- };
4539
- }
4540
- return widget;
4650
+ return updatedNode ? { ...widget, config: updatedNode } : widget;
4541
4651
  });
4542
4652
  const updatedDashboard = {
4543
4653
  ...currentDashboard,
4544
4654
  widgets: updatedWidgets,
4545
4655
  };
4546
- // Save to service
4547
4656
  await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4548
- // Update the dashboards
4549
4657
  const updatedDashboards = store
4550
4658
  .dashboards()
4551
4659
  .map((dashboard) => (dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard));
4552
4660
  patchState(store, { dashboards: updatedDashboards });
4553
4661
  },
4554
- // Handle widget configuration
4555
4662
  async handlePopupConfiguration(widgetNode) {
4556
- if (!store.currentDashboard()) {
4557
- console.warn('No current dashboard selected');
4663
+ if (!store.selectedDashboard())
4558
4664
  return;
4559
- }
4560
4665
  try {
4561
4666
  const updatedNode = await dashboardPopup.handlePopupConfiguration(widgetNode);
4562
- if (!updatedNode) {
4667
+ if (!updatedNode)
4563
4668
  return;
4564
- }
4565
- // Update the current dashboard's widget with the new configuration
4566
- const currentDashboard = store.currentDashboard();
4567
- const updatedWidgets = currentDashboard.widgets.map((widget) => {
4568
- if (widget.node?.name === widgetNode.name && widget.node?.path === widgetNode.path) {
4569
- return {
4570
- ...widget,
4571
- node: updatedNode,
4572
- };
4573
- }
4574
- return widget;
4575
- });
4669
+ const currentDashboard = store.selectedDashboard();
4670
+ const updatedWidgets = currentDashboard.widgets.map((widget) => widget.node?.name === widgetNode.name && widget.node?.path === widgetNode.path
4671
+ ? { ...widget, node: updatedNode }
4672
+ : widget);
4576
4673
  const updatedDashboard = {
4577
4674
  ...currentDashboard,
4578
4675
  widgets: updatedWidgets,
4579
4676
  };
4580
- // Save to service
4581
4677
  await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4582
- // Update the dashboards state
4583
4678
  const updatedDashboards = store
4584
4679
  .dashboards()
4585
4680
  .map((dashboard) => (dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard));
@@ -4589,74 +4684,47 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4589
4684
  console.error('Error handling widget configuration:', error);
4590
4685
  }
4591
4686
  },
4592
- // Handle widget value changes
4593
4687
  async handleValueChanged(widgetNode, data) {
4594
- if (!store.currentDashboard()) {
4595
- console.warn('No current dashboard selected');
4688
+ if (!store.selectedDashboard())
4596
4689
  return;
4597
- }
4598
4690
  try {
4599
- // Update the current dashboard's widget with the new value
4600
- const currentDashboard = store.currentDashboard();
4601
- const updatedWidgets = currentDashboard.widgets.map((widget) => {
4602
- if (widget.node && widget.node.name === widgetNode.name && widget.node.path === widgetNode.path) {
4603
- return {
4604
- ...widget,
4605
- node: {
4606
- ...widget.node,
4607
- defaultValue: data,
4608
- },
4609
- };
4610
- }
4611
- return widget;
4612
- });
4691
+ const currentDashboard = store.selectedDashboard();
4692
+ const updatedWidgets = currentDashboard.widgets.map((widget) => widget.node && widget.node.name === widgetNode.name && widget.node.path === widgetNode.path
4693
+ ? { ...widget, node: { ...widget.node, defaultValue: data } }
4694
+ : widget);
4613
4695
  const updatedDashboard = {
4614
4696
  ...currentDashboard,
4615
4697
  widgets: updatedWidgets,
4616
4698
  };
4617
- // Save to service
4618
4699
  await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4619
- // Update the dashboards state
4620
4700
  const updatedDashboards = store
4621
4701
  .dashboards()
4622
4702
  .map((dashboard) => (dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard));
4623
- // patchState(store, { dashboards: updatedDashboards });
4703
+ patchState(store, { dashboards: updatedDashboards });
4624
4704
  }
4625
4705
  catch (error) {
4626
4706
  console.error('Error handling widget value change:', error);
4627
4707
  }
4628
4708
  },
4629
- // Handle widget options changes
4630
4709
  async handleOptionsChanged(widgetNode, data) {
4631
- if (!store.currentDashboard()) {
4632
- console.warn('No current dashboard selected');
4710
+ if (!store.selectedDashboard())
4633
4711
  return;
4634
- }
4635
4712
  try {
4636
- // Update the current dashboard's widget with the new options
4637
- const currentDashboard = store.currentDashboard();
4638
- const updatedWidgets = currentDashboard.widgets.map((widget) => {
4639
- if (widget.node && widget.node.name === widgetNode.name && widget.node.path === widgetNode.path) {
4640
- return {
4641
- ...widget,
4642
- node: {
4643
- ...widget.node,
4644
- options: {
4645
- ...(widget.node.options || {}),
4646
- ...data,
4647
- },
4648
- },
4649
- };
4713
+ const currentDashboard = store.selectedDashboard();
4714
+ const updatedWidgets = currentDashboard.widgets.map((widget) => widget.node && widget.node.name === widgetNode.name && widget.node.path === widgetNode.path
4715
+ ? {
4716
+ ...widget,
4717
+ node: {
4718
+ ...widget.node,
4719
+ options: { ...(widget.node.options || {}), ...data },
4720
+ },
4650
4721
  }
4651
- return widget;
4652
- });
4722
+ : widget);
4653
4723
  const updatedDashboard = {
4654
4724
  ...currentDashboard,
4655
4725
  widgets: updatedWidgets,
4656
4726
  };
4657
- // Save to service
4658
4727
  await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4659
- // Update the dashboards state
4660
4728
  const updatedDashboards = store
4661
4729
  .dashboards()
4662
4730
  .map((dashboard) => (dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard));
@@ -4666,112 +4734,70 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4666
4734
  console.error('Error handling widget options change:', error);
4667
4735
  }
4668
4736
  },
4669
- // Reload dashboards from service
4670
- async refreshDashboards() {
4671
- try {
4672
- patchState(store, { isLoading: true });
4673
- // Get dashboards from service using query method
4674
- const result = await dashboardService.query({ skip: 0, take: 100 });
4675
- const dashboardModels = result.items || [];
4676
- // Convert dashboard models to AXPDashboardLayout
4677
- const dashboards = dashboardModels.map(modelToDashboardLayout);
4678
- // Update allDashboards state
4679
- patchState(store, {
4680
- allDashboards: dashboards,
4681
- isLoading: false,
4682
- });
4683
- // Re-apply filtering based on current isAdmin state
4684
- // This will update the dashboards state with filtered results
4685
- const userId = sessionService.user?.id;
4686
- const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4687
- if (userId) {
4688
- this.filterDashboardsByScope(store.isAdmin());
4689
- }
4690
- else {
4691
- // If no user, just show all dashboards
4692
- patchState(store, { dashboards });
4693
- }
4694
- }
4695
- catch (error) {
4696
- console.error('Error refreshing dashboards:', error);
4697
- patchState(store, { isLoading: false });
4698
- }
4737
+ setIsAdmin(isAdmin) {
4738
+ patchState(store, { isAdmin });
4699
4739
  },
4700
4740
  filterDashboardsByScope(isAdmin) {
4701
- // Get all dashboards from the stored allDashboards array
4702
- const allDashboards = store.allDashboards();
4703
- // Get user ID and role from session service
4741
+ const allDashboards = store.availableDashboards();
4704
4742
  const userId = sessionService.user?.id;
4705
4743
  const userRole = sessionService.user ? sessionService.user['role'] : undefined;
4706
4744
  if (!userId) {
4707
- // If no user ID, don't filter
4708
4745
  patchState(store, { dashboards: allDashboards });
4709
4746
  return;
4710
4747
  }
4711
- // Apply filtering based on user permissions
4712
- let filteredDashboards = allDashboards;
4713
- if (isAdmin) {
4714
- // Admin sees only tenant-level dashboards
4715
- filteredDashboards = allDashboards.filter((dashboard) => dashboard.scope === 'T');
4716
- }
4717
- else {
4718
- // Regular users see:
4719
- // 1. User-level dashboards they created
4720
- // 2. Tenant-level dashboards where their role is included AND isDeleted is false/undefined
4721
- filteredDashboards = allDashboards.filter((dashboard) => {
4722
- // Check if this is a user-level dashboard created by this user
4748
+ const filteredDashboards = isAdmin
4749
+ ? allDashboards.filter((dashboard) => dashboard.scope === 'T')
4750
+ : allDashboards.filter((dashboard) => {
4723
4751
  const isUserDashboard = dashboard.scope === 'U' && dashboard.createdBy === userId;
4724
- // Check if this is a tenant-level dashboard with user's role and is not deleted
4725
4752
  const hasRoleIds = dashboard.roleIds && Array.isArray(dashboard.roleIds) && dashboard.roleIds.length > 0;
4726
4753
  const isTenantDashboard = dashboard.scope === 'T';
4727
4754
  const hasUserRole = userRole && hasRoleIds && dashboard.roleIds?.includes(userRole);
4728
- const isNotDeleted = dashboard.isDeleted !== true; // Show if isDeleted is false or undefined
4755
+ const isNotDeleted = dashboard.isDeleted !== true;
4729
4756
  const isTenantDashboardWithRole = isTenantDashboard && hasUserRole && isNotDeleted;
4730
4757
  return isUserDashboard || isTenantDashboardWithRole;
4731
4758
  });
4732
- }
4733
- // Update dashboards state
4734
4759
  patchState(store, { dashboards: filteredDashboards });
4735
- // If current dashboard is not in filtered list, select the first one
4736
4760
  if (filteredDashboards.length > 0 && !filteredDashboards.some((d) => d.id === store.currentDashboardId())) {
4737
4761
  this.setCurrentDashboard(filteredDashboards[0].id);
4738
4762
  }
4739
4763
  },
4740
- // Add method to set isAdmin state
4741
- setIsAdmin(isAdmin) {
4742
- patchState(store, { isAdmin });
4743
- },
4744
- // Toggle lock state for the current dashboard
4745
4764
  async toggleLockDashboard() {
4746
- const currentDashboard = store.currentDashboard();
4747
- if (!currentDashboard) {
4748
- console.warn('No current dashboard selected');
4765
+ const currentDashboard = store.selectedDashboard();
4766
+ if (!currentDashboard)
4749
4767
  return;
4750
- }
4751
4768
  try {
4752
- // Toggle the locked state
4769
+ const isAdmin = store.isUserAdmin();
4770
+ const userId = sessionService.user?.id;
4771
+ const canToggle = (!isAdmin && currentDashboard.scope === 'U' && currentDashboard.createdBy === userId) ||
4772
+ (isAdmin && currentDashboard.scope === 'T');
4773
+ if (!canToggle) {
4774
+ console.warn('User does not have permission to toggle lock for this dashboard');
4775
+ return;
4776
+ }
4753
4777
  const newLockedState = !currentDashboard.locked;
4754
- // Create an updated dashboard with toggled lock state
4755
4778
  const updatedDashboard = {
4756
4779
  ...currentDashboard,
4757
4780
  locked: newLockedState,
4758
4781
  };
4759
- // Save to service
4760
4782
  await dashboardService.updateOne(updatedDashboard.id, dashboardLayoutToModel(updatedDashboard));
4761
- // Update the dashboards in store
4762
4783
  const updatedDashboards = store
4763
4784
  .dashboards()
4764
4785
  .map((dashboard) => (dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard));
4786
+ const baseOptions = { ...store.dashboardsOption() };
4765
4787
  patchState(store, { dashboards: updatedDashboards });
4766
- console.log(`Dashboard ${newLockedState ? 'locked' : 'unlocked'}`);
4788
+ const updatedOptions = {
4789
+ ...baseOptions,
4790
+ disableDrag: newLockedState,
4791
+ disableResize: newLockedState,
4792
+ };
4793
+ patchState(store, { dashboardsOption: updatedOptions });
4767
4794
  }
4768
4795
  catch (error) {
4769
4796
  console.error('Error toggling dashboard lock state:', error);
4770
4797
  }
4771
4798
  },
4772
- // Check if dashboard is locked
4773
4799
  isDashboardLocked() {
4774
- const currentDashboard = store.currentDashboard();
4800
+ const currentDashboard = store.selectedDashboard();
4775
4801
  return currentDashboard?.locked === true;
4776
4802
  },
4777
4803
  };
@@ -4780,61 +4806,40 @@ withMethods((store, dashboardPopup = inject(AXMDashboardPopupService), dialogSer
4780
4806
  class AXMDashboardHomeComponent extends AXPBasePageComponent {
4781
4807
  constructor() {
4782
4808
  super(...arguments);
4783
- //#region ---------------- Services & Dependencies ----------------
4809
+ // Dependencies
4784
4810
  this.rootConfig = RootConfig;
4785
- this.popupService = inject(AXPopupService);
4811
+ this.activatedRoute = inject(ActivatedRoute);
4786
4812
  this.dialogService = inject(AXDialogService);
4787
- this.store = inject(AXMDashboardStore);
4813
+ this.popupService = inject(AXPopupService);
4788
4814
  this.router = inject(Router);
4789
- this.activatedRoute = inject(ActivatedRoute);
4790
- this.layoutService = inject(AXPLayoutThemeService);
4791
- this.sessionService = inject(AXPSessionService);
4792
- // Track if dashboards have been loaded
4793
- this.dashboardsLoaded = signal(false);
4794
- //#endregion
4795
- //#region ---------------- View Properties ----------------
4796
- this.isEdited = signal(false);
4815
+ this.store = inject(AXMDashboardStore);
4816
+ this.themeService = inject(AXPLayoutThemeService);
4817
+ // Component State
4797
4818
  this.context = signal({});
4798
- //#endregion
4799
- //#region ---------------- Effects ----------------
4800
- // Create an effect to watch for dashboards loading
4801
- this.#dashboardsEffect = effect(() => {
4802
- const allDashboards = this.store.allDashboards();
4819
+ this.dashboardsLoaded = signal(false);
4820
+ // Effects
4821
+ this.#initEffect = effect(() => {
4822
+ const allDashboards = this.store.availableDashboards();
4803
4823
  if (allDashboards.length > 0 && !this.dashboardsLoaded()) {
4804
4824
  this.dashboardsLoaded.set(true);
4805
- // Apply dashboard filtering now that dashboards are loaded
4806
4825
  this.applyDashboardFiltering();
4826
+ this.recompute();
4807
4827
  }
4808
4828
  });
4809
- this.#loadingEffect = effect(() => {
4810
- const isLoading = false; // Since store doesn't have isLoading, we'll default to false
4811
- this.layoutService.setNavigationLoading(isLoading);
4812
- });
4813
4829
  }
4814
- //#endregion
4815
- //#region ---------------- Lifecycle Methods ----------------
4830
+ // Lifecycle Hooks
4816
4831
  async ngOnInit() {
4817
- // Get the child route if it exists
4818
4832
  const childRoute = this.activatedRoute.firstChild || this.activatedRoute;
4819
4833
  childRoute.data.subscribe((data) => {
4820
4834
  const isAdmin = data['isAdmin'] ?? false;
4821
- // Set isAdmin state in the store
4822
4835
  this.store.setIsAdmin(isAdmin);
4823
4836
  });
4824
4837
  }
4838
+ // Effects
4839
+ #initEffect;
4840
+ // Private Methods
4825
4841
  applyDashboardFiltering() {
4826
- // The store now gets user info directly from the session service
4827
- this.store.filterDashboardsByScope(this.store.isAdmin());
4828
- }
4829
- //#endregion
4830
- //#region ---------------- Effects ----------------
4831
- // Create an effect to watch for dashboards loading
4832
- #dashboardsEffect;
4833
- #loadingEffect;
4834
- //#endregion
4835
- //#region ---------------- Event Handlers ----------------
4836
- toggleEdit() {
4837
- this.isEdited.update((value) => !value);
4842
+ this.store.filterDashboardsByScope(this.store.isUserAdmin());
4838
4843
  }
4839
4844
  async confirmWidgetDelete(dashboardId, widgetId) {
4840
4845
  try {
@@ -4847,24 +4852,21 @@ class AXMDashboardHomeComponent extends AXPBasePageComponent {
4847
4852
  console.error('Error confirming widget deletion:', error);
4848
4853
  }
4849
4854
  }
4850
- //#endregion
4855
+ // Page Interface Implementation
4851
4856
  getPageTitle() {
4852
- return this.store.currentDashboard()?.title || 'Dashboard';
4857
+ return this.store.selectedDashboard()?.title || 'Dashboard';
4853
4858
  }
4854
4859
  async getPageDescription() {
4855
- return this.store.currentDashboard()?.description || '';
4860
+ return this.store.selectedDashboard()?.description || '';
4856
4861
  }
4857
4862
  getTitleActions() {
4858
- return [
4859
- ...this.store.dashboards().map((i) => ({
4860
- title: i.title,
4861
- command: { name: i.id, metadata: { isDashboard: true, dashboard: i } },
4862
- icon: i.id === this.store.currentDashboardId() ? 'fa-solid fa-check' : '',
4863
- })),
4864
- ];
4863
+ return this.store.dashboards().map((dashboard) => ({
4864
+ title: dashboard.title,
4865
+ command: { name: dashboard.id, metadata: { isDashboard: true, dashboard } },
4866
+ icon: dashboard.id === this.store.currentDashboardId() ? 'fa-solid fa-check' : '',
4867
+ }));
4865
4868
  }
4866
4869
  async getPrimaryMenuItems() {
4867
- const scope = this.rootConfig.config.i18n;
4868
4870
  return [
4869
4871
  {
4870
4872
  title: 't("add-item")',
@@ -4875,74 +4877,78 @@ class AXMDashboardHomeComponent extends AXPBasePageComponent {
4875
4877
  title: await this.translateService.translateAsync('dashboard', { scope: 'dashboard' }),
4876
4878
  icon: 'fa-light fa-gauge-high',
4877
4879
  break: true,
4878
- command: {
4879
- name: 'new-dashboard',
4880
- },
4880
+ command: { name: 'new-dashboard' },
4881
4881
  },
4882
4882
  {
4883
4883
  title: await this.translateService.translateAsync('widget', { scope: 'dashboard' }),
4884
4884
  icon: 'fa-light fa-window-restore',
4885
- command: {
4886
- name: 'new-widget',
4887
- },
4885
+ command: { name: 'new-widget' },
4886
+ disabled: this.store.dashboards().length < 1,
4888
4887
  },
4889
4888
  ],
4890
4889
  },
4891
4890
  ];
4892
4891
  }
4893
4892
  async getSecondaryMenuItems() {
4894
- const scope = this.rootConfig.config.i18n;
4895
4893
  const items = [
4896
4894
  {
4897
- title: await this.translateService.translateAsync('delete-current-dashboard', { scope: 'dashboard' }),
4898
- icon: 'fa-light fa-trash-can',
4899
- color: 'danger',
4895
+ title: await this.translateService.translateAsync('edit'),
4896
+ icon: 'fa-light fa-pen',
4897
+ color: 'primary',
4900
4898
  disabled: this.store.dashboards().length < 1,
4901
- command: {
4902
- name: 'delete',
4903
- },
4899
+ command: { name: 'edit' },
4904
4900
  },
4905
4901
  ];
4906
- // Only add lock toggle if not admin
4907
- if (!this.store.isAdmin()) {
4902
+ if (!this.store.isUserAdmin() && this.themeService.isDesktopDevice()) {
4908
4903
  items.push({
4909
- title: await this.translateService.translateAsync(this.store.isDashboardLocked() ? 'unlock-dashboard' : 'lock-dashboard', { scope: 'dashboard' }),
4904
+ title: await this.translateService.translateAsync(this.store.isDashboardLocked() ? 'unlock' : 'lock', {
4905
+ scope: 'dashboard',
4906
+ }),
4910
4907
  icon: this.store.isDashboardLocked() ? 'fa-light fa-lock-open' : 'fa-light fa-lock',
4911
4908
  color: 'accent3',
4912
4909
  disabled: this.store.dashboards().length < 1,
4913
- command: {
4914
- name: 'toggle-lock',
4915
- },
4910
+ command: { name: 'toggle-lock' },
4916
4911
  });
4917
4912
  }
4913
+ items.push({
4914
+ title: await this.translateService.translateAsync('delete'),
4915
+ icon: 'fa-light fa-trash-can',
4916
+ color: 'danger',
4917
+ disabled: this.store.dashboards().length < 1,
4918
+ command: { name: 'delete' },
4919
+ });
4918
4920
  return items;
4919
4921
  }
4920
4922
  async execute(command) {
4921
4923
  if (command.metadata?.['isDashboard']) {
4922
4924
  this.store.handleConfigChange(command.metadata?.['dashboard']);
4923
4925
  this.recompute();
4926
+ return;
4924
4927
  }
4925
- else {
4926
- switch (command.name) {
4927
- case 'new-dashboard':
4928
- await this.store.addDashboard();
4929
- this.applyDashboardFiltering();
4930
- this.recompute();
4931
- break;
4932
- case 'new-widget':
4933
- await this.store.addWidget();
4934
- this.recompute();
4935
- break;
4936
- case 'delete':
4937
- await this.store.removeDashboard(this.store.currentDashboard()?.id);
4938
- this.applyDashboardFiltering();
4939
- this.recompute();
4940
- break;
4941
- case 'toggle-lock':
4942
- await this.store.toggleLockDashboard();
4943
- this.recompute();
4944
- break;
4945
- }
4928
+ switch (command.name) {
4929
+ case 'new-dashboard':
4930
+ await this.store.addDashboard();
4931
+ this.applyDashboardFiltering();
4932
+ this.recompute();
4933
+ break;
4934
+ case 'new-widget':
4935
+ await this.store.addWidget();
4936
+ this.recompute();
4937
+ break;
4938
+ case 'edit':
4939
+ await this.store.editDashboard();
4940
+ this.recompute();
4941
+ break;
4942
+ case 'delete':
4943
+ await this.store.removeDashboard(this.store.selectedDashboard()?.id);
4944
+ this.applyDashboardFiltering();
4945
+ this.recompute();
4946
+ break;
4947
+ case 'toggle-lock':
4948
+ await this.store.toggleLockDashboard();
4949
+ this.recompute();
4950
+ setTimeout(() => this.recompute(), 50);
4951
+ break;
4946
4952
  }
4947
4953
  }
4948
4954
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMDashboardHomeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
@@ -4953,7 +4959,7 @@ class AXMDashboardHomeComponent extends AXPBasePageComponent {
4953
4959
  provide: AXPBasePage,
4954
4960
  useExisting: AXMDashboardHomeComponent,
4955
4961
  },
4956
- ], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.dashboardsOption()\" (onChange)=\"store.onGridChange($event)\">\n @for(widget of store.currentDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget [options]=\"widget.config\">\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.currentDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-bg-gray-50 ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-text-gray-400 ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-text-gray-700 ax-mb-2\">\n {{ t('no-widgets', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-gray-500 ax-text-center ax-mb-6\">\n {{ t('add-first-widget', { scope: 'dashboard' }) | async }}\n </p>\n </div>\n }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important;--ax-comp-grid-layout-stack-item-content-bg-color: var(--ax-sys-color-lightest-surface) }\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i3$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXGridLayoutBuilderModule }, { kind: "component", type: i4$1.AXGridLayoutContainerComponent, selector: "ax-grid-layout-container", inputs: ["options", "isEmpty"], outputs: ["onAdded", "onRemoved", "onWidgetChange", "onChange", "onRender", "isEmptyChange"] }, { kind: "component", type: i4$1.AXGridLayoutWidgetComponent, selector: "ax-grid-layout-widget", inputs: ["options"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer, axp-page-header, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-container, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i6.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "component", type: AXMDashboardWidgetWrapperComponent, selector: "axm-dashboard-widget-wrapper", inputs: ["title", "hasConfiguration"], outputs: ["onDelete", "onConfiguration", "onValueChanged", "onOptionsChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
4962
+ ], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget [options]=\"widget.config\">\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n [isLocked]=\"store.isWidgetLocked()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.selectedDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important;--ax-comp-grid-layout-stack-item-content-bg-color: var(--ax-sys-color-lightest-surface) }\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i3$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXGridLayoutBuilderModule }, { kind: "component", type: i4$1.AXGridLayoutContainerComponent, selector: "ax-grid-layout-container", inputs: ["options", "isEmpty"], outputs: ["onAdded", "onRemoved", "onWidgetChange", "onChange", "onRender", "isEmptyChange"] }, { kind: "component", type: i4$1.AXGridLayoutWidgetComponent, selector: "ax-grid-layout-widget", inputs: ["options"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer, axp-page-header, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-container, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i2$3.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "component", type: AXMDashboardWidgetWrapperComponent, selector: "axm-dashboard-widget-wrapper", inputs: ["title", "hasConfiguration", "isLocked"], outputs: ["onDelete", "onConfiguration", "onValueChanged", "onOptionsChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
4957
4963
  }
4958
4964
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AXMDashboardHomeComponent, decorators: [{
4959
4965
  type: Component,
@@ -4979,7 +4985,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImpo
4979
4985
  provide: AXPBasePage,
4980
4986
  useExisting: AXMDashboardHomeComponent,
4981
4987
  },
4982
- ], template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.dashboardsOption()\" (onChange)=\"store.onGridChange($event)\">\n @for(widget of store.currentDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget [options]=\"widget.config\">\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.currentDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } @empty {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-bg-gray-50 ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-text-gray-400 ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-text-gray-700 ax-mb-2\">\n {{ t('no-widgets', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-gray-500 ax-text-center ax-mb-6\">\n {{ t('add-first-widget', { scope: 'dashboard' }) | async }}\n </p>\n </div>\n }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important;--ax-comp-grid-layout-stack-item-content-bg-color: var(--ax-sys-color-lightest-surface) }\n"] }]
4988
+ ], template: "<axp-page-layout *translate=\"let t\">\n <!-- Content Section -->\n\n <axp-page-content class=\"ax-relative\">\n <!-- Loading State -->\n @if(store.isLoading()) {\n <div\n class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-w-full ax-absolute ax-z-10 ax-bg-white/80\"\n >\n <ax-loading></ax-loading>\n <p class=\"ax-mt-3 ax-text-gray-600\">{{ t('loading', { scope: 'dashboard' }) | async }}</p>\n </div>\n } @else {\n <axp-widgets-container [context]=\"context()\">\n <ax-grid-layout-container [options]=\"store.currentLayoutOptions()\" (onChange)=\"store.onGridChange($event)\">\n <!-- No Dashboards State -->\n @if(!store.dashboards() || store.dashboards().length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-dashboards', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Selected Dashboard State -->\n @else if (!store.selectedDashboard()) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">\n {{ t('no-current-dashboard', { scope: 'dashboard' }) | async }}\n </h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('select-dashboard', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- No Widgets State -->\n @else if (!store.selectedDashboard()?.widgets || store.selectedDashboard()?.widgets?.length === 0) {\n <div class=\"ax-flex ax-flex-col ax-items-center ax-justify-center ax-h-full ax-p-4\">\n <ax-icon icon=\"fa-light fa-shapes\" class=\"ax-text-4xl ax-mb-4\"></ax-icon>\n <h2 class=\"ax-text-xl ax-font-semibold ax-mb-2\">{{ t('no-widgets', { scope: 'dashboard' }) | async }}</h2>\n <p class=\"ax-text-center ax-mb-6\">{{ t('add-first-widget', { scope: 'dashboard' }) | async }}</p>\n </div>\n }\n <!-- Widgets Grid -->\n @else { @for(widget of store.selectedDashboard()?.widgets; track widget.config.id) {\n <ax-grid-layout-widget [options]=\"widget.config\">\n <axm-dashboard-widget-wrapper\n [title]=\"widget.node?.options?.['title']\"\n [hasConfiguration]=\"store.canConfigureWidget()(widget)\"\n [isLocked]=\"store.isWidgetLocked()(widget)\"\n (onDelete)=\"confirmWidgetDelete(store.selectedDashboard()?.id!, widget.config.id!)\"\n (onConfiguration)=\"store.handlePopupConfiguration(widget.node!)\"\n (onValueChanged)=\"store.handleValueChanged(widget?.node!,$event)\"\n (onOptionsChanged)=\"store.handleOptionsChanged(widget?.node!,$event)\"\n >\n @if(widget.node) {\n <ng-container axp-widget-renderer [node]=\"widget.node\" [mode]=\"'view'\"></ng-container>\n }\n </axm-dashboard-widget-wrapper>\n </ax-grid-layout-widget>\n } }\n </ax-grid-layout-container>\n </axp-widgets-container>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axm-dashboard-home{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-dashboard-home .placeholder-content{border-radius:.5rem!important;border-width:1px!important;border-style:dashed!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))!important;background-color:rgba(var(--ax-sys-color-primary-lightest-surface),.5)!important}axm-dashboard-home ax-grid-layout-widget .grid-stack-item-content{border-radius:.375rem!important;border-width:1px!important;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05) !important;--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important;--ax-comp-grid-layout-stack-item-content-bg-color: var(--ax-sys-color-lightest-surface) }\n"] }]
4983
4989
  }] });
4984
4990
 
4985
4991
  var homeDashboard = /*#__PURE__*/Object.freeze({