@hestia-earth/ui-components 0.37.3 → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,17 +6,19 @@ import { UntypedFormBuilder, Validators, FormsModule, ReactiveFormsModule, NG_VA
6
6
  import { NgTemplateOutlet, NgClass, DecimalPipe, KeyValuePipe, DOCUMENT, PlatformLocation, NgStyle, UpperCasePipe, JsonPipe, DatePipe, AsyncPipe } from '@angular/common';
7
7
  import * as i1$2 from '@ng-bootstrap/ng-bootstrap';
8
8
  import { NgbActiveModal, NgbHighlight, NgbTooltip, NgbDropdown, NgbDropdownMenu, NgbDropdownToggle, NgbDropdownItem, NgbTypeahead, NgbPopover, NgbModal, NgbTooltipModule, NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap';
9
- import { catchError, map, debounceTime, distinctUntilChanged, tap, switchMap, mergeMap, shareReplay, delay, take, first, filter, startWith, skip, throttleTime, skipUntil, reduce, mergeAll, toArray, distinct, groupBy } from 'rxjs/operators';
10
- import { of, zip, ReplaySubject, timer, Subject, combineLatest, pipe, fromEvent, merge as merge$1, EMPTY, animationFrameScheduler, forkJoin, from } from 'rxjs';
9
+ import { catchError, map, debounceTime, distinctUntilChanged, tap, switchMap, startWith, mergeMap, shareReplay, delay, take, first, filter, skip, throttleTime, skipUntil, reduce, mergeAll, toArray, distinct, groupBy } from 'rxjs/operators';
10
+ import { of, zip, fromEvent, ReplaySubject, timer, Subject, combineLatest, pipe, merge as merge$1, EMPTY, animationFrameScheduler, forkJoin, from } from 'rxjs';
11
11
  import { HttpClient } from '@angular/common/http';
12
12
  import get from 'lodash.get';
13
13
  import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, isTypeBlankNode, typeToSchemaType, managementTermTermType } from '@hestia-earth/schema';
14
- import { toPrecision, isUndefined, isEmpty, toComma, isNumber, getPercentileValue, unique, monthsBefore, keyToLabel, isEqual as isEqual$2, max, sum, toDashCase, diffInDays } from '@hestia-earth/utils';
14
+ import { isUndefined, isEmpty, toPrecision, ellipsis as ellipsis$1, sum, toComma, isNumber, getPercentileValue, unique, monthsBefore, keyToLabel, isEqual as isEqual$2, max, toDashCase, diffInDays } from '@hestia-earth/utils';
15
15
  import Gradient from 'javascript-color-gradient';
16
16
  import { ShadeGenerator } from 'shade-generator/dist/shadeGenerator';
17
- import Chart, { Chart as Chart$1 } from 'chart.js';
18
- import canvasToSvg from 'canvas-to-svg';
17
+ import { Chart, BarController, LineController, CategoryScale, LinearScale, PointElement, BarElement, LineElement, Title, Tooltip, Legend, TimeScale } from 'chart.js';
18
+ import C2S from 'canvas-to-svg';
19
+ import 'chartjs-adapter-date-fns';
19
20
  import merge from 'lodash.merge';
21
+ import { BreakpointObserver } from '@angular/cdk/layout';
20
22
  import { select, selectAll } from 'd3-selection';
21
23
  import { json2csv } from 'json-2-csv';
22
24
  import { propertyValue as propertyValue$1, emptyValue } from '@hestia-earth/utils/dist/term';
@@ -30,12 +32,11 @@ import { trigger, state, transition, style, animate } from '@angular/animations'
30
32
  import { signalStore, withState, withComputed, withMethods, patchState, withHooks } from '@ngrx/signals';
31
33
  import { rxMethod } from '@ngrx/signals/rxjs-interop';
32
34
  import { RouterLinkActive, RouterLink, ActivatedRoute } from '@angular/router';
33
- import { BreakpointObserver } from '@angular/cdk/layout';
34
35
  import { GoogleMap, MapMarker, MapPolygon } from '@angular/google-maps';
35
36
  import { Meta, DomSanitizer } from '@angular/platform-browser';
36
37
  import removeMd from 'remove-markdown';
37
38
  import orderBy from 'lodash.orderby';
38
- import { headersFromCsv, toCsv, toJson, toCsvPivot, ErrorKeys as ErrorKeys$1 } from '@hestia-earth/schema-convert';
39
+ import { headersFromCsv, toCsv, toJson, toCsvPivot, ErrorKeys } from '@hestia-earth/schema-convert';
39
40
  import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
40
41
  import { isCSVIncluded, isDefaultCSVSelected } from '@hestia-earth/json-schema/schema-utils';
41
42
  import { recommendedProperties, loadSchemas } from '@hestia-earth/json-schema';
@@ -592,16 +593,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
592
593
  }], ctorParameters: () => [], propDecorators: { search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }, { type: i0.Output, args: ["searchChange"] }], searchSources: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchSources", required: false }] }, { type: i0.Output, args: ["searchSourcesChange"] }], searchBibliographies: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchBibliographies", required: false }] }, { type: i0.Output, args: ["searchBibliographiesChange"] }], searchBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchBy", required: false }] }, { type: i0.Output, args: ["searchByChange"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
593
594
 
594
595
  const defaultBarDrawSettings = {
595
- xPosFn: x => x + 10,
596
+ xPosFn: (x, index, width, chart, data) => (data < 0 || isEmpty(data) ? chart.scales.x.getPixelForValue(0) : x) + 10,
596
597
  yPosFn: y => y + 3,
597
- colorFn: () => 'black',
598
- textFn: m => (typeof m.data === 'number' ? `${m.label} - ${toPrecision(m.data)} kg` : ''),
598
+ colorFn: (m, index, chart, data) => (isUndefined(data) ? '#b5b5b5' : '#4a4a4a'),
599
+ textFn: ({ data }) => `${data}`,
599
600
  font: '14px Lato',
600
601
  maxWidth: 90,
601
602
  emptyValueLabel: 'No data'
602
603
  };
