@hestia-earth/ui-components 0.37.2 → 0.38.0

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
19
  import merge from 'lodash.merge';
20
+ import 'chartjs-adapter-date-fns';
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,11 @@ const downloadSvg = (svgElement) => {
1197
1150
  return downloadFile(url, 'chart.svg');
1198
1151
  };
1199
1152
 
1153
+ function registerChartDefaults() {
1154
+ // Register components only once to avoid warnings
1155
+ Chart.register(BarController, LineController, CategoryScale, LinearScale, PointElement, BarElement, LineElement, Title, Tooltip, Legend, TimeScale);
1156
+ }
1157
+
1200
1158
  class ChartConfigurationDirective {
1201
1159
  constructor() {
1202
1160
  this._zone = inject(NgZone);
@@ -1255,8 +1213,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
1255
1213
  type: Directive,
1256
1214
  args: [{
1257
1215
  selector: '[chartConfiguration]',
1258
- exportAs: 'chart',
1259
- standalone: true
1216
+ exportAs: 'chart'
1260
1217
  }]
1261
1218
  }], propDecorators: { chartConfiguration: [{
1262
1219
  type: Input
@@ -1268,85 +1225,207 @@ const defaultSettings$3 = Object.freeze({
1268
1225
  options: {
1269
1226
  responsive: true,
1270
1227
  maintainAspectRatio: false,
1271
- legend: {
1272
- display: false
1228
+ plugins: {
1229
+ legend: {
1230
+ display: false
1231
+ }
1273
1232
  }
1274
1233
  }
1275
1234
  });
1276
1235
  class ChartComponent {
1277
1236
  constructor() {
1278
- this.data = input({}, ...(ngDevMode ? [{ debugName: "data" }] : []));
1237
+ this.data = input(undefined, ...(ngDevMode ? [{ debugName: "data" }] : []));
1279
1238
  this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1280
1239
  this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1240
+ this.exporting = signal(false, ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1281
1241
  this.configuration = computed(() => ({
1282
1242
  ...merge({}, defaultSettings$3, this.config()),
1283
1243
  data: this.data()
1284
1244
  }), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1245
+ registerChartDefaults();
1285
1246
  }
1286
- exportAsSvg(config = {}) {
1287
- return exportAsSVG(this.configuration(), {
1247
+ async exportAsSvg(config = {}) {
1248
+ this.exporting.set(true);
1249
+ await exportAsSVG(this.configuration(), {
1288
1250
  width: 600,
1289
1251
  height: 400,
1290
1252
  fileName: 'chart.svg',
1291
1253
  ...config
1292
1254
  });
1255
+ this.exporting.set(false);
1293
1256
  }
1294
1257
  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 }); }
1258
+ 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
1259
  }
1297
1260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartComponent, decorators: [{
1298
1261
  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"] }]
1300
- }], 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 }] }] } });
1262
+ 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"] }]
1263
+ }], ctorParameters: () => [], 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
1264
 
