@hestia-earth/ui-components 0.42.14 → 0.42.16

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.
@@ -9,11 +9,11 @@ import { NgbTooltip, NgbDropdown, NgbDropdownMenu, NgbDropdownToggle, NgbActiveM
9
9
  import { ReplaySubject, of, mergeMap, shareReplay, delay, map, catchError, distinctUntilChanged, timer, take, first, Subject, combineLatest, filter, fromEvent, startWith, merge, skip, switchMap, EMPTY, throttleTime, animationFrameScheduler, debounceTime, takeUntil, lastValueFrom, tap, skipUntil, zip, mergeAll, reduce, forkJoin, throwError, from, firstValueFrom, toArray, distinct, groupBy } from 'rxjs';
10
10
  import { HttpClient } from '@angular/common/http';
11
11
  import get from 'lodash.get';
12
- import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, uniquenessFields, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, isTypeBlankNode, typeToSchemaType, infrastructureTermTermType, managementTermTermType } from '@hestia-earth/schema';
12
+ import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, uniquenessFields, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, typeToSchemaType, infrastructureTermTermType, managementTermTermType } from '@hestia-earth/schema';
13
13
  import Gradient from 'javascript-color-gradient';
14
14
  import { ShadeGenerator } from 'shade-generator/dist/shadeGenerator';
15
15
  import { select, selectAll } from 'd3-selection';
16
- import { isEmpty, unique, monthsBefore, toPrecision, isNumber, isUndefined, toComma, duration, keyToLabel, sum, min, max, mean, median, ellipsis as ellipsis$1, getPercentileValue, isEqual as isEqual$2, toDashCase, diffInDays } from '@hestia-earth/utils';
16
+ import { isEmpty, unique, monthsBefore, toPrecision, isNumber, isUndefined, toComma, duration, keyToLabel, sum, min, max, mean, median, ellipsis as ellipsis$1, getPercentileValue, isEqual as isEqual$2, diffInDays } from '@hestia-earth/utils';
17
17
  import { json2csv } from 'json-2-csv';
18
18
  import { propertyValue as propertyValue$1, emptyValue } from '@hestia-earth/utils/term';
19
19
  import { getDefaultModelId, getModelGroup, loadResourceKey, getArrayTreatment, isInSystemBoundary } from '@hestia-earth/glossary';
@@ -46,7 +46,8 @@ import set from 'lodash.set';
46
46
  import * as semver from 'semver';
47
47
  import { parse } from 'papaparse';
48
48
  import omit from 'lodash.omit';
49
- import { validationsByMessage } from '@hestia-earth/data-validation';
49
+ import { createErrorFormatter, htmlRenderer, isMigrationError, isMissingPropertyError, missingNodeErrors, isMissingOneOfError, errorHasWarning, errorHasError, guidePageId, filterError } from '@hestia-earth/ui-components/file-errors';
50
+ export { errorHasError, errorHasWarning, filterError, guidePageId, isMigrationError, isMissingOneOfError, isMissingPropertyError, missingNodeErrors } from '@hestia-earth/ui-components/file-errors';
50
51
  import { format, subDays, parseISO } from 'date-fns';
51
52
  import { enGB } from 'date-fns/locale';
52
53
  import { MarkdownComponent } from 'ngx-markdown';
@@ -11481,7 +11482,7 @@ class CyclesNodesComponent {
11481
11482
  const index = (cycle?.[groupKey] || []).findIndex(n => n?.[idKey] === node[idKey]);
11482
11483
  return index >= 0 ? index : undefined;
11483
11484
  }, ...(ngDevMode ? [{ debugName: "jlogParentIndex" }] : []));
11484
- this.groupNodeValues = computed(() => unique(this.groupedNodes().map(value => value[this.groupNodeKey()])), ...(ngDevMode ? [{ debugName: "groupNodeValues" }] : []));
11485
+ this.groupNodeValues = computed(() => unique(this.groupedNodes().map(value => ({ value: value[this.groupNodeKey()], term: value.term }))), ...(ngDevMode ? [{ debugName: "groupNodeValues" }] : []));
11485
11486
  this.isGroupNode = computed(() => this.nodeKeyGroup() && this.groupedNodes()?.length > 0, ...(ngDevMode ? [{ debugName: "isGroupNode" }] : []));
11486
11487
  this.isEmission = computed(() => this.selectedNodeKey() === BlankNodesKey.emissions, ...(ngDevMode ? [{ debugName: "isEmission" }] : []));
11487
11488
  this.data = computed(() => this.isEmission()
@@ -11508,8 +11509,11 @@ class CyclesNodesComponent {
11508
11509
  }
11509
11510
  });
11510
11511
  effect(() => {
11511
- if (!this.selectedGroup() || !this.groupNodeValues().includes(this.selectedGroup())) {
11512
- this.selectedGroup.set(this.groupNodeValues()[0]);
11512
+ const values = this.groupNodeValues()
11513
+ .map(v => v.value)
11514
+ .filter(Boolean);
11515
+ if (values.length && (!this.selectedGroup() || !values.includes(this.selectedGroup()))) {
11516
+ this.selectedGroup.set(values[0]);
11513
11517
  }
11514
11518
  });
11515
11519
  effect(() => {
@@ -11548,22 +11552,23 @@ class CyclesNodesComponent {
11548
11552
  component.headerKeys.set(this.headerKeys());
11549
11553
  }
11550
11554
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesNodesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11551
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesNodesComponent, isStandalone: true, selector: "he-cycles-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKeys: { classPropertyName: "nodeKeys", publicName: "nodeKeys", isSignal: true, isRequired: true, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select another\n cycle above.\n </p>\n }\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 is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\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\n<ng-template #selectCycle>\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 is-nowrap\" 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</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { 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: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "component", type: CyclesFunctionalUnitMeasureComponent, selector: "he-cycles-functional-unit-measure", inputs: ["cycle"] }, { 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: 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: CyclesEmissionsChartComponent, selector: "he-cycles-emissions-chart", inputs: ["cycles"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CyclesNodesTimelineComponent, selector: "he-cycles-nodes-timeline", inputs: ["values", "maxDate", "minDate"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { 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.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: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11555
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesNodesComponent, isStandalone: true, selector: "he-cycles-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKeys: { classPropertyName: "nodeKeys", publicName: "nodeKeys", isSignal: true, isRequired: true, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li\n [class.is-active]=\"selectedGroup() === value.value\"\n [ngbTooltip]=\"value.term.name\"\n placement=\"top\"\n container=\"body\">\n <a (click)=\"selectedGroup.set(value.value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value.value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select another\n cycle above.\n </p>\n }\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 is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\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\n<ng-template #selectCycle>\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 is-nowrap\" 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</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: "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: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { 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: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "component", type: CyclesFunctionalUnitMeasureComponent, selector: "he-cycles-functional-unit-measure", inputs: ["cycle"] }, { 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: CyclesEmissionsChartComponent, selector: "he-cycles-emissions-chart", inputs: ["cycles"] }, { kind: "component", type: CyclesNodesTimelineComponent, selector: "he-cycles-nodes-timeline", inputs: ["values", "maxDate", "minDate"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { 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.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: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11552
11556
  }
11553
11557
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesNodesComponent, decorators: [{
11554
11558
  type: Component$1,
11555
11559
  args: [{ selector: 'he-cycles-nodes', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
11560
+ NgTemplateOutlet,
11561
+ NgbPopover,
11562
+ NgbTooltip,
11556
11563
  HESvgIconComponent,
11557
11564
  SearchExtendComponent,
11558
11565
  DataTableComponent,
11559
11566
  NodeLinkComponent,
11560
11567
  TermsUnitsDescriptionComponent,
11561
11568
  CyclesFunctionalUnitMeasureComponent,
11562
- NgbPopover,
11563
11569
  BlankNodeStateComponent,
11564
11570
  BlankNodeStateNoticeComponent,
11565
11571
  CyclesEmissionsChartComponent,
11566
- NgTemplateOutlet,
11567
11572
  CyclesNodesTimelineComponent,
11568
11573
  NodeLogsModelsComponent,
11569
11574
  NodeValueDetailsComponent,
@@ -11574,7 +11579,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
11574
11579
  KeyToLabelPipe,
11575
11580
  PrecisionPipe,
11576
11581
  PluralizePipe
11577
- ], template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select another\n cycle above.\n </p>\n }\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 is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\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\n<ng-template #selectCycle>\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 is-nowrap\" 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</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"] }]
11582
+ ], template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li\n [class.is-active]=\"selectedGroup() === value.value\"\n [ngbTooltip]=\"value.term.name\"\n placement=\"top\"\n container=\"body\">\n <a (click)=\"selectedGroup.set(value.value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value.value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select another\n cycle above.\n </p>\n }\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 is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\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\n<ng-template #selectCycle>\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 is-nowrap\" 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</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"] }]
11578
11583
  }], ctorParameters: () => [], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }], nodeKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKeys", required: true }] }], nodeKeyGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKeyGroup", required: false }] }] } });
11579
11584
 
11580
11585
  class CyclesResultComponent {
@@ -12580,706 +12585,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
12580
12585
  ], template: "<form class=\"needs-validation mt-3\" novalidate [formGroup]=\"form\">\n <div class=\"field is-horizontal\">\n <div class=\"field-label is-normal\">\n <label class=\"label\" for=\"productTermId\">\n <span>Product Term ID</span>\n </label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\" [class.has-icons-right]=\"suggestingProductTermId()\">\n <input\n class=\"input\"\n formControlName=\"productTermId\"\n name=\"productTermId\"\n placeholder=\"Search product by ID or name\"\n [editable]=\"false\"\n [ngbTypeahead]=\"suggestProductTermId\"\n [resultTemplate]=\"suggestionProductTermId\"\n [inputFormatter]=\"inputFormatterProductTermId\" />\n <span class=\"icon is-right has-text-grey-dark\" [class.is-hidden]=\"!suggestingProductTermId()\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"20\" />\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"field is-horizontal mt-3\">\n <div class=\"field-label is-normal\">\n <label class=\"label\" for=\"productTermType\">\n <span>Product Term Type</span>\n </label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-fullwidth\">\n <select formControlName=\"productTermType\" name=\"productTermType\">\n <option [ngValue]=\"undefined\">Select a Type</option>\n @for (termType of productTermTermType; track termType) {\n <option [value]=\"termType\">\n {{ termType | keyToLabel }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"field is-horizontal mt-3\">\n <div class=\"field-label is-normal\">\n <label class=\"label\" for=\"tier\">\n <span>Emissions Method Tier</span>\n </label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-fullwidth\">\n <select formControlName=\"tier\" name=\"tier\">\n <option [ngValue]=\"undefined\">Select a Tier</option>\n @for (tier of EmissionMethodTier | keyvalue; track tier) {\n <option [value]=\"tier.value\">{{ tier.value }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"field is-horizontal mt-3\">\n <div class=\"field-label is-normal\">\n <label class=\"label\" for=\"siteType\">\n <span>Site Type</span>\n </label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-fullwidth\">\n <select formControlName=\"siteType\" name=\"siteType\">\n <option [ngValue]=\"undefined\">Select a Type</option>\n @for (siteType of SiteSiteType | keyvalue; track siteType) {\n <option [value]=\"siteType.value\">\n {{ siteType.value }}\n </option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n</form>\n\n<ng-template #suggestionProductTermId let-r=\"result\" let-t=\"term\">\n <ngb-highlight [result]=\"r.name\" [term]=\"t\" />\n</ng-template>\n" }]