603
604
  const afterBarDrawPlugin = settings => ({
604
- afterDraw: (chart) => {
605
+ id: 'afterBarDrawPlugin',
606
+ afterDatasetsDraw: (chart) => {
605
607
  if (!chart.data.datasets?.length) {
606
608
  return;
607
609
  }
@@ -609,23 +611,23 @@ const afterBarDrawPlugin = settings => ({
609
611
  ...defaultBarDrawSettings,
610
612
  ...(settings ?? {})
611
613
  };
612
- const { ctx } = chart;
614
+ const { ctx, width, height } = chart;
613
615
  ctx.save();
614
- const height = chart.chartArea.bottom - chart.chartArea.top;
615
- const width = chart.chartArea.right - chart.chartArea.left;
616
- chart
617
- .getDatasetMeta(0)
618
- .data.filter(({ _view }) => !!_view)
619
- .forEach(({ _view, _model, _datasetIndex, _index }, index) => {
620
- const { x, y } = _view;
621
- const label = _model.label;
622
- const data = chart.data.datasets[_datasetIndex].data[_index];
616
+ const meta = chart.getDatasetMeta(0);
617
+ const dataset = chart.data.datasets[0];
618
+ const elements = meta.data;
619
+ elements
620
+ .filter(element => !element.skip)
621
+ .forEach((element, index) => {
622
+ const { x, y } = element;
623
+ const label = chart.data.labels?.[index] ?? '';
624
+ const data = dataset.data[index];
623
625
  const xPos = xPosFn(x, index, width, chart, data);
624
626
  const yPos = yPosFn(y, index, height, chart, data);
625
627
  const text = isUndefined(data) ? emptyValueLabel : textFn({ label, data }, index, chart);
626
628
  if (text) {
627
629
  ctx.font = font;
628
- ctx.fillStyle = colorFn(_view, index, chart, data);
630
+ ctx.fillStyle = colorFn(element.options, index, chart, data);
629
631
  if (Array.isArray(text)) {
630
632
  ctx.fillText(text[0], xPos, yPos - 5, maxWidth);
631
633
  ctx.fillText(text[1], xPos, yPos + 5, maxWidth);
@@ -736,6 +738,7 @@ const hexToRgba = (hex, aplha = 1) => {
736
738
  };
737
739
  const listColorWithAlpha = (alpha = 0.8) => (_v, index) => hexToRgba(getColor(index), alpha);
738
740
 
741
+ // ... createHoverGradient remains the same ...
739
742
  const createHoverGradient = (ctx, chartArea, color) => {
740
743
  const gradient = ctx.createLinearGradient(chartArea.left, 0, chartArea.right, 0);
741
744
  gradient.addColorStop(0, colorToRgba(color, 0.05));
@@ -743,34 +746,53 @@ const createHoverGradient = (ctx, chartArea, color) => {
743
746
  gradient.addColorStop(1, colorToRgba(color, 0.05));
744
747
  return gradient;
745
748
  };
746
- const calculateShadowBounds = (barModel, threshold, barWidth) => {
747
- const barY = barModel.y;
748
- const barX = barModel.x;
749
- const barBase = barModel.base || 0;
750
- const barHeight = barModel.height || barWidth;
751
- const barTop = barY - barHeight / 2;
752
- const barBottom = barY + barHeight / 2;
753
- const isNegative = barX < barBase;
754
- const shadowLeft = isNegative ? barX : barBase;
755
- const shadowRight = isNegative ? barBase : barX;
749
+ // UPDATED: Use element properties instead of _model
750
+ const calculateBarBounds = (element, indexAxis = 'y') => {
751
+ const { x, y, base, width, height } = element;
752
+ // Handle Horizontal Bars (indexAxis: 'y')
753
+ if (indexAxis === 'y') {
754
+ const barHeight = height; // Thickness of the bar
755
+ const barTop = y - barHeight / 2;
756
+ const barBottom = y + barHeight / 2;
757
+ const barLeft = Math.min(base, x);
758
+ const barRight = Math.max(base, x);
759
+ return { barLeft, barRight, barTop, barBottom, thickness: barHeight };
760
+ }
761
+ // Handle Vertical Bars (indexAxis: 'x')
762
+ else {
763
+ const barWidth = width; // Thickness of the bar
764
+ const barLeft = x - barWidth / 2;
765
+ const barRight = x + barWidth / 2;
766
+ const barTop = Math.min(base, y);
767
+ const barBottom = Math.max(base, y);
768
+ return { barLeft, barRight, barTop, barBottom, thickness: barWidth };
769
+ }
770
+ };
771
+ // UPDATED: Calculate shadow bounds based on the bounds we just found
772
+ const calculateShadowBounds = (element, bounds, threshold) => {
756
773
  return {
757
- top: barTop - threshold,
758
- bottom: barBottom + threshold,
759
- left: shadowLeft,
760
- right: shadowRight,
761
- width: shadowRight - shadowLeft,
762
- height: barBottom + threshold - (barTop - threshold)
774
+ top: bounds.barTop - threshold,
775
+ bottom: bounds.barBottom + threshold,
776
+ left: bounds.barLeft, // Usually we expand Y (thickness), but keep X (length) capped at value
777
+ right: bounds.barRight,
778
+ width: bounds.barRight - bounds.barLeft,
779
+ height: bounds.barBottom + threshold - (bounds.barTop - threshold)
763
780
  };
764
781
  };
765
- const drawHoverEffect = (ctx, chartArea, barModel, threshold, barWidth) => {
766
- const barColor = barModel.backgroundColor || barModel.borderColor || '';
782
+ const drawHoverEffect = (ctx, chartArea, element, threshold, indexAxis) => {
783
+ // Access colors via options
784
+ const opts = element.options || null;
785
+ const barColor = (opts?.backgroundColor || opts?.borderColor || '#000000');
767
786
  const color = parseColor(barColor);
768
- const bounds = calculateShadowBounds(barModel, threshold, barWidth);
787
+ const bounds = calculateBarBounds(element, indexAxis);
788
+ const shadow = calculateShadowBounds(element, bounds, threshold);
769
789
  ctx.save();
770
- const gradient = createHoverGradient(ctx, { left: bounds.left, right: bounds.right }, color);
790
+ // Draw Gradient Background
791
+ const gradient = createHoverGradient(ctx, { left: shadow.left, right: shadow.right }, color);
771
792
  ctx.fillStyle = gradient;
772
- ctx.fillRect(bounds.left, bounds.top, bounds.width, bounds.height);
773
- drawHorizontalLines(ctx, { left: bounds.left, right: bounds.right }, bounds.top, bounds.bottom, color);
793
+ ctx.fillRect(shadow.left, shadow.top, shadow.width, shadow.height);
794
+ // Draw Dashed Lines
795
+ drawHorizontalLines(ctx, { left: shadow.left, right: shadow.right }, shadow.top, shadow.bottom, color);
774
796
  ctx.restore();
775
797
  };
776
798
  const drawHorizontalLines = (ctx, barArea, topY, bottomY, color) => {
@@ -784,45 +806,36 @@ const drawHorizontalLines = (ctx, barArea, topY, bottomY, color) => {
784
806
  ctx.lineTo(barArea.right, bottomY);
785
807
  ctx.stroke();
786
808
  };
787
- const calculateBarBounds = (model) => {
788
- const barLeft = Math.min(model.base || 0, model.x);
789
- const barRight = Math.max(model.base || 0, model.x);
790
- const barHeight = model.height || 20;
791
- const barTop = model.y - barHeight / 2;
792
- const barBottom = model.y + barHeight / 2;
793
- return { barLeft, barRight, barTop, barBottom };
794
- };
809
+ // UPDATED: Distance calculation using the new bounds
795
810
  const calculateDistanceToBar = (x, y, bounds) => {
796
811
  let distance = 0;
797
- if (x < bounds.barLeft) {
812
+ // Horizontal distance
813
+ if (x < bounds.barLeft)
798
814
  distance += Math.pow(bounds.barLeft - x, 2);
799
- }
800
- else if (x > bounds.barRight) {
815
+ else if (x > bounds.barRight)
801
816
  distance += Math.pow(x - bounds.barRight, 2);
802
- }
803
- if (y < bounds.barTop) {
817
+ // Vertical distance
818
+ if (y < bounds.barTop)
804
819
  distance += Math.pow(bounds.barTop - y, 2);
805
- }
806
- else if (y > bounds.barBottom) {
820
+ else if (y > bounds.barBottom)
807
821
  distance += Math.pow(y - bounds.barBottom, 2);
808
- }
809
822
  return Math.sqrt(distance);
810
823
  };
824
+ // UPDATED: Hit area check
811
825
  const isWithinHitArea = (x, y, bounds, threshold) => {
812
826
  const hitLeft = bounds.barLeft - threshold;
813
827
  const hitRight = bounds.barRight + threshold;
814
828
  const hitTop = bounds.barTop - threshold;
815
829
  const hitBottom = bounds.barBottom + threshold;
816
- const withinHorizontal = x >= hitLeft && x <= hitRight;
817
- const withinVertical = y >= hitTop && y <= hitBottom;
818
- return withinHorizontal && withinVertical;
830
+ return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
819
831
  };
820
- const checkBarProximity = (element, index, datasetIndex, x, y, threshold, currentClosest) => {
832
+ const checkBarProximity = (element, // Raw element
833
+ index, datasetIndex, x, y, threshold, currentClosest, indexAxis) => {
821
834
  const bar = element;
822
- const model = bar._model;
823
- if (!model)
835
+ // V4 Safety check: Ensure the element has been drawn (has x/y)
836
+ if (bar.x == null || bar.y == null)
824
837
  return;
825
- const bounds = calculateBarBounds(model);
838
+ const bounds = calculateBarBounds(bar, indexAxis);
826
839
  if (!isWithinHitArea(x, y, bounds, threshold))
827
840
  return;
828
841
  const distance = calculateDistanceToBar(x, y, bounds);
@@ -831,109 +844,115 @@ const checkBarProximity = (element, index, datasetIndex, x, y, threshold, curren
831
844
  currentClosest.bar = {
832
845
  datasetIndex,
833
846
  index,
834
- model
847
+ element: bar // Save the whole element
835
848
  };
836
849
  }
837
850
  };
838
851
  const findNearBar = (chart, x, y, threshold) => {
839
852
  const closest = { bar: null, distance: Infinity };
853
+ // Determine orientation (horizontal bar vs vertical bar)
854
+ const indexAxis = chart.options.indexAxis || 'x';
840
855
  chart.data.datasets?.forEach((dataset, datasetIndex) => {
856
+ // V4 Visibility check
857
+ if (!chart.isDatasetVisible(datasetIndex))
858
+ return;
841
859
  const meta = chart.getDatasetMeta(datasetIndex);
842
- if (!meta.hidden) {
843
- meta.data.forEach((element, index) => {
844
- checkBarProximity(element, index, datasetIndex, x, y, threshold, closest);
845
- });
846
- }
860
+ meta.data.forEach((element, index) => {
861
+ // Skip hidden/skipped elements
862
+ if (element.hidden || element.skip)
863
+ return;
864
+ checkBarProximity(element, index, datasetIndex, x, y, threshold, closest, indexAxis);
865
+ });
847
866
  });
848
867
  return closest.distance <= threshold ? closest.bar : undefined;
849
868
  };
850
869
  const triggerBarClick = (chart, barData) => {
851
- const chartWithTooltip = chart;
852
- if (chartWithTooltip.tooltip) {
853
- chartWithTooltip.tooltip._active = [
854
- {
855
- _datasetIndex: barData.datasetIndex,
856
- _index: barData.index
857
- }
858
- ];
859
- }
860
- const config = chart.config;
861
- if (config?.options?.onClick) {
862
- const element = chart.getDatasetMeta(barData.datasetIndex).data[barData.index];
870
+ const activeElements = [
871
+ {
872
+ element: barData.element,
873
+ datasetIndex: barData.datasetIndex,
874
+ index: barData.index
875
+ }
876
+ ];
877
+ // 1. Highlight visually
878
+ chart.setActiveElements(activeElements);
879
+ // 2. Show Tooltip
880
+ chart.tooltip?.setActiveElements(activeElements, { x: 0, y: 0 });
881
+ // 3. Fire Click Callback
882
+ const onClickHandler = chart.options.onClick;
883
+ if (onClickHandler) {
863
884
  const mockEvent = {
864
885
  type: 'click',
865
- x: barData.model.x,
866
- y: barData.model.y,
886
+ x: barData.element.x,
887
+ y: barData.element.y,
888
+ chart: chart,
867
889
  native: {
868
- offsetX: barData.model.x,
869
- offsetY: barData.model.y,
870
- target: chart.canvas
871
- },
872
- originalEvent: {
873
- offsetX: barData.model.x,
874
- offsetY: barData.model.y,
875
- clientX: barData.model.x,
876
- clientY: barData.model.y,
877
- target: chart.canvas
878
- },
879
- target: chart.canvas
890
+ target: chart.canvas,
891
+ preventDefault: () => { },
892
+ stopPropagation: () => { }
893
+ }
880
894
  };
881
- config.options.onClick(mockEvent, [element]);
895
+ onClickHandler.call(chart, mockEvent, activeElements, chart);
882
896
  }
883
897
  chart.update();
884
898
  };
885
899
  const handleMouseMove = (chart, nearBar, threshold, e) => {
900
+ // Return object
886
901
  const newNearBar = findNearBar(chart, e.x, e.y, threshold);
887
- chart.canvas.style.cursor = newNearBar ? 'pointer' : 'default';
888
- if (newNearBar?.datasetIndex !== nearBar?.datasetIndex || newNearBar?.index !== nearBar?.index) {
889
- chart.render({ duration: 0 });
890
- return newNearBar;
891
- }
892
- return nearBar;
902
+ const prevCursor = chart.canvas.style.cursor;
903
+ const newCursor = newNearBar ? 'pointer' : 'default';
904
+ // Optimization: Only touch DOM if necessary
905
+ if (prevCursor !== newCursor) {
906
+ chart.canvas.style.cursor = newCursor;
907
+ }
908
+ // Check if the "near bar" target has changed
909
+ const hasChanged = newNearBar?.datasetIndex !== nearBar?.datasetIndex || newNearBar?.index !== nearBar?.index;
910
+ return {
911
+ nearBar: hasChanged ? newNearBar || null : nearBar,
912
+ changed: hasChanged
913
+ };
893
914
  };
894
915
  const handleMouseOut = (chart, nearBar) => {
895
916
  chart.canvas.style.cursor = 'default';
896
- nearBar && chart.render();
917
+ return !!nearBar;
897
918
  };
898
919
  const handleClick = (chart, nearBar) => {
899
- nearBar && triggerBarClick(chart, nearBar);
920
+ if (nearBar)
921
+ triggerBarClick(chart, nearBar);
900
922
  };
901
923
  const getActiveBar = (chart) => {
902
- const chartWithTooltip = chart;
903
- const activePoints = chartWithTooltip.tooltip._active;
904
- if (!activePoints || activePoints.length === 0) {
905
- return undefined;
906
- }
907
- const activePoint = activePoints[0];
908
- const meta = chart.getDatasetMeta(activePoint._datasetIndex);
909
- const bar = meta.data[activePoint._index];
910
- return bar._model || undefined;
924
+ const activeElements = chart.tooltip?.getActiveElements();
925
+ return activeElements?.[0]?.element;
911
926
  };
912
- const defaultSettings$4 = { barWidth: 20, threshold: 10 };
927
+ const defaultSettings$4 = { threshold: 10 };
913
928
  const backgroundHoverPlugin = (settings = {}) => {
914
929
  let nearBar = null;
915
- const { barWidth, threshold } = {
916
- ...defaultSettings$4,
917
- ...settings
918
- };
930
+ const { threshold } = { ...defaultSettings$4, ...settings };
919
931
  return {
920
932
  id: 'backgroundHover',
921
- afterEvent: (chart, event) => {
922
- const e = event.event || event;
933
+ afterEvent: (chart, args) => {
934
+ const e = args.event;
935
+ let changed = false;
923
936
  if (e.type === 'mousemove') {
924
- nearBar = handleMouseMove(chart, nearBar, threshold, e);
937
+ const result = handleMouseMove(chart, nearBar, threshold || 10, e);
938
+ nearBar = result.nearBar;
939
+ changed = result.changed;
925
940
  }
926
941
  else if (e.type === 'mouseout') {
927
- handleMouseOut(chart, nearBar);
942
+ changed = handleMouseOut(chart, nearBar);
928
943
  nearBar = null;
929
944
  }
930
945
  else if (e.type === 'click') {
931
946
  handleClick(chart, nearBar);
947
+ // Clicks usually trigger their own updates, but if you need one:
948
+ // changed = true;
932
949
  }
950
+ args.changed = changed;
933
951
  },
934
952
  beforeDraw: (chart) => {
935
- const activeBar = nearBar ? nearBar.model : getActiveBar(chart);
936
- return activeBar && drawHoverEffect(chart.ctx, chart.chartArea, activeBar, threshold, barWidth);
953
+ const indexAxis = chart.options.indexAxis || 'x';
954
+ const activeBar = nearBar ? nearBar.element : getActiveBar(chart);
955
+ activeBar && drawHoverEffect(chart.ctx, chart.chartArea, activeBar, threshold || 10, indexAxis);
937
956
  }
938
957
  };
939
958
  };
@@ -967,6 +986,7 @@ const defaultLollipopSettings = {
967
986
  isMouseInsideLollipopFn: () => null
968
987
  };
969
988
  const lollipopChartPlugin = settings => ({
989
+ id: 'lollipopChartPlugin',
970
990
  afterDatasetsDraw: (chart) => {
971
991
  if (!chart.data.datasets?.length) {
972
992
  return;
@@ -984,12 +1004,13 @@ const lollipopChartPlugin = settings => ({
984
1004
  if (meta.hidden)
985
1005
  return;
986
1006
  ctx.save();
987
- meta.data
988
- .filter(({ _view }) => !!_view && !_view.skip)
989
- .forEach(({ _view, _datasetIndex, _index }, index) => {
990
- const color = colorFn(_view, index);
991
- const { base, x, y } = _view;
992
- const data = chart.data.datasets[_datasetIndex].data[_index];
1007
+ const elements = meta.data;
1008
+ elements
1009
+ .filter(element => !element.skip)
1010
+ .forEach((element, index) => {
1011
+ const { base, x, y } = element;
1012
+ const color = colorFn(element.options, index);
1013
+ const data = dataset.data[index];
993
1014
  clickableDictionary.push((clientX, clientY) => isMouseInsideCircle({ clientX, clientY }, { x, y }, circleRadius));
994
1015
  clickableDictionary.push((clientX, clientY) => isMouseInsideCircle({ clientX, clientY }, { x: base, y }, circleRadius));
995
1016
  circle(ctx, x, y, color, circleRadius);
@@ -1006,185 +1027,117 @@ const lollipopChartPlugin = settings => ({
1006
1027
 
1007
1028
  const defaultChartWidth = 800;
1008
1029
  const defaultChartHeight = 600;
1009
- const isNonSerializableType = (value) => typeof value === 'function' || value instanceof HTMLElement || value instanceof Element || value instanceof Node;
1010
- const setDefaultOptions = (config) => {
1011
- config.options = config.options || {};
1012
- config.options.plugins = config.options.plugins || {};
1013
- config.options.plugins.legend = config.options.plugins.legend || { display: false };
1014
- config.options.legendCallback = null;
1015
- config.options.tooltips = {};
1016
- config.options.animation = undefined;
1017
- config.options.responsive = false;
1018
- config.options.maintainAspectRatio = false;
1019
- config.options.devicePixelRatio = 1;
1020
- return config;
1021
- };
1022
- const modernizeChartConfig = (config) => {
1023
- const modernized = { ...config };
1024
- // For Chart.js v2, keep the configuration as-is since we're using the same version
1025
- setDefaultOptions(modernized);
1026
- return modernized;
1027
- };
1028
- const extractEssentialChartConfig = (config) => {
1029
- const essentialConfig = {
1030
- type: config.type,
1031
- data: {
1032
- labels: config.data?.labels || [],
1033
- datasets: []
1030
+ const extractEssentialChartConfig = (config) => ({
1031
+ type: config.type || 'bar',
1032
+ data: config.data,
1033
+ options: {
1034
+ indexAxis: config.options?.indexAxis,
1035
+ responsive: false,
1036
+ maintainAspectRatio: false,
1037
+ devicePixelRatio: 1,
1038
+ animation: false,
1039
+ animations: {
1040
+ colors: false,
1041
+ x: false,
1042
+ y: false
1034
1043
  },
1035
- options: {
1036
- responsive: true,
1037
- maintainAspectRatio: false,
1038
- plugins: {
1039
- legend: {
1040
- display: false
1044
+ transitions: {
1045
+ active: {
1046
+ animation: {
1047
+ duration: 0
1041
1048
  }
1042
1049
  }
1043
- }
1044
- };
1045
- if (config.data?.datasets) {
1046
- essentialConfig.data.datasets = config.data.datasets.map((dataset) => ({
1047
- label: dataset.label,
1048
- data: dataset.data || [],
1049
- backgroundColor: dataset.backgroundColor,
1050
- borderColor: dataset.borderColor,
1051
- borderWidth: dataset.borderWidth || 1,
1052
- type: dataset.type
1053
- }));
1054
- }
1055
- if (config.options?.plugins?.title) {
1056
- essentialConfig.options.plugins.title = {
1057
- display: config.options.plugins.title.display,
1058
- text: config.options.plugins.title.text
1059
- };
1060
- }
1061
- if (config.options?.scales) {
1062
- essentialConfig.options.scales = {};
1063
- Object.keys(config.options.scales).forEach(scaleKey => {
1064
- const scale = config.options.scales[scaleKey];
1065
- if (scale) {
1066
- essentialConfig.options.scales[scaleKey] = {
1067
- display: scale.display !== false,
1068
- title: scale.title
1069
- ? {
1070
- display: scale.title.display,
1071
- text: scale.title.text
1072
- }
1073
- : undefined
1074
- };
1075
- }
1076
- });
1077
- }
1078
- return setDefaultOptions(essentialConfig);
1079
- };
1080
- const sanitizeChartConfig = (config) => {
1081
- try {
1082
- const sanitized = {
1083
- type: config.type,
1084
- data: deepCloneSerializable(config.data),
1085
- options: deepCloneSerializable(config.options)
1086
- };
1087
- if (sanitized.data?.datasets?.length) {
1088
- return modernizeChartConfig(sanitized);
1089
- }
1090
- }
1091
- catch (error) {
1092
- console.error('Sanitizing chart failed, fallback to default config');
1093
- }
1094
- return modernizeChartConfig(extractEssentialChartConfig(config));
1095
- };
1096
- const deepCloneSerializable = (obj, visited = new WeakSet()) => {
1097
- const simpleValue = getSimpleValue(obj, visited);
1098
- if (simpleValue !== undefined) {
1099
- return simpleValue.value;
1100
- }
1101
- visited.add(obj);
1102
- try {
1103
- return cloneComplexObject(obj, visited);
1104
- }
1105
- catch (error) {
1106
- console.warn('Error cloning object:', error);
1107
- return {};
1108
- }
1109
- finally {
1110
- visited.delete(obj);
1111
- }
1112
- };
1113
- const getSimpleValue = (obj, visited) => {
1114
- if (obj === null || typeof obj !== 'object') {
1115
- return { value: obj };
1116
- }
1117
- if (visited.has(obj)) {
1118
- return { value: {} };
1119
- }
1120
- const specialValue = handleSpecialTypes(obj);
1121
- return specialValue !== undefined ? { value: specialValue } : undefined;
1122
- };
1123
- const cloneComplexObject = (obj, visited) => Array.isArray(obj) ? obj.map(item => deepCloneSerializable(item, visited)) : cloneObject(obj, visited);
1124
- const handleSpecialTypes = (obj) => isNonSerializableType(obj) || obj instanceof RegExp ? null : obj instanceof Date ? obj.toISOString() : undefined;
1125
- const shouldSkipProperty = (key, value) => isNonSerializableType(value) || ['__ngContext__', 'chart', 'ctx', 'canvas'].includes(key) || key.startsWith('_');
1126
- const cloneObject = (obj, visited) => {
1127
- const cloned = {};
1128
- for (const key in obj) {
1129
- if (!Object.prototype.hasOwnProperty.call(obj, key)) {
1130
- continue;
1131
- }
1132
- const value = obj[key];
1133
- if (shouldSkipProperty(key, value)) {
1134
- continue;
1135
- }
1136
- const clonedValue = deepCloneSerializable(value, visited);
1137
- if (clonedValue !== null) {
1138
- cloned[key] = clonedValue;
1139
- }
1050
+ },
1051
+ plugins: {
1052
+ legend: { display: false },
1053
+ title: config.options.plugins?.title || { display: false }
1054
+ },
1055
+ scales: config.options.scales
1140
1056
  }
1141
- return cloned;
1142
- };
1143
- const stretchSvg = (svgString) => {
1057
+ });
1058
+ const stretchSvg = (svgString, width, height) => {
1144
1059
  const parser = new DOMParser();
1145
1060
  const doc = parser.parseFromString(svgString, 'image/svg+xml');
1146
1061
  const svgElement = doc.documentElement;
1147
- // include padding on the right for labels that go over the edge
1148
- svgElement.setAttribute('viewBox', `0 0 ${+svgElement.getAttribute('width') + 100} ${svgElement.getAttribute('height')}`);
1062
+ // Add 100px padding to ViewBox for overflow labels
1063
+ svgElement.setAttribute('viewBox', `0 0 ${width + 100} ${height}`);
1149
1064
  svgElement.setAttribute('width', '100%');
1150
1065
  svgElement.setAttribute('height', '100%');
1151
1066
  svgElement.setAttribute('preserveAspectRatio', 'xMidYMid meet');
1152
1067
  return svgElement.outerHTML;
1153
1068
  };
1154
- const convertToSvg = (config, metadata = {}) => {
1069
+ const convertToSvg = (config, metadata = {}) => new Promise((resolve, reject) => {
1155
1070
  const width = metadata.width || defaultChartWidth;
1156
1071
  const height = metadata.height || defaultChartHeight;
1157
- const svgContext = new canvasToSvg(width, height);
1072
+ // 1. Create the SVG Context
1073
+ const svgContext = new C2S(width, height);
1074
+ svgContext.setTransform = () => { };
1075
+ svgContext.resetTransform = () => { };
1076
+ svgContext.roundRect = function (x, y, w, h) {
1077
+ this.rect(x, y, w, h);
1078
+ };
1079
+ // 2. Mock the Canvas Element
1158
1080
  const mockCanvas = document.createElement('canvas');
1159
- // Set dimensions to match the SVG context
1160
1081
  mockCanvas.width = width;
1161
1082
  mockCanvas.height = height;
1162
- mockCanvas.style.width = width + 'px';
1163
- mockCanvas.style.height = height + 'px';
1164
- mockCanvas.getContext = type => {
1083
+ mockCanvas.style.width = `${width}px`;
1084
+ mockCanvas.style.height = `${height}px`;
1085
+ mockCanvas.getBoundingClientRect = () => ({
1086
+ x: 0,
1087
+ y: 0,
1088
+ bottom: height,
1089
+ height: height,
1090
+ left: 0,
1091
+ right: width,
1092
+ top: 0,
1093
+ width: width,
1094
+ toJSON: () => { }
1095
+ });
1096
+ // Intercept getContext to return our SVG generator
1097
+ mockCanvas.getContext = (type) => {
1165
1098
  if (type === '2d') {
1166
1099
  svgContext.canvas = mockCanvas;
1167
1100
  return svgContext;
1168
1101
  }
1169
1102
  return null;
1170
1103
  };
1171
- const chartConfig = sanitizeChartConfig(config);
1104
+ // 3. Prepare Config
1105
+ const chartConfig = extractEssentialChartConfig(config);
1106
+ // eslint-disable-next-line prefer-const
1107
+ let chart;
1108
+ chartConfig.options.animation = {
1109
+ onComplete: () => {
1110
+ try {
1111
+ const svgString = svgContext.getSerializedSvg(true);
1112
+ const finalSvg = stretchSvg(svgString, width, height);
1113
+ chart.destroy();
1114
+ resolve(finalSvg);
1115
+ }
1116
+ catch (e) {
1117
+ reject(e);
1118
+ }
1119
+ }
1120
+ };
1121
+ // 4. Register Export-Specific Plugins
1172
1122
  chartConfig.plugins = [
1173
1123
  afterBarDrawPlugin({
1174
1124
  textFn: ({ data }) => [toPrecision(data), metadata.units].filter(Boolean).join(' '),
1175
- xPosFn: (x, index, width, chart, data) => (data < 0 || isEmpty(data) ? chart.scales['x-axis-0'].getPixelForValue(0) : x) + 10,
1176
1125
  emptyValueLabel: 'No data'
1177
1126
  }),
1178
1127
  metadata.lollipopConfig ? lollipopChartPlugin(metadata.lollipopConfig) : null
1179
- ].filter(Boolean);
1180
- new Chart(mockCanvas, chartConfig);
1181
- return stretchSvg(svgContext.getSerializedSvg(true));
1182
- };
1183
- const exportAsSVG = (config, metadata) => {
1184
- const content = convertToSvg(config, metadata);
1185
- const blob = new Blob([content], { type: 'image/svg+xml;charset=utf-8' });
1186
- const url = URL.createObjectURL(blob);
1187
- downloadFile(url, metadata.fileName || 'aggregate-chart-export.svg');
1128
+ ].filter((p) => Boolean(p));
1129
+ chart = new Chart(mockCanvas, chartConfig);
1130
+ });
1131
+ const exportAsSVG = async (config, metadata) => {
1132
+ try {
1133
+ const content = await convertToSvg(config, metadata);
1134
+ const blob = new Blob([content], { type: 'image/svg+xml;charset=utf-8' });
1135
+ const url = URL.createObjectURL(blob);
1136
+ downloadFile(url, metadata.fileName || 'chart-export.svg');
1137
+ }
1138
+ catch (error) {
1139
+ console.error('Failed to export SVG', error);
1140
+ }
1188
1141
  };
1189
1142
  const downloadSvg = (svgElement) => {
1190
1143
  const serializer = new XMLSerializer();
@@ -1197,6 +1150,10 @@ const downloadSvg = (svgElement) => {
1197
1150
  return downloadFile(url, 'chart.svg');
1198
1151
  };
1199
1152
 
1153
+ const registerChart = (items = []) => () => {
1154
+ Chart.register(BarController, LineController, CategoryScale, LinearScale, PointElement, BarElement, LineElement, Title, Tooltip, Legend, TimeScale, ...items);
1155
+ };
1156
+
1200
1157
  class ChartConfigurationDirective {
1201
1158
  constructor() {
1202
1159
  this._zone = inject(NgZone);
@@ -1210,16 +1167,11 @@ class ChartConfigurationDirective {
1210
1167
  * @param configuration The chart configuration
1211
1168
  */
1212
1169
  set chartConfiguration(configuration) {
1213
- if (!configuration) {
1214
- this._chart?.destroy();
1215
- this._chart = null;
1216
- return;
1217
- }
1218
1170
  this._zone.runOutsideAngular(() => {
1219
- if (this._chart) {
1220
- this._chart.destroy();
1171
+ this.removeChart();
1172
+ if (configuration) {
1173
+ this._chart = new Chart(this._elementRef.nativeElement, configuration);
1221
1174
  }
1222
- this._chart = new Chart(this._elementRef.nativeElement, configuration);
1223
1175
  });
1224
1176
  }
1225
1177
  /**
@@ -1238,10 +1190,14 @@ class ChartConfigurationDirective {
1238
1190
  }
1239
1191
  }
1240
1192
  ngOnDestroy() {
1241
- this._chart?.destroy();
1242
- this._chart = null;
1193
+ this.removeChart();
1243
1194
  this._observer?.disconnect();
1244
1195
  }
1196
+ removeChart() {
1197
+ const chart = this._chart || Chart.getChart(this._elementRef.nativeElement);
1198
+ chart?.destroy();
1199
+ this._chart = null;
1200
+ }
1245
1201
  get chart() {
1246
1202
  return this._chart;
1247
1203
  }
@@ -1255,8 +1211,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
1255
1211
  type: Directive,
1256
1212
  args: [{
1257
1213
  selector: '[chartConfiguration]',
1258
- exportAs: 'chart',
1259
- standalone: true
1214
+ exportAs: 'chart'
1260
1215
  }]
1261
1216
  }], propDecorators: { chartConfiguration: [{
1262
1217
  type: Input
@@ -1268,85 +1223,206 @@ const defaultSettings$3 = Object.freeze({
1268
1223
  options: {
1269
1224
  responsive: true,
1270
1225
  maintainAspectRatio: false,
1271
- legend: {
1272
- display: false
1226
+ plugins: {
1227
+ legend: {
1228
+ display: false
1229
+ }
1273
1230
  }
1274
1231
  }
1275
1232
  });
1276
1233
  class ChartComponent {
1277
1234
  constructor() {
1278
- this.data = input({}, ...(ngDevMode ? [{ debugName: "data" }] : []));
1235
+ this.data = input(undefined, ...(ngDevMode ? [{ debugName: "data" }] : []));
1279
1236
  this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1280
1237
  this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1238
+ this.exporting = signal(false, ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1281
1239
  this.configuration = computed(() => ({
1282
1240
  ...merge({}, defaultSettings$3, this.config()),
1283
1241
  data: this.data()
1284
1242
  }), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1285
1243
  }
1286
- exportAsSvg(config = {}) {
1287
- return exportAsSVG(this.configuration(), {
1244
+ async exportAsSvg(config = {}) {
1245
+ this.exporting.set(true);
1246
+ await exportAsSVG(this.configuration(), {
1288
1247
  width: 600,
1289
1248
  height: 400,
1290
1249
  fileName: 'chart.svg',
1291
1250
  ...config
1292
1251
  });
1252
+ this.exporting.set(false);
1293
1253
  }
1294
1254
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1295
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ChartComponent, isStandalone: true, selector: "he-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["chart"], ngImport: i0, template: "<div class=\"is-relative h-100 | chart-container\" #container>\n @if (showExportButton()) {\n <a class=\"is-absolute | download\" (click)=\"exportAsSvg()\" ngbTooltip=\"Download Chart (SVG)\" placement=\"top\">\n <he-svg-icon name=\"download\" />\n </a>\n }\n\n <ng-content />\n\n <canvas [chartConfiguration]=\"configuration()\" [chartContainer]=\"container\"></canvas>\n</div>\n", styles: [":host{display:block;height:100%;overflow:visible}.chart-container{min-height:50px}.download{top:-12px;right:-10px}\n"], dependencies: [{ kind: "directive", type: ChartConfigurationDirective, selector: "[chartConfiguration]", inputs: ["chartConfiguration", "chartContainer"], exportAs: ["chart"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1255
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ChartComponent, isStandalone: true, selector: "he-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["chart"], ngImport: i0, template: "<div class=\"is-relative h-100 | chart-container\" #container>\n @if (showExportButton()) {\n <a\n class=\"is-absolute | download\"\n (click)=\"!exporting() && exportAsSvg()\"\n [ngbTooltip]=\"exporting() ? null : 'Download Chart (SVG)'\"\n placement=\"top\">\n @if (exporting()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else {\n <he-svg-icon name=\"download\" />\n }\n </a>\n }\n\n <ng-content />\n\n <canvas [chartConfiguration]=\"configuration()\" [chartContainer]=\"container\"></canvas>\n</div>\n", styles: [":host{display:block;height:100%;overflow:visible}.chart-container{min-height:50px}.download{top:-12px;right:-10px}\n"], dependencies: [{ kind: "directive", type: ChartConfigurationDirective, selector: "[chartConfiguration]", inputs: ["chartConfiguration", "chartContainer"], exportAs: ["chart"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1296
1256
  }
1297
1257
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartComponent, decorators: [{
1298
1258
  type: Component$1,
1299
- args: [{ selector: 'he-chart', exportAs: 'chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartConfigurationDirective, HESvgIconComponent, NgbTooltip], template: "<div class=\"is-relative h-100 | chart-container\" #container>\n @if (showExportButton()) {\n <a class=\"is-absolute | download\" (click)=\"exportAsSvg()\" ngbTooltip=\"Download Chart (SVG)\" placement=\"top\">\n <he-svg-icon name=\"download\" />\n </a>\n }\n\n <ng-content />\n\n <canvas [chartConfiguration]=\"configuration()\" [chartContainer]=\"container\"></canvas>\n</div>\n", styles: [":host{display:block;height:100%;overflow:visible}.chart-container{min-height:50px}.download{top:-12px;right:-10px}\n"] }]
1259
+ args: [{ selector: 'he-chart', exportAs: 'chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartConfigurationDirective, HESvgIconComponent, NgbTooltip], template: "<div class=\"is-relative h-100 | chart-container\" #container>\n @if (showExportButton()) {\n <a\n class=\"is-absolute | download\"\n (click)=\"!exporting() && exportAsSvg()\"\n [ngbTooltip]=\"exporting() ? null : 'Download Chart (SVG)'\"\n placement=\"top\">\n @if (exporting()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else {\n <he-svg-icon name=\"download\" />\n }\n </a>\n }\n\n <ng-content />\n\n <canvas [chartConfiguration]=\"configuration()\" [chartContainer]=\"container\"></canvas>\n</div>\n", styles: [":host{display:block;height:100%;overflow:visible}.chart-container{min-height:50px}.download{top:-12px;right:-10px}\n"] }]
1300
1260
  }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showExportButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButton", required: false }] }] } });
1301
1261
 
1262
+ var Breakpoint;
1263
+ (function (Breakpoint) {
1264
+ Breakpoint["tablet"] = "tablet";
1265
+ Breakpoint["desktop"] = "desktop";
1266
+ Breakpoint["widescreen"] = "widescreen";
1267
+ Breakpoint["fullhd"] = "fullhd";
1268
+ })(Breakpoint || (Breakpoint = {}));
1269
+ const beakpointWidths = {
1270
+ [Breakpoint.tablet]: 768,
1271
+ [Breakpoint.desktop]: 1024,
1272
+ [Breakpoint.widescreen]: 1216,
1273
+ [Breakpoint.fullhd]: 1408
1274
+ };
1275
+ const toSize = (size, dir) => `(${dir}-width: ${dir === 'max' ? size - 1 : size}px)`;
1276
+ const toBreakpoint = ({ min, max }) => [min ? toSize(beakpointWidths[min], 'min') : '', max ? toSize(beakpointWidths[max], 'max') : '']
1277
+ .filter(Boolean)
1278
+ .join(' and ');
1279
+ class ResponsiveService {
1280
+ constructor() {
1281
+ this.breakPointObserver = inject(BreakpointObserver);
1282
+ this.windowWidth$ = fromEvent(window, 'resize').pipe(startWith(window.innerWidth), map(() => window.innerWidth));
1283
+ this.isMobile$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.tablet })).pipe(map(state => state.matches), distinctUntilChanged());
1284
+ this.isTablet$ = this.breakPointObserver
1285
+ .observe(toBreakpoint({ min: Breakpoint.tablet, max: Breakpoint.desktop }))
1286
+ .pipe(map(state => state.matches), distinctUntilChanged());
1287
+ this.isDesktop$ = this.breakPointObserver
1288
+ .observe(toBreakpoint({ min: Breakpoint.desktop, max: Breakpoint.widescreen }))
1289
+ .pipe(map(state => state.matches), distinctUntilChanged());
1290
+ this.isWidescreen$ = this.breakPointObserver
1291
+ .observe(toBreakpoint({ min: Breakpoint.widescreen, max: Breakpoint.fullhd }))
1292
+ .pipe(map(state => state.matches), distinctUntilChanged());
1293
+ this.isFullHd$ = this.breakPointObserver.observe(toBreakpoint({ min: Breakpoint.fullhd })).pipe(map(state => state.matches), distinctUntilChanged());
1294
+ this.isTouch$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.desktop })).pipe(map(state => state.matches), distinctUntilChanged());
1295
+ /**
1296
+ * Resolution for 1080p (or Full HD) on a normal screen, although bulma defines it differently.
1297
+ */
1298
+ this.is1080p$ = this.breakPointObserver.observe(toSize(1920, 'min')).pipe(map(state => state.matches), distinctUntilChanged());
1299
+ this.isRetinaDisplay = () => {
1300
+ if (window.matchMedia) {
1301
+ const mq = window.matchMedia([
1302
+ 'min--moz-device-pixel-ratio: 1.3',
1303
+ '-o-min-device-pixel-ratio: 2.6/2',
1304
+ '-webkit-min-device-pixel-ratio: 1.3',
1305
+ 'min-device-pixel-ratio: 1.3',
1306
+ 'min-resolution: 1.3dppx'
1307
+ ]
1308
+ .map(v => `only screen and (${v})`)
1309
+ .join(', '));
1310
+ return mq?.matches || window.devicePixelRatio > 1;
1311
+ }
1312
+ return false;
1313
+ };
1314
+ this.isMobile = toSignal(this.isMobile$);
1315
+ this.isTablet = toSignal(this.isTablet$);
1316
+ this.isDesktop = toSignal(this.isDesktop$);
1317
+ this.isWidescreen = toSignal(this.isWidescreen$);
1318
+ this.isFullHd = toSignal(this.isFullHd$);
1319
+ this.isTouch = toSignal(this.isTouch$);
1320
+ this.is1080p = toSignal(this.is1080p$);
1321
+ this.resolutionName = computed(() => this.isMobile()
1322
+ ? 'mobile'
1323
+ : this.isTablet()
1324
+ ? 'tablet'
1325
+ : this.isDesktop()
1326
+ ? 'desktop'
1327
+ : this.isWidescreen()
1328
+ ? 'widescreen'
1329
+ : 'fullhd', ...(ngDevMode ? [{ debugName: "resolutionName" }] : []));
1330
+ this.resolutionName$ = toObservable(this.resolutionName);
1331
+ }
1332
+ isAboveBreakpoint$(breakpoint) {
1333
+ return typeof breakpoint === 'number'
1334
+ ? this.windowWidth$.pipe(map(width => width >= breakpoint))
1335
+ : breakpoint === 'none'
1336
+ ? of(false)
1337
+ : this._isAboveBreakpointName$(breakpoint);
1338
+ }
1339
+ _isAboveBreakpointName$(breakpoint) {
1340
+ return this.resolutionName$.pipe(map(resolutionName => {
1341
+ const width = beakpointWidths[resolutionName];
1342
+ const overlapBreakpointWidth = beakpointWidths[breakpoint];
1343
+ return width >= overlapBreakpointWidth;
1344
+ }));
1345
+ }
1346
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1347
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, providedIn: 'root' }); }
1348
+ }
1349
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, decorators: [{
1350
+ type: Injectable,
1351
+ args: [{
1352
+ providedIn: 'root'
1353
+ }]
1354
+ }] });
1355
+
1356
+ class BarChartLegendComponent {
1357
+ constructor() {
1358
+ this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1359
+ }
1360
+ trackByItem(item) {
1361
+ return Object.values(item).join('-');
1362
+ }
1363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartLegendComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1364
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: BarChartLegendComponent, isStandalone: true, selector: "he-bar-chart-legend", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"is-hidden-tablet is-flex is-flex-direction-column is-align-items-flex-start is-gap-4 is-py-1 is-px-2 is-mt-3 is-radius-3 w-100 | breakdown-legend\">\n @for (value of data(); track trackByItem(value)) {\n @if (value.includedItems?.length) {\n <span class=\"has-text-secondary has-text-weight-bold is-size-7\">\n {{ value.includedItems.length }} others grouped together\n </span>\n }\n\n <div class=\"is-flex is-align-items-center is-gap-4 w-100\">\n <div class=\"breakdown-legend--color\" [style.backgroundColor]=\"value.backgroundColor || value.color\"></div>\n\n @if (value.includedItems?.length) {\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n @for (subValue of value.includedItems; track trackByItem(subValue)) {\n <span class=\"is-size-7\">{{ subValue.label }}</span>\n }\n </div>\n } @else {\n <span class=\"is-size-7\">{{ value.label }}</span>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1365
+ }
1366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartLegendComponent, decorators: [{
1367
+ type: Component$1,
1368
+ args: [{ selector: 'he-bar-chart-legend', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"is-hidden-tablet is-flex is-flex-direction-column is-align-items-flex-start is-gap-4 is-py-1 is-px-2 is-mt-3 is-radius-3 w-100 | breakdown-legend\">\n @for (value of data(); track trackByItem(value)) {\n @if (value.includedItems?.length) {\n <span class=\"has-text-secondary has-text-weight-bold is-size-7\">\n {{ value.includedItems.length }} others grouped together\n </span>\n }\n\n <div class=\"is-flex is-align-items-center is-gap-4 w-100\">\n <div class=\"breakdown-legend--color\" [style.backgroundColor]=\"value.backgroundColor || value.color\"></div>\n\n @if (value.includedItems?.length) {\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n @for (subValue of value.includedItems; track trackByItem(subValue)) {\n <span class=\"is-size-7\">{{ subValue.label }}</span>\n }\n </div>\n } @else {\n <span class=\"is-size-7\">{{ value.label }}</span>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"] }]
1369
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
1370
+
1371
+ const grey = '#4a4a4a';
1302
1372
  const defaultSettings$2 = Object.freeze({
1303
- type: 'horizontalBar',
1373
+ type: 'bar',
1304
1374
  options: {
1305
1375
  animation: {
1306
1376
  duration: 0
1307
1377
  },
1308
- tooltips: {
1309
- enabled: false
1378
+ plugins: {
1379
+ legend: {
1380
+ align: 'start'
1381
+ },
1382
+ tooltip: {
1383
+ enabled: false
1384
+ }
1310
1385
  },
1311
1386
  scales: {
1312
- xAxes: [
1313
- {
1387
+ x: {
1388
+ display: true,
1389
+ min: 0,
1390
+ title: {
1314
1391
  display: false,
1315
- ticks: {
1316
- min: 0
1317
- },
1318
- scaleLabel: {
1319
- display: true,
1320
- fontSize: 14,
1321
- fontColor: '#4a4a4a'
1322
- },
1323
- gridLines: {
1324
- drawOnChartArea: false
1392
+ color: grey,
1393
+ font: {
1394
+ size: 14
1325
1395
  }
1326
1396
  }
1327
- ],
1328
- yAxes: [
1329
- {
1397
+ },
1398
+ y: {
1399
+ display: true,
1400
+ position: 'left',
1401
+ border: {
1402
+ display: true
1403
+ },
1404
+ grid: {
1330
1405
  display: true,
1331
- position: 'left',
1332
- gridLines: {
1333
- display: true,
1334
- drawOnChartArea: false,
1335
- drawTicks: true,
1336
- drawBorder: true,
1337
- tickMarkLength: 8,
1338
- offsetGridLines: false
1406
+ drawOnChartArea: true,
1407
+ drawTicks: true,
1408
+ tickLength: 8,
1409
+ offset: false
1410
+ },
1411
+ ticks: {
1412
+ color: grey,
1413
+ padding: 4,
1414
+ crossAlign: 'center',
1415
+ font: {
1416
+ family: 'Lato',
1417
+ size: 12,
1418
+ weight: 400
1339
1419
  },
1340
- ticks: {
1341
- fontColor: '#4a4a4a',
1342
- fontFamily: 'Lato',
1343
- fontSize: 12,
1344
- fontStyle: '400',
1345
- padding: 4,
1346
- crossAlign: 'center'
1420
+ callback: function (value) {
1421
+ const label = this.getLabelForValue(value);
1422
+ return ellipsis$1(label, 50);
1347
1423
  }
1348
1424
  }
1349
- ]
1425
+ }
1350
1426
  }
1351
1427
  }
1352
1428
  });
@@ -1357,43 +1433,93 @@ const defaultDatasets = {
1357
1433
  };
1358
1434
  class BarChartComponent {
1359
1435
  constructor() {
1360
- this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1436
+ this.responsiveService = inject(ResponsiveService);
1437
+ /**
1438
+ * X-axis label.
1439
+ */
1440
+ this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
1441
+ /**
1442
+ * Maximum value of the chart. If not supplied, the maximum is the highest value from the datasets.
1443
+ */
1361
1444
  this.max = input(...(ngDevMode ? [undefined, { debugName: "max" }] : []));
1362
1445
  this.datasets = input([], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
1446
+ this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1447
+ /**
1448
+ * When `datasets` is not provided, a single dataset is used from the `data` parameter, and this label is used.
1449
+ */
1450
+ this.datasetLabel = input('', ...(ngDevMode ? [{ debugName: "datasetLabel" }] : []));
1451
+ /**
1452
+ * If `data` is provided, the `labels` can be read from them. Otherwise use this to provide custom labels.
1453
+ */
1363
1454
  this.labels = input([], ...(ngDevMode ? [{ debugName: "labels" }] : []));
1455
+ /**
1456
+ * Override chart default configuration.
1457
+ */
1364
1458
  this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1459
+ /**
1460
+ * Show default button for export, located on the top-right corner of the chart.
1461
+ */
1365
1462
  this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1463
+ /**
1464
+ * If set to `false`, chart will show `0` instead if the value is negative.
1465
+ */
1466
+ this.showNegativeValues = input(true, ...(ngDevMode ? [{ debugName: "showNegativeValues" }] : []));
1467
+ /**
1468
+ * Maximum values to display on the chart.
1469
+ * All values not dislayed will be grouped together into a "summed" value.
1470
+ * Default is `20`.
1471
+ */
1472
+ this.maximumValues = input(20, ...(ngDevMode ? [{ debugName: "maximumValues" }] : []));
1473
+ this.hasNegativeContributions = computed(() => this.data()?.some(({ count }) => count < 0), ...(ngDevMode ? [{ debugName: "hasNegativeContributions" }] : []));
1366
1474
  this.chart = viewChild.required(ChartComponent);
1475
+ this.exporting = computed(() => this.chart()?.exporting(), ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1367
1476
  this.defaultConfig = computed(() => ({
1368
1477
  options: {
1369
- legend: {
1370
- align: 'start'
1371
- },
1372
1478
  scales: {
1373
- xAxes: [
1374
- {
1375
- display: true,
1376
- ticks: {
1377
- ...(this.max() ? { max: this.max() } : {})
1378
- }
1479
+ x: {
1480
+ display: !this.responsiveService.isMobile(),
1481
+ ...(this.max() ? { max: this.max() } : {}),
1482
+ title: {
1483
+ display: !!this.title(),
1484
+ text: this.title()
1379
1485
  }
1380
- ]
1486
+ }
1381
1487
  }
1382
1488
  }
1383
1489
  }), ...(ngDevMode ? [{ debugName: "defaultConfig" }] : []));
1490
+ this.maximumData = computed(() => {
1491
+ const data = this.data();
1492
+ const includedData = data.slice(0, this.maximumValues());
1493
+ const excludedData = data.slice(this.maximumValues());
1494
+ return [
1495
+ ...includedData,
1496
+ excludedData.length ? {
1497
+ label: `${excludedData.length} others`,
1498
+ count: sum(excludedData.map(({ count }) => count)),
1499
+ backgroundColor: excludedData[0].backgroundColor,
1500
+ borderColor: excludedData[0].borderColor,
1501
+ color: excludedData[0].color,
1502
+ includedItems: excludedData
1503
+ } : []
1504
+ ].flat();
1505
+ }, ...(ngDevMode ? [{ debugName: "maximumData" }] : []));
1384
1506
  this.defaultDatasets = computed(() => this.datasets()?.length
1385
- ? this.datasets()
1507
+ ? this.datasets().map(dataset => ({
1508
+ ...defaultDatasets,
1509
+ ...dataset
1510
+ }))
1386
1511
  : [
1387
1512
  {
1388
- defaultDatasets,
1389
- backgroundColor: this.data().map(({ backgroundColor, color }) => backgroundColor || color),
1390
- borderColor: this.data().map(({ borderColor, color }) => borderColor || color),
1391
- data: this.data().map(({ count }) => count)
1513
+ ...defaultDatasets,
1514
+ backgroundColor: this.maximumData().map(({ backgroundColor, color }) => backgroundColor || color),
1515
+ borderColor: this.maximumData().map(({ borderColor, color }) => borderColor || color),
1516
+ data: this.maximumData().map(({ count }) => toPrecision(this.showNegativeValues() ? count : Math.max(0, count))),
1517
+ label: this.datasetLabel()
1392
1518
  }
1393
1519
  ], ...(ngDevMode ? [{ debugName: "defaultDatasets" }] : []));
1394
1520
  this.dataConfig = computed(() => ({
1395
1521
  datasets: this.defaultDatasets(),
1396
- labels: this.labels().length ? this.labels() : this.data().map(({ label }) => label)
1522
+ labels: this.labels().length ? this.labels() : this.maximumData().map(({ label }) => label)
1397
1523
  }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1398
1524
  this.configuration = computed(() => merge({}, defaultSettings$2, this.defaultConfig(), this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1399
1525
  }
@@ -1401,12 +1527,12 @@ class BarChartComponent {
1401
1527
  return this.chart().exportAsSvg(config);
1402
1528
  }
1403
1529
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1404
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.13", type: BarChartComponent, isStandalone: true, selector: "he-bar-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, datasets: { classPropertyName: "datasets", publicName: "datasets", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chart", first: true, predicate: ChartComponent, descendants: true, isSignal: true }], exportAs: ["barChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\">\n <ng-content />\n</he-chart>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1530
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: BarChartComponent, isStandalone: true, selector: "he-bar-chart", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, datasets: { classPropertyName: "datasets", publicName: "datasets", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, datasetLabel: { classPropertyName: "datasetLabel", publicName: "datasetLabel", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null }, showNegativeValues: { classPropertyName: "showNegativeValues", publicName: "showNegativeValues", isSignal: true, isRequired: false, transformFunction: null }, maximumValues: { classPropertyName: "maximumValues", publicName: "maximumValues", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chart", first: true, predicate: ChartComponent, descendants: true, isSignal: true }], exportAs: ["barChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\">\n <ng-content />\n</he-chart>\n\n@if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n}\n\n<he-bar-chart-legend [data]=\"maximumData()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }, { kind: "component", type: BarChartLegendComponent, selector: "he-bar-chart-legend", inputs: ["data"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1405
1531
  }
1406
1532
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartComponent, decorators: [{
1407
1533
  type: Component$1,
1408
- args: [{ selector: 'he-bar-chart', exportAs: 'barChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\">\n <ng-content />\n</he-chart>\n", styles: [":host{display:block}\n"] }]
1409
- }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], datasets: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasets", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showExportButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButton", required: false }] }], chart: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ChartComponent), { isSignal: true }] }] } });
1534
+ args: [{ selector: 'he-bar-chart', exportAs: 'barChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent, BarChartLegendComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\">\n <ng-content />\n</he-chart>\n\n@if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n}\n\n<he-bar-chart-legend [data]=\"maximumData()\" />\n", styles: [":host{display:block}\n"] }]
1535
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], datasets: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasets", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], datasetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasetLabel", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showExportButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButton", required: false }] }], showNegativeValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNegativeValues", required: false }] }], maximumValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "maximumValues", required: false }] }], chart: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ChartComponent), { isSignal: true }] }] } });
1410
1536
 
1411
1537
  const parsePrecision = (value, precision) => toPrecision(parseFloat(`${value}`), parseInt(`${precision}`, 10));
1412
1538
  const transform = (value, precision = 3, enableComma = true) => typeof value !== 'boolean' && !isUndefined(value) && isNumber(value)
@@ -1422,8 +1548,7 @@ class PrecisionPipe {
1422
1548
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: PrecisionPipe, decorators: [{
1423
1549
  type: Pipe,
1424
1550
  args: [{
1425
- name: 'precision',
1426
- standalone: true
1551
+ name: 'precision'
1427
1552
  }]
1428
1553
  }] });
1429
1554
 
@@ -1437,27 +1562,27 @@ const defaultSettings$1 = Object.freeze({
1437
1562
  options: {
1438
1563
  events: [],
1439
1564
  responsive: true,
1440
- tooltips: {
1441
- enabled: false
1442
- },
1443
- legend: {
1444
- display: false,
1445
- align: 'center'
1565
+ plugins: {
1566
+ tooltip: {
1567
+ enabled: false
1568
+ },
1569
+ legend: {
1570
+ display: false,
1571
+ align: 'center'
1572
+ }
1446
1573
  },
1447
1574
  scales: {
1448
- yAxes: [
1449
- {
1450
- display: true,
1451
- position: 'left',
1452
- gridLines: {
1453
- display: true
1454
- },
1455
- ticks: {
1456
- beginAtZero: true,
1457
- crossAlign: 'center'
1458
- }
1575
+ y: {
1576
+ display: true,
1577
+ position: 'left',
1578
+ grid: {
1579
+ display: true
1580
+ },
1581
+ beginAtZero: true,
1582
+ ticks: {
1583
+ crossAlign: 'center'
1459
1584
  }
1460
- ]
1585
+ }
1461
1586
  }
1462
1587
  }
1463
1588
  });
@@ -1541,41 +1666,40 @@ class DistributionChartComponent {
1541
1666
  this.defaultConfig = computed(() => ({
1542
1667
  options: {
1543
1668
  scales: {
1544
- xAxes: [
1545
- {
1669
+ x: {
1670
+ display: true,
1671
+ grid: {
1672
+ offset: true
1673
+ },
1674
+ min: 0,
1675
+ ticks: {
1676
+ callback: (label) => label
1677
+ .split(joinXLabel)
1678
+ .map(parseFloat)
1679
+ .map(v => transform(v, 3, true))
1680
+ // .map(v => v.toExponential())
1681
+ .join('-')
1682
+ },
1683
+ title: {
1546
1684
  display: true,
1547
- gridLines: {
1548
- offsetGridLines: true
1549
- },
1550
- ticks: {
1551
- min: 0,
1552
- userCallback: (label) => label
1553
- .split(joinXLabel)
1554
- .map(parseFloat)
1555
- .map(v => transform(v, 3, true))
1556
- // .map(v => v.toExponential())
1557
- .join('-')
1558
- },
1559
- scaleLabel: {
1560
- display: true,
1561
- labelString: this.label()
1562
- }
1685
+ text: this.label()
1563
1686
  }
1564
- ],
1565
- yAxes: [
1566
- {
1567
- ticks: {
1568
- fontColor: '#4A4A4A',
1569
- fontFamily: 'Lato',
1570
- fontSize: 10,
1571
- fontStyle: '400'
1687
+ },
1688
+ y: {
1689
+ ticks: {
1690
+ font: {
1691
+ family: 'Lato',
1692
+ size: 10,
1693
+ style: 'normal',
1694
+ weight: 400
1572
1695
  },
1573
- scaleLabel: {
1574
- display: true,
1575
- labelString: 'Frequency of values'
1576
- }
1696
+ color: '#4A4A4A'
1697
+ },
1698
+ title: {
1699
+ display: true,
1700
+ text: 'Frequency of values'
1577
1701
  }
1578
- ]
1702
+ }
1579
1703
  }
1580
1704
  }
1581
1705
  }), ...(ngDevMode ? [{ debugName: "defaultConfig" }] : []));
@@ -1589,8 +1713,6 @@ class DistributionChartComponent {
1589
1713
  backgroundColor: opaqueColor(colors.lightBlue),
1590
1714
  borderColor: colors.lightBlue,
1591
1715
  borderWidth: 1,
1592
- fill: true,
1593
- pointRadius: 0,
1594
1716
  type: 'bar'
1595
1717
  },
1596
1718
  {
@@ -1604,7 +1726,7 @@ class DistributionChartComponent {
1604
1726
  type: 'line'
1605
1727
  }
1606
1728
  ]
1607
- : null,
1729
+ : [],
1608
1730
  this.singlePoint()?.length
1609
1731
  ? {
1610
1732
  label: 'Value',
@@ -1617,10 +1739,8 @@ class DistributionChartComponent {
1617
1739
  type: 'line',
1618
1740
  tension: 0
1619
1741
  }
1620
- : null
1621
- ]
1622
- .filter(Boolean)
1623
- .flat(),
1742
+ : []
1743
+ ].flat(),
1624
1744
  labels: this.groupedData().labels
1625
1745
  }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1626
1746
  this.configuration = computed(() => merge({}, defaultSettings$1, this.defaultConfig(), this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
@@ -1633,42 +1753,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
1633
1753
  args: [{ selector: 'he-distribution-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" />\n", styles: [":host{display:block}\n"] }]
1634
1754
  }], propDecorators: { distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], nbBins: [{ type: i0.Input, args: [{ isSignal: true, alias: "nbBins", required: false }] }], maxPercentile: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPercentile", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
1635
1755
 
1636
- const defaultSettings = {
1756
+ const defaultSettings = Object.freeze({
1637
1757
  type: 'line',
1638
1758
  options: {
1639
1759
  scales: {
1640
- xAxes: [
1641
- {
1642
- type: 'time',
1643
- time: {
1644
- unit: 'day'
1760
+ x: {
1761
+ type: 'time',
1762
+ time: {
1763
+ unit: 'day'
1764
+ }
1765
+ }
1766
+ }
1767
+ }
1768
+ });
1769
+ class LineChartComponent {
1770
+ constructor() {
1771
+ this.datasets = input([], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
1772
+ this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1773
+ this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1774
+ this.chart = viewChild.required(ChartComponent);
1775
+ this.exporting = computed(() => this.chart()?.exporting(), ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1776
+ this.dataConfig = computed(() => ({
1777
+ datasets: this.datasets()
1778
+ }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1779
+ this.configuration = computed(() => merge({}, defaultSettings, this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1780
+ }
1781
+ exportAsSvg(config = {}) {
1782
+ return this.chart().exportAsSvg(config);
1783
+ }
1784
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1785
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.13", type: LineChartComponent, isStandalone: true, selector: "he-line-chart", inputs: { datasets: { classPropertyName: "datasets", publicName: "datasets", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chart", first: true, predicate: ChartComponent, descendants: true, isSignal: true }], exportAs: ["lineChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1786
+ }
1787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, decorators: [{
1788
+ type: Component$1,
1789
+ args: [{ selector: 'he-line-chart', exportAs: 'lineChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\" />\n", styles: [":host{display:block}\n"] }]
1790
+ }], propDecorators: { datasets: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasets", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showExportButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButton", required: false }] }], chart: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ChartComponent), { isSignal: true }] }] } });
1791
+
1792
+ const defaultConfig = Object.freeze({
1793
+ options: {
1794
+ indexAxis: 'y',
1795
+ scales: {
1796
+ x: {
1797
+ grid: {
1798
+ drawOnChartArea: false
1799
+ },
1800
+ ticks: {
1801
+ callback: value => toPrecision(Number(value), 3)
1802
+ }
1803
+ },
1804
+ y: {
1805
+ grid: {
1806
+ drawOnChartArea: false
1807
+ },
1808
+ ticks: {
1809
+ crossAlign: 'near'
1810
+ }
1811
+ }
1812
+ }
1813
+ }
1814
+ });
1815
+ const defaultTooltipFn = ({ label, count, includedItems }) => includedItems.length ? includedItems.map(item => defaultTooltipFn(item)).join('</br>') : `${label}: ${count}`;
1816
+ class HorizontalBarChartComponent extends BarChartComponent {
1817
+ constructor() {
1818
+ super(...arguments);
1819
+ this.tooltipFn = input(defaultTooltipFn, ...(ngDevMode ? [{ debugName: "tooltipFn" }] : []));
1820
+ this.afterBarDrawSettings = input(...(ngDevMode ? [undefined, { debugName: "afterBarDrawSettings" }] : []));
1821
+ this.tooltip = viewChild.required('tooltip');
1822
+ this.horizontalConfiguration = computed(() => ({
1823
+ ...merge(this.configuration(), defaultConfig, {
1824
+ options: {
1825
+ onClick: (event, activeElements) => {
1826
+ const index = activeElements?.[0]?.index;
1827
+ !isUndefined(index) && this.showTooltip(index, event.x, event.y);
1828
+ },
1829
+ scales: {
1830
+ y: {
1831
+ display: !this.responsiveService.isMobile()
1832
+ }
1645
1833
  }
1646
1834
  }
1835
+ }),
1836
+ plugins: [
1837
+ lollipopChartPlugin(),
1838
+ backgroundHoverPlugin({ threshold: 5 }),
1839
+ afterBarDrawPlugin(this.afterBarDrawSettings()),
1840
+ ...(this.configuration().plugins ?? [])
1647
1841
  ]
1648
- }
1649
- }
1650
- };
1651
- class LineChartComponent {
1652
- constructor() {
1653
- this.datasets = input([], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
1654
- this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1655
- this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1656
- this.chart = viewChild.required(ChartComponent);
1657
- this.dataConfig = computed(() => ({
1658
- datasets: this.datasets()
1659
- }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1660
- this.configuration = computed(() => merge({}, defaultSettings, this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1842
+ }), ...(ngDevMode ? [{ debugName: "horizontalConfiguration" }] : []));
1843
+ this.tooltipX = signal(0, ...(ngDevMode ? [{ debugName: "tooltipX" }] : []));
1844
+ this.tooltipY = signal(0, ...(ngDevMode ? [{ debugName: "tooltipY" }] : []));
1661
1845
  }
1662
- exportAsSvg(config = {}) {
1663
- return this.chart().exportAsSvg(config);
1846
+ showTooltip(index, x, y) {
1847
+ this.tooltipX.set(x);
1848
+ this.tooltipY.set(y);
1849
+ const data = this.maximumData()[index];
1850
+ const text = this.tooltipFn()(data || {}, index);
1851
+ text && setTimeout(() => this.tooltip().open({ data: text }));
1664
1852
  }
1665
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1666
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.13", type: LineChartComponent, isStandalone: true, selector: "he-line-chart", inputs: { datasets: { classPropertyName: "datasets", publicName: "datasets", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showExportButton: { classPropertyName: "showExportButton", publicName: "showExportButton", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "chart", first: true, predicate: ChartComponent, descendants: true, isSignal: true }], exportAs: ["lineChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1853
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HorizontalBarChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1854
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: HorizontalBarChartComponent, isStandalone: true, selector: "he-horizontal-bar-chart", inputs: { tooltipFn: { classPropertyName: "tooltipFn", publicName: "tooltipFn", isSignal: true, isRequired: false, transformFunction: null }, afterBarDrawSettings: { classPropertyName: "afterBarDrawSettings", publicName: "afterBarDrawSettings", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "tooltip", first: true, predicate: ["tooltip"], descendants: true, isSignal: true }], exportAs: ["horizontalBarChart"], usesInheritance: true, ngImport: i0, template: "<div class=\"chart-area-border\">\n <he-chart\n class=\"is-relative h-100\"\n [data]=\"dataConfig()\"\n [config]=\"horizontalConfiguration()\"\n [showExportButton]=\"showExportButton()\">\n <div\n class=\"is-invisible is-absolute | shadow-tooltip\"\n [style.left.px]=\"tooltipX()\"\n [style.top.px]=\"tooltipY()\"\n [ngbTooltip]=\"rawHtmlContent\"\n triggers=\"manual\"\n autoClose=\"outside\"\n placement=\"bottom\"\n #tooltip=\"ngbTooltip\"></div>\n\n <ng-template #rawHtmlContent let-rawString=\"data\">\n <div [innerHTML]=\"rawString\"></div>\n </ng-template>\n\n <ng-content />\n </he-chart>\n</div>\n\n@if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n}\n\n<he-bar-chart-legend [data]=\"maximumData()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: BarChartLegendComponent, selector: "he-bar-chart-legend", inputs: ["data"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1667
1855
  }
1668
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, decorators: [{
1856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HorizontalBarChartComponent, decorators: [{
1669
1857
  type: Component$1,
1670
- args: [{ selector: 'he-line-chart', exportAs: 'lineChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" [showExportButton]=\"showExportButton()\" />\n", styles: [":host{display:block}\n"] }]
1671
- }], propDecorators: { datasets: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasets", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showExportButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButton", required: false }] }], chart: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ChartComponent), { isSignal: true }] }] } });
1858
+ args: [{ selector: 'he-horizontal-bar-chart', exportAs: 'horizontalBarChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent, NgbTooltip, BarChartLegendComponent], template: "<div class=\"chart-area-border\">\n <he-chart\n class=\"is-relative h-100\"\n [data]=\"dataConfig()\"\n [config]=\"horizontalConfiguration()\"\n [showExportButton]=\"showExportButton()\">\n <div\n class=\"is-invisible is-absolute | shadow-tooltip\"\n [style.left.px]=\"tooltipX()\"\n [style.top.px]=\"tooltipY()\"\n [ngbTooltip]=\"rawHtmlContent\"\n triggers=\"manual\"\n autoClose=\"outside\"\n placement=\"bottom\"\n #tooltip=\"ngbTooltip\"></div>\n\n <ng-template #rawHtmlContent let-rawString=\"data\">\n <div [innerHTML]=\"rawString\"></div>\n </ng-template>\n\n <ng-content />\n </he-chart>\n</div>\n\n@if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n}\n\n<he-bar-chart-legend [data]=\"maximumData()\" />\n", styles: [":host{display:block}\n"] }]
1859
+ }], propDecorators: { tooltipFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipFn", required: false }] }], afterBarDrawSettings: [{ type: i0.Input, args: [{ isSignal: true, alias: "afterBarDrawSettings", required: false }] }], tooltip: [{ type: i0.ViewChild, args: ['tooltip', { isSignal: true }] }] } });
1672
1860
 
1673
1861
  const ignoreCompounds = (value) => typeof value !== 'string' ||
1674
1862
  [
@@ -2703,8 +2891,7 @@ class ResizedDirective {
2703
2891
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResizedDirective, decorators: [{
2704
2892
  type: Directive,
2705
2893
  args: [{
2706
- selector: '[resized]',
2707
- standalone: true
2894
+ selector: '[resized]'
2708
2895
  }]
2709
2896
  }], ctorParameters: () => [], propDecorators: { resized: [{ type: i0.Output, args: ["resized"] }] } });
2710
2897
 
@@ -2898,7 +3085,7 @@ class BlankNodeStateNoticeComponent {
2898
3085
  }
2899
3086
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BlankNodeStateNoticeComponent, decorators: [{
2900
3087
  type: Component$1,
2901
- args: [{ selector: 'he-blank-node-state-notice', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "@if (show()) {\n <div class=\"is-flex is-gap-8 is-align-items-center is-size-7 is-italic\">\n <span class=\"notice-data-unchaged\">\u2020 Data uploaded by the user</span>\n <span class=\"divider\"></span>\n <span class=\"notice-data-added\">* Data added by HESTIA</span>\n <span class=\"divider\"></span>\n <span class=\"notice-data-updated\">** Data updated by HESTIA</span>\n @if (showDeleted()) {\n <span class=\"divider\"></span>\n <span class=\"notice-data-deleted\">**** Data deleted by HESTIA</span>\n }\n </div>\n}\n", styles: ["@media screen and (max-width: 767px){:host div{flex-direction:column;align-items:flex-start!important}:host div .divider{display:none}}.divider{width:1px;height:20px;background:#4a4a4a}\n"] }]
3088
+ args: [{ selector: 'he-blank-node-state-notice', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (show()) {\n <div class=\"is-flex is-gap-8 is-align-items-center is-size-7 is-italic\">\n <span class=\"notice-data-unchaged\">\u2020 Data uploaded by the user</span>\n <span class=\"divider\"></span>\n <span class=\"notice-data-added\">* Data added by HESTIA</span>\n <span class=\"divider\"></span>\n <span class=\"notice-data-updated\">** Data updated by HESTIA</span>\n @if (showDeleted()) {\n <span class=\"divider\"></span>\n <span class=\"notice-data-deleted\">**** Data deleted by HESTIA</span>\n }\n </div>\n}\n", styles: ["@media screen and (max-width: 767px){:host div{flex-direction:column;align-items:flex-start!important}:host div .divider{display:none}}.divider{width:1px;height:20px;background:#4a4a4a}\n"] }]
2902
3089
  }], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }], showDeleted: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDeleted", required: false }] }] } });
2903
3090
 
2904
3091
  class BlankNodeValueDeltaComponent {
@@ -3199,100 +3386,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
3199
3386
  }, template: "<aside\n class=\"is-flex is-flex-direction-column is-gap-12 is-overflow-hidden is-py-desktop-3 | menu\"\n [class.sticky]=\"sticky()\">\n <ng-content select=\"[header]\" />\n\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n @for (link of links(); track trackByLink(link)) {\n <ng-container *ngTemplateOutlet=\"linkItem; context: { link, parentLinks: [], level: 1 }\" />\n }\n </div>\n\n <ng-content select=\"[footer]\" />\n</aside>\n\n<ng-template #linkExpandIcon let-link>\n @if (isCollapsible(link)) {\n <he-svg-icon\n [name]=\"link.expanded ? 'chevron-down' : 'chevron-right'\"\n class=\"is-inline-block is-clickable\"\n size=\"20\"\n (click)=\"toggleLink($event, link)\" />\n }\n</ng-template>\n\n<ng-template #linkContent let-link=\"link\" let-level=\"level\">\n @if (level === 1) {\n @if (link.icon) {\n <he-svg-icon [name]=\"link.icon\" size=\"20\" class=\"is-inline-block has-text-secondary\" />\n } @else if (hasPrimaryIcons()) {\n <span class=\"primary-missing-icon\">&nbsp;</span>\n }\n }\n <span class=\"is-flex is-flex-grow-1 is-align-self-center\" [innerHTML]=\"link.title\"></span>\n <ng-container *ngTemplateOutlet=\"linkExpandIcon; context: { $implicit: link }\" />\n</ng-template>\n\n<ng-template #linkItemChildren let-link=\"link\" let-parentLinks=\"parentLinks\" let-level=\"level\">\n @let childParents = concatLinks(link, parentLinks);\n @if (isCollapsible(link)) {\n <div\n class=\"is-flex is-flex-direction-column is-align-items-stretch | he-menu-child-items\"\n [class.is-hidden]=\"!link.expanded\">\n @for (childLink of link.links; track trackByLink(childLink)) {\n <ng-container\n *ngTemplateOutlet=\"linkItem; context: { link: childLink, parentLinks: childParents, level: level + 1 }\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #linkItem let-link=\"link\" let-parentLinks=\"parentLinks\" let-level=\"level\">\n <div\n class=\"is-flex is-align-items-center is-gap-4 | he-menu-item\"\n [attr.data-menu-level]=\"level\"\n (click)=\"toggleLink($event, link)\"\n [class.with-border-color]=\"!!link.borderColor\">\n @if (link.borderColor) {\n <div class=\"he-menu-border\" [style.background-color]=\"link.borderColor\"></div>\n }\n <a\n class=\"is-flex is-flex-grow-1 is-align-self-stretch is-align-items-center is-gap-8 has-text-secondary | he-menu-label\"\n [class.he-menu-item-selectable]=\"!!link?.url\"\n (click)=\"link.url ? close() : null\"\n [routerLink]=\"link.url\"\n [queryParams]=\"link.queryParams\"\n [fragment]=\"link.fragment\"\n routerLinkActive=\"link-active\"\n [routerLinkActiveOptions]=\"linkActiveOptions(link, level)\"\n (isActiveChange)=\"$event && linksActiveChange(link, parentLinks)\">\n <ng-container *ngTemplateOutlet=\"linkContent; context: { link, level }\" />\n </a>\n </div>\n <ng-container *ngTemplateOutlet=\"linkItemChildren; context: { link, parentLinks, level }\" />\n</ng-template>\n", styles: [".navigation-menu{width:100%;display:block}.navigation-menu .menu{font-size:.875rem;line-height:16px;color:#193957;font-weight:400;width:100%!important;max-width:100%!important}@media screen and (min-width: 1024px){.navigation-menu .menu{width:14rem!important;min-width:14rem!important;max-width:14rem!important;border-style:solid;border-color:#ffc000;border-width:1px 0}}.navigation-menu .menu.fixed-top{transform:translate3d(0,6.75rem,0)}.navigation-menu .menu.sticky{position:sticky;top:6.75rem}.navigation-menu a{text-decoration:none!important}.navigation-menu a:focus,.navigation-menu a:active{outline:0!important}.navigation-menu .cursor-default{cursor:default!important}.navigation-menu .primary-missing-icon{height:20px;width:20px;min-width:20px}.navigation-menu .he-menu-item{padding:1px 0}.navigation-menu .he-menu-item .he-menu-label{height:28px;border-radius:3px;padding:4px}.navigation-menu .he-menu-item .he-menu-border{width:8px;height:28px}.navigation-menu .he-menu-item[data-menu-level=\"1\"] span{font-weight:700}.navigation-menu .he-menu-item[data-menu-level=\"1\"]+.he-menu-child-items{padding-left:14px}.navigation-menu .he-menu-item[data-menu-level=\"2\"]{padding-left:14px;border-left:1px solid #ffc000}.navigation-menu .he-menu-item[data-menu-level=\"2\"]+.he-menu-child-items{padding-left:28px}.navigation-menu .he-menu-item-selectable:not(.link-active):hover{background-color:#fefaef}.navigation-menu .he-menu-item.with-border-color .he-menu-label{border-radius:0}.navigation-menu .he-menu-item.with-border-color[data-menu-level=\"1\"]+.he-menu-child-items{padding-left:26px}.navigation-menu .he-menu-child-items{padding-left:14px}.navigation-menu .link-active{background-color:#ffe8a3;color:#193957!important}\n"] }]
3200
3387
  }], propDecorators: { links: [{ type: i0.Input, args: [{ isSignal: true, alias: "links", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], routerLinkMatchOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkMatchOptions", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
3201
3388
 
3202
- var Breakpoint;
3203
- (function (Breakpoint) {
3204
- Breakpoint["tablet"] = "tablet";
3205
- Breakpoint["desktop"] = "desktop";
3206
- Breakpoint["widescreen"] = "widescreen";
3207
- Breakpoint["fullhd"] = "fullhd";
3208
- })(Breakpoint || (Breakpoint = {}));
3209
- const beakpointWidths = {
3210
- [Breakpoint.tablet]: 768,
3211
- [Breakpoint.desktop]: 1024,
3212
- [Breakpoint.widescreen]: 1216,
3213
- [Breakpoint.fullhd]: 1408
3214
- };
3215
- const toSize = (size, dir) => `(${dir}-width: ${dir === 'max' ? size - 1 : size}px)`;
3216
- const toBreakpoint = ({ min, max }) => [min ? toSize(beakpointWidths[min], 'min') : '', max ? toSize(beakpointWidths[max], 'max') : '']
3217
- .filter(Boolean)
3218
- .join(' and ');
3219
- class ResponsiveService {
3220
- constructor() {
3221
- this.breakPointObserver = inject(BreakpointObserver);
3222
- this.windowWidth$ = fromEvent(window, 'resize').pipe(startWith(window.innerWidth), map(() => window.innerWidth));
3223
- this.isMobile$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.tablet })).pipe(map(state => state.matches), distinctUntilChanged());
3224
- this.isTablet$ = this.breakPointObserver
3225
- .observe(toBreakpoint({ min: Breakpoint.tablet, max: Breakpoint.desktop }))
3226
- .pipe(map(state => state.matches), distinctUntilChanged());
3227
- this.isDesktop$ = this.breakPointObserver
3228
- .observe(toBreakpoint({ min: Breakpoint.desktop, max: Breakpoint.widescreen }))
3229
- .pipe(map(state => state.matches), distinctUntilChanged());
3230
- this.isWidescreen$ = this.breakPointObserver
3231
- .observe(toBreakpoint({ min: Breakpoint.widescreen, max: Breakpoint.fullhd }))
3232
- .pipe(map(state => state.matches), distinctUntilChanged());
3233
- this.isFullHd$ = this.breakPointObserver.observe(toBreakpoint({ min: Breakpoint.fullhd })).pipe(map(state => state.matches), distinctUntilChanged());
3234
- this.isTouch$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.desktop })).pipe(map(state => state.matches), distinctUntilChanged());
3235
- /**
3236
- * Resolution for 1080p (or Full HD) on a normal screen, although bulma defines it differently.
3237
- */
3238
- this.is1080p$ = this.breakPointObserver.observe(toSize(1920, 'min')).pipe(map(state => state.matches), distinctUntilChanged());
3239
- this.isRetinaDisplay = () => {
3240
- if (window.matchMedia) {
3241
- const mq = window.matchMedia([
3242
- 'min--moz-device-pixel-ratio: 1.3',
3243
- '-o-min-device-pixel-ratio: 2.6/2',
3244
- '-webkit-min-device-pixel-ratio: 1.3',
3245
- 'min-device-pixel-ratio: 1.3',
3246
- 'min-resolution: 1.3dppx'
3247
- ]
3248
- .map(v => `only screen and (${v})`)
3249
- .join(', '));
3250
- return mq?.matches || window.devicePixelRatio > 1;
3251
- }
3252
- return false;
3253
- };
3254
- this.isMobile = toSignal(this.isMobile$);
3255
- this.isTablet = toSignal(this.isTablet$);
3256
- this.isDesktop = toSignal(this.isDesktop$);
3257
- this.isWidescreen = toSignal(this.isWidescreen$);
3258
- this.isFullHd = toSignal(this.isFullHd$);
3259
- this.isTouch = toSignal(this.isTouch$);
3260
- this.is1080p = toSignal(this.is1080p$);
3261
- this.resolutionName = computed(() => this.isMobile()
3262
- ? 'mobile'
3263
- : this.isTablet()
3264
- ? 'tablet'
3265
- : this.isDesktop()
3266
- ? 'desktop'
3267
- : this.isWidescreen()
3268
- ? 'widescreen'
3269
- : 'fullhd', ...(ngDevMode ? [{ debugName: "resolutionName" }] : []));
3270
- this.resolutionName$ = toObservable(this.resolutionName);
3271
- }
3272
- isAboveBreakpoint$(breakpoint) {
3273
- return typeof breakpoint === 'number'
3274
- ? this.windowWidth$.pipe(map(width => width >= breakpoint))
3275
- : breakpoint === 'none'
3276
- ? of(false)
3277
- : this._isAboveBreakpointName$(breakpoint);
3278
- }
3279
- _isAboveBreakpointName$(breakpoint) {
3280
- return this.resolutionName$.pipe(map(resolutionName => {
3281
- const width = beakpointWidths[resolutionName];
3282
- const overlapBreakpointWidth = beakpointWidths[breakpoint];
3283
- return width >= overlapBreakpointWidth;
3284
- }));
3285
- }
3286
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3287
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, providedIn: 'root' }); }
3288
- }
3289
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, decorators: [{
3290
- type: Injectable,
3291
- args: [{
3292
- providedIn: 'root'
3293
- }]
3294
- }] });
3295
-
3296
3389
  const storageKey$2 = 'he-drawer-container';
3297
3390
  const moveEvent = () => merge$1(fromEvent(window, 'mousemove').pipe(map(event => event.clientX)), fromEvent(window, 'touchmove', { passive: false }).pipe(map(event => event.touches[0].clientX)));
3298
3391
  class DrawerContainerComponent {
@@ -3518,8 +3611,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
3518
3611
  type: Directive,
3519
3612
  args: [{
3520
3613
  selector: '[buttonScroller]',
3521
- exportAs: 'buttonScroller',
3522
- standalone: true
3614
+ exportAs: 'buttonScroller'
3523
3615
  }]
3524
3616
  }], propDecorators: { scrollUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollUnit", required: false }] }] } });
3525
3617
 
@@ -3549,8 +3641,7 @@ class LongPressDirective {
3549
3641
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LongPressDirective, decorators: [{
3550
3642
  type: Directive,
3551
3643
  args: [{
3552
- selector: '[appLongPress]',
3553
- standalone: true
3644
+ selector: '[appLongPress]'
3554
3645
  }]
3555
3646
  }], propDecorators: { longPress: [{ type: i0.Output, args: ["longPress"] }], intervalMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervalMs", required: false }] }], onPressStart: [{
3556
3647
  type: HostListener,
@@ -3590,8 +3681,7 @@ class IsEllipsisActiveDirective {
3590
3681
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsEllipsisActiveDirective, decorators: [{
3591
3682
  type: Directive,
3592
3683
  args: [{
3593
- selector: '[isEllipsisActive]',
3594
- standalone: true
3684
+ selector: '[isEllipsisActive]'
3595
3685
  }]
3596
3686
  }] });
3597
3687
 
@@ -4109,7 +4199,7 @@ class SkeletonTextComponent {
4109
4199
  }
4110
4200
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SkeletonTextComponent, decorators: [{
4111
4201
  type: Component$1,
4112
- args: [{ selector: 'he-skeleton-text', standalone: true, template: "<span>&nbsp;</span>\n", styles: [":host{border-radius:3px;display:block;width:100%;height:inherit;margin-top:4px;margin-bottom:4px;background:#0001;line-height:10px;-webkit-user-select:none;user-select:none;pointer-events:none}span{display:inline-block}:host(.is-animated){position:relative;background:linear-gradient(to right,#0001 8%,#0002 18%,#0001 33%);background-size:800px 104px;animation-duration:1s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}\n"] }]
4202
+ args: [{ selector: 'he-skeleton-text', template: "<span>&nbsp;</span>\n", styles: [":host{border-radius:3px;display:block;width:100%;height:inherit;margin-top:4px;margin-bottom:4px;background:#0001;line-height:10px;-webkit-user-select:none;user-select:none;pointer-events:none}span{display:inline-block}:host(.is-animated){position:relative;background:linear-gradient(to right,#0001 8%,#0002 18%,#0001 33%);background-size:800px 104px;animation-duration:1s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}\n"] }]
4113
4203
  }], propDecorators: { animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], _animated: [{
4114
4204
  type: HostBinding,
4115
4205
  args: ['class.is-animated']
@@ -4148,8 +4238,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
4148
4238
  args: [{
4149
4239
  selector: 'he-social-tags',
4150
4240
  template: '',
4151
- changeDetection: ChangeDetectionStrategy.OnPush,
4152
- standalone: true
4241
+ changeDetection: ChangeDetectionStrategy.OnPush
4153
4242
  }]
4154
4243
  }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], classes: [{
4155
4244
  type: HostBinding,
@@ -4177,7 +4266,7 @@ class ToastComponent {
4177
4266
  }
4178
4267
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ToastComponent, decorators: [{
4179
4268
  type: Component$1,
4180
- args: [{ selector: 'he-toast', standalone: true, template: "<div class=\"mb-3 columns is-centered is-vcentered\">\n @for (toast of toasts; track toast) {\n <div class=\"notification is-{{ toast.color }}\" role=\"alert\">\n <button class=\"delete\" (click)=\"dismiss(toast)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n <strong>\n @switch (toast.color) {\n @case ('danger') {\n @switch (toast.message) {\n @case ('Unauthorized') {\n <span>You are not allowed to perform this action.</span>\n }\n @case ('form-invalid') {\n <span>Please fix all the errors on this page.</span>\n }\n @case ('users-email-already-taken') {\n <span>Email already taken.</span>\n }\n @case ('users-auth-already-taken') {\n <span>Account already connected.</span>\n }\n @default {\n <span>\n @if (toast.showRawMessage) {\n <span>{{ toast.message }}</span>\n }\n <span [class.is-hidden]=\"toast.showRawMessage\">\n An unknown error occurred. Please try again later.\n </span>\n </span>\n }\n }\n }\n @default {\n @if (toast.showRawMessage) {\n <span>{{ toast.message }}</span>\n }\n <span [class.is-hidden]=\"toast.showRawMessage\">An unknown error occurred. Please try again later.</span>\n }\n }\n </strong>\n </div>\n }\n</div>\n", styles: [":host{bottom:0;position:fixed;width:100%;z-index:1000}\n"] }]
4269
+ args: [{ selector: 'he-toast', template: "<div class=\"mb-3 columns is-centered is-vcentered\">\n @for (toast of toasts; track toast) {\n <div class=\"notification is-{{ toast.color }}\" role=\"alert\">\n <button class=\"delete\" (click)=\"dismiss(toast)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n <strong>\n @switch (toast.color) {\n @case ('danger') {\n @switch (toast.message) {\n @case ('Unauthorized') {\n <span>You are not allowed to perform this action.</span>\n }\n @case ('form-invalid') {\n <span>Please fix all the errors on this page.</span>\n }\n @case ('users-email-already-taken') {\n <span>Email already taken.</span>\n }\n @case ('users-auth-already-taken') {\n <span>Account already connected.</span>\n }\n @default {\n <span>\n @if (toast.showRawMessage) {\n <span>{{ toast.message }}</span>\n }\n <span [class.is-hidden]=\"toast.showRawMessage\">\n An unknown error occurred. Please try again later.\n </span>\n </span>\n }\n }\n }\n @default {\n @if (toast.showRawMessage) {\n <span>{{ toast.message }}</span>\n }\n <span [class.is-hidden]=\"toast.showRawMessage\">An unknown error occurred. Please try again later.</span>\n }\n }\n </strong>\n </div>\n }\n</div>\n", styles: [":host{bottom:0;position:fixed;width:100%;z-index:1000}\n"] }]
4181
4270
  }], ctorParameters: () => [] });
4182
4271
 
4183
4272
  /* eslint-disable prefer-spread */
@@ -4198,8 +4287,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
4198
4287
  type: Pipe,
4199
4288
  args: [{
4200
4289
  name: 'applyPure',
4201
- pure: true,
4202
- standalone: true
4290
+ pure: true
4203
4291
  }]
4204
4292
  }] });
4205
4293
 
@@ -4213,8 +4301,7 @@ class CapitalizePipe {
4213
4301
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CapitalizePipe, decorators: [{
4214
4302
  type: Pipe,
4215
4303
  args: [{
4216
- name: 'capitalize',
4217
- standalone: true
4304
+ name: 'capitalize'
4218
4305
  }]
4219
4306
  }] });
4220
4307
 
@@ -4265,8 +4352,7 @@ class ClickOutsideDirective {
4265
4352
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ClickOutsideDirective, decorators: [{
4266
4353
  type: Directive,
4267
4354
  args: [{
4268
- selector: '[clickOutside]',
4269
- standalone: true
4355
+ selector: '[clickOutside]'
4270
4356
  }]
4271
4357
  }], propDecorators: { clickOutsideListenAfter: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickOutsideListenAfter", required: false }] }], clickOutside: [{ type: i0.Output, args: ["clickOutside"] }] } });
4272
4358
 
@@ -4285,8 +4371,7 @@ class CompoundDirective {
4285
4371
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CompoundDirective, decorators: [{
4286
4372
  type: Directive,
4287
4373
  args: [{
4288
- selector: '[appCompound]',
4289
- standalone: true
4374
+ selector: '[appCompound]'
4290
4375
  }]
4291
4376
  }], ctorParameters: () => [], propDecorators: { appCompound: [{ type: i0.Input, args: [{ isSignal: true, alias: "appCompound", required: true }] }], compoundTermType: [{ type: i0.Input, args: [{ isSignal: true, alias: "compoundTermType", required: false }] }] } });
4292
4377
 
@@ -4300,8 +4385,7 @@ class CompoundPipe {
4300
4385
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CompoundPipe, decorators: [{
4301
4386
  type: Pipe,
4302
4387
  args: [{
4303
- name: 'compound',
4304
- standalone: true
4388
+ name: 'compound'
4305
4389
  }]
4306
4390
  }] });
4307
4391
 
@@ -4315,8 +4399,7 @@ class DefaultPipe {
4315
4399
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: DefaultPipe, decorators: [{
4316
4400
  type: Pipe,
4317
4401
  args: [{
4318
- name: 'default',
4319
- standalone: true
4402
+ name: 'default'
4320
4403
  }]
4321
4404
  }] });
4322
4405
 
@@ -4350,8 +4433,7 @@ class DurationPipe {
4350
4433
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: DurationPipe, decorators: [{
4351
4434
  type: Pipe,
4352
4435
  args: [{
4353
- name: 'duration',
4354
- standalone: true
4436
+ name: 'duration'
4355
4437
  }]
4356
4438
  }] });
4357
4439
 
@@ -4365,8 +4447,7 @@ class EllipsisPipe {
4365
4447
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: EllipsisPipe, decorators: [{
4366
4448
  type: Pipe,
4367
4449
  args: [{
4368
- name: 'ellipsis',
4369
- standalone: true
4450
+ name: 'ellipsis'
4370
4451
  }]
4371
4452
  }] });
4372
4453
 
@@ -4380,8 +4461,7 @@ class FileSizePipe {
4380
4461
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: FileSizePipe, decorators: [{
4381
4462
  type: Pipe,
4382
4463
  args: [{
4383
- name: 'fileSize',
4384
- standalone: true
4464
+ name: 'fileSize'
4385
4465
  }]
4386
4466
  }] });
4387
4467
 
@@ -4395,8 +4475,7 @@ class GetPipe {
4395
4475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: GetPipe, decorators: [{
4396
4476
  type: Pipe,
4397
4477
  args: [{
4398
- name: 'get',
4399
- standalone: true
4478
+ name: 'get'
4400
4479
  }]
4401
4480
  }] });
4402
4481
 
@@ -4410,8 +4489,7 @@ class IsArrayPipe {
4410
4489
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsArrayPipe, decorators: [{
4411
4490
  type: Pipe,
4412
4491
  args: [{
4413
- name: 'isArray',
4414
- standalone: true
4492
+ name: 'isArray'
4415
4493
  }]
4416
4494
  }] });
4417
4495
 
@@ -4425,8 +4503,7 @@ class IsObjectPipe {
4425
4503
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsObjectPipe, decorators: [{
4426
4504
  type: Pipe,
4427
4505
  args: [{
4428
- name: 'isObject',
4429
- standalone: true
4506
+ name: 'isObject'
4430
4507
  }]
4431
4508
  }] });
4432
4509
 
@@ -4484,8 +4561,7 @@ class KeyToLabelPipe {
4484
4561
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: KeyToLabelPipe, decorators: [{
4485
4562
  type: Pipe,
4486
4563
  args: [{
4487
- name: 'keyToLabel',
4488
- standalone: true
4564
+ name: 'keyToLabel'
4489
4565
  }]
4490
4566
  }] });
4491
4567
 
@@ -4499,8 +4575,7 @@ class NoExtPipe {
4499
4575
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: NoExtPipe, decorators: [{
4500
4576
  type: Pipe,
4501
4577
  args: [{
4502
- name: 'noExt',
4503
- standalone: true
4578
+ name: 'noExt'
4504
4579
  }]
4505
4580
  }] });
4506
4581
 
@@ -4514,8 +4589,7 @@ class PluralizePipe {
4514
4589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: PluralizePipe, decorators: [{
4515
4590
  type: Pipe,
4516
4591
  args: [{
4517
- name: 'pluralize',
4518
- standalone: true
4592
+ name: 'pluralize'
4519
4593
  }]
4520
4594
  }] });
4521
4595
 
@@ -4529,8 +4603,7 @@ class RemoveMarkdownPipe {
4529
4603
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: RemoveMarkdownPipe, decorators: [{
4530
4604
  type: Pipe,
4531
4605
  args: [{
4532
- name: 'removeMarkdown',
4533
- standalone: true
4606
+ name: 'removeMarkdown'
4534
4607
  }]
4535
4608
  }] });
4536
4609
 
@@ -4544,8 +4617,7 @@ class RepeatPipe {
4544
4617
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: RepeatPipe, decorators: [{
4545
4618
  type: Pipe,
4546
4619
  args: [{
4547
- name: 'repeat',
4548
- standalone: true
4620
+ name: 'repeat'
4549
4621
  }]
4550
4622
  }] });
4551
4623
 
@@ -6103,8 +6175,7 @@ class TagsInputDirective {
6103
6175
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: TagsInputDirective, decorators: [{
6104
6176
  type: Directive,
6105
6177
  args: [{
6106
- selector: '[appTagsInput]',
6107
- standalone: true
6178
+ selector: '[appTagsInput]'
6108
6179
  }]
6109
6180
  }], propDecorators: { appTagsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "appTagsInput", required: true }] }] } });