1265
+ var Breakpoint;
1266
+ (function (Breakpoint) {
1267
+ Breakpoint["tablet"] = "tablet";
1268
+ Breakpoint["desktop"] = "desktop";
1269
+ Breakpoint["widescreen"] = "widescreen";
1270
+ Breakpoint["fullhd"] = "fullhd";
1271
+ })(Breakpoint || (Breakpoint = {}));
1272
+ const beakpointWidths = {
1273
+ [Breakpoint.tablet]: 768,
1274
+ [Breakpoint.desktop]: 1024,
1275
+ [Breakpoint.widescreen]: 1216,
1276
+ [Breakpoint.fullhd]: 1408
1277
+ };
1278
+ const toSize = (size, dir) => `(${dir}-width: ${dir === 'max' ? size - 1 : size}px)`;
1279
+ const toBreakpoint = ({ min, max }) => [min ? toSize(beakpointWidths[min], 'min') : '', max ? toSize(beakpointWidths[max], 'max') : '']
1280
+ .filter(Boolean)
1281
+ .join(' and ');
1282
+ class ResponsiveService {
1283
+ constructor() {
1284
+ this.breakPointObserver = inject(BreakpointObserver);
1285
+ this.windowWidth$ = fromEvent(window, 'resize').pipe(startWith(window.innerWidth), map(() => window.innerWidth));
1286
+ this.isMobile$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.tablet })).pipe(map(state => state.matches), distinctUntilChanged());
1287
+ this.isTablet$ = this.breakPointObserver
1288
+ .observe(toBreakpoint({ min: Breakpoint.tablet, max: Breakpoint.desktop }))
1289
+ .pipe(map(state => state.matches), distinctUntilChanged());
1290
+ this.isDesktop$ = this.breakPointObserver
1291
+ .observe(toBreakpoint({ min: Breakpoint.desktop, max: Breakpoint.widescreen }))
1292
+ .pipe(map(state => state.matches), distinctUntilChanged());
1293
+ this.isWidescreen$ = this.breakPointObserver
1294
+ .observe(toBreakpoint({ min: Breakpoint.widescreen, max: Breakpoint.fullhd }))
1295
+ .pipe(map(state => state.matches), distinctUntilChanged());
1296
+ this.isFullHd$ = this.breakPointObserver.observe(toBreakpoint({ min: Breakpoint.fullhd })).pipe(map(state => state.matches), distinctUntilChanged());
1297
+ this.isTouch$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.desktop })).pipe(map(state => state.matches), distinctUntilChanged());
1298
+ /**
1299
+ * Resolution for 1080p (or Full HD) on a normal screen, although bulma defines it differently.
1300
+ */
1301
+ this.is1080p$ = this.breakPointObserver.observe(toSize(1920, 'min')).pipe(map(state => state.matches), distinctUntilChanged());
1302
+ this.isRetinaDisplay = () => {
1303
+ if (window.matchMedia) {
1304
+ const mq = window.matchMedia([
1305
+ 'min--moz-device-pixel-ratio: 1.3',
1306
+ '-o-min-device-pixel-ratio: 2.6/2',
1307
+ '-webkit-min-device-pixel-ratio: 1.3',
1308
+ 'min-device-pixel-ratio: 1.3',
1309
+ 'min-resolution: 1.3dppx'
1310
+ ]
1311
+ .map(v => `only screen and (${v})`)
1312
+ .join(', '));
1313
+ return mq?.matches || window.devicePixelRatio > 1;
1314
+ }
1315
+ return false;
1316
+ };
1317
+ this.isMobile = toSignal(this.isMobile$);
1318
+ this.isTablet = toSignal(this.isTablet$);
1319
+ this.isDesktop = toSignal(this.isDesktop$);
1320
+ this.isWidescreen = toSignal(this.isWidescreen$);
1321
+ this.isFullHd = toSignal(this.isFullHd$);
1322
+ this.isTouch = toSignal(this.isTouch$);
1323
+ this.is1080p = toSignal(this.is1080p$);
1324
+ this.resolutionName = computed(() => this.isMobile()
1325
+ ? 'mobile'
1326
+ : this.isTablet()
1327
+ ? 'tablet'
1328
+ : this.isDesktop()
1329
+ ? 'desktop'
1330
+ : this.isWidescreen()
1331
+ ? 'widescreen'
1332
+ : 'fullhd', ...(ngDevMode ? [{ debugName: "resolutionName" }] : []));
1333
+ this.resolutionName$ = toObservable(this.resolutionName);
1334
+ }
1335
+ isAboveBreakpoint$(breakpoint) {
1336
+ return typeof breakpoint === 'number'
1337
+ ? this.windowWidth$.pipe(map(width => width >= breakpoint))
1338
+ : breakpoint === 'none'
1339
+ ? of(false)
1340
+ : this._isAboveBreakpointName$(breakpoint);
1341
+ }
1342
+ _isAboveBreakpointName$(breakpoint) {
1343
+ return this.resolutionName$.pipe(map(resolutionName => {
1344
+ const width = beakpointWidths[resolutionName];
1345
+ const overlapBreakpointWidth = beakpointWidths[breakpoint];
1346
+ return width >= overlapBreakpointWidth;
1347
+ }));
1348
+ }
1349
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1350
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, providedIn: 'root' }); }
1351
+ }
1352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResponsiveService, decorators: [{
1353
+ type: Injectable,
1354
+ args: [{
1355
+ providedIn: 'root'
1356
+ }]
1357
+ }] });
1358
+
1359
+ class BarChartLegendComponent {
1360
+ constructor() {
1361
+ this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1362
+ }
1363
+ trackByItem(item) {
1364
+ return Object.values(item).join('-');
1365
+ }
1366
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartLegendComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1367
+ 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 }); }
1368
+ }
1369
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartLegendComponent, decorators: [{
1370
+ type: Component$1,
1371
+ 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"] }]
1372
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
1373
+
1374
+ const grey = '#4a4a4a';
1302
1375
  const defaultSettings$2 = Object.freeze({
1303
- type: 'horizontalBar',
1376
+ type: 'bar',
1304
1377
  options: {
1305
1378
  animation: {
1306
1379
  duration: 0
1307
1380
  },
1308
- tooltips: {
1309
- enabled: false
1381
+ plugins: {
1382
+ legend: {
1383
+ align: 'start'
1384
+ },
1385
+ tooltip: {
1386
+ enabled: false
1387
+ }
1310
1388
  },
1311
1389
  scales: {
1312
- xAxes: [
1313
- {
1390
+ x: {
1391
+ display: true,
1392
+ min: 0,
1393
+ title: {
1314
1394
  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
1395
+ color: grey,
1396
+ font: {
1397
+ size: 14
1325
1398
  }
1326
1399
  }
1327
- ],
1328
- yAxes: [
1329
- {
1400
+ },
1401
+ y: {
1402
+ display: true,
1403
+ position: 'left',
1404
+ border: {
1405
+ display: true
1406
+ },
1407
+ grid: {
1330
1408
  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
1409
+ drawOnChartArea: true,
1410
+ drawTicks: true,
1411
+ tickLength: 8,
1412
+ offset: false
1413
+ },
1414
+ ticks: {
1415
+ color: grey,
1416
+ padding: 4,
1417
+ crossAlign: 'center',
1418
+ font: {
1419
+ family: 'Lato',
1420
+ size: 12,
1421
+ weight: 400
1339
1422
  },
1340
- ticks: {
1341
- fontColor: '#4a4a4a',
1342
- fontFamily: 'Lato',
1343
- fontSize: 12,
1344
- fontStyle: '400',
1345
- padding: 4,
1346
- crossAlign: 'center'
1423
+ callback: function (value) {
1424
+ const label = this.getLabelForValue(value);
1425
+ return ellipsis$1(label, 50);
1347
1426
  }
1348
1427
  }
1349
- ]
1428
+ }
1350
1429
  }
1351
1430
  }
1352
1431
  });
@@ -1357,43 +1436,93 @@ const defaultDatasets = {
1357
1436
  };
1358
1437
  class BarChartComponent {
1359
1438
  constructor() {
1360
- this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1439
+ this.responsiveService = inject(ResponsiveService);
1440
+ /**
1441
+ * X-axis label.
1442
+ */
1443
+ this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
1444
+ /**
1445
+ * Maximum value of the chart. If not supplied, the maximum is the highest value from the datasets.
1446
+ */
1361
1447
  this.max = input(...(ngDevMode ? [undefined, { debugName: "max" }] : []));
1362
1448
  this.datasets = input([], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
1449
+ this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1450
+ /**
1451
+ * When `datasets` is not provided, a single dataset is used from the `data` parameter, and this label is used.
1452
+ */
1453
+ this.datasetLabel = input('', ...(ngDevMode ? [{ debugName: "datasetLabel" }] : []));
1454
+ /**
1455
+ * If `data` is provided, the `labels` can be read from them. Otherwise use this to provide custom labels.
1456
+ */
1363
1457
  this.labels = input([], ...(ngDevMode ? [{ debugName: "labels" }] : []));
1458
+ /**
1459
+ * Override chart default configuration.
1460
+ */
1364
1461
  this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1462
+ /**
1463
+ * Show default button for export, located on the top-right corner of the chart.
1464
+ */
1365
1465
  this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1466
+ /**
1467
+ * If set to `false`, chart will show `0` instead if the value is negative.
1468
+ */
1469
+ this.showNegativeValues = input(true, ...(ngDevMode ? [{ debugName: "showNegativeValues" }] : []));
1470
+ /**
1471
+ * Maximum values to display on the chart.
1472
+ * All values not dislayed will be grouped together into a "summed" value.
1473
+ * Default is `20`.
1474
+ */
1475
+ this.maximumValues = input(20, ...(ngDevMode ? [{ debugName: "maximumValues" }] : []));
1476
+ this.hasNegativeContributions = computed(() => this.data()?.some(({ count }) => count < 0), ...(ngDevMode ? [{ debugName: "hasNegativeContributions" }] : []));
1366
1477
  this.chart = viewChild.required(ChartComponent);
1478
+ this.exporting = computed(() => this.chart()?.exporting(), ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1367
1479
  this.defaultConfig = computed(() => ({
1368
1480
  options: {
1369
- legend: {
1370
- align: 'start'
1371
- },
1372
1481
  scales: {
1373
- xAxes: [
1374
- {
1375
- display: true,
1376
- ticks: {
1377
- ...(this.max() ? { max: this.max() } : {})
1378
- }
1482
+ x: {
1483
+ display: !this.responsiveService.isMobile(),
1484
+ ...(this.max() ? { max: this.max() } : {}),
1485
+ title: {
1486
+ display: !!this.title(),
1487
+ text: this.title()
1379
1488
  }
1380
- ]
1489
+ }
1381
1490
  }
1382
1491
  }
1383
1492
  }), ...(ngDevMode ? [{ debugName: "defaultConfig" }] : []));
1493
+ this.maximumData = computed(() => {
1494
+ const data = this.data();
1495
+ const includedData = data.slice(0, this.maximumValues());
1496
+ const excludedData = data.slice(this.maximumValues());
1497
+ return [
1498
+ ...includedData,
1499
+ excludedData.length ? {
1500
+ label: `${excludedData.length} others`,
1501
+ count: sum(excludedData.map(({ count }) => count)),
1502
+ backgroundColor: excludedData[0].backgroundColor,
1503
+ borderColor: excludedData[0].borderColor,
1504
+ color: excludedData[0].color,
1505
+ includedItems: excludedData
1506
+ } : []
1507
+ ].flat();
1508
+ }, ...(ngDevMode ? [{ debugName: "maximumData" }] : []));
1384
1509
  this.defaultDatasets = computed(() => this.datasets()?.length
1385
- ? this.datasets()
1510
+ ? this.datasets().map(dataset => ({
1511
+ ...defaultDatasets,
1512
+ ...dataset
1513
+ }))
1386
1514
  : [
1387
1515
  {
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)
1516
+ ...defaultDatasets,
1517
+ backgroundColor: this.maximumData().map(({ backgroundColor, color }) => backgroundColor || color),
1518
+ borderColor: this.maximumData().map(({ borderColor, color }) => borderColor || color),
1519
+ data: this.maximumData().map(({ count }) => toPrecision(this.showNegativeValues() ? count : Math.max(0, count))),
1520
+ label: this.datasetLabel()
1392
1521
  }
1393
1522
  ], ...(ngDevMode ? [{ debugName: "defaultDatasets" }] : []));
1394
1523
  this.dataConfig = computed(() => ({
1395
1524
  datasets: this.defaultDatasets(),
1396
- labels: this.labels().length ? this.labels() : this.data().map(({ label }) => label)
1525
+ labels: this.labels().length ? this.labels() : this.maximumData().map(({ label }) => label)
1397
1526
  }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1398
1527
  this.configuration = computed(() => merge({}, defaultSettings$2, this.defaultConfig(), this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1399
1528
  }
@@ -1401,12 +1530,12 @@ class BarChartComponent {
1401
1530
  return this.chart().exportAsSvg(config);
1402
1531
  }
1403
1532
  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 }); }
1533
+ 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
1534
  }
1406
1535
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BarChartComponent, decorators: [{
1407
1536
  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 }] }] } });
1537
+ 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"] }]
1538
+ }], 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
1539
 
1411
1540
  const parsePrecision = (value, precision) => toPrecision(parseFloat(`${value}`), parseInt(`${precision}`, 10));
1412
1541
  const transform = (value, precision = 3, enableComma = true) => typeof value !== 'boolean' && !isUndefined(value) && isNumber(value)
@@ -1422,8 +1551,7 @@ class PrecisionPipe {
1422
1551
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: PrecisionPipe, decorators: [{
1423
1552
  type: Pipe,
1424
1553
  args: [{
1425
- name: 'precision',
1426
- standalone: true
1554
+ name: 'precision'
1427
1555
  }]
1428
1556
  }] });
1429
1557
 
@@ -1437,27 +1565,27 @@ const defaultSettings$1 = Object.freeze({
1437
1565
  options: {
1438
1566
  events: [],
1439
1567
  responsive: true,
1440
- tooltips: {
1441
- enabled: false
1442
- },
1443
- legend: {
1444
- display: false,
1445
- align: 'center'
1568
+ plugins: {
1569
+ tooltip: {
1570
+ enabled: false
1571
+ },
1572
+ legend: {
1573
+ display: false,
1574
+ align: 'center'
1575
+ }
1446
1576
  },
1447
1577
  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
- }
1578
+ y: {
1579
+ display: true,
1580
+ position: 'left',
1581
+ grid: {
1582
+ display: true
1583
+ },
1584
+ beginAtZero: true,
1585
+ ticks: {
1586
+ crossAlign: 'center'
1459
1587
  }
1460
- ]
1588
+ }
1461
1589
  }
1462
1590
  }
1463
1591
  });