12581
12586
  }] });
12582
12587
 
12583
- /* eslint-disable complexity */
12584
- /* eslint-disable max-len */
12585
- /* eslint-disable no-useless-escape */
12586
- const guidePageId = (nodeType, errorMessage) => {
12587
- const error = validationsByMessage?.[errorMessage]?.[0]?.function;
12588
- return error ? [toDashCase(nodeType), error].filter(Boolean).join('#') : null;
12589
- };
12590
- const mapErrorMessage = 'does not contain latitude and longitude';
12591
- const parseDataPath = (dataPath = '') => {
12592
- const [_, ...paths] = dataPath
12593
- .replace(/[\[\]\'\'\"\"]/g, '')
12594
- .replace(/(\w)(\@)/g, '$1.@')
12595
- .split('.');
12596
- return paths.map(path => {
12597
- const label = path.replace(/[\d\@]+/g, '');
12598
- const type = pluralize(keyToLabel(label), 1);
12599
- return {
12600
- nodeType: isTypeNode(type) ? type : null,
12601
- schemaType: isTypeBlankNode(type) ? type : null,
12602
- path: path.replace(/(\d+)/g, '[$1]'),
12603
- label: isTypeValid({ type }) ? type : `<code>${pluralize(label, 1)}</code>`
12604
- };
12605
- });
12606
- };
12607
- const allowedDataPathsLabels = Object.values(SchemaType);
12608
- const listAsCode = (values) => (values ?? []).map(code).join(', ');
12609
- const dataPathLabel = (dataPath = '') => parseDataPath(dataPath)
12610
- .filter(({ label }) => allowedDataPathsLabels.includes(label))
12611
- .pop()?.label;
12612
- const guideLink = (guidePath, title) => externalLink(`${baseUrl()}/guide/${guidePath}`, title);
12613
- const glossaryTypeLink = (type, text = termTypeLabel(type)) => externalLink(`${glossaryBaseUrl()}?termType=${type}`, text);
12614
- const termLink = ({ id, name }) => externalLink(`${baseUrl()}/term/${id}`, name || id);
12615
- const dateFormatMessage = `Should follow the ISO 8601 date format, e.g. ${code(2000)}, or ${code('2000-12')}, or ${code('2000-12-30')}, and in some cases an optional time. Please refer to the schema for more details.`;
12616
- const threshold = (value) => code(`${value * 100}%`);
12617
- const joinValues = (values) => (values || []).filter(Boolean).map(code).join('<span>, </span>');
12618
- const formatListLine = (value) => `<li class="is-pre-wrap">${value}</li>`;
12619
- const formatListLines = (values) => values.flat().map(formatListLine).join('');
12620
- const formatList = (values, style = 'disc') => `<ul class="is-pl-3 is-list-style-${style} is-nowrap">${formatListLines(values)}</ul>`;
12621
- const noTillage = { id: 'noTillage', name: 'No tillage' };
12622
- const pastureGrass = { id: 'pastureGrass', name: 'Pasture grass' };
12623
- const idNotFoundDefaultMessage = `
12624
- If you are using the ${code('name')} of the Term, make sure to use ${code('term.name')} column;
12625
- if you are using the ${code('@id')} of the Term, use the ${code('term.@id')} column instead.
12626
- `.trim();
12627
- const isMigrationError = ({ params }) => params?.current && 'expected' in params;
12628
- const migrationErrorMessage = ({ params }) => params?.expected
12629
- ? `The Term ${code(params.current)} was updated, please use this Term instead: ${code(params.expected)}.`
12630
- : `The Term ${code(params.current)} was deleted. Please search the ${glossaryLink('Glossary')} for a new Term.`;
12631
- const idNotFoundError = (_error, _errorCount, allErrors) => {
12632
- const migrationErrors = allErrors.filter(isMigrationError);
12633
- const noMigrationErrors = allErrors.filter(error => !isMigrationError(error));
12634
- return `
12635
- <p>Does not exist in HESTIA.</p>
12636
- ${noMigrationErrors.length ? `<p>${idNotFoundDefaultMessage}</p>` : ''}
12637
- ${unique(migrationErrors.map(migrationErrorMessage)).join('</br>')}
12638
- `;
12639
- };
12640
- const idPatternError = (chars) => `You can only use the following characters for this field: ${chars.join(', ')}`;
12641
- const methodModelMappingError = ({ params }, errorCount) => `${errorCount === 1
12642
- ? `${params?.allowedValues.length
12643
- ? `can only be used with one of these methods: ${listAsCode(params?.allowedValues)}`
12644
- : `does not currently have any method allowed. Please ${contactUsLink()} to change this.`}.`
12645
- : `Some Terms are not allowed with the method you selected.`}
12646
- You can find the list of allowed methods for each Term by clicking on them.`;
12647
- const formatRule = (rule, path = '', negation = false) => rule?.enum?.length
12648
- ? `${code(path)} with of the following values: ${joinValues(rule.enum)}.`
12649
- : rule.const
12650
- ? `${code(path)} = ${code(rule.const)}`
12651
- : rule.properties
12652
- ? Object.entries(rule.properties).map(([key, value]) => formatRule(value, [path, key].filter(Boolean).join('.')))
12653
- : rule.items
12654
- ? formatRule(rule.items, path)
12655
- : rule.not
12656
- ? formatRule(rule.not, path, true)
12657
- : rule.anyOf
12658
- ? `<u>${negation ? 'none' : 'one'}</u> of the following must be valid: ${formatList(rule.anyOf.map(r => formatRule(r)))}`
12659
- : '';
12660
- const patternErrorKey = (pattern) => `should match pattern "${pattern}"`;
12661
- // set message as empty to not display it
12662
- const customErrorMessage = {
12663
- 'this field is required': ({ dataPath }, _errorCount, allErrors) => {
12664
- const parts = parseDataPath(dataPath);
12665
- const key = parts[parts.length - 1];
12666
- const type = parts[parts.length - 2];
12667
- return allErrors?.length
12668
- ? `You are missing the following required field: ${key.label} (for ${type.label}).`
12669
- : 'This field is required.';
12670
- },
12671
- 'should not be empty': ({ params }) => [
12672
- `Empty ${params.type} are not allowed in HESTIA.`,
12673
- params?.type === NodeType.ImpactAssessment
12674
- ? `Please, either link your ImpactAssessment to an existing Cycle using the ${code('cycle.id')},
12675
- or add one or more ${schemaLink('ImpactAssessment#emissionsResourceUse', 'emissionsResourceUse')},
12676
- ${schemaLink('ImpactAssessment#impacts', 'impacts')},
12677
- or ${schemaLink('ImpactAssessment#endpoints', 'endpoints')}.`
12678
- : ''
12679
- ].join('\n'),
12680
- "should have required property '@type'": ({ dataPath }) => {
12681
- // make sure schemaType is the last path
12682
- const { schemaType } = parseDataPath(dataPath).pop() ?? {};
12683
- // ignore .inputs as Term, find a better solution by parsing the dataPath correctly
12684
- // @see https://gitlab.com/hestia-earth/hestia-ui-components/-/issues/399
12685
- const isInputAsTerm = dataPath.match(/(emissions|emissionsResourceUse)\[[\d]+\].inputs[\[\d]+\]$/g);
12686
- return schemaType && !isInputAsTerm ? `Please add ${code(`"@type" = "${schemaType}"`)} to this blank node.` : '';
12687
- },
12688
- "should have required property '@id'": idNotFoundError,
12689
- "should have required property 'id'": idNotFoundError,
12690
- 'should match exactly one schema in oneOf': () => '',
12691
- 'should match some schema in anyOf': () => '',
12692
- 'should match "then" schema': () => '',
12693
- 'should be null': () => '',
12694
- 'should NOT have additional properties': ({ params }, errorCount) => errorCount === 1
12695
- ? `The following field does not exist: ${params?.additionalProperty} or is not allowed in this case.`
12696
- : `Should not have additional properties.`,
12697
- 'should NOT be valid': ({ schema }) => schema?.required?.includes('areaPercent')
12698
- ? `If the term units is already in ${code('% area')}, just use ${code('value')}. Dont use ${code('areaPercent')}.`
12699
- : schema?.required?.includes('transformation')
12700
- ? 'A transformation can not be added here.'
12701
- : schema?.required?.includes('fromCycle')
12702
- ? `This field can only be added to the ${schemaLink('Transformation#inputs', 'inputs of a Transformation')}.`
12703
- : schema?.required?.includes('otherSites')
12704
- ? `Please only specify a single ${schemaLink('Cycle#site', 'site')} when the functional unit is ${code(CycleFunctionalUnit['1 ha'])}.`
12705
- : // termType restriction on the item
12706
- schema?.properties?.term?.properties?.termType?.enum?.length
12707
- ? `This ${code('termType')} is not allowed here.`
12708
- : schema?.required
12709
- ? `The following ${pluralize('field', schema.required.length)} should not be used: ${listAsCode(schema.required)}`
12710
- : 'Should not be used in this case.',
12711
- [patternErrorKey('^[0-9]{4}(-01)?(-01)?$')]: () => 'should be the first month/day of the year',
12712
- [patternErrorKey('^\\d{13}$')]: () => 'should be composed of 13 numbers',
12713
- 'not a valid date': () => dateFormatMessage,
12714
- [patternErrorKey('^[0-9]{4}(-[0-9]{2})?(-[0-9]{2})?$')]: () => dateFormatMessage,
12715
- [patternErrorKey('^([0-9]{4}|-)(-[0-9]{2})?(-[0-9]{2})?$')]: () => dateFormatMessage,
12716
- [patternErrorKey('^([0-9]{4}|-)(-[0-9]{2})?(-[0-9]{2})?([T][0-2][0-9]:[0-5][0-9]:[0-5][0-9]((+|-)[0-1][0-9]:[0-5][0-9])?)?$')]: () => dateFormatMessage,
12717
- [patternErrorKey('^10.(d)+/(S)+$')]: () => `The DOI should not include the domain name, e.g. ${code('10.1000/182')} instead of ${code('https://doi.org/10.1000/182')}`,
12718
- [patternErrorKey('^[\\w\\-\\.]+$')]: () => idPatternError(['letters', 'numbers', 'underscores', 'dashes', 'dots (.)']),
12719
- [patternErrorKey('^[\\w\\-\\.\\s]+$')]: () => idPatternError(['letters', 'numbers', 'underscores', 'dashes', 'dots (.)', 'spaces']),
12720
- [patternErrorKey('^[\\w\\-\\.\\s\\(\\)]+$')]: () => idPatternError(['letters', 'numbers', 'underscores', 'dashes', 'dots (.)', 'spaces', 'parentheses']),
12721
- [patternErrorKey('^[\\w\\-\\.\\s\\(\\),]+$')]: () => idPatternError(['letters', 'numbers', 'underscores', 'dashes', 'dots (.)', 'spaces', 'parentheses', 'commas']),
12722
- [patternErrorKey('^[\\w\\u00C0-\\u017F\\-\\.\\s\\(\\),]+$')]: () => idPatternError(['letters', 'numbers', 'underscores', 'dashes', 'dots (.)', 'spaces', 'parentheses', 'commas']),
12723
- [patternErrorKey('^[\\w\\u00C0-\\u017F\\-\\.\\s\\(\\),+]+$')]: () => idPatternError([
12724
- 'letters',
12725
- 'numbers',
12726
- 'underscores',
12727
- 'dashes',
12728
- 'dots (.)',
12729
- 'spaces',
12730
- 'parentheses',
12731
- 'commas',
12732
- 'plus'
12733
- ]),
12734
- 'should have the same length as endDate': () => `The startDate must be in the same date format as ${code('endDate')}: YYYY-MM-DD, YYYY-MM, or YYYY.`,
12735
- 'node not found': (error, _errorCount, allErrors) => `${allErrors?.length
12736
- ? `The following Nodes do not exist on the platform:
12737
- ${formatList(unique(allErrors.map(({ params }) => `${params?.node?.['@type']} with ${code(`@id=${params?.node?.['@id']}`)}`)))}`
12738
- : `The ${error.params?.node?.['@type']} with ${code(`@id=${error.params?.node?.['@id']}`)} does not exist on the platform.`} If you are trying to link to nodes included in this upload, you must use ${code('id')} field instead. Otherwise, please check the ids are correct and try again.`,
12739
- 'should be linked to an existing node': (error, _errorCount, allErrors) => allErrors?.length
12740
- ? `Your upload does not contain the following Nodes:
12741
- ${formatList(unique(allErrors.map(({ params }) => `${params?.node?.type} with ${code(`id=${params?.node?.id}`)}`)))}
12742
- If you are trying to link to an existing Node on the HESTIA platform, you must use ${code('@id')} field instead.
12743
- Otherwise you must include a full ${unique(allErrors.map(({ params }) => `${params?.node?.type} with id ${code(params?.node?.id)}.`)).join(', ')}`
12744
- : `Your upload does not contain a ${error.params?.node?.type} with ${code(`id=${error.params?.node?.id}`)}.
12745
- If you are trying to link to an existing Node on the HESTIA platform, you must use ${code('@id')} field instead.
12746
- Otherwise you must include a full ${error.params?.node?.type} with id ${code(error.params?.node?.id)}.`,
12747
- 'must be within the country': () => `The country provided does not contain the region provided. Please check
12748
- the country for errors or the region for errors, and reference the ${glossaryLink('Glossary of Terms')}.`,
12749
- [mapErrorMessage]: ({ dataPath, params }, errorCount) => errorCount === 1
12750
- ? `The longitude and latitude provided are${params?.distance ? ` ${params?.distance}kms` : ''} outside of the ${dataPath.substring(1)} provided.
12751
- Please check the longitude and latitude for errors or check if the wrong ${dataPath.substring(1)} from the ${glossaryTypeLink(TermTermType.region, 'Glossary')} was used.
12752
- ${params?.expected
12753
- ? `Hint: the coordinates appear to be located in the following ${dataPath.substring(1)}: ${termLink({
12754
- id: params.expected
12755
- })}`
12756
- : ''}`
12757
- : `The region provided does not contain the longitude and latitude provided.
12758
- Please check the longitude and latitude for errors or the region for error, and reference the ${glossaryTypeLink(TermTermType.region, 'Glossary of Terms')}.`,
12759
- 'sum not equal to 100% for sandContent, siltContent, clayContent': () => `The sum of Sand, Silt, and Clay content should equal 100% for each soil depth interval.`,
12760
- 'is outside the allowed range': ({ params }, errorCount) => `${errorCount === 1
12761
- ? params?.term
12762
- ? `The value for ${code(params?.term['@id'] || params?.term.name)} is outside the range established for the soil texture you provided.
12763
- For this soil texture, the maximum ${code(params?.term['@id'] || params?.term.name)} is ${params?.range?.max} and the minimum is ${params?.range?.min}.`
12764
- : `Does not match the possible ranges of sand, silt and clay content.`
12765
- : `Each soil texture has a maximum and minimum value for sand, silt, and clay content.
12766
- At least one measurement of sand, silt, or clay content does not match the possible range for the specified soil texture.`}
12767
- ${errorCount === 1
12768
- ? `Please check the measurement, its depth intervals, and the dates of the measurement or update the soil texture if needed.`
12769
- : `Please check your measurements, their depth intervals, and the dates of the measurements or update the soil textures if needed.`}`,
12770
- 'should be equal to one of the allowed values': ({ params, dataPath, schemaPath }, count, errors) => {
12771
- const paths = parseDataPath(dataPath);
12772
- const values = paths.length >= 2 ? pluralize(paths[paths.length - 1].path, params?.allowedValues?.length || 0) : 'values';
12773
- // find the matching conditional `if`
12774
- const schemaPathMatch = schemaPath?.split('/').slice(0, 3).join('/');
12775
- const ifError = schemaPathMatch
12776
- ? errors.find(error => [
12777
- error.keyword === 'if',
12778
- error.schemaPath !== schemaPath,
12779
- error.schemaPath?.startsWith(schemaPathMatch)
12780
- ].every(Boolean))
12781
- : null;
12782
- return [
12783
- dataPath.endsWith('term.termType')
12784
- ? [
12785
- `For ${pluralize(paths[paths.length - 3].label, 0)}, we only allow terms from the following glossaries: ${listAsCode(params?.allowedValues)}.`,
12786
- ifError
12787
- ? ''
12788
- : 'Please either change the Term you are using and ensure it is from one of the glossaries listed above, or follow the schema to identify where this Term can be added.'
12789
- ]
12790
- .filter(Boolean)
12791
- .join(' ')
12792
- : `Only the following ${values} are permitted: ${listAsCode(params?.allowedValues)}.`,
12793
- ifError?.schema.properties
12794
- ? `This validation applies when the following conditions are met:${formatList(Object.entries(ifError.schema.properties).map(([key, value]) => formatRule(value, key)))}`
12795
- : ''
12796
- ]
12797
- .filter(Boolean)
12798
- .join(' ');
12799
- },
12800
- 'should be equal to constant': ({ params }) => `Must be: ${code(params?.allowedValue)}`,
12801
- 'can only contain one primary item': ({ dataPath }) => `Only 1 primary ${parseDataPath(dataPath).pop().label} allowed.`,
12802
- 'is not allowed for this emission': methodModelMappingError,
12803
- 'is not allowed for this characterisedIndicator': methodModelMappingError,
12804
- 'is not allowed for this resourceUse': methodModelMappingError,
12805
- 'should contain a valid item': ({ dataPath, schema }) => {
12806
- const paths = parseDataPath(dataPath);
12807
- return paths.length >= 2
12808
- ? `The ${paths[paths.length - 1].path} related to this ${pluralize(paths[paths.length - 2].label, 1)} are invalid`
12809
- : `The ${paths[0].path} are invalid because they do not contain a blank node with:${formatList(Object.entries(schema?.properties).map(([key, value]) => formatRule(value, key)))}`;
12810
- },
12811
- 'may be between 0 and 100': () => 'Percentages should be between 0 and 100, not 0 and 1. This may be an error.',
12812
- 'may not all be set to false': () => `Every value in the data completeness assessment is ${code(false)}. You may have forgotten to fill it in.
12813
- For information on how to fill it in, please see the ${schemaLink('Cycle#completeness', 'schema')}.`,
12814
- 'may not be empty': () => 'if this value signifies no data, HESTIA only accepts "-" or empty for no data',
12815
- 'may not be 0': ({ dataPath }, errorCount) => `Adding a value ${errorCount === 1 ? ` to every ${dataPathLabel(dataPath)} ` : ' '} is highly recommended.
12816
- If the amount produced is zero, we recommend setting value to 0.`,
12817
- 'longFallowDuration must be lower than 5 years': () => `Your long fallow duration is greater than five years.
12818
- Fallow is defined by FAOSTAT as land left uncultivated for between 1 and 5 years,
12819
- and this definition is used for HESTIA also.`,
12820
- 'should be more than the cropping duration': ({ params }) => `The ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} is shorter than the country's minimum cropping duration for rice (${code(params?.expected)}).
12821
- This might be an error and result in the underestimation of the ${code('CH4, to air, flooded rice')} emissions.
12822
- Please, double-check that the ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} is correctly set.
12823
- `,
12824
- 'croppingDuration must be between min and max': ({ params }) => `The ${code('croppingDuration')} should be within the country's minimum (${params.min}) and maximum (${params.max}) cropping duration for rice.
12825
- This might be an error and result in the overestimation of ${code('CH4, to air, flooded rice')} emissions.
12826
- Please, double-check that the ${code('croppingDuration')} is correctly set.`,
12827
- 'should be within percentage of default value': ({ params }, errorCount) => errorCount === 1
12828
- ? `This value is ±${threshold(params?.threshold)} different to our default value which is ${params?.default}.
12829
- Please check your uploaded data as this may be an error.`
12830
- : `This value is substantially different than our default value.
12831
- Please check your uploaded data as this may be an error.`,
12832
- 'the value provided is not consistent with the model result': ({ params }, errorCount) => `The expected result ${errorCount === 1
12833
- ? `for ${code(params?.term.name)} ${params?.model?.name ? `using ${code(params.model.name)} ` : ''}`
12834
- : ''}
12835
- from the data provided in the upload is ${errorCount === 1
12836
- ? `${code(toPrecision(params?.expected, 3))}, but the value in the upload is ${code(toPrecision(params?.current, 3))}.
12837
- ${params?.threshold ? `Our threshold is ±${threshold(params?.threshold)}.` : ''}
12838
- Please either:
12839
- ${formatList([
12840
- 'Check the ${params?.term.termType} value you provided;',
12841
- 'Check the data you provided which is the input into this model;',
12842
- 'Carefully read the documentation to understand if we used a default property as part of the calculations.'
12843
- ], 'decimal')}`
12844
- : 'not consistent with the model result.'}`,
12845
- 'the measurement provided might be in error': ({ params }, errorCount) => `The expected value for ${code(params?.term.name)}
12846
- ${params?.model?.name ? `using ${code(params.model.name)} ` : ''}
12847
- from the data provided in the upload is ${errorCount === 1
12848
- ? `${code(toPrecision(params?.expected, 3))}, but the value in the upload is ${code(toPrecision(params?.current, 3))}.
12849
- ${params?.threshold ? `Our threshold is ±${threshold(params?.threshold)}.` : ''}`
12850
- : `not consistent with the model result.`}`,
12851
- 'must be equal to previous product multiplied by the share': () => `Products from a transformation which are an Input in to the next transformation must follow the following rule:
12852
- ${code('previous.product.value * current.transformedShare / 100 == current.input.value')}`,
12853
- 'at least one Input must be a Product of the Cycle': () => `A Transformation converts a Product from a Cycle into another Product.
12854
- Therefore, at least one Input into the Transformation must be a Product of the Cycle.`,
12855
- 'must have only one entry with the same term.termType = excretaManagement': () => `There can only be one Practice of type excretaManagement in a Cycle.
12856
- To represent multiple excreta management systems either use multiple Cycles and link them together,
12857
- or use Transformations within a Cycle and link those together.`,
12858
- 'must be included as an Input': ({ params }, errorCount) => `The excreta Products are not of the same type as the excreta Inputs.
12859
- ${errorCount === 1
12860
- ? `E.g., you cannot get ${code(params?.term?.name)} from ${(params?.expected || [])
12861
- .map(v => code(keyToLabel(v)))
12862
- .join(' or ')}.`
12863
- : ''}
12864
- Please check the Inputs and Products of the Transformation.`,
12865
- 'must add the linked inputs to the cycle': ({ params }, errorCount) => `${errorCount === 1
12866
- ? `You have stated that ${code(params?.term?.name)} was created by the following Inputs ${params?.expected
12867
- ?.map(e => code(e.name))
12868
- .join(' , ')}`
12869
- : 'You have stated some Emissions were created by some Inputs'}.
12870
- However, these Inputs do not exist in the Cycle.
12871
- Please add these Inputs, even if you do not have a value for them.`,
12872
- 'must add the linked transformations to the cycle': ({ level, params }, errorCount) => `${errorCount === 1
12873
- ? `You have specified that${code(params?.term?.name)} was created during a Transformation with the Term name ${code(params?.expected?.name)}`
12874
- : 'You have stated some Emissions were created by some Transformations'}.
12875
- However, we cannot find a Transformation within the Cycle with this Term name.
12876
- ${level === 'error'
12877
- ? 'Please check the Terms used in the Emissions and/or the Transformations.'
12878
- : 'You may want to add this Transformation.'}`,
12879
- 'every node should be unique': ({ params }) => `This Node is duplicated. Every Node should be unique.
12880
- Uniqueness is determined by the following fields: ${listAsCode(params?.keys)}`,
12881
- 'every item in the list should be unique': ({ params }) => `This blank node is duplicated${params?.duplicatedIndexes?.length
12882
- ? ` with the blank ${pluralize('node', params.duplicatedIndexes.length)} with numbered: ${params.duplicatedIndexes.join(', ')}`
12883
- : ''}. Every blank node should be unique.
12884
- Uniqueness is determined by the following fields: ${listAsCode(params?.keys)}`,
12885
- 'must contain as many items as values': ({ params, dataPath }) => `The number of ${code(dataPath.split('.').pop())} must match the number of ${code('value')}.
12886
- Currently there are ${params?.current} ${code(dataPath.split('.').pop())} but ${params?.expected} ${code('value')}.`,
12887
- 'is too generic': ({ params }) => `You have the following Product ${code(params?.product?.name)} however,
12888
- you have used a generic ${glossaryTypeLink(params?.term?.termType)} term ${code(params?.term?.name)}.
12889
- Use a more specific term for the ${glossaryTypeLink(params?.term?.termType)} which reflects the specific ${glossaryTypeLink(params?.product?.termType)}.`,
12890
- 'should not use identical terms with different units': ({ params }) => `You have added the same ${code(params?.term?.termType)} in ${params?.units
12891
- ?.map(unit => code(unit))
12892
- .join(' and ')} units.
12893
- If these terms refer to the same ${code(params?.term?.termType)}, this will lead to double counting.${params?.units?.includes('kg N')
12894
- ? ` Instead use the ${termLink({ id: 'nitrogenContent', name: 'Nitrogen Content' })} Property on the ${code('kg')} term to define the nitrogen content of the ${code(params?.term?.termType)}.`
12895
- : ''}`,
12896
- 'is missing required bibliographic information': () => `The automatic bibliography search failed for this Bibliography. Either:
12897
- ${formatList([
12898
- `Manually fill-in the <b>required</b> bibliographic information as per ${schemaLink(SchemaType.Bibliography, 'our schema')}.`,
12899
- `Provide the ${code('documentDOI')} as well as the ${code('title')}.`,
12900
- `Check the ${code('documentDOI')} and ${code('title')} for typos against the ${externalLink('https://www.mendeley.com', 'Mendeley catalogue')}.`
12901
- ], 'decimal')}`,
12902
- 'should be lower than max size': ({ params }) => `The boundary or region is >${params?.expected}km2 and is too large to reliably gap fill Measurements.
12903
- If you are able to use a more specific region or smaller boundary, please do.`,
12904
- 'an excreta input is required when using an excretaManagement practice': ({ dataPath }) => {
12905
- const paths = parseDataPath(dataPath);
12906
- return `Excreta management is the conversion of excreta to any type of product (e.g., another type of excreta or organic fertiliser).
12907
- You have added an ${code('excretaManagement')} Practice to this ${paths[0].label} but there is no excreta Input.
12908
- To represent excreta management, use a ${paths[0].label} with excreta as an Input and ${code('excretaManagement')} as a Practice.`;
12909
- },
12910
- 'only 1 primary product allowed': () => 'There can only be one primary product in each Cycle.',
12911
- 'is not allowed in combination with noTillage': () => `This operation involves tillage, yet you have specified the Practice ${termLink(noTillage)}.
12912
- Either change this operation or the Practice.`,
12913
- 'should contain a tillage practice': () => `We recommend specifying the type of tillage used for this Cycle.
12914
- Please see the ${glossaryTypeLink(TermTermType.tillage)} glossary.`,
12915
- 'must contain a tillage practice': ({ params }) => `If you have specified a tillage Operation, e.g., ${code(params?.term?.name)}, please specify a tillage regime (excluding ${code('noTillage')}).`,
12916
- 'must set value for every tillage practice': () => `Either specify a single ${glossaryTypeLink(TermTermType.tillage)} practice or add a value to all practices.`,
12917
- 'sum not equal to 100% for tillage practices': () => `The sum of ${glossaryTypeLink(TermTermType.tillage)} practices must equal 100%.`,
12918
- 'can only have 1 tillage practice without a value': ({ params }) => `It is not possible for a Cycle to have the following tillage Practices:
12919
- ${(params?.current ?? []).map(({ name }) => name).join(' and ')} at the same time.
12920
- If multiple tillage practices did occur, please specify the percentage of area they occurred on.`,
12921
- 'cannot use no tillage if depth or number of tillages is not 0': () => `This Practice cannot have a value of ${code(100)} if the Tillage depth is higher than ${code(0)} or the Number of tillages is higher than ${code(0)}. Please resolve this conflict.`,
12922
- 'cannot use full tillage if depth or number of tillages is 0': () => `This Practice cannot have a value of ${code(100)} if the Tillage depth is equal to ${code(0)} or the Number of tillages is equal to ${code(0)}. Please resolve this conflict.`,
12923
- 'must use no tillage when number of tillages is 0': () => `You cannot use a tillage term other than No tillage with a value of ${code(100)} if the Number of tillages has been set to ${code(0)}. Please resolve this conflict.`,
12924
- 'can not be linked to the same Cycle': () => 'You can not link an Input to the Impact Assessment of the same Cycle.',
12925
- // deprecated, remove when message is not being used anymore
12926
- 'must be 0 for product value 0': ({ dataPath, params }, errorCount) => `If the amount produced is zero, the ${code(dataPath?.split('.').pop())} of ${errorCount === 1 ? code(params?.term.name) : 'that product'} must also be zero.`,
12927
- 'economicValueShare must be 0 for product value 0': ({ params }, errorCount) => `If the amount produced is zero, the economicValueShare of ${errorCount === 1 ? code(params?.term.name) : 'that product'} must also be zero.`,
12928
- 'revenue must be 0 for product value 0': ({ params }, errorCount) => `If the amount produced is zero, the revenue of ${errorCount === 1 ? code(params?.term.name) : 'that product'} must also be zero.`,
12929
- 'should add a source': ({ params }) => `We recommend adding a Source to all data items.
12930
- This can be done by adding the ${code(params?.current)} field.
12931
- Sources can also be specified for each data item (i.e., each Input, Emission, Product, Practice, Measurement, or Infrastructure).`,
12932
- 'cover crop cycle contains non cover crop product': () => `You have specified that this crop is a cover crop using a Practice.
12933
- A cover crop is defined as "a crop which is left in the field without any fraction harvested by the end of the Cycle".
12934
- The Products of this Cycle are incompatible with this crop being a cover crop.
12935
- Please check the Products or the Practices.`,
12936
- 'should be included in the cycle products': ({ params }, errorCount) => `${errorCount === 1
12937
- ? `The Product ${code(params.product.name)} cannot be found in the Cycle with id ${code(params.node.id)}`
12938
- : 'The Product in the Impact Assessment cannot be found in the linked Cycle'}.
12939
- This could be simply because the product does not exist in the Cycle: in this case, add it to the Cycle or remove the Impact Assessment.
12940
- It could also be because you have multiple Products in the Cycle using the same Term, but having different Properties or different fields:
12941
- in this case, ensure all of the Properties and fields which make the Product unique are copied into the Impact Assessment.`,
12942
- 'multiple ImpactAssessment are associated with the same Product of the same Cycle': () => `Only one Impact Assessment can be related to this Product.
12943
- Please make sure the product is correct or the cycle.id you are referring to is correct.`,
12944
- 'multiple ImpactAssessment are associated with this Product': () => `Only one Impact Assessment can be related to this Product.
12945
- Please make sure the product of the related ImpactAssessments are correct or the ${code('cycle.id')} is correct.`,
12946
- 'no ImpactAssessment are associated with this Product': () => `In cases where Impact Assessment data are being uploaded, the number of Impact Assessments must match the number of Products.
12947
- This ensures the Cycle data matches the Impact Assessment data.
12948
- To fix this, add one Impact Assessment for every Product in the Cycle, following at least the minimum required fields for Impact Assessments.`,
12949
- 'must be less than or equal to land occupation': () => `Land transformation should be less than or equal to land occupation
12950
- (land transformation is the amount of land converted between some date in the past and the current year,
12951
- divided by an amortization period, so it should always be less than land occupation by definition).`,
12952
- 'should be linked to an emission in the Cycle': ({ params }, errorCount) => `${errorCount === 1 ? `${code(params?.term.name)} exists` : 'Some Emissions exist'} in both the Cycle and the Transformation but ${errorCount === 1 ? 'it is' : 'they are'} not linked using ${code('cycle.emissions.X.transformation.term')}. This may be an error.`,
12953
- 'should add an animal production system': ({ params }) => `For animal rearing cycles, we recommend adding a practice to specify the production system.
12954
- This information is used to estimate ruminants' grass intake and enteric methane emissions for all animals.
12955
- You can choose one or more of the following terms: ${listAsCode(params?.expected)}`,
12956
- 'must be set to false when specifying fuel use': ({ params }) => `If fuel for machinery (${listAsCode(params?.allowedValues)}) is used during a Cycle,
12957
- but there is no data on the amount of ${glossaryTypeLink(TermTermType.material)} used for agricultural equipment,
12958
- then ${code('completeness.material')} must be ${code('false')}.
12959
- Here, we mean the quantity of physical material used to construct agricultural machinery,
12960
- which is then depreciated over each Cycle.`,
12961
- 'must be below or equal to 1 for unit in ha': () => `The maximum value for a product with units ${code('ha')} on a Cycle with a ${schemaLink('Cycle#functionalUnit', 'functional unit')} of ${code('1 ha')} is ${code('1')}.
12962
- If you are trying to add a product with the units ${code('kg')}, use a different term.`,
12963
- "pastureGrass key termType must be 'landCover'": ({ params }) => `The Term ${code(params?.term.name)} can't be used as a key for ${termLink(pastureGrass)}.
12964
- Please, use a term with termType ${glossaryTypeLink(TermTermType.landCover)} instead.
12965
- This will help us gap-fill the amount of grass consumed by the herd.`,
12966
- 'the sum of all pastureGrass values must be 100': ({ params }) => `The sum of all ${termLink(pastureGrass)} values must be equal to ${params.expected}%.`,
12967
- 'is outside confidence interval': (error, errorCount, allErrors) => `${unique((allErrors.length ? allErrors : [error]).flatMap(({ dataPath, params }) => params?.outliers?.map(value => `The ${dataPath.includes('product') ? 'product' : 'input'} value ${errorCount === 1 ? `${code(value)} ` : ''}is ${value > params?.min ? 'above' : 'below'} ${params?.threshold ? `${code(`${(params.threshold + (1 - params.threshold) / 2) * 100}%`)} of` : ''} all ${params?.group ? code(params.group) : code(params?.term?.name)} data in ${code(params?.country.name)} on the HESTIA platform.`))).join('</br>')}
12968
- </br>
12969
- Please double-check these values before submitting.`,
12970
- 'should be equal to boundary': ({ params }) => `The calculated ${schemaLink('Site#area', 'area')} from ${code('boundary')} is ${code(params?.expected)} ha.
12971
- This may be an error if the boundary represents the area under cultivation.`,
12972
- 'must specify the fate of cropResidue': ({ params }) => `For sites of type ${params.siteType.map(code).join(' or ')},
12973
- if data completeness is marked ${code(true)} for crop residue, the fates and quantities of the residue must be specified.
12974
- <br/>
12975
- The quantity must include both above and below ground crop residue, where the sum of above ground crop residue and below ground crop residue must be greater than zero.
12976
- This can be added using the terms:
12977
- ${formatList([
12978
- `${termLink({ id: 'belowGroundCropResidue', name: 'Below ground crop residue' })}; and`,
12979
- termLink({
12980
- id: 'aboveGroundCropResidueTotal',
12981
- name: 'Above ground crop residue total'
12982
- })
12983
- ])}
12984
- <br/>
12985
- The fate can be added using:
12986
- ${formatList([
12987
- `The ${glossaryTypeLink(TermTermType.cropResidueManagement)} practices; and`,
12988
- `The ${glossaryTypeLink(TermTermType.cropResidue)} products.`
12989
- ])}
12990
- `,
12991
- 'should specify the fate of cropResidue': () => `You have not specified the fate of the crop residue.
12992
- Adding this information will improve emissions and soil carbon stock calculations.
12993
- The fate can be added using:
12994
- ${formatList([
12995
- `The ${glossaryTypeLink(TermTermType.cropResidueManagement)} practices; and/or`,
12996
- `The ${glossaryTypeLink(TermTermType.cropResidue)} products.`
12997
- ])}
12998
- Remember to set ${code('completeness.cropResidue')} to ${code(true)} if both the above and below ground crop residue quantities and fates are specified.`,
12999
- 'should have the same privacy as the related source': ({ params }) => `To link to a ${(params?.defaultSource || params?.source)?.dataPrivate ? 'private' : 'public'} Source,
13000
- this Node needs to be ${(params?.defaultSource || params?.source)?.dataPrivate ? 'private' : 'public'} as well.
13001
- Please set ${code('dataPrivate')}=${code(`${(params?.defaultSource || params?.source)?.dataPrivate}`)}.`,
13002
- 'should not use not relevant model': () => `All emissions should generally have a method tier, which states how the data were modelled or how the data were collected.
13003
- Please see the ${schemaLink('Emission#methodTier', 'schema')} for the options available and definitions of the options.`,
13004
- 'should not use not relevant methodTier': () => `All emissions should generally have a method tier, which states how the data were modelled or how the data were collected.
13005
- Please see the ${schemaLink('Emission#methodTier', 'schema')} for the options available and definitions of the options.`,
13006
- 'animal population must not be complete': () => `This Cycle has ${code('liveAnimals')} or ${code('liveAquaticSpecies')} as Products, ${code('completeness.animalPopulation')} is set to ${code('true')}, but there are no ${code('animals')} blank nodes.
13007
- Either: set ${code('completeness.animalPopulation')} to ${code('false')} or add the animal blank nodes to describe the animal population.`,
13008
- 'ingredients should be complete': ({ params }) => `Data completeness for ${code('ingredient')} must be true for site of type ${params.siteType}`,
13009
- 'must have inputs to represent ingredients': () => `Data completeness for ${code('ingredient')} cannot be true if there are no Inputs.`,
13010
- 'must have inputs representing the forage when set to true': ({ params }) => `This Cycle includes animals ${params?.siteType ? `on ${params.siteType}` : ''} and completeness is set to ${code(true)} for ${code('freshForage')}.
13011
- However, there are no Inputs representing the forage intake by animals in the Cycle (Inputs with ${code('termType')} ${code('freshForage')}" and a ${code('value')}).
13012
- Either, set completeness to ${code(false)} for ${code('freshForage')}, make sure all fresh forage Inputs have a ${code('value')}, or add one or more Inputs representing the forage intake.`,
13013
- 'must specify is it an animal feed': () => `This Cycle is an animal production Cycle and this Input could be an animal feed or could be for another use.
13014
- Please specify the ${schemaLink('Input#isAnimalFeed', 'isAnimalFeed')} field on this Input.
13015
- Knowing the fate is essential to distinguish Inputs between those which are fed to animals and those which are used for other purposes.`,
13016
- 'should specify a treatment when experimentDesign is specified': () => `You have specified that this Source uses an experimental design, but have not specified the treatment for this Cycle.
13017
- Adding the treatment provides important meta-data and will enable greater re-use of these data.
13018
- Add the ${schemaLink('Cycle#treatment', 'treatment')} field to the Cycle.
13019
- Note that the field ${schemaLink('Cycle#commercialPracticeTreatment', 'commercialPracticeTreatment')} becomes required if treatment is specified.`,
13020
- 'should not specify both liveAnimal and animalProduct': () => `You have added both a ${glossaryTypeLink(TermTermType.liveAnimal)} and ${glossaryTypeLink(TermTermType.animalProduct)} term as Products.
13021
- If these terms refer to the same animals, this will lead to double counting:
13022
- instead use a Property on the ${glossaryTypeLink(TermTermType.liveAnimal)} term to define the quantity of liveweight per head, carcass weight per head, etc.`,
13023
- 'should add an excreta product': () => `Animal production Cycles create excreta.
13024
- There should be at least one ${code(TermTermType.excreta)} product in this Cycle.
13025
- Please add an ${code(TermTermType.excreta)} Product to the Cycle.
13026
- You do not need to set a ${code('value')} for the Product, but adding a ${code('value')} is desirable.`,
13027
- 'is not an allowed excreta product': ({ params }) => `This excreta product is not allowed for the animal products added to this Cycle.
13028
- Instead, please add one of the following excreta: ${listAsCode(params.expected)}`,
13029
- 'value should sum to 100 across all values': ({ params }, errorCount) => `${errorCount === 1
13030
- ? `The total value of the following terms should sum up to a value of 100%: ${formatList((params.termIds || []).map(code))}`
13031
- : 'Some of the terms are grouped together, and their total value should sum up to 100%.'}
13032
- Make sure to add any missing term if needed and/or adjust the values of the existing terms you already recorded.`,
13033
- 'value should sum to maximum 100 across all values': ({ params }, errorCount) => `${errorCount === 1
13034
- ? `The total value of the following terms should sum up to a maximum value of 100%: ${formatList((params.termIds || []).map(code))}`
13035
- : 'Some of the terms are grouped together, and their total value should not go over 100%.'}
13036
- Make sure to add any missing term if needed and/or adjust the values of the existing terms you already recorded.`,
13037
- 'rice products not allowed for this water regime practice': ({ params }) => `This practice is not allowed with the products ${params.products?.map(p => code(p.name || p['@id']))}.
13038
- Recording the right water regime for rice ensures methane emissions from flooded fields are correctly recalculated.
13039
- To fix this error, either change the practice or the products.`,
13040
- 'must not be equal to 1 ha': ({ params }) => `${code(CycleFunctionalUnit['1 ha'])} cannot be used as ${schemaLink('Cycle#functionalUnit', 'functionalUnit')} for Cycles linked to Sites with ${schemaLink('Site#siteType', 'siteType')} = ${code(params?.siteType)}.
13041
- Either change the ${schemaLink('Cycle#functionalUnit', 'functionalUnit')} to ${code(CycleFunctionalUnit.relative)} or change the ${schemaLink('Site#siteType', 'siteType')}.`,
13042
- 'should specify a value when HESTIA has a default one': ({ params }) => `As you have not specified a ${code('value')}, we will assume the value is ${code(params?.expected)}.
13043
- If this is incorrect, pelase add a value.`,
13044
- 'should contain at least one management node': ({ params }) => `${params?.termType
13045
- ? `Does not contain information about ${code(params.termType)}.
13046
- Please consider adding a history of ${code(params.termType)} for as many years as possible in the Management blank nodes.`
13047
- : `There is no Management node present in this upload.
13048
- We recommend adding this to the Site, including information about current and historical tillage.
13049
- `}
13050
- We use this information to model CO<sub>2</sub> emissions from soil organic carbon change.`,
13051
- 'can not be used on this termType': ({ params }) => `This Property can only be used on blank nodes with the following ${code('term.termType')}: ${listAsCode(params.expected)}.`,
13052
- 'not a valid GeoJSON': ({ params }) => `
13053
- ${params?.invalidCoordinates === 'true'
13054
- ? `GeoJSON data should follow the WGS84 datum.
13055
- We have found coordinates outside of the -180 to +180 range which is not possible under WGS84.
13056
- Please check the datum or check for other possible errors.`
13057
- : 'This GeoJSON appears to be invalid.'}
13058
- You can validate your GeoJSON using an online tool like <a href="https://geojson.io/">geojson.io</a>.
13059
- If you think this is a mistake, please report the error ${reportIssueLink(Repository.schema, Template.bug)}.`,
13060
- 'should add the term stockingDensityPermanentPastureAverage': ({ params }) => `You did not specify ${externalNodeLink({ '@type': NodeType.Term, '@id': params.expected })}.
13061
- Adding this Practice is essential for Cycles with relative functional unit which happen entirely or partially on permanent pasture.
13062
- Without this information HESTIA cannot calculate animal related emissions.`,
13063
- 'should specify the herd composition': () => `We recommend adding information on the herd composition using the Animal node.
13064
- Without this, we cannot re-model many animal related Inputs, Products, and Emissions.`,
13065
- 'should specify the pregnancy rate': ({ params }) => `For female mammals in their reproductive age, we recommend adding ${externalNodeLink({
13066
- '@type': NodeType.Term,
13067
- '@id': params.expected
13068
- })} as a ${schemaLink('Animal#properties', 'Property')}.
13069
- This is particularly important for ruminants, as the pregnancy rate influences animals' energy requirements and is used in the estimation of grass intake.`,
13070
- 'should specify the a milkYield practice': ({ params }) => `For this Animal, we recommend adding one of the following practices: ${listAsCode(params?.expected)}.
13071
- These practices will be used for estimating grass intake. If not added, default values will be used. `,
13072
- 'should specify a recommended product': ({ params }) => `Based on the Animals present in your Cycles, some Products might be missing: ${listAsCode(params?.expected)}.
13073
- Recording all products is essential to correctly allocate impacts.
13074
- Consider adding the suggested products or updating the product completeness.`,
13075
- 'should set both depthUpper and depthLower': () => `
13076
- We recommend setting both ${schemaLink('Measurement#depthUpper', 'depthUpper')} and ${schemaLink('Measurement#depthLower', 'depthLower')} on this Measurement.`,
13077
- 'must set both depthUpper and depthLower': () => `This measurement can vary substantially with depth.
13078
- We require you set ${schemaLink('Measurement#depthUpper', 'depthUpper')} and ${schemaLink('Measurement#depthLower', 'depthLower')}.
13079
- Please check the source for depth information and add it.
13080
- If the source does not have depth information, but you have evidence this measurement reflects the topsoil, set ${code('depthUpper = 0')} and ${code('depthLower = 20')}, and set ${schemaLink('Measurement#methodClassification', 'methodClassification')} to ${code('modelled using other measurements')} and describe this assumption usign ${schemaLink('Measurement#methodClassificationDescription', 'methodClassificationDescription')}.
13081
- If you have no evidence about the depth of the measurement, delete the data.`,
13082
- 'multiple cycles on the same site cannot overlap': (error, _, allErrors) => `Cycles taking place on the same Site cannot overlap:
13083
- ${formatList((allErrors.length ? allErrors : [error]).map(({ params }) => listAsCode(params.ids)))}
13084
- Please consider any of the following suggestions to resolve this conflict:
13085
- ${formatList([
13086
- `You can amend the Cycles' ${schemaLink('Cycle#startDate', 'startDate')} and ${schemaLink('Cycle#endDate', 'endDate')} to ensure that they do not overlap anymore.`,
13087
- 'You can break down your Cycles into shorter Cycles to ensure that they do not overlap anymore.',
13088
- `You can merge the overlapping Cycles into one overall Cycle if the Products of each Cycle are grown at the same time on the same Site.
13089
- This is relevant if intercropping is used, for instance.`,
13090
- `You can create a different Site for each overlapping Cycle.
13091
- This is appropriate if a field is divided into different plots, each dedicated to growing a different Product; each plot would be considered a unique Site on the platform.`
13092
- ])}
13093
- `,
13094
- 'cycles linked together cannot be added to the same site': ({ params }) => `Cycles linked together by an Impact Assessment cannot take place on the same Site.
13095
- Please create different Sites for the following Cycles: ${listAsCode(params.ids)}.`,
13096
- 'is not an allowed animalProduct': ({ params }) => `The ${glossaryTypeLink(TermTermType.liveAnimal)} producing this Product is not recorded in the ${schemaLink('Cycle#animals', 'Animal')} blank nodes. Either change this product or add the missing ${glossaryTypeLink(TermTermType.liveAnimal)} to the ${schemaLink('Cycle#animals', 'Animal')} blank nodes.
13097
- The allowed product ids are: ${listAsCode(params?.expected)}`,
13098
- 'duration must be in specified interval': ({ params: { term } = {} }) => ['shortFallow', 'shortBareFallow'].includes(term['@id'])
13099
- ? `${code('Short fallow')} is defined as land left fallow for less than 365 days.
13100
- Please check the ${schemaLink('Management#startDate', 'startDate')} and ${schemaLink('Management#endDate', 'endDate')} on this term and ensure the difference between the two dates is less than 365 days.
13101
- If it is more than 365 days, consider using the terms ${code('Long fallow')} or ${code('Set aside')} instead.`
13102
- : ['longFallow', 'longBareFallow'].includes(term['@id'])
13103
- ? `${code('Long fallow')} is defined as land left fallow for more than a year but less than five years.
13104
- Please check the ${schemaLink('Management#startDate', 'startDate')} and ${schemaLink('Management#endDate', 'endDate')} on this term and ensure the difference between the two dates falls between 365 and 1826 days.
13105
- If it is less than 365 days, consider using the term ${code('Short fallow')} instead.
13106
- If it is more than 1826 days, consider using the term ${code('Set aside')} instead.`
13107
- : `${code('Set aside')} is defined as the temporary set aside of land for more than five years but less than twenty years.
13108
- Please check the ${schemaLink('Management#startDate', 'startDate')} and ${schemaLink('Management#endDate', 'endDate')} on this term and ensure the difference between the two dates falls between 1826 and 7305 days.
13109
- If it is less than 1826 days, consider using the terms ${code('Short fallow')}or ${code('Long fallow')} instead.
13110
- If it is more than 7305 days, consider using the term ${code('Other natural vegetation')} instead.`,
13111
- 'must not add the feed input to the Cycle as well': ({ params: { term } = {} }) => `You have added the animal feed Input ${code(term['@id'])} to the Cycle inputs as well, which might lead to double counting.
13112
- If you do not know the amount of ${code(term['@id'])} given to each Animal, please add the Input to the Cycle only.`,
13113
- 'must provide value or min and max': ({ params }) => `You have provided only a ${code('max')} without a ${code('min')} or a ${code('value')}${params.term ? ` for ${termLink(params.term)}` : ''}.
13114
- ${params?.term?.termType === TermTermType.measurement
13115
- ? `This Measurement has additional restrictions and needs either a ${code('value')} or both a ${code('min')} and ${code('max')} specified.
13116
- Please consider adding both the ${code('min')} and the ${code('max')}, or delete the Measurement.`
13117
- : ''}`,
13118
- 'must specify water type for ponds': ({ params }) => `For Sites with ${schemaLink('Site#siteType', 'siteType')} = ${code('pond')}, you must specify the ${externalNodeLink({
13119
- '@type': NodeType.Term,
13120
- '@id': 'waterSalinity',
13121
- name: 'Water salinity'
13122
- })} or the water type (${externalNodeLink({
13123
- '@type': NodeType.Term,
13124
- '@id': 'salineWater',
13125
- name: 'Saline water'
13126
- })} / ${externalNodeLink({ '@type': NodeType.Term, '@id': 'freshWater', name: 'Fresh water' })} / ${externalNodeLink({
13127
- '@type': NodeType.Term,
13128
- '@id': 'brackishWater',
13129
- name: 'Brackish water'
13130
- })}).
13131
- This will allow us to calculate methane emissions from constructed waterbodies.
13132
- ${params?.products
13133
- ? `Note: our gap-filling model can only work when the lookup ${code('defaultSalinity')} is set for all products,
13134
- but we are currently missing a value for: ${joinValues(params.products)}.`
13135
- : ''}`,
13136
- 'invalid water salinity': ({ params }) => `The water type ${params?.current} is not consistent with the Water salinity you specified.
13137
- Make sure the Water salinity value is correct and either fix it or update the water type accordingly.`,
13138
- 'measurements for the same termType must be consistent': ({ params }) => `The information you have provided for ${code(params.termType)} Measurements is not consistent across all Measurements.
13139
- Please ensure that all your ${code(params.termType)} Measurements have a ${code('dates')} field if at least one ${code(params.termType)} Measurement has a ${code('dates')} field specified.
13140
- Please also ensure that all your ${code(params.termType)} Measurements have ${code('depthUpper')} and ${code('depthLower')} fields if at least one ${code(params.termType)} Measurement has ${code('depthUpper')} and ${code('depthLower')} fields specified.`,
13141
- 'must add substrate inputs': () => 'The substrate must be specified when a substrate-based protected cropping system has been added.',
13142
- 'should be equal to cycleDuration for crop': ({ params }) => `For temporary crop production Cycles, ${schemaLink('Cycle#siteDuration', 'siteDuration')} must represent the period from harvest of the previous crop to harvest of the current crop.
13143
- Here, you have stated that ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} represents the period from
13144
- ${code(params?.current)} to harvest of the current crop, and set ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} as not equal to ${schemaLink('Cycle#siteDuration', 'siteDuration')}.
13145
- Please check the affected fields for errors.`,
13146
- 'should be greater than cycleDuration for crop': ({ params }) => `For temporary crop production Cycles, ${schemaLink('Cycle#siteDuration', 'siteDuration')} must represent the period from harvest of the previous crop to harvest of the current crop.
13147
- Here, you have stated that ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} represents the period from
13148
- ${code(params?.current)} to harvest of the current crop, and set ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} as greater than ${schemaLink('Cycle#siteDuration', 'siteDuration')}.
13149
- Please check the affected fields for errors.`,
13150
- 'should be less than cycleDuration for animals': () => `You have specified that ${schemaLink('Cycle#siteDuration', 'siteDuration')} is greater than or equal to ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} for your Cycle.
13151
- However, because you indicated that there were ${schemaLink('Cycle#otherSites', 'otherSites')} used by the animals, this is not possible.
13152
- When ${schemaLink('Cycle#otherSites', 'otherSites')} is set, the Cycle's ${schemaLink('Cycle#siteDuration', 'siteDuration')} must be lower than the ${schemaLink('Cycle#cycleDuration', 'cycleDuration')}.
13153
- This is because the animals are also spending time on the other Sites.
13154
- Please fix the ${schemaLink('Cycle#siteDuration', 'siteDuration')} or the ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} accordingly.`,
13155
- 'should be equal to cycleDuration - otherSitesDuration for animals': () => `The values you have provided for your Cycle's ${schemaLink('Cycle#siteDuration', 'siteDuration')} and ${schemaLink('Cycle#otherSitesDuration', 'otherSitesDuration')} do not match the ${schemaLink('Cycle#cycleDuration', 'cycleDuration')}.
13156
- The sum of ${schemaLink('Cycle#siteDuration', 'siteDuration')} and all ${schemaLink('Cycle#otherSitesDuration', 'otherSitesDuration')} must equal ${schemaLink('Cycle#cycleDuration', 'cycleDuration')}.
13157
- Please amend the values of ${schemaLink('Cycle#siteDuration', 'siteDuration')}, ${schemaLink('Cycle#otherSitesDuration', 'otherSitesDuration')} or ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} accordingly.`,
13158
- 'should be equal to cycleDuration for animals': () => `You have specified that ${schemaLink('Cycle#siteDuration', 'siteDuration')} is not equal to ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} for your Cycle.
13159
- However, ${schemaLink('Cycle#siteDuration', 'siteDuration')} must equal ${schemaLink('Cycle#cycleDuration', 'cycleDuration')} for animal Cycles with a single associated Site.
13160
- Please ensure that the ${schemaLink('Cycle#siteDuration', 'siteDuration')} is equal to the ${schemaLink('Cycle#cycleDuration', 'cycleDuration')}.`,
13161
- 'is required when using other model': () => `If you are using the term ${code('Other model')}, please provide a short description of the model in ${code('methodModelDescription')}, including any references to model documentation.`,
13162
- 'should add the term productivePhasePermanentCrops': () => `You need to specify whether the permanent crop is in its productive phase when the value of the primary product is ${code('0')}.
13163
- To do this, add the ${termLink({
13164
- id: 'productivePhasePermanentCrops',
13165
- name: 'Productive phase (permanent crops)'
13166
- })} practice and set a value of ${code('true')} or ${code('false')}.`,
13167
- 'must have a single inputs of termType waste': () => `Can only be linked to a single ${glossaryTypeLink(TermTermType.waste)} input.`,
13168
- 'must be below maximum cycleDuration': ({ params }) => `The maximum duration for this crop production cycle is ${params.limit} days,
13169
- but the calculated duration from the end date and start date provided is ${params.current}.`,
13170
- 'should add the term pastureGrass': () => `For Cycles with ${code('siteType=permanent pasture')} we recommend specifying the type(s) of ${code('Pasture grass')} grown.
13171
- This is particularly important for ruminants and will allow for a more accurate estimate of the amount of grass grazed.`,
13172
- 'should add the fields for a relative cycle': ({ params }) => `We strongly recommend setting ${params?.expected
13173
- ?.map((param) => code(param))
13174
- .join('and')} on all other sites for any uploads with a ${code('relative')} functional unit. This will allow calculation of land occupation and land transformation.`,
13175
- 'must not be blank if complete': ({ params }) => `If completeness is set to true for ${schemaLink(`Completeness#${params.expected}`, params.expected)}, none of the data in the completeness area can have missing or blank values.`,
13176
- 'primary product cannot be an input': ({ params }) => params.siteType === SiteSiteType['agri-food processor']
13177
- ? `For a processing cycle, the primary Product must not also be an Input into the cycle.
13178
- This ensures we reflect the full process rather than just single sub-processes.
13179
- Use Transformations if needed to represent additional processing steps rather than new Cycles.`
13180
- : `The primary Product must not also be an Input into the cycle.`,
13181
- 'must have a primary processing operation': () => `For processing cycles, a primary Operation must be specified, it should reflect the main process in the Cycle.`,
13182
- 'primaryPercent not allowed on this siteType': ({ params }) => `The ${schemaLink('Practice#primaryPercent', 'primaryPercent')} can only be used on ${schemaLink('Site#siteType', 'siteType')} ${params?.expected?.map(code).join(' or ')}.`,
13183
- 'primaryPercent not allowed on this practice': () => `This practice is not a processing operation.
13184
- You can only add the ${schemaLink('Practice#primaryPercent', 'primaryPercent')} field to terms with ${code('termType')} = ${code(TermTermType.operation)} and lookup ${code('isProcessingOperation')} = ${code(true)}.`,
13185
- 'at least one landCover practice must match an equivalent product': ({ params }) => `To ensure there is no conflicting data between your Cycle and Products, your specified ${code(TermTermType.landCover)} Practices must match a Product.
13186
- ${formatList([
13187
- `Ensure at least one Practice matches a Product (e.g., ${listAsCode(params?.current)} matching ${listAsCode(params?.expected)}). Check ${code('landCoverTermId')} in the glossary for equivalents.`,
13188
- `If specifying fallow periods, you must also include the Product's equivalent Practice with a ${code('startDate')} and ${code('endDate')}.`,
13189
- `Alternatively, do not set these ${code(TermTermType.landCover)} practices, and they will be gap filled automatically from products.`
13190
- ])}`,
13191
- 'should match the site management node value': () => `The data you have uploaded in the Management node are not consistent with the data provided in the Cycles.
13192
- If the same ${code('term')} is used between the same ${code('startDate')} and ${code('endDate')}, they must have the same ${code('value')} in ${code('Management')} and in the Cycles.
13193
- Please check your upload and ensure that the data is consistent throughout.`,
13194
- 'saplings cannot be used as an input here': () => `To input ${code('Saplings')} into a plantation crop Cycle, you must use ${externalNodeLink({
13195
- '@type': NodeType.Term,
13196
- '@id': 'saplingsDepreciatedAmountPerCycle',
13197
- name: 'Saplings, depreciated amount per Cycle'
13198
- })}.
13199
- This input should be present in each plantation Cycle in your upload, with the ${code('value')} being the total number of ${code('Saplings')} used divided by the number of possible Cycles in the plantation's lifespan.
13200
- See the ${guideLink('guide-file-upload-special-cases', 'special upload case')} for more details.`,
13201
- 'must be linked to a verified country-level Impact Assessment': ({ params }) => [
13202
- 'This Input must be linked to a country-level verified aggregation, but none could be found.',
13203
- params?.current ? 'Note: using a verified World aggregation is not valid.' : ''
13204
- ]
13205
- .filter(Boolean)
13206
- .join('\n'),
13207
- 'must contain water inputs': () => `If ${schemaLink('Completeness#water', 'completeness.water')}=${code(true)} for irrigated Cycles, you must provide ${glossaryTypeLink(TermTermType.water)} inputs.
13208
- Otherwise, set ${schemaLink('Completeness#water', 'completeness.water')}=${code(false)}.`,
13209
- 'must be true for rainfed cycles': () => 'For rainfed cycles, water completeness should be TRUE as other water inputs are negligible to irrigation quantities.',
13210
- 'must not set rainfed with water inputs': ({ params }) => `For Cycles with rainfed practices (${listAsCode(params.termIds)}), the sum of the ${code(TermTermType.water)} inputs must be below ${code(params.expected)}m3.
13211
- If the ${code(TermTermType.water)} inputs are correct, then the ${code(TermTermType.waterRegime)} practices should be set as one of the "irrigated" terms.`,
13212
- 'management date must be before cycle start date': () => `The Site Management's dates must not overlap with any of the Cycles' dates.
13213
- The Site Management must only be used to record historical information about years preceding your first Cycle.
13214
- If you are trying to specify land management or practices that take place during the period covered by your Cycles, please do so directly in the Cycles, using the Product or Practice nodes.
13215
- Please refer to our Guide section on special case uploads for more information: ${guideLink('guide-file-upload-special-cases', 'special upload case')}.
13216
- Note: if the first Cycle ${code('startDate')} is not provided, the ${code('cycleDuration')} can be used to set the earliest date of overlap.
13217
- If the first Cycle ${code('cycleDuration')} is not provided, the lookup of the ${code('maximumCycleDuration')} primary Product can be used to set the earliest date of overlap.`,
13218
- 'must be in the same format as endDate': () => `The date format does not match the format of ${code('endDate')}. You must use the same date format for both fields.`,
13219
- 'must be at least equal to the minimum value': ({ params: { min } }) => `Must be at least equal to ${min}`,
13220
- 'must equal to endDate - startDate in days': ({ params: { expected } }) => `Must be equal to ${code('endDate')} - ${code('startDate')} in days (inclusive of the ${code('startDate')} and ${code('endDate')} days) (~${expected})`,
13221
- 'must equal to endDate - startDate in decimal years': ({ params: { expected } }) => `Must be equal to ${code('endDate')} - ${code('startDate')} in years (~${expected})`,
13222
- 'must be more than or equal to other crop residues': ({ params: { expected } }) => `Must be more than or equal to sum(${expected.join(' + ')})`,
13223
- 'should add missing inputs': ({ params: { expected } }) => `Should add missing inputs: ${listAsCode(expected)}`,
13224
- 'the property value type is incorrect': ({ params: { expected } }) => `The value must be a ${expected}.`,
13225
- 'the node value type is incorrect': ({ params: { expected } }) => `The value must be a ${expected}.`,
13226
- 'can not be linked to the same type': ({ params: { current } }) => `Cannot be linked to the same ${current}.`,
13227
- 'must be lower or equal to siteArea': () => `The value of ${code('harvestedArea')} cannot be greater than ${code('siteArea')}.
13228
- This is because ${code('harvestedArea')} corresponds to the extent of the overall ${code('siteArea')} that is actually harvested.
13229
- Please amend the value of ${code('harvestedArea')} accordingly.`,
13230
- 'must be above the minimum': ({ params: { min } }) => `Must be above ${min}.`,
13231
- 'must be below the maximum': ({ params: { max } }) => `Must be below ${max}.`,
13232
- 'must be linked to waste input': () => `The term ${code('ionisingCompoundsToAirInputsProduction')} can only have 1 entry of ${code('termType')}: ${glossaryTypeLink(TermTermType.waste)}, so that the ${code('value')} field can represent the amount of units of that waste term.`,
13233
- 'must not have background methodTier': ({ params: { allowedValues } }) => `Only background emissions (e.g., "Inputs Production") can have ${code('methodTier')}=${EmissionMethodTier.background}.
13234
- You must instead choose one of the following values: ${listAsCode(allowedValues)}`,
13235
- 'should be within acceptable range of the lookup value': ({ params }) => `The ${code(params.term['@id'])} value is ${code(params.delta)}% higher than our default value for this Term (${code(params.expected)}).
13236
- Please check your data as this may be an error. ${params?.threshold ? `Our threshold is ±${threshold(params?.threshold)}.` : ''}`,
13237
- 'should add missing properties': ({ params: { expected, termType } }) => [
13238
- `We recommend adding the following properties: ${listAsCode(expected)}.`,
13239
- termType === TermTermType.liveAnimal
13240
- ? `These properties influence energy requirements and are used for estimating grass intake.`
13241
- : null,
13242
- termType === TermTermType.animalManagement ? `These properties will be used for estimating grass intake.` : null,
13243
- 'If not added, default values might be used.'
13244
- ]
13245
- .filter(Boolean)
13246
- .join('\n'),
13247
- 'should set the depth': ({ params }) => `The value of Emission ${code(params.term['@id'])} can change significantly based on the soil depth taken into account.
13248
- Please consider adding ${schemaLink('Emission#depthUpper', 'depthUpper')} and ${schemaLink('Emission#depthLower', 'depthLower')} fields to the Emission.`,
13249
- 'must include practices for plantation weighting': () => `For permanent crop aggregations, we must be able to weight based on the plantation phase.
13250
- This means practices ${externalNodeLink({
13251
- '@type': NodeType.Term,
13252
- '@id': 'plantationLifespan'
13253
- })} and ${externalNodeLink({ '@type': NodeType.Term, '@id': 'plantationProductiveLifespan' })} must have values.`
13254
- };
13255
- const requiredPropertyError = (message, error) => {
13256
- const field = message.split("'")[1].replace("'", '');
13257
- const nodeType = dataPathLabel(error?.dataPath);
13258
- return `You are missing the following required field: ${code(field)}. ${nodeType && nodeType.toLowerCase() !== 'completeness'
13259
- ? `Either: add ${code(field)}, or if you if you did not intend to add this ${nodeType}, please remove all fields on this ${nodeType}.`
13260
- : ''}`.trim();
13261
- };
13262
- const parseDefaultMessage = (message, error) => `<span class="is-capitalized-first-letter">${message?.startsWith('should have required property') ? requiredPropertyError(message, error) : message}</span>`;
13263
- const formatCustomErrorMessage = (message, error, allErrors = []) => {
13264
- const formattedMessage = customErrorMessage?.[message]
13265
- ? customErrorMessage[message](error, allErrors.length || 1, allErrors)
13266
- : parseDefaultMessage(message, error);
13267
- return formattedMessage ? `<p class="is-normal">${formattedMessage}</p>` : '';
13268
- };
13269
- const formatError = (error, allErrors = []) => error
13270
- ? {
13271
- level: 'error',
13272
- ...error,
13273
- message: formatCustomErrorMessage(error.message, error, allErrors)
13274
- }
13275
- : undefined;
13276
- const errorHasError = (error) => error && (error.level === 'error' || !error.level);
13277
- const errorHasWarning = (error) => error && error.level === 'warning';
13278
- const isMissingPropertyError = ({ params }) => !!params && 'missingProperty' in params;
13279
- const isMissingOneOfError = ({ keyword, schemaPath }) => keyword === 'required' && (schemaPath || '').includes('oneOf');
13280
- const isFailingKeywordError = ({ params }) => !!params && 'failingKeyword' in params;
13281
- const filterError = (error) => [isFailingKeywordError].every(func => !func(error));
13282
- const missingNodeErrors = (errors) => errors.filter(({ keyword, params }) => keyword === 'required' && (params?.missingProperty === '@type' || params?.missingProperty === '@id'));
12588
+ /**
12589
+ * Angular-side adapter over the framework-agnostic error catalog.
12590
+ *
12591
+ * The single source of truth for error messages lives in the standalone `errors` entry
12592
+ * point (`@hestia-earth/ui-components/file-errors`). Here we bind it to the HTML renderer (the
12593
+ * exact Bulma-classed output the platform UI expects) and to URLs derived from
12594
+ * `window.location`, then re-export the same public API this module has always exposed.
12595
+ */
12596
+ const formatter$1 = createErrorFormatter({
12597
+ renderer: htmlRenderer,
12598
+ urls: { baseUrl, glossaryBaseUrl, schemaBaseUrl }
12599
+ });
12600
+ const parseDataPath = formatter$1.parseDataPath;
12601
+ const dataPathLabel = formatter$1.dataPathLabel;
12602
+ const migrationErrorMessage = formatter$1.migrationErrorMessage;
12603
+ const formatCustomErrorMessage = formatter$1.formatCustomErrorMessage;
12604
+ const formatError = formatter$1.formatError;
13283
12605
 
13284
12606
  /* eslint-disable complexity */
13285
12607
  const missingNodeErrorMessage = ({ '@type': _t, type, name }, missingIdError) => (_t || type) === 'Term'
@@ -13583,6 +12905,11 @@ const propertyError = (errors) => (dataPath, nonExpandableArray = false) => erro
13583
12905
  (nonExpandableArray &&
13584
12906
  nonExpandableArrayDataPath(error.dataPath) === nonExpandableArrayDataPath(dataPath))) &&
13585
12907
  (dataPath.length > 0 || !isMissingPropertyError(error)));
12908
+ const propertySchema = (schemas, schemaType, key, expandable) => (schemas && isTypeValid({ type: schemaType })
12909
+ ? expandable
12910
+ ? schemas[schemaType]
12911
+ : schemas[schemaType].properties[key]
12912
+ : null) || {};
13586
12913
  const missingPropertyErrors = (node, errors, parent = '') => {
13587
12914
  const allErrors = errors.filter(error => error.dataPath === keyToDataPath(parent) && isMissingPropertyError(error));
13588
12915
  // check for node not found errors
@@ -13628,16 +12955,18 @@ const missingPropertyErrors = (node, errors, parent = '') => {
13628
12955
  };
13629
12956
  });
13630
12957
  };
13631
- const requiredPropertyErrors = (node, errors, parent = '') => {
12958
+ const requiredPropertyErrors = (schemas, node, errors, parent = '') => {
13632
12959
  const allErrors = errors.filter(error => parentKey(error.dataPath) === parent && error.message === 'this field is required');
13633
12960
  return allErrors.map(error => {
12961
+ const key = error.dataPath.split('.').pop();
13634
12962
  const fullKey = error.dataPath;
13635
12963
  const missingOneOf = isMissingOneOfError(error);
13636
12964
  return {
13637
12965
  id: propertyId(),
12966
+ schema: propertySchema(schemas, node.type, key),
13638
12967
  schemaType: node.type,
13639
12968
  suggestions: { type: defaultSuggestionType },
13640
- key: error.dataPath.split('.').pop(),
12969
+ key: key,
13641
12970
  fullKey,
13642
12971
  value: '',
13643
12972
  editable: false,
@@ -13665,11 +12994,7 @@ const propertyFromNode = (schemas, errors, nodeSchema, deepEditable, parent = ''
13665
12994
  ? value[0].type || value[0]['@type']
13666
12995
  : value.type || value['@type']
13667
12996
  : nodeType;
13668
- const schema = (schemas && isTypeValid({ type: schemaType })
13669
- ? expandable
13670
- ? schemas[schemaType]
13671
- : schemas[schemaType].properties[key]
13672
- : null) || {};
12997
+ const schema = propertySchema(schemas, schemaType, key, expandable);
13673
12998
  const isIri = isSchemaIri(schema);
13674
12999
  const error = propertyError(errors)(keyToDataPath(fullKey), nonExpandableArray);
13675
13000
  const parentSchema = expandable
@@ -13737,7 +13062,7 @@ const recursiveProperties = (schemas, errors, nodeSchema, deepEditable, parent =
13737
13062
  .filter(key => !ignoreKeys.includes(key))
13738
13063
  .map(propertyFromNode(schemas, errors, nodeSchema, deepEditable, parent, node, parentNode || node))
13739
13064
  .concat(...missingPropertyErrors(node, errors, parent))
13740
- .concat(...requiredPropertyErrors(node, errors, parent))
13065
+ .concat(...requiredPropertyErrors(schemas, node, errors, parent))
13741
13066
  .sort(sortProperties);
13742
13067
  const fullKeyParts = (fullKey) => fullKey.split('.').flatMap(val => {
13743
13068
  if (val.endsWith(']')) {
@@ -14150,7 +13475,7 @@ class FilesFormComponent {
14150
13475
  return focusFirstError(this.ref.nativeElement);
14151
13476
  }
14152
13477
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
14153
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FilesFormComponent, isStandalone: true, selector: "he-files-form", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, showNodeLink: { classPropertyName: "showNodeLink", publicName: "showNodeLink", isSignal: true, isRequired: false, transformFunction: null }, errorGuidePrefix: { classPropertyName: "errorGuidePrefix", publicName: "errorGuidePrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", nodeErorrResolved: "nodeErorrResolved" }, exportAs: ["filesForm"], ngImport: i0, template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#48c78e}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { 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: NodeIconComponent, selector: "he-node-icon", inputs: ["type", "size"] }, { kind: "component", type: SitesMapsComponent, selector: "he-sites-maps", inputs: ["loadPolygons", "sites", "zoom", "showNotice"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: ClipboardComponent, selector: "he-clipboard", inputs: ["icon", "value", "disabled", "hideText", "hideIcon", "size", "clipboardClass", "tooltipPlacement"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
13478
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FilesFormComponent, isStandalone: true, selector: "he-files-form", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, showNodeLink: { classPropertyName: "showNodeLink", publicName: "showNodeLink", isSignal: true, isRequired: false, transformFunction: null }, errorGuidePrefix: { classPropertyName: "errorGuidePrefix", publicName: "errorGuidePrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", nodeErorrResolved: "nodeErorrResolved" }, exportAs: ["filesForm"], ngImport: i0, template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#48c78e}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { 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: NodeIconComponent, selector: "he-node-icon", inputs: ["type", "size"] }, { kind: "component", type: SitesMapsComponent, selector: "he-sites-maps", inputs: ["loadPolygons", "sites", "zoom", "showNotice"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: ClipboardComponent, selector: "he-clipboard", inputs: ["icon", "value", "disabled", "hideText", "hideIcon", "size", "clipboardClass", "tooltipPlacement"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
14154
13479
  }
14155
13480
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesFormComponent, decorators: [{
14156
13481
  type: Component$1,
@@ -14166,7 +13491,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
14166
13491
  ClipboardComponent,
14167
13492
  GuideOverlayComponent,
14168
13493
  EllipsisPipe
14169
- ], template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#48c78e}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"] }]
13494
+ ], template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#48c78e}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"] }]
14170
13495
  }], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }, { type: i0.Output, args: ["isOpenChange"] }], node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], showNodeLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNodeLink", required: false }] }], errorGuidePrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorGuidePrefix", required: false }] }], nodeErorrResolved: [{ type: i0.Output, args: ["nodeErorrResolved"] }] } });
14171
13496
 
14172
13497
  class SchemaInfoComponent {
@@ -17029,5 +16354,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
17029
16354
  * Generated bundle index. Do not edit.
17030
16355
  */
17031
16356
 
17032
- export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, 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, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJLogModelsComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorHasError, errorHasWarning, errorText, evaluateSuccess, exportAsSVG, exportFormats, 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, groupJLogByField, groupJLogByTerm, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, guidePageId, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isMigrationError, isMissingOneOfError, isMissingPropertyError, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, jLogModelCount, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, locationQuery, logToCsv$2 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, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
16357
+ export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, 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, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJLogModelsComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorText, evaluateSuccess, exportAsSVG, exportFormats, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupChanged, groupJLogByField, groupJLogByTerm, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, jLogModelCount, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, locationQuery, logToCsv$2 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, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
17033
16358
  //# sourceMappingURL=hestia-earth-ui-components.mjs.map