@hestia-earth/ui-components 0.42.11 → 0.42.12
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';
|
|
@@ -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`)
|
|
@@ -9737,8 +9741,13 @@ splitParallelModels = false) => {
|
|
|
9737
9741
|
// the value model carries the blank node's method tier (e.g. an emission tier) even when its log omits
|
|
9738
9742
|
// it, so it shows next to the model name like the other tier emissions
|
|
9739
9743
|
const valueMethodTier = value?.methodTier;
|
|
9740
|
-
|
|
9744
|
+
const withTier = mapValueModel(withSuccess, valueModelId, model => !!valueMethodTier && !model.logs?.methodTier, model => ({ ...model, logs: { ...(model.logs || {}), methodTier: valueMethodTier } }));
|
|
9745
|
+
return dropEmptySkipsBeforeSuccess(withTier);
|
|
9741
9746
|
};
|
|
9747
|
+
// a "skipped" model run with no logs of its own (a config model shown as "not run - a higher-tier model
|
|
9748
|
+
// ran instead") is just noise when a later model in the row actually succeeded: it never ran on this row
|
|
9749
|
+
// (e.g. it produced the same measurement at a different depth), so drop it
|
|
9750
|
+
const dropEmptySkipsBeforeSuccess = (models) => models.filter((model, index) => !(model.status === LogStatus.skipHierarchy && !model.showLogs && models.slice(index + 1).some(isSucceededModel)));
|
|
9742
9751
|
/**
|
|
9743
9752
|
* Build a sub-row for every nested key of a blank node entry (all keys except `logs`): scalar fields
|
|
9744
9753
|
* become "Field: <key>" rows; index-keyed nested blank nodes (e.g. `properties`) become term sub-rows.
|
|
@@ -9747,13 +9756,13 @@ splitParallelModels = false) => {
|
|
|
9747
9756
|
const isFieldEntry = ([, nested]) => Array.isArray(nested?.logs);
|
|
9748
9757
|
const isPropertyEntry = ([, nested]) => !Array.isArray(nested?.logs) && nested && typeof nested === 'object';
|
|
9749
9758
|
const isFailedFieldEntry = ([key]) => key.endsWith(failedFieldSuffix);
|
|
9750
|
-
const blankNodeSubRows = (entry, value, originalValue, nodeType, type, getTerm) => {
|
|
9759
|
+
const blankNodeSubRows = (entry, value, originalValue, nodeType, type, termId, getTerm) => {
|
|
9751
9760
|
// a scalar field (with its own `logs`) becomes a "Field:" sub-row; an index-keyed nested node (e.g.
|
|
9752
9761
|
// `properties`) expands into "Property:" sub-rows; `<field>-failed` entries become failed sub-rows.
|
|
9753
9762
|
const entries = Object.entries(entry || {}).filter(([key]) => key !== 'logs');
|
|
9754
9763
|
const fields = entries
|
|
9755
9764
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isFieldEntry(entryItem))
|
|
9756
|
-
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, type));
|
|
9765
|
+
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, termId, type));
|
|
9757
9766
|
const properties = entries
|
|
9758
9767
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isPropertyEntry(entryItem))
|
|
9759
9768
|
.flatMap(([key, nested]) => nestedBlankNodeSubRows(key, nested, value, nodeType));
|
|
@@ -9785,14 +9794,63 @@ const valueChanged = (value) => [...(value?.added || []), ...(value?.updated ||
|
|
|
9785
9794
|
// e.g. a measured emission method) - it was not recalculated
|
|
9786
9795
|
const valueRetainedFromOriginal = (value, originalValue) => !!originalValue && typeof originalValue.value !== 'undefined' && !valueChanged(value);
|
|
9787
9796
|
const isRecalculatedValue = (value, originalValue) => valueChanged(value) || (!!blankNodeModelId(value) && !valueRetainedFromOriginal(value, originalValue));
|
|
9788
|
-
//
|
|
9789
|
-
//
|
|
9797
|
+
// the suffix of a dotted orchestrator (`<context>.<suffix>`) that names an actual sub-field of the blank
|
|
9798
|
+
// node (e.g. `product.price`, `input.properties`) - shown via its own field/property sub-row, so it is
|
|
9799
|
+
// NOT the value run. `properties`, a same-named entry key (a `<suffix>.logs` field), or a `<suffix>` field
|
|
9800
|
+
// on the recalculated value all mark a real sub-field.
|
|
9801
|
+
const isSubFieldSuffix = (suffix, entry, value) => suffix === 'properties' ||
|
|
9802
|
+
!!entry?.[suffix] ||
|
|
9803
|
+
(!!value && suffix !== 'value' && typeof value[suffix] !== 'undefined');
|
|
9804
|
+
// the value-producing logs at the entry's top level: a dotted orchestrator (`<context>.<suffix>`) whose
|
|
9805
|
+
// suffix is not a real sub-field set the blank node's own value (e.g. `transformation`/`product.excreta`,
|
|
9806
|
+
// `cycle`/`practice.landCover`, `cycle`/`animal.milkYield`) - unlike a same-node sub-field run
|
|
9807
|
+
// (`product.price`, `input.properties`). Shown as a "Field: value" sub-row so the main row keeps just its
|
|
9808
|
+
// expand toggle, rather than the value appearing with no model at all.
|
|
9809
|
+
const valueRunLogs = (entry, value) => (entry?.logs || []).flat().filter((log) => {
|
|
9810
|
+
const orchestratorValue = log?.orchestrator?.value;
|
|
9811
|
+
return (!!orchestratorValue &&
|
|
9812
|
+
orchestratorValue.includes('.') &&
|
|
9813
|
+
!isSubFieldSuffix(orchestratorValue.split('.').pop(), entry, value));
|
|
9814
|
+
});
|
|
9815
|
+
const valueFieldSubRow = (entry, value, originalValue, nodeType, termId, type) => {
|
|
9816
|
+
// only when the node records no value model of its own (otherwise the main row already shows it): surface
|
|
9817
|
+
// the value-producing run here so the value is not left with no model
|
|
9818
|
+
if (blankNodeModelId(value))
|
|
9819
|
+
return null;
|
|
9820
|
+
const logs = valueRunLogs(entry, value);
|
|
9821
|
+
if (!logs.length)
|
|
9822
|
+
return null;
|
|
9823
|
+
return {
|
|
9824
|
+
...emptySubRow(),
|
|
9825
|
+
key: 'value',
|
|
9826
|
+
termId: 'value',
|
|
9827
|
+
// carry the blank node type so the "value" label links to the schema (`/<Type>#value`), matching the
|
|
9828
|
+
// generic `fieldSubRow` path (e.g. a transformation input's nested `value.logs` run)
|
|
9829
|
+
type,
|
|
9830
|
+
// the value is resolved like the main row (`propertyValue` unwraps the `[n]` array form), not as a
|
|
9831
|
+
// raw scalar - so the sub-row shows the same recalculated value rather than "-"
|
|
9832
|
+
originalValue: originalValue ? propertyValue$1(originalValue.value, termId) : null,
|
|
9833
|
+
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9834
|
+
isOriginal: typeof originalValue?.value !== 'undefined',
|
|
9835
|
+
isRecalculated: valueChanged(value),
|
|
9836
|
+
models: jLogModelRuns(logs, nodeType, termId, false)
|
|
9837
|
+
};
|
|
9838
|
+
};
|
|
9839
|
+
// every sub-row of a (non-failed) blank node: its own value run (when set by a model not recorded on the
|
|
9840
|
+
// node), its field/property sub-rows, plus - for an input - the "Background Data" sub-row of background runs
|
|
9841
|
+
// an input's "Background Data" sub-row (its background-emission model runs), or null for other node types
|
|
9842
|
+
const inputBackgroundSubRow = (entry, type, nodeType, termId) => {
|
|
9843
|
+
if (type !== SchemaType.Input)
|
|
9844
|
+
return null;
|
|
9845
|
+
const inputEntries = (entry?.logs || []).flat().filter((e) => !!e?.model);
|
|
9846
|
+
return backgroundDataSubRow(inputEntries, nodeType, termId);
|
|
9847
|
+
};
|
|
9790
9848
|
const allSubRows = (entry, value, originalValue, nodeType, type, termId, getTerm) => {
|
|
9791
|
-
const
|
|
9792
|
-
const
|
|
9793
|
-
const backgroundData = isInput ? backgroundDataSubRow(inputEntries, nodeType, termId) : null;
|
|
9849
|
+
const valueField = valueFieldSubRow(entry, value, originalValue, nodeType, termId, type);
|
|
9850
|
+
const backgroundData = inputBackgroundSubRow(entry, type, nodeType, termId);
|
|
9794
9851
|
return [
|
|
9795
|
-
...
|
|
9852
|
+
...(valueField ? [valueField] : []),
|
|
9853
|
+
...blankNodeSubRows(entry, value, originalValue, nodeType, type, termId, getTerm),
|
|
9796
9854
|
...(backgroundData ? [backgroundData] : [])
|
|
9797
9855
|
];
|
|
9798
9856
|
};
|
|
@@ -9830,19 +9888,26 @@ const failedBlankNodeContent = (entry, nodeType, termId) => {
|
|
|
9830
9888
|
modelColumns: columns
|
|
9831
9889
|
};
|
|
9832
9890
|
};
|
|
9891
|
+
// a lone "value" sub-row only carries the model that set the value (the value itself already shows on the
|
|
9892
|
+
// main row); with no other sub-rows to expand, fold its model onto the main row so the value and its model
|
|
9893
|
+
// show on one line (e.g. a transformation product) instead of behind an expand toggle
|
|
9894
|
+
const foldLoneValueSubRow = (subRows, models) => !models.length && subRows.length === 1 && subRows[0].key === 'value'
|
|
9895
|
+
? { subRows: [], models: subRows[0].models }
|
|
9896
|
+
: { subRows, models };
|
|
9833
9897
|
// a regular blank node: its identity, sub-rows and the model(s) that set the value (or none when retained)
|
|
9834
9898
|
const valueBlankNodeContent = (entry, value, originalValue, termId, { nodeType, type, nodeKey, config, getTerm }) => {
|
|
9835
9899
|
const spec = identitySpec(type, nodeType, nodeKey);
|
|
9900
|
+
const { subRows, models } = foldLoneValueSubRow(allSubRows(entry, value, originalValue, nodeType, type, termId, getTerm || defaultGetTerm), valueModelRuns(entry, value, originalValue, nodeType, termId, nodeKey, config, modelIsUniquenessField(spec)));
|
|
9836
9901
|
return {
|
|
9837
9902
|
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9838
9903
|
identity: blankNodeIdentity(value, spec),
|
|
9839
9904
|
// `identityLabel`/`identitySegments` are filled per group (`withRowLabels`), which needs all rows
|
|
9840
9905
|
identityLabel: '',
|
|
9841
9906
|
identitySegments: [],
|
|
9842
|
-
subRows
|
|
9907
|
+
subRows,
|
|
9843
9908
|
isRecalculated: isRecalculatedValue(value, originalValue),
|
|
9844
9909
|
recalculated: value ? [value] : [],
|
|
9845
|
-
models
|
|
9910
|
+
models
|
|
9846
9911
|
};
|
|
9847
9912
|
};
|
|
9848
9913
|
const buildBlankNode = (entry, value, originalValue, index, term, isFailed, context) => {
|
|
@@ -9981,20 +10046,71 @@ const groupBlankNodesByTerm = (blankNodes) => blankNodes.reduce((groups, blankNo
|
|
|
9981
10046
|
}
|
|
9982
10047
|
];
|
|
9983
10048
|
}, []);
|
|
9984
|
-
//
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
10049
|
+
// the combined value across several blank nodes. Site measurements are depth-weighted (a thicker soil
|
|
10050
|
+
// layer counts more - `measurementValue`); everything else follows the term's array treatment (sum/mean/..)
|
|
10051
|
+
const reduceValues = (values, termId, type) => {
|
|
10052
|
+
const present = values.filter(({ value }) => propertyValue$1(value, termId) !== null);
|
|
10053
|
+
if (!present.length)
|
|
10054
|
+
return null;
|
|
10055
|
+
if (type === SchemaType.Measurement && present.length > 1) {
|
|
10056
|
+
return measurementValue({ nodes: present }, termId);
|
|
10057
|
+
}
|
|
10058
|
+
return propertyValue$1(present.map(({ value }) => propertyValue$1(value, termId)), termId);
|
|
10059
|
+
};
|
|
10060
|
+
const formatFormulaValue = (value) => typeof value === 'number' ? `${toPrecision(value, 3)}`.replace(/\.00$/, '') : `${value}`;
|
|
10061
|
+
// the depth thickness of a measurement node (`depthLower - depthUpper`), the weight in its weighted average
|
|
10062
|
+
const nodeThickness = (node) => (node?.depthLower ?? 0) - (node?.depthUpper ?? 0);
|
|
10063
|
+
// the depth-weighted-average formula for Site measurements (null when depths are missing, so the caller
|
|
10064
|
+
// falls back to the array-treatment formula)
|
|
10065
|
+
const measurementFormula = (values, termId, total) => {
|
|
10066
|
+
const parts = values
|
|
10067
|
+
.map(node => ({ value: propertyValue$1(node.value, termId), thickness: nodeThickness(node) }))
|
|
10068
|
+
.filter(part => typeof part.value === 'number' && part.thickness > 0);
|
|
10069
|
+
if (parts.length < 2)
|
|
10070
|
+
return null;
|
|
10071
|
+
const numerator = parts.map(p => `${formatFormulaValue(p.value)} × ${formatFormulaValue(p.thickness)}`).join(' + ');
|
|
10072
|
+
const denominator = parts.map(p => formatFormulaValue(p.thickness)).join(' + ');
|
|
10073
|
+
return `Depth-weighted average: (${numerator}) / (${denominator}) = ${total}`;
|
|
10074
|
+
};
|
|
10075
|
+
// the formula following the term's array treatment (sum/mean/...) over the already-combined numeric values
|
|
10076
|
+
const arrayTreatmentFormula = (numbers, termId, total) => {
|
|
10077
|
+
const list = numbers.map(formatFormulaValue);
|
|
10078
|
+
const count = numbers.length;
|
|
10079
|
+
switch (getArrayTreatment(termId)) {
|
|
10080
|
+
case 'mean':
|
|
10081
|
+
return `Average of ${count} values: (${list.join(' + ')}) / ${count} = ${total}`;
|
|
10082
|
+
case 'mode':
|
|
10083
|
+
return `Most common of ${count} values: ${list.join(', ')} = ${total}`;
|
|
10084
|
+
case 'first':
|
|
10085
|
+
return `First of ${count} values: ${list.join(', ')} = ${total}`;
|
|
10086
|
+
default:
|
|
10087
|
+
return `Sum of ${count} values: ${list.join(' + ')} = ${total}`;
|
|
10088
|
+
}
|
|
10089
|
+
};
|
|
10090
|
+
// a human-readable explanation of how the rows' values were combined into the header value. Returns null
|
|
10091
|
+
// unless several numeric values were actually combined - so single-value groups show no misleading formula
|
|
10092
|
+
const valueFormula = (values, termId, result, type) => {
|
|
10093
|
+
const numbers = values.map(({ value }) => propertyValue$1(value, termId)).filter(v => typeof v === 'number');
|
|
10094
|
+
if (numbers.length < 2)
|
|
10095
|
+
return null;
|
|
10096
|
+
const total = formatFormulaValue(result);
|
|
10097
|
+
return ((type === SchemaType.Measurement && measurementFormula(values, termId, total)) ||
|
|
10098
|
+
arrayTreatmentFormula(numbers, termId, total));
|
|
9988
10099
|
};
|
|
9989
10100
|
// a group with several blank nodes (or with nested sub-rows) is collapsible, as are its rows with sub-rows;
|
|
9990
10101
|
// its header shows the combined value across all rows
|
|
9991
|
-
const withCollapsible = (group) =>
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
})
|
|
10102
|
+
const withCollapsible = (group) => {
|
|
10103
|
+
const recalculatedNodes = group.rows.flatMap(row => row.recalculated);
|
|
10104
|
+
const recalculatedValue = reduceValues(recalculatedNodes, group.termId, group.type);
|
|
10105
|
+
return {
|
|
10106
|
+
...group,
|
|
10107
|
+
canOpen: group.rows.length > 1 || group.rows.some(row => row.subRows.length > 0),
|
|
10108
|
+
rows: group.rows.map(row => ({ ...row, canOpen: row.subRows.length > 0 })),
|
|
10109
|
+
originalValue: reduceValues(group.rows.flatMap(row => row.original), group.termId, group.type),
|
|
10110
|
+
recalculatedValue,
|
|
10111
|
+
recalculatedFormula: valueFormula(recalculatedNodes, group.termId, recalculatedValue, group.type)
|
|
10112
|
+
};
|
|
10113
|
+
};
|
|
9998
10114
|
const isSucceededModel = (model) => [LogStatus.success, LogStatus.notRequired, LogStatus.dataProvided].includes(model.status);
|
|
9999
10115
|
// did this row succeed? not failed, and either has a successful direct model or every sub-row did
|
|
10000
10116
|
const rowSucceeded = (row) => {
|
|
@@ -10247,7 +10363,7 @@ class NodeJLogModelsComponent {
|
|
|
10247
10363
|
return model.methodId;
|
|
10248
10364
|
}
|
|
10249
10365
|
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 }); }
|
|
10366
|
+
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 @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 (!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}: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
10367
|
}
|
|
10252
10368
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, decorators: [{
|
|
10253
10369
|
type: Component$1,
|
|
@@ -10271,7 +10387,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
10271
10387
|
NodeLogsModelsLogsStatusComponent,
|
|
10272
10388
|
NodeLogsModelsContributionsComponent,
|
|
10273
10389
|
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"] }]
|
|
10390
|
+
], 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 @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 (!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}: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
10391
|
}], 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
10392
|
|
|
10277
10393
|
const groupTerms = (terms) => terms.reduce((prev, curr) => ({ ...prev, [curr['@id']]: curr }), {});
|