6110
6181
 
@@ -6118,8 +6189,7 @@ class ThousandSuffixesPipe {
6118
6189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ThousandSuffixesPipe, decorators: [{
6119
6190
  type: Pipe,
6120
6191
  args: [{
6121
- name: 'thousandSuff',
6122
- standalone: true
6192
+ name: 'thousandSuff'
6123
6193
  }]
6124
6194
  }] });
6125
6195
 
@@ -6133,8 +6203,7 @@ class ThousandsPipe {
6133
6203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ThousandsPipe, decorators: [{
6134
6204
  type: Pipe,
6135
6205
  args: [{
6136
- name: 'thousands',
6137
- standalone: true
6206
+ name: 'thousands'
6138
6207
  }]
6139
6208
  }] });
6140
6209
 
@@ -6148,8 +6217,7 @@ class TimesPipe {
6148
6217
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: TimesPipe, decorators: [{
6149
6218
  type: Pipe,
6150
6219
  args: [{
6151
- name: 'times',
6152
- standalone: true
6220
+ name: 'times'
6153
6221
  }]
6154
6222
  }] });
6155
6223
 
@@ -6163,8 +6231,7 @@ class UncapitalizePipe {
6163
6231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: UncapitalizePipe, decorators: [{
6164
6232
  type: Pipe,
6165
6233
  args: [{
6166
- name: 'uncapitalize',
6167
- standalone: true
6234
+ name: 'uncapitalize'
6168
6235
  }]
6169
6236
  }] });
