@hestia-earth/ui-components 0.42.11 → 0.42.13
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.
|
@@ -16,7 +16,7 @@ import { select, selectAll } from 'd3-selection';
|
|
|
16
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';
|
|
17
17
|
import { json2csv } from 'json-2-csv';
|
|
18
18
|
import { propertyValue as propertyValue$1, emptyValue } from '@hestia-earth/utils/term';
|
|
19
|
-
import { getDefaultModelId, getModelGroup, loadResourceKey, isInSystemBoundary } from '@hestia-earth/glossary';
|
|
19
|
+
import { getDefaultModelId, getModelGroup, loadResourceKey, getArrayTreatment, isInSystemBoundary } from '@hestia-earth/glossary';
|
|
20
20
|
import isEqual$1 from 'lodash.isequal';
|
|
21
21
|
import { DataState, filenameWithoutExt, nodeTypeToParam, allowedDataStates, SupportedExtensions, fileToExt, fileExt, maxFileSizeMb } from '@hestia-earth/api';
|
|
22
22
|
import { models as models$1, loadConfig, getMaxStage } from '@hestia-earth/engine-models';
|
|
@@ -1784,11 +1784,11 @@ class BlankNodeValueDeltaComponent {
|
|
|
1784
1784
|
this.color = computed(() => this.displayType() === DeltaDisplayType.percent ? evaluateSuccess(this.delta()) : '', ...(ngDevMode ? [{ debugName: "color" }] : []));
|
|
1785
1785
|
}
|
|
1786
1786
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BlankNodeValueDeltaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1787
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: BlankNodeValueDeltaComponent, isStandalone: true, selector: "he-blank-node-value-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, originalValue: { classPropertyName: "originalValue", publicName: "originalValue", isSignal: true, isRequired: false, transformFunction: null }, displayType: { classPropertyName: "displayType", publicName: "displayType", isSignal: true, isRequired: false, transformFunction: null }, useCustomFunctions: { classPropertyName: "useCustomFunctions", publicName: "useCustomFunctions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!hide()) {\n <small class=\"has-text-{{ color() }}\">\n
|
|
1787
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: BlankNodeValueDeltaComponent, isStandalone: true, selector: "he-blank-node-value-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, originalValue: { classPropertyName: "originalValue", publicName: "originalValue", isSignal: true, isRequired: false, transformFunction: null }, displayType: { classPropertyName: "displayType", publicName: "displayType", isSignal: true, isRequired: false, transformFunction: null }, useCustomFunctions: { classPropertyName: "useCustomFunctions", publicName: "useCustomFunctions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!hide()) {\n @if (delta() === 0) {\n <!-- no difference between the values: a \"0 %\"/\"0\" delta carries no information, show a dash instead -->\n <small>-</small>\n } @else {\n <small class=\"has-text-{{ color() }}\">\n @if (delta() > 0) {\n <span>+</span>\n }\n @switch (displayType()) {\n @case (DeltaDisplayType.absolute) {\n <span>{{ delta() | precision: 3 }}</span>\n }\n @case (DeltaDisplayType.percent) {\n <span>{{ delta() | number: '1.0-2' }}</span>\n <span>%</span>\n }\n }\n </small>\n }\n}\n", styles: [""], dependencies: [{ kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1788
1788
|
}
|
|
1789
1789
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BlankNodeValueDeltaComponent, decorators: [{
|
|
1790
1790
|
type: Component$1,
|
|
1791
|
-
args: [{ selector: 'he-blank-node-value-delta', changeDetection: ChangeDetectionStrategy.OnPush, imports: [DecimalPipe, PrecisionPipe], template: "@if (!hide()) {\n <small class=\"has-text-{{ color() }}\">\n
|
|
1791
|
+
args: [{ selector: 'he-blank-node-value-delta', changeDetection: ChangeDetectionStrategy.OnPush, imports: [DecimalPipe, PrecisionPipe], template: "@if (!hide()) {\n @if (delta() === 0) {\n <!-- no difference between the values: a \"0 %\"/\"0\" delta carries no information, show a dash instead -->\n <small>-</small>\n } @else {\n <small class=\"has-text-{{ color() }}\">\n @if (delta() > 0) {\n <span>+</span>\n }\n @switch (displayType()) {\n @case (DeltaDisplayType.absolute) {\n <span>{{ delta() | precision: 3 }}</span>\n }\n @case (DeltaDisplayType.percent) {\n <span>{{ delta() | number: '1.0-2' }}</span>\n <span>%</span>\n }\n }\n </small>\n }\n}\n" }]
|
|
1792
1792
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], originalValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "originalValue", required: false }] }], displayType: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayType", required: false }] }], useCustomFunctions: [{ type: i0.Input, args: [{ isSignal: true, alias: "useCustomFunctions", required: false }] }] } });
|
|
1793
1793
|
|
|
1794
1794
|
const defaultIcon = 'clipboard';
|
|
@@ -8793,11 +8793,11 @@ class NodeLogsModelsLogsComponent {
|
|
|
8793
8793
|
sorting.sortOrder = sortOrder;
|
|
8794
8794
|
}
|
|
8795
8795
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsLogsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8796
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsLogsComponent, isStandalone: true, selector: "he-node-logs-models-logs", inputs: { logs: { classPropertyName: "logs", publicName: "logs", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"table-container\">\n
|
|
8796
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsLogsComponent, isStandalone: true, selector: "he-node-logs-models-logs", inputs: { logs: { classPropertyName: "logs", publicName: "logs", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (allLogs().length) {\n <div class=\"table-container\">\n <table class=\"table is-dark is-fullwidth\">\n <tbody>\n @for (log of allLogs(); track log.key) {\n <ng-container *ngTemplateOutlet=\"logRow; context: log\" />\n }\n </tbody>\n </table>\n </div>\n} @else if (!missingLookups().length) {\n <p>No specific logs available for this model.</p>\n}\n\n@if (missingLookups().length) {\n <div class=\"it-mt-2\">\n <p>Data missing (might be optional):</p>\n <div class=\"table-container data-table-container\">\n <table class=\"table is-dark is-fullwidth is-striped\">\n <thead>\n <tr>\n <th class=\"has-text-white\">\n <span>Filename</span>\n </th>\n <th class=\"has-text-white\">\n <span>Column Title</span>\n </th>\n <th class=\"has-text-white\">\n <span>Row (term.id)</span>\n </th>\n </tr>\n </thead>\n <tbody class=\"has-text-white\">\n @for (data of missingLookups(); track dataIndex; let dataIndex = $index) {\n <tr>\n <td>{{ data.filename }}</td>\n <td>{{ data.column }}</td>\n <td>{{ data.termId }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n}\n\n@if (raw()) {\n <div class=\"is-mt-2\">\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <a class=\"has-text-white\" (click)=\"toggleRaw()\">\n <he-svg-icon [name]=\"showRaw() ? 'chevron-down' : 'chevron-right'\" size=\"16\" />\n <span>Raw log</span>\n </a>\n @if (showRaw()) {\n <he-clipboard clipboardClass=\"is-size-7 is-p-1\" [value]=\"rawJson()\" [hideText]=\"true\" />\n }\n </div>\n @if (showRaw()) {\n <pre class=\"raw-log is-mt-1\">{{ rawJson() }}</pre>\n }\n </div>\n}\n\n<ng-template #sortColumn let-column=\"column\" let-sorting=\"sorting\">\n <a class=\"is-p-1 has-text-white\" (click)=\"toggleSort(column, sorting)\">\n @if (sorting.sortBy === column) {\n @if (sorting.sortOrder === 'asc') {\n <he-svg-icon name=\"sort-caret-up-filled\" size=\"16\" />\n } @else {\n <he-svg-icon name=\"sort-caret-down-filled\" size=\"16\" />\n }\n } @else {\n <he-svg-icon name=\"sort-caret-stacked-filled-stacked\" size=\"16\" />\n }\n </a>\n</ng-template>\n\n<ng-template #logLineArray let-value=\"value\" let-sorting=\"sorting\">\n <table class=\"table is-dark is-bordered is-striped\">\n @let headers = listHeaders(value);\n @if (headers.length) {\n <thead>\n <tr>\n @for (header of headers; track header) {\n <th class=\"has-text-white\">\n <div class=\"is-nowrap\">\n {{ header }}\n <ng-container *ngTemplateOutlet=\"sortColumn; context: { column: header, sorting }\" />\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n <tbody>\n @for (v of value | sortBy: sorting.sortBy : sorting.sortOrder; track vIndex; let vIndex = $index) {\n <tr>\n @if (headers.length) {\n @for (header of headers; track header) {\n <td>{{ v[header] }}</td>\n }\n } @else {\n <td>{{ v }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n</ng-template>\n\n<ng-template #logLineValue let-key=\"key\" let-value=\"value\">\n @if (requirementLinkedNode(key, value); as linkedNode) {\n <he-node-link\n class=\"is-inline-block is-align-middle\"\n linkClass=\"is-dark\"\n [node]=\"linkedNode\"\n [showExternalLink]=\"true\" />\n } @else {\n <span class=\"is-inline-block is-align-middle\">{{ value }}</span>\n }\n</ng-template>\n\n<ng-template #logRow let-key=\"key\" let-value=\"value\" let-isCompleteness=\"isCompleteness\" let-complete=\"complete\">\n <tr>\n <td class=\"has-border-right | copy-log\">\n <span class=\"is-inline-block is-align-middle\">\n @if (isCompleteness) {\n <span>Data completeness for</span>\n <code class=\"is-mx-1\">{{ key }}</code>\n <span>must be</span>\n <code class=\"is-mx-1\">{{ complete }}</code>\n } @else {\n @switch (key) {\n @default {\n {{ parseKey(key) }}\n }\n @case ('property_id') {\n Property Term @id\n }\n @case ('product_id') {\n Product Term @id\n }\n @case ('crop_product_id') {\n Crop Product Term @id\n }\n @case ('input_id') {\n Input Term @id\n }\n @case ('node_type_allowed') {\n <span>Is the current</span>\n <code class=\"is-mx-1\">Node</code>\n <span>allowed to run this model</span>\n }\n @case ('siteType_allowed') {\n <span>Is the current</span>\n <code class=\"is-mx-1\">siteType</code>\n <span>allowed to run this model</span>\n }\n @case ('product_id_allowed') {\n <span>Are any of the Product</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('site_measurement_id_allowed') {\n <span>Are any of the Measurement</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('product_termType_allowed') {\n <span>Are any of the Product</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n @case ('input_id_allowed') {\n <span>Are any of the Input</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('input_termType_allowed') {\n <span>Are any of the Input</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n <!-- Deprecated -->\n @case ('primary_product_id_allowed') {\n <span>Is the current primary product</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('primary_product_termType_allowed') {\n <span>Is the current primary product</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n @case ('has_pesticides_inputs') {\n <span>Cycle contains</span>\n <code class=\"is-mx-1\">pesticideAI</code>\n <span>Inputs</span>\n }\n @case ('all_pesticideAI_have_lookup_value') {\n <span>All</span>\n <code class=\"is-mx-1\">pesticideAI</code>\n <span>Inputs have a lookup value</span>\n }\n @case ('has_crop_residue_burnt') {\n <code class=\"is-mr-1\">aboveGroundCropResidueBurnt</code>\n <span>is present as Product</span>\n }\n @case ('no_cycle_inputs_feed') {\n <span>\n Cycle has\n <b>no</b>\n Input with\n </span>\n <code>isAnimalFeed=true</code>\n }\n @case ('has_cycle_inputs_feed') {\n <span>\n Cycle has\n <b>some</b>\n Input with\n </span>\n <code>isAnimalFeed=true</code>\n }\n }\n }\n </span>\n <he-clipboard\n class=\"is-inline-block is-align-middle\"\n clipboardClass=\"is-size-7 is-p-1\"\n [value]=\"key\"\n [hideText]=\"true\" />\n </td>\n <td>\n @if (value | isArray) {\n <ng-container *ngTemplateOutlet=\"logLineArray; context: { value: value, sorting: {} }\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"logLineValue; context: { key, value }\" />\n }\n </td>\n </tr>\n</ng-template>\n", styles: [".copy-log he-clipboard{visibility:hidden}.copy-log:hover he-clipboard{visibility:visible}.raw-log{max-height:300px;overflow:auto;white-space:pre;font-size:.75rem;background:#00000059;color:inherit;padding:.5rem;border-radius:3px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: ClipboardComponent, selector: "he-clipboard", inputs: ["icon", "value", "disabled", "hideText", "hideIcon", "size", "clipboardClass", "tooltipPlacement"] }, { kind: "pipe", type: SortByPipe, name: "sortBy" }, { kind: "pipe", type: IsArrayPipe, name: "isArray" }] }); }
|
|
8797
8797
|
}
|
|
8798
8798
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsLogsComponent, decorators: [{
|
|
8799
8799
|
type: Component$1,
|
|
8800
|
-
args: [{ selector: 'he-node-logs-models-logs', imports: [NgTemplateOutlet, HESvgIconComponent, NodeLinkComponent, ClipboardComponent, SortByPipe, IsArrayPipe], template: "<div class=\"table-container\">\n
|
|
8800
|
+
args: [{ selector: 'he-node-logs-models-logs', imports: [NgTemplateOutlet, HESvgIconComponent, NodeLinkComponent, ClipboardComponent, SortByPipe, IsArrayPipe], template: "@if (allLogs().length) {\n <div class=\"table-container\">\n <table class=\"table is-dark is-fullwidth\">\n <tbody>\n @for (log of allLogs(); track log.key) {\n <ng-container *ngTemplateOutlet=\"logRow; context: log\" />\n }\n </tbody>\n </table>\n </div>\n} @else if (!missingLookups().length) {\n <p>No specific logs available for this model.</p>\n}\n\n@if (missingLookups().length) {\n <div class=\"it-mt-2\">\n <p>Data missing (might be optional):</p>\n <div class=\"table-container data-table-container\">\n <table class=\"table is-dark is-fullwidth is-striped\">\n <thead>\n <tr>\n <th class=\"has-text-white\">\n <span>Filename</span>\n </th>\n <th class=\"has-text-white\">\n <span>Column Title</span>\n </th>\n <th class=\"has-text-white\">\n <span>Row (term.id)</span>\n </th>\n </tr>\n </thead>\n <tbody class=\"has-text-white\">\n @for (data of missingLookups(); track dataIndex; let dataIndex = $index) {\n <tr>\n <td>{{ data.filename }}</td>\n <td>{{ data.column }}</td>\n <td>{{ data.termId }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n}\n\n@if (raw()) {\n <div class=\"is-mt-2\">\n <div class=\"is-flex is-align-items-center is-gap-8\">\n <a class=\"has-text-white\" (click)=\"toggleRaw()\">\n <he-svg-icon [name]=\"showRaw() ? 'chevron-down' : 'chevron-right'\" size=\"16\" />\n <span>Raw log</span>\n </a>\n @if (showRaw()) {\n <he-clipboard clipboardClass=\"is-size-7 is-p-1\" [value]=\"rawJson()\" [hideText]=\"true\" />\n }\n </div>\n @if (showRaw()) {\n <pre class=\"raw-log is-mt-1\">{{ rawJson() }}</pre>\n }\n </div>\n}\n\n<ng-template #sortColumn let-column=\"column\" let-sorting=\"sorting\">\n <a class=\"is-p-1 has-text-white\" (click)=\"toggleSort(column, sorting)\">\n @if (sorting.sortBy === column) {\n @if (sorting.sortOrder === 'asc') {\n <he-svg-icon name=\"sort-caret-up-filled\" size=\"16\" />\n } @else {\n <he-svg-icon name=\"sort-caret-down-filled\" size=\"16\" />\n }\n } @else {\n <he-svg-icon name=\"sort-caret-stacked-filled-stacked\" size=\"16\" />\n }\n </a>\n</ng-template>\n\n<ng-template #logLineArray let-value=\"value\" let-sorting=\"sorting\">\n <table class=\"table is-dark is-bordered is-striped\">\n @let headers = listHeaders(value);\n @if (headers.length) {\n <thead>\n <tr>\n @for (header of headers; track header) {\n <th class=\"has-text-white\">\n <div class=\"is-nowrap\">\n {{ header }}\n <ng-container *ngTemplateOutlet=\"sortColumn; context: { column: header, sorting }\" />\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n <tbody>\n @for (v of value | sortBy: sorting.sortBy : sorting.sortOrder; track vIndex; let vIndex = $index) {\n <tr>\n @if (headers.length) {\n @for (header of headers; track header) {\n <td>{{ v[header] }}</td>\n }\n } @else {\n <td>{{ v }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n</ng-template>\n\n<ng-template #logLineValue let-key=\"key\" let-value=\"value\">\n @if (requirementLinkedNode(key, value); as linkedNode) {\n <he-node-link\n class=\"is-inline-block is-align-middle\"\n linkClass=\"is-dark\"\n [node]=\"linkedNode\"\n [showExternalLink]=\"true\" />\n } @else {\n <span class=\"is-inline-block is-align-middle\">{{ value }}</span>\n }\n</ng-template>\n\n<ng-template #logRow let-key=\"key\" let-value=\"value\" let-isCompleteness=\"isCompleteness\" let-complete=\"complete\">\n <tr>\n <td class=\"has-border-right | copy-log\">\n <span class=\"is-inline-block is-align-middle\">\n @if (isCompleteness) {\n <span>Data completeness for</span>\n <code class=\"is-mx-1\">{{ key }}</code>\n <span>must be</span>\n <code class=\"is-mx-1\">{{ complete }}</code>\n } @else {\n @switch (key) {\n @default {\n {{ parseKey(key) }}\n }\n @case ('property_id') {\n Property Term @id\n }\n @case ('product_id') {\n Product Term @id\n }\n @case ('crop_product_id') {\n Crop Product Term @id\n }\n @case ('input_id') {\n Input Term @id\n }\n @case ('node_type_allowed') {\n <span>Is the current</span>\n <code class=\"is-mx-1\">Node</code>\n <span>allowed to run this model</span>\n }\n @case ('siteType_allowed') {\n <span>Is the current</span>\n <code class=\"is-mx-1\">siteType</code>\n <span>allowed to run this model</span>\n }\n @case ('product_id_allowed') {\n <span>Are any of the Product</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('site_measurement_id_allowed') {\n <span>Are any of the Measurement</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('product_termType_allowed') {\n <span>Are any of the Product</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n @case ('input_id_allowed') {\n <span>Are any of the Input</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('input_termType_allowed') {\n <span>Are any of the Input</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n <!-- Deprecated -->\n @case ('primary_product_id_allowed') {\n <span>Is the current primary product</span>\n <code class=\"is-mx-1\">@id</code>\n <span>allowed to run this model</span>\n }\n @case ('primary_product_termType_allowed') {\n <span>Is the current primary product</span>\n <code class=\"is-mx-1\">termType</code>\n <span>allowed to run this model</span>\n }\n @case ('has_pesticides_inputs') {\n <span>Cycle contains</span>\n <code class=\"is-mx-1\">pesticideAI</code>\n <span>Inputs</span>\n }\n @case ('all_pesticideAI_have_lookup_value') {\n <span>All</span>\n <code class=\"is-mx-1\">pesticideAI</code>\n <span>Inputs have a lookup value</span>\n }\n @case ('has_crop_residue_burnt') {\n <code class=\"is-mr-1\">aboveGroundCropResidueBurnt</code>\n <span>is present as Product</span>\n }\n @case ('no_cycle_inputs_feed') {\n <span>\n Cycle has\n <b>no</b>\n Input with\n </span>\n <code>isAnimalFeed=true</code>\n }\n @case ('has_cycle_inputs_feed') {\n <span>\n Cycle has\n <b>some</b>\n Input with\n </span>\n <code>isAnimalFeed=true</code>\n }\n }\n }\n </span>\n <he-clipboard\n class=\"is-inline-block is-align-middle\"\n clipboardClass=\"is-size-7 is-p-1\"\n [value]=\"key\"\n [hideText]=\"true\" />\n </td>\n <td>\n @if (value | isArray) {\n <ng-container *ngTemplateOutlet=\"logLineArray; context: { value: value, sorting: {} }\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"logLineValue; context: { key, value }\" />\n }\n </td>\n </tr>\n</ng-template>\n", styles: [".copy-log he-clipboard{visibility:hidden}.copy-log:hover he-clipboard{visibility:visible}.raw-log{max-height:300px;overflow:auto;white-space:pre;font-size:.75rem;background:#00000059;color:inherit;padding:.5rem;border-radius:3px}\n"] }]
|
|
8801
8801
|
}], propDecorators: { logs: [{ type: i0.Input, args: [{ isSignal: true, alias: "logs", required: true }] }] } });
|
|
8802
8802
|
|
|
8803
8803
|
class NodeLogsModelsLogsStatusComponent {
|
|
@@ -9540,18 +9540,22 @@ const scalarValue = (value) => (['string', 'number', 'boolean'].includes(typeof
|
|
|
9540
9540
|
* A scalar field of a blank node (e.g. `impactAssessment`, `price`, `economicValueShare`), shown as a
|
|
9541
9541
|
* "Field: <key>" sub-row with the model(s) that gap-filled it.
|
|
9542
9542
|
*/
|
|
9543
|
-
|
|
9543
|
+
// the displayed value of a field sub-row: the blank node's own `value` field (set by a nested `value.logs`
|
|
9544
|
+
// run, e.g. `transformation`/`input.value`) is the `[n]` array form, resolved like the main row
|
|
9545
|
+
// (`propertyValue`) so it shows the value rather than "-"; other scalar fields (price, ...) stay scalar
|
|
9546
|
+
const fieldSubRowValue = (field, key, termId) => key === 'value' ? (field ? propertyValue$1(field.value, termId) : null) : scalarValue(field?.[key]);
|
|
9547
|
+
const fieldSubRow = (key, nested, value, originalValue, nodeType, termId, type) => {
|
|
9544
9548
|
const updated = [...(value?.added || []), ...(value?.updated || [])];
|
|
9545
9549
|
return {
|
|
9546
9550
|
...emptySubRow(),
|
|
9547
9551
|
key,
|
|
9548
9552
|
termId: key,
|
|
9549
9553
|
type,
|
|
9550
|
-
originalValue:
|
|
9551
|
-
recalculatedValue:
|
|
9554
|
+
originalValue: fieldSubRowValue(originalValue, key, termId),
|
|
9555
|
+
recalculatedValue: fieldSubRowValue(value, key, termId),
|
|
9552
9556
|
isOriginal: typeof originalValue?.[key] !== 'undefined',
|
|
9553
9557
|
isRecalculated: updated.includes(key),
|
|
9554
|
-
models: jLogModelRuns(nested?.logs, nodeType, key, false)
|
|
9558
|
+
models: jLogModelRuns(nested?.logs, nodeType, key === 'value' ? termId : key, false)
|
|
9555
9559
|
};
|
|
9556
9560
|
};
|
|
9557
9561
|
// the model runs for a property: its logs usually live under the `value` field (`properties[i].value.logs`)
|
|
@@ -9655,13 +9659,25 @@ const configModelStatus = (methodId, valueModelId, isRecalculated, hasOriginal)
|
|
|
9655
9659
|
// the `logs` entry that targets the value: the recorded model when present, otherwise (the value was
|
|
9656
9660
|
// recalculated but the recorded model isn't in the logs - e.g. `hestiaAggregatedData` is computed by the
|
|
9657
9661
|
// `linkedImpactAssessment` orchestrator) the first run that actually set the value
|
|
9658
|
-
const selectValueLog = (logs, valueModelId, isValueLog, isRecalculated) =>
|
|
9659
|
-
(
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
+
const selectValueLog = (logs, valueModelId, isValueLog, isRecalculated) => {
|
|
9663
|
+
// the recorded model may have several runs (different orchestrators sharing one model id, e.g. `hestia`
|
|
9664
|
+
// via both `soilTextureComposition` and `soilMeasurement`): prefer the run that actually executed
|
|
9665
|
+
// (`should_run: true`) over one that was skipped (the value already existed), so we lock onto the
|
|
9666
|
+
// orchestrator that produced the value rather than a skipped sibling that would show the row as failed
|
|
9667
|
+
const byModel = logs.filter((log) => log?.model === valueModelId && isValueLog(log));
|
|
9668
|
+
return (byModel.find((log) => log?.should_run === true) ||
|
|
9669
|
+
byModel[0] ||
|
|
9670
|
+
(isRecalculated
|
|
9671
|
+
? logs.find((log) => isValueLog(log) && log?.should_run === true) ||
|
|
9672
|
+
logs.find((log) => isValueLog(log) && log?.orchestrator?.should_run)
|
|
9673
|
+
: undefined));
|
|
9674
|
+
};
|
|
9662
9675
|
// model ids in display order: config models first, then any logged models, with "not relevant" models
|
|
9663
9676
|
// (the actual outcome) pulled to the front
|
|
9664
9677
|
const orderValueModelIds = (configModelIds, logModels) => [...new Set([...configModelIds, ...logModels.map(model => model.methodId)])].sort((a, b) => Number(isNotRelevantModel(b)) - Number(isNotRelevantModel(a)));
|
|
9678
|
+
// the logged runs for each model id, in log order: a model may run for one value under several
|
|
9679
|
+
// orchestrators (e.g. `hestia` via `soilTextureComposition` and `soilMeasurement`), each its own column
|
|
9680
|
+
const logRunsByMethodId = (logModels) => logModels.reduce((map, run) => map.set(run.methodId, [...(map.get(run.methodId) || []), run]), new Map());
|
|
9665
9681
|
// apply `update` to the model that set the value (matched by id) when `condition` holds, leaving the rest
|
|
9666
9682
|
const mapValueModel = (models, valueModelId, condition, update) => models.map(model => (model.methodId === valueModelId && condition(model) ? update(model) : model));
|
|
9667
9683
|
/**
|
|
@@ -9692,7 +9708,12 @@ splitParallelModels = false) => {
|
|
|
9692
9708
|
const isValueLog = (log) => !isBackgroundLog(log) && !isSubRowOrchestrator(log?.orchestrator?.value, subRowValues);
|
|
9693
9709
|
const valueLog = selectValueLog(logs, valueModelId, isValueLog, isRecalculated);
|
|
9694
9710
|
const valueOrchestrator = valueLog?.orchestrator?.value;
|
|
9695
|
-
|
|
9711
|
+
// the value's model runs: the winning orchestrator's runs (its fallback hierarchy), plus any other run
|
|
9712
|
+
// by the recorded value model targeting the value - the same model can run for one measurement under
|
|
9713
|
+
// several orchestrators (e.g. `hestia` via both `soilTextureComposition`, which skipped, and
|
|
9714
|
+
// `soilMeasurement`, which succeeded), each shown as its own "Model N" column rather than just the winner
|
|
9715
|
+
const matchesValueOrchestrator = (log) => !isBackgroundLog(log) &&
|
|
9716
|
+
(log?.orchestrator?.value === valueOrchestrator || (log?.model === valueModelId && isValueLog(log)));
|
|
9696
9717
|
// keep the parallel grouping (a nested `logs` array): parallel siblings are independent, so a model
|
|
9697
9718
|
// that did not run failed rather than being "skipped" by a sibling that ran (a higher-tier hierarchy
|
|
9698
9719
|
// model). `jLogModelColumns` applies the pre-group success state to each parallel sibling; flatten the
|
|
@@ -9724,9 +9745,12 @@ splitParallelModels = false) => {
|
|
|
9724
9745
|
const configModelIds = !valueIsNotRelevant && config && configModelKeys.includes(nodeKey) && !configModelsParallel(config, termId, nodeKey)
|
|
9725
9746
|
? configModelsForTerm(config, termId, nodeKey)
|
|
9726
9747
|
: [];
|
|
9727
|
-
const
|
|
9728
|
-
|
|
9729
|
-
|
|
9748
|
+
const logRuns = logRunsByMethodId(logModels);
|
|
9749
|
+
// each model id expands to all its logged runs (a model may run under several orchestrators), or a
|
|
9750
|
+
// single synthetic run when it only appears in the config (a could-have-run model)
|
|
9751
|
+
const models = orderValueModelIds(configModelIds, logModels).flatMap(methodId => logRuns.get(methodId) || [
|
|
9752
|
+
syntheticModelRun(methodId, configModelStatus(methodId, valueModelId, isRecalculated, hasOriginal), nodeType, termId)
|
|
9753
|
+
]);
|
|
9730
9754
|
// the value model (e.g. a measured method gap-filled this run) is not always in the logs or config
|
|
9731
9755
|
const baseModels = models.length || !valueModelId || valueFromOriginal
|
|
9732
9756
|
? models
|
|
@@ -9737,8 +9761,13 @@ splitParallelModels = false) => {
|
|
|
9737
9761
|
// the value model carries the blank node's method tier (e.g. an emission tier) even when its log omits
|
|
9738
9762
|
// it, so it shows next to the model name like the other tier emissions
|
|
9739
9763
|
const valueMethodTier = value?.methodTier;
|
|
9740
|
-
|
|
9764
|
+
const withTier = mapValueModel(withSuccess, valueModelId, model => !!valueMethodTier && !model.logs?.methodTier, model => ({ ...model, logs: { ...(model.logs || {}), methodTier: valueMethodTier } }));
|
|
9765
|
+
return dropEmptySkipsBeforeSuccess(withTier);
|
|
9741
9766
|
};
|
|
9767
|
+
// a "skipped" model run with no logs of its own (a config model shown as "not run - a higher-tier model
|
|
9768
|
+
// ran instead") is just noise when a later model in the row actually succeeded: it never ran on this row
|
|
9769
|
+
// (e.g. it produced the same measurement at a different depth), so drop it
|
|
9770
|
+
const dropEmptySkipsBeforeSuccess = (models) => models.filter((model, index) => !(model.status === LogStatus.skipHierarchy && !model.showLogs && models.slice(index + 1).some(isSucceededModel)));
|
|
9742
9771
|
/**
|
|
9743
9772
|
* Build a sub-row for every nested key of a blank node entry (all keys except `logs`): scalar fields
|
|
9744
9773
|
* become "Field: <key>" rows; index-keyed nested blank nodes (e.g. `properties`) become term sub-rows.
|
|
@@ -9747,19 +9776,23 @@ splitParallelModels = false) => {
|
|
|
9747
9776
|
const isFieldEntry = ([, nested]) => Array.isArray(nested?.logs);
|
|
9748
9777
|
const isPropertyEntry = ([, nested]) => !Array.isArray(nested?.logs) && nested && typeof nested === 'object';
|
|
9749
9778
|
const isFailedFieldEntry = ([key]) => key.endsWith(failedFieldSuffix);
|
|
9750
|
-
const blankNodeSubRows = (entry, value, originalValue, nodeType, type, getTerm) => {
|
|
9779
|
+
const blankNodeSubRows = (entry, value, originalValue, nodeType, type, termId, getTerm) => {
|
|
9751
9780
|
// a scalar field (with its own `logs`) becomes a "Field:" sub-row; an index-keyed nested node (e.g.
|
|
9752
9781
|
// `properties`) expands into "Property:" sub-rows; `<field>-failed` entries become failed sub-rows.
|
|
9753
9782
|
const entries = Object.entries(entry || {}).filter(([key]) => key !== 'logs');
|
|
9754
9783
|
const fields = entries
|
|
9755
9784
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isFieldEntry(entryItem))
|
|
9756
|
-
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, type));
|
|
9785
|
+
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, termId, type));
|
|
9757
9786
|
const properties = entries
|
|
9758
9787
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isPropertyEntry(entryItem))
|
|
9759
9788
|
.flatMap(([key, nested]) => nestedBlankNodeSubRows(key, nested, value, nodeType));
|
|
9789
|
+
// a term can appear in both `properties` (a model added it) and `<field>-failed` (another model failed to
|
|
9790
|
+
// add it): it was added, so drop the redundant failed sub-row (also avoids a duplicate row for the term)
|
|
9791
|
+
const addedTermIds = new Set(properties.map(subRow => subRow.termId));
|
|
9760
9792
|
const failed = entries
|
|
9761
9793
|
.filter(isFailedFieldEntry)
|
|
9762
|
-
.flatMap(([key, nested]) => failedNestedSubRows(key, nested, nodeType, getTerm))
|
|
9794
|
+
.flatMap(([key, nested]) => failedNestedSubRows(key, nested, nodeType, getTerm))
|
|
9795
|
+
.filter(subRow => !addedTermIds.has(subRow.termId));
|
|
9763
9796
|
return [...fields, ...properties, ...failed];
|
|
9764
9797
|
};
|
|
9765
9798
|
/**
|
|
@@ -9785,14 +9818,67 @@ const valueChanged = (value) => [...(value?.added || []), ...(value?.updated ||
|
|
|
9785
9818
|
// e.g. a measured emission method) - it was not recalculated
|
|
9786
9819
|
const valueRetainedFromOriginal = (value, originalValue) => !!originalValue && typeof originalValue.value !== 'undefined' && !valueChanged(value);
|
|
9787
9820
|
const isRecalculatedValue = (value, originalValue) => valueChanged(value) || (!!blankNodeModelId(value) && !valueRetainedFromOriginal(value, originalValue));
|
|
9788
|
-
//
|
|
9789
|
-
//
|
|
9821
|
+
// the suffix of a dotted orchestrator (`<context>.<suffix>`) that names an actual sub-field of the blank
|
|
9822
|
+
// node (e.g. `product.price`, `input.properties`) - shown via its own field/property sub-row, so it is
|
|
9823
|
+
// NOT the value run. `properties`, a same-named entry key (a `<suffix>.logs` field), or a `<suffix>` field
|
|
9824
|
+
// on the recalculated value all mark a real sub-field.
|
|
9825
|
+
const isSubFieldSuffix = (suffix, entry, value) => suffix === 'properties' ||
|
|
9826
|
+
!!entry?.[suffix] ||
|
|
9827
|
+
(!!value && suffix !== 'value' && typeof value[suffix] !== 'undefined');
|
|
9828
|
+
// the value-producing logs at the entry's top level: a dotted orchestrator (`<context>.<suffix>`) whose
|
|
9829
|
+
// suffix is not a real sub-field set the blank node's own value (e.g. `transformation`/`product.excreta`,
|
|
9830
|
+
// `cycle`/`practice.landCover`, `cycle`/`animal.milkYield`) - unlike a same-node sub-field run
|
|
9831
|
+
// (`product.price`, `input.properties`). Shown as a "Field: value" sub-row so the main row keeps just its
|
|
9832
|
+
// expand toggle, rather than the value appearing with no model at all.
|
|
9833
|
+
const valueRunLogs = (entry, value) => (entry?.logs || []).flat().filter((log) => {
|
|
9834
|
+
const orchestratorValue = log?.orchestrator?.value;
|
|
9835
|
+
return (!!orchestratorValue &&
|
|
9836
|
+
orchestratorValue.includes('.') &&
|
|
9837
|
+
!isSubFieldSuffix(orchestratorValue.split('.').pop(), entry, value));
|
|
9838
|
+
});
|
|
9839
|
+
// a scalar "Field:" sub-row (e.g. price, revenue) - not a nested property, Background Data or value row
|
|
9840
|
+
const isFieldSubRow = (subRow) => !['property', 'backgroundData', 'value'].includes(subRow.key);
|
|
9841
|
+
// the "Field: value" sub-row for a blank node's own value, carrying the model run(s) that set it
|
|
9842
|
+
const buildValueSubRow = (value, originalValue, termId, type, models) => ({
|
|
9843
|
+
...emptySubRow(),
|
|
9844
|
+
key: 'value',
|
|
9845
|
+
termId: 'value',
|
|
9846
|
+
// carry the blank node type so the "value" label links to the schema (`/<Type>#value`), matching the
|
|
9847
|
+
// generic `fieldSubRow` path (e.g. a transformation input's nested `value.logs` run)
|
|
9848
|
+
type,
|
|
9849
|
+
// the value is resolved like the main row (`propertyValue` unwraps the `[n]` array form), not as a
|
|
9850
|
+
// raw scalar - so the sub-row shows the same recalculated value rather than "-"
|
|
9851
|
+
originalValue: originalValue ? propertyValue$1(originalValue.value, termId) : null,
|
|
9852
|
+
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9853
|
+
isOriginal: typeof originalValue?.value !== 'undefined',
|
|
9854
|
+
isRecalculated: valueChanged(value),
|
|
9855
|
+
models
|
|
9856
|
+
});
|
|
9857
|
+
const valueFieldSubRow = (entry, value, originalValue, nodeType, termId, type) => {
|
|
9858
|
+
// only when the node records no value model of its own (otherwise the main row already shows it): surface
|
|
9859
|
+
// the value-producing run here so the value is not left with no model
|
|
9860
|
+
if (blankNodeModelId(value))
|
|
9861
|
+
return null;
|
|
9862
|
+
const logs = valueRunLogs(entry, value);
|
|
9863
|
+
if (!logs.length)
|
|
9864
|
+
return null;
|
|
9865
|
+
return buildValueSubRow(value, originalValue, termId, type, jLogModelRuns(logs, nodeType, termId, false));
|
|
9866
|
+
};
|
|
9867
|
+
// every sub-row of a (non-failed) blank node: its own value run (when set by a model not recorded on the
|
|
9868
|
+
// node), its field/property sub-rows, plus - for an input - the "Background Data" sub-row of background runs
|
|
9869
|
+
// an input's "Background Data" sub-row (its background-emission model runs), or null for other node types
|
|
9870
|
+
const inputBackgroundSubRow = (entry, type, nodeType, termId) => {
|
|
9871
|
+
if (type !== SchemaType.Input)
|
|
9872
|
+
return null;
|
|
9873
|
+
const inputEntries = (entry?.logs || []).flat().filter((e) => !!e?.model);
|
|
9874
|
+
return backgroundDataSubRow(inputEntries, nodeType, termId);
|
|
9875
|
+
};
|
|
9790
9876
|
const allSubRows = (entry, value, originalValue, nodeType, type, termId, getTerm) => {
|
|
9791
|
-
const
|
|
9792
|
-
const
|
|
9793
|
-
const backgroundData = isInput ? backgroundDataSubRow(inputEntries, nodeType, termId) : null;
|
|
9877
|
+
const valueField = valueFieldSubRow(entry, value, originalValue, nodeType, termId, type);
|
|
9878
|
+
const backgroundData = inputBackgroundSubRow(entry, type, nodeType, termId);
|
|
9794
9879
|
return [
|
|
9795
|
-
...
|
|
9880
|
+
...(valueField ? [valueField] : []),
|
|
9881
|
+
...blankNodeSubRows(entry, value, originalValue, nodeType, type, termId, getTerm),
|
|
9796
9882
|
...(backgroundData ? [backgroundData] : [])
|
|
9797
9883
|
];
|
|
9798
9884
|
};
|
|
@@ -9830,19 +9916,38 @@ const failedBlankNodeContent = (entry, nodeType, termId) => {
|
|
|
9830
9916
|
modelColumns: columns
|
|
9831
9917
|
};
|
|
9832
9918
|
};
|
|
9919
|
+
// a lone "value" sub-row only carries the model that set the value (the value itself already shows on the
|
|
9920
|
+
// main row); with no other sub-rows to expand, fold its model onto the main row so the value and its model
|
|
9921
|
+
// show on one line (e.g. a transformation product) instead of behind an expand toggle
|
|
9922
|
+
const foldLoneValueSubRow = (subRows, models) => !models.length && subRows.length === 1 && subRows[0].key === 'value'
|
|
9923
|
+
? { subRows: [], models: subRows[0].models }
|
|
9924
|
+
: { subRows, models };
|
|
9925
|
+
// the blank node's sub-rows and main-row models. When the value was set by a model AND the node's only
|
|
9926
|
+
// sub-rows are scalar "Field:" rows (e.g. price, revenue, economicValueShare), surface the value as its
|
|
9927
|
+
// own first "Field: value" sub-row (moving its model off the main row), so it sits alongside the other
|
|
9928
|
+
// fields rather than only on the main row. Nodes with nested sub-rows (properties / Background Data) keep
|
|
9929
|
+
// the value model on the main row, and a value sub-row already produced for a cross-context run (see
|
|
9930
|
+
// `valueFieldSubRow`) is left as is.
|
|
9931
|
+
const subRowsAndModels = (value, originalValue, termId, type, valueModels, rawSubRows) => {
|
|
9932
|
+
const surfaceValue = valueModels.length > 0 && rawSubRows.length > 0 && rawSubRows.every(subRow => isFieldSubRow(subRow));
|
|
9933
|
+
return foldLoneValueSubRow(surfaceValue ? [buildValueSubRow(value, originalValue, termId, type, valueModels), ...rawSubRows] : rawSubRows, surfaceValue ? [] : valueModels);
|
|
9934
|
+
};
|
|
9833
9935
|
// a regular blank node: its identity, sub-rows and the model(s) that set the value (or none when retained)
|
|
9834
9936
|
const valueBlankNodeContent = (entry, value, originalValue, termId, { nodeType, type, nodeKey, config, getTerm }) => {
|
|
9835
9937
|
const spec = identitySpec(type, nodeType, nodeKey);
|
|
9938
|
+
const valueModels = valueModelRuns(entry, value, originalValue, nodeType, termId, nodeKey, config, modelIsUniquenessField(spec));
|
|
9939
|
+
const rawSubRows = allSubRows(entry, value, originalValue, nodeType, type, termId, getTerm || defaultGetTerm);
|
|
9940
|
+
const { subRows, models } = subRowsAndModels(value, originalValue, termId, type, valueModels, rawSubRows);
|
|
9836
9941
|
return {
|
|
9837
9942
|
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9838
9943
|
identity: blankNodeIdentity(value, spec),
|
|
9839
9944
|
// `identityLabel`/`identitySegments` are filled per group (`withRowLabels`), which needs all rows
|
|
9840
9945
|
identityLabel: '',
|
|
9841
9946
|
identitySegments: [],
|
|
9842
|
-
subRows
|
|
9947
|
+
subRows,
|
|
9843
9948
|
isRecalculated: isRecalculatedValue(value, originalValue),
|
|
9844
9949
|
recalculated: value ? [value] : [],
|
|
9845
|
-
models
|
|
9950
|
+
models
|
|
9846
9951
|
};
|
|
9847
9952
|
};
|
|
9848
9953
|
const buildBlankNode = (entry, value, originalValue, index, term, isFailed, context) => {
|
|
@@ -9981,20 +10086,74 @@ const groupBlankNodesByTerm = (blankNodes) => blankNodes.reduce((groups, blankNo
|
|
|
9981
10086
|
}
|
|
9982
10087
|
];
|
|
9983
10088
|
}, []);
|
|
9984
|
-
//
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
10089
|
+
// the combined value across several blank nodes. Site measurements are depth-weighted (a thicker soil
|
|
10090
|
+
// layer counts more - `measurementValue`); everything else follows the term's array treatment (sum/mean/..)
|
|
10091
|
+
const reduceValues = (values, termId, type) => {
|
|
10092
|
+
const present = values.filter(({ value }) => propertyValue$1(value, termId) !== null);
|
|
10093
|
+
if (!present.length)
|
|
10094
|
+
return null;
|
|
10095
|
+
if (type === SchemaType.Measurement && present.length > 1) {
|
|
10096
|
+
return measurementValue({ nodes: present }, termId);
|
|
10097
|
+
}
|
|
10098
|
+
return propertyValue$1(present.map(({ value }) => propertyValue$1(value, termId)), termId);
|
|
10099
|
+
};
|
|
10100
|
+
const formatFormulaValue = (value) => typeof value === 'number' ? `${toPrecision(value, 3)}`.replace(/\.00$/, '') : `${value}`;
|
|
10101
|
+
// the depth thickness of a measurement node (`depthLower - depthUpper`), the weight in its weighted average
|
|
10102
|
+
const nodeThickness = (node) => (node?.depthLower ?? 0) - (node?.depthUpper ?? 0);
|
|
10103
|
+
// the depth-weighted-average formula for Site measurements (null when depths are missing, so the caller
|
|
10104
|
+
// falls back to the array-treatment formula)
|
|
10105
|
+
const measurementFormula = (values, termId, total) => {
|
|
10106
|
+
const parts = values
|
|
10107
|
+
.map(node => ({ value: propertyValue$1(node.value, termId), thickness: nodeThickness(node) }))
|
|
10108
|
+
.filter(part => typeof part.value === 'number' && part.thickness > 0);
|
|
10109
|
+
if (parts.length < 2)
|
|
10110
|
+
return null;
|
|
10111
|
+
const numerator = parts.map(p => `${formatFormulaValue(p.value)} × ${formatFormulaValue(p.thickness)}`).join(' + ');
|
|
10112
|
+
const denominator = parts.map(p => formatFormulaValue(p.thickness)).join(' + ');
|
|
10113
|
+
return `Depth-weighted average: (${numerator}) / (${denominator}) = ${total}`;
|
|
10114
|
+
};
|
|
10115
|
+
// the formula following the term's array treatment (sum/mean/...) over the already-combined numeric values
|
|
10116
|
+
const arrayTreatmentFormula = (numbers, termId, total) => {
|
|
10117
|
+
const list = numbers.map(formatFormulaValue);
|
|
10118
|
+
const count = numbers.length;
|
|
10119
|
+
switch (getArrayTreatment(termId)) {
|
|
10120
|
+
case 'mean':
|
|
10121
|
+
return `Average of ${count} values: (${list.join(' + ')}) / ${count} = ${total}`;
|
|
10122
|
+
case 'mode':
|
|
10123
|
+
return `Most common of ${count} values: ${list.join(', ')} = ${total}`;
|
|
10124
|
+
case 'first':
|
|
10125
|
+
return `First of ${count} values: ${list.join(', ')} = ${total}`;
|
|
10126
|
+
default:
|
|
10127
|
+
return `Sum of ${count} values: ${list.join(' + ')} = ${total}`;
|
|
10128
|
+
}
|
|
10129
|
+
};
|
|
10130
|
+
// a human-readable explanation of how the rows' values were combined into the header value. Returns null
|
|
10131
|
+
// unless several numeric values were actually combined - so single-value groups show no misleading formula
|
|
10132
|
+
const valueFormula = (values, termId, result, type) => {
|
|
10133
|
+
const numbers = values
|
|
10134
|
+
.map(({ value }) => propertyValue$1(value, termId))
|
|
10135
|
+
.filter(v => typeof v === 'number');
|
|
10136
|
+
if (numbers.length < 2)
|
|
10137
|
+
return null;
|
|
10138
|
+
const total = formatFormulaValue(result);
|
|
10139
|
+
return ((type === SchemaType.Measurement && measurementFormula(values, termId, total)) ||
|
|
10140
|
+
arrayTreatmentFormula(numbers, termId, total));
|
|
9988
10141
|
};
|
|
9989
10142
|
// a group with several blank nodes (or with nested sub-rows) is collapsible, as are its rows with sub-rows;
|
|
9990
10143
|
// its header shows the combined value across all rows
|
|
9991
|
-
const withCollapsible = (group) =>
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
})
|
|
10144
|
+
const withCollapsible = (group) => {
|
|
10145
|
+
const recalculatedNodes = group.rows.flatMap(row => row.recalculated);
|
|
10146
|
+
const recalculatedValue = reduceValues(recalculatedNodes, group.termId, group.type);
|
|
10147
|
+
return {
|
|
10148
|
+
...group,
|
|
10149
|
+
canOpen: group.rows.length > 1 || group.rows.some(row => row.subRows.length > 0),
|
|
10150
|
+
rows: group.rows.map(row => ({ ...row, canOpen: row.subRows.length > 0 })),
|
|
10151
|
+
originalValue: reduceValues(group.rows.flatMap(row => row.original), group.termId, group.type),
|
|
10152
|
+
recalculatedValue,
|
|
10153
|
+
isRecalculated: group.rows.some(row => row.isRecalculated),
|
|
10154
|
+
recalculatedFormula: valueFormula(recalculatedNodes, group.termId, recalculatedValue, group.type)
|
|
10155
|
+
};
|
|
10156
|
+
};
|
|
9998
10157
|
const isSucceededModel = (model) => [LogStatus.success, LogStatus.notRequired, LogStatus.dataProvided].includes(model.status);
|
|
9999
10158
|
// did this row succeed? not failed, and either has a successful direct model or every sub-row did
|
|
10000
10159
|
const rowSucceeded = (row) => {
|
|
@@ -10241,13 +10400,15 @@ class NodeJLogModelsComponent {
|
|
|
10241
10400
|
return group.termId;
|
|
10242
10401
|
}
|
|
10243
10402
|
trackByRow(_index, row) {
|
|
10244
|
-
|
|
10403
|
+
// include the sub-row `key` (a term may appear as several sub-row kinds) and the position as a final
|
|
10404
|
+
// tiebreaker, so the `@for` track expression stays unique even if two rows share term/index/label
|
|
10405
|
+
return `${row.termId}-${row.index}-${row.identityLabel}-${row.key}-${_index}`;
|
|
10245
10406
|
}
|
|
10246
10407
|
trackByModel(_index, model) {
|
|
10247
10408
|
return model.methodId;
|
|
10248
10409
|
}
|
|
10249
10410
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10250
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeJLogModelsComponent, isStandalone: true, selector: "he-node-jlog-models", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, originalValues: { classPropertyName: "originalValues", publicName: "originalValues", isSignal: true, isRequired: false, transformFunction: null }, recalculatedValues: { classPropertyName: "recalculatedValues", publicName: "recalculatedValues", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypesLabel: { classPropertyName: "filterTermTypesLabel", publicName: "filterTermTypesLabel", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", isSignal: true, isRequired: false, transformFunction: null }, jlog: { classPropertyName: "jlog", publicName: "jlog", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.recalculatedValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (!isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "directive", type: NgbTypeahead, selector: "input[ngbTypeahead]", inputs: ["autocomplete", "container", "editable", "focusFirst", "inputFormatter", "ngbTypeahead", "resultFormatter", "resultTemplate", "selectOnExact", "showHint", "placement", "popperOptions", "popupClass"], outputs: ["selectItem"], exportAs: ["ngbTypeahead"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLogsModelsLogsComponent, selector: "he-node-logs-models-logs", inputs: ["logs"] }, { kind: "component", type: NodeLogsModelsLogsStatusComponent, selector: "he-node-logs-models-logs-status", inputs: ["nodeType", "model", "data"] }, { kind: "component", type: NodeLogsModelsContributionsComponent, selector: "he-node-logs-models-contributions", inputs: ["node", "nodeKey", "model"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: TimesPipe, name: "times" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10411
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeJLogModelsComponent, isStandalone: true, selector: "he-node-jlog-models", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, originalValues: { classPropertyName: "originalValues", publicName: "originalValues", isSignal: true, isRequired: false, transformFunction: null }, recalculatedValues: { classPropertyName: "recalculatedValues", publicName: "recalculatedValues", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypesLabel: { classPropertyName: "filterTermTypesLabel", publicName: "filterTermTypesLabel", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", isSignal: true, isRequired: false, transformFunction: null }, jlog: { classPropertyName: "jlog", publicName: "jlog", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (group.isRecalculated && !isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (\n group.isRecalculated && !isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)\n ) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "directive", type: NgbTypeahead, selector: "input[ngbTypeahead]", inputs: ["autocomplete", "container", "editable", "focusFirst", "inputFormatter", "ngbTypeahead", "resultFormatter", "resultTemplate", "selectOnExact", "showHint", "placement", "popperOptions", "popupClass"], outputs: ["selectItem"], exportAs: ["ngbTypeahead"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLogsModelsLogsComponent, selector: "he-node-logs-models-logs", inputs: ["logs"] }, { kind: "component", type: NodeLogsModelsLogsStatusComponent, selector: "he-node-logs-models-logs-status", inputs: ["nodeType", "model", "data"] }, { kind: "component", type: NodeLogsModelsContributionsComponent, selector: "he-node-logs-models-contributions", inputs: ["node", "nodeKey", "model"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: TimesPipe, name: "times" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10251
10412
|
}
|
|
10252
10413
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, decorators: [{
|
|
10253
10414
|
type: Component$1,
|
|
@@ -10271,7 +10432,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
10271
10432
|
NodeLogsModelsLogsStatusComponent,
|
|
10272
10433
|
NodeLogsModelsContributionsComponent,
|
|
10273
10434
|
GuideOverlayComponent
|
|
10274
|
-
], template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.recalculatedValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (!isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"] }]
|
|
10435
|
+
], template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (group.isRecalculated && !isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (\n group.isRecalculated && !isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)\n ) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"] }]
|
|
10275
10436
|
}], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], nodeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKey", required: false }] }], originalValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "originalValues", required: false }] }], recalculatedValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "recalculatedValues", required: false }] }], filterTermTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypes", required: false }] }], filterTermTypesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypesLabel", required: false }] }], cycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycle", required: false }] }], jlog: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlog", required: false }] }], jlogParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentKey", required: false }] }], jlogParentIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentIndex", required: false }] }] } });
|
|
10276
10437
|
|
|
10277
10438
|
const groupTerms = (terms) => terms.reduce((prev, curr) => ({ ...prev, [curr['@id']]: curr }), {});
|