@@ -1541,41 +1669,40 @@ class DistributionChartComponent {
1541
1669
  this.defaultConfig = computed(() => ({
1542
1670
  options: {
1543
1671
  scales: {
1544
- xAxes: [
1545
- {
1672
+ x: {
1673
+ display: true,
1674
+ grid: {
1675
+ offset: true
1676
+ },
1677
+ min: 0,
1678
+ ticks: {
1679
+ callback: (label) => label
1680
+ .split(joinXLabel)
1681
+ .map(parseFloat)
1682
+ .map(v => transform(v, 3, true))
1683
+ // .map(v => v.toExponential())
1684
+ .join('-')
1685
+ },
1686
+ title: {
1546
1687
  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
- }
1688
+ text: this.label()
1563
1689
  }
1564
- ],
1565
- yAxes: [
1566
- {
1567
- ticks: {
1568
- fontColor: '#4A4A4A',
1569
- fontFamily: 'Lato',
1570
- fontSize: 10,
1571
- fontStyle: '400'
1690
+ },
1691
+ y: {
1692
+ ticks: {
1693
+ font: {
1694
+ family: 'Lato',
1695
+ size: 10,
1696
+ style: 'normal',
1697
+ weight: 400
1572
1698
  },
1573
- scaleLabel: {
1574
- display: true,
1575
- labelString: 'Frequency of values'
1576
- }
1699
+ color: '#4A4A4A'
1700
+ },
1701
+ title: {
1702
+ display: true,
1703
+ text: 'Frequency of values'
1577
1704
  }
1578
- ]
1705
+ }
1579
1706
  }
1580
1707
  }
1581
1708
  }), ...(ngDevMode ? [{ debugName: "defaultConfig" }] : []));
@@ -1589,8 +1716,6 @@ class DistributionChartComponent {
1589
1716
  backgroundColor: opaqueColor(colors.lightBlue),
1590
1717
  borderColor: colors.lightBlue,
1591
1718
  borderWidth: 1,
1592
- fill: true,
1593
- pointRadius: 0,
1594
1719
  type: 'bar'
1595
1720
  },
1596
1721
  {
@@ -1604,7 +1729,7 @@ class DistributionChartComponent {
1604
1729
  type: 'line'
1605
1730
  }
1606
1731
  ]
1607
- : null,
1732
+ : [],
1608
1733
  this.singlePoint()?.length
1609
1734
  ? {
1610
1735
  label: 'Value',
@@ -1617,10 +1742,8 @@ class DistributionChartComponent {
1617
1742
  type: 'line',
1618
1743
  tension: 0
1619
1744
  }
1620
- : null
1621
- ]
1622
- .filter(Boolean)
1623
- .flat(),
1745
+ : []
1746
+ ].flat(),
1624
1747
  labels: this.groupedData().labels
1625
1748
  }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1626
1749
  this.configuration = computed(() => merge({}, defaultSettings$1, this.defaultConfig(), this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
@@ -1633,42 +1756,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
1633
1756
  args: [{ selector: 'he-distribution-chart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" />\n", styles: [":host{display:block}\n"] }]
1634
1757
  }], 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
1758
 
1636
- const defaultSettings = {
1759
+ const defaultSettings = Object.freeze({
1637
1760
  type: 'line',
1638
1761
  options: {
1639
1762
  scales: {
1640
- xAxes: [
1641
- {
1642
- type: 'time',
1643
- time: {
1644
- unit: 'day'
1763
+ x: {
1764
+ type: 'time',
1765
+ time: {
1766
+ unit: 'day'
1767
+ }
1768
+ }
1769
+ }
1770
+ }
1771
+ });
1772
+ class LineChartComponent {
1773
+ constructor() {
1774
+ this.datasets = input([], ...(ngDevMode ? [{ debugName: "datasets" }] : []));
1775
+ this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
1776
+ this.showExportButton = input(true, ...(ngDevMode ? [{ debugName: "showExportButton" }] : []));
1777
+ this.chart = viewChild.required(ChartComponent);
1778
+ this.exporting = computed(() => this.chart()?.exporting(), ...(ngDevMode ? [{ debugName: "exporting" }] : []));
1779
+ this.dataConfig = computed(() => ({
1780
+ datasets: this.datasets()
1781
+ }), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
1782
+ this.configuration = computed(() => merge({}, defaultSettings, this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
1783
+ }
1784
+ exportAsSvg(config = {}) {
1785
+ return this.chart().exportAsSvg(config);
1786
+ }
1787
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1788
+ 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 }); }
1789
+ }
1790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, decorators: [{
1791
+ type: Component$1,
1792
+ 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"] }]
1793
+ }], 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 }] }] } });
1794
+
1795
+ const defaultConfig = Object.freeze({
1796
+ options: {
1797
+ indexAxis: 'y',
1798
+ scales: {
1799
+ x: {
1800
+ grid: {
1801
+ drawOnChartArea: false
1802
+ },
1803
+ ticks: {
1804
+ callback: value => toPrecision(Number(value), 3)
1805
+ }
1806
+ },
1807
+ y: {
1808
+ grid: {
1809
+ drawOnChartArea: false
1810
+ },
1811
+ ticks: {
1812
+ crossAlign: 'near'
1813
+ }
1814
+ }
1815
+ }
1816
+ }
1817
+ });
1818
+ const defaultTooltipFn = ({ label, count, includedItems }) => includedItems.length ? includedItems.map(item => defaultTooltipFn(item)).join('</br>') : `${label}: ${count}`;
1819
+ class HorizontalBarChartComponent extends BarChartComponent {
1820
+ constructor() {
1821
+ super(...arguments);
1822
+ this.tooltipFn = input(defaultTooltipFn, ...(ngDevMode ? [{ debugName: "tooltipFn" }] : []));
1823
+ this.afterBarDrawSettings = input(...(ngDevMode ? [undefined, { debugName: "afterBarDrawSettings" }] : []));
1824
+ this.tooltip = viewChild.required('tooltip');
1825
+ this.horizontalConfiguration = computed(() => ({
1826
+ ...merge(this.configuration(), defaultConfig, {
1827
+ options: {
1828
+ onClick: (event, activeElements) => {
1829
+ const index = activeElements?.[0]?.index;
1830
+ !isUndefined(index) && this.showTooltip(index, event.x, event.y);
1831
+ },
1832
+ scales: {
1833
+ y: {
1834
+ display: !this.responsiveService.isMobile()
1835
+ }
1645
1836
  }
1646
1837
  }
1838
+ }),
1839
+ plugins: [
1840
+ lollipopChartPlugin(),
1841
+ backgroundHoverPlugin({ threshold: 5 }),
1842
+ afterBarDrawPlugin(this.afterBarDrawSettings()),
1843
+ ...(this.configuration().plugins ?? [])
1647
1844
  ]
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" }] : []));
1845
+ }), ...(ngDevMode ? [{ debugName: "horizontalConfiguration" }] : []));
1846
+ this.tooltipX = signal(0, ...(ngDevMode ? [{ debugName: "tooltipX" }] : []));
1847
+ this.tooltipY = signal(0, ...(ngDevMode ? [{ debugName: "tooltipY" }] : []));
1661
1848
  }
1662
- exportAsSvg(config = {}) {
1663
- return this.chart().exportAsSvg(config);
1849
+ showTooltip(index, x, y) {
1850
+ this.tooltipX.set(x);
1851
+ this.tooltipY.set(y);
1852
+ const data = this.maximumData()[index];
1853
+ const text = this.tooltipFn()(data || {}, index);
1854
+ text && setTimeout(() => this.tooltip().open({ data: text }));
1664
1855
  }
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 }); }
1856
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HorizontalBarChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1857
+ 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
1858
  }
1668
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LineChartComponent, decorators: [{
1859
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HorizontalBarChartComponent, decorators: [{
1669
1860
  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 }] }] } });
1861
+ 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"] }]
1862
+ }], 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
1863
 
1673
1864
  const ignoreCompounds = (value) => typeof value !== 'string' ||
1674
1865
  [
@@ -2703,8 +2894,7 @@ class ResizedDirective {
2703
2894
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ResizedDirective, decorators: [{
2704
2895
  type: Directive,
2705
2896
  args: [{
2706
- selector: '[resized]',
2707
- standalone: true
2897
+ selector: '[resized]'
2708
2898
  }]
2709
2899
  }], ctorParameters: () => [], propDecorators: { resized: [{ type: i0.Output, args: ["resized"] }] } });
2710
2900
 
@@ -2898,7 +3088,7 @@ class BlankNodeStateNoticeComponent {
2898
3088
  }
2899
3089
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: BlankNodeStateNoticeComponent, decorators: [{
2900
3090
  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"] }]
3091
+ 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
3092
  }], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }], showDeleted: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDeleted", required: false }] }] } });
2903
3093
 
2904
3094
  class BlankNodeValueDeltaComponent {
@@ -3199,100 +3389,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
3199
3389
  }, 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
3390
  }], 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
3391
 
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
3392
  const storageKey$2 = 'he-drawer-container';
3297
3393
  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
3394
  class DrawerContainerComponent {
@@ -3518,8 +3614,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
3518
3614
  type: Directive,
3519
3615
  args: [{
3520
3616
  selector: '[buttonScroller]',
3521
- exportAs: 'buttonScroller',
3522
- standalone: true
3617
+ exportAs: 'buttonScroller'
3523
3618
  }]
3524
3619
  }], propDecorators: { scrollUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollUnit", required: false }] }] } });
3525
3620
 
@@ -3549,8 +3644,7 @@ class LongPressDirective {
3549
3644
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: LongPressDirective, decorators: [{
3550
3645
  type: Directive,
3551
3646
  args: [{
3552
- selector: '[appLongPress]',
3553
- standalone: true
3647
+ selector: '[appLongPress]'
3554
3648
  }]
3555
3649
  }], propDecorators: { longPress: [{ type: i0.Output, args: ["longPress"] }], intervalMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervalMs", required: false }] }], onPressStart: [{
3556
3650
  type: HostListener,
@@ -3590,8 +3684,7 @@ class IsEllipsisActiveDirective {
3590
3684
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsEllipsisActiveDirective, decorators: [{
3591
3685
  type: Directive,
3592
3686
  args: [{
3593
- selector: '[isEllipsisActive]',
3594
- standalone: true
3687
+ selector: '[isEllipsisActive]'
3595
3688
  }]
3596
3689
  }] });
3597
3690
 
@@ -4109,7 +4202,7 @@ class SkeletonTextComponent {
4109
4202
  }
4110
4203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SkeletonTextComponent, decorators: [{
4111
4204
  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"] }]
4205
+ 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
4206
  }], 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
4207
  type: HostBinding,
4115
4208
  args: ['class.is-animated']
@@ -4148,8 +4241,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
4148
4241
  args: [{
4149
4242
  selector: 'he-social-tags',
4150
4243
  template: '',
4151
- changeDetection: ChangeDetectionStrategy.OnPush,
4152
- standalone: true
4244
+ changeDetection: ChangeDetectionStrategy.OnPush
4153
4245
  }]
4154
4246
  }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], classes: [{
4155
4247
  type: HostBinding,
@@ -4177,7 +4269,7 @@ class ToastComponent {
4177
4269
  }
4178
4270
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ToastComponent, decorators: [{
4179
4271
  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"] }]
4272
+ 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
4273
  }], ctorParameters: () => [] });
4182
4274
 
4183
4275
  /* eslint-disable prefer-spread */
@@ -4198,8 +4290,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
4198
4290
  type: Pipe,
4199
4291
  args: [{
4200
4292
  name: 'applyPure',
4201
- pure: true,
4202
- standalone: true
4293
+ pure: true
4203
4294
  }]
4204
4295
  }] });
4205
4296
 
@@ -4213,8 +4304,7 @@ class CapitalizePipe {
4213
4304
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CapitalizePipe, decorators: [{
4214
4305
  type: Pipe,
4215
4306
  args: [{
4216
- name: 'capitalize',
4217
- standalone: true
4307
+ name: 'capitalize'
4218
4308
  }]
4219
4309
  }] });
4220
4310
 