6170
6237
 
@@ -6178,8 +6245,7 @@ class SortByPipe {
6178
6245
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SortByPipe, decorators: [{
6179
6246
  type: Pipe,
6180
6247
  args: [{
6181
- name: 'sortBy',
6182
- standalone: true
6248
+ name: 'sortBy'
6183
6249
  }]
6184
6250
  }] });
6185
6251
 
@@ -8012,7 +8078,11 @@ class NodeLogsModelsComponent {
8012
8078
  this.nodeType = computed(() => nodeType(this.node()), ...(ngDevMode ? [{ debugName: "nodeType" }] : []));
8013
8079
  this.logsResource = rxResource({
8014
8080
  params: () => ({ node: this.node() }),
8015
- stream: ({ params: { node } }) => this.nodeService.getLog$({ ...node, dataState: DataState.recalculated })
8081
+ stream: ({ params: { node } }) => this.nodeService.getLog$({
8082
+ '@type': node['@type'],
8083
+ '@id': node['@id'],
8084
+ dataState: node.aggregated ? DataState.original : DataState.recalculated
8085
+ })
8016
8086
  });
8017
8087
  this.allLogs = computed(() => this.logsResource.value() ?? '', ...(ngDevMode ? [{ debugName: "allLogs" }] : []));
8018
8088
  this.hasLogs = computed(() => this.allLogs() !== '', ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
@@ -8285,20 +8355,34 @@ class CyclesCompletenessComponent {
8285
8355
  component.headerKeys.set(headerKeys$1);
8286
8356
  }
8287
8357
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesCompletenessComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8288
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: CyclesCompletenessComponent, isStandalone: true, selector: "he-cycles-completeness", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n @if (selectedView() === View.table) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n\n @if (selectedView() === View.logs) {\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n }\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n</div>\n\n@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track trackById(i, cycle); let i = $index) {\n <tr>\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span>{{ i + 1 }}. {{ defaultLabel(cycle) }}</span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n", styles: [""], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8358
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: CyclesCompletenessComponent, isStandalone: true, selector: "he-cycles-completeness", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track trackById(i, cycle); let i = $index) {\n <tr>\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span>{{ i + 1 }}. {{ defaultLabel(cycle) }}</span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8289
8359
  }
8290
8360
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesCompletenessComponent, decorators: [{
8291
8361
  type: Component$1,
8292
8362
  args: [{ selector: 'he-cycles-completeness', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
8363
+ NgTemplateOutlet,
8293
8364
  HESvgIconComponent,
8294
8365
  DataTableComponent,
8295
8366
  NodeLinkComponent,
8296
8367
  BlankNodeStateComponent,
8297
8368
  BlankNodeStateNoticeComponent,
8298
8369
  NodeLogsModelsComponent
8299
- ], template: "<div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n @if (selectedView() === View.table) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n\n @if (selectedView() === View.logs) {\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n }\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n</div>\n\n@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track trackById(i, cycle); let i = $index) {\n <tr>\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span>{{ i + 1 }}. {{ defaultLabel(cycle) }}</span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n" }]
8370
+ ], template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track trackById(i, cycle); let i = $index) {\n <tr>\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span>{{ i + 1 }}. {{ defaultLabel(cycle) }}</span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n" }]
8300
8371
  }], ctorParameters: () => [], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }] } });
