@hestia-earth/ui-components 0.42.5 → 0.42.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -9,7 +9,7 @@ import { NgbTooltip, NgbDropdown, NgbDropdownMenu, NgbDropdownToggle, NgbActiveM
|
|
|
9
9
|
import { ReplaySubject, of, mergeMap, shareReplay, delay, map, catchError, distinctUntilChanged, timer, take, first, Subject, combineLatest, filter, fromEvent, startWith, merge, skip, switchMap, EMPTY, throttleTime, animationFrameScheduler, debounceTime, takeUntil, lastValueFrom, tap, skipUntil, zip, mergeAll, reduce, forkJoin, throwError, from, firstValueFrom, toArray, distinct, groupBy } from 'rxjs';
|
|
10
10
|
import { HttpClient } from '@angular/common/http';
|
|
11
11
|
import get from 'lodash.get';
|
|
12
|
-
import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, isTypeBlankNode, typeToSchemaType, infrastructureTermTermType, managementTermTermType } from '@hestia-earth/schema';
|
|
12
|
+
import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, uniquenessFields, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, isTypeBlankNode, typeToSchemaType, infrastructureTermTermType, managementTermTermType } from '@hestia-earth/schema';
|
|
13
13
|
import Gradient from 'javascript-color-gradient';
|
|
14
14
|
import { ShadeGenerator } from 'shade-generator/dist/shadeGenerator';
|
|
15
15
|
import { select, selectAll } from 'd3-selection';
|
|
@@ -7428,7 +7428,7 @@ class HeNodeService {
|
|
|
7428
7428
|
params
|
|
7429
7429
|
})
|
|
7430
7430
|
.pipe(catchError(() => of('')))
|
|
7431
|
-
: this.http.get(url, { params }).pipe(catchError(() => of({})));
|
|
7431
|
+
: this.http.get(url, { params: { ...params, format: 'json' } }).pipe(catchError(() => of({})));
|
|
7432
7432
|
}
|
|
7433
7433
|
getContributions$({ dataState, ...impactAssessment }) {
|
|
7434
7434
|
return this.http.get(`${this.nodeUrl(impactAssessment)}/contributions`).pipe(mergeMap(contributions => isEmpty(contributions) ? this.getContributionsFromLog$(impactAssessment) : of(contributions)), catchError(() => this.getContributionsFromLog$(impactAssessment)));
|
|
@@ -8055,8 +8055,8 @@ const inputGroupsTermTypes = [TermTermType.pesticideBrandName, TermTermType.fert
|
|
|
8055
8055
|
const defaultGroupOpen = false;
|
|
8056
8056
|
const noValue = 'None';
|
|
8057
8057
|
// add any other models that are set as "not relevant"
|
|
8058
|
-
const notRelevantModels = ['emissionNotRelevant'];
|
|
8059
|
-
const isNotRelevantModel = (model) => notRelevantModels.includes(model.methodId);
|
|
8058
|
+
const notRelevantModels$1 = ['emissionNotRelevant'];
|
|
8059
|
+
const isNotRelevantModel$1 = (model) => notRelevantModels$1.includes(model.methodId);
|
|
8060
8060
|
const asArray = (values) => (Array.isArray(values) ? values : []);
|
|
8061
8061
|
const subValueKeys = ['transformation', 'animal'];
|
|
8062
8062
|
const computeTerms = (originalValues, recalculatedValues, terms, filterTermTypes, extraTerms = []) => orderBy(uniqBy([
|
|
@@ -8079,7 +8079,7 @@ var LogStatus;
|
|
|
8079
8079
|
})(LogStatus || (LogStatus = {}));
|
|
8080
8080
|
const hasLogs = (logs) => !!logs?.requirements || !!logs?.logs || logs?.missingLookups?.length > 0;
|
|
8081
8081
|
const hasLogDetails = (status, logs) => [LogStatus.success, LogStatus.error, LogStatus.dataProvided].includes(status) && hasLogs(logs);
|
|
8082
|
-
const isRecalculatedByModel = (data, model) => 'recalculated' in data && data.recalculated?.some(value => blankNodeModelId(value) === model.methodId);
|
|
8082
|
+
const isRecalculatedByModel = (data, model) => 'recalculated' in data && data.recalculated?.some(value => blankNodeModelId$1(value) === model.methodId);
|
|
8083
8083
|
const logStatus = (data, logs, model, hasPreviousSuccess = false) => {
|
|
8084
8084
|
const termLogs = logs?.[model.methodId];
|
|
8085
8085
|
const withLogs = hasLog(termLogs);
|
|
@@ -8090,7 +8090,7 @@ const logStatus = (data, logs, model, hasPreviousSuccess = false) => {
|
|
|
8090
8090
|
].every(Boolean);
|
|
8091
8091
|
// can be not required for a specific model
|
|
8092
8092
|
const isRequired = !!termLogs && 'runRequired' in termLogs ? termLogs.runRequired : data.isRequired;
|
|
8093
|
-
const isCurrentModel = (data.recalculated ?? []).some(v => blankNodeModelId(v) == model.methodId);
|
|
8093
|
+
const isCurrentModel = (data.recalculated ?? []).some(v => blankNodeModelId$1(v) == model.methodId);
|
|
8094
8094
|
return withLogs
|
|
8095
8095
|
? !isRequired
|
|
8096
8096
|
? LogStatus.notRequired
|
|
@@ -8135,7 +8135,7 @@ const mergeSubValues = (values) => Object.values(values.reduce((prev, { id, key,
|
|
|
8135
8135
|
};
|
|
8136
8136
|
return prev;
|
|
8137
8137
|
}, {}));
|
|
8138
|
-
const reduceValues = (values, termId) => {
|
|
8138
|
+
const reduceValues$1 = (values, termId) => {
|
|
8139
8139
|
const propertyValues = values
|
|
8140
8140
|
.map(({ value }) => propertyValue$1(value, termId))
|
|
8141
8141
|
// propertyValue may return null if the value is null or undefined, therefore remove them from total
|
|
@@ -8170,11 +8170,11 @@ const groupSubvalues = (subValues, termsGrouping) => Object.keys(termsGrouping).
|
|
|
8170
8170
|
const blankNodeValueByKey = {
|
|
8171
8171
|
property: (values, _k, id) => !!id && values?.length ? (values[0].properties || []).find(p => p.term['@id'] === id)?.value || '' : '',
|
|
8172
8172
|
input: (values, _k, id, animalId) => !!id && (values || []).filter(v => v['@type'] === SchemaType.Emission || v['@type'] === SchemaType.Indicator).length
|
|
8173
|
-
? reduceValues(values.filter(({ inputs, animals }) => (inputs || []).some(input => input['@id'] === id) &&
|
|
8173
|
+
? reduceValues$1(values.filter(({ inputs, animals }) => (inputs || []).some(input => input['@id'] === id) &&
|
|
8174
8174
|
(!animalId || (animals || []).some(animal => animal['@id'] === animalId))), id)
|
|
8175
8175
|
: '',
|
|
8176
8176
|
transformation: (values, _k, id) => values.length
|
|
8177
|
-
? reduceValues(values.filter(({ transformation }) => transformation?.['@id'] === id), id)
|
|
8177
|
+
? reduceValues$1(values.filter(({ transformation }) => transformation?.['@id'] === id), id)
|
|
8178
8178
|
: '',
|
|
8179
8179
|
default: (blankNodes, key) => {
|
|
8180
8180
|
const value = blankNodes?.length ? blankNodes[0][key] : null;
|
|
@@ -8267,9 +8267,9 @@ const logAnimals = (node) => (node.animals ?? []).map(animal => ({
|
|
|
8267
8267
|
}));
|
|
8268
8268
|
const includeCycleSubValue = (subValues) => subValues.some(v => !['property', 'backgroundData'].includes(v.key));
|
|
8269
8269
|
const cycleSubValue = ({ termId, configModels, isRequired, subValues, original, recalculated }) => {
|
|
8270
|
-
const originalValue = reduceValues(original.filter((v) => !v.inputs?.length && !v.transformation), termId);
|
|
8270
|
+
const originalValue = reduceValues$1(original.filter((v) => !v.inputs?.length && !v.transformation), termId);
|
|
8271
8271
|
const recalculatedValues = recalculated.filter((v) => !v.inputs?.length && !v.transformation);
|
|
8272
|
-
const recalculatedValue = reduceValues(recalculatedValues, termId);
|
|
8272
|
+
const recalculatedValue = reduceValues$1(recalculatedValues, termId);
|
|
8273
8273
|
return includeCycleSubValue(subValues) && !isEmpty(recalculatedValue)
|
|
8274
8274
|
? {
|
|
8275
8275
|
blankNode: true,
|
|
@@ -8454,7 +8454,7 @@ const configModelWithDocs = ({ nodeType, type, termId, termType, key }, subValue
|
|
|
8454
8454
|
? findMatchingModel({ model: methodId, modelKey: 'seed_emissions' })
|
|
8455
8455
|
: undefined) ||
|
|
8456
8456
|
(modelKey ? findMatchingModel({ modelKey, model: methodId }) : undefined) ||
|
|
8457
|
-
(isNotRelevantModel({ methodId }) ? findMatchingModel({ model: methodId }) : undefined);
|
|
8457
|
+
(isNotRelevantModel$1({ methodId }) ? findMatchingModel({ model: methodId }) : undefined);
|
|
8458
8458
|
return { methodId, model };
|
|
8459
8459
|
};
|
|
8460
8460
|
const configModelWithLogs = (data, logs, previousModelSuccess = false) => (model) => {
|
|
@@ -8498,7 +8498,7 @@ const dataWithConfigModelLogs = (logs, termId) => (data) => {
|
|
|
8498
8498
|
}
|
|
8499
8499
|
return {
|
|
8500
8500
|
...data,
|
|
8501
|
-
configModels: filterConfigModels(configModels, (model) => ![LogStatus.notRequired].includes(model?.status) || isNotRelevantModel(model))
|
|
8501
|
+
configModels: filterConfigModels(configModels, (model) => ![LogStatus.notRequired].includes(model?.status) || isNotRelevantModel$1(model))
|
|
8502
8502
|
};
|
|
8503
8503
|
};
|
|
8504
8504
|
/**
|
|
@@ -8526,8 +8526,8 @@ const groupParallelModels = (config, termId, modelKey, models) => {
|
|
|
8526
8526
|
.map(v => (v.length === 1 ? v[0] : v));
|
|
8527
8527
|
};
|
|
8528
8528
|
const allParallel = (models) => models.length === 1 && Array.isArray(models[0]) && models[0].length > 1;
|
|
8529
|
-
const blankNodeModelId = (value) => (value.methodModel || value.method || value.model)?.['@id'];
|
|
8530
|
-
const valueByMethodId = (values, methodId, termId) => propertyValue$1(values.find(v => blankNodeModelId(v) === methodId)?.value, termId);
|
|
8529
|
+
const blankNodeModelId$1 = (value) => (value.methodModel || value.method || value.model)?.['@id'];
|
|
8530
|
+
const valueByMethodId = (values, methodId, termId) => propertyValue$1(values.find(v => blankNodeModelId$1(v) === methodId)?.value, termId);
|
|
8531
8531
|
const groupParallelValues = (values, models, termId) => Array.isArray(models)
|
|
8532
8532
|
? Object.fromEntries(models.map(model => [model.methodId, valueByMethodId(values, model.methodId, termId)]))
|
|
8533
8533
|
: {};
|
|
@@ -8558,7 +8558,7 @@ const groupLogsByTerm = (node, logs, config, allOriginalValues, allRecalculatedV
|
|
|
8558
8558
|
const modelsFromRecalculated = recalculated
|
|
8559
8559
|
// ignore background emissions as no models run directly on them
|
|
8560
8560
|
.filter((v) => ![EmissionMethodTier.background].includes(v.methodTier))
|
|
8561
|
-
.map(blankNodeModelId)
|
|
8561
|
+
.map(blankNodeModelId$1)
|
|
8562
8562
|
.filter(Boolean);
|
|
8563
8563
|
const models = unique([
|
|
8564
8564
|
...modelsFromLogs,
|
|
@@ -8577,9 +8577,9 @@ const groupLogsByTerm = (node, logs, config, allOriginalValues, allRecalculatedV
|
|
|
8577
8577
|
subValues.some(v => v.key === 'transformation')
|
|
8578
8578
|
].every(Boolean);
|
|
8579
8579
|
const filteredOriginalValues = ignoreTransformationValues ? filterTransformation(original) : original;
|
|
8580
|
-
const originalValue = reduceValues(filteredOriginalValues, termId);
|
|
8580
|
+
const originalValue = reduceValues$1(filteredOriginalValues, termId);
|
|
8581
8581
|
const filteredRecalculatedValues = ignoreTransformationValues ? filterTransformation(recalculated) : recalculated;
|
|
8582
|
-
const recalculatedValue = reduceValues(filteredRecalculatedValues, termId);
|
|
8582
|
+
const recalculatedValue = reduceValues$1(filteredRecalculatedValues, termId);
|
|
8583
8583
|
const nodeLog = dataWithConfigModelLogs(termLogs)({
|
|
8584
8584
|
blankNode: true,
|
|
8585
8585
|
isOpen: defaultGroupOpen,
|
|
@@ -8691,7 +8691,7 @@ const modelCount = (blankNodeLogs) => Math.max.apply(Math.max, [
|
|
|
8691
8691
|
])
|
|
8692
8692
|
]);
|
|
8693
8693
|
const parseLogValue = (value) => (isNumber(value) ? parseFloat(value) : value);
|
|
8694
|
-
const logValueArray = (value) => [';', ':'].some(v => value.includes(v))
|
|
8694
|
+
const logValueArray = (value) => typeof value === 'string' && [';', ':'].some(v => value.includes(v))
|
|
8695
8695
|
? value.split(';').flatMap(v => {
|
|
8696
8696
|
const res = v
|
|
8697
8697
|
.split('_')
|
|
@@ -8778,22 +8778,32 @@ class NodeLogsModelsLogsComponent {
|
|
|
8778
8778
|
this.requirements = computed(() => this.logs()?.requirements ?? {}, ...(ngDevMode ? [{ debugName: "requirements" }] : []));
|
|
8779
8779
|
this.requirementKeys = computed(() => requirementKeys(this.requirements()), ...(ngDevMode ? [{ debugName: "requirementKeys" }] : []));
|
|
8780
8780
|
this.missingLookups = computed(() => this.logs().missingLookups ?? [], ...(ngDevMode ? [{ debugName: "missingLookups" }] : []));
|
|
8781
|
+
// the untouched `.jlog` entry (new log format only), shown on demand as raw JSON
|
|
8782
|
+
this.raw = computed(() => this.logs()?.raw, ...(ngDevMode ? [{ debugName: "raw" }] : []));
|
|
8783
|
+
this.rawJson = computed(() => {
|
|
8784
|
+
const raw = this.raw();
|
|
8785
|
+
return raw ? JSON.stringify(raw, null, 2) : '';
|
|
8786
|
+
}, ...(ngDevMode ? [{ debugName: "rawJson" }] : []));
|
|
8787
|
+
this.showRaw = signal(false, ...(ngDevMode ? [{ debugName: "showRaw" }] : []));
|
|
8781
8788
|
this.allLogs = computed(() => [
|
|
8782
8789
|
...requirementKeys(this.requirements()).map(key => parseLog$1(key, this.requirements()[key])),
|
|
8783
8790
|
...parseLogs(this.logs()?.logs ?? {})
|
|
8784
8791
|
].filter(v => v.value !== null), ...(ngDevMode ? [{ debugName: "allLogs" }] : []));
|
|
8785
8792
|
}
|
|
8793
|
+
toggleRaw() {
|
|
8794
|
+
this.showRaw.update(value => !value);
|
|
8795
|
+
}
|
|
8786
8796
|
toggleSort(sortBy, sorting) {
|
|
8787
8797
|
const sortOrder = sorting.sortOrder === 'asc' ? 'desc' : 'asc';
|
|
8788
8798
|
sorting.sortBy = sortBy;
|
|
8789
8799
|
sorting.sortOrder = sortOrder;
|
|
8790
8800
|
}
|
|
8791
8801
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsLogsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8792
|
-
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 <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\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<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}\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" }] }); }
|
|
8802
|
+
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 <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\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" }] }); }
|
|
8793
8803
|
}
|
|
8794
8804
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsLogsComponent, decorators: [{
|
|
8795
8805
|
type: Component$1,
|
|
8796
|
-
args: [{ selector: 'he-node-logs-models-logs', imports: [NgTemplateOutlet, HESvgIconComponent, NodeLinkComponent, ClipboardComponent, SortByPipe, IsArrayPipe], template: "<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\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<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}\n"] }]
|
|
8806
|
+
args: [{ selector: 'he-node-logs-models-logs', imports: [NgTemplateOutlet, HESvgIconComponent, NodeLinkComponent, ClipboardComponent, SortByPipe, IsArrayPipe], template: "<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\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"] }]
|
|
8797
8807
|
}], propDecorators: { logs: [{ type: i0.Input, args: [{ isSignal: true, alias: "logs", required: true }] }] } });
|
|
8798
8808
|
|
|
8799
8809
|
class NodeLogsModelsLogsStatusComponent {
|
|
@@ -9138,19 +9148,27 @@ const groupLogsByModel = (data = '', groupBySubValue = false, groupByAnimal = fa
|
|
|
9138
9148
|
? groupLogSubValue(group, log, subValue)
|
|
9139
9149
|
: groupLog(group, log, groupByAnimal);
|
|
9140
9150
|
}, {});
|
|
9151
|
+
const logNodeFor = (node) => ({
|
|
9152
|
+
'@type': node['@type'],
|
|
9153
|
+
'@id': node['@id'],
|
|
9154
|
+
dataState: node.aggregated && node['@type'] !== NodeType.ImpactAssessment ? DataState.original : DataState.recalculated
|
|
9155
|
+
});
|
|
9141
9156
|
class NodeLogsModelsService {
|
|
9142
9157
|
constructor() {
|
|
9143
9158
|
this.nodeService = inject(HeNodeService);
|
|
9144
9159
|
}
|
|
9145
9160
|
getNodeLogs$(node, groupByAnimal = false) {
|
|
9146
9161
|
return this.nodeService
|
|
9147
|
-
.getLog$(
|
|
9148
|
-
'@type': node['@type'],
|
|
9149
|
-
'@id': node['@id'],
|
|
9150
|
-
dataState: node.aggregated && node['@type'] !== NodeType.ImpactAssessment ? DataState.original : DataState.recalculated
|
|
9151
|
-
})
|
|
9162
|
+
.getLog$(logNodeFor(node))
|
|
9152
9163
|
.pipe(map(logs => logs ? groupLogsByModel(logs, node['@type'] === NodeType.Cycle, groupByAnimal) : {}));
|
|
9153
9164
|
}
|
|
9165
|
+
/**
|
|
9166
|
+
* Fetch the new `.jlog` (JSON) recalculation logs, following the representation of the node.
|
|
9167
|
+
* Resolves to an empty object when the node only has the legacy text logs.
|
|
9168
|
+
*/
|
|
9169
|
+
getJLog$(node) {
|
|
9170
|
+
return this.nodeService.getLog$(logNodeFor(node), 'json').pipe(map(jlog => (jlog || {})));
|
|
9171
|
+
}
|
|
9154
9172
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
9155
9173
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsService, providedIn: 'root' }); }
|
|
9156
9174
|
}
|
|
@@ -9161,6 +9179,889 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
9161
9179
|
}]
|
|
9162
9180
|
}] });
|
|
9163
9181
|
|
|
9182
|
+
/**
|
|
9183
|
+
* The `.jlog` recalculation logs follow the representation of the recalculated node: model logs are
|
|
9184
|
+
* stored per blank node index (with nested `properties`), plus `<field>-failed` entries (keyed by
|
|
9185
|
+
* term) for models that failed to add anything. Unlike the legacy text logs - which merge everything
|
|
9186
|
+
* by `term.@id` - this keeps every blank node distinct, so the same term can appear multiple times
|
|
9187
|
+
* (e.g. a Measurement at two different date ranges) and each is shown as its own sub-row.
|
|
9188
|
+
*/
|
|
9189
|
+
const failedFieldSuffix = '-failed';
|
|
9190
|
+
const blankNodeModelId = (value) => (value?.methodModel || value?.method || value?.model)?.['@id'];
|
|
9191
|
+
// models that mark a blank node as "not relevant" rather than producing a value (mirrors the legacy list)
|
|
9192
|
+
const notRelevantModels = ['emissionNotRelevant'];
|
|
9193
|
+
const isNotRelevantModel = (methodId) => notRelevantModels.includes(methodId);
|
|
9194
|
+
// eslint-disable-next-line complexity -- exhaustive value-type mapping
|
|
9195
|
+
const jLogValue = (value) => value === true
|
|
9196
|
+
? 'True'
|
|
9197
|
+
: value === false
|
|
9198
|
+
? 'False'
|
|
9199
|
+
: value === null || typeof value === 'undefined'
|
|
9200
|
+
? 'None'
|
|
9201
|
+
: Array.isArray(value)
|
|
9202
|
+
? value
|
|
9203
|
+
: // a non-array object (e.g. an empty `{}`) is shown as readable text, not "[object Object]"
|
|
9204
|
+
typeof value === 'object'
|
|
9205
|
+
? JSON.stringify(value)
|
|
9206
|
+
: String(value);
|
|
9207
|
+
// the orchestrator records these as model-debug logs (the legacy text format keeps them on a separate
|
|
9208
|
+
// line from the requirements). The `.jlog` flattens both onto the entry, so route the known ones to
|
|
9209
|
+
// `logs` - where the status/detail popovers read them (e.g. the "not relevant" breakdown)
|
|
9210
|
+
const modelLogKeys = [
|
|
9211
|
+
'siteType_allowed',
|
|
9212
|
+
'product_id_allowed',
|
|
9213
|
+
'site_measurement_id_allowed',
|
|
9214
|
+
'product_termType_allowed',
|
|
9215
|
+
'input_id_allowed',
|
|
9216
|
+
'input_termType_allowed',
|
|
9217
|
+
'node_type_allowed',
|
|
9218
|
+
'is_empty',
|
|
9219
|
+
'error'
|
|
9220
|
+
];
|
|
9221
|
+
// spread `obj` only when `condition` is truthy, otherwise nothing (for building objects declaratively)
|
|
9222
|
+
const spreadWhen = (condition, obj) => (condition ? obj : {});
|
|
9223
|
+
// the `key -> value` fields of an entry matching the predicate, with their values normalised
|
|
9224
|
+
const pickFields = (rest, predicate) => Object.fromEntries(Object.entries(rest)
|
|
9225
|
+
.filter(([key]) => predicate(key))
|
|
9226
|
+
.map(([key, value]) => [key, jLogValue(value)]));
|
|
9227
|
+
// the orchestrator's own status flags (`shouldRunOrchestrator`, and `runRequired` when the entry has none)
|
|
9228
|
+
const orchestratorFlags = (orchestrator, runRequired) => orchestrator && typeof orchestrator === 'object'
|
|
9229
|
+
? {
|
|
9230
|
+
...spreadWhen('should_run' in orchestrator, { shouldRunOrchestrator: orchestrator.should_run }),
|
|
9231
|
+
...spreadWhen('run_required' in orchestrator && typeof runRequired === 'undefined', {
|
|
9232
|
+
runRequired: orchestrator.run_required
|
|
9233
|
+
})
|
|
9234
|
+
}
|
|
9235
|
+
: {};
|
|
9236
|
+
/**
|
|
9237
|
+
* Map a `.jlog` model run entry to the legacy `INodeTermLog` (status flags + `requirements` + `logs`),
|
|
9238
|
+
* so the requirements/logs and status detail components can render it unchanged.
|
|
9239
|
+
*/
|
|
9240
|
+
const jLogEntryToLog = (entry) => {
|
|
9241
|
+
const { model, orchestrator, should_run, run_required, methodTier, model_key, is_not_relevant, ...rest } = entry;
|
|
9242
|
+
const logs = pickFields(rest, key => modelLogKeys.includes(key));
|
|
9243
|
+
const requirements = pickFields(rest, key => !modelLogKeys.includes(key));
|
|
9244
|
+
return {
|
|
9245
|
+
// keep the untouched `.jlog` entry so the popover can show the raw JSON
|
|
9246
|
+
raw: entry,
|
|
9247
|
+
// kept on the log itself (not in `requirements`) so the method tier shows next to the model name
|
|
9248
|
+
...spreadWhen(methodTier, { methodTier }),
|
|
9249
|
+
...spreadWhen(model_key, { model_key }),
|
|
9250
|
+
// surfaced at the top level so the status popover can read `is_not_relevant === 'True'`
|
|
9251
|
+
...spreadWhen(typeof is_not_relevant !== 'undefined', { is_not_relevant: jLogValue(is_not_relevant) }),
|
|
9252
|
+
...orchestratorFlags(orchestrator, run_required),
|
|
9253
|
+
...spreadWhen(typeof should_run !== 'undefined', { shouldRun: should_run }),
|
|
9254
|
+
...spreadWhen(typeof run_required !== 'undefined', { runRequired: run_required }),
|
|
9255
|
+
...spreadWhen(Object.keys(logs).length, { logs }),
|
|
9256
|
+
...spreadWhen(Object.keys(requirements).length, { requirements })
|
|
9257
|
+
};
|
|
9258
|
+
};
|
|
9259
|
+
/**
|
|
9260
|
+
* Derive the run status from the explicit `.jlog` fields:
|
|
9261
|
+
* - failed-section entries always count as an error;
|
|
9262
|
+
* - a model the orchestrator did not select (`orchestrator.should_run === false`) retained user data;
|
|
9263
|
+
* - a model that was selected but did not run failed - unless an earlier model in the hierarchy already
|
|
9264
|
+
* succeeded, in which case it was skipped (a higher-tier model ran instead).
|
|
9265
|
+
*/
|
|
9266
|
+
// eslint-disable-next-line complexity -- a sequence of priority status rules
|
|
9267
|
+
const jLogModelStatus = (entry, isFailed, hasPreviousSuccess = false) => {
|
|
9268
|
+
if (isFailed)
|
|
9269
|
+
return LogStatus.error;
|
|
9270
|
+
if (entry?.run_required === false)
|
|
9271
|
+
return LogStatus.notRequired;
|
|
9272
|
+
if (entry?.orchestrator?.should_run === false)
|
|
9273
|
+
return LogStatus.dataProvided;
|
|
9274
|
+
if (entry?.should_run === true)
|
|
9275
|
+
return LogStatus.success;
|
|
9276
|
+
if (entry?.should_run === false)
|
|
9277
|
+
return hasPreviousSuccess ? LogStatus.skipHierarchy : LogStatus.error;
|
|
9278
|
+
return LogStatus.dataProvided;
|
|
9279
|
+
};
|
|
9280
|
+
// candidate engine-model-link queries, most precise first:
|
|
9281
|
+
// - the log's `model` + `orchestrator.value` map directly onto the link's `model` + `modelKey`;
|
|
9282
|
+
// - a dotted orchestrator value (e.g. `animal.pregnancyRateTotal`) may map to the bare key/term suffix
|
|
9283
|
+
// (`pregnancyRateTotal`) - links are keyed by `modelKey` or `term`, so try both;
|
|
9284
|
+
// - then the term-scoped matches, then the node-level model key (background models run at the node level,
|
|
9285
|
+
// e.g. `cycle`), and finally any model with that id
|
|
9286
|
+
const modelLinkQueries = (nodeType, termId, methodId, modelKey) => {
|
|
9287
|
+
const keySuffix = modelKey?.includes('.') ? modelKey.split('.').pop() : undefined;
|
|
9288
|
+
return [
|
|
9289
|
+
modelKey && { model: methodId, modelKey },
|
|
9290
|
+
keySuffix && { model: methodId, modelKey: keySuffix },
|
|
9291
|
+
keySuffix && { model: methodId, term: keySuffix },
|
|
9292
|
+
{ '@type': nodeType, term: termId, model: methodId },
|
|
9293
|
+
{ term: termId, model: methodId },
|
|
9294
|
+
{ modelKey: toSnakeCase(nodeType), model: methodId },
|
|
9295
|
+
{ model: methodId }
|
|
9296
|
+
].filter(Boolean);
|
|
9297
|
+
};
|
|
9298
|
+
const resolveModel = (nodeType, termId, methodId, modelKey) => modelLinkQueries(nodeType, termId, methodId, modelKey)
|
|
9299
|
+
.map(query => findMatchingModel(query))
|
|
9300
|
+
.find(Boolean);
|
|
9301
|
+
const toModelRun = (entry, status, nodeType, termId) => {
|
|
9302
|
+
const log = jLogEntryToLog(entry);
|
|
9303
|
+
return {
|
|
9304
|
+
methodId: entry.model,
|
|
9305
|
+
modelKey: entry.orchestrator?.value,
|
|
9306
|
+
status,
|
|
9307
|
+
logs: log,
|
|
9308
|
+
showLogs: !!(log.requirements || log.logs || log.raw),
|
|
9309
|
+
model: resolveModel(nodeType, termId, entry.model, entry.orchestrator?.value)
|
|
9310
|
+
};
|
|
9311
|
+
};
|
|
9312
|
+
const jLogModelRuns = (logs, nodeType, termId, isFailed) => (logs || [])
|
|
9313
|
+
.flat()
|
|
9314
|
+
.filter(entry => !!entry?.model)
|
|
9315
|
+
// models run in hierarchy order, so thread "did an earlier model succeed?" through the runs: a later
|
|
9316
|
+
// model that did not run was skipped (a higher-tier model ran instead) rather than failed
|
|
9317
|
+
.reduce(({ runs, hasPreviousSuccess }, entry) => {
|
|
9318
|
+
const status = jLogModelStatus(entry, isFailed, hasPreviousSuccess);
|
|
9319
|
+
return {
|
|
9320
|
+
runs: [...runs, toModelRun(entry, status, nodeType, termId)],
|
|
9321
|
+
hasPreviousSuccess: hasPreviousSuccess || status === LogStatus.success
|
|
9322
|
+
};
|
|
9323
|
+
}, { runs: [], hasPreviousSuccess: false }).runs;
|
|
9324
|
+
// like `jLogModelRuns` but keeps the `.jlog` `logs` structure: each top-level entry is one "Model N"
|
|
9325
|
+
// column, and a nested array is a parallel group whose runs are stacked in that column (each independent,
|
|
9326
|
+
// so they share the same "previous success" state rather than skipping one another)
|
|
9327
|
+
const jLogModelColumns = (logs, nodeType, termId, isFailed) => (logs || [])
|
|
9328
|
+
.map(step => (Array.isArray(step) ? step : [step]).filter((entry) => !!entry?.model))
|
|
9329
|
+
.filter(entries => entries.length > 0)
|
|
9330
|
+
.reduce(({ columns, hasPreviousSuccess }, entries) => {
|
|
9331
|
+
const runs = entries.map((entry) => toModelRun(entry, jLogModelStatus(entry, isFailed, hasPreviousSuccess), nodeType, termId));
|
|
9332
|
+
return {
|
|
9333
|
+
columns: [...columns, runs.length > 1 ? runs : runs[0]],
|
|
9334
|
+
hasPreviousSuccess: hasPreviousSuccess || runs.some((run) => run.status === LogStatus.success)
|
|
9335
|
+
};
|
|
9336
|
+
}, { columns: [], hasPreviousSuccess: false }).columns;
|
|
9337
|
+
// `term.@id` defines the group; every other uniqueness field (including `key.@id`) distinguishes rows
|
|
9338
|
+
// within the group - Term-valued ones (key, inputs, country, landCover, methodModel, ...) become links
|
|
9339
|
+
const excludedIdentityFields = ['term.@id'];
|
|
9340
|
+
/**
|
|
9341
|
+
* The fields (from the schema `uniquenessFields`) that distinguish two blank nodes sharing a term.
|
|
9342
|
+
* Relations come from the type-keyed definition (e.g. `Emission` -> `inputs`); the scalar properties are
|
|
9343
|
+
* the union of that definition with the richer parent-keyed list (e.g. `Site.measurements`, which adds
|
|
9344
|
+
* `depthUpper`/`depthLower`), minus the term/key and any relation roots.
|
|
9345
|
+
*/
|
|
9346
|
+
// eslint-disable-next-line complexity -- assembles the identity fields from two `uniquenessFields` sources
|
|
9347
|
+
const identitySpec = (type, nodeType, nodeKey) => {
|
|
9348
|
+
const def = (type && uniquenessFields[type]) || {};
|
|
9349
|
+
const relations = Object.keys(def).filter(key => key !== 'properties');
|
|
9350
|
+
const parentFields = (nodeType && uniquenessFields[nodeType]?.[nodeKey]) || [];
|
|
9351
|
+
const properties = [...new Set([...(def.properties || []), ...parentFields])].filter((field) => !excludedIdentityFields.includes(field) && !relations.includes(field.split('.')[0]));
|
|
9352
|
+
return { def, properties, relations };
|
|
9353
|
+
};
|
|
9354
|
+
const isPresent = (value) => value !== undefined && value !== null && value !== '';
|
|
9355
|
+
// the joined uniqueness-field ids of each item in a relation (e.g. an emission's `inputs[].@id`)
|
|
9356
|
+
const relationItemIds = (items, fields) => Array.isArray(items)
|
|
9357
|
+
? items.map(item => fields.map(field => get(item, field)).filter(Boolean).join(':')).filter(Boolean)
|
|
9358
|
+
: [];
|
|
9359
|
+
const blankNodeIdentity = (value, { def, properties, relations }) => {
|
|
9360
|
+
const propertyEntries = properties
|
|
9361
|
+
.map((path) => [path, get(value, path)])
|
|
9362
|
+
.filter(([, v]) => isPresent(v));
|
|
9363
|
+
const relationEntries = relations
|
|
9364
|
+
.map((relation) => [relation, relationItemIds(value?.[relation], def[relation])])
|
|
9365
|
+
.filter(([, ids]) => ids.length);
|
|
9366
|
+
return Object.fromEntries([...propertyEntries, ...relationEntries]);
|
|
9367
|
+
};
|
|
9368
|
+
const identityKey = (identity) => JSON.stringify(identity);
|
|
9369
|
+
// is this a Term object (has an `@id` and looks like a Term), so it can be shown as a link
|
|
9370
|
+
const isTermLike = (value) => value?.['@type'] === NodeType.Term || !!value?.termType;
|
|
9371
|
+
const isTermObject = (value) => typeof value === 'object' && !Array.isArray(value) && !!value?.['@id'] && isTermLike(value);
|
|
9372
|
+
// the term(s) an identity field points to on the blank node (empty when the field is a scalar)
|
|
9373
|
+
const identityFieldTerms = (value, field) => {
|
|
9374
|
+
const target = value?.[field.split('.')[0]];
|
|
9375
|
+
return Array.isArray(target) ? target.filter(isTermObject) : isTermObject(target) ? [target] : [];
|
|
9376
|
+
};
|
|
9377
|
+
// method-metadata uniqueness fields are noise in the row identity (the model is already its own column)
|
|
9378
|
+
// unless they alone tell the rows apart
|
|
9379
|
+
const noisyIdentityFields = ['methodClassification', 'methodDescription', 'method.@id', 'methodModel.@id'];
|
|
9380
|
+
const isNoisyIdentityField = (field) => noisyIdentityFields.includes(field);
|
|
9381
|
+
const identityWithout = (identity, predicate) => Object.fromEntries(Object.entries(identity).filter(([key]) => !predicate(key)));
|
|
9382
|
+
const formatIdentityProperty = ([key, value]) => `${key.replace('.@id', '')}: ${Array.isArray(value) ? value.join(', ') : value}`;
|
|
9383
|
+
// the scalar identities as text; `depthUpper`/`depthLower` are combined into "depths: <upper>-<lower>"
|
|
9384
|
+
const formatIdentityLabel = (scalars) => {
|
|
9385
|
+
const props = Object.entries(scalars);
|
|
9386
|
+
const { depthUpper, depthLower } = Object.fromEntries(props);
|
|
9387
|
+
const hasDepths = isPresent(depthUpper) && isPresent(depthLower);
|
|
9388
|
+
const depths = hasDepths ? [`depths: ${depthUpper}-${depthLower}`] : [];
|
|
9389
|
+
const rest = props.filter(([key]) => !(hasDepths && (key === 'depthUpper' || key === 'depthLower')));
|
|
9390
|
+
return [...depths, ...rest.map(formatIdentityProperty)].join(' · ');
|
|
9391
|
+
};
|
|
9392
|
+
// whether dropping the noisy method fields still gives every row a distinct identity
|
|
9393
|
+
const noisyFieldsRedundant = (rows) => new Set(rows.map(row => identityKey(identityWithout(row.identity, isNoisyIdentityField)))).size === rows.length;
|
|
9394
|
+
// split a row's identity into Term-link segments (any field whose value is a Term) and a scalar text label
|
|
9395
|
+
const identityDisplay = (identity, value) => {
|
|
9396
|
+
const segments = [];
|
|
9397
|
+
const scalars = {};
|
|
9398
|
+
Object.entries(identity).forEach(([field, val]) => {
|
|
9399
|
+
const terms = identityFieldTerms(value, field);
|
|
9400
|
+
if (terms.length) {
|
|
9401
|
+
segments.push({ field: field.split('.')[0], terms });
|
|
9402
|
+
}
|
|
9403
|
+
else {
|
|
9404
|
+
scalars[field] = val;
|
|
9405
|
+
}
|
|
9406
|
+
});
|
|
9407
|
+
return { segments, label: formatIdentityLabel(scalars) };
|
|
9408
|
+
};
|
|
9409
|
+
// fill each row's identity segments + text label, dropping the noisy method fields unless they are the
|
|
9410
|
+
// only thing telling rows apart (a methodModel that distinguishes the rows is then shown as a link)
|
|
9411
|
+
const withRowLabels = (group) => {
|
|
9412
|
+
const keepNoisy = !noisyFieldsRedundant(group.rows);
|
|
9413
|
+
return {
|
|
9414
|
+
...group,
|
|
9415
|
+
rows: group.rows.map(row => {
|
|
9416
|
+
const displayIdentity = keepNoisy ? row.identity : identityWithout(row.identity, isNoisyIdentityField);
|
|
9417
|
+
const { segments, label } = identityDisplay(displayIdentity, row.recalculated[0] || row.original[0]);
|
|
9418
|
+
return { ...row, identitySegments: segments, identityLabel: label };
|
|
9419
|
+
})
|
|
9420
|
+
};
|
|
9421
|
+
};
|
|
9422
|
+
const emptySubRow = () => ({
|
|
9423
|
+
index: 0,
|
|
9424
|
+
identity: {},
|
|
9425
|
+
identityLabel: '',
|
|
9426
|
+
identitySegments: [],
|
|
9427
|
+
originalValue: null,
|
|
9428
|
+
isOriginal: false,
|
|
9429
|
+
isRequired: true,
|
|
9430
|
+
isFailed: false,
|
|
9431
|
+
original: [],
|
|
9432
|
+
recalculated: [],
|
|
9433
|
+
subRows: [],
|
|
9434
|
+
canOpen: false,
|
|
9435
|
+
isOpen: false
|
|
9436
|
+
});
|
|
9437
|
+
const scalarValue = (value) => (['string', 'number', 'boolean'].includes(typeof value) ? value : null);
|
|
9438
|
+
/**
|
|
9439
|
+
* A scalar field of a blank node (e.g. `impactAssessment`, `price`, `economicValueShare`), shown as a
|
|
9440
|
+
* "Field: <key>" sub-row with the model(s) that gap-filled it.
|
|
9441
|
+
*/
|
|
9442
|
+
const fieldSubRow = (key, nested, value, originalValue, nodeType, type) => {
|
|
9443
|
+
const updated = [...(value?.added || []), ...(value?.updated || [])];
|
|
9444
|
+
return {
|
|
9445
|
+
...emptySubRow(),
|
|
9446
|
+
key,
|
|
9447
|
+
termId: key,
|
|
9448
|
+
type,
|
|
9449
|
+
originalValue: scalarValue(originalValue?.[key]),
|
|
9450
|
+
recalculatedValue: scalarValue(value?.[key]),
|
|
9451
|
+
isOriginal: typeof originalValue?.[key] !== 'undefined',
|
|
9452
|
+
isRecalculated: updated.includes(key),
|
|
9453
|
+
models: jLogModelRuns(nested?.logs, nodeType, key, false)
|
|
9454
|
+
};
|
|
9455
|
+
};
|
|
9456
|
+
// the model runs for a property: its logs usually live under the `value` field (`properties[i].value.logs`)
|
|
9457
|
+
const propertyModels = (childEntry, child, nodeType, termId) => {
|
|
9458
|
+
const valueFieldLogs = childEntry?.value?.logs;
|
|
9459
|
+
const rawModels = jLogModelRuns(valueFieldLogs || childEntry?.logs, nodeType, termId, false);
|
|
9460
|
+
// the `input.properties` model loads each property (with fallbacks), so it set the value: a
|
|
9461
|
+
// `should_run: false` on the value field is not a failure - the property was added, so it succeeded
|
|
9462
|
+
const logModels = valueFieldLogs
|
|
9463
|
+
? rawModels.map(model => (model.status === LogStatus.error ? { ...model, status: LogStatus.success } : model))
|
|
9464
|
+
: rawModels;
|
|
9465
|
+
// when no model is logged, fall back to the model recorded on the property (its `methodModel`)
|
|
9466
|
+
const valueModelId = blankNodeModelId(child);
|
|
9467
|
+
return logModels.length || !valueModelId
|
|
9468
|
+
? logModels
|
|
9469
|
+
: [syntheticModelRun(valueModelId, LogStatus.success, nodeType, termId)];
|
|
9470
|
+
};
|
|
9471
|
+
/**
|
|
9472
|
+
* Index-keyed nested blank nodes (e.g. `properties`), each mapped to its term and shown as a sub-row.
|
|
9473
|
+
*/
|
|
9474
|
+
const nestedBlankNodeSubRows = (key, nested, value, nodeType) => Object.entries(nested || {})
|
|
9475
|
+
.map(([index, childEntry]) => {
|
|
9476
|
+
const child = value?.[key]?.[+index];
|
|
9477
|
+
const term = child?.term;
|
|
9478
|
+
if (!term?.['@id'])
|
|
9479
|
+
return null;
|
|
9480
|
+
const termId = term['@id'];
|
|
9481
|
+
return {
|
|
9482
|
+
...emptySubRow(),
|
|
9483
|
+
index: +index,
|
|
9484
|
+
key: 'property',
|
|
9485
|
+
term,
|
|
9486
|
+
termId,
|
|
9487
|
+
type: SchemaType.Property,
|
|
9488
|
+
recalculatedValue: propertyValue$1(child?.value, termId),
|
|
9489
|
+
isRecalculated: true,
|
|
9490
|
+
recalculated: child ? [child] : [],
|
|
9491
|
+
models: propertyModels(childEntry, child, nodeType, termId)
|
|
9492
|
+
};
|
|
9493
|
+
})
|
|
9494
|
+
.filter(Boolean);
|
|
9495
|
+
const defaultGetTerm = (id) => ({ '@type': NodeType.Term, '@id': id, name: id });
|
|
9496
|
+
// a blank node's `<field>-failed` entries (e.g. an animal's `properties-failed`/`inputs-failed`): the
|
|
9497
|
+
// properties/inputs no model could add, shown as failed sub-rows keyed by term (resolved via `getTerm`)
|
|
9498
|
+
const failedNestedSubRows = (key, nested, nodeType, getTerm) => {
|
|
9499
|
+
const subKey = pluralize(key.replace(failedFieldSuffix, ''), 1);
|
|
9500
|
+
return Object.entries(nested || {}).map(([termId, childEntry]) => ({
|
|
9501
|
+
...emptySubRow(),
|
|
9502
|
+
key: subKey,
|
|
9503
|
+
term: getTerm(termId),
|
|
9504
|
+
termId,
|
|
9505
|
+
type: subKey === 'property' ? SchemaType.Property : undefined,
|
|
9506
|
+
isFailed: true,
|
|
9507
|
+
models: jLogModelRuns(childEntry?.logs, nodeType, termId, true)
|
|
9508
|
+
}));
|
|
9509
|
+
};
|
|
9510
|
+
/**
|
|
9511
|
+
* The keys (property term ids and scalar field names) that have their own sub-row; the matching
|
|
9512
|
+
* orchestrator entries in `logs` are shown there, not as a model on the main row.
|
|
9513
|
+
*/
|
|
9514
|
+
const subRowOrchestratorValues = (entry, value) => [
|
|
9515
|
+
...Object.keys(entry?.properties || {})
|
|
9516
|
+
.map(index => value?.properties?.[+index]?.term?.['@id'])
|
|
9517
|
+
.filter(Boolean),
|
|
9518
|
+
...Object.keys(entry || {}).filter(key => key !== 'logs' && Array.isArray(entry[key]?.logs))
|
|
9519
|
+
];
|
|
9520
|
+
const isSubRowOrchestrator = (orchestratorValue, subRowValues) => !!orchestratorValue && (orchestratorValue.includes('.') || subRowValues.includes(orchestratorValue));
|
|
9521
|
+
// node keys for which the orchestrator config also lists models that could run (mirrors the legacy)
|
|
9522
|
+
const configModelKeys = ['measurements', 'practices', 'emissions', 'impacts'];
|
|
9523
|
+
const configModelMatches = (termId, nodeKey) => (model) => model.value === termId && pluralize(model.key, 2) === nodeKey;
|
|
9524
|
+
/**
|
|
9525
|
+
* The models the orchestrator config lists for a term (in config order), so models that could run after
|
|
9526
|
+
* a successful one are still shown.
|
|
9527
|
+
*/
|
|
9528
|
+
const configModelsForTerm = (config, termId, nodeKey) => (config?.models || [])
|
|
9529
|
+
.flat(2)
|
|
9530
|
+
.filter(configModelMatches(termId, nodeKey))
|
|
9531
|
+
.map(model => model.model);
|
|
9532
|
+
/**
|
|
9533
|
+
* Models within the same orchestrator-config array run in parallel: each produces its own blank node, so
|
|
9534
|
+
* they are not fallbacks for one another and should not all be listed on every row (each row keeps only
|
|
9535
|
+
* the model that produced it). True when the term's config models all sit in a single parallel array.
|
|
9536
|
+
*/
|
|
9537
|
+
const configModelsParallel = (config, termId, nodeKey) => {
|
|
9538
|
+
const matches = configModelMatches(termId, nodeKey);
|
|
9539
|
+
const groups = (config?.models || []).filter(group => (Array.isArray(group) ? group : [group]).some(matches));
|
|
9540
|
+
return groups.length === 1 && Array.isArray(groups[0]) && groups[0].filter(matches).length > 1;
|
|
9541
|
+
};
|
|
9542
|
+
const syntheticModelRun = (methodId, status, nodeType, termId) => ({ methodId, status, logs: {}, showLogs: false, model: resolveModel(nodeType, termId, methodId) });
|
|
9543
|
+
/**
|
|
9544
|
+
* The status of a config model that has no log: it succeeded if it set the value, was skipped if the
|
|
9545
|
+
* value was recalculated (by another model), provided when it came from the original, otherwise failed.
|
|
9546
|
+
*/
|
|
9547
|
+
const configModelStatus = (methodId, valueModelId, isRecalculated, hasOriginal) => methodId === valueModelId
|
|
9548
|
+
? LogStatus.success
|
|
9549
|
+
: isRecalculated
|
|
9550
|
+
? LogStatus.skipHierarchy
|
|
9551
|
+
: hasOriginal
|
|
9552
|
+
? LogStatus.dataProvided
|
|
9553
|
+
: LogStatus.error;
|
|
9554
|
+
// the `logs` entry that targets the value: the recorded model when present, otherwise (the value was
|
|
9555
|
+
// recalculated but the recorded model isn't in the logs - e.g. `hestiaAggregatedData` is computed by the
|
|
9556
|
+
// `linkedImpactAssessment` orchestrator) the first run that actually set the value
|
|
9557
|
+
const selectValueLog = (logs, valueModelId, isValueLog, isRecalculated) => logs.find((log) => log?.model === valueModelId && isValueLog(log)) ||
|
|
9558
|
+
(isRecalculated
|
|
9559
|
+
? logs.find((log) => isValueLog(log) && (log?.should_run === true || log?.orchestrator?.should_run))
|
|
9560
|
+
: undefined);
|
|
9561
|
+
// model ids in display order: config models first, then any logged models, with "not relevant" models
|
|
9562
|
+
// (the actual outcome) pulled to the front
|
|
9563
|
+
const orderValueModelIds = (configModelIds, logModels) => [...new Set([...configModelIds, ...logModels.map(model => model.methodId)])].sort((a, b) => Number(isNotRelevantModel(b)) - Number(isNotRelevantModel(a)));
|
|
9564
|
+
// apply `update` to the model that set the value (matched by id) when `condition` holds, leaving the rest
|
|
9565
|
+
const mapValueModel = (models, valueModelId, condition, update) => models.map(model => (model.methodId === valueModelId && condition(model) ? update(model) : model));
|
|
9566
|
+
/**
|
|
9567
|
+
* A blank node's direct (value) model runs, in hierarchy order:
|
|
9568
|
+
* - the model that set the value is recorded on the recalculated blank node (`blankNodeModelId`);
|
|
9569
|
+
* - its matching `logs` entry (one targeting the value, not a sub-row) provides the run requirements,
|
|
9570
|
+
* together with any other model sharing that orchestrator value;
|
|
9571
|
+
* - for measurements/practices/emissions/impacts, the orchestrator config adds the models that could
|
|
9572
|
+
* run - the one that ran is successful, the others were skipped (a higher-tier model ran instead).
|
|
9573
|
+
*
|
|
9574
|
+
* When the value came from the original (no model, no config), the row shows no model.
|
|
9575
|
+
*/
|
|
9576
|
+
// eslint-disable-next-line complexity -- orchestrates the value-model resolution (delegated to helpers)
|
|
9577
|
+
const valueModelRuns = (entry, value, originalValue, nodeType, termId, nodeKey, config) => {
|
|
9578
|
+
const valueModelId = blankNodeModelId(value);
|
|
9579
|
+
const isRecalculated = isRecalculatedValue(value, originalValue);
|
|
9580
|
+
const hasOriginal = !!originalValue && typeof originalValue.value !== 'undefined';
|
|
9581
|
+
const valueFromOriginal = valueRetainedFromOriginal(value, originalValue);
|
|
9582
|
+
const subRowValues = subRowOrchestratorValues(entry, value);
|
|
9583
|
+
const logs = (entry?.logs || []).flat();
|
|
9584
|
+
// background-tier logs belong to an input's "Background Data" sub-row - unless the blank node is itself
|
|
9585
|
+
// a background emission, in which case its value model IS the background run (e.g. `bafu2025`)
|
|
9586
|
+
const valueIsBackground = value?.methodTier === EmissionMethodTier.background;
|
|
9587
|
+
const isBackgroundLog = (log) => !valueIsBackground && log?.methodTier === EmissionMethodTier.background;
|
|
9588
|
+
const isValueLog = (log) => !isBackgroundLog(log) && !isSubRowOrchestrator(log?.orchestrator?.value, subRowValues);
|
|
9589
|
+
const valueLog = selectValueLog(logs, valueModelId, isValueLog, isRecalculated);
|
|
9590
|
+
const valueOrchestrator = valueLog?.orchestrator?.value;
|
|
9591
|
+
const rawLogModels = valueLog
|
|
9592
|
+
? jLogModelRuns(logs.filter((log) => log?.orchestrator?.value === valueOrchestrator && !isBackgroundLog(log)), nodeType, termId, false)
|
|
9593
|
+
: [];
|
|
9594
|
+
// the recorded value model (the blank node `methodModel`, e.g. `hestiaAggregatedData`) can differ from
|
|
9595
|
+
// the single orchestrator model in the logs (e.g. `linkedImpactAssessment`); relabel that run to the
|
|
9596
|
+
// recorded model so it shows under the expected name, but keep the orchestrator run's logs and its
|
|
9597
|
+
// resolved guide link (the recorded model - an aggregation source - has no model link of its own)
|
|
9598
|
+
const logModels = valueModelId && rawLogModels.length === 1 && rawLogModels[0].methodId !== valueModelId
|
|
9599
|
+
? [{ ...rawLogModels[0], methodId: valueModelId }]
|
|
9600
|
+
: rawLogModels;
|
|
9601
|
+
// parallel config models each produce their own blank node, so they are not listed together on a row
|
|
9602
|
+
const configModelIds = config && configModelKeys.includes(nodeKey) && !configModelsParallel(config, termId, nodeKey)
|
|
9603
|
+
? configModelsForTerm(config, termId, nodeKey)
|
|
9604
|
+
: [];
|
|
9605
|
+
const logByMethodId = new Map(logModels.map(model => [model.methodId, model]));
|
|
9606
|
+
const models = orderValueModelIds(configModelIds, logModels).map(methodId => logByMethodId.get(methodId) ||
|
|
9607
|
+
syntheticModelRun(methodId, configModelStatus(methodId, valueModelId, isRecalculated, hasOriginal), nodeType, termId));
|
|
9608
|
+
// the value model (e.g. a measured method gap-filled this run) is not always in the logs or config
|
|
9609
|
+
const baseModels = models.length || !valueModelId || valueFromOriginal
|
|
9610
|
+
? models
|
|
9611
|
+
: [syntheticModelRun(valueModelId, LogStatus.success, nodeType, termId)];
|
|
9612
|
+
// the model recorded on the node set the value this run, so it ran successfully - even when its log
|
|
9613
|
+
// omits `should_run` (e.g. the `seed_emissions` orchestrator), which falls through to "data retained"
|
|
9614
|
+
const withSuccess = mapValueModel(baseModels, valueModelId, model => isRecalculated && !valueFromOriginal && model.status === LogStatus.dataProvided, model => ({ ...model, status: LogStatus.success }));
|
|
9615
|
+
// the value model carries the blank node's method tier (e.g. an emission tier) even when its log omits
|
|
9616
|
+
// it, so it shows next to the model name like the other tier emissions
|
|
9617
|
+
const valueMethodTier = value?.methodTier;
|
|
9618
|
+
return mapValueModel(withSuccess, valueModelId, model => !!valueMethodTier && !model.logs?.methodTier, model => ({ ...model, logs: { ...(model.logs || {}), methodTier: valueMethodTier } }));
|
|
9619
|
+
};
|
|
9620
|
+
/**
|
|
9621
|
+
* Build a sub-row for every nested key of a blank node entry (all keys except `logs`): scalar fields
|
|
9622
|
+
* become "Field: <key>" rows; index-keyed nested blank nodes (e.g. `properties`) become term sub-rows.
|
|
9623
|
+
* Field sub-rows are listed before property sub-rows.
|
|
9624
|
+
*/
|
|
9625
|
+
const isFieldEntry = ([, nested]) => Array.isArray(nested?.logs);
|
|
9626
|
+
const isPropertyEntry = ([, nested]) => !Array.isArray(nested?.logs) && nested && typeof nested === 'object';
|
|
9627
|
+
const isFailedFieldEntry = ([key]) => key.endsWith(failedFieldSuffix);
|
|
9628
|
+
const blankNodeSubRows = (entry, value, originalValue, nodeType, type, getTerm) => {
|
|
9629
|
+
// a scalar field (with its own `logs`) becomes a "Field:" sub-row; an index-keyed nested node (e.g.
|
|
9630
|
+
// `properties`) expands into "Property:" sub-rows; `<field>-failed` entries become failed sub-rows.
|
|
9631
|
+
const entries = Object.entries(entry || {}).filter(([key]) => key !== 'logs');
|
|
9632
|
+
const fields = entries
|
|
9633
|
+
.filter(entryItem => !isFailedFieldEntry(entryItem) && isFieldEntry(entryItem))
|
|
9634
|
+
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, type));
|
|
9635
|
+
const properties = entries
|
|
9636
|
+
.filter(entryItem => !isFailedFieldEntry(entryItem) && isPropertyEntry(entryItem))
|
|
9637
|
+
.flatMap(([key, nested]) => nestedBlankNodeSubRows(key, nested, value, nodeType));
|
|
9638
|
+
const failed = entries
|
|
9639
|
+
.filter(isFailedFieldEntry)
|
|
9640
|
+
.flatMap(([key, nested]) => failedNestedSubRows(key, nested, nodeType, getTerm));
|
|
9641
|
+
return [...fields, ...properties, ...failed];
|
|
9642
|
+
};
|
|
9643
|
+
/**
|
|
9644
|
+
* An input's background-emission models (`methodTier: background`), grouped under a single
|
|
9645
|
+
* "Background Data" sub-row.
|
|
9646
|
+
*/
|
|
9647
|
+
const backgroundDataSubRow = (inputEntries, nodeType, termId) => {
|
|
9648
|
+
const backgroundEntries = inputEntries.filter(log => log?.methodTier === EmissionMethodTier.background);
|
|
9649
|
+
return backgroundEntries.length
|
|
9650
|
+
? {
|
|
9651
|
+
...emptySubRow(),
|
|
9652
|
+
key: 'backgroundData',
|
|
9653
|
+
termId: 'backgroundData',
|
|
9654
|
+
recalculatedValue: null,
|
|
9655
|
+
isRecalculated: false,
|
|
9656
|
+
models: jLogModelRuns(backgroundEntries, nodeType, termId, false)
|
|
9657
|
+
}
|
|
9658
|
+
: null;
|
|
9659
|
+
};
|
|
9660
|
+
// the value was set/changed this run (listed in `added`/`updated`)
|
|
9661
|
+
const valueChanged = (value) => [...(value?.added || []), ...(value?.updated || [])].includes('value');
|
|
9662
|
+
// a value present in the original and not changed this run was retained (even if it keeps a `methodModel`,
|
|
9663
|
+
// e.g. a measured emission method) - it was not recalculated
|
|
9664
|
+
const valueRetainedFromOriginal = (value, originalValue) => !!originalValue && typeof originalValue.value !== 'undefined' && !valueChanged(value);
|
|
9665
|
+
const isRecalculatedValue = (value, originalValue) => valueChanged(value) || (!!blankNodeModelId(value) && !valueRetainedFromOriginal(value, originalValue));
|
|
9666
|
+
// every sub-row of a (non-failed) blank node: its field/property sub-rows, plus - for an input - the
|
|
9667
|
+
// "Background Data" sub-row holding its background-emission models
|
|
9668
|
+
const allSubRows = (entry, value, originalValue, nodeType, type, termId, getTerm) => {
|
|
9669
|
+
const isInput = type === SchemaType.Input;
|
|
9670
|
+
const inputEntries = isInput ? (entry?.logs || []).flat().filter((e) => !!e?.model) : [];
|
|
9671
|
+
const backgroundData = isInput ? backgroundDataSubRow(inputEntries, nodeType, termId) : null;
|
|
9672
|
+
return [
|
|
9673
|
+
...blankNodeSubRows(entry, value, originalValue, nodeType, type, getTerm),
|
|
9674
|
+
...(backgroundData ? [backgroundData] : [])
|
|
9675
|
+
];
|
|
9676
|
+
};
|
|
9677
|
+
const flattenColumns = (columns) => columns.flatMap(column => (Array.isArray(column) ? column : [column]));
|
|
9678
|
+
// a `<key>-failed` entry has no value: its identity/sub-rows are empty and the models that tried are
|
|
9679
|
+
// errors; parallel models (a nested `logs` array) are kept grouped (`modelColumns`) so they stack in one
|
|
9680
|
+
// column, while `models` stays flat for the status checks
|
|
9681
|
+
const failedBlankNodeContent = (entry, nodeType, termId) => {
|
|
9682
|
+
const columns = jLogModelColumns(entry?.logs, nodeType, termId, true);
|
|
9683
|
+
return {
|
|
9684
|
+
recalculatedValue: null,
|
|
9685
|
+
identity: {},
|
|
9686
|
+
identityLabel: '',
|
|
9687
|
+
identitySegments: [],
|
|
9688
|
+
subRows: [],
|
|
9689
|
+
isRecalculated: false,
|
|
9690
|
+
recalculated: [],
|
|
9691
|
+
models: flattenColumns(columns),
|
|
9692
|
+
modelColumns: columns
|
|
9693
|
+
};
|
|
9694
|
+
};
|
|
9695
|
+
// a regular blank node: its identity, sub-rows and the model(s) that set the value (or none when retained)
|
|
9696
|
+
const valueBlankNodeContent = (entry, value, originalValue, termId, { nodeType, type, nodeKey, config, getTerm }) => {
|
|
9697
|
+
const spec = identitySpec(type, nodeType, nodeKey);
|
|
9698
|
+
return {
|
|
9699
|
+
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9700
|
+
identity: blankNodeIdentity(value, spec),
|
|
9701
|
+
// `identityLabel`/`identitySegments` are filled per group (`withRowLabels`), which needs all rows
|
|
9702
|
+
identityLabel: '',
|
|
9703
|
+
identitySegments: [],
|
|
9704
|
+
subRows: allSubRows(entry, value, originalValue, nodeType, type, termId, getTerm || defaultGetTerm),
|
|
9705
|
+
isRecalculated: isRecalculatedValue(value, originalValue),
|
|
9706
|
+
recalculated: value ? [value] : [],
|
|
9707
|
+
models: valueModelRuns(entry, value, originalValue, nodeType, termId, nodeKey, config)
|
|
9708
|
+
};
|
|
9709
|
+
};
|
|
9710
|
+
const buildBlankNode = (entry, value, originalValue, index, term, isFailed, context) => {
|
|
9711
|
+
const termId = term['@id'];
|
|
9712
|
+
return {
|
|
9713
|
+
index,
|
|
9714
|
+
term,
|
|
9715
|
+
termId,
|
|
9716
|
+
type: context.type,
|
|
9717
|
+
originalValue: originalValue ? propertyValue$1(originalValue.value, termId) : null,
|
|
9718
|
+
isOriginal: !!originalValue && typeof originalValue.value !== 'undefined',
|
|
9719
|
+
isRequired: !isFailed,
|
|
9720
|
+
isFailed,
|
|
9721
|
+
original: originalValue ? [originalValue] : [],
|
|
9722
|
+
canOpen: false,
|
|
9723
|
+
isOpen: false,
|
|
9724
|
+
...(isFailed
|
|
9725
|
+
? failedBlankNodeContent(entry, context.nodeType, termId)
|
|
9726
|
+
: valueBlankNodeContent(entry, value, originalValue, termId, context))
|
|
9727
|
+
};
|
|
9728
|
+
};
|
|
9729
|
+
/**
|
|
9730
|
+
* Group the `.jlog` logs for one node key into rows, one per term, keeping every blank node distinct.
|
|
9731
|
+
*
|
|
9732
|
+
* @param jlog The full parsed `.jlog`.
|
|
9733
|
+
* @param nodeKey The node field being shown (e.g. `inputs`, `measurements`).
|
|
9734
|
+
* @param recalculatedValues The recalculated blank nodes for that key (index-aligned with the `.jlog`).
|
|
9735
|
+
* @param originalValues The original blank nodes for that key (matched by uniqueness for the delta).
|
|
9736
|
+
* @param nodeType The node type.
|
|
9737
|
+
* @param getTerm Resolve a term by `@id` (used for `<key>-failed` entries that have no blank node).
|
|
9738
|
+
* @param config The orchestrator config, used to list models that could run for a term.
|
|
9739
|
+
*/
|
|
9740
|
+
// eslint-disable-next-line complexity -- builds the type/term context then delegates to helpers
|
|
9741
|
+
const groupJLogByTerm = (jlog, nodeKey, recalculatedValues = [], originalValues = [], nodeType = undefined, getTerm = id => ({ '@type': NodeType.Term, '@id': id, name: id }), config) => {
|
|
9742
|
+
const keyLogs = jlog?.[nodeKey] || {};
|
|
9743
|
+
const failedLogs = jlog?.[`${nodeKey}${failedFieldSuffix}`] || {};
|
|
9744
|
+
const type = recalculatedValues?.[0]?.['@type'] ||
|
|
9745
|
+
recalculatedValues?.[0]?.type ||
|
|
9746
|
+
originalValues?.[0]?.['@type'];
|
|
9747
|
+
const context = { nodeType, type, nodeKey, config, getTerm };
|
|
9748
|
+
const spec = identitySpec(type, nodeType, nodeKey);
|
|
9749
|
+
const matchOriginal = (value) => {
|
|
9750
|
+
const key = identityKey(blankNodeIdentity(value, spec));
|
|
9751
|
+
return (originalValues || []).find(original => original.term?.['@id'] === value.term?.['@id'] && identityKey(blankNodeIdentity(original, spec)) === key);
|
|
9752
|
+
};
|
|
9753
|
+
const blankNodes = [
|
|
9754
|
+
// list every blank node, attaching its `.jlog` logs when present (a node may exist without logs,
|
|
9755
|
+
// e.g. a value provided in the original)
|
|
9756
|
+
...(recalculatedValues || []).map((value, index) => {
|
|
9757
|
+
const term = value?.term;
|
|
9758
|
+
return term?.['@id']
|
|
9759
|
+
? buildBlankNode(keyLogs[index] || {}, value, matchOriginal(value), index, term, false, context)
|
|
9760
|
+
: null;
|
|
9761
|
+
}),
|
|
9762
|
+
...Object.entries(failedLogs).map(([termId, entry], i) => buildBlankNode(entry, undefined, undefined, -1 - i, getTerm(termId), true, context))
|
|
9763
|
+
].filter(Boolean);
|
|
9764
|
+
return orderGroups(groupBlankNodesByTerm(blankNodes)
|
|
9765
|
+
.map(withCollapsible)
|
|
9766
|
+
.map(withRowLabels), nodeKey);
|
|
9767
|
+
};
|
|
9768
|
+
// group blank nodes by their term id, preserving first-seen order
|
|
9769
|
+
const groupBlankNodesByTerm = (blankNodes) => blankNodes.reduce((groups, blankNode) => {
|
|
9770
|
+
const group = groups.find(g => g.termId === blankNode.termId);
|
|
9771
|
+
if (group) {
|
|
9772
|
+
group.rows.push(blankNode);
|
|
9773
|
+
return groups;
|
|
9774
|
+
}
|
|
9775
|
+
const { term, termId, type } = blankNode;
|
|
9776
|
+
return [
|
|
9777
|
+
...groups,
|
|
9778
|
+
{ term, termId, type, rows: [blankNode], originalValue: null, recalculatedValue: null, canOpen: false, isOpen: false }
|
|
9779
|
+
];
|
|
9780
|
+
}, []);
|
|
9781
|
+
// combine (sum) the `value` of several blank nodes into one (mirrors the legacy `reduceValues`)
|
|
9782
|
+
const reduceValues = (values, termId) => {
|
|
9783
|
+
const propertyValues = values.map(({ value }) => propertyValue$1(value, termId)).filter(v => v !== null);
|
|
9784
|
+
return propertyValues.length ? propertyValue$1(propertyValues, termId) : null;
|
|
9785
|
+
};
|
|
9786
|
+
// a group with several blank nodes (or with nested sub-rows) is collapsible, as are its rows with sub-rows;
|
|
9787
|
+
// its header shows the combined value across all rows
|
|
9788
|
+
const withCollapsible = (group) => ({
|
|
9789
|
+
...group,
|
|
9790
|
+
canOpen: group.rows.length > 1 || group.rows.some(row => row.subRows.length > 0),
|
|
9791
|
+
rows: group.rows.map(row => ({ ...row, canOpen: row.subRows.length > 0 })),
|
|
9792
|
+
originalValue: reduceValues(group.rows.flatMap(row => row.original), group.termId),
|
|
9793
|
+
recalculatedValue: reduceValues(group.rows.flatMap(row => row.recalculated), group.termId)
|
|
9794
|
+
});
|
|
9795
|
+
const groupName = (group) => group.term?.name || group.termId;
|
|
9796
|
+
const groupMethodTier = (group) => methodTierOrder(group.rows[0]?.recalculated?.[0]?.methodTier);
|
|
9797
|
+
// emissions are ordered by method tier (like the legacy component), everything else by term name
|
|
9798
|
+
const orderGroups = (groups, nodeKey) => nodeKey === 'emissions'
|
|
9799
|
+
? orderBy(groups, [groupMethodTier, groupName], ['asc', 'asc'])
|
|
9800
|
+
: orderBy(groups, [groupName], ['asc']);
|
|
9801
|
+
/**
|
|
9802
|
+
* Group the `.jlog` logs for a metadata or completeness node (a `key -> value` map, not blank nodes).
|
|
9803
|
+
*
|
|
9804
|
+
* Each key is one row: the model logs come from the field's own `.jlog` entry (e.g. `startDate`), or
|
|
9805
|
+
* from the shared node-key entry for completeness (`completeness`). Values come from the `key -> value`
|
|
9806
|
+
* original/recalculated maps.
|
|
9807
|
+
*
|
|
9808
|
+
* @param jlog The full parsed `.jlog`.
|
|
9809
|
+
* @param nodeKey The node field being shown (`completeness`, or empty for cycle metadata).
|
|
9810
|
+
* @param originalValues The original `key -> value` map.
|
|
9811
|
+
* @param recalculatedValues The recalculated `key -> value` map.
|
|
9812
|
+
* @param nodeType The node type.
|
|
9813
|
+
*/
|
|
9814
|
+
const groupJLogByField = (jlog, nodeKey, originalValues, recalculatedValues, nodeType = undefined) => {
|
|
9815
|
+
const updated = [
|
|
9816
|
+
...(recalculatedValues?.added || []),
|
|
9817
|
+
...(recalculatedValues?.updated || [])
|
|
9818
|
+
];
|
|
9819
|
+
// eslint-disable-next-line complexity -- maps each field key to a fully-populated row
|
|
9820
|
+
return computeKeys(originalValues, recalculatedValues).map(key => {
|
|
9821
|
+
// for a node-key field map (e.g. `completeness`) the per-field logs are nested under
|
|
9822
|
+
// `jlog[nodeKey][key]`; the node-key's own top-level `logs` are ignored. metadata fields are top-level
|
|
9823
|
+
const entry = nodeKey ? jlog?.[nodeKey]?.[key] : jlog?.[key];
|
|
9824
|
+
const originalValue = originalValues?.[key];
|
|
9825
|
+
const recalculatedValue = recalculatedValues?.[key];
|
|
9826
|
+
const row = {
|
|
9827
|
+
index: 0,
|
|
9828
|
+
termId: key,
|
|
9829
|
+
key,
|
|
9830
|
+
identity: {},
|
|
9831
|
+
identityLabel: '',
|
|
9832
|
+
identitySegments: [],
|
|
9833
|
+
originalValue: originalValue ?? null,
|
|
9834
|
+
recalculatedValue: recalculatedValue ?? null,
|
|
9835
|
+
isOriginal: typeof originalValue !== 'undefined',
|
|
9836
|
+
isRecalculated: updated.includes(key) || (recalculatedValue !== undefined && recalculatedValue !== originalValue),
|
|
9837
|
+
isRequired: true,
|
|
9838
|
+
isFailed: false,
|
|
9839
|
+
original: [],
|
|
9840
|
+
recalculated: [],
|
|
9841
|
+
models: jLogModelRuns(entry?.logs, nodeType, key, false),
|
|
9842
|
+
subRows: [],
|
|
9843
|
+
canOpen: false,
|
|
9844
|
+
isOpen: false
|
|
9845
|
+
};
|
|
9846
|
+
return {
|
|
9847
|
+
termId: key,
|
|
9848
|
+
key,
|
|
9849
|
+
rows: [row],
|
|
9850
|
+
originalValue: null,
|
|
9851
|
+
recalculatedValue: null,
|
|
9852
|
+
canOpen: false,
|
|
9853
|
+
isOpen: false
|
|
9854
|
+
};
|
|
9855
|
+
});
|
|
9856
|
+
};
|
|
9857
|
+
// the number of "Model N" columns a row needs (a parallel group counts as one column)
|
|
9858
|
+
const rowColumnCount = (row) => (row.modelColumns ?? row.models).length;
|
|
9859
|
+
/**
|
|
9860
|
+
* The maximum number of model columns across all rows, to size the "Model N" columns.
|
|
9861
|
+
*/
|
|
9862
|
+
const jLogModelCount = (groups) => Math.max(0, ...groups.flatMap(group => group.rows.flatMap(row => [rowColumnCount(row), ...row.subRows.map(rowColumnCount)])));
|
|
9863
|
+
|
|
9864
|
+
const groupTerms$1 = (terms) => terms.reduce((prev, curr) => ({ ...prev, [curr['@id']]: curr }), {});
|
|
9865
|
+
const logIcon$1 = {
|
|
9866
|
+
[LogStatus.success]: 'checkmark',
|
|
9867
|
+
[LogStatus.error]: 'xmark',
|
|
9868
|
+
[LogStatus.skipHierarchy]: 'circle',
|
|
9869
|
+
[LogStatus.dataProvided]: 'dot-filled',
|
|
9870
|
+
[LogStatus.notRequired]: 'dot-circle'
|
|
9871
|
+
};
|
|
9872
|
+
const logColor$1 = {
|
|
9873
|
+
[LogStatus.success]: 'success',
|
|
9874
|
+
[LogStatus.error]: 'danger',
|
|
9875
|
+
[LogStatus.skipHierarchy]: 'dark',
|
|
9876
|
+
[LogStatus.dataProvided]: 'dark',
|
|
9877
|
+
[LogStatus.notRequired]: 'grey'
|
|
9878
|
+
};
|
|
9879
|
+
const methodIdLabel$1 = (methodId) => (methodId
|
|
9880
|
+
? { 'cycle/transformation': 'Data From Transformation', impact_assessment: 'Data From Cycle' }[methodId]
|
|
9881
|
+
: '') || (methodId.includes('/') ? methodId.split('/')[0] : keyToLabel(methodId));
|
|
9882
|
+
// some runs are better described by the orchestrator value (model key) than by the model id (e.g. `cycle`)
|
|
9883
|
+
const modelKeyLabel = {
|
|
9884
|
+
'input.hestiaAggregatedData': 'HESTIA aggregated data'
|
|
9885
|
+
};
|
|
9886
|
+
const termSearch$1 = (term = '') => term.replace(/[,\s]/g, '').toLowerCase();
|
|
9887
|
+
class NodeJLogModelsComponent {
|
|
9888
|
+
constructor() {
|
|
9889
|
+
this.searchService = inject(HeSearchService);
|
|
9890
|
+
this.engineService = inject(HeEngineService);
|
|
9891
|
+
this.guideEnabled = inject(GUIDE_ENABLED);
|
|
9892
|
+
this.node = input.required(...(ngDevMode ? [{ debugName: "node" }] : []));
|
|
9893
|
+
this.nodeKey = input(...(ngDevMode ? [undefined, { debugName: "nodeKey" }] : []));
|
|
9894
|
+
this.originalValues = input([], ...(ngDevMode ? [{ debugName: "originalValues" }] : []));
|
|
9895
|
+
this.recalculatedValues = input([], ...(ngDevMode ? [{ debugName: "recalculatedValues" }] : []));
|
|
9896
|
+
this.filterTermTypes = input([], ...(ngDevMode ? [{ debugName: "filterTermTypes" }] : []));
|
|
9897
|
+
// a single label for the filtered term types (e.g. "Management"), shown instead of joining them all
|
|
9898
|
+
this.filterTermTypesLabel = input('', ...(ngDevMode ? [{ debugName: "filterTermTypesLabel" }] : []));
|
|
9899
|
+
this.cycle = input(...(ngDevMode ? [undefined, { debugName: "cycle" }] : []));
|
|
9900
|
+
this.jlog = input({}, ...(ngDevMode ? [{ debugName: "jlog" }] : []));
|
|
9901
|
+
// for a grouped sub-node view (e.g. an animal's inputs), the `.jlog` is nested under its parent: scope
|
|
9902
|
+
// to `jlog[<parentKey>][<parentIndex>]` (e.g. `jlog.animals.0`) so `nodeKey` reads the right section
|
|
9903
|
+
this.jlogParentKey = input(...(ngDevMode ? [undefined, { debugName: "jlogParentKey" }] : []));
|
|
9904
|
+
this.jlogParentIndex = input(...(ngDevMode ? [undefined, { debugName: "jlogParentIndex" }] : []));
|
|
9905
|
+
// the `.jlog` section the rows are read from - the whole jlog, or the parent-scoped sub-node entry
|
|
9906
|
+
this.scopedJlog = computed(() => {
|
|
9907
|
+
const key = this.jlogParentKey();
|
|
9908
|
+
const index = this.jlogParentIndex();
|
|
9909
|
+
return key && typeof index === 'number' && index >= 0 ? (this.jlog()?.[key]?.[index] ?? {}) : this.jlog();
|
|
9910
|
+
}, ...(ngDevMode ? [{ debugName: "scopedJlog" }] : []));
|
|
9911
|
+
this.schemaBaseUrl = schemaBaseUrl();
|
|
9912
|
+
this.isExternal = isExternal();
|
|
9913
|
+
this.LogStatus = LogStatus;
|
|
9914
|
+
this.logIcon = logIcon$1;
|
|
9915
|
+
this.logColor = logColor$1;
|
|
9916
|
+
this.isInSystemBoundary = isInSystemBoundary;
|
|
9917
|
+
this.typeaheadFocus = typeaheadFocus;
|
|
9918
|
+
this.isNumber = (value) => typeof value === 'number';
|
|
9919
|
+
this.isEmptyValue = (value) => value === null || value === undefined || value === '';
|
|
9920
|
+
this.onlyRequired = signal(true, ...(ngDevMode ? [{ debugName: "onlyRequired" }] : []));
|
|
9921
|
+
this.term = signal(undefined, ...(ngDevMode ? [{ debugName: "term" }] : []));
|
|
9922
|
+
this.nodeType = computed(() => nodeType(this.node()), ...(ngDevMode ? [{ debugName: "nodeType" }] : []));
|
|
9923
|
+
// blank nodes are passed as arrays; metadata/completeness as a `key -> value` map
|
|
9924
|
+
this.isBlankNodes = computed(() => Array.isArray(this.originalValues()) || Array.isArray(this.recalculatedValues()), ...(ngDevMode ? [{ debugName: "isBlankNodes" }] : []));
|
|
9925
|
+
// resolve names for `<key>-failed` terms (top-level, and the `<field>-failed` nested inside each blank
|
|
9926
|
+
// node, e.g. an animal's failed properties) so they render as proper term links
|
|
9927
|
+
this.failedTermIds = computed(() => {
|
|
9928
|
+
if (!this.isBlankNodes())
|
|
9929
|
+
return [];
|
|
9930
|
+
const jlog = this.scopedJlog() || {};
|
|
9931
|
+
const topLevel = Object.keys(jlog[`${this.nodeKey()}-failed`] || {});
|
|
9932
|
+
const nested = Object.values(jlog[this.nodeKey()] || {}).flatMap((entry) => Object.entries(entry || {})
|
|
9933
|
+
.filter(([key]) => key.endsWith('-failed'))
|
|
9934
|
+
.flatMap(([, failedEntry]) => Object.keys(failedEntry || {})));
|
|
9935
|
+
return unique([...topLevel, ...nested].filter(Boolean));
|
|
9936
|
+
}, ...(ngDevMode ? [{ debugName: "failedTermIds" }] : []));
|
|
9937
|
+
this.failedTermsResource = rxResource({
|
|
9938
|
+
params: () => ({ ids: this.failedTermIds() }),
|
|
9939
|
+
stream: ({ params: { ids } }) => ids.length
|
|
9940
|
+
? this.searchTerms({
|
|
9941
|
+
bool: { must: [matchType(NodeType.Term)], should: ids.map(matchId), minimum_should_match: 1 }
|
|
9942
|
+
}).pipe(map(groupTerms$1))
|
|
9943
|
+
: of({})
|
|
9944
|
+
});
|
|
9945
|
+
this.failedTerms = computed(() => this.failedTermsResource.value() ?? {}, ...(ngDevMode ? [{ debugName: "failedTerms" }] : []));
|
|
9946
|
+
// orchestrator config lists the models that could run for a term (so skipped models are still shown)
|
|
9947
|
+
this.configResource = rxResource({
|
|
9948
|
+
params: () => ({ node: this.node() }),
|
|
9949
|
+
stream: ({ params: { node } }) => this.engineService.ochestratorConfig$(nodeType(node), node['@id'] || node.id)
|
|
9950
|
+
});
|
|
9951
|
+
this.config = computed(() => this.configResource.value(), ...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
9952
|
+
this.allGroups = computed(() => {
|
|
9953
|
+
if (!this.isBlankNodes()) {
|
|
9954
|
+
return groupJLogByField(this.scopedJlog(), this.nodeKey(), this.originalValues(), this.recalculatedValues(), this.nodeType());
|
|
9955
|
+
}
|
|
9956
|
+
const groups = groupJLogByTerm(this.scopedJlog(), this.nodeKey(), this.recalculatedValues(), this.originalValues(), this.nodeType(), id => this.failedTerms()[id] || { '@type': NodeType.Term, '@id': id, name: termTypeLabel(id) }, this.config());
|
|
9957
|
+
// a combined node key (e.g. `emissionsResourceUse`) holds several term types; keep only the requested
|
|
9958
|
+
// ones (like the legacy `computeTerms`), keeping terms whose type is not yet resolved
|
|
9959
|
+
const termTypes = this.filterTermTypes();
|
|
9960
|
+
return termTypes?.length
|
|
9961
|
+
? groups.filter(group => !group.term?.termType || termTypes.includes(group.term.termType))
|
|
9962
|
+
: groups;
|
|
9963
|
+
}, ...(ngDevMode ? [{ debugName: "allGroups" }] : []));
|
|
9964
|
+
this.groups = computed(() => this.allGroups().filter(group => {
|
|
9965
|
+
const selected = this.term();
|
|
9966
|
+
if (selected)
|
|
9967
|
+
return group.term?.name?.toLowerCase().includes(selected.name.toLowerCase());
|
|
9968
|
+
// hide non-system-boundary terms with no recalculation when "only required" is on
|
|
9969
|
+
return (!this.onlyRequired() ||
|
|
9970
|
+
!this.filteredType() ||
|
|
9971
|
+
isInSystemBoundary(group.termId) ||
|
|
9972
|
+
group.rows.some(row => row.isRecalculated || row.isFailed));
|
|
9973
|
+
}), ...(ngDevMode ? [{ debugName: "groups" }] : []));
|
|
9974
|
+
this.hasLogs = computed(() => !isEmpty(this.jlog()), ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
|
|
9975
|
+
this.methodModelsCount = computed(() => Math.max(1, jLogModelCount(this.allGroups())), ...(ngDevMode ? [{ debugName: "methodModelsCount" }] : []));
|
|
9976
|
+
this.filteredType = computed(() => this.filterTermTypesLabel() || this.filterTermTypes()?.map(termTypeLabel).join(' & '), ...(ngDevMode ? [{ debugName: "filteredType" }] : []));
|
|
9977
|
+
this.allTerms = computed(() => this.allGroups().map(group => group.term).filter(Boolean), ...(ngDevMode ? [{ debugName: "allTerms" }] : []));
|
|
9978
|
+
this.enableFilterByTerm = computed(() => this.allTerms().length > 0, ...(ngDevMode ? [{ debugName: "enableFilterByTerm" }] : []));
|
|
9979
|
+
this.termFormatter = ({ name }) => name;
|
|
9980
|
+
this.suggestTerm = (text$) => text$.pipe(distinctUntilChanged(), map(value => this.allTerms().filter(v => termSearch$1(v.name).includes(termSearch$1(value)))));
|
|
9981
|
+
this.methodsById = toSignal(this.searchTerms({
|
|
9982
|
+
bool: { must: [matchType(NodeType.Term), { match: { termType: TermTermType.model } }] }
|
|
9983
|
+
}).pipe(map(groupTerms$1)));
|
|
9984
|
+
this.isArray = Array.isArray;
|
|
9985
|
+
this.succeeded = (model) => [LogStatus.success, LogStatus.notRequired, LogStatus.dataProvided].includes(model.status);
|
|
9986
|
+
}
|
|
9987
|
+
searchTerms(query) {
|
|
9988
|
+
return this.searchService
|
|
9989
|
+
.search$({
|
|
9990
|
+
fields: ['@type', '@id', 'name', 'units', 'termType'],
|
|
9991
|
+
limit: 10000,
|
|
9992
|
+
query
|
|
9993
|
+
})
|
|
9994
|
+
.pipe(map(({ results }) => results));
|
|
9995
|
+
}
|
|
9996
|
+
methodName({ methodId, modelKey }) {
|
|
9997
|
+
return modelKeyLabel[modelKey] || this.methodsById()?.[methodId]?.name || methodIdLabel$1(methodId);
|
|
9998
|
+
}
|
|
9999
|
+
modelMethodTier(model) {
|
|
10000
|
+
return model.logs?.methodTier || model.model?.methodTier;
|
|
10001
|
+
}
|
|
10002
|
+
// the per-column view of a row's models (a column may be a parallel group of runs, shown stacked)
|
|
10003
|
+
modelColumns(row) {
|
|
10004
|
+
return row.modelColumns ?? row.models;
|
|
10005
|
+
}
|
|
10006
|
+
// a collapsed row with sub-rows but no direct model "all succeeded" when each sub-row has a run that
|
|
10007
|
+
// did not fail (mirrors the legacy `hasCompleteSuccess`)
|
|
10008
|
+
subRowsAllSucceeded(row) {
|
|
10009
|
+
return row.subRows.every(sub => sub.models.some(this.succeeded));
|
|
10010
|
+
}
|
|
10011
|
+
// a collapsed multi-row group "all succeeded" when every one of its rows succeeded
|
|
10012
|
+
groupAllSucceeded(group) {
|
|
10013
|
+
return group.rows.every(row => this.rowSucceeded(row));
|
|
10014
|
+
}
|
|
10015
|
+
rowSucceeded(row) {
|
|
10016
|
+
if (row.isFailed)
|
|
10017
|
+
return false;
|
|
10018
|
+
if (row.models.length)
|
|
10019
|
+
return row.models.some(this.succeeded);
|
|
10020
|
+
return row.subRows.length ? this.subRowsAllSucceeded(row) : true;
|
|
10021
|
+
}
|
|
10022
|
+
toggleGroup(group) {
|
|
10023
|
+
group.isOpen = !group.isOpen;
|
|
10024
|
+
!group.isOpen && group.rows.forEach(row => (row.isOpen = false));
|
|
10025
|
+
}
|
|
10026
|
+
toggleRow(row) {
|
|
10027
|
+
row.isOpen = !row.isOpen;
|
|
10028
|
+
}
|
|
10029
|
+
trackByGroup(_index, group) {
|
|
10030
|
+
return group.termId;
|
|
10031
|
+
}
|
|
10032
|
+
trackByRow(_index, row) {
|
|
10033
|
+
return `${row.termId}-${row.index}-${row.identityLabel}`;
|
|
10034
|
+
}
|
|
10035
|
+
trackByModel(_index, model) {
|
|
10036
|
+
return model.methodId;
|
|
10037
|
+
}
|
|
10038
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10039
|
+
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\"><span>Model {{ i + 1 }}</span></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 (groupAllSucceeded(group)) {\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=\"onlyRequiredJLog\" />\n <label class=\"is-size-7\" for=\"onlyRequiredJLog\">\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 (subRowsAllSucceeded(row)) {\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 @let columns = modelColumns(row);\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (columns[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 <he-node-logs-models-logs [logs]=\"model.logs\" />\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: 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 }); }
|
|
10040
|
+
}
|
|
10041
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, decorators: [{
|
|
10042
|
+
type: Component$1,
|
|
10043
|
+
args: [{ selector: 'he-node-jlog-models', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
10044
|
+
KeyValuePipe,
|
|
10045
|
+
NgTemplateOutlet,
|
|
10046
|
+
FormsModule,
|
|
10047
|
+
DataTableComponent,
|
|
10048
|
+
BlankNodeValueDeltaComponent,
|
|
10049
|
+
NodeLinkComponent,
|
|
10050
|
+
NgbTypeahead,
|
|
10051
|
+
NgbPopover,
|
|
10052
|
+
CompoundPipe,
|
|
10053
|
+
DefaultPipe,
|
|
10054
|
+
KeyToLabelPipe,
|
|
10055
|
+
PrecisionPipe,
|
|
10056
|
+
TimesPipe,
|
|
10057
|
+
CapitalizePipe,
|
|
10058
|
+
HESvgIconComponent,
|
|
10059
|
+
NodeLogsModelsLogsComponent,
|
|
10060
|
+
NodeLogsModelsLogsStatusComponent,
|
|
10061
|
+
GuideOverlayComponent
|
|
10062
|
+
], 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\"><span>Model {{ i + 1 }}</span></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 (groupAllSucceeded(group)) {\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=\"onlyRequiredJLog\" />\n <label class=\"is-size-7\" for=\"onlyRequiredJLog\">\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 (subRowsAllSucceeded(row)) {\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 @let columns = modelColumns(row);\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (columns[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 <he-node-logs-models-logs [logs]=\"model.logs\" />\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"] }]
|
|
10063
|
+
}], 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 }] }] } });
|
|
10064
|
+
|
|
9164
10065
|
const groupTerms = (terms) => terms.reduce((prev, curr) => ({ ...prev, [curr['@id']]: curr }), {});
|
|
9165
10066
|
const logIcon = {
|
|
9166
10067
|
[LogStatus.success]: 'checkmark',
|
|
@@ -9267,6 +10168,9 @@ class NodeLogsModelsComponent {
|
|
|
9267
10168
|
this.logsKey = input('', ...(ngDevMode ? [{ debugName: "logsKey" }] : []));
|
|
9268
10169
|
this.noDataMessage = input('', ...(ngDevMode ? [{ debugName: "noDataMessage" }] : []));
|
|
9269
10170
|
this.cycle = input(...(ngDevMode ? [undefined, { debugName: "cycle" }] : []));
|
|
10171
|
+
// for a grouped sub-node view (e.g. an animal's inputs), scope the `.jlog` to its parent entry
|
|
10172
|
+
this.jlogParentKey = input(...(ngDevMode ? [undefined, { debugName: "jlogParentKey" }] : []));
|
|
10173
|
+
this.jlogParentIndex = input(...(ngDevMode ? [undefined, { debugName: "jlogParentIndex" }] : []));
|
|
9270
10174
|
this.isEmpty = isEmpty;
|
|
9271
10175
|
this.schemaBaseUrl = schemaBaseUrl();
|
|
9272
10176
|
this.isExternal = isExternal();
|
|
@@ -9291,12 +10195,27 @@ class NodeLogsModelsComponent {
|
|
|
9291
10195
|
this.hasContributions = computed(() => [this.nodeType() === NodeType.ImpactAssessment, ['impacts', 'endpoints'].includes(this.nodeKey())].every(Boolean), ...(ngDevMode ? [{ debugName: "hasContributions" }] : []));
|
|
9292
10196
|
this.logsUrl = computed(() => this.nodeService.nodeLogsUrl(this.node()), ...(ngDevMode ? [{ debugName: "logsUrl" }] : []));
|
|
9293
10197
|
this.nodeType = computed(() => nodeType(this.node()), ...(ngDevMode ? [{ debugName: "nodeType" }] : []));
|
|
10198
|
+
// the new `.jlog` (JSON) recalculation logs, when available
|
|
10199
|
+
this.jlogResource = rxResource({
|
|
10200
|
+
params: () => ({ node: this.node() }),
|
|
10201
|
+
stream: ({ params: { node } }) => this.nodeLogsModelsService.getJLog$(node)
|
|
10202
|
+
});
|
|
10203
|
+
this.jlog = computed(() => this.jlogResource.value() ?? {}, ...(ngDevMode ? [{ debugName: "jlog" }] : []));
|
|
10204
|
+
this.loadingJLog = computed(() => !this.jlogResource.hasValue() || this.jlogResource.isLoading(), ...(ngDevMode ? [{ debugName: "loadingJLog" }] : []));
|
|
10205
|
+
// a `.jlog` means a new calculation (no text logs): render everything with the dedicated component.
|
|
10206
|
+
// the legacy text path only remains for older calculations that have no `.jlog`.
|
|
10207
|
+
this.useJLog = computed(() => !isEmpty(this.jlog()), ...(ngDevMode ? [{ debugName: "useJLog" }] : []));
|
|
10208
|
+
// only fetch the legacy text logs once we know the node has no `.jlog`
|
|
9294
10209
|
this.logsResource = rxResource({
|
|
9295
|
-
params: () => ({
|
|
9296
|
-
|
|
10210
|
+
params: () => ({
|
|
10211
|
+
node: this.node(),
|
|
10212
|
+
groupByAnimal: !!this.logsKey(),
|
|
10213
|
+
skip: this.loadingJLog() || this.useJLog()
|
|
10214
|
+
}),
|
|
10215
|
+
stream: ({ params: { node, groupByAnimal, skip } }) => skip ? of({}) : this.nodeLogsModelsService.getNodeLogs$(node, groupByAnimal)
|
|
9297
10216
|
});
|
|
9298
10217
|
this.allLogs = computed(() => this.logsResource.value() ?? {}, ...(ngDevMode ? [{ debugName: "allLogs" }] : []));
|
|
9299
|
-
this.hasLogs = computed(() => !isEmpty(this.allLogs()), ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
|
|
10218
|
+
this.hasLogs = computed(() => !isEmpty(this.allLogs()) || this.useJLog(), ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
|
|
9300
10219
|
this.configResource = rxResource({
|
|
9301
10220
|
params: () => ({ node: this.node() }),
|
|
9302
10221
|
stream: ({ params: { node } }) => this.engineService.ochestratorConfig$(nodeType(node), nodeId(node))
|
|
@@ -9463,7 +10382,7 @@ class NodeLogsModelsComponent {
|
|
|
9463
10382
|
return subValues.every(v => v.configModels.some(vv => [LogStatus.success, LogStatus.notRequired, LogStatus.dataProvided].includes(vv.status)));
|
|
9464
10383
|
}
|
|
9465
10384
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9466
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsComponent, isStandalone: true, selector: "he-node-logs-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 }, terms: { classPropertyName: "terms", publicName: "terms", 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 }, logsKey: { classPropertyName: "logsKey", publicName: "logsKey", isSignal: true, isRequired: false, transformFunction: null }, noDataMessage: { classPropertyName: "noDataMessage", publicName: "noDataMessage", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n\n @if (!isExternal && !loading() && logsUrl() && hasLogs()) {\n <a class=\"is-size-7\" [href]=\"logsUrl()\" target=\"_blank\">\n <span>Open Full Logs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</div>\n\n@if (!isExternal && !loading() && !hasLogs()) {\n <p class=\"is-my-2\">\n <he-svg-icon class=\"has-text-warning\" name=\"exclamation-triangle\" />\n <span class=\"is-size-7 has-text-warning is-pl-1\">No logs found. Recalculation logs will be incomplete.</span>\n </p>\n}\n\n<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\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>\n <span class=\"is-pr-1\">Units</span>\n @if (functionalUnit()) {\n <span>(per </span>\n <span>{{ functionalUnit() }}</span>\n <span>)</span>\n }\n </span>\n </div>\n </th>\n }\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Original</span>\n </div>\n </th>\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Recalculated</span>\n </div>\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Difference</span>\n </div>\n </th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Model {{ i + 1 }}</span>\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n </td>\n </tr>\n } @else if (blankNodes().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">\n @if (noDataMessage()) {\n <span>{{ noDataMessage() }}</span>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResultsDefaultMessage\" />\n }\n </p>\n </td>\n </tr>\n }\n @for (blankNode of blankNodes(); track trackByBlankNode($index, blankNode)) {\n @let configModels = $any(blankNode).configModels;\n <tr [class.has-sub-rows]=\"blankNode.canOpen\" [class.is-open]=\"blankNode.isOpen\">\n <td\n class=\"width-auto has-border-right is-nowrap\"\n [attr.title]=\"$any(blankNode).term?.name || $any(blankNode).key\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: blankNode }\" />\n @if ($any(blankNode).term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"$any(blankNode).term\">\n <span\n class=\"break-word\"\n [innerHtml]=\"$any(blankNode).term.name | compound: $any(blankNode).term.termType\"></span>\n </he-node-link>\n } @else if ($any(blankNode).key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if ($any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n <ng-template #originalValueContent>\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </ng-template>\n\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).originalValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span\n [class.trigger-popover]=\"!!$any(blankNode).original?.[0]?.methodModel\"\n [ngbPopover]=\"blankNodeOriginalValueDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n placement=\"bottom left right auto\"\n container=\"body\"\n [disablePopover]=\"!$any(blankNode).original?.[0]?.methodModel\"\n [popoverContext]=\"{ blankNode }\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </span>\n }\n </td>\n <td class=\"has-border-right\">\n @if (blankNode.isRecalculated) {\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).recalculatedValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: blankNode.recalculatedValue }\" />\n </span>\n }\n } @else if (configModels?.length) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n @if (\n $any(blankNode).originalValueByMethodId[model.methodId] !== null &&\n $any(blankNode).recalculatedValueByMethodId[model.methodId] !== null\n ) {\n <he-blank-node-value-delta\n [value]=\"$any(blankNode).recalculatedValueByMethodId[model.methodId]\"\n [originalValue]=\"$any(blankNode).originalValueByMethodId[model.methodId]\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </div>\n }\n } @else {\n @if ($any(blankNode).original.length && blankNode.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"blankNode.recalculatedValue\"\n [originalValue]=\"$any(blankNode).originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n }\n </td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: blankNode }\" />\n </tr>\n @for (subValue of $any(blankNode).keys; track trackBySubValue(subValue)) {\n @if (blankNode.isOpen) {\n <tr [class.has-sub-rows]=\"$any(blankNode).subValues?.length\" [class.is-sub-row]=\"blankNode.canOpen\">\n <td class=\"width-auto has-border-right is-nowrap\">\n <span class=\"is-inline-block is-align-top pl-3 pr-1 field-node\">Field:</span>\n @if (blankNode.type) {\n <a\n class=\"is-inline-block is-pre-wrap\"\n [href]=\"schemaBaseUrl + '/' + blankNode.type + '#' + subValue.key\"\n target=\"_blank\"\n [title]=\"subValue.key\">\n <span>{{ subValue.key }}</span>\n </a>\n }\n @if (!blankNode.type) {\n <span class=\"is-inline-block is-align-top\">{{ subValue.key }}</span>\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\"></td>\n }\n <td class=\"has-border-right\">\n @if (subValue.originalValue !== null) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated || subValue.key === 'impactAssessment') {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n } @else {\n not recalculated\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n }\n @for (subValue of $any(blankNode).subValues; track trackBySubValue(subValue)) {\n <ng-container *ngTemplateOutlet=\"subValueRow; context: { blankNode, parent: blankNode, subValue }\" />\n }\n }\n </tbody>\n </table>\n</he-data-table>\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=\"onlyRequired\" />\n <label class=\"is-size-7\" for=\"onlyRequired\">\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 #noResultsDefaultMessage>\n <span>No original data was provided and no gap filling occurred</span>\n @if (term() && !isInSystemBoundary(term()['@id'])) {\n <span class=\"is-pl-1\">as</span>\n <i class=\"is-px-1\">{{ term().name }}</i>\n <span>is not in the HESTIA system boundary</span>\n }\n <span>.</span>\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 #collapseButton let-blankNode>\n @if (blankNode.canOpen) {\n <a class=\"open-node\" (click)=\"toggleBlankNode(blankNode)\">\n <he-svg-icon [name]=\"blankNode.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n</ng-template>\n\n<ng-template #subValueRow let-blankNode=\"blankNode\" let-parent=\"parent\" let-subValue=\"subValue\" let-rowClass=\"rowClass\">\n @let term = subValue.term || termById(subValue.id);\n @if (parent.isOpen) {\n <tr [class.is-sub-row]=\"parent.canOpen\" [ngClass]=\"rowClass\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 h-100\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: subValue }\" />\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\" [class.is-pl-3]=\"!subValue.canOpen\">\n <span>\n <span>{{ subValue.key | keyToLabel }}</span>\n @if (subValue.id) {\n <span class=\"is-inline-block\">:</span>\n }\n </span>\n @if (subValue.id) {\n @switch (subValue.key) {\n @case ('backgroundData') {\n <span class=\"is-inline-block\">{{ term?.name }}</span>\n }\n @case ('animal') {\n <span class=\"is-inline-block\">{{ subValue.id }}</span>\n }\n @default {\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-inline-block\"\n [node]=\"term\"\n [attr.title]=\"term?.name\">\n <span class=\"break-word\" [innerHtml]=\"term?.name | compound\"></span>\n </he-node-link>\n }\n }\n }\n </div>\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (subValue.showUnits && $any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmpty(subValue.originalValue)) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated) {\n @if (subValue.multiGroups) {\n <span\n class=\"trigger-popover\"\n ngbPopover=\"The total value across all inputs\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n </span>\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n }\n } @else if (!isEmpty(subValue.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n @if (subValue.subValues) {\n @for (sub of subValue.subValues; track trackBySubValue(sub)) {\n <ng-container\n *ngTemplateOutlet=\"\n subValueRow;\n context: { blankNode, parent: subValue, subValue: sub, rowClass: 'is-sub-sub-row' }\n \" />\n }\n }\n</ng-template>\n\n<ng-template #blankNodeOriginalValueDetails let-blankNode=\"blankNode\">\n <span class=\"is-pr-1\">The original value was reported using:</span>\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-dark\"\n [node]=\"$any(blankNode).original[0].methodModel\"\n [showExternalLink]=\"true\">\n <span>{{ $any(blankNode).original[0].methodModel.name }}</span>\n </he-node-link>\n</ng-template>\n\n<ng-template #blankNodeModels let-data=\"data\">\n @let extraColumns = methodModelsCount() - 1;\n\n <ng-template #notInSystemBoundary>\n <td class=\"has-border-right\">\n <span>Not in HESTIA system boundary</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n </ng-template>\n\n @if (data.canOpen && !data.isOpen && !data.configModels?.length) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @let key = subValuesKey(data, 'sub-values');\n @if (hasCompleteSuccess(data)) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1\" name=\"checkmark\" class=\"has-text-success\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1\" name=\"xmark\" class=\"has-text-danger\" />\n }\n <span>)</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (configModel of methodModelsCount() | times; track configModelIndex; let configModelIndex = $index) {\n <td class=\"has-border-right blank-node-index-{{ configModelIndex }}\">\n @if (getModelsAt(data, configModelIndex); as models) {\n @if ($any(models) | isArray) {\n <div>\n @for (model of $any(models); track model.methodId) {\n <p>\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model, data }\" />\n </p>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model: models, data }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #blankNodeModel let-model=\"model\" let-data=\"data\">\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, data })\">\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\n @if (model.logs?.methodTier || model.model?.methodTier) {\n <span class=\"is-nowrap\">[{{ model.logs?.methodTier || model.model?.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() : model.showLogs ? p.open({ model }) : null\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\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-data=\"data\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"\" />\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 td:first-child{padding-left:12px}::ng-deep .table .is-sub-row .sub-sub-row-icon{display:none}::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}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon{display:inline-block}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon+div{padding-left:0!important}::ng-deep .table .popover-body .table-container{max-height:260px;overflow-y:auto}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { 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: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { 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: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "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: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { 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: IsArrayPipe, name: "isArray" }, { kind: "pipe", type: RepeatPipe, name: "repeat" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10385
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsComponent, isStandalone: true, selector: "he-node-logs-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 }, terms: { classPropertyName: "terms", publicName: "terms", 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 }, logsKey: { classPropertyName: "logsKey", publicName: "logsKey", isSignal: true, isRequired: false, transformFunction: null }, noDataMessage: { classPropertyName: "noDataMessage", publicName: "noDataMessage", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", 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: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n\n @if (!isExternal && !loading() && logsUrl() && hasLogs()) {\n <a class=\"is-size-7\" [href]=\"logsUrl()\" target=\"_blank\">\n <span>Open Full Logs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</div>\n\n@if (!isExternal && !loading() && !loadingJLog() && !hasLogs()) {\n <p class=\"is-my-2\">\n <he-svg-icon class=\"has-text-warning\" name=\"exclamation-triangle\" />\n <span class=\"is-size-7 has-text-warning is-pl-1\">No logs found. Recalculation logs will be incomplete.</span>\n </p>\n}\n\n@if (loadingJLog()) {\n <p class=\"has-text-centered py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </p>\n} @else if (useJLog()) {\n <he-node-jlog-models\n [node]=\"node()\"\n [nodeKey]=\"$any(nodeKey())\"\n [originalValues]=\"$any(originalValues())\"\n [recalculatedValues]=\"$any(recalculatedValues())\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"filterTermTypesLabel()\"\n [cycle]=\"cycle()\"\n [jlog]=\"jlog()\"\n [jlogParentKey]=\"jlogParentKey()\"\n [jlogParentIndex]=\"jlogParentIndex()\" />\n} @else {\n <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\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>\n <span class=\"is-pr-1\">Units</span>\n @if (functionalUnit()) {\n <span>(per </span>\n <span>{{ functionalUnit() }}</span>\n <span>)</span>\n }\n </span>\n </div>\n </th>\n }\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Original</span>\n </div>\n </th>\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Recalculated</span>\n </div>\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Difference</span>\n </div>\n </th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Model {{ i + 1 }}</span>\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n </td>\n </tr>\n } @else if (blankNodes().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">\n @if (noDataMessage()) {\n <span>{{ noDataMessage() }}</span>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResultsDefaultMessage\" />\n }\n </p>\n </td>\n </tr>\n }\n @for (blankNode of blankNodes(); track trackByBlankNode($index, blankNode)) {\n @let configModels = $any(blankNode).configModels;\n <tr [class.has-sub-rows]=\"blankNode.canOpen\" [class.is-open]=\"blankNode.isOpen\">\n <td\n class=\"width-auto has-border-right is-nowrap\"\n [attr.title]=\"$any(blankNode).term?.name || $any(blankNode).key\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: blankNode }\" />\n @if ($any(blankNode).term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"$any(blankNode).term\">\n <span\n class=\"break-word\"\n [innerHtml]=\"$any(blankNode).term.name | compound: $any(blankNode).term.termType\"></span>\n </he-node-link>\n } @else if ($any(blankNode).key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if ($any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n <ng-template #originalValueContent>\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </ng-template>\n\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).originalValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span\n [class.trigger-popover]=\"!!$any(blankNode).original?.[0]?.methodModel\"\n [ngbPopover]=\"blankNodeOriginalValueDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n placement=\"bottom left right auto\"\n container=\"body\"\n [disablePopover]=\"!$any(blankNode).original?.[0]?.methodModel\"\n [popoverContext]=\"{ blankNode }\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </span>\n }\n </td>\n <td class=\"has-border-right\">\n @if (blankNode.isRecalculated) {\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).recalculatedValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: blankNode.recalculatedValue }\" />\n </span>\n }\n } @else if (configModels?.length) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n @if (\n $any(blankNode).originalValueByMethodId[model.methodId] !== null &&\n $any(blankNode).recalculatedValueByMethodId[model.methodId] !== null\n ) {\n <he-blank-node-value-delta\n [value]=\"$any(blankNode).recalculatedValueByMethodId[model.methodId]\"\n [originalValue]=\"$any(blankNode).originalValueByMethodId[model.methodId]\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </div>\n }\n } @else {\n @if ($any(blankNode).original.length && blankNode.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"blankNode.recalculatedValue\"\n [originalValue]=\"$any(blankNode).originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n }\n </td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: blankNode }\" />\n </tr>\n @for (subValue of $any(blankNode).keys; track trackBySubValue(subValue)) {\n @if (blankNode.isOpen) {\n <tr [class.has-sub-rows]=\"$any(blankNode).subValues?.length\" [class.is-sub-row]=\"blankNode.canOpen\">\n <td class=\"width-auto has-border-right is-nowrap\">\n <span class=\"is-inline-block is-align-top pl-3 pr-1 field-node\">Field:</span>\n @if (blankNode.type) {\n <a\n class=\"is-inline-block is-pre-wrap\"\n [href]=\"schemaBaseUrl + '/' + blankNode.type + '#' + subValue.key\"\n target=\"_blank\"\n [title]=\"subValue.key\">\n <span>{{ subValue.key }}</span>\n </a>\n }\n @if (!blankNode.type) {\n <span class=\"is-inline-block is-align-top\">{{ subValue.key }}</span>\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\"></td>\n }\n <td class=\"has-border-right\">\n @if (subValue.originalValue !== null) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated || subValue.key === 'impactAssessment') {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n } @else {\n not recalculated\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n }\n @for (subValue of $any(blankNode).subValues; track trackBySubValue(subValue)) {\n <ng-container *ngTemplateOutlet=\"subValueRow; context: { blankNode, parent: blankNode, subValue }\" />\n }\n }\n </tbody>\n </table>\n</he-data-table>\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=\"onlyRequired\" />\n <label class=\"is-size-7\" for=\"onlyRequired\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n </div>\n}\n\n<ng-template #noResultsDefaultMessage>\n <span>No original data was provided and no gap filling occurred</span>\n @if (term() && !isInSystemBoundary(term()['@id'])) {\n <span class=\"is-pl-1\">as</span>\n <i class=\"is-px-1\">{{ term().name }}</i>\n <span>is not in the HESTIA system boundary</span>\n }\n <span>.</span>\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 #collapseButton let-blankNode>\n @if (blankNode.canOpen) {\n <a class=\"open-node\" (click)=\"toggleBlankNode(blankNode)\">\n <he-svg-icon [name]=\"blankNode.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n</ng-template>\n\n<ng-template #subValueRow let-blankNode=\"blankNode\" let-parent=\"parent\" let-subValue=\"subValue\" let-rowClass=\"rowClass\">\n @let term = subValue.term || termById(subValue.id);\n @if (parent.isOpen) {\n <tr [class.is-sub-row]=\"parent.canOpen\" [ngClass]=\"rowClass\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 h-100\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: subValue }\" />\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\" [class.is-pl-3]=\"!subValue.canOpen\">\n <span>\n <span>{{ subValue.key | keyToLabel }}</span>\n @if (subValue.id) {\n <span class=\"is-inline-block\">:</span>\n }\n </span>\n @if (subValue.id) {\n @switch (subValue.key) {\n @case ('backgroundData') {\n <span class=\"is-inline-block\">{{ term?.name }}</span>\n }\n @case ('animal') {\n <span class=\"is-inline-block\">{{ subValue.id }}</span>\n }\n @default {\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-inline-block\"\n [node]=\"term\"\n [attr.title]=\"term?.name\">\n <span class=\"break-word\" [innerHtml]=\"term?.name | compound\"></span>\n </he-node-link>\n }\n }\n }\n </div>\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (subValue.showUnits && $any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmpty(subValue.originalValue)) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated) {\n @if (subValue.multiGroups) {\n <span\n class=\"trigger-popover\"\n ngbPopover=\"The total value across all inputs\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n </span>\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n }\n } @else if (!isEmpty(subValue.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n @if (subValue.subValues) {\n @for (sub of subValue.subValues; track trackBySubValue(sub)) {\n <ng-container\n *ngTemplateOutlet=\"\n subValueRow;\n context: { blankNode, parent: subValue, subValue: sub, rowClass: 'is-sub-sub-row' }\n \" />\n }\n }\n</ng-template>\n\n<ng-template #blankNodeOriginalValueDetails let-blankNode=\"blankNode\">\n <span class=\"is-pr-1\">The original value was reported using:</span>\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-dark\"\n [node]=\"$any(blankNode).original[0].methodModel\"\n [showExternalLink]=\"true\">\n <span>{{ $any(blankNode).original[0].methodModel.name }}</span>\n </he-node-link>\n</ng-template>\n\n<ng-template #blankNodeModels let-data=\"data\">\n @let extraColumns = methodModelsCount() - 1;\n\n <ng-template #notInSystemBoundary>\n <td class=\"has-border-right\">\n <span>Not in HESTIA system boundary</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n </ng-template>\n\n @if (data.canOpen && !data.isOpen && !data.configModels?.length) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @let key = subValuesKey(data, 'sub-values');\n @if (hasCompleteSuccess(data)) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1\" name=\"checkmark\" class=\"has-text-success\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1\" name=\"xmark\" class=\"has-text-danger\" />\n }\n <span>)</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (configModel of methodModelsCount() | times; track configModelIndex; let configModelIndex = $index) {\n <td class=\"has-border-right blank-node-index-{{ configModelIndex }}\">\n @if (getModelsAt(data, configModelIndex); as models) {\n @if ($any(models) | isArray) {\n <div>\n @for (model of $any(models); track model.methodId) {\n <p>\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model, data }\" />\n </p>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model: models, data }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #blankNodeModel let-model=\"model\" let-data=\"data\">\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, data })\">\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\n @if (model.logs?.methodTier || model.model?.methodTier) {\n <span class=\"is-nowrap\">[{{ model.logs?.methodTier || model.model?.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() : model.showLogs ? p.open({ model }) : null\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\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-data=\"data\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"\" />\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 td:first-child{padding-left:12px}::ng-deep .table .is-sub-row .sub-sub-row-icon{display:none}::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}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon{display:inline-block}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon+div{padding-left:0!important}::ng-deep .table .popover-body .table-container{max-height:260px;overflow-y:auto}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { 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: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { 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: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "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: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "component", type: NodeJLogModelsComponent, selector: "he-node-jlog-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "filterTermTypes", "filterTermTypesLabel", "cycle", "jlog", "jlogParentKey", "jlogParentIndex"] }, { 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: IsArrayPipe, name: "isArray" }, { kind: "pipe", type: RepeatPipe, name: "repeat" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9467
10386
|
}
|
|
9468
10387
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsComponent, decorators: [{
|
|
9469
10388
|
type: Component$1,
|
|
@@ -9489,9 +10408,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
9489
10408
|
NodeLogsModelsLogsStatusComponent,
|
|
9490
10409
|
NodeLogsModelsContributionsComponent,
|
|
9491
10410
|
HESvgIconComponent,
|
|
9492
|
-
GuideOverlayComponent
|
|
9493
|
-
], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n\n @if (!isExternal && !loading() && logsUrl() && hasLogs()) {\n <a class=\"is-size-7\" [href]=\"logsUrl()\" target=\"_blank\">\n <span>Open Full Logs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</div>\n\n@if (!isExternal && !loading() && !hasLogs()) {\n <p class=\"is-my-2\">\n <he-svg-icon class=\"has-text-warning\" name=\"exclamation-triangle\" />\n <span class=\"is-size-7 has-text-warning is-pl-1\">No logs found. Recalculation logs will be incomplete.</span>\n </p>\n}\n\n<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\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>\n <span class=\"is-pr-1\">Units</span>\n @if (functionalUnit()) {\n <span>(per </span>\n <span>{{ functionalUnit() }}</span>\n <span>)</span>\n }\n </span>\n </div>\n </th>\n }\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Original</span>\n </div>\n </th>\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Recalculated</span>\n </div>\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Difference</span>\n </div>\n </th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Model {{ i + 1 }}</span>\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n </td>\n </tr>\n } @else if (blankNodes().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">\n @if (noDataMessage()) {\n <span>{{ noDataMessage() }}</span>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResultsDefaultMessage\" />\n }\n </p>\n </td>\n </tr>\n }\n @for (blankNode of blankNodes(); track trackByBlankNode($index, blankNode)) {\n @let configModels = $any(blankNode).configModels;\n <tr [class.has-sub-rows]=\"blankNode.canOpen\" [class.is-open]=\"blankNode.isOpen\">\n <td\n class=\"width-auto has-border-right is-nowrap\"\n [attr.title]=\"$any(blankNode).term?.name || $any(blankNode).key\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: blankNode }\" />\n @if ($any(blankNode).term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"$any(blankNode).term\">\n <span\n class=\"break-word\"\n [innerHtml]=\"$any(blankNode).term.name | compound: $any(blankNode).term.termType\"></span>\n </he-node-link>\n } @else if ($any(blankNode).key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if ($any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n <ng-template #originalValueContent>\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </ng-template>\n\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).originalValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span\n [class.trigger-popover]=\"!!$any(blankNode).original?.[0]?.methodModel\"\n [ngbPopover]=\"blankNodeOriginalValueDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n placement=\"bottom left right auto\"\n container=\"body\"\n [disablePopover]=\"!$any(blankNode).original?.[0]?.methodModel\"\n [popoverContext]=\"{ blankNode }\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </span>\n }\n </td>\n <td class=\"has-border-right\">\n @if (blankNode.isRecalculated) {\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).recalculatedValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: blankNode.recalculatedValue }\" />\n </span>\n }\n } @else if (configModels?.length) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n @if (\n $any(blankNode).originalValueByMethodId[model.methodId] !== null &&\n $any(blankNode).recalculatedValueByMethodId[model.methodId] !== null\n ) {\n <he-blank-node-value-delta\n [value]=\"$any(blankNode).recalculatedValueByMethodId[model.methodId]\"\n [originalValue]=\"$any(blankNode).originalValueByMethodId[model.methodId]\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </div>\n }\n } @else {\n @if ($any(blankNode).original.length && blankNode.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"blankNode.recalculatedValue\"\n [originalValue]=\"$any(blankNode).originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n }\n </td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: blankNode }\" />\n </tr>\n @for (subValue of $any(blankNode).keys; track trackBySubValue(subValue)) {\n @if (blankNode.isOpen) {\n <tr [class.has-sub-rows]=\"$any(blankNode).subValues?.length\" [class.is-sub-row]=\"blankNode.canOpen\">\n <td class=\"width-auto has-border-right is-nowrap\">\n <span class=\"is-inline-block is-align-top pl-3 pr-1 field-node\">Field:</span>\n @if (blankNode.type) {\n <a\n class=\"is-inline-block is-pre-wrap\"\n [href]=\"schemaBaseUrl + '/' + blankNode.type + '#' + subValue.key\"\n target=\"_blank\"\n [title]=\"subValue.key\">\n <span>{{ subValue.key }}</span>\n </a>\n }\n @if (!blankNode.type) {\n <span class=\"is-inline-block is-align-top\">{{ subValue.key }}</span>\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\"></td>\n }\n <td class=\"has-border-right\">\n @if (subValue.originalValue !== null) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated || subValue.key === 'impactAssessment') {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n } @else {\n not recalculated\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n }\n @for (subValue of $any(blankNode).subValues; track trackBySubValue(subValue)) {\n <ng-container *ngTemplateOutlet=\"subValueRow; context: { blankNode, parent: blankNode, subValue }\" />\n }\n }\n </tbody>\n </table>\n</he-data-table>\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=\"onlyRequired\" />\n <label class=\"is-size-7\" for=\"onlyRequired\">\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 #noResultsDefaultMessage>\n <span>No original data was provided and no gap filling occurred</span>\n @if (term() && !isInSystemBoundary(term()['@id'])) {\n <span class=\"is-pl-1\">as</span>\n <i class=\"is-px-1\">{{ term().name }}</i>\n <span>is not in the HESTIA system boundary</span>\n }\n <span>.</span>\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 #collapseButton let-blankNode>\n @if (blankNode.canOpen) {\n <a class=\"open-node\" (click)=\"toggleBlankNode(blankNode)\">\n <he-svg-icon [name]=\"blankNode.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n</ng-template>\n\n<ng-template #subValueRow let-blankNode=\"blankNode\" let-parent=\"parent\" let-subValue=\"subValue\" let-rowClass=\"rowClass\">\n @let term = subValue.term || termById(subValue.id);\n @if (parent.isOpen) {\n <tr [class.is-sub-row]=\"parent.canOpen\" [ngClass]=\"rowClass\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 h-100\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: subValue }\" />\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\" [class.is-pl-3]=\"!subValue.canOpen\">\n <span>\n <span>{{ subValue.key | keyToLabel }}</span>\n @if (subValue.id) {\n <span class=\"is-inline-block\">:</span>\n }\n </span>\n @if (subValue.id) {\n @switch (subValue.key) {\n @case ('backgroundData') {\n <span class=\"is-inline-block\">{{ term?.name }}</span>\n }\n @case ('animal') {\n <span class=\"is-inline-block\">{{ subValue.id }}</span>\n }\n @default {\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-inline-block\"\n [node]=\"term\"\n [attr.title]=\"term?.name\">\n <span class=\"break-word\" [innerHtml]=\"term?.name | compound\"></span>\n </he-node-link>\n }\n }\n }\n </div>\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (subValue.showUnits && $any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmpty(subValue.originalValue)) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated) {\n @if (subValue.multiGroups) {\n <span\n class=\"trigger-popover\"\n ngbPopover=\"The total value across all inputs\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n </span>\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n }\n } @else if (!isEmpty(subValue.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n @if (subValue.subValues) {\n @for (sub of subValue.subValues; track trackBySubValue(sub)) {\n <ng-container\n *ngTemplateOutlet=\"\n subValueRow;\n context: { blankNode, parent: subValue, subValue: sub, rowClass: 'is-sub-sub-row' }\n \" />\n }\n }\n</ng-template>\n\n<ng-template #blankNodeOriginalValueDetails let-blankNode=\"blankNode\">\n <span class=\"is-pr-1\">The original value was reported using:</span>\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-dark\"\n [node]=\"$any(blankNode).original[0].methodModel\"\n [showExternalLink]=\"true\">\n <span>{{ $any(blankNode).original[0].methodModel.name }}</span>\n </he-node-link>\n</ng-template>\n\n<ng-template #blankNodeModels let-data=\"data\">\n @let extraColumns = methodModelsCount() - 1;\n\n <ng-template #notInSystemBoundary>\n <td class=\"has-border-right\">\n <span>Not in HESTIA system boundary</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n </ng-template>\n\n @if (data.canOpen && !data.isOpen && !data.configModels?.length) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @let key = subValuesKey(data, 'sub-values');\n @if (hasCompleteSuccess(data)) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1\" name=\"checkmark\" class=\"has-text-success\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1\" name=\"xmark\" class=\"has-text-danger\" />\n }\n <span>)</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (configModel of methodModelsCount() | times; track configModelIndex; let configModelIndex = $index) {\n <td class=\"has-border-right blank-node-index-{{ configModelIndex }}\">\n @if (getModelsAt(data, configModelIndex); as models) {\n @if ($any(models) | isArray) {\n <div>\n @for (model of $any(models); track model.methodId) {\n <p>\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model, data }\" />\n </p>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model: models, data }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #blankNodeModel let-model=\"model\" let-data=\"data\">\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, data })\">\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\n @if (model.logs?.methodTier || model.model?.methodTier) {\n <span class=\"is-nowrap\">[{{ model.logs?.methodTier || model.model?.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() : model.showLogs ? p.open({ model }) : null\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\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-data=\"data\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"\" />\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 td:first-child{padding-left:12px}::ng-deep .table .is-sub-row .sub-sub-row-icon{display:none}::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}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon{display:inline-block}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon+div{padding-left:0!important}::ng-deep .table .popover-body .table-container{max-height:260px;overflow-y:auto}\n"] }]
|
|
9494
|
-
}], 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 }] }], terms: [{ type: i0.Input, args: [{ isSignal: true, alias: "terms", required: false }] }], filterTermTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypes", required: false }] }], filterTermTypesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypesLabel", required: false }] }], logsKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "logsKey", required: false }] }], noDataMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataMessage", required: false }] }], cycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycle", required: false }] }] } });
|
|
10411
|
+
GuideOverlayComponent,
|
|
10412
|
+
NodeJLogModelsComponent
|
|
10413
|
+
], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n\n @if (!isExternal && !loading() && logsUrl() && hasLogs()) {\n <a class=\"is-size-7\" [href]=\"logsUrl()\" target=\"_blank\">\n <span>Open Full Logs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</div>\n\n@if (!isExternal && !loading() && !loadingJLog() && !hasLogs()) {\n <p class=\"is-my-2\">\n <he-svg-icon class=\"has-text-warning\" name=\"exclamation-triangle\" />\n <span class=\"is-size-7 has-text-warning is-pl-1\">No logs found. Recalculation logs will be incomplete.</span>\n </p>\n}\n\n@if (loadingJLog()) {\n <p class=\"has-text-centered py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </p>\n} @else if (useJLog()) {\n <he-node-jlog-models\n [node]=\"node()\"\n [nodeKey]=\"$any(nodeKey())\"\n [originalValues]=\"$any(originalValues())\"\n [recalculatedValues]=\"$any(recalculatedValues())\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"filterTermTypesLabel()\"\n [cycle]=\"cycle()\"\n [jlog]=\"jlog()\"\n [jlogParentKey]=\"jlogParentKey()\"\n [jlogParentIndex]=\"jlogParentIndex()\" />\n} @else {\n <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\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>\n <span class=\"is-pr-1\">Units</span>\n @if (functionalUnit()) {\n <span>(per </span>\n <span>{{ functionalUnit() }}</span>\n <span>)</span>\n }\n </span>\n </div>\n </th>\n }\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Original</span>\n </div>\n </th>\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Recalculated</span>\n </div>\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Difference</span>\n </div>\n </th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <div class=\"is-flex is-flex-direction-column is-justify-content-center h-100\">\n <span>Model {{ i + 1 }}</span>\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <div class=\"has-text-center py-3\">\n <he-svg-icon name=\"loading\" animation=\"spin\" size=\"40\" />\n </div>\n </td>\n </tr>\n } @else if (blankNodes().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">\n @if (noDataMessage()) {\n <span>{{ noDataMessage() }}</span>\n } @else {\n <ng-container *ngTemplateOutlet=\"noResultsDefaultMessage\" />\n }\n </p>\n </td>\n </tr>\n }\n @for (blankNode of blankNodes(); track trackByBlankNode($index, blankNode)) {\n @let configModels = $any(blankNode).configModels;\n <tr [class.has-sub-rows]=\"blankNode.canOpen\" [class.is-open]=\"blankNode.isOpen\">\n <td\n class=\"width-auto has-border-right is-nowrap\"\n [attr.title]=\"$any(blankNode).term?.name || $any(blankNode).key\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: blankNode }\" />\n @if ($any(blankNode).term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"$any(blankNode).term\">\n <span\n class=\"break-word\"\n [innerHtml]=\"$any(blankNode).term.name | compound: $any(blankNode).term.termType\"></span>\n </he-node-link>\n } @else if ($any(blankNode).key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + $any(blankNode).key\" target=\"_blank\">\n <span>{{ $any(blankNode).key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if ($any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n <ng-template #originalValueContent>\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </ng-template>\n\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).originalValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span\n [class.trigger-popover]=\"!!$any(blankNode).original?.[0]?.methodModel\"\n [ngbPopover]=\"blankNodeOriginalValueDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n placement=\"bottom left right auto\"\n container=\"body\"\n [disablePopover]=\"!$any(blankNode).original?.[0]?.methodModel\"\n [popoverContext]=\"{ blankNode }\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: $any(blankNode).originalValue }\" />\n </span>\n </span>\n }\n </td>\n <td class=\"has-border-right\">\n @if (blankNode.isRecalculated) {\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n <ng-container\n *ngTemplateOutlet=\"\n valueContent;\n context: { value: $any(blankNode).recalculatedValueByMethodId[model.methodId] }\n \" />\n </div>\n }\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: blankNode.recalculatedValue }\" />\n </span>\n }\n } @else if (configModels?.length) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (blankNode.allParallel) {\n @for (model of configModels[0]; track model.methodId) {\n <div>\n @if (\n $any(blankNode).originalValueByMethodId[model.methodId] !== null &&\n $any(blankNode).recalculatedValueByMethodId[model.methodId] !== null\n ) {\n <he-blank-node-value-delta\n [value]=\"$any(blankNode).recalculatedValueByMethodId[model.methodId]\"\n [originalValue]=\"$any(blankNode).originalValueByMethodId[model.methodId]\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </div>\n }\n } @else {\n @if ($any(blankNode).original.length && blankNode.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"blankNode.recalculatedValue\"\n [originalValue]=\"$any(blankNode).originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n }\n </td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: blankNode }\" />\n </tr>\n @for (subValue of $any(blankNode).keys; track trackBySubValue(subValue)) {\n @if (blankNode.isOpen) {\n <tr [class.has-sub-rows]=\"$any(blankNode).subValues?.length\" [class.is-sub-row]=\"blankNode.canOpen\">\n <td class=\"width-auto has-border-right is-nowrap\">\n <span class=\"is-inline-block is-align-top pl-3 pr-1 field-node\">Field:</span>\n @if (blankNode.type) {\n <a\n class=\"is-inline-block is-pre-wrap\"\n [href]=\"schemaBaseUrl + '/' + blankNode.type + '#' + subValue.key\"\n target=\"_blank\"\n [title]=\"subValue.key\">\n <span>{{ subValue.key }}</span>\n </a>\n }\n @if (!blankNode.type) {\n <span class=\"is-inline-block is-align-top\">{{ subValue.key }}</span>\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\"></td>\n }\n <td class=\"has-border-right\">\n @if (subValue.originalValue !== null) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated || subValue.key === 'impactAssessment') {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n } @else {\n not recalculated\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n }\n @for (subValue of $any(blankNode).subValues; track trackBySubValue(subValue)) {\n <ng-container *ngTemplateOutlet=\"subValueRow; context: { blankNode, parent: blankNode, subValue }\" />\n }\n }\n </tbody>\n </table>\n</he-data-table>\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=\"onlyRequired\" />\n <label class=\"is-size-7\" for=\"onlyRequired\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n </div>\n}\n\n<ng-template #noResultsDefaultMessage>\n <span>No original data was provided and no gap filling occurred</span>\n @if (term() && !isInSystemBoundary(term()['@id'])) {\n <span class=\"is-pl-1\">as</span>\n <i class=\"is-px-1\">{{ term().name }}</i>\n <span>is not in the HESTIA system boundary</span>\n }\n <span>.</span>\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 #collapseButton let-blankNode>\n @if (blankNode.canOpen) {\n <a class=\"open-node\" (click)=\"toggleBlankNode(blankNode)\">\n <he-svg-icon [name]=\"blankNode.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n</ng-template>\n\n<ng-template #subValueRow let-blankNode=\"blankNode\" let-parent=\"parent\" let-subValue=\"subValue\" let-rowClass=\"rowClass\">\n @let term = subValue.term || termById(subValue.id);\n @if (parent.isOpen) {\n <tr [class.is-sub-row]=\"parent.canOpen\" [ngClass]=\"rowClass\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 h-100\">\n <ng-container *ngTemplateOutlet=\"collapseButton; context: { $implicit: subValue }\" />\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\" [class.is-pl-3]=\"!subValue.canOpen\">\n <span>\n <span>{{ subValue.key | keyToLabel }}</span>\n @if (subValue.id) {\n <span class=\"is-inline-block\">:</span>\n }\n </span>\n @if (subValue.id) {\n @switch (subValue.key) {\n @case ('backgroundData') {\n <span class=\"is-inline-block\">{{ term?.name }}</span>\n }\n @case ('animal') {\n <span class=\"is-inline-block\">{{ subValue.id }}</span>\n }\n @default {\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-inline-block\"\n [node]=\"term\"\n [attr.title]=\"term?.name\">\n <span class=\"break-word\" [innerHtml]=\"term?.name | compound\"></span>\n </he-node-link>\n }\n }\n }\n </div>\n </div>\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (subValue.showUnits && $any(blankNode).term) {\n <span class=\"is-nowrap\" [innerHtml]=\"$any(blankNode).term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmpty(subValue.originalValue)) {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.originalValue }\" />\n </span>\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (subValue.isRecalculated) {\n @if (subValue.multiGroups) {\n <span\n class=\"trigger-popover\"\n ngbPopover=\"The total value across all inputs\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\">\n <span pointer>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n </span>\n } @else {\n <span>\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: subValue.recalculatedValue }\" />\n </span>\n }\n } @else if (!isEmpty(subValue.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">-</td>\n }\n <ng-container *ngTemplateOutlet=\"blankNodeModels; context: { data: subValue }\" />\n </tr>\n }\n @if (subValue.subValues) {\n @for (sub of subValue.subValues; track trackBySubValue(sub)) {\n <ng-container\n *ngTemplateOutlet=\"\n subValueRow;\n context: { blankNode, parent: subValue, subValue: sub, rowClass: 'is-sub-sub-row' }\n \" />\n }\n }\n</ng-template>\n\n<ng-template #blankNodeOriginalValueDetails let-blankNode=\"blankNode\">\n <span class=\"is-pr-1\">The original value was reported using:</span>\n <he-node-link\n class=\"is-inline-block\"\n linkClass=\"is-dark\"\n [node]=\"$any(blankNode).original[0].methodModel\"\n [showExternalLink]=\"true\">\n <span>{{ $any(blankNode).original[0].methodModel.name }}</span>\n </he-node-link>\n</ng-template>\n\n<ng-template #blankNodeModels let-data=\"data\">\n @let extraColumns = methodModelsCount() - 1;\n\n <ng-template #notInSystemBoundary>\n <td class=\"has-border-right\">\n <span>Not in HESTIA system boundary</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n </ng-template>\n\n @if (data.canOpen && !data.isOpen && !data.configModels?.length) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @let key = subValuesKey(data, 'sub-values');\n @if (hasCompleteSuccess(data)) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1\" name=\"checkmark\" class=\"has-text-success\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1\" name=\"xmark\" class=\"has-text-danger\" />\n }\n <span>)</span>\n </td>\n @for (v of data | repeat: extraColumns; track repeatIndex; let repeatIndex = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (configModel of methodModelsCount() | times; track configModelIndex; let configModelIndex = $index) {\n <td class=\"has-border-right blank-node-index-{{ configModelIndex }}\">\n @if (getModelsAt(data, configModelIndex); as models) {\n @if ($any(models) | isArray) {\n <div>\n @for (model of $any(models); track model.methodId) {\n <p>\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model, data }\" />\n </p>\n }\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"blankNodeModel; context: { model: models, data }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #blankNodeModel let-model=\"model\" let-data=\"data\">\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, data })\">\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\n @if (model.logs?.methodTier || model.model?.methodTier) {\n <span class=\"is-nowrap\">[{{ model.logs?.methodTier || model.model?.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() : model.showLogs ? p.open({ model }) : null\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\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-data=\"data\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"\" />\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 td:first-child{padding-left:12px}::ng-deep .table .is-sub-row .sub-sub-row-icon{display:none}::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}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon{display:inline-block}::ng-deep .table .is-sub-sub-row .sub-sub-row-icon+div{padding-left:0!important}::ng-deep .table .popover-body .table-container{max-height:260px;overflow-y:auto}\n"] }]
|
|
10414
|
+
}], 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 }] }], terms: [{ type: i0.Input, args: [{ isSignal: true, alias: "terms", required: false }] }], filterTermTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypes", required: false }] }], filterTermTypesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTermTypesLabel", required: false }] }], logsKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "logsKey", required: false }] }], noDataMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataMessage", required: false }] }], cycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "cycle", required: false }] }], jlogParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentKey", required: false }] }], jlogParentIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentIndex", required: false }] }] } });
|
|
9495
10415
|
|
|
9496
10416
|
var View$4;
|
|
9497
10417
|
(function (View) {
|
|
@@ -9561,7 +10481,7 @@ class CyclesCompletenessComponent {
|
|
|
9561
10481
|
component.headerKeys.set(headerKeys$1);
|
|
9562
10482
|
}
|
|
9563
10483
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesCompletenessComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9564
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesCompletenessComponent, isStandalone: true, selector: "he-cycles-completeness", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10484
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesCompletenessComponent, isStandalone: true, selector: "he-cycles-completeness", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n } @else if (selectedView() === View.logs) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" id=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9565
10485
|
}
|
|
9566
10486
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesCompletenessComponent, decorators: [{
|
|
9567
10487
|
type: Component$1,
|
|
@@ -9573,7 +10493,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
9573
10493
|
BlankNodeStateComponent,
|
|
9574
10494
|
BlankNodeStateNoticeComponent,
|
|
9575
10495
|
NodeLogsModelsComponent
|
|
9576
|
-
], template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n" }]
|
|
10496
|
+
], template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (completeness of completenessKeys(); track completeness) {\n <th [attr.title]=\"completeness\">\n <a [href]=\"schemaBaseUrl + '/Completeness#' + completeness\" target=\"_blank\">\n {{ keyToLabel(completeness) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of completenessKeys(); track key) {\n <td class=\"is-nowrap\">\n <span>\n {{ getCompleteness(cycle)[key] ? 'Complete' : 'Incomplete' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"getCompleteness(cycle)\"\n [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No completeness data</span>\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n } @else if (selectedView() === View.logs) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" id=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n" }]
|
|
9577
10497
|
}], ctorParameters: () => [], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }] } });
|
|
9578
10498
|
|
|
9579
10499
|
const cycleValue = (cycle, values) => (values[cycle['@id']]?.nodes[0] || { value: [0] }).value;
|
|
@@ -9698,7 +10618,7 @@ class CyclesMetadataComponent {
|
|
|
9698
10618
|
component.headerKeys.set(headerKeys);
|
|
9699
10619
|
}
|
|
9700
10620
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesMetadataComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9701
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesMetadataComponent, isStandalone: true, selector: "he-cycles-metadata", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (key of keys(); track key) {\n <th [attr.title]=\"key\">\n <a [href]=\"schemaBaseUrl + '/Cycle#' + key\" target=\"_blank\">\n {{ keyToLabel(key) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of keys(); track key) {\n <td class=\"is-nowrap\">\n @if (isUndefined(cycle[key])) {\n <span>-</span>\n } @else {\n <span>{{ toString(cycle[key]) }}</span>\n }\n <he-blank-node-state class=\"ml-1\" [dataState]=\"dataState()\" [node]=\"cycle\" [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No data.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedCycle()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedCycle()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10621
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesMetadataComponent, isStandalone: true, selector: "he-cycles-metadata", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@switch (selectedView()) {\n @case (View.table) {\n @if (hasData()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (key of keys(); track key) {\n <th [attr.title]=\"key\">\n <a [href]=\"schemaBaseUrl + '/Cycle#' + key\" target=\"_blank\">\n {{ keyToLabel(key) }}\n </a>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycle\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (key of keys(); track key) {\n <td class=\"is-nowrap\">\n @if (isUndefined(cycle[key])) {\n <span>-</span>\n } @else {\n <span>{{ toString(cycle[key]) }}</span>\n }\n <he-blank-node-state class=\"ml-1\" [dataState]=\"dataState()\" [node]=\"cycle\" [key]=\"key\" />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <he-blank-node-state-notice class=\"is-mt-2\" [dataState]=\"dataState()\" />\n } @else {\n <div class=\"panel-block\">\n <span>No data.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.logs) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedCycle()) {\n <he-node-logs-models\n class=\"is-mt-2\"\n [node]=\"selectedCycle()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\" />\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9702
10622
|
}
|
|
9703
10623
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesMetadataComponent, decorators: [{
|
|
9704
10624
|
type: Component$1,
|
|
@@ -10105,6 +11025,18 @@ class CyclesNodesComponent {
|
|
|
10105
11025
|
this.isNodeKeyAllowed = computed(() => nodeKeyViews$2[this.firstNodeKey()].includes(this.selectedView()), ...(ngDevMode ? [{ debugName: "isNodeKeyAllowed" }] : []));
|
|
10106
11026
|
this.groupedNodes = computed(() => this.originalNodes().flatMap(cycle => cycleGroupNodes(this.nodeKeyGroup(), cycle)), ...(ngDevMode ? [{ debugName: "groupedNodes" }] : []));
|
|
10107
11027
|
this.groupNodeKey = computed(() => groupNodesKeyToProperty[this.nodeKeyGroup()], ...(ngDevMode ? [{ debugName: "groupNodeKey" }] : []));
|
|
11028
|
+
// for a grouped view (e.g. animals), the selected node's index within its parent cycle, so the `.jlog`
|
|
11029
|
+
// can be scoped to `jlog[<group>][<index>]` (the sub-node follows the recalculated node representation)
|
|
11030
|
+
this.jlogParentIndex = computed(() => {
|
|
11031
|
+
const groupKey = this.nodeKeyGroup();
|
|
11032
|
+
const node = this.selectedCycle();
|
|
11033
|
+
if (!groupKey || !node)
|
|
11034
|
+
return undefined;
|
|
11035
|
+
const idKey = this.groupNodeKey();
|
|
11036
|
+
const cycle = this.currentNodes().find(c => c['@id'] === node['@id']);
|
|
11037
|
+
const index = (cycle?.[groupKey] || []).findIndex(n => n?.[idKey] === node[idKey]);
|
|
11038
|
+
return index >= 0 ? index : undefined;
|
|
11039
|
+
}, ...(ngDevMode ? [{ debugName: "jlogParentIndex" }] : []));
|
|
10108
11040
|
this.groupNodeValues = computed(() => unique(this.groupedNodes().map(value => value[this.groupNodeKey()])), ...(ngDevMode ? [{ debugName: "groupNodeValues" }] : []));
|
|
10109
11041
|
this.isGroupNode = computed(() => this.nodeKeyGroup() && this.groupedNodes()?.length > 0, ...(ngDevMode ? [{ debugName: "isGroupNode" }] : []));
|
|
10110
11042
|
this.isEmission = computed(() => this.selectedNodeKey() === BlankNodesKey.emissions, ...(ngDevMode ? [{ debugName: "isEmission" }] : []));
|
|
@@ -10136,6 +11068,13 @@ class CyclesNodesComponent {
|
|
|
10136
11068
|
this.selectedGroup.set(this.groupNodeValues()[0]);
|
|
10137
11069
|
}
|
|
10138
11070
|
});
|
|
11071
|
+
effect(() => {
|
|
11072
|
+
// keep the selected cycle index in range when the available cycles change (e.g. switching group),
|
|
11073
|
+
// otherwise the selected node becomes undefined and the view goes blank
|
|
11074
|
+
if (this.cycles().length > 0 && this.selectedIndex() >= this.cycles().length) {
|
|
11075
|
+
this.selectedIndex.set(0);
|
|
11076
|
+
}
|
|
11077
|
+
});
|
|
10139
11078
|
}
|
|
10140
11079
|
groupNodesByKey({ nodeKey }) {
|
|
10141
11080
|
const nodesPerCycle = groupNodesByTerm(this.cycles(), nodeKey, filterBlankNode$1(this.filterTerm()), this.hideZeroValues(), this.hideIdenticalValues());
|
|
@@ -10165,7 +11104,7 @@ class CyclesNodesComponent {
|
|
|
10165
11104
|
component.headerKeys.set(this.headerKeys());
|
|
10166
11105
|
}
|
|
10167
11106
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesNodesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10168
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesNodesComponent, isStandalone: true, selector: "he-cycles-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKeys: { classPropertyName: "nodeKeys", publicName: "nodeKeys", isSignal: true, isRequired: true, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "component", type: CyclesFunctionalUnitMeasureComponent, selector: "he-cycles-functional-unit-measure", inputs: ["cycle"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: CyclesEmissionsChartComponent, selector: "he-cycles-emissions-chart", inputs: ["cycles"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CyclesNodesTimelineComponent, selector: "he-cycles-nodes-timeline", inputs: ["values", "maxDate", "minDate"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11107
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CyclesNodesComponent, isStandalone: true, selector: "he-cycles-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKeys: { classPropertyName: "nodeKeys", publicName: "nodeKeys", isSignal: true, isRequired: true, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select\n another cycle above.\n </p>\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "component", type: CyclesFunctionalUnitMeasureComponent, selector: "he-cycles-functional-unit-measure", inputs: ["cycle"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: CyclesEmissionsChartComponent, selector: "he-cycles-emissions-chart", inputs: ["cycles"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CyclesNodesTimelineComponent, selector: "he-cycles-nodes-timeline", inputs: ["values", "maxDate", "minDate"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10169
11108
|
}
|
|
10170
11109
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CyclesNodesComponent, decorators: [{
|
|
10171
11110
|
type: Component$1,
|
|
@@ -10191,7 +11130,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
10191
11130
|
KeyToLabelPipe,
|
|
10192
11131
|
PrecisionPipe,
|
|
10193
11132
|
PluralizePipe
|
|
10194
|
-
], template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"] }]
|
|
11133
|
+
], template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n <span>{{ dataKey | keyToLabel }}</span>\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <a [href]=\"schemaBaseUrl + '/Cycle#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (cycle of cycles(); track cycle['@id']; let cycleIndex = $index) {\n <tr [class.is-suggested]=\"$any(cycle).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(cycle)\">\n <he-node-link [node]=\"cycleNode(cycle)\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(cycle).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ cycleIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(cycle) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [class.is-hidden]=\"isGroupNode()\">\n <he-cycles-functional-unit-measure [cycle]=\"cycle\" />\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let cycleData = node.value.values[cycle['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (cycleData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: cycleData, cycle, key: dataKey }\">\n <span pointer>\n {{ cycleData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"cycleData.node\"\n key=\"value\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice\n [dataState]=\"dataState()\"\n [showDeleted]=\"firstNodeKey() === BlankNodesKey.emissions\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n @if (showHideZeroValues()) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n }\n @if (cycles().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @switch (firstNodeKey()) {\n @case (BlankNodesKey.emissions) {\n <he-cycles-emissions-chart [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-emissions-chart>\n }\n }\n }\n @case (View.timeline) {\n <he-cycles-nodes-timeline\n [values]=\"timelineValues()\"\n [minDate]=\"selectedCycle().startDate\"\n [maxDate]=\"selectedCycle().endDate\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-cycles-nodes-timeline>\n }\n @case (View.logs) {\n <!-- keep the cycle selector visible even when the selected cycle has no grouped node (e.g. a cycle\n with no transformations under \"Transformation: Inputs\"), so the user can switch to one that has -->\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (selectedNode()) {\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedNode()\"\n [nodeKey]=\"selectedNodeKey()\"\n [logsKey]=\"selectedLogsKey()\"\n [jlogParentKey]=\"nodeKeyGroup()\"\n [jlogParentIndex]=\"jlogParentIndex()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\">\n @if (nodeKeys().length > 1) {\n <div class=\"tabs is-m-0\">\n <ul>\n @for (nodeKey of nodeKeys(); track nodeKey) {\n <li [class.is-active]=\"selectedNodeKey() === nodeKey\">\n <a (click)=\"selectedNodeKey.set(nodeKey)\">{{ nodeKey | keyToLabel }}</a>\n </li>\n }\n </ul>\n </div>\n }\n </he-node-logs-models>\n } @else if (isGroupNode()) {\n <p class=\"is-p-3 has-text-grey\">\n No recalculation logs for the selected {{ nodeKeyGroup() | pluralize: 1 }} in this cycle \u2014 select\n another cycle above.\n </p>\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectCycle()) {\n <ng-container *ngTemplateOutlet=\"selectCycle\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectCycle>\n @if (cycles().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectCycle\">Cycle</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectCycle\">\n @for (value of cycles(); track value; let cycleIndex = $index) {\n <option [value]=\"cycleIndex\">{{ cycleIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"cycle\" let-data=\"data\" let-key=\"key\">\n <p>\n <b>{{ defaultLabel(node) }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"key\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:106px;width:106px}\n"] }]
|
|
10195
11134
|
}], ctorParameters: () => [], propDecorators: { dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: false }] }], nodeKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKeys", required: true }] }], nodeKeyGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKeyGroup", required: false }] }] } });
|
|
10196
11135
|
|
|
10197
11136
|
class CyclesResultComponent {
|
|
@@ -14967,7 +15906,7 @@ class ImpactAssessmentsProductsComponent {
|
|
|
14967
15906
|
component.headerKeys.set(this.headerKeys());
|
|
14968
15907
|
}
|
|
14969
15908
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ImpactAssessmentsProductsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14970
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ImpactAssessmentsProductsComponent, isStandalone: true, selector: "he-impact-assessments-products", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, enableFilterMethodModel: { classPropertyName: "enableFilterMethodModel", publicName: "enableFilterMethodModel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <div class=\"is-hidden-tablet is-mt-3\">\n <ng-container *ngTemplateOutlet=\"filterModel\" />\n </div>\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto\"></th>\n <th></th>\n <th></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n @if (dataKey) {\n <span>{{ dataKey | keyToLabel }}</span>\n }\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right is-py-0\">\n <div class=\"is-hidden-mobile\">\n <ng-container *ngTemplateOutlet=\"filterModel\" />\n </div>\n </th>\n <th class=\"has-border-right\"></th>\n <th class=\"has-border-right\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\">\n <a [href]=\"schemaBaseUrl + '/ImpactAssessment#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n <th class=\"has-border-right\">\n <a [href]=\"schemaBaseUrl + '/ImpactAssessment#product'\" target=\"_blank\">Product</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (impactAssessment of impactAssessments(); track impactAssessment['@id']; let impactIndex = $index) {\n @let product = productTerm(impactAssessment);\n <tr [class.is-suggested]=\"$any(impactAssessment).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"impactName(impactAssessment)\">\n <he-node-link [node]=\"impactAssessment\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(impactAssessment).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ impactIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ impactName(impactAssessment) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [attr.title]=\"product?.units\">\n <span>1 {{ product?.units }}</span>\n </td>\n <td class=\"has-border-right\" [attr.title]=\"product?.name\">\n @if (product) {\n <he-node-link [node]=\"product\">\n <span>{{ product.name | ellipsis: 30 }}</span>\n </he-node-link>\n }\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let impactData = node.value.values[impactAssessment['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (impactData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{\n data: impactData,\n impactAssessment\n }\">\n <span pointer>\n {{ impactData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"impactData.node\"\n key=\"value\"\n [state]=\"impactAssessment.aggregated ? 'aggregated' : undefined\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n @if (impactAssessments().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n } @else if (noDataMessage()) {\n <div class=\"is-pt-3 has-text-centered\">\n <span>{{ noDataMessage() }}</span>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n <he-impact-assessments-indicators-chart [key]=\"nodeKey()\" [filterTermTypes]=\"filterTermTypes()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-impact-assessments-indicators-chart>\n }\n @case (View.breakdown) {\n @if (selectedNode()) {\n <he-impact-assessments-indicator-breakdown-chart\n [impactAssessment]=\"selectedNode()\"\n [indicators]=\"selectedRecalculatedValues()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-impact-assessments-indicator-breakdown-chart>\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedCycle()\"\n [nodeKey]=\"nodeKey()\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"filterTermTypesLabel()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [noDataMessage]=\"noDataMessage()\" />\n }\n }\n }\n}\n\n<ng-template #filterModel>\n @if (enableFilterMethodModel()) {\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"updateSelectedMethodModel($event.target.value)\">\n <option [ngValue]=\"undefined\">Filter Model</option>\n @for (term of methodModels(); track term) {\n <option [ngValue]=\"term\">{{ term.name }}</option>\n }\n </select>\n </div>\n }\n</ng-template>\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectImpact()) {\n <ng-container *ngTemplateOutlet=\"selectImpact\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectImpact>\n @if (impactAssessments().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectImpactAssessment\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectImpactAssessment\">\n @for (value of impactAssessments(); track value; let i = $index) {\n <option [value]=\"i\">{{ i + 1 }}. {{ impactName(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"impactAssessment\" let-data=\"data\">\n <p>\n <b>\n @if (data.cycle) {\n <span>{{ cycleLabel(node.cycle) }}</span>\n }\n @if (!data.cycle) {\n <span>{{ data.name }}</span>\n }\n </b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"nodeKey()\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:102px;width:102px}he-data-table ::ng-deep .table thead tr th:nth-child(3),he-data-table ::ng-deep .table tbody tr td:nth-child(3){min-width:110px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: ImpactAssessmentsIndicatorsChartComponent, selector: "he-impact-assessments-indicators-chart", inputs: ["key", "filterTermTypes"] }, { kind: "component", type: ImpactAssessmentsIndicatorBreakdownChartComponent, selector: "he-impact-assessments-indicator-breakdown-chart", inputs: ["impactAssessment", "indicators"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
15909
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ImpactAssessmentsProductsComponent, isStandalone: true, selector: "he-impact-assessments-products", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, enableFilterMethodModel: { classPropertyName: "enableFilterMethodModel", publicName: "enableFilterMethodModel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <div class=\"is-hidden-tablet is-mt-3\">\n <ng-container *ngTemplateOutlet=\"filterModel\" />\n </div>\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n @if (dataKeys().length > 1) {\n <tr class=\"has-text-weight-bold\">\n <th class=\"width-auto\"></th>\n <th></th>\n <th></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @let blankNodesCount = countGroupVisibleNodes(blankNodes);\n @if (blankNodesCount > 0) {\n <th [attr.colspan]=\"blankNodesCount\" [class.has-border-right]=\"!dataKeyLast\">\n @if (dataKey) {\n <span>{{ dataKey | keyToLabel }}</span>\n }\n </th>\n }\n }\n </tr>\n }\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right is-py-0\">\n <div class=\"is-hidden-mobile\">\n <ng-container *ngTemplateOutlet=\"filterModel\" />\n </div>\n </th>\n <th class=\"has-border-right\"></th>\n <th class=\"has-border-right\"></th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.name\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"\n node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\n \"></span>\n </he-node-link>\n </th>\n }\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\">\n <a [href]=\"schemaBaseUrl + '/ImpactAssessment#functionalUnit'\" target=\"_blank\">Functional unit</a>\n </th>\n <th class=\"has-border-right\">\n <a [href]=\"schemaBaseUrl + '/ImpactAssessment#product'\" target=\"_blank\">Product</a>\n </th>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n <th\n [attr.title]=\"node.value.term.units\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (impactAssessment of impactAssessments(); track impactAssessment['@id']; let impactIndex = $index) {\n @let product = productTerm(impactAssessment);\n <tr [class.is-suggested]=\"$any(impactAssessment).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"impactName(impactAssessment)\">\n <he-node-link [node]=\"impactAssessment\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(impactAssessment).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ impactIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ impactName(impactAssessment) }}</span>\n </span>\n </he-node-link>\n </td>\n <td class=\"has-border-right\" [attr.title]=\"product?.units\">\n <span>1 {{ product?.units }}</span>\n </td>\n <td class=\"has-border-right\" [attr.title]=\"product?.name\">\n @if (product) {\n <he-node-link [node]=\"product\">\n <span>{{ product.name | ellipsis: 30 }}</span>\n </he-node-link>\n }\n </td>\n @for (dataKey of dataKeys(); track dataKey; let dataKeyLast = $last) {\n @let blankNodes = data()[dataKey];\n @for (node of blankNodes; track node.value.term.name; let nodeLast = $last) {\n @if (node.value.visible) {\n @let impactData = node.value.values[impactAssessment['@id']];\n <td\n class=\"is-nowrap\"\n [class.has-border-right]=\"dataKeys().length > 1 && !dataKeyLast && nodeLast\">\n @if (impactData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{\n data: impactData,\n impactAssessment\n }\">\n <span pointer>\n {{ impactData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"impactData.node\"\n key=\"value\"\n [state]=\"impactAssessment.aggregated ? 'aggregated' : undefined\" />\n </span>\n } @else {\n <span>-</span>\n }\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n @if (impactAssessments().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n } @else if (noDataMessage()) {\n <div class=\"is-pt-3 has-text-centered\">\n <span>{{ noDataMessage() }}</span>\n </div>\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n <he-impact-assessments-indicators-chart [key]=\"nodeKey()\" [filterTermTypes]=\"filterTermTypes()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-impact-assessments-indicators-chart>\n }\n @case (View.breakdown) {\n @if (selectedNode()) {\n <he-impact-assessments-indicator-breakdown-chart\n [impactAssessment]=\"selectedNode()\"\n [indicators]=\"selectedRecalculatedValues()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-impact-assessments-indicator-breakdown-chart>\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [cycle]=\"selectedCycle()\"\n [nodeKey]=\"nodeKey()\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"filterTermTypesLabel()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [noDataMessage]=\"noDataMessage()\" />\n }\n }\n }\n}\n\n<ng-template #filterModel>\n @if (enableFilterMethodModel()) {\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"updateSelectedMethodModel($event.target.value)\">\n <option [ngValue]=\"undefined\">Filter Model</option>\n @for (term of methodModels(); track term) {\n <option [ngValue]=\"term\">{{ term.name }}</option>\n }\n </select>\n </div>\n }\n</ng-template>\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectImpact()) {\n <ng-container *ngTemplateOutlet=\"selectImpact\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectImpact>\n @if (impactAssessments().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary is-nowrap\" for=\"selectImpactAssessment\">Impact Assessment</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectImpactAssessment\">\n @for (value of impactAssessments(); track value; let i = $index) {\n <option [value]=\"i\">{{ i + 1 }}. {{ impactName(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #details let-node=\"impactAssessment\" let-data=\"data\">\n <p>\n <b>\n @if (data.cycle) {\n <span>{{ cycleLabel(node.cycle) }}</span>\n }\n @if (!data.cycle) {\n <span>{{ data.name }}</span>\n }\n </b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"nodeKey()\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}he-data-table ::ng-deep .table thead tr th:nth-child(2),he-data-table ::ng-deep .table tbody tr td:nth-child(2){max-width:102px;width:102px}he-data-table ::ng-deep .table thead tr th:nth-child(3),he-data-table ::ng-deep .table tbody tr td:nth-child(3){min-width:110px}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "component", type: ImpactAssessmentsIndicatorsChartComponent, selector: "he-impact-assessments-indicators-chart", inputs: ["key", "filterTermTypes"] }, { kind: "component", type: ImpactAssessmentsIndicatorBreakdownChartComponent, selector: "he-impact-assessments-indicator-breakdown-chart", inputs: ["impactAssessment", "indicators"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14971
15910
|
}
|
|
14972
15911
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ImpactAssessmentsProductsComponent, decorators: [{
|
|
14973
15912
|
type: Component$1,
|
|
@@ -15559,7 +16498,7 @@ class SitesNodesComponent {
|
|
|
15559
16498
|
component.headerKeys.set(this.headerKeys());
|
|
15560
16499
|
}
|
|
15561
16500
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SitesNodesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
15562
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: SitesNodesComponent, isStandalone: true, selector: "he-sites-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, enableChart: { classPropertyName: "enableChart", publicName: "enableChart", isSignal: true, isRequired: false, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ groupNodeDisplayNames()[value] || value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n <th [attr.title]=\"node.value.term.name\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\"></span>\n </he-node-link>\n </th>\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n <th [attr.title]=\"node.value.term.units\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (site of sites(); track site['@id']; let siteIndex = $index) {\n <tr [class.is-suggested]=\"$any(site).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(site)\">\n <he-node-link [node]=\"site\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(site).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ siteIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(site) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n @let siteData = node.value.values[site['@id']];\n <td class=\"is-nowrap\">\n @if (siteData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: siteData, site }\">\n <span pointer>\n {{ siteData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"siteData.node\"\n key=\"value\" />\n </span>\n }\n @if (isMeasurement() && !siteData) {\n <span>\n <span>-</span>\n @if (siteTooBig(site)) {\n <sup class=\"pl-1\">(1)</sup>\n }\n </span>\n }\n </td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n @if (sites().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n @if (showAreaTooBig()) {\n <p class=\"is-size-7 is-italic\">\n (1) This region is >{{ maxAreaSize }}km2 and is too large to reliably gap fill Measurements.\n </p>\n }\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @if (nodeKey() === BlankNodesKey.management) {\n @if (selectedNode()) {\n <he-sites-management-chart [site]=\"selectedNode()\" [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-sites-management-chart>\n }\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"nodeKey() | capitalize\" />\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectSite()) {\n <ng-container *ngTemplateOutlet=\"selectSite\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectSite>\n @if (sites().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectSite\">Site</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectSite\">\n @for (value of sites(); track value; let siteIndex = $index) {\n <option [value]=\"siteIndex\">{{ siteIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #emptyValue>\n <span>-</span>\n</ng-template>\n\n<ng-template #details let-node=\"site\" let-data=\"data\">\n <p>\n <b>{{ node.name }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"nodeKey()\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}\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: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "component", type: SitesManagementChartComponent, selector: "he-sites-management-chart", inputs: ["site", "cycles"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }] }); }
|
|
16501
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: SitesNodesComponent, isStandalone: true, selector: "he-sites-nodes", inputs: { dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, enableChart: { classPropertyName: "enableChart", publicName: "enableChart", isSignal: true, isRequired: false, transformFunction: null }, nodeKeyGroup: { classPropertyName: "nodeKeyGroup", publicName: "nodeKeyGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isGroupNode()) {\n <div class=\"tabs is-mb-1 | group-nodes-tabs\">\n <ul>\n @for (value of groupNodeValues(); track value) {\n <li [class.is-active]=\"selectedGroup() === value\">\n <a (click)=\"selectedGroup.set(value)\">\n <span class=\"is-capitalized is-pr-1\">{{ nodeKeyGroup() | pluralize: 1 }}:</span>\n <span>{{ groupNodeDisplayNames()[value] || value }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (isNodeKeyAllowed()) {\n @switch (selectedView()) {\n @case (View.table) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n @if (hasData()) {\n <he-data-table class=\"is-mt-3 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr class=\"has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n <th [attr.title]=\"node.value.term.name\">\n <he-node-link [node]=\"node.value.term\">\n <span\n [innerHtml]=\"node.value.term.name | ellipsis: 30 | compound: node.value.term.termType\"></span>\n </he-node-link>\n </th>\n }\n }\n </tr>\n <tr class=\"is-italic has-text-weight-semibold\">\n <th class=\"width-auto has-border-right\"></th>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n <th [attr.title]=\"node.value.term.units\">\n <span [innerHtml]=\"node.value.term.units | compound\"></span>\n <he-terms-units-description class=\"is-inline-block is-ml-2\" [term]=\"node.value.term\" />\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (site of sites(); track site['@id']; let siteIndex = $index) {\n <tr [class.is-suggested]=\"$any(site).suggested\">\n <td class=\"width-auto has-border-right\" [attr.title]=\"defaultLabel(site)\">\n <he-node-link [node]=\"site\">\n <span class=\"has-text-ellipsis is-ellipsis-3\">\n @if ($any(site).suggested) {\n <he-svg-icon name=\"compare\" />\n } @else {\n <span>{{ siteIndex + 1 }}.</span>\n }\n <span class=\"is-pl-1\">{{ defaultLabel(site) }}</span>\n </span>\n </he-node-link>\n </td>\n @for (node of data(); track node.value.term.name) {\n @if (node.value.visible) {\n @let siteData = node.value.values[site['@id']];\n <td class=\"is-nowrap\">\n @if (siteData) {\n <span\n class=\"trigger-popover\"\n [ngbPopover]=\"details\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow is-overflow-visible\"\n placement=\"left bottom auto\"\n container=\"body\"\n [popoverContext]=\"{ data: siteData, site }\">\n <span pointer>\n {{ siteData.propertyValue | precision: 3 | default: '-' }}\n </span>\n <he-blank-node-state\n class=\"ml-1\"\n [dataState]=\"dataState()\"\n [node]=\"siteData.node\"\n key=\"value\" />\n </span>\n }\n @if (isMeasurement() && !siteData) {\n <span>\n <span>-</span>\n @if (siteTooBig(site)) {\n <sup class=\"pl-1\">(1)</sup>\n }\n </span>\n }\n </td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </he-data-table>\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-justify-content-space-between is-mt-2\">\n <he-blank-node-state-notice [dataState]=\"dataState()\" />\n <div class=\"is-flex is-flex-wrap-wrap is-gap-8\">\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideZeroValues'\"\n name=\"hideZeroValues\"\n [(ngModel)]=\"hideZeroValues\" />\n <label [for]=\"componentId() + 'hideZeroValues'\">\n <span>\n Hide\n <b>0</b>\n values\n </span>\n </label>\n </div>\n @if (sites().length > 1) {\n <div class=\"field is-relative is-mb-0\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"componentId() + 'hideIdenticalValues'\"\n name=\"hideIdenticalValues\"\n [(ngModel)]=\"hideIdenticalValues\" />\n <label [for]=\"componentId() + 'hideIdenticalValues'\">\n <span>Hide identical values</span>\n </label>\n </div>\n }\n </div>\n </div>\n @if (showAreaTooBig()) {\n <p class=\"is-size-7 is-italic\">\n (1) This region is >{{ maxAreaSize }}km2 and is too large to reliably gap fill Measurements.\n </p>\n }\n } @else {\n <div class=\"is-pt-3 has-text-centered\">\n <span>No data available</span>\n @if (filterTerm()) {\n <span class=\"is-pl-1\">matching your search criteria</span>\n }\n <span>.</span>\n @if (showSwitchToRecalculated()) {\n <span>\n Switch to\n <code>recalculated</code>\n version.\n </span>\n }\n </div>\n }\n }\n @case (View.chart) {\n @if (nodeKey() === BlankNodesKey.management) {\n @if (selectedNode()) {\n <he-sites-management-chart [site]=\"selectedNode()\" [cycles]=\"cycles()\">\n <ng-container *ngTemplateOutlet=\"selectView\" />\n </he-sites-management-chart>\n }\n }\n }\n @case (View.logs) {\n @if (selectedNode()) {\n <ng-container *ngTemplateOutlet=\"selectView\" />\n\n <he-node-logs-models\n [node]=\"selectedNode()\"\n [nodeKey]=\"nodeKey()\"\n [originalValues]=\"selectedOriginalValues()\"\n [recalculatedValues]=\"selectedRecalculatedValues()\"\n [filterTermTypes]=\"filterTermTypes()\"\n [filterTermTypesLabel]=\"nodeKey() | capitalize\" />\n }\n }\n }\n}\n\n<ng-template #selectView>\n <div class=\"is-flex is-gap-8 is-align-items-center is-justify-content-space-between\">\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (selectedView() === View.table) {\n @if (hasData()) {\n <button class=\"button is-small is-ghost is-p-2\" (click)=\"showDownload()\">\n <he-svg-icon name=\"download\" />\n </button>\n }\n\n <he-search-extend\n class=\"is-secondary\"\n collapsedClass=\"is-p-2\"\n placeholder=\"Filter terms by name\"\n (searchText)=\"filterTerm.set($event)\" />\n } @else if (showSelectSite()) {\n <ng-container *ngTemplateOutlet=\"selectSite\" />\n }\n </div>\n\n @if (views()?.length > 1) {\n <div class=\"field has-addons button-segments\">\n @for (view of views(); track view) {\n <div class=\"control\">\n <button\n class=\"button is-small\"\n [class.is-selected]=\"selectedView() === view\"\n (click)=\"selectedView.set(view)\">\n <he-svg-icon\n name=\"checkmark\"\n aria-hidden=\"true\"\n class=\"is-hidden-mobile\"\n [class.is-hidden-tablet]=\"selectedView() !== view\" />\n <he-svg-icon\n [name]=\"viewIcon[view]\"\n aria-hidden=\"true\"\n [class.is-hidden-tablet]=\"selectedView() === view\" />\n <span class=\"is-hidden-mobile\">{{ view }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #selectSite>\n @if (sites().length > 1) {\n <div class=\"field is-horizontal is-mb-0\">\n <div class=\"field-label is-normal\">\n <label class=\"label has-text-secondary\" for=\"selectSite\">Site</label>\n </div>\n <div class=\"field-body\">\n <div class=\"field\">\n <div class=\"control is-expanded\">\n <div class=\"select is-small is-fullwidth\">\n <select (change)=\"selectIndex($event)\" if=\"selectSite\">\n @for (value of sites(); track value; let siteIndex = $index) {\n <option [value]=\"siteIndex\">{{ siteIndex + 1 }}. {{ defaultLabel(value) }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #emptyValue>\n <span>-</span>\n</ng-template>\n\n<ng-template #details let-node=\"site\" let-data=\"data\">\n <p>\n <b>{{ node.name }}</b>\n </p>\n <he-node-value-details\n class=\"is-overflow-visible\"\n [data]=\"data\"\n [dataState]=\"dataState()\"\n [nodeType]=\"node['@type']\"\n [dataKey]=\"nodeKey()\"\n [aggregated]=\"node.aggregated\" />\n</ng-template>\n", styles: [":host{display:block}\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: SearchExtendComponent, selector: "he-search-extend", inputs: ["value", "disabled", "placeholder", "class", "collapsedClass"], outputs: ["valueChange", "searchText"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: TermsUnitsDescriptionComponent, selector: "he-terms-units-description", inputs: ["term", "iconTemplate"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: BlankNodeStateComponent, selector: "he-blank-node-state", inputs: ["dataState", "nodeType", "dataKey", "key", "node", "state", "linkClass"] }, { kind: "component", type: BlankNodeStateNoticeComponent, selector: "he-blank-node-state-notice", inputs: ["dataState", "showDeleted"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NodeLogsModelsComponent, selector: "he-node-logs-models", inputs: ["node", "nodeKey", "originalValues", "recalculatedValues", "terms", "filterTermTypes", "filterTermTypesLabel", "logsKey", "noDataMessage", "cycle", "jlogParentKey", "jlogParentIndex"] }, { kind: "component", type: NodeValueDetailsComponent, selector: "he-node-value-details", inputs: ["data", "nodeType", "dataState", "dataKey", "aggregated"] }, { kind: "component", type: SitesManagementChartComponent, selector: "he-sites-management-chart", inputs: ["site", "cycles"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }] }); }
|
|
15563
16502
|
}
|
|
15564
16503
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SitesNodesComponent, decorators: [{
|
|
15565
16504
|
type: Component$1,
|
|
@@ -15646,5 +16585,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
15646
16585
|
* Generated bundle index. Do not edit.
|
|
15647
16586
|
*/
|
|
15648
16587
|
|
|
15649
|
-
export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FileUploadErrorKeys, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HESvgIconComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalBarChartComponent, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorHasError, errorHasWarning, errorText, evaluateSuccess, exportAsSVG, exportFormats, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterError, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupChanged, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, guidePageId, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isMigrationError, isMissingOneOfError, isMissingPropertyError, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, locationQuery, logToCsv$2 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, missingNodeErrors, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
|
|
16588
|
+
export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FileUploadErrorKeys, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HESvgIconComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalBarChartComponent, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJLogModelsComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultSvgIconSize, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorHasError, errorHasWarning, errorText, evaluateSuccess, exportAsSVG, exportFormats, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterError, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupChanged, groupJLogByField, groupJLogByTerm, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, guidePageId, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, iconSizes, icons, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isMigrationError, isMissingOneOfError, isMissingPropertyError, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, jLogModelCount, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, loadSvgSprite, locationQuery, logToCsv$2 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, missingNodeErrors, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeId, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
|
|
15650
16589
|
//# sourceMappingURL=hestia-earth-ui-components.mjs.map
|