@@ -4265,8 +4355,7 @@ class ClickOutsideDirective {
4265
4355
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ClickOutsideDirective, decorators: [{
4266
4356
  type: Directive,
4267
4357
  args: [{
4268
- selector: '[clickOutside]',
4269
- standalone: true
4358
+ selector: '[clickOutside]'
4270
4359
  }]
4271
4360
  }], propDecorators: { clickOutsideListenAfter: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickOutsideListenAfter", required: false }] }], clickOutside: [{ type: i0.Output, args: ["clickOutside"] }] } });
4272
4361
 
@@ -4285,8 +4374,7 @@ class CompoundDirective {
4285
4374
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CompoundDirective, decorators: [{
4286
4375
  type: Directive,
4287
4376
  args: [{
4288
- selector: '[appCompound]',
4289
- standalone: true
4377
+ selector: '[appCompound]'
4290
4378
  }]
4291
4379
  }], 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
4380
 
@@ -4300,8 +4388,7 @@ class CompoundPipe {
4300
4388
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CompoundPipe, decorators: [{
4301
4389
  type: Pipe,
4302
4390
  args: [{
4303
- name: 'compound',
4304
- standalone: true
4391
+ name: 'compound'
4305
4392
  }]
4306
4393
  }] });
4307
4394
 
@@ -4315,8 +4402,7 @@ class DefaultPipe {
4315
4402
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: DefaultPipe, decorators: [{
4316
4403
  type: Pipe,
4317
4404
  args: [{
4318
- name: 'default',
4319
- standalone: true
4405
+ name: 'default'
4320
4406
  }]
4321
4407
  }] });
4322
4408
 
@@ -4350,8 +4436,7 @@ class DurationPipe {
4350
4436
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: DurationPipe, decorators: [{
4351
4437
  type: Pipe,
4352
4438
  args: [{
4353
- name: 'duration',
4354
- standalone: true
4439
+ name: 'duration'
4355
4440
  }]
4356
4441
  }] });
4357
4442
 
@@ -4365,8 +4450,7 @@ class EllipsisPipe {
4365
4450
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: EllipsisPipe, decorators: [{
4366
4451
  type: Pipe,
4367
4452
  args: [{
4368
- name: 'ellipsis',
4369
- standalone: true
4453
+ name: 'ellipsis'
4370
4454
  }]
4371
4455
  }] });
4372
4456
 
@@ -4380,8 +4464,7 @@ class FileSizePipe {
4380
4464
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: FileSizePipe, decorators: [{
4381
4465
  type: Pipe,
4382
4466
  args: [{
4383
- name: 'fileSize',
4384
- standalone: true
4467
+ name: 'fileSize'
4385
4468
  }]
4386
4469
  }] });
4387
4470
 
@@ -4395,8 +4478,7 @@ class GetPipe {
4395
4478
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: GetPipe, decorators: [{
4396
4479
  type: Pipe,
4397
4480
  args: [{
4398
- name: 'get',
4399
- standalone: true
4481
+ name: 'get'
4400
4482
  }]
4401
4483
  }] });
4402
4484
 
@@ -4410,8 +4492,7 @@ class IsArrayPipe {
4410
4492
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsArrayPipe, decorators: [{
4411
4493
  type: Pipe,
4412
4494
  args: [{
4413
- name: 'isArray',
4414
- standalone: true
4495
+ name: 'isArray'
4415
4496
  }]
4416
4497
  }] });
4417
4498
 
@@ -4425,8 +4506,7 @@ class IsObjectPipe {
4425
4506
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: IsObjectPipe, decorators: [{
4426
4507
  type: Pipe,
4427
4508
  args: [{
4428
- name: 'isObject',
4429
- standalone: true
4509
+ name: 'isObject'
4430
4510
  }]
4431
4511
  }] });
4432
4512
 
@@ -4484,8 +4564,7 @@ class KeyToLabelPipe {
4484
4564
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: KeyToLabelPipe, decorators: [{
4485
4565
  type: Pipe,
4486
4566
  args: [{
4487
- name: 'keyToLabel',
4488
- standalone: true
4567
+ name: 'keyToLabel'
4489
4568
  }]
4490
4569
  }] });
4491
4570
 
@@ -4499,8 +4578,7 @@ class NoExtPipe {
4499
4578
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: NoExtPipe, decorators: [{
4500
4579
  type: Pipe,
4501
4580
  args: [{
4502
- name: 'noExt',
4503
- standalone: true
4581
+ name: 'noExt'
4504
4582
  }]
4505
4583
  }] });
4506
4584
 
@@ -4514,8 +4592,7 @@ class PluralizePipe {
4514
4592
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: PluralizePipe, decorators: [{
4515
4593
  type: Pipe,
4516
4594
  args: [{
4517
- name: 'pluralize',
4518
- standalone: true
4595
+ name: 'pluralize'
4519
4596
  }]
4520
4597
  }] });
4521
4598
 
@@ -4529,8 +4606,7 @@ class RemoveMarkdownPipe {
4529
4606
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: RemoveMarkdownPipe, decorators: [{
4530
4607
  type: Pipe,
4531
4608
  args: [{
4532
- name: 'removeMarkdown',
4533
- standalone: true
4609
+ name: 'removeMarkdown'
4534
4610
  }]
4535
4611
  }] });
4536
4612
 
@@ -4544,8 +4620,7 @@ class RepeatPipe {
4544
4620
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: RepeatPipe, decorators: [{
4545
4621
  type: Pipe,
4546
4622
  args: [{
4547
- name: 'repeat',
4548
- standalone: true
4623
+ name: 'repeat'
4549
4624
  }]
4550
4625
  }] });
4551
4626
 
@@ -6103,8 +6178,7 @@ class TagsInputDirective {
6103
6178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: TagsInputDirective, decorators: [{
6104
6179
  type: Directive,
6105
6180
  args: [{
6106
- selector: '[appTagsInput]',
6107
- standalone: true
6181
+ selector: '[appTagsInput]'
6108
6182
  }]
6109
6183
  }], propDecorators: { appTagsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "appTagsInput", required: true }] }] } });
6110
6184
 
@@ -6118,8 +6192,7 @@ class ThousandSuffixesPipe {
6118
6192
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ThousandSuffixesPipe, decorators: [{
6119
6193
  type: Pipe,
6120
6194
  args: [{
6121
- name: 'thousandSuff',
6122
- standalone: true
6195
+ name: 'thousandSuff'
6123
6196
  }]
6124
6197
  }] });
6125
6198
 
@@ -6133,8 +6206,7 @@ class ThousandsPipe {
6133
6206
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ThousandsPipe, decorators: [{
6134
6207
  type: Pipe,
6135
6208
  args: [{
6136
- name: 'thousands',
6137
- standalone: true
6209
+ name: 'thousands'
6138
6210
  }]
6139
6211
  }] });
6140
6212
 
@@ -6148,8 +6220,7 @@ class TimesPipe {
6148
6220
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: TimesPipe, decorators: [{
6149
6221
  type: Pipe,
6150
6222
  args: [{
6151
- name: 'times',
6152
- standalone: true
6223
+ name: 'times'
6153
6224
  }]
6154
6225
  }] });
6155
6226
 
@@ -6163,8 +6234,7 @@ class UncapitalizePipe {
6163
6234
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: UncapitalizePipe, decorators: [{
6164
6235
  type: Pipe,
6165
6236
  args: [{
6166
- name: 'uncapitalize',
6167
- standalone: true
6237
+ name: 'uncapitalize'
6168
6238
  }]
6169
6239
  }] });
6170
6240
 
@@ -6178,8 +6248,7 @@ class SortByPipe {
6178
6248
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SortByPipe, decorators: [{
6179
6249
  type: Pipe,
6180
6250
  args: [{
6181
- name: 'sortBy',
6182
- standalone: true
6251
+ name: 'sortBy'
6183
6252
  }]
6184
6253
  }] });
6185
6254
 
@@ -8012,7 +8081,11 @@ class NodeLogsModelsComponent {
8012
8081
  this.nodeType = computed(() => nodeType(this.node()), ...(ngDevMode ? [{ debugName: "nodeType" }] : []));
8013
8082
  this.logsResource = rxResource({
8014
8083
  params: () => ({ node: this.node() }),
8015
- stream: ({ params: { node } }) => this.nodeService.getLog$({ ...node, dataState: DataState.recalculated })
8084
+ stream: ({ params: { node } }) => this.nodeService.getLog$({
8085
+ '@type': node['@type'],
8086
+ '@id': node['@id'],
8087
+ dataState: node.aggregated ? DataState.original : DataState.recalculated
8088
+ })
8016
8089
  });
8017
8090
  this.allLogs = computed(() => this.logsResource.value() ?? '', ...(ngDevMode ? [{ debugName: "allLogs" }] : []));
8018
8091
  this.hasLogs = computed(() => this.allLogs() !== '', ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
@@ -8285,20 +8358,34 @@ class CyclesCompletenessComponent {
8285
8358
  component.headerKeys.set(headerKeys$1);
8286
8359
  }
8287
8360
  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 }); }
8361
+ 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
8362
  }
8290
8363
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesCompletenessComponent, decorators: [{
8291
8364
  type: Component$1,
8292
8365
  args: [{ selector: 'he-cycles-completeness', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
8366
+ NgTemplateOutlet,
8293
8367
  HESvgIconComponent,
8294
8368
  DataTableComponent,
8295
8369
  NodeLinkComponent,
8296
8370
  BlankNodeStateComponent,
8297
8371
  BlankNodeStateNoticeComponent,
8298
8372
  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" }]
8373
+ ], 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
8374
  }], ctorParameters: () => [], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }] } });
8301
8375
 