8301
8372
 
8373
+ class ChartExportButtonComponent {
8374
+ constructor() {
8375
+ this.chart = input.required(...(ngDevMode ? [{ debugName: "chart" }] : []));
8376
+ this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
8377
+ }
8378
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartExportButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8379
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ChartExportButtonComponent, isStandalone: true, selector: "he-chart-export-button", inputs: { chart: { classPropertyName: "chart", publicName: "chart", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<button\n class=\"button is-small is-ghost\"\n (click)=\"!chart().exporting() && chart().exportAsSvg(config())\"\n [ngbTooltip]=\"chart().exporting() ? null : 'Download Chart (SVG)'\"\n placement=\"right\">\n @if (chart().exporting()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else {\n <he-svg-icon name=\"download\" />\n }\n</button>\n", styles: [""], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8380
+ }
8381
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartExportButtonComponent, decorators: [{
8382
+ type: Component$1,
8383
+ args: [{ selector: 'he-chart-export-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HESvgIconComponent, NgbTooltip], template: "<button\n class=\"button is-small is-ghost\"\n (click)=\"!chart().exporting() && chart().exportAsSvg(config())\"\n [ngbTooltip]=\"chart().exporting() ? null : 'Download Chart (SVG)'\"\n placement=\"right\">\n @if (chart().exporting()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else {\n <he-svg-icon name=\"download\" />\n }\n</button>\n" }]
8384
+ }], propDecorators: { chart: [{ type: i0.Input, args: [{ isSignal: true, alias: "chart", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
8385
+
8302
8386
  const cycleValue = (cycle, values) => (values[cycle['@id']]?.nodes[0] || { value: [0] }).value;
8303
8387
  const cycleName = (cycle, index) => `${index + 1}. ${defaultLabel(cycle)}`;
8304
8388
  class CyclesEmissionsChartComponent {
@@ -8306,46 +8390,17 @@ class CyclesEmissionsChartComponent {
8306
8390
  this.cycles = input.required(...(ngDevMode ? [{ debugName: "cycles" }] : []));
8307
8391
  this.emissionPerCycle = computed(() => groupNodesByTerm(this.cycles(), 'emissions'), ...(ngDevMode ? [{ debugName: "emissionPerCycle" }] : []));
8308
8392
  this.terms = computed(() => Object.values(this.emissionPerCycle() ?? {})
8309
- .filter(({ values }) => Object.values(values).some(({ nodes: [{ value }] }) => propertyValue$1(value) >= 0))
8393
+ .filter(({ values }) => Object.values(values).some(({ nodes: [{ value }] }) => propertyValue$1(value) > 0))
8310
8394
  .map(({ term }) => term)
8311
8395
  .sort((a, b) => a.name.localeCompare(b.name)), ...(ngDevMode ? [{ debugName: "terms" }] : []));
8312
8396
  this.selectedTerm = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedTerm" }] : []));
8313
8397
  this.labels = computed(() => this.cycles().map(cycleName), ...(ngDevMode ? [{ debugName: "labels" }] : []));
8314
- this.chartColors = computed(() => this.cycles().map(listColor), ...(ngDevMode ? [{ debugName: "chartColors" }] : []));
8315
8398
  this.chartValues = computed(() => this.emissionPerCycle()?.[this.selectedTerm()?.name]?.values || {}, ...(ngDevMode ? [{ debugName: "chartValues" }] : []));
8316
- this.datasets = computed(() => [
8317
- {
8318
- label: this.selectedTerm()?.name || '',
8319
- data: this.cycles().map(cycle => toPrecision(propertyValue$1(cycleValue(cycle, this.chartValues()), this.selectedTerm?.['@id']))),
8320
- backgroundColor: this.chartColors(),
8321
- borderColor: this.chartColors(),
8322
- barThickness: 2,
8323
- barPercentage: 1,
8324
- categoryPercentage: 1
8325
- }
8326
- ], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
8327
- this.chartConfig = computed(() => ({
8328
- plugins: [
8329
- lollipopChartPlugin(),
8330
- afterBarDrawPlugin({
8331
- xPosFn: (x, index, width, chart) => (x || chart.scales['x-axis-0'].getPixelForValue(0)) + 10,
8332
- textFn: ({ data }) => `${data}`,
8333
- colorFn: (m, index, chart, data) => (isUndefined(data) ? '#b5b5b5' : '#4a4a4a'),
8334
- emptyValueLabel: 'No value'
8335
- })
8336
- ],
8337
- options: {
8338
- scales: {
8339
- xAxes: [
8340
- {
8341
- scaleLabel: {
8342
- labelString: this.selectedTerm()?.units
8343
- }
8344
- }
8345
- ]
8346
- }
8347
- }
8348
- }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
8399
+ this.chartData = computed(() => this.cycles().map((cycle, index) => ({
8400
+ label: cycleName(cycle, index),
8401
+ count: propertyValue$1(cycleValue(cycle, this.chartValues()), this.selectedTerm?.['@id']),
8402
+ color: listColor(cycle, index)
8403
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
8349
8404
  effect(() => {
8350
8405
  // make sure selected term exists
8351
8406
  const terms = this.terms();
@@ -8360,11 +8415,11 @@ class CyclesEmissionsChartComponent {
8360
8415
  this.selectedTerm.set(term);
8361
8416
  }
8362
8417
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesEmissionsChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8363
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: CyclesEmissionsChartComponent, isStandalone: true, selector: "he-cycles-emissions-chart", inputs: { cycles: { classPropertyName: "cycles", publicName: "cycles", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (terms().length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\" />\n</div>\n", styles: [":host{display:block;overflow:visible}he-bar-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: BarChartComponent, selector: "he-bar-chart", inputs: ["data", "max", "datasets", "labels", "config", "showExportButton"], exportAs: ["barChart"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }] }); }
8418
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: CyclesEmissionsChartComponent, isStandalone: true, selector: "he-cycles-emissions-chart", inputs: { cycles: { classPropertyName: "cycles", publicName: "cycles", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" [config]=\"{ lollipopConfig: {} }\" />\n\n <ng-content />\n</div>\n\n@if (terms().length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [labels]=\"labels()\"\n [showExportButton]=\"false\" />\n", styles: [":host{display:block;overflow:visible}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "component", type: HorizontalBarChartComponent, selector: "he-horizontal-bar-chart", inputs: ["tooltipFn", "afterBarDrawSettings"], exportAs: ["horizontalBarChart"] }, { kind: "component", type: ChartExportButtonComponent, selector: "he-chart-export-button", inputs: ["chart", "config"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8364
8419
  }
8365
8420
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesEmissionsChartComponent, decorators: [{
8366
8421
  type: Component$1,
8367
- args: [{ selector: 'he-cycles-emissions-chart', imports: [FormsModule, NgbTooltip, BarChartComponent, HESvgIconComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (terms().length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\" />\n</div>\n", styles: [":host{display:block;overflow:visible}he-bar-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
8422
+ args: [{ selector: 'he-cycles-emissions-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, HorizontalBarChartComponent, ChartExportButtonComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" [config]=\"{ lollipopConfig: {} }\" />\n\n <ng-content />\n</div>\n\n@if (terms().length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [labels]=\"labels()\"\n [showExportButton]=\"false\" />\n", styles: [":host{display:block;overflow:visible}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
8368
8423
  }], ctorParameters: () => [], propDecorators: { cycles: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycles", required: true }] }] } });
8369
8424
 
8370
8425
  class CyclesFunctionalUnitMeasureComponent {
@@ -8378,7 +8433,7 @@ class CyclesFunctionalUnitMeasureComponent {
8378
8433
  }
8379
8434
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesFunctionalUnitMeasureComponent, decorators: [{
8380
8435
  type: Component$1,
8381
- args: [{ selector: 'he-cycles-functional-unit-measure', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<span class=\"is-nowrap has-text-ellipsis\" [attr.title]=\"functionalUnit()\">\n @switch (functionalUnit()) {\n @case (CycleFunctionalUnit['1 ha']) {\n 1 hectare\n }\n @default {\n relative\n }\n }\n</span>\n", styles: [":host{display:inline-block}\n"] }]
8436
+ args: [{ selector: 'he-cycles-functional-unit-measure', changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"is-nowrap has-text-ellipsis\" [attr.title]=\"functionalUnit()\">\n @switch (functionalUnit()) {\n @case (CycleFunctionalUnit['1 ha']) {\n 1 hectare\n }\n @default {\n relative\n }\n }\n</span>\n", styles: [":host{display:inline-block}\n"] }]
8382
8437
  }], propDecorators: { cycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycle", required: true }] }] } });
8383
8438
 
8384
8439
  var View$3;
@@ -8651,7 +8706,7 @@ class CyclesNodesTimelineComponent {
8651
8706
  this.maxChart = computed(() => formatDate(this.maxDate(), false), ...(ngDevMode ? [{ debugName: "maxChart" }] : []));
8652
8707
  this.minChart = computed(() => this.minDate() ? formatDate(this.minDate(), true) : monthsBefore(this.maxChart(), 12), ...(ngDevMode ? [{ debugName: "minChart" }] : []));
8653
8708
  this.chartConfig = computed(() => ({
8654
- type: 'horizontalBar',
8709
+ type: 'bar',
8655
8710
  plugins: [
8656
8711
  lollipopChartPlugin({
8657
8712
  circleRadius: 6,
@@ -8659,64 +8714,62 @@ class CyclesNodesTimelineComponent {
8659
8714
  colorFn: () => colour
8660
8715
  }),
8661
8716
  afterBarDrawPlugin({
8662
- xPosFn: (x, index, width, chart) => (x || chart.scales['x-axis-0'].getPixelForValue(this.minChart())) + 10,
8663
- colorFn: () => '#b5b5b5',
8717
+ xPosFn: (x, index, width, chart) => (x || chart.scales.x.getPixelForValue(this.minChart().getTime())) + 10,
8664
8718
  emptyValueLabel: 'No dates available'
8665
8719
  })
8666
8720
  ],
8667
8721
  options: {
8668
- legend: {
8669
- display: false
8670
- },
8671
- tooltips: {
8672
- mode: 'point',
8673
- enabled: false,
8674
- intersect: true,
8675
- axis: 'y'
8722
+ indexAxis: 'y',
8723
+ plugins: {
8724
+ legend: {
8725
+ display: false
8726
+ },
8727
+ tooltip: {
8728
+ mode: 'point',
8729
+ enabled: false,
8730
+ intersect: true,
8731
+ axis: 'y'
8732
+ }
8676
8733
  },
8677
8734
  scales: {
8678
- xAxes: [
8679
- {
8680
- type: 'time',
8681
- time: {
8682
- unit: 'month'
8683
- },
8684
- ticks: {
8685
- max: this.maxChart(),
8686
- ...(this.minChart() ? { min: this.minChart() } : {})
8687
- },
8688
- stacked: false,
8689
- gridLines: {
8690
- drawOnChartArea: false
8691
- }
8735
+ x: {
8736
+ type: 'time',
8737
+ time: {
8738
+ unit: 'month'
8739
+ },
8740
+ max: this.maxChart().getTime(),
8741
+ ...(this.minChart() ? { min: this.minChart().getTime() } : {}),
8742
+ stacked: false,
8743
+ grid: {
8744
+ drawOnChartArea: false
8692
8745
  }
8693
- ],
8694
- yAxes: [
8695
- {
8696
- stacked: true,
8697
- ticks: {
8698
- padding: 4
8699
- },
8700
- gridLines: {
8701
- display: true,
8702
- drawOnChartArea: false,
8703
- drawTicks: true,
8704
- drawBorder: true,
8705
- tickMarkLength: 8,
8706
- offsetGridLines: false
8707
- }
8746
+ },
8747
+ y: {
8748
+ stacked: true,
8749
+ border: {
8750
+ display: true
8751
+ },
8752
+ grid: {
8753
+ display: true,
8754
+ drawOnChartArea: false,
8755
+ drawTicks: true,
8756
+ tickLength: 8,
8757
+ offset: false
8758
+ },
8759
+ ticks: {
8760
+ padding: 4
8708
8761
  }
8709
- ]
8762
+ }
8710
8763
  }
8711
8764
  }
8712
8765
  }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
8713
8766
  }
8714
8767
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesNodesTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8715
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.13", type: CyclesNodesTimelineComponent, isStandalone: true, selector: "he-cycles-nodes-timeline", inputs: { values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: true, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: true, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-content />\n\n<div class=\"chart-area-border is-mt-3\">\n <he-chart class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig()\" />\n</div>\n", styles: ["he-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }] }); }
8768
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.13", type: CyclesNodesTimelineComponent, isStandalone: true, selector: "he-cycles-nodes-timeline", inputs: { values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: true, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: true, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-content />\n\n<div class=\"chart-area-border is-mt-3\">\n <he-chart class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig()\" />\n</div>\n", styles: ["he-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8716
8769
  }
8717
8770
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesNodesTimelineComponent, decorators: [{
8718
8771
  type: Component$1,
8719
- args: [{ selector: 'he-cycles-nodes-timeline', imports: [ChartComponent], template: "<ng-content />\n\n<div class=\"chart-area-border is-mt-3\">\n <he-chart class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig()\" />\n</div>\n", styles: ["he-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
8772
+ args: [{ selector: 'he-cycles-nodes-timeline', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<ng-content />\n\n<div class=\"chart-area-border is-mt-3\">\n <he-chart class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig()\" />\n</div>\n", styles: ["he-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
8720
8773
  }], propDecorators: { values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: true }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: true }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }] } });
8721
8774
 
8722
8775
  class TermsUnitsDescriptionComponent {
@@ -8809,7 +8862,7 @@ class CyclesNodesComponent {
8809
8862
  this.View = View$2;
8810
8863
  this.viewIcon = viewIcon$2;
8811
8864
  this.showView = computed(() => ({
8812
- [View$2.chart]: this.selectedNodeKey() === BlankNodesKey.emissions && this.cycles().length > 1,
8865
+ [View$2.chart]: [this.isEmission() && this.cycles().length > 1].some(Boolean),
8813
8866
  [View$2.logs]: !this.isOriginal() && this.hasRecalculatedNodes(),
8814
8867
  [View$2.table]: true,
8815
8868
  [View$2.timeline]: this.enableTimeline()
@@ -8955,7 +9008,7 @@ class CyclesResultComponent {
8955
9008
  backgroundColor: color,
8956
9009
  borderColor: color,
8957
9010
  barPercentage: 0.5,
8958
- data: this.cycles().map(({ '@id': id }) => (values[id] ? propertyValue$1(values[id].value, termId) : 0))
9011
+ data: this.cycles().map(({ '@id': id }) => values[id] ? propertyValue$1(values[id].value, termId) : 0)
8959
9012
  };
8960
9013
  }), ...(ngDevMode ? [{ debugName: "chartDatasets" }] : []));
8961
9014
  this.chartData = computed(() => ({
@@ -8963,41 +9016,37 @@ class CyclesResultComponent {
8963
9016
  labels: this.chartLabels()
8964
9017
  }), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
8965
9018
  this.chartConfig = {
8966
- type: 'horizontalBar',
9019
+ type: 'bar',
8967
9020
  options: {
8968
- legend: {
8969
- display: true
8970
- },
8971
- tooltips: {
8972
- callbacks: {
8973
- title: (tooltipItems, data) => data.labels[tooltipItems[0].index]
9021
+ indexAxis: 'y',
9022
+ plugins: {
9023
+ legend: {
9024
+ display: true
9025
+ },
9026
+ tooltip: {
9027
+ callbacks: {
9028
+ title: tooltipItems => tooltipItems[0].label
9029
+ }
8974
9030
  }
8975
9031
  },
8976
9032
  scales: {
8977
- xAxes: [
8978
- {
8979
- ticks: {
8980
- min: 0
8981
- }
8982
- }
8983
- ],
8984
- yAxes: [
8985
- {
8986
- position: 'left',
8987
- scaleLabel: {
8988
- display: true,
8989
- labelString: 'Cycle'
8990
- }
9033
+ x: {
9034
+ min: 0
9035
+ },
9036
+ y: {
9037
+ position: 'left',
9038
+ title: {
9039
+ display: true,
9040
+ text: 'Cycle'
8991
9041
  }
8992
- ]
9042
+ }
8993
9043
  }
8994
9044
  }
8995
9045
  };
8996
- Chart$1.scaleService.updateScaleDefaults('category', {
8997
- ticks: {
8998
- callback: tick => ellipsis(`${tick}`, 25)
8999
- }
9000
- });
9046
+ Chart.defaults.scales.category.ticks.callback = function (val) {
9047
+ const label = this.getLabelForValue(val);
9048
+ return ellipsis(`${label}`, 25);
9049
+ };
9001
9050
  }
9002
9051
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesResultComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9003
9052
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.13", type: CyclesResultComponent, isStandalone: true, selector: "he-cycles-result", inputs: { cycles: { classPropertyName: "cycles", publicName: "cycles", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<he-chart class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig\" />\n", styles: [":host{display:block}he-chart ::ng-deep .chart-container{min-height:300px}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -9402,19 +9451,16 @@ class NodeAggregatedQualityScoreComponent {
9402
9451
  : of(undefined)
9403
9452
  });
9404
9453
  this.countryId = computed(() => this.countryResource.value()?.['@id'], ...(ngDevMode ? [{ debugName: "countryId" }] : []));
9405
- this.aggregationId = computed(() => [!!this.node(), !!this.countryId()].every(Boolean) ? nodeToAggregationFilename(this.node(), this.countryId()) : null, ...(ngDevMode ? [{ debugName: "aggregationId" }] : []));
9406
9454
  this.logsResource = rxResource({
9407
9455
  params: () => ({
9408
9456
  showInfo: this.showInfo(),
9409
- node: this.node(),
9410
- aggregationId: this.aggregationId()
9457
+ node: this.node()
9411
9458
  }),
9412
- stream: ({ params: { showInfo, node, aggregationId } }) => showInfo && aggregationId
9459
+ stream: ({ params: { showInfo, node } }) => showInfo
9413
9460
  ? this.nodeService
9414
9461
  .getLog$({
9415
9462
  '@type': node['@type'],
9416
- '@id': aggregationId,
9417
- aggregated: true
9463
+ '@id': node['@id']
9418
9464
  })
9419
9465
  .pipe(map(value => (value ? parseLines(value) : [])), mergeAll(), filter(({ data: { message } }) => !!message), map(({ data: { message } }) => parseMessage$1(message)), filter(({ id }) => id === this.node()['@id']), reduce((a, b) => ({ ...a, ...b }), {}))
9420
9466
  : of({})
@@ -9845,7 +9891,7 @@ class EngineModelsStageComponent {
9845
9891
  }
9846
9892
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: EngineModelsStageComponent, decorators: [{
9847
9893
  type: Component$1,
9848
- args: [{ selector: 'he-engine-models-stage', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "@if (inProgress()) {\n <span class=\"tag is-warning\">\n <span>Calculation in progress (stage {{ stage() }} out of {{ maxStage() }})</span>\n </span>\n}\n", styles: [":host{display:inline-block}\n"] }]
9894
+ args: [{ selector: 'he-engine-models-stage', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (inProgress()) {\n <span class=\"tag is-warning\">\n <span>Calculation in progress (stage {{ stage() }} out of {{ maxStage() }})</span>\n </span>\n}\n", styles: [":host{display:inline-block}\n"] }]
9849
9895
  }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }] } });
9850
9896
 
9851
9897
  class EngineModelsVersionLinkComponent {
@@ -12035,31 +12081,31 @@ ${JSON.stringify(error)}
12035
12081
  /label ~"Priority::MEDIUM"
12036
12082
  /label ~"Tracking::Triage"
12037
12083
  `.trim())}`;
12038
- var ErrorKeys;
12039
- (function (ErrorKeys) {
12040
- ErrorKeys["PrivacyNotAllowed"] = "privacy-not-allowed";
12041
- ErrorKeys["NoData"] = "no-data";
12042
- ErrorKeys["NoHeaders"] = "no-headers";
12043
- ErrorKeys["InvalidJSON"] = "invalid-json";
12044
- ErrorKeys["InvalidSheetName"] = "invalid-sheet-name";
12045
- ErrorKeys["InvalidFirstColumn"] = "invalid-first-column";
12046
- ErrorKeys["InvalidExcelFile"] = "invalid-excel-file";
12047
- ErrorKeys["DuplicatedHeaders"] = "duplicated-headers";
12048
- ErrorKeys["DuplicatedIds"] = "duplicated-ids";
12049
- ErrorKeys["PropertyRequired"] = "property-required";
12050
- ErrorKeys["PropertyInternal"] = "property-internal";
12051
- ErrorKeys["UploadsLimit"] = "upload-limit";
12052
- ErrorKeys["NestedHeaders"] = "nested-headers";
12053
- ErrorKeys["NestedNodes"] = "nested-nodes";
12054
- ErrorKeys["ReferenceExistingHeaders"] = "reference-existing-headers";
12055
- ErrorKeys["MultipleTermHeaders"] = "multiple-term-headers";
12056
- ErrorKeys["MaxSize"] = "max-size";
12057
- ErrorKeys["InvalidBlankNodeHeaders"] = "invalid-blank-node-headers";
12058
- ErrorKeys["MaxRows"] = "max-rows";
12059
- ErrorKeys["Mendeley"] = "'content-type'";
12060
- ErrorKeys["Timeout"] = "TimeoutError: Timeout has occurred";
12061
- ErrorKeys["SetValueError"] = "set-value-failed";
12062
- })(ErrorKeys || (ErrorKeys = {}));
12084
+ var FileUploadErrorKeys;
12085
+ (function (FileUploadErrorKeys) {
12086
+ FileUploadErrorKeys["PrivacyNotAllowed"] = "privacy-not-allowed";
12087
+ FileUploadErrorKeys["NoData"] = "no-data";
12088
+ FileUploadErrorKeys["NoHeaders"] = "no-headers";
12089
+ FileUploadErrorKeys["InvalidJSON"] = "invalid-json";
12090
+ FileUploadErrorKeys["InvalidSheetName"] = "invalid-sheet-name";
12091
+ FileUploadErrorKeys["InvalidFirstColumn"] = "invalid-first-column";
12092
+ FileUploadErrorKeys["InvalidExcelFile"] = "invalid-excel-file";
12093
+ FileUploadErrorKeys["DuplicatedHeaders"] = "duplicated-headers";
12094
+ FileUploadErrorKeys["DuplicatedIds"] = "duplicated-ids";
12095
+ FileUploadErrorKeys["PropertyRequired"] = "property-required";
12096
+ FileUploadErrorKeys["PropertyInternal"] = "property-internal";
12097
+ FileUploadErrorKeys["UploadsLimit"] = "upload-limit";
12098
+ FileUploadErrorKeys["NestedHeaders"] = "nested-headers";
12099
+ FileUploadErrorKeys["NestedNodes"] = "nested-nodes";
12100
+ FileUploadErrorKeys["ReferenceExistingHeaders"] = "reference-existing-headers";
12101
+ FileUploadErrorKeys["MultipleTermHeaders"] = "multiple-term-headers";
12102
+ FileUploadErrorKeys["MaxSize"] = "max-size";
12103
+ FileUploadErrorKeys["InvalidBlankNodeHeaders"] = "invalid-blank-node-headers";
12104
+ FileUploadErrorKeys["MaxRows"] = "max-rows";
12105
+ FileUploadErrorKeys["Mendeley"] = "'content-type'";
12106
+ FileUploadErrorKeys["Timeout"] = "TimeoutError: Timeout has occurred";
12107
+ FileUploadErrorKeys["SetValueError"] = "set-value-failed";
12108
+ })(FileUploadErrorKeys || (FileUploadErrorKeys = {}));
12063
12109
  const valueToNodes = (value, type) => Array.isArray(value)
12064
12110
  ? isExpandable(value)
12065
12111
  ? value.map(val => ({
@@ -12107,14 +12153,14 @@ class FilesUploadErrorsComponent {
12107
12153
  this.hasGeoJSONError = computed(() => this.error()?.error?.includes('Unable to parse GeoJSON value'), ...(ngDevMode ? [{ debugName: "hasGeoJSONError" }] : []));
12108
12154
  this.schemaUrl = computed(() => [schemaBaseUrl(this.file()?.schemaVersion), this.error()?.schema].filter(Boolean).join('/'), ...(ngDevMode ? [{ debugName: "schemaUrl" }] : []));
12109
12155
  this.schemaKeyUrl = computed(() => [this.schemaUrl(), this.error()?.schemaKey || this.error()?.key].filter(Boolean).join('#'), ...(ngDevMode ? [{ debugName: "schemaKeyUrl" }] : []));
12110
- this.isSchemaError = computed(() => [ErrorKeys$1.PropertyNotFound, ErrorKeys$1.SchemaNotFound].includes(this.error()?.message), ...(ngDevMode ? [{ debugName: "isSchemaError" }] : []));
12156
+ this.isSchemaError = computed(() => [ErrorKeys.PropertyNotFound, ErrorKeys.SchemaNotFound].includes(this.error()?.message), ...(ngDevMode ? [{ debugName: "isSchemaError" }] : []));
12111
12157
  this.showJsonPreview = computed(() => !!this.error()?.node && this.isJSONFile(), ...(ngDevMode ? [{ debugName: "showJsonPreview" }] : []));
12112
12158
  this.showCsvPreview = computed(() => this.headers().length && this.rows().length && !this.isSchemaError() && !this.isJSONFile(), ...(ngDevMode ? [{ debugName: "showCsvPreview" }] : []));
12113
12159
  this.reportErrorUrl = computed(() => issueLink(this.file()?.pipelineStatus || this.file()?.status, this.message()), ...(ngDevMode ? [{ debugName: "reportErrorUrl" }] : []));
12114
12160
  this.baseUrl = baseUrl();
12115
12161
  this.nodeTypes = acceptedTypes;
12116
- this.SchemaErrorKeys = ErrorKeys$1;
12117
- this.ErrorKeys = ErrorKeys;
12162
+ this.SchemaErrorKeys = ErrorKeys;
12163
+ this.ErrorKeys = FileUploadErrorKeys;
12118
12164
  this.maxFileSizeMb = maxFileSizeMb;
12119
12165
  this.columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
12120
12166
  this.headers = signal([], ...(ngDevMode ? [{ debugName: "headers" }] : []));
@@ -13234,11 +13280,11 @@ class ImpactAssessmentsGraphComponent {
13234
13280
  effect(() => this.showWarnings.set(this.warnings()?.length > 0));
13235
13281
  }
13236
13282
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13237
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsGraphComponent, isStandalone: true, selector: "he-impact-assessments-graph", inputs: { impactAssessments: { classPropertyName: "impactAssessments", publicName: "impactAssessments", isSignal: true, isRequired: false, transformFunction: null }, dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isRecalculated()) {\n @if (loading()) {\n <div class=\"loading-container has-text-center my-5 py-5\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n <p class=\"is-mt-2 is-italic is-size-7\">Loading chart, please wait...</p>\n </div>\n } @else {\n @if (filteredImpactAssessments().length > 1) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedImpactAssessmentId\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedImpactAssessmentId\" [disabled]=\"loading()\">\n @for (value of filteredImpactAssessments(); track value['@id']) {\n <option [value]=\"value['@id']\">\n {{ value.name || value['@id'] }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (!noData()) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedModelId\">Model</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedModelId\" id=\"selectedModelId\" [disabled]=\"loading()\">\n @for (model of models(); track model['@id']) {\n <option [value]=\"model['@id']\">{{ model.name || model['@id'] }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (showWarnings()) {\n <div class=\"has-text-warning py-3 has-text-centered\">\n @for (warning of warnings(); track warning) {\n <p class=\"is-mb-2\">\n <he-svg-icon name=\"exclamation-triangle\" class=\"pr-2\" />\n @switch (warning) {\n @case ('missing-terms') {\n <span>Calculations are not up to date. Some terms may not display correctly.</span>\n }\n }\n </p>\n }\n <p class=\"is-underlined is-size-7\"><a (click)=\"showWarnings.set(false)\">View chart anyway.</a></p>\n </div>\n }\n @if (error()) {\n <p class=\"has-text-danger py-3\">\n @switch (error()) {\n @case ('not-found') {\n <p>Impact Assessment not found</p>\n }\n @default {\n <div>\n <span>An unexpected error occurred:</span>\n <p class=\"mt-1\">{{ error() }}</p>\n </div>\n }\n }\n </p>\n }\n @if (noData()) {\n <div class=\"py-3\">\n <p class=\"has-text-centered\">No chart available.</p>\n </div>\n }\n }\n} @else {\n <p class=\"has-text-centered py-3\">\n No chart available. Switch to\n <code>recalculated</code>\n version.\n </p>\n}\n\n@if (showChart()) {\n <he-hierarchy-chart [data]=\"chartData()\" [terms]=\"allTerms()\" (chartError)=\"error.set($event)\" />\n}\n", styles: [".loading-container{min-height:200px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: HierarchyChartComponent, selector: "he-hierarchy-chart", inputs: ["data", "terms"], outputs: ["chartError"] }] }); }
13283
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsGraphComponent, isStandalone: true, selector: "he-impact-assessments-graph", inputs: { impactAssessments: { classPropertyName: "impactAssessments", publicName: "impactAssessments", isSignal: true, isRequired: false, transformFunction: null }, dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isRecalculated()) {\n @if (loading()) {\n <div class=\"loading-container has-text-center my-5 py-5\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n <p class=\"is-mt-2 is-italic is-size-7\">Loading chart, please wait...</p>\n </div>\n } @else {\n @if (filteredImpactAssessments().length > 1) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedImpactAssessmentId\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedImpactAssessmentId\" [disabled]=\"loading()\">\n @for (value of filteredImpactAssessments(); track value['@id']) {\n <option [value]=\"value['@id']\">\n {{ value.name || value['@id'] }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (!noData()) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedModelId\">Model</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedModelId\" id=\"selectedModelId\" [disabled]=\"loading()\">\n @for (model of models(); track model['@id']) {\n <option [value]=\"model['@id']\">{{ model.name || model['@id'] }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (showWarnings()) {\n <div class=\"has-text-warning py-3 has-text-centered\">\n @for (warning of warnings(); track warning) {\n <p class=\"is-mb-2\">\n <he-svg-icon name=\"exclamation-triangle\" class=\"pr-2\" />\n @switch (warning) {\n @case ('missing-terms') {\n <span>Calculations are not up to date. Some terms may not display correctly.</span>\n }\n }\n </p>\n }\n <p class=\"is-underlined is-size-7\"><a (click)=\"showWarnings.set(false)\">View chart anyway.</a></p>\n </div>\n }\n @if (error()) {\n <p class=\"has-text-danger py-3\">\n @switch (error()) {\n @case ('not-found') {\n <p>Impact Assessment not found</p>\n }\n @default {\n <div>\n <span>An unexpected error occurred:</span>\n <p class=\"mt-1\">{{ error() }}</p>\n </div>\n }\n }\n </p>\n }\n @if (noData()) {\n <div class=\"py-3\">\n <p class=\"has-text-centered\">No chart available.</p>\n </div>\n }\n }\n} @else {\n <p class=\"has-text-centered py-3\">\n No chart available. Switch to\n <code>recalculated</code>\n version.\n </p>\n}\n\n@if (showChart()) {\n <he-hierarchy-chart [data]=\"chartData()\" [terms]=\"allTerms()\" (chartError)=\"error.set($event)\" />\n}\n", styles: [".loading-container{min-height:200px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: HierarchyChartComponent, selector: "he-hierarchy-chart", inputs: ["data", "terms"], outputs: ["chartError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13238
13284
  }
13239
13285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsGraphComponent, decorators: [{
13240
13286
  type: Component$1,
13241
- args: [{ selector: 'he-impact-assessments-graph', imports: [HESvgIconComponent, FormsModule, HierarchyChartComponent], template: "@if (isRecalculated()) {\n @if (loading()) {\n <div class=\"loading-container has-text-center my-5 py-5\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n <p class=\"is-mt-2 is-italic is-size-7\">Loading chart, please wait...</p>\n </div>\n } @else {\n @if (filteredImpactAssessments().length > 1) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedImpactAssessmentId\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedImpactAssessmentId\" [disabled]=\"loading()\">\n @for (value of filteredImpactAssessments(); track value['@id']) {\n <option [value]=\"value['@id']\">\n {{ value.name || value['@id'] }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (!noData()) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedModelId\">Model</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedModelId\" id=\"selectedModelId\" [disabled]=\"loading()\">\n @for (model of models(); track model['@id']) {\n <option [value]=\"model['@id']\">{{ model.name || model['@id'] }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (showWarnings()) {\n <div class=\"has-text-warning py-3 has-text-centered\">\n @for (warning of warnings(); track warning) {\n <p class=\"is-mb-2\">\n <he-svg-icon name=\"exclamation-triangle\" class=\"pr-2\" />\n @switch (warning) {\n @case ('missing-terms') {\n <span>Calculations are not up to date. Some terms may not display correctly.</span>\n }\n }\n </p>\n }\n <p class=\"is-underlined is-size-7\"><a (click)=\"showWarnings.set(false)\">View chart anyway.</a></p>\n </div>\n }\n @if (error()) {\n <p class=\"has-text-danger py-3\">\n @switch (error()) {\n @case ('not-found') {\n <p>Impact Assessment not found</p>\n }\n @default {\n <div>\n <span>An unexpected error occurred:</span>\n <p class=\"mt-1\">{{ error() }}</p>\n </div>\n }\n }\n </p>\n }\n @if (noData()) {\n <div class=\"py-3\">\n <p class=\"has-text-centered\">No chart available.</p>\n </div>\n }\n }\n} @else {\n <p class=\"has-text-centered py-3\">\n No chart available. Switch to\n <code>recalculated</code>\n version.\n </p>\n}\n\n@if (showChart()) {\n <he-hierarchy-chart [data]=\"chartData()\" [terms]=\"allTerms()\" (chartError)=\"error.set($event)\" />\n}\n", styles: [".loading-container{min-height:200px}\n"] }]
13287
+ args: [{ selector: 'he-impact-assessments-graph', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HESvgIconComponent, FormsModule, HierarchyChartComponent], template: "@if (isRecalculated()) {\n @if (loading()) {\n <div class=\"loading-container has-text-center my-5 py-5\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n <p class=\"is-mt-2 is-italic is-size-7\">Loading chart, please wait...</p>\n </div>\n } @else {\n @if (filteredImpactAssessments().length > 1) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedImpactAssessmentId\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedImpactAssessmentId\" [disabled]=\"loading()\">\n @for (value of filteredImpactAssessments(); track value['@id']) {\n <option [value]=\"value['@id']\">\n {{ value.name || value['@id'] }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (!noData()) {\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectedModelId\">Model</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth is-secondary\">\n <select [(ngModel)]=\"selectedModelId\" id=\"selectedModelId\" [disabled]=\"loading()\">\n @for (model of models(); track model['@id']) {\n <option [value]=\"model['@id']\">{{ model.name || model['@id'] }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n @if (showWarnings()) {\n <div class=\"has-text-warning py-3 has-text-centered\">\n @for (warning of warnings(); track warning) {\n <p class=\"is-mb-2\">\n <he-svg-icon name=\"exclamation-triangle\" class=\"pr-2\" />\n @switch (warning) {\n @case ('missing-terms') {\n <span>Calculations are not up to date. Some terms may not display correctly.</span>\n }\n }\n </p>\n }\n <p class=\"is-underlined is-size-7\"><a (click)=\"showWarnings.set(false)\">View chart anyway.</a></p>\n </div>\n }\n @if (error()) {\n <p class=\"has-text-danger py-3\">\n @switch (error()) {\n @case ('not-found') {\n <p>Impact Assessment not found</p>\n }\n @default {\n <div>\n <span>An unexpected error occurred:</span>\n <p class=\"mt-1\">{{ error() }}</p>\n </div>\n }\n }\n </p>\n }\n @if (noData()) {\n <div class=\"py-3\">\n <p class=\"has-text-centered\">No chart available.</p>\n </div>\n }\n }\n} @else {\n <p class=\"has-text-centered py-3\">\n No chart available. Switch to\n <code>recalculated</code>\n version.\n </p>\n}\n\n@if (showChart()) {\n <he-hierarchy-chart [data]=\"chartData()\" [terms]=\"allTerms()\" (chartError)=\"error.set($event)\" />\n}\n", styles: [".loading-container{min-height:200px}\n"] }]
13242
13288
  }], ctorParameters: () => [], propDecorators: { impactAssessments: [{ type: i0.Input, args: [{ isSignal: true, alias: "impactAssessments", required: false }] }], dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }] } });
13243
13289
 
13244
13290
  const parseLog = (data) => ({
@@ -13263,13 +13309,12 @@ const logsTotalValue = (logs, includeNegativeValues) => sum((includeNegativeValu
13263
13309
  const valueRatio = (value, total) => toPrecision((value * 100) / total, 2);
13264
13310
  const chartLabel = (value, total) => {
13265
13311
  const ratio = valueRatio(value, total);
13266
- return value === 0 ? '0' : `${toPrecision(value, 3)}, ${ratio}%`;
13312
+ return value === 0 ? '0' : `${value}, ${ratio}%`;
13267
13313
  };
13268
13314
  const chartBreakdownLabel = (logs, total, maxValues) => {
13269
13315
  const values = logs.slice(maxValues);
13270
13316
  return values.map(({ blankNodeTermId, value }) => `${blankNodeTermId}: ${chartLabel(value, total)}`).join('</br>');
13271
13317
  };
13272
- const chartTextColor = (value) => (isUndefined(value) ? '#b5b5b5' : '#4a4a4a');
13273
13318
  const logToCsv = (logs, impact) => [
13274
13319
  csvHeaders.join(','),
13275
13320
  ...logs
@@ -13288,7 +13333,6 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13288
13333
  this.responsiveService = inject(ResponsiveService);
13289
13334
  this.impactAssessment = input.required(...(ngDevMode ? [{ debugName: "impactAssessment" }] : []));
13290
13335
  this.indicators = input([], ...(ngDevMode ? [{ debugName: "indicators" }] : []));
13291
- this.tooltip = viewChild.required('tooltip');
13292
13336
  this.maximumValues = computed(() => (this.responsiveService.isMobile() ? 10 : 20), ...(ngDevMode ? [{ debugName: "maximumValues" }] : []));
13293
13337
  this.logsResource = rxResource({
13294
13338
  params: () => ({
@@ -13305,7 +13349,10 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13305
13349
  ].filter(v => v.term['@id'] === log.blankNodeTermId);
13306
13350
  const inputs = blankNodes
13307
13351
  .filter(v => v.inputs?.length)
13308
- .map(v => ({ name: v.inputs.map(i => i['@id']).join(';'), value: v.value * log.coefficient }));
13352
+ .map(v => ({
13353
+ name: v.inputs.map(i => i['@id']).join(';'),
13354
+ value: toPrecision(v.value * log.coefficient, 3)
13355
+ }));
13309
13356
  const inputsValue = inputs.reduce((prev, curr) => prev + curr.value, 0);
13310
13357
  const impact = impacts?.find(v => v.term['@id'] === log.impactTermId);
13311
13358
  // logs might exist but impact was not added => skip logs
@@ -13313,7 +13360,7 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13313
13360
  ? {
13314
13361
  ...log,
13315
13362
  impactTermUnits: impact.term?.units,
13316
- value: total,
13363
+ value: toPrecision(total, 3),
13317
13364
  inputs,
13318
13365
  inputsValue
13319
13366
  }
@@ -13355,93 +13402,34 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13355
13402
  ...(this.impactAssessment()?.endpoints || [])
13356
13403
  ], ...(ngDevMode ? [{ debugName: "impacts" }] : []));
13357
13404
  this.noData = computed(() => this.nonZeroLogs()?.length === 0, ...(ngDevMode ? [{ debugName: "noData" }] : []));
13358
- this.hasNegativeContributions = computed(() => this.nonZeroLogs()?.some(log => log.value < 0), ...(ngDevMode ? [{ debugName: "hasNegativeContributions" }] : []));
13359
- this.values = computed(() => {
13360
- const includedValues = this.nonZeroLogs()?.slice(0, this.maximumValues());
13361
- const excludedValues = this.nonZeroLogs()?.slice(this.maximumValues());
13362
- return [
13363
- ...includedValues,
13364
- excludedValues.length
13365
- ? {
13366
- blankNodeTermId: `${excludedValues.length} others`,
13367
- value: sum(excludedValues.map(({ value }) => value)),
13368
- subLogs: excludedValues.map(value => ({
13369
- ...value,
13370
- name: this.emissions()?.find(v => v['@id'] === value.blankNodeTermId)?.name || value.blankNodeTermId
13371
- }))
13372
- }
13373
- : null
13374
- ]
13375
- .filter(Boolean)
13376
- .map((value, index) => ({
13377
- ...value,
13378
- name: this.emissions()?.find(v => v['@id'] === value.blankNodeTermId)?.name || value.blankNodeTermId,
13379
- color: listColor(value, index),
13380
- secondaryColor: listColorWithAlpha()(value, index)
13381
- }));
13382
- }, ...(ngDevMode ? [{ debugName: "values" }] : []));
13405
+ this.values = computed(() => this.nonZeroLogs().map((value, index) => ({
13406
+ ...value,
13407
+ name: this.emissions()?.find(v => v['@id'] === value.blankNodeTermId)?.name || value.blankNodeTermId,
13408
+ color: listColor(value, index)
13409
+ })), ...(ngDevMode ? [{ debugName: "values" }] : []));
13383
13410
  this.csvContent = computed(() => this.domSanitizer.bypassSecurityTrustResourceUrl(`data:text/html;charset=utf-8,${encodeURIComponent(logToCsv(this.logs(), this.impactAssessment()))}`), ...(ngDevMode ? [{ debugName: "csvContent" }] : []));
13384
13411
  this.id = computed(() => this.impactAssessment()?.['@id'] || this.impactAssessment()?.id, ...(ngDevMode ? [{ debugName: "id" }] : []));
13385
13412
  this.downloadFilename = computed(() => `${this.id()}-logs.csv`, ...(ngDevMode ? [{ debugName: "downloadFilename" }] : []));
13386
13413
  this.displayValue = signal(false, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
13387
13414
  this.total = computed(() => logsTotalValue(this.nonZeroLogs(), false), ...(ngDevMode ? [{ debugName: "total" }] : []));
13388
- this.labels = computed(() => this.values().map(({ name }) => name), ...(ngDevMode ? [{ debugName: "labels" }] : []));
13389
- this.datasets = computed(() => [
13390
- {
13391
- label: this.selectedTerm()?.name ?? '',
13392
- // do not show negative values in the chart
13393
- data: this.values().map(({ value }) => Math.max(0, value)),
13394
- backgroundColor: this.values().map(({ color }) => color),
13395
- borderColor: this.values().map(({ color }) => color),
13396
- barThickness: 2,
13397
- barPercentage: 1,
13398
- categoryPercentage: 1,
13399
- hoverBackgroundColor: this.values().map(({ secondaryColor }) => secondaryColor),
13400
- hoverBorderColor: this.values().map(({ secondaryColor }) => secondaryColor),
13401
- hoverBorderWidth: 3
13402
- }
13403
- ], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
13404
- this.chartConfig = computed(() => ({
13405
- plugins: [
13406
- lollipopChartPlugin(),
13407
- afterBarDrawPlugin({
13408
- xPosFn: (x, index, width, chart) => (x || chart.scales['x-axis-0'].getPixelForValue(0)) + 10,
13409
- colorFn: (m, index, chart, data) => chartTextColor(data),
13410
- emptyValueLabel: 'No value',
13411
- ...(this.displayValue()
13412
- ? {
13413
- textFn: ({ label, data }, index) => index === this.maximumValues()
13414
- ? `${label} at ${toPrecision(data)}`
13415
- : `${toPrecision(data)}`
13416
- }
13417
- : { textFn: ({ data }) => `${valueRatio(data, this.total())}%` })
13418
- }),
13419
- backgroundHoverPlugin({ threshold: 5 })
13420
- ],
13421
- options: {
13422
- onClick: (event, activeElements) => {
13423
- const index = activeElements?.[0]?.['_index'];
13424
- !event.isTrusted && this.showTooltip(index, event.x, event.y);
13425
- },
13426
- scales: {
13427
- xAxes: [
13428
- {
13429
- display: !this.responsiveService.isMobile(),
13430
- scaleLabel: {
13431
- labelString: this.selectedTerm()?.units
13432
- }
13433
- }
13434
- ],
13435
- yAxes: [
13436
- {
13437
- display: !this.responsiveService.isMobile()
13438
- }
13439
- ]
13440
- }
13415
+ this.chartData = computed(() => this.values().map(value => ({
13416
+ label: value.name,
13417
+ count: value.value,
13418
+ backgroundColor: value.color
13419
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
13420
+ this.chartTooltipFn = ({ includedItems }, index) => {
13421
+ const { value } = this.values()[index] || {};
13422
+ return !isUndefined(value)
13423
+ ? includedItems?.length
13424
+ ? chartBreakdownLabel(this.nonZeroLogs(), this.total(), this.maximumValues())
13425
+ : chartLabel(value, this.total())
13426
+ : '';
13427
+ };
13428
+ this.afterBarDrawSettings = computed(() => (this.displayValue()
13429
+ ? {
13430
+ textFn: ({ label, data }, index) => (index === this.maximumValues() ? `${label} at ${data}` : `${data}`)
13441
13431
  }
13442
- }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
13443
- this.tooltipX = signal(0, ...(ngDevMode ? [{ debugName: "tooltipX" }] : []));
13444
- this.tooltipY = signal(0, ...(ngDevMode ? [{ debugName: "tooltipY" }] : []));
13432
+ : { textFn: ({ data }) => `${valueRatio(data, this.total())}%` }), ...(ngDevMode ? [{ debugName: "afterBarDrawSettings" }] : []));
13445
13433
  // make sure selected term exists
13446
13434
  effect(() => {
13447
13435
  const terms = this.terms();
@@ -13466,24 +13454,13 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13466
13454
  trackByLog({ blankNodeTermId, modelId, impactTermId }) {
13467
13455
  return [blankNodeTermId, modelId, impactTermId].join('-');
13468
13456
  }
13469
- showTooltip(index, x, y) {
13470
- this.tooltipX.set(x);
13471
- this.tooltipY.set(y);
13472
- const { value } = this.values()[index] || {};
13473
- const text = value
13474
- ? index === this.maximumValues()
13475
- ? chartBreakdownLabel(this.nonZeroLogs(), this.total(), this.maximumValues())
13476
- : chartLabel(value, this.total())
13477
- : '';
13478
- text && setTimeout(() => this.tooltip().open({ data: text }));
13479
- }
13480
13457
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorBreakdownChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13481
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsIndicatorBreakdownChartComponent, isStandalone: true, selector: "he-impact-assessments-indicator-breakdown-chart", inputs: { impactAssessment: { classPropertyName: "impactAssessment", publicName: "impactAssessment", isSignal: true, isRequired: true, transformFunction: null }, indicators: { classPropertyName: "indicators", publicName: "indicators", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "tooltip", first: true, predicate: ["tooltip"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"is-mb-3\">\n <ng-content />\n</div>\n\n@if (logsResource.isLoading()) {\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n} @else if (terms()?.length) {\n <div class=\"is-flex is-align-items-center is-gap-12 is-mb-2 | breakdown-actions-table\">\n @if (terms()?.length) {\n <div class=\"control is-expanded is-flex-grow-1\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedTermId\" name=\"selectedTermId\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n @if (methods()?.length) {\n <div class=\"control is-expanded\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedMethodId\" name=\"selectedMethodId\">\n @if (methods().length > 1) {\n <option [ngValue]=\"undefined\">Filter Model</option>\n }\n @for (term of methods(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n\n <div class=\"is-flex is-justify-content-space-between w-100\">\n <div ngbDropdown #optionDd=\"ngbDropdown\" container=\"body\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small\"\n type=\"button\"\n aria-haspopup=\"true\"\n aria-controls=\"download-menu\">\n <span class=\"is-pr-1 is-align-middle\">Download</span>\n <he-svg-icon name=\"chevron-down\" aria-hidden=\"true\" />\n </button>\n <div ngbDropdownMenu id=\"download-menu\" role=\"menu\">\n <div class=\"dropdown-content\">\n <a ngbDropdownItem (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\">\n <he-svg-icon size=\"20\" name=\"chart\" />\n <span class=\"is-pl-2 is-size-7\">Chart Image (.svg)</span>\n </a>\n\n <a ngbDropdownItem [href]=\"csvContent()\" [download]=\"downloadFilename()\">\n <he-svg-icon size=\"20\" name=\"table\" />\n <span class=\"is-pl-2 is-size-7\">Chart Data (.csv)</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"field is-relative is-mb-0 is-hidden-tablet\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n id=\"displayValue\"\n name=\"displayValue\"\n [(ngModel)]=\"displayValue\" />\n <label for=\"displayValue\">Show numerical value</label>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n @if (!logsResource.isLoading() && noData()) {\n <p class=\"has-text-centered\">\n <span>No breakdown available for</span>\n @if (selectedTerm()) {\n <span class=\"is-pl-1\">{{ selectedTerm().name }}</span>\n }\n @if (selectedMethod()) {\n <span class=\"is-pl-1\">({{ selectedMethod().name }})</span>\n }\n <span>.</span>\n </p>\n }\n\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [max]=\"total()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\">\n <div\n class=\"is-invisible is-absolute | shadow-tooltip\"\n [style.left.px]=\"tooltipX()\"\n [style.top.px]=\"tooltipY()\"\n [ngbTooltip]=\"rawHtmlContent\"\n triggers=\"manual\"\n autoClose=\"outside\"\n placement=\"bottom\"\n #tooltip=\"ngbTooltip\"></div>\n\n <ng-template #rawHtmlContent let-rawString=\"data\">\n <div [innerHTML]=\"rawString\"></div>\n </ng-template>\n </he-bar-chart>\n\n @if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n }\n</div>\n\n<div\n class=\"is-hidden-tablet is-flex is-flex-direction-column is-align-items-flex-start is-gap-4 is-py-1 is-px-2 is-mt-3 is-radius-3 w-100 | breakdown-legend\">\n @for (value of values(); track trackByLog(value)) {\n @if (value.subLogs?.length) {\n <span class=\"has-text-secondary has-text-weight-bold is-size-7\">\n {{ value.subLogs.length }} others grouped together\n </span>\n }\n\n <div class=\"is-flex is-align-items-center is-gap-4 w-100\">\n <div class=\"breakdown-legend--color\" [style.backgroundColor]=\"value.color\"></div>\n\n @if (value.subLogs?.length) {\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n @for (subValue of value.subLogs; track trackByLog(subValue)) {\n <span class=\"is-size-7\">{{ subValue.name }}</span>\n }\n </div>\n } @else {\n <span class=\"is-size-7\">{{ value.name }}</span>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}.shadow-tooltip{width:1px;height:1px;pointer-events:none}he-bar-chart ::ng-deep .chart-container{min-height:400px}@media screen and (max-width: 767px){he-bar-chart ::ng-deep .chart-container{min-height:200px}}@media screen and (max-width: 767px){.chart-area-border{padding:0}}@media screen and (max-width: 767px){.breakdown-actions-table{flex-direction:column;align-items:flex-start!important}}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "ngmodule", type: NgbDropdownModule }, { kind: "directive", type: i1$2.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i1$2.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i1$2.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i1$2.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["tabindex", "disabled"] }, { kind: "component", type: BarChartComponent, selector: "he-bar-chart", inputs: ["data", "max", "datasets", "labels", "config", "showExportButton"], exportAs: ["barChart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13458
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsIndicatorBreakdownChartComponent, isStandalone: true, selector: "he-impact-assessments-indicator-breakdown-chart", inputs: { impactAssessment: { classPropertyName: "impactAssessment", publicName: "impactAssessment", isSignal: true, isRequired: true, transformFunction: null }, indicators: { classPropertyName: "indicators", publicName: "indicators", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-mb-3\">\n <ng-content />\n</div>\n\n@if (logsResource.isLoading()) {\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n} @else if (terms()?.length) {\n <div class=\"is-flex is-align-items-center is-gap-12 is-mb-2 | breakdown-actions-table\">\n @if (terms()?.length) {\n <div class=\"control is-expanded is-flex-grow-1\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedTermId\" name=\"selectedTermId\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n @if (methods()?.length) {\n <div class=\"control is-expanded is-flex-shrink-0\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedMethodId\" name=\"selectedMethodId\">\n @if (methods().length > 1) {\n <option [ngValue]=\"undefined\">Filter Model</option>\n }\n @for (term of methods(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n\n <div class=\"is-flex is-justify-content-space-between w-100\">\n <div ngbDropdown #optionDd=\"ngbDropdown\" container=\"body\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small\"\n type=\"button\"\n aria-haspopup=\"true\"\n aria-controls=\"download-menu\">\n <span class=\"is-pr-1 is-align-middle\">Download</span>\n <he-svg-icon name=\"chevron-down\" aria-hidden=\"true\" />\n </button>\n <div ngbDropdownMenu id=\"download-menu\" role=\"menu\">\n <div class=\"dropdown-content\">\n <a ngbDropdownItem (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\">\n <he-svg-icon size=\"20\" name=\"chart\" />\n <span class=\"is-pl-2 is-size-7\">Chart Image (.svg)</span>\n </a>\n\n <a ngbDropdownItem [href]=\"csvContent()\" [download]=\"downloadFilename()\">\n <he-svg-icon size=\"20\" name=\"table\" />\n <span class=\"is-pl-2 is-size-7\">Chart Data (.csv)</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"field is-relative is-mb-0 is-hidden-tablet\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n id=\"displayValue\"\n name=\"displayValue\"\n [(ngModel)]=\"displayValue\" />\n <label for=\"displayValue\">Show numerical value</label>\n </div>\n </div>\n </div>\n}\n\n@if (!logsResource.isLoading() && noData()) {\n <div class=\"chart-area-border\">\n <p class=\"has-text-centered\">\n <span>No breakdown available for</span>\n @if (selectedTerm()) {\n <span class=\"is-pl-1\">{{ selectedTerm().name }}</span>\n }\n @if (selectedMethod()) {\n <span class=\"is-pl-1\">({{ selectedMethod().name }})</span>\n }\n <span>.</span>\n </p>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [max]=\"total()\"\n [maximumValues]=\"maximumValues()\"\n [showExportButton]=\"false\"\n [showNegativeValues]=\"false\"\n [tooltipFn]=\"chartTooltipFn\"\n [afterBarDrawSettings]=\"afterBarDrawSettings()\" />\n", styles: [":host{display:block;overflow:visible}.shadow-tooltip{width:1px;height:1px;pointer-events:none}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}@media screen and (max-width: 767px){he-horizontal-bar-chart ::ng-deep .chart-container{min-height:200px}}@media screen and (max-width: 767px){.chart-area-border{padding:0}}@media screen and (max-width: 767px){.breakdown-actions-table{flex-direction:column;align-items:flex-start!important}}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgbDropdownModule }, { kind: "directive", type: i1$2.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i1$2.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i1$2.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i1$2.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["tabindex", "disabled"] }, { kind: "component", type: HorizontalBarChartComponent, selector: "he-horizontal-bar-chart", inputs: ["tooltipFn", "afterBarDrawSettings"], exportAs: ["horizontalBarChart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13482
13459
  }
13483
13460
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorBreakdownChartComponent, decorators: [{
13484
13461
  type: Component$1,
13485
- args: [{ selector: 'he-impact-assessments-indicator-breakdown-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HESvgIconComponent, FormsModule, NgbTooltip, NgbDropdownModule, BarChartComponent], template: "<div class=\"is-mb-3\">\n <ng-content />\n</div>\n\n@if (logsResource.isLoading()) {\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n} @else if (terms()?.length) {\n <div class=\"is-flex is-align-items-center is-gap-12 is-mb-2 | breakdown-actions-table\">\n @if (terms()?.length) {\n <div class=\"control is-expanded is-flex-grow-1\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedTermId\" name=\"selectedTermId\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n @if (methods()?.length) {\n <div class=\"control is-expanded\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedMethodId\" name=\"selectedMethodId\">\n @if (methods().length > 1) {\n <option [ngValue]=\"undefined\">Filter Model</option>\n }\n @for (term of methods(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n\n <div class=\"is-flex is-justify-content-space-between w-100\">\n <div ngbDropdown #optionDd=\"ngbDropdown\" container=\"body\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small\"\n type=\"button\"\n aria-haspopup=\"true\"\n aria-controls=\"download-menu\">\n <span class=\"is-pr-1 is-align-middle\">Download</span>\n <he-svg-icon name=\"chevron-down\" aria-hidden=\"true\" />\n </button>\n <div ngbDropdownMenu id=\"download-menu\" role=\"menu\">\n <div class=\"dropdown-content\">\n <a ngbDropdownItem (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\">\n <he-svg-icon size=\"20\" name=\"chart\" />\n <span class=\"is-pl-2 is-size-7\">Chart Image (.svg)</span>\n </a>\n\n <a ngbDropdownItem [href]=\"csvContent()\" [download]=\"downloadFilename()\">\n <he-svg-icon size=\"20\" name=\"table\" />\n <span class=\"is-pl-2 is-size-7\">Chart Data (.csv)</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"field is-relative is-mb-0 is-hidden-tablet\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n id=\"displayValue\"\n name=\"displayValue\"\n [(ngModel)]=\"displayValue\" />\n <label for=\"displayValue\">Show numerical value</label>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n @if (!logsResource.isLoading() && noData()) {\n <p class=\"has-text-centered\">\n <span>No breakdown available for</span>\n @if (selectedTerm()) {\n <span class=\"is-pl-1\">{{ selectedTerm().name }}</span>\n }\n @if (selectedMethod()) {\n <span class=\"is-pl-1\">({{ selectedMethod().name }})</span>\n }\n <span>.</span>\n </p>\n }\n\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [max]=\"total()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\">\n <div\n class=\"is-invisible is-absolute | shadow-tooltip\"\n [style.left.px]=\"tooltipX()\"\n [style.top.px]=\"tooltipY()\"\n [ngbTooltip]=\"rawHtmlContent\"\n triggers=\"manual\"\n autoClose=\"outside\"\n placement=\"bottom\"\n #tooltip=\"ngbTooltip\"></div>\n\n <ng-template #rawHtmlContent let-rawString=\"data\">\n <div [innerHTML]=\"rawString\"></div>\n </ng-template>\n </he-bar-chart>\n\n @if (hasNegativeContributions()) {\n <p class=\"is-mt-2 is-italic is-size-7 has-text-center\">\n <span class=\"is-pr-1\">This chart includes negative contributions that will appear as</span>\n <b>0</b>\n <span>.</span>\n </p>\n }\n</div>\n\n<div\n class=\"is-hidden-tablet is-flex is-flex-direction-column is-align-items-flex-start is-gap-4 is-py-1 is-px-2 is-mt-3 is-radius-3 w-100 | breakdown-legend\">\n @for (value of values(); track trackByLog(value)) {\n @if (value.subLogs?.length) {\n <span class=\"has-text-secondary has-text-weight-bold is-size-7\">\n {{ value.subLogs.length }} others grouped together\n </span>\n }\n\n <div class=\"is-flex is-align-items-center is-gap-4 w-100\">\n <div class=\"breakdown-legend--color\" [style.backgroundColor]=\"value.color\"></div>\n\n @if (value.subLogs?.length) {\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n @for (subValue of value.subLogs; track trackByLog(subValue)) {\n <span class=\"is-size-7\">{{ subValue.name }}</span>\n }\n </div>\n } @else {\n <span class=\"is-size-7\">{{ value.name }}</span>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}.shadow-tooltip{width:1px;height:1px;pointer-events:none}he-bar-chart ::ng-deep .chart-container{min-height:400px}@media screen and (max-width: 767px){he-bar-chart ::ng-deep .chart-container{min-height:200px}}@media screen and (max-width: 767px){.chart-area-border{padding:0}}@media screen and (max-width: 767px){.breakdown-actions-table{flex-direction:column;align-items:flex-start!important}}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"] }]
13486
- }], ctorParameters: () => [], propDecorators: { impactAssessment: [{ type: i0.Input, args: [{ isSignal: true, alias: "impactAssessment", required: true }] }], indicators: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicators", required: false }] }], tooltip: [{ type: i0.ViewChild, args: ['tooltip', { isSignal: true }] }] } });
13462
+ args: [{ selector: 'he-impact-assessments-indicator-breakdown-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HESvgIconComponent, FormsModule, NgbDropdownModule, HorizontalBarChartComponent], template: "<div class=\"is-mb-3\">\n <ng-content />\n</div>\n\n@if (logsResource.isLoading()) {\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n} @else if (terms()?.length) {\n <div class=\"is-flex is-align-items-center is-gap-12 is-mb-2 | breakdown-actions-table\">\n @if (terms()?.length) {\n <div class=\"control is-expanded is-flex-grow-1\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedTermId\" name=\"selectedTermId\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n @if (methods()?.length) {\n <div class=\"control is-expanded is-flex-shrink-0\">\n <div class=\"select is-fullwidth is-small\">\n <select [(ngModel)]=\"selectedMethodId\" name=\"selectedMethodId\">\n @if (methods().length > 1) {\n <option [ngValue]=\"undefined\">Filter Model</option>\n }\n @for (term of methods(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n }\n\n <div class=\"is-flex is-justify-content-space-between w-100\">\n <div ngbDropdown #optionDd=\"ngbDropdown\" container=\"body\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small\"\n type=\"button\"\n aria-haspopup=\"true\"\n aria-controls=\"download-menu\">\n <span class=\"is-pr-1 is-align-middle\">Download</span>\n <he-svg-icon name=\"chevron-down\" aria-hidden=\"true\" />\n </button>\n <div ngbDropdownMenu id=\"download-menu\" role=\"menu\">\n <div class=\"dropdown-content\">\n <a ngbDropdownItem (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\">\n <he-svg-icon size=\"20\" name=\"chart\" />\n <span class=\"is-pl-2 is-size-7\">Chart Image (.svg)</span>\n </a>\n\n <a ngbDropdownItem [href]=\"csvContent()\" [download]=\"downloadFilename()\">\n <he-svg-icon size=\"20\" name=\"table\" />\n <span class=\"is-pl-2 is-size-7\">Chart Data (.csv)</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"field is-relative is-mb-0 is-hidden-tablet\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n id=\"displayValue\"\n name=\"displayValue\"\n [(ngModel)]=\"displayValue\" />\n <label for=\"displayValue\">Show numerical value</label>\n </div>\n </div>\n </div>\n}\n\n@if (!logsResource.isLoading() && noData()) {\n <div class=\"chart-area-border\">\n <p class=\"has-text-centered\">\n <span>No breakdown available for</span>\n @if (selectedTerm()) {\n <span class=\"is-pl-1\">{{ selectedTerm().name }}</span>\n }\n @if (selectedMethod()) {\n <span class=\"is-pl-1\">({{ selectedMethod().name }})</span>\n }\n <span>.</span>\n </p>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [max]=\"total()\"\n [maximumValues]=\"maximumValues()\"\n [showExportButton]=\"false\"\n [showNegativeValues]=\"false\"\n [tooltipFn]=\"chartTooltipFn\"\n [afterBarDrawSettings]=\"afterBarDrawSettings()\" />\n", styles: [":host{display:block;overflow:visible}.shadow-tooltip{width:1px;height:1px;pointer-events:none}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}@media screen and (max-width: 767px){he-horizontal-bar-chart ::ng-deep .chart-container{min-height:200px}}@media screen and (max-width: 767px){.chart-area-border{padding:0}}@media screen and (max-width: 767px){.breakdown-actions-table{flex-direction:column;align-items:flex-start!important}}.breakdown-legend{background:#fafafa}.breakdown-legend--color{width:8px;height:8px;border-radius:50%}\n"] }]
13463
+ }], ctorParameters: () => [], propDecorators: { impactAssessment: [{ type: i0.Input, args: [{ isSignal: true, alias: "impactAssessment", required: true }] }], indicators: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicators", required: false }] }] } });
13487
13464
 
13488
13465
  const impactValue = (impact, values) => (values[impact['@id']]?.nodes[0] || { value: 0 }).value;
13489
13466
  const impactName = (impact, index) => `${index + 1}. ${defaultLabel(impact)}`;
@@ -13501,42 +13478,12 @@ class ImpactAssessmentsIndicatorsChartComponent {
13501
13478
  .map(({ term }) => term)
13502
13479
  .sort((a, b) => a.name.localeCompare(b.name)), ...(ngDevMode ? [{ debugName: "terms" }] : []));
13503
13480
  this.selectedTerm = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedTerm" }] : []));
13504
- this.labels = computed(() => this.impactAssessments().map(impactName), ...(ngDevMode ? [{ debugName: "labels" }] : []));
13505
- this.colors = computed(() => this.impactAssessments().map(listColor), ...(ngDevMode ? [{ debugName: "colors" }] : []));
13506
13481
  this.values = computed(() => this.indicatorPerImpactAssessment()?.[this.selectedTerm()?.name]?.values || {}, ...(ngDevMode ? [{ debugName: "values" }] : []));
13507
- this.datasets = computed(() => [
13508
- {
13509
- label: this.selectedTerm()?.name || '',
13510
- data: this.impactAssessments().map(impact => toPrecision(impactValue(impact, this.values()))),
13511
- backgroundColor: this.colors(),
13512
- borderColor: this.colors(),
13513
- barThickness: 2,
13514
- barPercentage: 1,
13515
- categoryPercentage: 1
13516
- }
13517
- ], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
13518
- this.chartConfig = computed(() => ({
13519
- plugins: [
13520
- lollipopChartPlugin(),
13521
- afterBarDrawPlugin({
13522
- xPosFn: (x, index, width, chart) => (x || chart.scales['x-axis-0'].getPixelForValue(0)) + 10,
13523
- textFn: ({ data }) => `${data}`,
13524
- colorFn: (m, index, chart, data) => (isUndefined(data) ? '#b5b5b5' : '#4a4a4a'),
13525
- emptyValueLabel: 'No value'
13526
- })
13527
- ],
13528
- options: {
13529
- scales: {
13530
- xAxes: [
13531
- {
13532
- scaleLabel: {
13533
- labelString: this.selectedTerm()?.units
13534
- }
13535
- }
13536
- ]
13537
- }
13538
- }
13539
- }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
13482
+ this.chartData = computed(() => this.impactAssessments().map((impact, index) => ({
13483
+ label: impactName(impact, index),
13484
+ count: impactValue(impact, this.values()),
13485
+ color: listColor(impact, index)
13486
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
13540
13487
  effect(() => {
13541
13488
  // make sure selected term exists
13542
13489
  const terms = this.terms();
@@ -13551,11 +13498,11 @@ class ImpactAssessmentsIndicatorsChartComponent {
13551
13498
  this.selectedTerm.set(term);
13552
13499
  }
13553
13500
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorsChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13554
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsIndicatorsChartComponent, isStandalone: true, selector: "he-impact-assessments-indicators-chart", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (terms()?.length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\" />\n</div>\n", styles: [":host{display:block;overflow:visible}he-bar-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: BarChartComponent, selector: "he-bar-chart", inputs: ["data", "max", "datasets", "labels", "config", "showExportButton"], exportAs: ["barChart"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13501
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: ImpactAssessmentsIndicatorsChartComponent, isStandalone: true, selector: "he-impact-assessments-indicators-chart", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" [config]=\"{ lollipopConfig: {} }\" />\n\n <ng-content />\n</div>\n\n@if (terms()?.length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [showExportButton]=\"false\" />\n", styles: [":host{display:block;overflow:visible}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "component", type: HorizontalBarChartComponent, selector: "he-horizontal-bar-chart", inputs: ["tooltipFn", "afterBarDrawSettings"], exportAs: ["horizontalBarChart"] }, { kind: "component", type: ChartExportButtonComponent, selector: "he-chart-export-button", inputs: ["chart", "config"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13555
13502
  }
13556
13503
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorsChartComponent, decorators: [{
13557
13504
  type: Component$1,
13558
- args: [{ selector: 'he-impact-assessments-indicators-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, NgbTooltip, BarChartComponent, HESvgIconComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg({ lollipopConfig: {} })\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (terms()?.length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-bar-chart\n #chart=\"barChart\"\n class=\"is-relative h-100\"\n [datasets]=\"datasets()\"\n [labels]=\"labels()\"\n [config]=\"chartConfig()\"\n [showExportButton]=\"false\" />\n</div>\n", styles: [":host{display:block;overflow:visible}he-bar-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
13505
+ args: [{ selector: 'he-impact-assessments-indicators-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, HorizontalBarChartComponent, ChartExportButtonComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" [config]=\"{ lollipopConfig: {} }\" />\n\n <ng-content />\n</div>\n\n@if (terms()?.length) {\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectTerm($event)\" id=\"selectTerm\">\n @for (term of terms(); track term) {\n <option [value]=\"term['@id']\">{{ term.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<he-horizontal-bar-chart\n #chart=\"horizontalBarChart\"\n class=\"is-relative h-100\"\n [title]=\"selectedTerm()?.units\"\n [data]=\"chartData()\"\n [showExportButton]=\"false\" />\n", styles: [":host{display:block;overflow:visible}he-horizontal-bar-chart ::ng-deep .chart-container{min-height:400px}\n"] }]
13559
13506
  }], ctorParameters: () => [], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }], filterTermTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypes", required: false }] }] } });
13560
13507
 
13561
13508
  var View$1;
@@ -13785,8 +13732,7 @@ class InputIndeterminateDirective {
13785
13732
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: InputIndeterminateDirective, decorators: [{
13786
13733
  type: Directive,
13787
13734
  args: [{
13788
- selector: 'input[indeterminate]',
13789
- standalone: true
13735
+ selector: 'input[indeterminate]'
13790
13736
  }]
13791
13737
  }], ctorParameters: () => [], propDecorators: { indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: true }] }] } });
13792
13738
 
@@ -13852,8 +13798,7 @@ class FilterAccordionGroupPipe {
13852
13798
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: FilterAccordionGroupPipe, decorators: [{
13853
13799
  type: Pipe,
13854
13800
  args: [{
13855
- name: 'filterAccordionGroup',
13856
- standalone: true
13801
+ name: 'filterAccordionGroup'
13857
13802
  }]
13858
13803
  }] });
13859
13804
  class FilterAccordionComponent extends ControlValueAccessor {
@@ -14036,8 +13981,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
14036
13981
  }], ctorParameters: () => [], propDecorators: { showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], showGlobalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGlobalSearch", required: false }] }], globalSearchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalSearchPlaceholder", required: false }] }], showClearAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearAll", required: false }] }], preserveOptionsOnSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "preserveOptionsOnSelection", required: false }] }], maintainPanelStates: [{ type: i0.Input, args: [{ isSignal: true, alias: "maintainPanelStates", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showGroupCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGroupCount", required: false }] }], selectionChanged: [{ type: i0.Output, args: ["selectionChanged"] }] } });
14037
13982
 
14038
13983
  const sortedPoints = (values) => Object.entries(values)
14039
- .map(([x, y]) => ({ x, y }))
14040
- .sort((a, b) => new Date(a.x).getTime() - new Date(b.x).getTime());
13984
+ .map(([x, y]) => ({ x: new Date(x).getTime(), y }))
13985
+ .sort((a, b) => a.x - b.x);
14041
13986
  class SitesManagementChartComponent {
14042
13987
  constructor() {
14043
13988
  this.nodeService = inject(HeNodeService);
@@ -14100,26 +14045,18 @@ class SitesManagementChartComponent {
14100
14045
  type: 'bar',
14101
14046
  options: {
14102
14047
  scales: {
14103
- xAxes: [
14104
- {
14105
- type: 'time',
14106
- time: {
14107
- unit: 'month'
14108
- },
14109
- stacked: true
14110
- }
14111
- ],
14112
- yAxes: [
14113
- {
14114
- position: 'left',
14115
- ticks: {
14116
- min: 0
14117
- // TODO: not all of them are in %
14118
- // userCallback: (label: string) => `${label}%`
14119
- },
14120
- stacked: true
14121
- }
14122
- ]
14048
+ x: {
14049
+ type: 'time',
14050
+ time: {
14051
+ unit: 'month'
14052
+ },
14053
+ stacked: true
14054
+ },
14055
+ y: {
14056
+ position: 'left',
14057
+ min: 0,
14058
+ stacked: true
14059
+ }
14123
14060
  }
14124
14061
  }
14125
14062
  };
@@ -14133,11 +14070,11 @@ class SitesManagementChartComponent {
14133
14070
  });
14134
14071
  }
14135
14072
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SitesManagementChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
14136
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: SitesManagementChartComponent, isStandalone: true, selector: "he-sites-management-chart", inputs: { site: { classPropertyName: "site", publicName: "site", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg()\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (termTypes().length > 1) {\n <he-horizontal-buttons-group\n [buttons]=\"termTypeButtons()\"\n [(ngModel)]=\"termTypeModel\"\n styles=\"primary\"\n class=\"is-hidden-mobile\" />\n\n <div class=\"field is-hidden-tablet\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select [(ngModel)]=\"termTypeModel\" if=\"termTypeModel\">\n @for (button of termTypeButtons(); track button.id) {\n <option [value]=\"button.id\">{{ button.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-chart #chart=\"chart\" class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig\" [showExportButton]=\"false\" />\n</div>\n\n<div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 is-mt-2 chart-area-border is-legend\">\n @for (color of chartColors() | keyvalue; track color.key) {\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <div class=\"legend-color\" [style.background-color]=\"color.value\"></div>\n <span class=\"is-size-7\">{{ color.key }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}he-chart ::ng-deep .chart-container{min-height:400px}he-horizontal-buttons-group ::ng-deep .tabs-list{border-bottom:none}.legend-container{background:#f5f7f9}.legend-color{width:20px;height:20px;border-radius:3px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }, { kind: "component", type: HorizontalButtonsGroupComponent, selector: "he-horizontal-buttons-group", inputs: ["buttons", "defaultSelectedIndex", "removable", "styles"], outputs: ["termRemoved"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
14073
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: SitesManagementChartComponent, isStandalone: true, selector: "he-sites-management-chart", inputs: { site: { classPropertyName: "site", publicName: "site", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" />\n\n <ng-content />\n</div>\n\n@if (termTypes().length > 1) {\n <he-horizontal-buttons-group\n [buttons]=\"termTypeButtons()\"\n [(ngModel)]=\"termTypeModel\"\n styles=\"primary\"\n class=\"is-hidden-mobile\" />\n\n <div class=\"field is-hidden-tablet\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select [(ngModel)]=\"termTypeModel\" if=\"termTypeModel\">\n @for (button of termTypeButtons(); track button.id) {\n <option [value]=\"button.id\">{{ button.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-chart #chart=\"chart\" class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig\" [showExportButton]=\"false\" />\n</div>\n\n<div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 is-mt-2 chart-area-border is-legend\">\n @for (color of chartColors() | keyvalue; track color.key) {\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <div class=\"legend-color\" [style.background-color]=\"color.value\"></div>\n <span class=\"is-size-7\">{{ color.key }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}he-chart ::ng-deep .chart-container{min-height:400px}he-horizontal-buttons-group ::ng-deep .tabs-list{border-bottom:none}.legend-container{background:#f5f7f9}.legend-color{width:20px;height:20px;border-radius:3px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }, { kind: "component", type: ChartExportButtonComponent, selector: "he-chart-export-button", inputs: ["chart", "config"] }, { kind: "component", type: HorizontalButtonsGroupComponent, selector: "he-horizontal-buttons-group", inputs: ["buttons", "defaultSelectedIndex", "removable", "styles"], outputs: ["termRemoved"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14137
14074
  }
14138
14075
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SitesManagementChartComponent, decorators: [{
14139
14076
  type: Component$1,
14140
- args: [{ selector: 'he-sites-management-chart', imports: [FormsModule, KeyValuePipe, NgbTooltip, ChartComponent, HorizontalButtonsGroupComponent, HESvgIconComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <button\n class=\"button is-small is-ghost\"\n (click)=\"chart.exportAsSvg()\"\n ngbTooltip=\"Download Chart (SVG)\"\n placement=\"right\">\n <he-svg-icon name=\"download\" />\n </button>\n\n <ng-content />\n</div>\n\n@if (termTypes().length > 1) {\n <he-horizontal-buttons-group\n [buttons]=\"termTypeButtons()\"\n [(ngModel)]=\"termTypeModel\"\n styles=\"primary\"\n class=\"is-hidden-mobile\" />\n\n <div class=\"field is-hidden-tablet\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select [(ngModel)]=\"termTypeModel\" if=\"termTypeModel\">\n @for (button of termTypeButtons(); track button.id) {\n <option [value]=\"button.id\">{{ button.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-chart #chart=\"chart\" class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig\" [showExportButton]=\"false\" />\n</div>\n\n<div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 is-mt-2 chart-area-border is-legend\">\n @for (color of chartColors() | keyvalue; track color.key) {\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <div class=\"legend-color\" [style.background-color]=\"color.value\"></div>\n <span class=\"is-size-7\">{{ color.key }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}he-chart ::ng-deep .chart-container{min-height:400px}he-horizontal-buttons-group ::ng-deep .tabs-list{border-bottom:none}.legend-container{background:#f5f7f9}.legend-color{width:20px;height:20px;border-radius:3px}\n"] }]
14077
+ args: [{ selector: 'he-sites-management-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, KeyValuePipe, ChartComponent, ChartExportButtonComponent, HorizontalButtonsGroupComponent], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-mb-3\">\n <he-chart-export-button [chart]=\"chart\" />\n\n <ng-content />\n</div>\n\n@if (termTypes().length > 1) {\n <he-horizontal-buttons-group\n [buttons]=\"termTypeButtons()\"\n [(ngModel)]=\"termTypeModel\"\n styles=\"primary\"\n class=\"is-hidden-mobile\" />\n\n <div class=\"field is-hidden-tablet\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select [(ngModel)]=\"termTypeModel\" if=\"termTypeModel\">\n @for (button of termTypeButtons(); track button.id) {\n <option [value]=\"button.id\">{{ button.name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n}\n\n<div class=\"chart-area-border\">\n <he-chart #chart=\"chart\" class=\"is-relative\" [data]=\"chartData()\" [config]=\"chartConfig\" [showExportButton]=\"false\" />\n</div>\n\n<div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 is-mt-2 chart-area-border is-legend\">\n @for (color of chartColors() | keyvalue; track color.key) {\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <div class=\"legend-color\" [style.background-color]=\"color.value\"></div>\n <span class=\"is-size-7\">{{ color.key }}</span>\n </div>\n }\n</div>\n", styles: [":host{display:block;overflow:visible}he-chart ::ng-deep .chart-container{min-height:400px}he-horizontal-buttons-group ::ng-deep .tabs-list{border-bottom:none}.legend-container{background:#f5f7f9}.legend-color{width:20px;height:20px;border-radius:3px}\n"] }]
14141
14078
  }], ctorParameters: () => [], propDecorators: { site: [{ type: i0.Input, args: [{ isSignal: true, alias: "site", required: true }] }] } });
14142
14079
 
14143
14080
  var View;
@@ -14320,5 +14257,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
14320
14257
  * Generated bundle index. Do not edit.
14321
14258
  */
14322
14259
 
14323
- export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, ColorPalette, CompoundDirective, CompoundPipe, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HESvgIconComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MendeleySearchResult, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, arrayValue, availableProperties, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorHasError, errorHasWarning, errorText, evaluateSuccess, exportAsSVG, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterError, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupChanged, groupLogsByModel, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, guidePageId, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isGroupVisible, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isMigrationError, isMissingOneOfError, isMissingPropertyError, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, localStorageSignal, locationQuery, logToCsv$1 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, missingNodeErrors, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage$1 as parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, singleProperty, siteTooBig, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueTypeToDefault, waitFor, wildcardQuery };
14260
+ export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, ColorPalette, CompoundDirective, CompoundPipe, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FileUploadErrorKeys, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HESvgIconComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalBarChartComponent, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MendeleySearchResult, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, arrayValue, availableProperties, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorHasError, errorHasWarning, errorText, evaluateSuccess, exportAsSVG, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterError, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupChanged, groupLogsByModel, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, guidePageId, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isGroupVisible, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isMigrationError, isMissingOneOfError, isMissingPropertyError, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, localStorageSignal, locationQuery, logToCsv$1 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, missingNodeErrors, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage$1 as parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, singleProperty, siteTooBig, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueTypeToDefault, waitFor, wildcardQuery };
14324
14261
  //# sourceMappingURL=hestia-earth-ui-components.mjs.map