@hestia-earth/ui-components 0.42.12 → 0.42.14
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.
|
@@ -1784,11 +1784,11 @@ class BlankNodeValueDeltaComponent {
|
|
|
1784
1784
|
this.color = computed(() => this.displayType() === DeltaDisplayType.percent ? evaluateSuccess(this.delta()) : '', ...(ngDevMode ? [{ debugName: "color" }] : []));
|
|
1785
1785
|
}
|
|
1786
1786
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BlankNodeValueDeltaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1787
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: BlankNodeValueDeltaComponent, isStandalone: true, selector: "he-blank-node-value-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, originalValue: { classPropertyName: "originalValue", publicName: "originalValue", isSignal: true, isRequired: false, transformFunction: null }, displayType: { classPropertyName: "displayType", publicName: "displayType", isSignal: true, isRequired: false, transformFunction: null }, useCustomFunctions: { classPropertyName: "useCustomFunctions", publicName: "useCustomFunctions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!hide()) {\n <small class=\"has-text-{{ color() }}\">\n
|
|
1787
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: BlankNodeValueDeltaComponent, isStandalone: true, selector: "he-blank-node-value-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, originalValue: { classPropertyName: "originalValue", publicName: "originalValue", isSignal: true, isRequired: false, transformFunction: null }, displayType: { classPropertyName: "displayType", publicName: "displayType", isSignal: true, isRequired: false, transformFunction: null }, useCustomFunctions: { classPropertyName: "useCustomFunctions", publicName: "useCustomFunctions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!hide()) {\n @if (delta() === 0) {\n <!-- no difference between the values: a \"0 %\"/\"0\" delta carries no information, show a dash instead -->\n <small>-</small>\n } @else {\n <small class=\"has-text-{{ color() }}\">\n @if (delta() > 0) {\n <span>+</span>\n }\n @switch (displayType()) {\n @case (DeltaDisplayType.absolute) {\n <span>{{ delta() | precision: 3 }}</span>\n }\n @case (DeltaDisplayType.percent) {\n <span>{{ delta() | number: '1.0-2' }}</span>\n <span>%</span>\n }\n }\n </small>\n }\n}\n", styles: [""], dependencies: [{ kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1788
1788
|
}
|
|
1789
1789
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BlankNodeValueDeltaComponent, decorators: [{
|
|
1790
1790
|
type: Component$1,
|
|
1791
|
-
args: [{ selector: 'he-blank-node-value-delta', changeDetection: ChangeDetectionStrategy.OnPush, imports: [DecimalPipe, PrecisionPipe], template: "@if (!hide()) {\n <small class=\"has-text-{{ color() }}\">\n
|
|
1791
|
+
args: [{ selector: 'he-blank-node-value-delta', changeDetection: ChangeDetectionStrategy.OnPush, imports: [DecimalPipe, PrecisionPipe], template: "@if (!hide()) {\n @if (delta() === 0) {\n <!-- no difference between the values: a \"0 %\"/\"0\" delta carries no information, show a dash instead -->\n <small>-</small>\n } @else {\n <small class=\"has-text-{{ color() }}\">\n @if (delta() > 0) {\n <span>+</span>\n }\n @switch (displayType()) {\n @case (DeltaDisplayType.absolute) {\n <span>{{ delta() | precision: 3 }}</span>\n }\n @case (DeltaDisplayType.percent) {\n <span>{{ delta() | number: '1.0-2' }}</span>\n <span>%</span>\n }\n }\n </small>\n }\n}\n" }]
|
|
1792
1792
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], originalValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "originalValue", required: false }] }], displayType: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayType", required: false }] }], useCustomFunctions: [{ type: i0.Input, args: [{ isSignal: true, alias: "useCustomFunctions", required: false }] }] } });
|
|
1793
1793
|
|
|
1794
1794
|
const defaultIcon = 'clipboard';
|
|
@@ -9346,8 +9346,10 @@ const jLogModelColumns = (logs, nodeType, termId, isFailed) => (logs || [])
|
|
|
9346
9346
|
};
|
|
9347
9347
|
}, { columns: [], hasPreviousSuccess: false }).columns;
|
|
9348
9348
|
// `term.@id` defines the group; every other uniqueness field (including `key.@id`) distinguishes rows
|
|
9349
|
-
// within the group - Term-valued ones (key, inputs, country, landCover, methodModel, ...) become links
|
|
9350
|
-
|
|
9349
|
+
// within the group - Term-valued ones (key, inputs, country, landCover, methodModel, ...) become links.
|
|
9350
|
+
// `value` is the measured quantity (shown in the value column / as a "Field: value" sub-row), not a
|
|
9351
|
+
// distinguishing label - it is excluded so a row's identity reads e.g. "variety: ... · fate: ..."
|
|
9352
|
+
const excludedIdentityFields = ['term.@id', 'value'];
|
|
9351
9353
|
/**
|
|
9352
9354
|
* The fields (from the schema `uniquenessFields`) that distinguish two blank nodes sharing a term.
|
|
9353
9355
|
* Relations come from the type-keyed definition (e.g. `Emission` -> `inputs`); the scalar properties are
|
|
@@ -9399,16 +9401,24 @@ const identityFieldTerms = (value, field) => {
|
|
|
9399
9401
|
const noisyIdentityFields = ['methodClassification', 'methodDescription', 'method.@id', 'methodModel.@id'];
|
|
9400
9402
|
const isNoisyIdentityField = (field) => noisyIdentityFields.includes(field);
|
|
9401
9403
|
const identityWithout = (identity, predicate) => Object.fromEntries(Object.entries(identity).filter(([key]) => !predicate(key)));
|
|
9402
|
-
const
|
|
9403
|
-
// the scalar identities
|
|
9404
|
-
|
|
9404
|
+
const formatScalarValue = (value) => (Array.isArray(value) ? value.join(', ') : `${value}`);
|
|
9405
|
+
// the scalar identities, each linking its field name to its schema docs; `depthUpper`/`depthLower` are
|
|
9406
|
+
// combined into a single non-linked "depths: <upper>-<lower>" entry
|
|
9407
|
+
const buildIdentityScalars = (scalars) => {
|
|
9405
9408
|
const props = Object.entries(scalars);
|
|
9406
9409
|
const { depthUpper, depthLower } = Object.fromEntries(props);
|
|
9407
9410
|
const hasDepths = isPresent(depthUpper) && isPresent(depthLower);
|
|
9408
|
-
const depths = hasDepths ? [
|
|
9409
|
-
const rest = props
|
|
9410
|
-
|
|
9411
|
+
const depths = hasDepths ? [{ key: 'depths', value: `${depthUpper}-${depthLower}` }] : [];
|
|
9412
|
+
const rest = props
|
|
9413
|
+
.filter(([key]) => !(hasDepths && (key === 'depthUpper' || key === 'depthLower')))
|
|
9414
|
+
.map(([key, value]) => {
|
|
9415
|
+
const field = key.replace('.@id', '');
|
|
9416
|
+
return { key: field, value: formatScalarValue(value), field };
|
|
9417
|
+
});
|
|
9418
|
+
return [...depths, ...rest];
|
|
9411
9419
|
};
|
|
9420
|
+
// the scalar identities joined as text (a standalone label keeps just its key, e.g. "Cycle")
|
|
9421
|
+
const identityScalarsLabel = (scalars) => scalars.map(({ key, value }) => (value ? `${key}: ${value}` : key)).join(' · ');
|
|
9412
9422
|
// whether dropping the noisy method fields still gives every row a distinct identity
|
|
9413
9423
|
const noisyFieldsRedundant = (rows) => new Set(rows.map(row => identityKey(identityWithout(row.identity, isNoisyIdentityField)))).size === rows.length;
|
|
9414
9424
|
// segment fields shown first (e.g. an emission's `inputs` before its `landCover`/`previousLandCover`);
|
|
@@ -9418,7 +9428,8 @@ const segmentFieldRank = (field) => {
|
|
|
9418
9428
|
const index = segmentFieldOrder.indexOf(field);
|
|
9419
9429
|
return index === -1 ? segmentFieldOrder.length : index;
|
|
9420
9430
|
};
|
|
9421
|
-
// split a row's identity into Term-link segments (any field whose value is a Term) and
|
|
9431
|
+
// split a row's identity into Term-link segments (any field whose value is a Term) and scalar `key: value`
|
|
9432
|
+
// entries (their field name linking to the schema docs)
|
|
9422
9433
|
const identityDisplay = (identity, value) => {
|
|
9423
9434
|
const segments = [];
|
|
9424
9435
|
const scalars = {};
|
|
@@ -9436,19 +9447,20 @@ const identityDisplay = (identity, value) => {
|
|
|
9436
9447
|
.map((segment, index) => ({ segment, index }))
|
|
9437
9448
|
.sort((a, b) => segmentFieldRank(a.segment.field) - segmentFieldRank(b.segment.field) || a.index - b.index)
|
|
9438
9449
|
.map(({ segment }) => segment);
|
|
9439
|
-
return { segments: orderedSegments,
|
|
9450
|
+
return { segments: orderedSegments, scalars: buildIdentityScalars(scalars) };
|
|
9440
9451
|
};
|
|
9441
9452
|
// the raw blank node value used to derive the fallback identity (logs/`failed` rows have no value)
|
|
9442
9453
|
const rowRawValue = (row) => row.recalculated[0] || row.original[0] || {};
|
|
9443
9454
|
// top-level fields skipped when looking for a fallback identity: the group key (`term`), JSON-LD
|
|
9444
|
-
// metadata (`@type`/`@id`), change-tracking (`added`/`updated`/`removed` and their `Version` siblings)
|
|
9445
|
-
//
|
|
9455
|
+
// metadata (`@type`/`@id`), change-tracking (`added`/`updated`/`removed` and their `Version` siblings),
|
|
9456
|
+
// the nested `logs`, and the measured `value` (shown in the value column, never a distinguishing label)
|
|
9446
9457
|
const fallbackExcludedKeys = new Set([
|
|
9447
9458
|
'term',
|
|
9448
9459
|
'@type',
|
|
9449
9460
|
'@id',
|
|
9450
9461
|
'type',
|
|
9451
9462
|
'id',
|
|
9463
|
+
'value',
|
|
9452
9464
|
'logs',
|
|
9453
9465
|
'added',
|
|
9454
9466
|
'addedVersion',
|
|
@@ -9492,8 +9504,8 @@ const fallbackIdentity = (row, keys) => {
|
|
|
9492
9504
|
const cycleOwnerFields = ['transformation', 'animal'];
|
|
9493
9505
|
const isCycleOwnedRow = (row) => cycleOwnerFields.every(key => !isPresent(rowRawValue(row)[key]));
|
|
9494
9506
|
const hasCycleOwnerSibling = (rows) => rows.some(row => cycleOwnerFields.some(key => isPresent(rowRawValue(row)[key])));
|
|
9495
|
-
const isNonEmptyIdentity = ({ segments,
|
|
9496
|
-
const emptyIdentity = { segments: [],
|
|
9507
|
+
const isNonEmptyIdentity = ({ segments, scalars }) => segments.length > 0 || scalars.length > 0;
|
|
9508
|
+
const emptyIdentity = { segments: [], scalars: [] };
|
|
9497
9509
|
// pick the first non-empty identity for a row, in order of preference:
|
|
9498
9510
|
// 1. the schema-uniqueness fields,
|
|
9499
9511
|
// 2. a fallback built from the keys that actually differ across the group's raw values,
|
|
@@ -9504,7 +9516,7 @@ const resolveRowIdentity = (row, fallbackKeys, keepNoisy, cycleOwned) => {
|
|
|
9504
9516
|
const candidates = [
|
|
9505
9517
|
identityDisplay(keepNoisy ? row.identity : identityWithout(row.identity, isNoisyIdentityField), value),
|
|
9506
9518
|
identityDisplay(fallbackIdentity(row, fallbackKeys), value),
|
|
9507
|
-
{ segments: [],
|
|
9519
|
+
{ segments: [], scalars: cycleOwned && isCycleOwnedRow(row) ? [{ key: 'Cycle', value: '' }] : [] }
|
|
9508
9520
|
];
|
|
9509
9521
|
return candidates.find(isNonEmptyIdentity) ?? emptyIdentity;
|
|
9510
9522
|
};
|
|
@@ -9515,8 +9527,8 @@ const withRowLabels = (group) => {
|
|
|
9515
9527
|
return {
|
|
9516
9528
|
...group,
|
|
9517
9529
|
rows: group.rows.map(row => {
|
|
9518
|
-
const { segments,
|
|
9519
|
-
return { ...row, identitySegments: segments, identityLabel:
|
|
9530
|
+
const { segments, scalars } = resolveRowIdentity(row, fallbackKeys, keepNoisy, cycleOwned);
|
|
9531
|
+
return { ...row, identitySegments: segments, identityScalars: scalars, identityLabel: identityScalarsLabel(scalars) };
|
|
9520
9532
|
})
|
|
9521
9533
|
};
|
|
9522
9534
|
};
|
|
@@ -9524,6 +9536,7 @@ const emptySubRow = () => ({
|
|
|
9524
9536
|
index: 0,
|
|
9525
9537
|
identity: {},
|
|
9526
9538
|
identityLabel: '',
|
|
9539
|
+
identityScalars: [],
|
|
9527
9540
|
identitySegments: [],
|
|
9528
9541
|
originalValue: null,
|
|
9529
9542
|
isOriginal: false,
|
|
@@ -9659,13 +9672,25 @@ const configModelStatus = (methodId, valueModelId, isRecalculated, hasOriginal)
|
|
|
9659
9672
|
// the `logs` entry that targets the value: the recorded model when present, otherwise (the value was
|
|
9660
9673
|
// recalculated but the recorded model isn't in the logs - e.g. `hestiaAggregatedData` is computed by the
|
|
9661
9674
|
// `linkedImpactAssessment` orchestrator) the first run that actually set the value
|
|
9662
|
-
const selectValueLog = (logs, valueModelId, isValueLog, isRecalculated) =>
|
|
9663
|
-
(
|
|
9664
|
-
|
|
9665
|
-
|
|
9675
|
+
const selectValueLog = (logs, valueModelId, isValueLog, isRecalculated) => {
|
|
9676
|
+
// the recorded model may have several runs (different orchestrators sharing one model id, e.g. `hestia`
|
|
9677
|
+
// via both `soilTextureComposition` and `soilMeasurement`): prefer the run that actually executed
|
|
9678
|
+
// (`should_run: true`) over one that was skipped (the value already existed), so we lock onto the
|
|
9679
|
+
// orchestrator that produced the value rather than a skipped sibling that would show the row as failed
|
|
9680
|
+
const byModel = logs.filter((log) => log?.model === valueModelId && isValueLog(log));
|
|
9681
|
+
return (byModel.find((log) => log?.should_run === true) ||
|
|
9682
|
+
byModel[0] ||
|
|
9683
|
+
(isRecalculated
|
|
9684
|
+
? logs.find((log) => isValueLog(log) && log?.should_run === true) ||
|
|
9685
|
+
logs.find((log) => isValueLog(log) && log?.orchestrator?.should_run)
|
|
9686
|
+
: undefined));
|
|
9687
|
+
};
|
|
9666
9688
|
// model ids in display order: config models first, then any logged models, with "not relevant" models
|
|
9667
9689
|
// (the actual outcome) pulled to the front
|
|
9668
9690
|
const orderValueModelIds = (configModelIds, logModels) => [...new Set([...configModelIds, ...logModels.map(model => model.methodId)])].sort((a, b) => Number(isNotRelevantModel(b)) - Number(isNotRelevantModel(a)));
|
|
9691
|
+
// the logged runs for each model id, in log order: a model may run for one value under several
|
|
9692
|
+
// orchestrators (e.g. `hestia` via `soilTextureComposition` and `soilMeasurement`), each its own column
|
|
9693
|
+
const logRunsByMethodId = (logModels) => logModels.reduce((map, run) => map.set(run.methodId, [...(map.get(run.methodId) || []), run]), new Map());
|
|
9669
9694
|
// apply `update` to the model that set the value (matched by id) when `condition` holds, leaving the rest
|
|
9670
9695
|
const mapValueModel = (models, valueModelId, condition, update) => models.map(model => (model.methodId === valueModelId && condition(model) ? update(model) : model));
|
|
9671
9696
|
/**
|
|
@@ -9696,7 +9721,12 @@ splitParallelModels = false) => {
|
|
|
9696
9721
|
const isValueLog = (log) => !isBackgroundLog(log) && !isSubRowOrchestrator(log?.orchestrator?.value, subRowValues);
|
|
9697
9722
|
const valueLog = selectValueLog(logs, valueModelId, isValueLog, isRecalculated);
|
|
9698
9723
|
const valueOrchestrator = valueLog?.orchestrator?.value;
|
|
9699
|
-
|
|
9724
|
+
// the value's model runs: the winning orchestrator's runs (its fallback hierarchy), plus any other run
|
|
9725
|
+
// by the recorded value model targeting the value - the same model can run for one measurement under
|
|
9726
|
+
// several orchestrators (e.g. `hestia` via both `soilTextureComposition`, which skipped, and
|
|
9727
|
+
// `soilMeasurement`, which succeeded), each shown as its own "Model N" column rather than just the winner
|
|
9728
|
+
const matchesValueOrchestrator = (log) => !isBackgroundLog(log) &&
|
|
9729
|
+
(log?.orchestrator?.value === valueOrchestrator || (log?.model === valueModelId && isValueLog(log)));
|
|
9700
9730
|
// keep the parallel grouping (a nested `logs` array): parallel siblings are independent, so a model
|
|
9701
9731
|
// that did not run failed rather than being "skipped" by a sibling that ran (a higher-tier hierarchy
|
|
9702
9732
|
// model). `jLogModelColumns` applies the pre-group success state to each parallel sibling; flatten the
|
|
@@ -9728,9 +9758,12 @@ splitParallelModels = false) => {
|
|
|
9728
9758
|
const configModelIds = !valueIsNotRelevant && config && configModelKeys.includes(nodeKey) && !configModelsParallel(config, termId, nodeKey)
|
|
9729
9759
|
? configModelsForTerm(config, termId, nodeKey)
|
|
9730
9760
|
: [];
|
|
9731
|
-
const
|
|
9732
|
-
|
|
9733
|
-
|
|
9761
|
+
const logRuns = logRunsByMethodId(logModels);
|
|
9762
|
+
// each model id expands to all its logged runs (a model may run under several orchestrators), or a
|
|
9763
|
+
// single synthetic run when it only appears in the config (a could-have-run model)
|
|
9764
|
+
const models = orderValueModelIds(configModelIds, logModels).flatMap(methodId => logRuns.get(methodId) || [
|
|
9765
|
+
syntheticModelRun(methodId, configModelStatus(methodId, valueModelId, isRecalculated, hasOriginal), nodeType, termId)
|
|
9766
|
+
]);
|
|
9734
9767
|
// the value model (e.g. a measured method gap-filled this run) is not always in the logs or config
|
|
9735
9768
|
const baseModels = models.length || !valueModelId || valueFromOriginal
|
|
9736
9769
|
? models
|
|
@@ -9763,13 +9796,20 @@ const blankNodeSubRows = (entry, value, originalValue, nodeType, type, termId, g
|
|
|
9763
9796
|
const fields = entries
|
|
9764
9797
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isFieldEntry(entryItem))
|
|
9765
9798
|
.map(([key, nested]) => fieldSubRow(key, nested, value, originalValue, nodeType, termId, type));
|
|
9799
|
+
// fields whose runs only exist as flat dotted-orchestrator logs (no nested entry), e.g. a duplicated
|
|
9800
|
+
// product's `product.price`/`product.economicValueShare`, shown alongside the nested field sub-rows
|
|
9801
|
+
const flatFields = flatFieldSubRows(entry, value, originalValue, nodeType, type);
|
|
9766
9802
|
const properties = entries
|
|
9767
9803
|
.filter(entryItem => !isFailedFieldEntry(entryItem) && isPropertyEntry(entryItem))
|
|
9768
9804
|
.flatMap(([key, nested]) => nestedBlankNodeSubRows(key, nested, value, nodeType));
|
|
9805
|
+
// a term can appear in both `properties` (a model added it) and `<field>-failed` (another model failed to
|
|
9806
|
+
// add it): it was added, so drop the redundant failed sub-row (also avoids a duplicate row for the term)
|
|
9807
|
+
const addedTermIds = new Set(properties.map(subRow => subRow.termId));
|
|
9769
9808
|
const failed = entries
|
|
9770
9809
|
.filter(isFailedFieldEntry)
|
|
9771
|
-
.flatMap(([key, nested]) => failedNestedSubRows(key, nested, nodeType, getTerm))
|
|
9772
|
-
|
|
9810
|
+
.flatMap(([key, nested]) => failedNestedSubRows(key, nested, nodeType, getTerm))
|
|
9811
|
+
.filter(subRow => !addedTermIds.has(subRow.termId));
|
|
9812
|
+
return [...fields, ...flatFields, ...properties, ...failed];
|
|
9773
9813
|
};
|
|
9774
9814
|
/**
|
|
9775
9815
|
* An input's background-emission models (`methodTier: background`), grouped under a single
|
|
@@ -9806,11 +9846,72 @@ const isSubFieldSuffix = (suffix, entry, value) => suffix === 'properties' ||
|
|
|
9806
9846
|
// `cycle`/`practice.landCover`, `cycle`/`animal.milkYield`) - unlike a same-node sub-field run
|
|
9807
9847
|
// (`product.price`, `input.properties`). Shown as a "Field: value" sub-row so the main row keeps just its
|
|
9808
9848
|
// expand toggle, rather than the value appearing with no model at all.
|
|
9809
|
-
const valueRunLogs = (entry, value) =>
|
|
9849
|
+
const valueRunLogs = (entry, value) =>
|
|
9850
|
+
// a dotted orchestrator only set the blank node's own value when the value was actually (re)set this run.
|
|
9851
|
+
// When the value was retained, the dotted logs are field runs (e.g. a product's `product.price`), surfaced
|
|
9852
|
+
// as field sub-rows (`flatFieldSubRows`) rather than mistaken for the value run
|
|
9853
|
+
valueChanged(value)
|
|
9854
|
+
? (entry?.logs || []).flat().filter((log) => {
|
|
9855
|
+
const orchestratorValue = log?.orchestrator?.value;
|
|
9856
|
+
return (!!orchestratorValue &&
|
|
9857
|
+
orchestratorValue.includes('.') &&
|
|
9858
|
+
!isSubFieldSuffix(orchestratorValue.split('.').pop(), entry, value));
|
|
9859
|
+
})
|
|
9860
|
+
: [];
|
|
9861
|
+
// the suffix of a dotted orchestrator value (`<context>.<suffix>`, e.g. `product.price` -> `price`), or null
|
|
9862
|
+
const dottedOrchestratorSuffix = (log) => {
|
|
9810
9863
|
const orchestratorValue = log?.orchestrator?.value;
|
|
9811
|
-
return
|
|
9812
|
-
orchestratorValue.
|
|
9813
|
-
|
|
9864
|
+
return typeof orchestratorValue === 'string' && orchestratorValue.includes('.')
|
|
9865
|
+
? orchestratorValue.split('.').pop()
|
|
9866
|
+
: null;
|
|
9867
|
+
};
|
|
9868
|
+
/**
|
|
9869
|
+
* Sub-field model runs that only appear as flat dotted-orchestrator logs on the entry (e.g. a product whose
|
|
9870
|
+
* `price`/`currency`/`economicValueShare`/`primary` runs are logged as `product.<field>` in the top-level
|
|
9871
|
+
* `logs`, with no nested entry of their own). Each distinct suffix becomes a "Field: <suffix>" sub-row
|
|
9872
|
+
* carrying its runs. Suffixes already covered by a nested entry key, the node's own value run, or
|
|
9873
|
+
* `value`/`properties` are left out (those have their own sub-row path).
|
|
9874
|
+
*/
|
|
9875
|
+
const flatFieldSubRows = (entry, value, originalValue, nodeType, type) => {
|
|
9876
|
+
const nestedKeys = new Set(Object.keys(entry || {}));
|
|
9877
|
+
const valueRunSuffixes = new Set(valueRunLogs(entry, value).map(dottedOrchestratorSuffix));
|
|
9878
|
+
const updated = [...(value?.added || []), ...(value?.updated || [])];
|
|
9879
|
+
// a suffix has its own field sub-row unless it is the value/properties run, a nested entry (its own
|
|
9880
|
+
// sub-row path), or the node's value run (surfaced as a "value" sub-row)
|
|
9881
|
+
const isFlatFieldSuffix = (suffix) => !!suffix && !['value', 'properties'].includes(suffix) && !nestedKeys.has(suffix) && !valueRunSuffixes.has(suffix);
|
|
9882
|
+
const bySuffix = (entry?.logs || []).flat().reduce((map, log) => {
|
|
9883
|
+
const suffix = dottedOrchestratorSuffix(log);
|
|
9884
|
+
return isFlatFieldSuffix(suffix) ? map.set(suffix, [...(map.get(suffix) || []), log]) : map;
|
|
9885
|
+
}, new Map());
|
|
9886
|
+
return [...bySuffix.entries()].map(([suffix, logs]) => ({
|
|
9887
|
+
...emptySubRow(),
|
|
9888
|
+
key: suffix,
|
|
9889
|
+
termId: suffix,
|
|
9890
|
+
type,
|
|
9891
|
+
originalValue: scalarValue(originalValue?.[suffix]),
|
|
9892
|
+
recalculatedValue: scalarValue(value?.[suffix]),
|
|
9893
|
+
isOriginal: typeof originalValue?.[suffix] !== 'undefined',
|
|
9894
|
+
isRecalculated: updated.includes(suffix),
|
|
9895
|
+
models: jLogModelRuns(logs, nodeType, suffix, false)
|
|
9896
|
+
}));
|
|
9897
|
+
};
|
|
9898
|
+
// a scalar "Field:" sub-row (e.g. price, revenue) - not a nested property, Background Data or value row
|
|
9899
|
+
const isFieldSubRow = (subRow) => !['property', 'backgroundData', 'value'].includes(subRow.key);
|
|
9900
|
+
// the "Field: value" sub-row for a blank node's own value, carrying the model run(s) that set it
|
|
9901
|
+
const buildValueSubRow = (value, originalValue, termId, type, models) => ({
|
|
9902
|
+
...emptySubRow(),
|
|
9903
|
+
key: 'value',
|
|
9904
|
+
termId: 'value',
|
|
9905
|
+
// carry the blank node type so the "value" label links to the schema (`/<Type>#value`), matching the
|
|
9906
|
+
// generic `fieldSubRow` path (e.g. a transformation input's nested `value.logs` run)
|
|
9907
|
+
type,
|
|
9908
|
+
// the value is resolved like the main row (`propertyValue` unwraps the `[n]` array form), not as a
|
|
9909
|
+
// raw scalar - so the sub-row shows the same recalculated value rather than "-"
|
|
9910
|
+
originalValue: originalValue ? propertyValue$1(originalValue.value, termId) : null,
|
|
9911
|
+
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9912
|
+
isOriginal: typeof originalValue?.value !== 'undefined',
|
|
9913
|
+
isRecalculated: valueChanged(value),
|
|
9914
|
+
models
|
|
9814
9915
|
});
|
|
9815
9916
|
const valueFieldSubRow = (entry, value, originalValue, nodeType, termId, type) => {
|
|
9816
9917
|
// only when the node records no value model of its own (otherwise the main row already shows it): surface
|
|
@@ -9820,21 +9921,7 @@ const valueFieldSubRow = (entry, value, originalValue, nodeType, termId, type) =
|
|
|
9820
9921
|
const logs = valueRunLogs(entry, value);
|
|
9821
9922
|
if (!logs.length)
|
|
9822
9923
|
return null;
|
|
9823
|
-
return
|
|
9824
|
-
...emptySubRow(),
|
|
9825
|
-
key: 'value',
|
|
9826
|
-
termId: 'value',
|
|
9827
|
-
// carry the blank node type so the "value" label links to the schema (`/<Type>#value`), matching the
|
|
9828
|
-
// generic `fieldSubRow` path (e.g. a transformation input's nested `value.logs` run)
|
|
9829
|
-
type,
|
|
9830
|
-
// the value is resolved like the main row (`propertyValue` unwraps the `[n]` array form), not as a
|
|
9831
|
-
// raw scalar - so the sub-row shows the same recalculated value rather than "-"
|
|
9832
|
-
originalValue: originalValue ? propertyValue$1(originalValue.value, termId) : null,
|
|
9833
|
-
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9834
|
-
isOriginal: typeof originalValue?.value !== 'undefined',
|
|
9835
|
-
isRecalculated: valueChanged(value),
|
|
9836
|
-
models: jLogModelRuns(logs, nodeType, termId, false)
|
|
9837
|
-
};
|
|
9924
|
+
return buildValueSubRow(value, originalValue, termId, type, jLogModelRuns(logs, nodeType, termId, false));
|
|
9838
9925
|
};
|
|
9839
9926
|
// every sub-row of a (non-failed) blank node: its own value run (when set by a model not recorded on the
|
|
9840
9927
|
// node), its field/property sub-rows, plus - for an input - the "Background Data" sub-row of background runs
|
|
@@ -9880,6 +9967,7 @@ const failedBlankNodeContent = (entry, nodeType, termId) => {
|
|
|
9880
9967
|
recalculatedValue: null,
|
|
9881
9968
|
identity: {},
|
|
9882
9969
|
identityLabel: '',
|
|
9970
|
+
identityScalars: [],
|
|
9883
9971
|
identitySegments: [],
|
|
9884
9972
|
subRows: [],
|
|
9885
9973
|
isRecalculated: false,
|
|
@@ -9894,15 +9982,28 @@ const failedBlankNodeContent = (entry, nodeType, termId) => {
|
|
|
9894
9982
|
const foldLoneValueSubRow = (subRows, models) => !models.length && subRows.length === 1 && subRows[0].key === 'value'
|
|
9895
9983
|
? { subRows: [], models: subRows[0].models }
|
|
9896
9984
|
: { subRows, models };
|
|
9985
|
+
// the blank node's sub-rows and main-row models. When the value was set by a model AND the node's only
|
|
9986
|
+
// sub-rows are scalar "Field:" rows (e.g. price, revenue, economicValueShare), surface the value as its
|
|
9987
|
+
// own first "Field: value" sub-row (moving its model off the main row), so it sits alongside the other
|
|
9988
|
+
// fields rather than only on the main row. Nodes with nested sub-rows (properties / Background Data) keep
|
|
9989
|
+
// the value model on the main row, and a value sub-row already produced for a cross-context run (see
|
|
9990
|
+
// `valueFieldSubRow`) is left as is.
|
|
9991
|
+
const subRowsAndModels = (value, originalValue, termId, type, valueModels, rawSubRows) => {
|
|
9992
|
+
const surfaceValue = valueModels.length > 0 && rawSubRows.length > 0 && rawSubRows.every(subRow => isFieldSubRow(subRow));
|
|
9993
|
+
return foldLoneValueSubRow(surfaceValue ? [buildValueSubRow(value, originalValue, termId, type, valueModels), ...rawSubRows] : rawSubRows, surfaceValue ? [] : valueModels);
|
|
9994
|
+
};
|
|
9897
9995
|
// a regular blank node: its identity, sub-rows and the model(s) that set the value (or none when retained)
|
|
9898
9996
|
const valueBlankNodeContent = (entry, value, originalValue, termId, { nodeType, type, nodeKey, config, getTerm }) => {
|
|
9899
9997
|
const spec = identitySpec(type, nodeType, nodeKey);
|
|
9900
|
-
const
|
|
9998
|
+
const valueModels = valueModelRuns(entry, value, originalValue, nodeType, termId, nodeKey, config, modelIsUniquenessField(spec));
|
|
9999
|
+
const rawSubRows = allSubRows(entry, value, originalValue, nodeType, type, termId, getTerm || defaultGetTerm);
|
|
10000
|
+
const { subRows, models } = subRowsAndModels(value, originalValue, termId, type, valueModels, rawSubRows);
|
|
9901
10001
|
return {
|
|
9902
10002
|
recalculatedValue: propertyValue$1(value?.value, termId),
|
|
9903
10003
|
identity: blankNodeIdentity(value, spec),
|
|
9904
10004
|
// `identityLabel`/`identitySegments` are filled per group (`withRowLabels`), which needs all rows
|
|
9905
10005
|
identityLabel: '',
|
|
10006
|
+
identityScalars: [],
|
|
9906
10007
|
identitySegments: [],
|
|
9907
10008
|
subRows,
|
|
9908
10009
|
isRecalculated: isRecalculatedValue(value, originalValue),
|
|
@@ -9953,6 +10054,7 @@ const buildParallelSiblingRow = (log, term, index, context) => {
|
|
|
9953
10054
|
recalculatedValue: null,
|
|
9954
10055
|
identity: { 'methodModel.@id': log.model },
|
|
9955
10056
|
identityLabel: '',
|
|
10057
|
+
identityScalars: [],
|
|
9956
10058
|
identitySegments: [],
|
|
9957
10059
|
isRecalculated: false,
|
|
9958
10060
|
recalculated: [syntheticValue],
|
|
@@ -10090,7 +10192,9 @@ const arrayTreatmentFormula = (numbers, termId, total) => {
|
|
|
10090
10192
|
// a human-readable explanation of how the rows' values were combined into the header value. Returns null
|
|
10091
10193
|
// unless several numeric values were actually combined - so single-value groups show no misleading formula
|
|
10092
10194
|
const valueFormula = (values, termId, result, type) => {
|
|
10093
|
-
const numbers = values
|
|
10195
|
+
const numbers = values
|
|
10196
|
+
.map(({ value }) => propertyValue$1(value, termId))
|
|
10197
|
+
.filter(v => typeof v === 'number');
|
|
10094
10198
|
if (numbers.length < 2)
|
|
10095
10199
|
return null;
|
|
10096
10200
|
const total = formatFormulaValue(result);
|
|
@@ -10108,6 +10212,7 @@ const withCollapsible = (group) => {
|
|
|
10108
10212
|
rows: group.rows.map(row => ({ ...row, canOpen: row.subRows.length > 0 })),
|
|
10109
10213
|
originalValue: reduceValues(group.rows.flatMap(row => row.original), group.termId, group.type),
|
|
10110
10214
|
recalculatedValue,
|
|
10215
|
+
isRecalculated: group.rows.some(row => row.isRecalculated),
|
|
10111
10216
|
recalculatedFormula: valueFormula(recalculatedNodes, group.termId, recalculatedValue, group.type)
|
|
10112
10217
|
};
|
|
10113
10218
|
};
|
|
@@ -10167,6 +10272,7 @@ const groupJLogByField = (jlog, nodeKey, originalValues, recalculatedValues, nod
|
|
|
10167
10272
|
key,
|
|
10168
10273
|
identity: {},
|
|
10169
10274
|
identityLabel: '',
|
|
10275
|
+
identityScalars: [],
|
|
10170
10276
|
identitySegments: [],
|
|
10171
10277
|
originalValue: originalValue ?? null,
|
|
10172
10278
|
recalculatedValue: recalculatedValue ?? null,
|
|
@@ -10357,13 +10463,15 @@ class NodeJLogModelsComponent {
|
|
|
10357
10463
|
return group.termId;
|
|
10358
10464
|
}
|
|
10359
10465
|
trackByRow(_index, row) {
|
|
10360
|
-
|
|
10466
|
+
// include the sub-row `key` (a term may appear as several sub-row kinds) and the position as a final
|
|
10467
|
+
// tiebreaker, so the `@for` track expression stays unique even if two rows share term/index/label
|
|
10468
|
+
return `${row.termId}-${row.index}-${row.identityLabel}-${row.key}-${_index}`;
|
|
10361
10469
|
}
|
|
10362
10470
|
trackByModel(_index, model) {
|
|
10363
10471
|
return model.methodId;
|
|
10364
10472
|
}
|
|
10365
10473
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10366
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeJLogModelsComponent, isStandalone: true, selector: "he-node-jlog-models", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, originalValues: { classPropertyName: "originalValues", publicName: "originalValues", isSignal: true, isRequired: false, transformFunction: null }, recalculatedValues: { classPropertyName: "recalculatedValues", publicName: "recalculatedValues", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypesLabel: { classPropertyName: "filterTermTypesLabel", publicName: "filterTermTypesLabel", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", isSignal: true, isRequired: false, transformFunction: null }, jlog: { classPropertyName: "jlog", publicName: "jlog", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (!isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "directive", type: NgbTypeahead, selector: "input[ngbTypeahead]", inputs: ["autocomplete", "container", "editable", "focusFirst", "inputFormatter", "ngbTypeahead", "resultFormatter", "resultTemplate", "selectOnExact", "showHint", "placement", "popperOptions", "popupClass"], outputs: ["selectItem"], exportAs: ["ngbTypeahead"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLogsModelsLogsComponent, selector: "he-node-logs-models-logs", inputs: ["logs"] }, { kind: "component", type: NodeLogsModelsLogsStatusComponent, selector: "he-node-logs-models-logs-status", inputs: ["nodeType", "model", "data"] }, { kind: "component", type: NodeLogsModelsContributionsComponent, selector: "he-node-logs-models-contributions", inputs: ["node", "nodeKey", "model"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: TimesPipe, name: "times" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10474
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeJLogModelsComponent, isStandalone: true, selector: "he-node-jlog-models", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, originalValues: { classPropertyName: "originalValues", publicName: "originalValues", isSignal: true, isRequired: false, transformFunction: null }, recalculatedValues: { classPropertyName: "recalculatedValues", publicName: "recalculatedValues", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypes: { classPropertyName: "filterTermTypes", publicName: "filterTermTypes", isSignal: true, isRequired: false, transformFunction: null }, filterTermTypesLabel: { classPropertyName: "filterTermTypesLabel", publicName: "filterTermTypesLabel", isSignal: true, isRequired: false, transformFunction: null }, cycle: { classPropertyName: "cycle", publicName: "cycle", isSignal: true, isRequired: false, transformFunction: null }, jlog: { classPropertyName: "jlog", publicName: "jlog", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (group.isRecalculated && !isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (\n group.isRecalculated && !isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)\n ) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityScalars.length) {\n @for (segment of row.identitySegments; track segment.field; let s = $index) {\n @if (s > 0) {<span>\u00B7</span>}\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 @for (scalar of row.identityScalars; track scalar.key; let i = $index) {\n <span class=\"break-word\">\n @if (i > 0 || row.identitySegments.length) {\u00B7}\n @if (scalar.field && row.type) {\n <a [href]=\"schemaBaseUrl + '/' + row.type + '#' + scalar.field\" target=\"_blank\">{{\n scalar.key\n }}</a\n >@if (scalar.value) {: {{ scalar.value }}}\n } @else {\n {{ scalar.key }}@if (scalar.value) {: {{ scalar.value }}}\n }\n </span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: BlankNodeValueDeltaComponent, selector: "he-blank-node-value-delta", inputs: ["value", "originalValue", "displayType", "useCustomFunctions"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "directive", type: NgbTypeahead, selector: "input[ngbTypeahead]", inputs: ["autocomplete", "container", "editable", "focusFirst", "inputFormatter", "ngbTypeahead", "resultFormatter", "resultTemplate", "selectOnExact", "showHint", "placement", "popperOptions", "popupClass"], outputs: ["selectItem"], exportAs: ["ngbTypeahead"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLogsModelsLogsComponent, selector: "he-node-logs-models-logs", inputs: ["logs"] }, { kind: "component", type: NodeLogsModelsLogsStatusComponent, selector: "he-node-logs-models-logs-status", inputs: ["nodeType", "model", "data"] }, { kind: "component", type: NodeLogsModelsContributionsComponent, selector: "he-node-logs-models-contributions", inputs: ["node", "nodeKey", "model"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: KeyToLabelPipe, name: "keyToLabel" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: TimesPipe, name: "times" }, { kind: "pipe", type: CapitalizePipe, name: "capitalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10367
10475
|
}
|
|
10368
10476
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeJLogModelsComponent, decorators: [{
|
|
10369
10477
|
type: Component$1,
|
|
@@ -10387,7 +10495,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
10387
10495
|
NodeLogsModelsLogsStatusComponent,
|
|
10388
10496
|
NodeLogsModelsContributionsComponent,
|
|
10389
10497
|
GuideOverlayComponent
|
|
10390
|
-
], template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (!isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityLabel) {\n @for (segment of row.identitySegments; track segment.field) {\n <span>{{ segment.field | keyToLabel }}:</span>\n @for (term of segment.terms; track term['@id']) {\n <he-node-link class=\"is-inline-block\" [node]=\"term\">\n <span class=\"break-word\" [innerHtml]=\"term.name | compound: term.termType\"></span>\n </he-node-link>\n }\n }\n @if (row.identityLabel) {\n <span class=\"break-word\">{{ row.identityLabel }}</span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n @for (v of methodModelsCount() - 1 | times; track empty; let empty = $index) {\n <td class=\"has-border-right\"></td>\n }\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"] }]
|
|
10498
|
+
], template: "<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\">\n @if (enableFilterByTerm()) {\n <div class=\"field is-pb-1\">\n <div class=\"control is-expanded has-icons-right\">\n <input\n class=\"input search-input is-small\"\n [ngModel]=\"term()\"\n name=\"term\"\n placeholder=\"Select entry by name\"\n [ngbTypeahead]=\"suggestTerm\"\n [resultFormatter]=\"termFormatter\"\n [inputFormatter]=\"termFormatter\"\n [focusFirst]=\"true\"\n (focus)=\"typeaheadFocus($event)\"\n (selectItem)=\"term.set($event.item)\"\n container=\"body\"\n popupClass=\"is-small\" />\n <a class=\"icon is-small is-right\" [class.is-hidden]=\"!term()\" (click)=\"term.set(undefined)\">\n <he-svg-icon name=\"xmark\" />\n </a>\n </div>\n </div>\n }\n </th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Units</span></th>\n }\n <th class=\"has-border-right\"><span>Original</span></th>\n <th class=\"has-border-right\"><span>Recalculated</span></th>\n @if (isBlankNodes()) {\n <th class=\"has-border-right\"><span>Difference</span></th>\n }\n @for (c of methodModelsCount() | times; track i; let i = $index) {\n <th class=\"has-border-right\">\n <span>Model {{ i + 1 }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (groups().length === 0) {\n <tr>\n <td class=\"has-border-right has-text-centered\" colspan=\"100\">\n <p class=\"is-p-1\">No recalculation logs to show.</p>\n </td>\n </tr>\n }\n @for (group of groups(); track trackByGroup($index, group)) {\n @let single = group.rows.length === 1;\n <tr [class.has-sub-rows]=\"group.canOpen\" [class.is-open]=\"group.isOpen\">\n <td class=\"width-auto has-border-right is-nowrap\" [attr.title]=\"group.term?.name\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4\">\n @if (group.canOpen) {\n <a class=\"open-node\" (click)=\"toggleGroup(group)\">\n <he-svg-icon [name]=\"group.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n @if (group.term) {\n <he-node-link class=\"is-inline-block is-pre-wrap is-pr-2\" [node]=\"group.term\">\n <span class=\"break-word\" [innerHtml]=\"group.term?.name | compound: group.term?.termType\"></span>\n </he-node-link>\n } @else if (group.key) {\n @if (nodeKey() === 'completeness') {\n <a [href]=\"schemaBaseUrl + '/Completeness#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n } @else {\n <a [href]=\"schemaBaseUrl + '/' + nodeType() + '#' + group.key\" target=\"_blank\">\n <span>{{ group.key | keyToLabel }}</span>\n </a>\n }\n }\n </div>\n </td>\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0] }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: group.rows[0], open: group.isOpen }\" />\n } @else {\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (group.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"group.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(group.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (group.isRecalculated && !isEmptyValue(group.recalculatedValue)) {\n @if (group.recalculatedFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.recalculatedFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: group.recalculatedValue }\" />\n }\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (\n group.isRecalculated && !isEmptyValue(group.originalValue) && !isEmptyValue(group.recalculatedValue)\n ) {\n <he-blank-node-value-delta\n [value]=\"group.recalculatedValue\"\n [originalValue]=\"group.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (group.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n }\n </tr>\n\n @if (single) {\n <ng-container\n *ngTemplateOutlet=\"subRowsTemplate; context: { row: group.rows[0], open: group.isOpen, nested: false }\" />\n } @else if (group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr [class.has-sub-rows]=\"row.canOpen\" [class.is-sub-row]=\"true\">\n <td class=\"width-auto has-border-right\">\n <div class=\"is-flex is-align-items-flex-start is-gap-4 is-pl-3\">\n @if (row.canOpen) {\n <a class=\"open-node\" (click)=\"toggleRow(row)\">\n <he-svg-icon [name]=\"row.isOpen ? 'chevron-down' : 'chevron-right'\" />\n </a>\n }\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n @if (row.isFailed) {\n <span class=\"has-text-danger\">failed</span>\n } @else if (row.identitySegments.length || row.identityScalars.length) {\n @for (segment of row.identitySegments; track segment.field; let s = $index) {\n @if (s > 0) {<span>\u00B7</span>}\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 @for (scalar of row.identityScalars; track scalar.key; let i = $index) {\n <span class=\"break-word\">\n @if (i > 0 || row.identitySegments.length) {\u00B7}\n @if (scalar.field && row.type) {\n <a [href]=\"schemaBaseUrl + '/' + row.type + '#' + scalar.field\" target=\"_blank\">{{\n scalar.key\n }}</a\n >@if (scalar.value) {: {{ scalar.value }}}\n } @else {\n {{ scalar.key }}@if (scalar.value) {: {{ scalar.value }}}\n }\n </span>\n }\n } @else {\n <span class=\"has-text-grey\">entry {{ row.index + 1 }}</span>\n }\n </div>\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row, open: row.isOpen }\" />\n </tr>\n <ng-container *ngTemplateOutlet=\"subRowsTemplate; context: { row, open: row.isOpen, nested: true }\" />\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<div class=\"is-size-7\">\n <div class=\"is-flex is-py-2 is-px-3 is-gap-16 | status-legend\">\n <div\n class=\"is-flex is-justify-content-center is-align-items-center is-align-content-center is-flex-wrap-wrap is-gap-8\">\n @for (status of LogStatus | keyvalue; track status.value) {\n @if (logIcon[status.value]) {\n <span class=\"is-flex is-align-items-center is-gap-8\">\n <he-svg-icon [name]=\"logIcon[status.value]\" size=\"20\" class=\"has-text-{{ logColor[status.value] }}\" />\n <span class=\"is-size-7\">{{ status.value | capitalize }}</span>\n </span>\n }\n }\n </div>\n\n @if (filteredType()) {\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded is-secondary\"\n [(ngModel)]=\"onlyRequired\"\n [disabled]=\"!!term()\"\n [id]=\"onlyRequiredId\" />\n <label class=\"is-size-7\" [attr.for]=\"onlyRequiredId\">\n <span>Only show {{ filteredType() }} included in the default HESTIA system boundary</span>\n </label>\n </div>\n }\n </div>\n</div>\n\n<ng-template #valueCells let-row=\"row\">\n @if (isBlankNodes()) {\n <td class=\"has-border-right\">\n @if (row.term) {\n <span class=\"is-nowrap\" [innerHtml]=\"row.term.units | compound\"></span>\n }\n </td>\n }\n <td class=\"has-border-right\">\n @if (!isEmptyValue(row.originalValue)) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.originalValue }\" />\n } @else {\n -\n }\n </td>\n <td class=\"has-border-right\">\n @if (row.isRecalculated) {\n <ng-container *ngTemplateOutlet=\"valueContent; context: { value: row.recalculatedValue }\" />\n } @else if (row.key === 'backgroundData') {\n <!-- a container grouping the input's background-emission models; it has no value of its own -->\n -\n } @else if (row.isFailed || row.models.length || isEmptyValue(row.originalValue)) {\n not recalculated\n } @else {\n -\n }\n </td>\n @if (isBlankNodes()) {\n <td class=\"has-border-right is-nowrap\">\n @if (row.isOriginal && row.isRecalculated) {\n <he-blank-node-value-delta\n [value]=\"row.recalculatedValue\"\n [originalValue]=\"row.originalValue\"\n [useCustomFunctions]=\"false\" />\n } @else {\n -\n }\n </td>\n }\n</ng-template>\n\n<ng-template #subRowsTemplate let-row=\"row\" let-open=\"open\" let-nested=\"nested\">\n @if (row.canOpen && open) {\n @for (subRow of row.subRows; track trackByRow($index, subRow)) {\n <tr class=\"is-sub-row\">\n <td class=\"width-auto has-border-right\">\n <div\n class=\"is-flex is-align-items-flex-start is-flex-wrap-wrap is-gap-4\"\n [class.is-pl-3]=\"!nested\"\n [class.is-pl-5]=\"nested\">\n <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n @if (subRow.key === 'backgroundData') {\n <span>Background Data</span>\n } @else if (subRow.term) {\n <span>{{ subRow.key | keyToLabel }}:</span>\n <he-node-link class=\"is-inline-block\" [node]=\"subRow.term\">\n <span class=\"break-word\" [innerHtml]=\"subRow.term?.name | compound\"></span>\n </he-node-link>\n } @else {\n <span>Field:</span>\n @if (subRow.type) {\n <a [href]=\"schemaBaseUrl + '/' + subRow.type + '#' + subRow.key\" target=\"_blank\">{{ subRow.key }}</a>\n } @else {\n <span>{{ subRow.key }}</span>\n }\n }\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: subRow }\" />\n <ng-container *ngTemplateOutlet=\"modelCells; context: { row: subRow, open: true }\" />\n </tr>\n }\n }\n</ng-template>\n\n<ng-template #valueContent let-value=\"value\">\n @if (isNumber(value)) {\n {{ value | precision: 3 | default: '-' }}\n } @else {\n {{ value | default: '-' }}\n }\n</ng-template>\n\n<ng-template #modelCells let-row=\"row\" let-open=\"open\">\n @if (row.canOpen && !open && row.models.length === 0) {\n <td class=\"has-border-right\" [attr.colspan]=\"methodModelsCount()\">\n <span>Expand to see logs (</span>\n @if (row.allSucceeded) {\n <span>all succeeded</span>\n <he-svg-icon class=\"is-ml-1 has-text-success\" name=\"checkmark\" />\n } @else {\n <span>some failed</span>\n <he-svg-icon class=\"is-ml-1 has-text-danger\" name=\"xmark\" />\n }\n <span>)</span>\n </td>\n } @else {\n @for (i of methodModelsCount() | times; track modelIndex; let modelIndex = $index) {\n <td class=\"has-border-right\">\n @if (row.modelColumns[modelIndex]; as column) {\n @if (isArray(column)) {\n <!-- parallel models: stacked in the same column, each with its own status -->\n @for (model of column; track model.methodId) {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model, row }\" />\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"modelCell; context: { model: column, row }\" />\n }\n } @else {\n -\n }\n </td>\n }\n }\n</ng-template>\n\n<ng-template #modelCell let-model=\"model\" let-row=\"row\">\n <div class=\"is-flex is-align-self-stretch is-justify-content-center is-align-items-center is-gap-8\">\n <div class=\"is-flex is-gap-4 is-flex-grow-1 is-align-items-center\">\n <span\n class=\"pl-1 has-text-{{ logColor[model.status] }}\"\n [class.trigger-popover]=\"hasLogs()\"\n [ngbPopover]=\"logStatusDetails\"\n [disablePopover]=\"!hasLogs()\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p1=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation(); p1.isOpen() ? p1.close() : p1.open({ model, row })\">\n <he-svg-icon [name]=\"logIcon[model.status]\" />\n </span>\n\n <span class=\"is-flex is-flex-grow-1 is-gap-4\">\n <span class=\"is-nowrap is-capitalized\">{{ methodName(model) }}</span>\n @if (modelMethodTier(model); as methodTier) {\n <span class=\"is-nowrap\">[{{ methodTier }}]</span>\n }\n </span>\n </div>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (model.showLogs) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"logDetails\"\n autoClose=\"outside\"\n popoverClass=\"is-narrow\"\n triggers=\"manual\"\n #p=\"ngbPopover\"\n placement=\"bottom left right auto\"\n container=\"body\"\n (click)=\"p.isOpen() ? p.close() : p.open({ model })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n }\n @if (model.model) {\n @if (model.showLogs) {\n <div class=\"vertical-divider\"></div>\n }\n <ng-container *ngTemplateOutlet=\"docsLink; context: { $implicit: model.model }\" />\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #logDetails let-model=\"model\">\n @if (hasContributions()) {\n @if (showContributionsLogs()) {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(false)\">\n Hide contributions details\n </button>\n </div>\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model\" />\n } @else {\n <div class=\"has-text-right is-mb-1\">\n <button class=\"button is-white is-small is-outlined\" (click)=\"showContributionsLogs.set(true)\">\n Show contributions details\n </button>\n </div>\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n } @else {\n <he-node-logs-models-logs [logs]=\"model.logs\" />\n }\n</ng-template>\n\n<ng-template #logStatusDetails let-model=\"model\" let-row=\"row\">\n <he-node-logs-models-logs-status [nodeType]=\"nodeType()\" [model]=\"model\" [data]=\"$any(row)\" />\n</ng-template>\n\n<ng-template #docsLink let-model>\n @if (guideEnabled && model.guidePath) {\n <he-guide-overlay [pageId]=\"model.guidePath\" [width]=\"500\" />\n } @else {\n <a [href]=\"model.docPath || model.path\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}:host .status-legend{border:1px solid #dbe3ea;background:#f5f7f9}:host .has-formula{cursor:help;border-bottom:1px dotted currentColor}::ng-deep .table{background-color:transparent}::ng-deep .table td.has-border-right{box-shadow:1px 0 #4c7194}::ng-deep .table td>div{min-height:24px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before,::ng-deep .table .is-sub-row>td:first-child:before{display:block;position:absolute;content:\" \";background-color:#4c719433;height:100%;width:1px;top:0;left:14px}::ng-deep .table .has-sub-rows.is-open>td:first-child:before{top:25px}::ng-deep .table .is-sub-row .open-node>he-svg-icon,::ng-deep .table .is-sub-row .sub-sub-row-icon{height:16px!important;width:16px!important}::ng-deep .table .is-sub-sub-row td:first-child{padding-left:24px}\n"] }]
|
|
10391
10499
|
}], 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 }] }] } });
|
|
10392
10500
|
|
|
10393
10501
|
const groupTerms = (terms) => terms.reduce((prev, curr) => ({ ...prev, [curr['@id']]: curr }), {});
|