8376
+ class ChartExportButtonComponent {
8377
+ constructor() {
8378
+ this.chart = input.required(...(ngDevMode ? [{ debugName: "chart" }] : []));
8379
+ this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
8380
+ }
8381
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartExportButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8382
+ 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 }); }
8383
+ }
8384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ChartExportButtonComponent, decorators: [{
8385
+ type: Component$1,
8386
+ 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" }]
8387
+ }], propDecorators: { chart: [{ type: i0.Input, args: [{ isSignal: true, alias: "chart", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
8388
+
8302
8389
  const cycleValue = (cycle, values) => (values[cycle['@id']]?.nodes[0] || { value: [0] }).value;
8303
8390
  const cycleName = (cycle, index) => `${index + 1}. ${defaultLabel(cycle)}`;
8304
8391
  class CyclesEmissionsChartComponent {
@@ -8306,46 +8393,17 @@ class CyclesEmissionsChartComponent {
8306
8393
  this.cycles = input.required(...(ngDevMode ? [{ debugName: "cycles" }] : []));
8307
8394
  this.emissionPerCycle = computed(() => groupNodesByTerm(this.cycles(), 'emissions'), ...(ngDevMode ? [{ debugName: "emissionPerCycle" }] : []));
8308
8395
  this.terms = computed(() => Object.values(this.emissionPerCycle() ?? {})
8309
- .filter(({ values }) => Object.values(values).some(({ nodes: [{ value }] }) => propertyValue$1(value) >= 0))
8396
+ .filter(({ values }) => Object.values(values).some(({ nodes: [{ value }] }) => propertyValue$1(value) > 0))
8310
8397
  .map(({ term }) => term)
8311
8398
  .sort((a, b) => a.name.localeCompare(b.name)), ...(ngDevMode ? [{ debugName: "terms" }] : []));
8312
8399
  this.selectedTerm = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedTerm" }] : []));
8313
8400
  this.labels = computed(() => this.cycles().map(cycleName), ...(ngDevMode ? [{ debugName: "labels" }] : []));
8314
- this.chartColors = computed(() => this.cycles().map(listColor), ...(ngDevMode ? [{ debugName: "chartColors" }] : []));
8315
8401
  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" }] : []));
8402
+ this.chartData = computed(() => this.cycles().map((cycle, index) => ({
8403
+ label: cycleName(cycle, index),
8404
+ count: propertyValue$1(cycleValue(cycle, this.chartValues()), this.selectedTerm?.['@id']),
8405
+ color: listColor(cycle, index)
8406
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
8349
8407
  effect(() => {
8350
8408
  // make sure selected term exists
8351
8409
  const terms = this.terms();
@@ -8360,11 +8418,11 @@ class CyclesEmissionsChartComponent {
8360
8418
  this.selectedTerm.set(term);
8361
8419
  }
8362
8420
  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"] }] }); }
8421
+ 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
8422
  }
8365
8423
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesEmissionsChartComponent, decorators: [{
8366
8424
  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"] }]
8425
+ 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
8426
  }], ctorParameters: () => [], propDecorators: { cycles: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycles", required: true }] }] } });
8369
8427
 
8370
8428
  class CyclesFunctionalUnitMeasureComponent {
@@ -8378,7 +8436,7 @@ class CyclesFunctionalUnitMeasureComponent {
8378
8436
  }
8379
8437
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesFunctionalUnitMeasureComponent, decorators: [{
8380
8438
  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"] }]
8439
+ 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
8440
  }], propDecorators: { cycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycle", required: true }] }] } });
8383
8441
 
8384
8442
  var View$3;
@@ -8651,7 +8709,7 @@ class CyclesNodesTimelineComponent {
8651
8709
  this.maxChart = computed(() => formatDate(this.maxDate(), false), ...(ngDevMode ? [{ debugName: "maxChart" }] : []));
8652
8710
  this.minChart = computed(() => this.minDate() ? formatDate(this.minDate(), true) : monthsBefore(this.maxChart(), 12), ...(ngDevMode ? [{ debugName: "minChart" }] : []));
8653
8711
  this.chartConfig = computed(() => ({
8654
- type: 'horizontalBar',
8712
+ type: 'bar',
8655
8713
  plugins: [
8656
8714
  lollipopChartPlugin({
8657
8715
  circleRadius: 6,
@@ -8659,64 +8717,62 @@ class CyclesNodesTimelineComponent {
8659
8717
  colorFn: () => colour
8660
8718
  }),
8661
8719
  afterBarDrawPlugin({
8662
- xPosFn: (x, index, width, chart) => (x || chart.scales['x-axis-0'].getPixelForValue(this.minChart())) + 10,
8663
- colorFn: () => '#b5b5b5',
8720
+ xPosFn: (x, index, width, chart) => (x || chart.scales.x.getPixelForValue(this.minChart().getTime())) + 10,
8664
8721
  emptyValueLabel: 'No dates available'
8665
8722
  })
8666
8723
  ],
8667
8724
  options: {
8668
- legend: {
8669
- display: false
8670
- },
8671
- tooltips: {
8672
- mode: 'point',
8673
- enabled: false,
8674
- intersect: true,
8675
- axis: 'y'
8725
+ indexAxis: 'y',
8726
+ plugins: {
8727
+ legend: {
8728
+ display: false
8729
+ },
8730
+ tooltip: {
8731
+ mode: 'point',
8732
+ enabled: false,
8733
+ intersect: true,
8734
+ axis: 'y'
8735
+ }
8676
8736
  },
8677
8737
  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
- }
8738
+ x: {
8739
+ type: 'time',
8740
+ time: {
8741
+ unit: 'month'
8742
+ },
8743
+ max: this.maxChart().getTime(),
8744
+ ...(this.minChart() ? { min: this.minChart().getTime() } : {}),
8745
+ stacked: false,
8746
+ grid: {
8747
+ drawOnChartArea: false
8692
8748
  }
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
- }
8749
+ },
8750
+ y: {
8751
+ stacked: true,
8752
+ border: {
8753
+ display: true
8754
+ },
8755
+ grid: {
8756
+ display: true,
8757
+ drawOnChartArea: false,
8758
+ drawTicks: true,
8759
+ tickLength: 8,
8760
+ offset: false
8761
+ },
8762
+ ticks: {
8763
+ padding: 4
8708
8764
  }
8709
- ]
8765
+ }
8710
8766
  }
8711
8767
  }
8712
8768
  }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
8713
8769
  }
8714
8770
  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"] }] }); }
8771
+ 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
8772
  }
8717
8773
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesNodesTimelineComponent, decorators: [{
8718
8774
  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"] }]
8775
+ 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
8776
  }], 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
8777
 
8722
8778
  class TermsUnitsDescriptionComponent {
@@ -8809,7 +8865,7 @@ class CyclesNodesComponent {
8809
8865
  this.View = View$2;
8810
8866
  this.viewIcon = viewIcon$2;
8811
8867
  this.showView = computed(() => ({
8812
- [View$2.chart]: this.selectedNodeKey() === BlankNodesKey.emissions && this.cycles().length > 1,
8868
+ [View$2.chart]: [this.isEmission() && this.cycles().length > 1].some(Boolean),
8813
8869
  [View$2.logs]: !this.isOriginal() && this.hasRecalculatedNodes(),
8814
8870
  [View$2.table]: true,
8815
8871
  [View$2.timeline]: this.enableTimeline()
@@ -8955,7 +9011,7 @@ class CyclesResultComponent {
8955
9011
  backgroundColor: color,
8956
9012
  borderColor: color,
8957
9013
  barPercentage: 0.5,
8958
- data: this.cycles().map(({ '@id': id }) => (values[id] ? propertyValue$1(values[id].value, termId) : 0))
9014
+ data: this.cycles().map(({ '@id': id }) => values[id] ? propertyValue$1(values[id].value, termId) : 0)
8959
9015
  };
8960
9016
  }), ...(ngDevMode ? [{ debugName: "chartDatasets" }] : []));
8961
9017
  this.chartData = computed(() => ({
@@ -8963,41 +9019,37 @@ class CyclesResultComponent {
8963
9019
  labels: this.chartLabels()
8964
9020
  }), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
8965
9021
  this.chartConfig = {
8966
- type: 'horizontalBar',
9022
+ type: 'bar',
8967
9023
  options: {
8968
- legend: {
8969
- display: true
8970
- },
8971
- tooltips: {
8972
- callbacks: {
8973
- title: (tooltipItems, data) => data.labels[tooltipItems[0].index]
9024
+ indexAxis: 'y',
9025
+ plugins: {
9026
+ legend: {
9027
+ display: true
9028
+ },
9029
+ tooltip: {
9030
+ callbacks: {
9031
+ title: tooltipItems => tooltipItems[0].label
9032
+ }
8974
9033
  }
8975
9034
  },
8976
9035
  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
- }
9036
+ x: {
9037
+ min: 0
9038
+ },
9039
+ y: {
9040
+ position: 'left',
9041
+ title: {
9042
+ display: true,
9043
+ text: 'Cycle'
8991
9044
  }
8992
- ]
9045
+ }
8993
9046
  }
8994
9047
  }
8995
9048
  };
8996
- Chart$1.scaleService.updateScaleDefaults('category', {
8997
- ticks: {
8998
- callback: tick => ellipsis(`${tick}`, 25)
8999
- }
9000
- });
9049
+ Chart.defaults.scales.category.ticks.callback = function (val) {
9050
+ const label = this.getLabelForValue(val);
9051
+ return ellipsis(`${label}`, 25);
9052
+ };
9001
9053
  }
9002
9054
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: CyclesResultComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9003
9055
  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 +9454,16 @@ class NodeAggregatedQualityScoreComponent {
9402
9454
  : of(undefined)
9403
9455
  });
9404
9456
  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
9457
  this.logsResource = rxResource({
9407
9458
  params: () => ({
9408
9459
  showInfo: this.showInfo(),
9409
- node: this.node(),
9410
- aggregationId: this.aggregationId()
9460
+ node: this.node()
9411
9461
  }),
9412
- stream: ({ params: { showInfo, node, aggregationId } }) => showInfo && aggregationId
9462
+ stream: ({ params: { showInfo, node } }) => showInfo
9413
9463
  ? this.nodeService
9414
9464
  .getLog$({
9415
9465
  '@type': node['@type'],
9416
- '@id': aggregationId,
9417
- aggregated: true
9466
+ '@id': node['@id']
9418
9467
  })
9419
9468
  .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
9469
  : of({})
@@ -9845,7 +9894,7 @@ class EngineModelsStageComponent {
9845
9894
  }
9846
9895
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: EngineModelsStageComponent, decorators: [{
9847
9896
  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"] }]
9897
+ 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
9898
  }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }] } });
9850
9899
 
9851
9900
  class EngineModelsVersionLinkComponent {
@@ -12035,31 +12084,31 @@ ${JSON.stringify(error)}
12035
12084
  /label ~"Priority::MEDIUM"
12036
12085
  /label ~"Tracking::Triage"
12037
12086
  `.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 = {}));
12087
+ var FileUploadErrorKeys;
12088
+ (function (FileUploadErrorKeys) {
12089
+ FileUploadErrorKeys["PrivacyNotAllowed"] = "privacy-not-allowed";
12090
+ FileUploadErrorKeys["NoData"] = "no-data";
12091
+ FileUploadErrorKeys["NoHeaders"] = "no-headers";
12092
+ FileUploadErrorKeys["InvalidJSON"] = "invalid-json";
12093
+ FileUploadErrorKeys["InvalidSheetName"] = "invalid-sheet-name";
12094
+ FileUploadErrorKeys["InvalidFirstColumn"] = "invalid-first-column";
12095
+ FileUploadErrorKeys["InvalidExcelFile"] = "invalid-excel-file";
12096
+ FileUploadErrorKeys["DuplicatedHeaders"] = "duplicated-headers";
12097
+ FileUploadErrorKeys["DuplicatedIds"] = "duplicated-ids";
12098
+ FileUploadErrorKeys["PropertyRequired"] = "property-required";
12099
+ FileUploadErrorKeys["PropertyInternal"] = "property-internal";
12100
+ FileUploadErrorKeys["UploadsLimit"] = "upload-limit";
12101
+ FileUploadErrorKeys["NestedHeaders"] = "nested-headers";
12102
+ FileUploadErrorKeys["NestedNodes"] = "nested-nodes";
12103
+ FileUploadErrorKeys["ReferenceExistingHeaders"] = "reference-existing-headers";
12104
+ FileUploadErrorKeys["MultipleTermHeaders"] = "multiple-term-headers";
12105
+ FileUploadErrorKeys["MaxSize"] = "max-size";
12106
+ FileUploadErrorKeys["InvalidBlankNodeHeaders"] = "invalid-blank-node-headers";
12107
+ FileUploadErrorKeys["MaxRows"] = "max-rows";
12108
+ FileUploadErrorKeys["Mendeley"] = "'content-type'";
12109
+ FileUploadErrorKeys["Timeout"] = "TimeoutError: Timeout has occurred";
12110
+ FileUploadErrorKeys["SetValueError"] = "set-value-failed";
12111
+ })(FileUploadErrorKeys || (FileUploadErrorKeys = {}));
12063
12112
  const valueToNodes = (value, type) => Array.isArray(value)
12064
12113
  ? isExpandable(value)
12065
12114
  ? value.map(val => ({
@@ -12107,14 +12156,14 @@ class FilesUploadErrorsComponent {
12107
12156
  this.hasGeoJSONError = computed(() => this.error()?.error?.includes('Unable to parse GeoJSON value'), ...(ngDevMode ? [{ debugName: "hasGeoJSONError" }] : []));
12108
12157
  this.schemaUrl = computed(() => [schemaBaseUrl(this.file()?.schemaVersion), this.error()?.schema].filter(Boolean).join('/'), ...(ngDevMode ? [{ debugName: "schemaUrl" }] : []));
12109
12158
  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" }] : []));
12159
+ this.isSchemaError = computed(() => [ErrorKeys.PropertyNotFound, ErrorKeys.SchemaNotFound].includes(this.error()?.message), ...(ngDevMode ? [{ debugName: "isSchemaError" }] : []));
12111
12160
  this.showJsonPreview = computed(() => !!this.error()?.node && this.isJSONFile(), ...(ngDevMode ? [{ debugName: "showJsonPreview" }] : []));
12112
12161
  this.showCsvPreview = computed(() => this.headers().length && this.rows().length && !this.isSchemaError() && !this.isJSONFile(), ...(ngDevMode ? [{ debugName: "showCsvPreview" }] : []));
12113
12162
  this.reportErrorUrl = computed(() => issueLink(this.file()?.pipelineStatus || this.file()?.status, this.message()), ...(ngDevMode ? [{ debugName: "reportErrorUrl" }] : []));
12114
12163
  this.baseUrl = baseUrl();
12115
12164
  this.nodeTypes = acceptedTypes;
12116
- this.SchemaErrorKeys = ErrorKeys$1;
12117
- this.ErrorKeys = ErrorKeys;
12165
+ this.SchemaErrorKeys = ErrorKeys;
12166
+ this.ErrorKeys = FileUploadErrorKeys;
12118
12167
  this.maxFileSizeMb = maxFileSizeMb;
12119
12168
  this.columns = signal([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
12120
12169
  this.headers = signal([], ...(ngDevMode ? [{ debugName: "headers" }] : []));
@@ -13052,11 +13101,11 @@ class HierarchyChartComponent {
13052
13101
  return downloadSvg(this.chart().nativeElement);
13053
13102
  }
13054
13103
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HierarchyChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13055
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: HierarchyChartComponent, isStandalone: true, selector: "he-hierarchy-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, terms: { classPropertyName: "terms", publicName: "terms", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartError: "chartError" }, viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true, isSignal: true }, { propertyName: "zoomContainer", first: true, predicate: ["zoomContainer"], descendants: true, isSignal: true }, { propertyName: "chartContainer", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }, { propertyName: "tooltipOperator", first: true, predicate: ["t"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"chart-area-border\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 chart-area-border is-legend\">\n @for (legendItem of legend(); track legendItem.type) {\n <div class=\"is-flex is-align-items-center is-gap-8 | is-legend-item\">\n <span\n class=\"is-inline-block-tablet is-align-middle | key-colour\"\n [style.backgroundColor]=\"nodeColours[legendItem.type]\"\n [style.borderColor]=\"nodeBorderColours[legendItem.type]\"></span>\n <span class=\"is-size-7\">{{ legendItem.text }}</span>\n </div>\n }\n </div>\n\n <div class=\"chart-container is-relative w-100 is-mt-2\">\n <svg class=\"w-100 h-100\" #chart>\n <g #zoomContainer>\n <g #chartContainer></g>\n </g>\n </svg>\n\n <span\n class=\"is-hidden\"\n [ngbPopover]=\"tipContent\"\n triggers=\"manual\"\n placement=\"right left auto\"\n container=\"body\"\n #t=\"ngbPopover\"\n positionTarget=\".tip-target\"\n popoverClass=\"is-narrow driver-chart-tooltip\"\n [animation]=\"true\"></span>\n\n <div class=\"is-absolute | zoom-controls\">\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n <button class=\"button is-small\" (click)=\"zoomIn()\">\n <he-svg-icon name=\"plus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"zoomOut()\">\n <he-svg-icon name=\"minus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"downloadSvg()\">\n <he-svg-icon name=\"download\" size=\"20\" />\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tipContent let-tipData=\"tipData\">\n @if (tipData.hasWeightedValue) {\n <p>contribution: {{ tipData.weightedValueText }}</p>\n }\n @if (tipData.valueValueText) {\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.valueKeyHref\">value</a>\n <span class=\"is-pr-1\">:</span>\n <span>{{ tipData.valueValueText }}</span>\n @if (tipData.hasValue) {\n <a class=\"is-dark is-ml-2\" [href]=\"tipData.modelDocsHref\" target=\"_blank\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </p>\n }\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelKeyHref\">methodModel</a>\n <span class=\"is-pr-1\">:</span>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelValueHref\">{{ tipData.modelValue }}</a>\n </p>\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.termKeyHref\">terms</a>\n <span class=\"is-pr-1\">:</span>\n @for (term of tipData.terms; track term.text; let lastTerm = $last) {\n <a class=\"is-dark\" target=\"_blank\" [href]=\"term.href\">{{ term.text }}</a>\n @if (!lastTerm) {\n <span class=\"is-px-1\">;</span>\n }\n }\n </p>\n</ng-template>\n", styles: [".chart-container{height:500px}@media screen and (min-width: 1216px){.is-legend-item{min-width:130px}}.zoom-controls{top:0;right:0}.zoom-controls .button{width:36px;height:36px}.key-colour{border-radius:3px;border:1px solid transparent;height:20px;width:20px}svg{pointer-events:none}:host ::ng-deep .node-box{fill-opacity:.3;stroke-opacity:.3;pointer-events:auto}:host ::ng-deep .node-openable:not(.mask-openable){cursor:pointer;stroke-opacity:1;fill-opacity:1}:host ::ng-deep .group-button,:host ::ng-deep .group-button-text{display:inline!important;cursor:pointer;pointer-events:auto}:host ::ng-deep .node-label tspan{alignment-baseline:inherit}:host ::ng-deep .sibling-mask{pointer-events:none}:host ::ng-deep .mask-openable{cursor:pointer;pointer-events:all}:host ::ng-deep .mask-openable:hover{fill:none;stroke:none}\n"], dependencies: [{ kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }] }); }
13104
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.13", type: HierarchyChartComponent, isStandalone: true, selector: "he-hierarchy-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, terms: { classPropertyName: "terms", publicName: "terms", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartError: "chartError" }, viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true, isSignal: true }, { propertyName: "zoomContainer", first: true, predicate: ["zoomContainer"], descendants: true, isSignal: true }, { propertyName: "chartContainer", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }, { propertyName: "tooltipOperator", first: true, predicate: ["t"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"chart-area-border\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 chart-area-border is-legend\">\n @for (legendItem of legend(); track legendItem.type) {\n <div class=\"is-flex is-align-items-center is-gap-8 | is-legend-item\">\n <span\n class=\"is-inline-block-tablet is-align-middle | key-colour\"\n [style.backgroundColor]=\"nodeColours[legendItem.type]\"\n [style.borderColor]=\"nodeBorderColours[legendItem.type]\"></span>\n <span class=\"is-size-7\">{{ legendItem.text }}</span>\n </div>\n }\n </div>\n\n <div class=\"chart-container is-relative w-100 is-mt-2\">\n <svg class=\"w-100 h-100\" #chart>\n <g #zoomContainer>\n <g #chartContainer></g>\n </g>\n </svg>\n\n <span\n class=\"is-hidden\"\n [ngbPopover]=\"tipContent\"\n triggers=\"manual\"\n placement=\"right left auto\"\n container=\"body\"\n #t=\"ngbPopover\"\n positionTarget=\".tip-target\"\n popoverClass=\"is-narrow driver-chart-tooltip\"\n [animation]=\"true\"></span>\n\n <div class=\"is-absolute | zoom-controls\">\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n <button class=\"button is-small\" (click)=\"zoomIn()\">\n <he-svg-icon name=\"plus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"zoomOut()\">\n <he-svg-icon name=\"minus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"downloadSvg()\">\n <he-svg-icon name=\"download\" size=\"20\" />\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tipContent let-tipData=\"tipData\">\n @if (tipData.hasWeightedValue) {\n <p>contribution: {{ tipData.weightedValueText }}</p>\n }\n @if (tipData.valueValueText) {\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.valueKeyHref\">value</a>\n <span class=\"is-pr-1\">:</span>\n <span>{{ tipData.valueValueText }}</span>\n @if (tipData.hasValue) {\n <a class=\"is-dark is-ml-2\" [href]=\"tipData.modelDocsHref\" target=\"_blank\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </p>\n }\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelKeyHref\">methodModel</a>\n <span class=\"is-pr-1\">:</span>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelValueHref\">{{ tipData.modelValue }}</a>\n </p>\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.termKeyHref\">terms</a>\n <span class=\"is-pr-1\">:</span>\n @for (term of tipData.terms; track term.text; let lastTerm = $last) {\n <a class=\"is-dark\" target=\"_blank\" [href]=\"term.href\">{{ term.text }}</a>\n @if (!lastTerm) {\n <span class=\"is-px-1\">;</span>\n }\n }\n </p>\n</ng-template>\n", styles: [".chart-container{height:500px}@media screen and (min-width: 1216px){.is-legend-item{min-width:130px}}.zoom-controls{top:0;right:0}.zoom-controls .button{width:36px;height:36px}.key-colour{border-radius:3px;border:1px solid transparent;height:20px;width:20px}svg{pointer-events:none}:host ::ng-deep .node-box{fill-opacity:.3;stroke-opacity:.3;pointer-events:auto}:host ::ng-deep .node-openable:not(.mask-openable){cursor:pointer;stroke-opacity:1;fill-opacity:1}:host ::ng-deep .group-button,:host ::ng-deep .group-button-text{display:inline!important;cursor:pointer}:host ::ng-deep .node-label tspan{alignment-baseline:inherit}:host ::ng-deep .sibling-mask{pointer-events:none}:host ::ng-deep .mask-openable{cursor:pointer;pointer-events:all}:host ::ng-deep .mask-openable:hover{fill:none;stroke:none}\n"], dependencies: [{ kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }] }); }
13056
13105
  }
13057
13106
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: HierarchyChartComponent, decorators: [{
13058
13107
  type: Component$1,
13059
- args: [{ selector: 'he-hierarchy-chart', imports: [NgbPopover, HESvgIconComponent], template: "<div class=\"chart-area-border\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 chart-area-border is-legend\">\n @for (legendItem of legend(); track legendItem.type) {\n <div class=\"is-flex is-align-items-center is-gap-8 | is-legend-item\">\n <span\n class=\"is-inline-block-tablet is-align-middle | key-colour\"\n [style.backgroundColor]=\"nodeColours[legendItem.type]\"\n [style.borderColor]=\"nodeBorderColours[legendItem.type]\"></span>\n <span class=\"is-size-7\">{{ legendItem.text }}</span>\n </div>\n }\n </div>\n\n <div class=\"chart-container is-relative w-100 is-mt-2\">\n <svg class=\"w-100 h-100\" #chart>\n <g #zoomContainer>\n <g #chartContainer></g>\n </g>\n </svg>\n\n <span\n class=\"is-hidden\"\n [ngbPopover]=\"tipContent\"\n triggers=\"manual\"\n placement=\"right left auto\"\n container=\"body\"\n #t=\"ngbPopover\"\n positionTarget=\".tip-target\"\n popoverClass=\"is-narrow driver-chart-tooltip\"\n [animation]=\"true\"></span>\n\n <div class=\"is-absolute | zoom-controls\">\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n <button class=\"button is-small\" (click)=\"zoomIn()\">\n <he-svg-icon name=\"plus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"zoomOut()\">\n <he-svg-icon name=\"minus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"downloadSvg()\">\n <he-svg-icon name=\"download\" size=\"20\" />\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tipContent let-tipData=\"tipData\">\n @if (tipData.hasWeightedValue) {\n <p>contribution: {{ tipData.weightedValueText }}</p>\n }\n @if (tipData.valueValueText) {\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.valueKeyHref\">value</a>\n <span class=\"is-pr-1\">:</span>\n <span>{{ tipData.valueValueText }}</span>\n @if (tipData.hasValue) {\n <a class=\"is-dark is-ml-2\" [href]=\"tipData.modelDocsHref\" target=\"_blank\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </p>\n }\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelKeyHref\">methodModel</a>\n <span class=\"is-pr-1\">:</span>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelValueHref\">{{ tipData.modelValue }}</a>\n </p>\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.termKeyHref\">terms</a>\n <span class=\"is-pr-1\">:</span>\n @for (term of tipData.terms; track term.text; let lastTerm = $last) {\n <a class=\"is-dark\" target=\"_blank\" [href]=\"term.href\">{{ term.text }}</a>\n @if (!lastTerm) {\n <span class=\"is-px-1\">;</span>\n }\n }\n </p>\n</ng-template>\n", styles: [".chart-container{height:500px}@media screen and (min-width: 1216px){.is-legend-item{min-width:130px}}.zoom-controls{top:0;right:0}.zoom-controls .button{width:36px;height:36px}.key-colour{border-radius:3px;border:1px solid transparent;height:20px;width:20px}svg{pointer-events:none}:host ::ng-deep .node-box{fill-opacity:.3;stroke-opacity:.3;pointer-events:auto}:host ::ng-deep .node-openable:not(.mask-openable){cursor:pointer;stroke-opacity:1;fill-opacity:1}:host ::ng-deep .group-button,:host ::ng-deep .group-button-text{display:inline!important;cursor:pointer;pointer-events:auto}:host ::ng-deep .node-label tspan{alignment-baseline:inherit}:host ::ng-deep .sibling-mask{pointer-events:none}:host ::ng-deep .mask-openable{cursor:pointer;pointer-events:all}:host ::ng-deep .mask-openable:hover{fill:none;stroke:none}\n"] }]
13108
+ args: [{ selector: 'he-hierarchy-chart', imports: [NgbPopover, HESvgIconComponent], template: "<div class=\"chart-area-border\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap is-gap-16 chart-area-border is-legend\">\n @for (legendItem of legend(); track legendItem.type) {\n <div class=\"is-flex is-align-items-center is-gap-8 | is-legend-item\">\n <span\n class=\"is-inline-block-tablet is-align-middle | key-colour\"\n [style.backgroundColor]=\"nodeColours[legendItem.type]\"\n [style.borderColor]=\"nodeBorderColours[legendItem.type]\"></span>\n <span class=\"is-size-7\">{{ legendItem.text }}</span>\n </div>\n }\n </div>\n\n <div class=\"chart-container is-relative w-100 is-mt-2\">\n <svg class=\"w-100 h-100\" #chart>\n <g #zoomContainer>\n <g #chartContainer></g>\n </g>\n </svg>\n\n <span\n class=\"is-hidden\"\n [ngbPopover]=\"tipContent\"\n triggers=\"manual\"\n placement=\"right left auto\"\n container=\"body\"\n #t=\"ngbPopover\"\n positionTarget=\".tip-target\"\n popoverClass=\"is-narrow driver-chart-tooltip\"\n [animation]=\"true\"></span>\n\n <div class=\"is-absolute | zoom-controls\">\n <div class=\"is-flex is-flex-direction-column is-gap-4\">\n <button class=\"button is-small\" (click)=\"zoomIn()\">\n <he-svg-icon name=\"plus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"zoomOut()\">\n <he-svg-icon name=\"minus\" size=\"20\" />\n </button>\n <button class=\"button is-small\" (click)=\"downloadSvg()\">\n <he-svg-icon name=\"download\" size=\"20\" />\n </button>\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tipContent let-tipData=\"tipData\">\n @if (tipData.hasWeightedValue) {\n <p>contribution: {{ tipData.weightedValueText }}</p>\n }\n @if (tipData.valueValueText) {\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.valueKeyHref\">value</a>\n <span class=\"is-pr-1\">:</span>\n <span>{{ tipData.valueValueText }}</span>\n @if (tipData.hasValue) {\n <a class=\"is-dark is-ml-2\" [href]=\"tipData.modelDocsHref\" target=\"_blank\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </p>\n }\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelKeyHref\">methodModel</a>\n <span class=\"is-pr-1\">:</span>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.modelValueHref\">{{ tipData.modelValue }}</a>\n </p>\n <p>\n <a class=\"is-dark\" target=\"_blank\" [href]=\"tipData.termKeyHref\">terms</a>\n <span class=\"is-pr-1\">:</span>\n @for (term of tipData.terms; track term.text; let lastTerm = $last) {\n <a class=\"is-dark\" target=\"_blank\" [href]=\"term.href\">{{ term.text }}</a>\n @if (!lastTerm) {\n <span class=\"is-px-1\">;</span>\n }\n }\n </p>\n</ng-template>\n", styles: [".chart-container{height:500px}@media screen and (min-width: 1216px){.is-legend-item{min-width:130px}}.zoom-controls{top:0;right:0}.zoom-controls .button{width:36px;height:36px}.key-colour{border-radius:3px;border:1px solid transparent;height:20px;width:20px}svg{pointer-events:none}:host ::ng-deep .node-box{fill-opacity:.3;stroke-opacity:.3;pointer-events:auto}:host ::ng-deep .node-openable:not(.mask-openable){cursor:pointer;stroke-opacity:1;fill-opacity:1}:host ::ng-deep .group-button,:host ::ng-deep .group-button-text{display:inline!important;cursor:pointer}:host ::ng-deep .node-label tspan{alignment-baseline:inherit}:host ::ng-deep .sibling-mask{pointer-events:none}:host ::ng-deep .mask-openable{cursor:pointer;pointer-events:all}:host ::ng-deep .mask-openable:hover{fill:none;stroke:none}\n"] }]
13060
13109
  }], ctorParameters: () => [], propDecorators: { chart: [{ type: i0.ViewChild, args: ['chart', { isSignal: true }] }], zoomContainer: [{ type: i0.ViewChild, args: ['zoomContainer', { isSignal: true }] }], chartContainer: [{ type: i0.ViewChild, args: ['chartContainer', { isSignal: true }] }], tooltipOperator: [{ type: i0.ViewChild, args: ['t', { isSignal: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], terms: [{ type: i0.Input, args: [{ isSignal: true, alias: "terms", required: false }] }], chartError: [{ type: i0.Output, args: ["chartError"] }] } });
13061
13110
 
13062
13111
  const filterTermTypes$1 = [
@@ -13234,11 +13283,11 @@ class ImpactAssessmentsGraphComponent {
13234
13283
  effect(() => this.showWarnings.set(this.warnings()?.length > 0));
13235
13284
  }
13236
13285
  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"] }] }); }
13286
+ 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
13287
  }
13239
13288
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsGraphComponent, decorators: [{
13240
13289
  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"] }]
13290
+ 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
13291
  }], 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
13292
 
13244
13293
  const parseLog = (data) => ({
@@ -13263,13 +13312,12 @@ const logsTotalValue = (logs, includeNegativeValues) => sum((includeNegativeValu
13263
13312
  const valueRatio = (value, total) => toPrecision((value * 100) / total, 2);
13264
13313
  const chartLabel = (value, total) => {
13265
13314
  const ratio = valueRatio(value, total);
13266
- return value === 0 ? '0' : `${toPrecision(value, 3)}, ${ratio}%`;
13315
+ return value === 0 ? '0' : `${value}, ${ratio}%`;
13267
13316
  };
13268
13317
  const chartBreakdownLabel = (logs, total, maxValues) => {
13269
13318
  const values = logs.slice(maxValues);
13270
13319
  return values.map(({ blankNodeTermId, value }) => `${blankNodeTermId}: ${chartLabel(value, total)}`).join('</br>');
13271
13320
  };
13272
- const chartTextColor = (value) => (isUndefined(value) ? '#b5b5b5' : '#4a4a4a');
13273
13321
  const logToCsv = (logs, impact) => [
13274
13322
  csvHeaders.join(','),
13275
13323
  ...logs
@@ -13288,7 +13336,6 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13288
13336
  this.responsiveService = inject(ResponsiveService);
13289
13337
  this.impactAssessment = input.required(...(ngDevMode ? [{ debugName: "impactAssessment" }] : []));
13290
13338
  this.indicators = input([], ...(ngDevMode ? [{ debugName: "indicators" }] : []));
13291
- this.tooltip = viewChild.required('tooltip');
13292
13339
  this.maximumValues = computed(() => (this.responsiveService.isMobile() ? 10 : 20), ...(ngDevMode ? [{ debugName: "maximumValues" }] : []));
13293
13340
  this.logsResource = rxResource({
13294
13341
  params: () => ({
@@ -13305,7 +13352,10 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13305
13352
  ].filter(v => v.term['@id'] === log.blankNodeTermId);
13306
13353
  const inputs = blankNodes
13307
13354
  .filter(v => v.inputs?.length)
13308
- .map(v => ({ name: v.inputs.map(i => i['@id']).join(';'), value: v.value * log.coefficient }));
13355
+ .map(v => ({
13356
+ name: v.inputs.map(i => i['@id']).join(';'),
13357
+ value: toPrecision(v.value * log.coefficient, 3)
13358
+ }));
13309
13359
  const inputsValue = inputs.reduce((prev, curr) => prev + curr.value, 0);
13310
13360
  const impact = impacts?.find(v => v.term['@id'] === log.impactTermId);
13311
13361
  // logs might exist but impact was not added => skip logs
@@ -13313,7 +13363,7 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13313
13363
  ? {
13314
13364
  ...log,
13315
13365
  impactTermUnits: impact.term?.units,
13316
- value: total,
13366
+ value: toPrecision(total, 3),
13317
13367
  inputs,
13318
13368
  inputsValue
13319
13369
  }
@@ -13355,93 +13405,34 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13355
13405
  ...(this.impactAssessment()?.endpoints || [])
13356
13406
  ], ...(ngDevMode ? [{ debugName: "impacts" }] : []));
13357
13407
  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" }] : []));
13408
+ this.values = computed(() => this.nonZeroLogs().map((value, index) => ({
13409
+ ...value,
13410
+ name: this.emissions()?.find(v => v['@id'] === value.blankNodeTermId)?.name || value.blankNodeTermId,
13411
+ color: listColor(value, index)
13412
+ })), ...(ngDevMode ? [{ debugName: "values" }] : []));
13383
13413
  this.csvContent = computed(() => this.domSanitizer.bypassSecurityTrustResourceUrl(`data:text/html;charset=utf-8,${encodeURIComponent(logToCsv(this.logs(), this.impactAssessment()))}`), ...(ngDevMode ? [{ debugName: "csvContent" }] : []));
13384
13414
  this.id = computed(() => this.impactAssessment()?.['@id'] || this.impactAssessment()?.id, ...(ngDevMode ? [{ debugName: "id" }] : []));
13385
13415
  this.downloadFilename = computed(() => `${this.id()}-logs.csv`, ...(ngDevMode ? [{ debugName: "downloadFilename" }] : []));
13386
13416
  this.displayValue = signal(false, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
13387
13417
  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
- }
13418
+ this.chartData = computed(() => this.values().map(value => ({
13419
+ label: value.name,
13420
+ count: value.value,
13421
+ backgroundColor: value.color
13422
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
13423
+ this.chartTooltipFn = ({ includedItems }, index) => {
13424
+ const { value } = this.values()[index] || {};
13425
+ return !isUndefined(value)
13426
+ ? includedItems?.length
13427
+ ? chartBreakdownLabel(this.nonZeroLogs(), this.total(), this.maximumValues())
13428
+ : chartLabel(value, this.total())
13429
+ : '';
13430
+ };
13431
+ this.afterBarDrawSettings = computed(() => (this.displayValue()
13432
+ ? {
13433
+ textFn: ({ label, data }, index) => (index === this.maximumValues() ? `${label} at ${data}` : `${data}`)
13441
13434
  }
13442
- }), ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
13443
- this.tooltipX = signal(0, ...(ngDevMode ? [{ debugName: "tooltipX" }] : []));
13444
- this.tooltipY = signal(0, ...(ngDevMode ? [{ debugName: "tooltipY" }] : []));
13435
+ : { textFn: ({ data }) => `${valueRatio(data, this.total())}%` }), ...(ngDevMode ? [{ debugName: "afterBarDrawSettings" }] : []));
13445
13436
  // make sure selected term exists
13446
13437
  effect(() => {
13447
13438
  const terms = this.terms();
@@ -13466,24 +13457,13 @@ class ImpactAssessmentsIndicatorBreakdownChartComponent {
13466
13457
  trackByLog({ blankNodeTermId, modelId, impactTermId }) {
13467
13458
  return [blankNodeTermId, modelId, impactTermId].join('-');
13468
13459
  }
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
13460
  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 }); }
13461
+ 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
13462
  }
13483
13463
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorBreakdownChartComponent, decorators: [{
13484
13464
  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 }] }] } });
13465
+ 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"] }]
13466
+ }], 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
13467
 
13488
13468
  const impactValue = (impact, values) => (values[impact['@id']]?.nodes[0] || { value: 0 }).value;
13489
13469
  const impactName = (impact, index) => `${index + 1}. ${defaultLabel(impact)}`;
@@ -13501,42 +13481,12 @@ class ImpactAssessmentsIndicatorsChartComponent {
13501
13481
  .map(({ term }) => term)
13502
13482
  .sort((a, b) => a.name.localeCompare(b.name)), ...(ngDevMode ? [{ debugName: "terms" }] : []));
13503
13483
  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
13484
  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" }] : []));
13485
+ this.chartData = computed(() => this.impactAssessments().map((impact, index) => ({
13486
+ label: impactName(impact, index),
13487
+ count: impactValue(impact, this.values()),
13488
+ color: listColor(impact, index)
13489
+ })), ...(ngDevMode ? [{ debugName: "chartData" }] : []));
13540
13490
  effect(() => {
13541
13491
  // make sure selected term exists
13542
13492
  const terms = this.terms();
@@ -13551,11 +13501,11 @@ class ImpactAssessmentsIndicatorsChartComponent {
13551
13501
  this.selectedTerm.set(term);
13552
13502
  }
13553
13503
  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 }); }
13504
+ 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
13505
  }
13556
13506
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: ImpactAssessmentsIndicatorsChartComponent, decorators: [{
13557
13507
  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"] }]
13508
+ 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
13509
  }], 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
13510
 
13561
13511
  var View$1;
@@ -13785,8 +13735,7 @@ class InputIndeterminateDirective {
13785
13735
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: InputIndeterminateDirective, decorators: [{
13786
13736
  type: Directive,
13787
13737
  args: [{
13788
- selector: 'input[indeterminate]',
13789
- standalone: true
13738
+ selector: 'input[indeterminate]'
13790
13739
  }]
13791
13740
  }], ctorParameters: () => [], propDecorators: { indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: true }] }] } });
13792
13741
 
@@ -13852,8 +13801,7 @@ class FilterAccordionGroupPipe {
13852
13801
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: FilterAccordionGroupPipe, decorators: [{
13853
13802
  type: Pipe,
13854
13803
  args: [{
13855
- name: 'filterAccordionGroup',
13856
- standalone: true
13804
+ name: 'filterAccordionGroup'
13857
13805
  }]
13858
13806
  }] });
13859
13807
  class FilterAccordionComponent extends ControlValueAccessor {
@@ -14036,8 +13984,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
14036
13984
  }], 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
13985
 
14038
13986
  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());
13987
+ .map(([x, y]) => ({ x: new Date(x).getTime(), y }))
13988
+ .sort((a, b) => a.x - b.x);
14041
13989
  class SitesManagementChartComponent {
14042
13990
  constructor() {
14043
13991
  this.nodeService = inject(HeNodeService);
@@ -14100,26 +14048,18 @@ class SitesManagementChartComponent {
14100
14048
  type: 'bar',
14101
14049
  options: {
14102
14050
  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
- ]
14051
+ x: {
14052
+ type: 'time',
14053
+ time: {
14054
+ unit: 'month'
14055
+ },
14056
+ stacked: true
14057
+ },
14058
+ y: {
14059
+ position: 'left',
14060
+ min: 0,
14061
+ stacked: true
14062
+ }
14123
14063
  }
14124
14064
  }
14125
14065
  };
@@ -14133,11 +14073,11 @@ class SitesManagementChartComponent {
14133
14073
  });
14134
14074
  }
14135
14075
  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" }] }); }
14076
+ 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
14077
  }
14138
14078
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImport: i0, type: SitesManagementChartComponent, decorators: [{
14139
14079
  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"] }]
14080
+ 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
14081
  }], ctorParameters: () => [], propDecorators: { site: [{ type: i0.Input, args: [{ isSignal: true, alias: "site", required: true }] }] } });
14142
14082
 
14143
14083
  var View;
@@ -14320,5 +14260,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.13", ngImpo
14320
14260
  * Generated bundle index. Do not edit.
14321
14261
  */
14322
14262
 
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 };
14263
+ 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, 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
14264
  //# sourceMappingURL=hestia-earth-ui-components.mjs.map