@hestia-earth/ui-components 0.43.10 → 0.43.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/hestia-earth-ui-components-file-errors.mjs +46 -12
- package/fesm2022/hestia-earth-ui-components-file-errors.mjs.map +1 -1
- package/fesm2022/hestia-earth-ui-components.mjs +675 -82
- package/fesm2022/hestia-earth-ui-components.mjs.map +1 -1
- package/package.json +1 -1
- package/types/hestia-earth-ui-components-file-errors.d.ts +1 -1
- package/types/hestia-earth-ui-components.d.ts +182 -48
|
@@ -6899,7 +6899,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
6899
6899
|
|
|
6900
6900
|
const colors = {
|
|
6901
6901
|
darkBlue: 'rgba(25, 57, 87, 1)',
|
|
6902
|
-
lightBlue: 'rgba(132, 160, 220, 1)'
|
|
6902
|
+
lightBlue: 'rgba(132, 160, 220, 1)',
|
|
6903
|
+
// `$warning` — marks the reported value, and is the one colour that reads against both a white
|
|
6904
|
+
// page and the dark blue popover the parametric chart is shown in
|
|
6905
|
+
orange: 'rgba(255, 136, 27, 1)'
|
|
6903
6906
|
};
|
|
6904
6907
|
const opaqueColor = (color, opacity = 0.5) => color.replace(', 1)', `, ${opacity})`);
|
|
6905
6908
|
const defaultSettings$1 = Object.freeze({
|
|
@@ -6960,6 +6963,96 @@ const createDynamicHistogramData = (values, numberOfBins) => {
|
|
|
6960
6963
|
frequencies[numberOfBins - 1] += values.filter(p => p === max).length;
|
|
6961
6964
|
return { labels, frequencies };
|
|
6962
6965
|
};
|
|
6966
|
+
/**
|
|
6967
|
+
* Parametric mode: how far either side of the mean the curve is drawn, in standard deviations.
|
|
6968
|
+
* Four covers ~99.99% of the density, so the tails are visually flat by the time it stops.
|
|
6969
|
+
*/
|
|
6970
|
+
const curveSpread = 4;
|
|
6971
|
+
const curvePoints = 120;
|
|
6972
|
+
/** Fraction of the drawn range kept clear at each end, so a marker on the edge is not clipped. */
|
|
6973
|
+
const curvePadding = 0.05;
|
|
6974
|
+
const normalPdf = (x, mu, sd) => Math.exp(-0.5 * ((x - mu) / sd) ** 2) / (sd * Math.sqrt(2 * Math.PI));
|
|
6975
|
+
/**
|
|
6976
|
+
* The x range to draw. The reported value is included when it is known, because the whole point of
|
|
6977
|
+
* the chart is to show how far outside the interval it sits — clipping it to the curve would hide
|
|
6978
|
+
* exactly what the reader came to see.
|
|
6979
|
+
*/
|
|
6980
|
+
const curveRange = (mu, sd, value, minX) => {
|
|
6981
|
+
const values = [mu - curveSpread * sd, mu + curveSpread * sd, ...(Number.isFinite(value) ? [value] : [])];
|
|
6982
|
+
const from = Math.min(...values);
|
|
6983
|
+
const to = Math.max(...values);
|
|
6984
|
+
const padding = (to - from) * curvePadding;
|
|
6985
|
+
// a fitted normal has mass either side of the mean, but the quantity it describes may not:
|
|
6986
|
+
// drawing a physical amount below its floor invites the reader to think that is possible
|
|
6987
|
+
return { from: Number.isFinite(minX) ? Math.max(from - padding, minX) : from - padding, to: to + padding };
|
|
6988
|
+
};
|
|
6989
|
+
/** Samples the normal PDF, as `{x, y}` points for a linear x axis. */
|
|
6990
|
+
const createNormalCurve = (mu, sd, value, minX) => {
|
|
6991
|
+
const { from, to } = curveRange(mu, sd, value, minX);
|
|
6992
|
+
return Array.from({ length: curvePoints + 1 }, (_, index) => from + ((to - from) * index) / curvePoints).map(x => ({
|
|
6993
|
+
x,
|
|
6994
|
+
y: normalPdf(x, mu, sd)
|
|
6995
|
+
}));
|
|
6996
|
+
};
|
|
6997
|
+
/**
|
|
6998
|
+
* The shaded confidence interval, the mean, and the vertical marker at the reported value.
|
|
6999
|
+
*
|
|
7000
|
+
* The mean earns its line: the y axis is a probability density, whose absolute value means nothing
|
|
7001
|
+
* to a reader, so without it there is no way to tell what the peak of the curve represents.
|
|
7002
|
+
*/
|
|
7003
|
+
const distributionAnnotations = (min, max, value, mean) => ({
|
|
7004
|
+
...(Number.isFinite(min) && Number.isFinite(max)
|
|
7005
|
+
? {
|
|
7006
|
+
interval: {
|
|
7007
|
+
type: 'box',
|
|
7008
|
+
xMin: min,
|
|
7009
|
+
xMax: max,
|
|
7010
|
+
backgroundColor: opaqueColor(colors.lightBlue, 0.3),
|
|
7011
|
+
borderWidth: 0,
|
|
7012
|
+
drawTime: 'beforeDatasetsDraw'
|
|
7013
|
+
}
|
|
7014
|
+
}
|
|
7015
|
+
: {}),
|
|
7016
|
+
...(Number.isFinite(mean)
|
|
7017
|
+
? {
|
|
7018
|
+
mean: {
|
|
7019
|
+
type: 'line',
|
|
7020
|
+
xMin: mean,
|
|
7021
|
+
xMax: mean,
|
|
7022
|
+
borderColor: colors.lightBlue,
|
|
7023
|
+
borderWidth: 1,
|
|
7024
|
+
borderDash: [4, 4],
|
|
7025
|
+
label: {
|
|
7026
|
+
display: true,
|
|
7027
|
+
content: 'average',
|
|
7028
|
+
position: 'start',
|
|
7029
|
+
backgroundColor: colors.lightBlue,
|
|
7030
|
+
color: colors.darkBlue,
|
|
7031
|
+
font: { size: 9 }
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
: {}),
|
|
7036
|
+
...(Number.isFinite(value)
|
|
7037
|
+
? {
|
|
7038
|
+
value: {
|
|
7039
|
+
type: 'line',
|
|
7040
|
+
xMin: value,
|
|
7041
|
+
xMax: value,
|
|
7042
|
+
borderColor: colors.orange,
|
|
7043
|
+
borderWidth: 2,
|
|
7044
|
+
label: {
|
|
7045
|
+
display: true,
|
|
7046
|
+
content: `${transform(value, 3, true)}`,
|
|
7047
|
+
position: 'start',
|
|
7048
|
+
backgroundColor: colors.orange,
|
|
7049
|
+
color: '#fff',
|
|
7050
|
+
font: { size: 10 }
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
: {})
|
|
7055
|
+
});
|
|
6963
7056
|
const createSinglePointDataset = (labels, pointValue) => {
|
|
6964
7057
|
// Create an array with the same length as the labels, filled with nulls.
|
|
6965
7058
|
const pointData = new Array(labels.length).fill(null);
|
|
@@ -7003,6 +7096,34 @@ class DistributionChartComponent {
|
|
|
7003
7096
|
*/
|
|
7004
7097
|
this.maxPercentile = input(0, ...(ngDevMode ? [{ debugName: "maxPercentile" }] : []));
|
|
7005
7098
|
this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
7099
|
+
/**
|
|
7100
|
+
* Parametric mode: the mean of the distribution. Set `mu` and `sd` to plot the normal curve
|
|
7101
|
+
* instead of binning `distribution` into a histogram — used where only the parameters are known
|
|
7102
|
+
* and there are no samples to bin.
|
|
7103
|
+
*/
|
|
7104
|
+
this.mu = input(...(ngDevMode ? [undefined, { debugName: "mu" }] : []));
|
|
7105
|
+
/**
|
|
7106
|
+
* Parametric mode: the standard deviation of the distribution. See `mu`.
|
|
7107
|
+
*/
|
|
7108
|
+
this.sd = input(...(ngDevMode ? [undefined, { debugName: "sd" }] : []));
|
|
7109
|
+
/**
|
|
7110
|
+
* Parametric mode: lower bound of the confidence interval to shade.
|
|
7111
|
+
*/
|
|
7112
|
+
this.intervalMin = input(...(ngDevMode ? [undefined, { debugName: "intervalMin" }] : []));
|
|
7113
|
+
/**
|
|
7114
|
+
* Parametric mode: upper bound of the confidence interval to shade.
|
|
7115
|
+
*/
|
|
7116
|
+
this.intervalMax = input(...(ngDevMode ? [undefined, { debugName: "intervalMax" }] : []));
|
|
7117
|
+
/**
|
|
7118
|
+
* Parametric mode: floor for the drawn range, for a quantity that cannot go below it — pass `0`
|
|
7119
|
+
* for a physical amount. Left unset the curve is drawn symmetrically about `mu`.
|
|
7120
|
+
*/
|
|
7121
|
+
this.minX = input(...(ngDevMode ? [undefined, { debugName: "minX" }] : []));
|
|
7122
|
+
/**
|
|
7123
|
+
* `sd` must be strictly positive: a zero or negative deviation makes the PDF a division by zero.
|
|
7124
|
+
*/
|
|
7125
|
+
this.parametric = computed(() => Number.isFinite(this.mu()) && Number.isFinite(this.sd()) && this.sd() > 0, ...(ngDevMode ? [{ debugName: "parametric" }] : []));
|
|
7126
|
+
this.curve = computed(() => createNormalCurve(this.mu(), this.sd(), this.value(), this.minX()), ...(ngDevMode ? [{ debugName: "curve" }] : []));
|
|
7006
7127
|
this.maxPercentileValue = computed(() => this.maxPercentile() ? getPercentileValue(this.distribution(), this.maxPercentile()) : null, ...(ngDevMode ? [{ debugName: "maxPercentileValue" }] : []));
|
|
7007
7128
|
this.groupedData = computed(() => createDynamicHistogramData(this.maxPercentileValue()
|
|
7008
7129
|
? (this.distribution() ?? []).filter(v => v <= this.maxPercentileValue())
|
|
@@ -7050,7 +7171,51 @@ class DistributionChartComponent {
|
|
|
7050
7171
|
}
|
|
7051
7172
|
}
|
|
7052
7173
|
}), ...(ngDevMode ? [{ debugName: "defaultConfig" }] : []));
|
|
7053
|
-
|
|
7174
|
+
/**
|
|
7175
|
+
* The x axis is `linear` here, not the category axis the histogram uses: the curve is `{x, y}`
|
|
7176
|
+
* points, and the annotations position the interval and the marker at real x values.
|
|
7177
|
+
*/
|
|
7178
|
+
this.parametricConfig = computed(() => ({
|
|
7179
|
+
options: {
|
|
7180
|
+
plugins: {
|
|
7181
|
+
annotation: {
|
|
7182
|
+
annotations: distributionAnnotations(this.intervalMin(), this.intervalMax(), this.value(), this.mu())
|
|
7183
|
+
}
|
|
7184
|
+
},
|
|
7185
|
+
scales: {
|
|
7186
|
+
x: {
|
|
7187
|
+
type: 'linear',
|
|
7188
|
+
display: true,
|
|
7189
|
+
ticks: {
|
|
7190
|
+
font: {
|
|
7191
|
+
family: defaultTicksFont.family,
|
|
7192
|
+
size: 10,
|
|
7193
|
+
weight: 400
|
|
7194
|
+
},
|
|
7195
|
+
color: '#4A4A4A',
|
|
7196
|
+
callback: value => `${transform(value, 3, true)}`
|
|
7197
|
+
},
|
|
7198
|
+
title: {
|
|
7199
|
+
display: true,
|
|
7200
|
+
text: this.label()
|
|
7201
|
+
}
|
|
7202
|
+
},
|
|
7203
|
+
y: {
|
|
7204
|
+
// the density itself carries no meaning for the reader, only the shape does
|
|
7205
|
+
ticks: {
|
|
7206
|
+
display: false
|
|
7207
|
+
},
|
|
7208
|
+
grid: {
|
|
7209
|
+
display: false
|
|
7210
|
+
},
|
|
7211
|
+
title: {
|
|
7212
|
+
display: false
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
}), ...(ngDevMode ? [{ debugName: "parametricConfig" }] : []));
|
|
7218
|
+
this.histogramData = computed(() => ({
|
|
7054
7219
|
datasets: [
|
|
7055
7220
|
this.distribution()
|
|
7056
7221
|
? [
|
|
@@ -7089,16 +7254,32 @@ class DistributionChartComponent {
|
|
|
7089
7254
|
: []
|
|
7090
7255
|
].flat(),
|
|
7091
7256
|
labels: this.groupedData().labels
|
|
7092
|
-
}), ...(ngDevMode ? [{ debugName: "
|
|
7093
|
-
this.
|
|
7257
|
+
}), ...(ngDevMode ? [{ debugName: "histogramData" }] : []));
|
|
7258
|
+
this.parametricData = computed(() => ({
|
|
7259
|
+
datasets: [
|
|
7260
|
+
{
|
|
7261
|
+
label: 'Distribution',
|
|
7262
|
+
data: this.curve(),
|
|
7263
|
+
backgroundColor: opaqueColor(colors.lightBlue, 0.2),
|
|
7264
|
+
// light enough to read on a dark panel, dark enough to read on a white one
|
|
7265
|
+
borderColor: colors.lightBlue,
|
|
7266
|
+
borderWidth: 1,
|
|
7267
|
+
fill: true,
|
|
7268
|
+
pointRadius: 0,
|
|
7269
|
+
type: 'line'
|
|
7270
|
+
}
|
|
7271
|
+
]
|
|
7272
|
+
}), ...(ngDevMode ? [{ debugName: "parametricData" }] : []));
|
|
7273
|
+
this.dataConfig = computed(() => this.parametric() ? this.parametricData() : this.histogramData(), ...(ngDevMode ? [{ debugName: "dataConfig" }] : []));
|
|
7274
|
+
this.configuration = computed(() => merge$1({}, defaultSettings$1, this.parametric() ? this.parametricConfig() : this.defaultConfig(), this.config()), ...(ngDevMode ? [{ debugName: "configuration" }] : []));
|
|
7094
7275
|
}
|
|
7095
7276
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DistributionChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7096
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: DistributionChartComponent, isStandalone: true, selector: "he-distribution-chart", inputs: { distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, nbBins: { classPropertyName: "nbBins", publicName: "nbBins", isSignal: true, isRequired: false, transformFunction: null }, maxPercentile: { classPropertyName: "maxPercentile", publicName: "maxPercentile", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["distributionChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7277
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: DistributionChartComponent, isStandalone: true, selector: "he-distribution-chart", inputs: { distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, nbBins: { classPropertyName: "nbBins", publicName: "nbBins", isSignal: true, isRequired: false, transformFunction: null }, maxPercentile: { classPropertyName: "maxPercentile", publicName: "maxPercentile", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, mu: { classPropertyName: "mu", publicName: "mu", isSignal: true, isRequired: false, transformFunction: null }, sd: { classPropertyName: "sd", publicName: "sd", isSignal: true, isRequired: false, transformFunction: null }, intervalMin: { classPropertyName: "intervalMin", publicName: "intervalMin", isSignal: true, isRequired: false, transformFunction: null }, intervalMax: { classPropertyName: "intervalMax", publicName: "intervalMax", isSignal: true, isRequired: false, transformFunction: null }, minX: { classPropertyName: "minX", publicName: "minX", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["distributionChart"], ngImport: i0, template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" />\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ChartComponent, selector: "he-chart", inputs: ["data", "config", "showExportButton"], exportAs: ["chart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7097
7278
|
}
|
|
7098
7279
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DistributionChartComponent, decorators: [{
|
|
7099
7280
|
type: Component$1,
|
|
7100
7281
|
args: [{ selector: 'he-distribution-chart', exportAs: 'distributionChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ChartComponent], template: "<he-chart [data]=\"dataConfig()\" [config]=\"configuration()\" />\n", styles: [":host{display:block}\n"] }]
|
|
7101
|
-
}], propDecorators: { distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], nbBins: [{ type: i0.Input, args: [{ isSignal: true, alias: "nbBins", required: false }] }], maxPercentile: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPercentile", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|
|
7282
|
+
}], propDecorators: { distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], nbBins: [{ type: i0.Input, args: [{ isSignal: true, alias: "nbBins", required: false }] }], maxPercentile: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPercentile", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], mu: [{ type: i0.Input, args: [{ isSignal: true, alias: "mu", required: false }] }], sd: [{ type: i0.Input, args: [{ isSignal: true, alias: "sd", required: false }] }], intervalMin: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervalMin", required: false }] }], intervalMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervalMax", required: false }] }], minX: [{ type: i0.Input, args: [{ isSignal: true, alias: "minX", required: false }] }] } });
|
|
7102
7283
|
|
|
7103
7284
|
const defaultSettings = Object.freeze({
|
|
7104
7285
|
type: 'line',
|
|
@@ -9130,6 +9311,39 @@ const toTextParts = (value) => {
|
|
|
9130
9311
|
return parts;
|
|
9131
9312
|
};
|
|
9132
9313
|
|
|
9314
|
+
/**
|
|
9315
|
+
* A titled block that can be folded away, with room for a control beside its heading.
|
|
9316
|
+
*
|
|
9317
|
+
* Presentation only: it holds no opinion on what it contains, so several of them stacked read as
|
|
9318
|
+
* one document a reader can collapse section by section.
|
|
9319
|
+
*/
|
|
9320
|
+
class CollapsibleBlockComponent {
|
|
9321
|
+
constructor() {
|
|
9322
|
+
/**
|
|
9323
|
+
* The label above the content.
|
|
9324
|
+
*/
|
|
9325
|
+
this.heading = input('', ...(ngDevMode ? [{ debugName: "heading" }] : []));
|
|
9326
|
+
/**
|
|
9327
|
+
* Whether the block can be folded away. Turn it off and it renders as a plain titled block.
|
|
9328
|
+
*/
|
|
9329
|
+
this.collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : []));
|
|
9330
|
+
/**
|
|
9331
|
+
* Whether the content is shown. Two-way, so the caller can fold a block from outside.
|
|
9332
|
+
*/
|
|
9333
|
+
this.open = model(true, ...(ngDevMode ? [{ debugName: "open" }] : []));
|
|
9334
|
+
}
|
|
9335
|
+
toggle() {
|
|
9336
|
+
if (this.collapsible())
|
|
9337
|
+
this.open.set(!this.open());
|
|
9338
|
+
}
|
|
9339
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CollapsibleBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9340
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CollapsibleBlockComponent, isStandalone: true, selector: "he-collapsible-block", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, ngImport: i0, template: "<div class=\"collapsible-block is-mb-2\">\n <div class=\"is-flex is-align-items-center is-justify-content-space-between is-gap-8 is-mb-1 is-size-8\">\n <span\n class=\"is-flex is-align-items-center is-gap-4 is-uppercase has-text-weight-semibold\"\n [class.is-clickable]=\"collapsible()\"\n (click)=\"toggle()\">\n @if (collapsible()) {\n <he-svg-icon [name]=\"open() ? 'chevron-down' : 'chevron-right'\" />\n }\n <span>{{ heading() }}</span>\n </span>\n\n <!-- a control that belongs to the block rather than to its content, e.g. a display switch -->\n <ng-content select=\"[blockActions]\" />\n </div>\n\n @if (open()) {\n <ng-content />\n }\n</div>\n", styles: [".collapsible-block{border-bottom:1px solid rgba(255,255,255,.2)}\n"], dependencies: [{ kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9341
|
+
}
|
|
9342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CollapsibleBlockComponent, decorators: [{
|
|
9343
|
+
type: Component$1,
|
|
9344
|
+
args: [{ selector: 'he-collapsible-block', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HESvgIconComponent], template: "<div class=\"collapsible-block is-mb-2\">\n <div class=\"is-flex is-align-items-center is-justify-content-space-between is-gap-8 is-mb-1 is-size-8\">\n <span\n class=\"is-flex is-align-items-center is-gap-4 is-uppercase has-text-weight-semibold\"\n [class.is-clickable]=\"collapsible()\"\n (click)=\"toggle()\">\n @if (collapsible()) {\n <he-svg-icon [name]=\"open() ? 'chevron-down' : 'chevron-right'\" />\n }\n <span>{{ heading() }}</span>\n </span>\n\n <!-- a control that belongs to the block rather than to its content, e.g. a display switch -->\n <ng-content select=\"[blockActions]\" />\n </div>\n\n @if (open()) {\n <ng-content />\n }\n</div>\n", styles: [".collapsible-block{border-bottom:1px solid rgba(255,255,255,.2)}\n"] }]
|
|
9345
|
+
}], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }] } });
|
|
9346
|
+
|
|
9133
9347
|
/**
|
|
9134
9348
|
* Displays a set of formulas with the variables documented under them, and a switch between the
|
|
9135
9349
|
* symbolic and the substituted view.
|
|
@@ -9167,10 +9381,19 @@ class FormulaBlockComponent {
|
|
|
9167
9381
|
* several blocks: they share one state, so repeating the switch only repeats the same control.
|
|
9168
9382
|
*/
|
|
9169
9383
|
this.showToggle = input(true, ...(ngDevMode ? [{ debugName: "showToggle" }] : []));
|
|
9384
|
+
/**
|
|
9385
|
+
* Whether the block can be folded away, so a reader can put aside the part they are not reading.
|
|
9386
|
+
*/
|
|
9387
|
+
this.collapsible = input(false, ...(ngDevMode ? [{ debugName: "collapsible" }] : []));
|
|
9388
|
+
/**
|
|
9389
|
+
* Whether the block is unfolded. Two-way, so the caller can fold it from outside.
|
|
9390
|
+
*/
|
|
9391
|
+
this.open = model(true, ...(ngDevMode ? [{ debugName: "open" }] : []));
|
|
9170
9392
|
/**
|
|
9171
9393
|
* Whether the substituted view is shown. Two-way, so the caller can render accordingly.
|
|
9172
9394
|
*/
|
|
9173
9395
|
this.substituted = model(false, ...(ngDevMode ? [{ debugName: "substituted" }] : []));
|
|
9396
|
+
this.blockHeading = computed(() => this.heading() || `Formula${this.formulas().length > 1 ? 's' : ''}`, ...(ngDevMode ? [{ debugName: "blockHeading" }] : []));
|
|
9174
9397
|
// unique per instance so a label only toggles its own checkbox - several can co-exist on a page
|
|
9175
9398
|
this.toggleId = uuid('formulaSubstituted-');
|
|
9176
9399
|
/**
|
|
@@ -9192,12 +9415,12 @@ class FormulaBlockComponent {
|
|
|
9192
9415
|
this.substituted.set(!this.substituted());
|
|
9193
9416
|
}
|
|
9194
9417
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FormulaBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9195
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FormulaBlockComponent, isStandalone: true, selector: "he-formula-block", inputs: { formulas: { classPropertyName: "formulas", publicName: "formulas", isSignal: true, isRequired: false, transformFunction: null }, hasSubstitutions: { classPropertyName: "hasSubstitutions", publicName: "hasSubstitutions", isSignal: true, isRequired: false, transformFunction: null }, emptyTitle: { classPropertyName: "emptyTitle", publicName: "emptyTitle", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, note: { classPropertyName: "note", publicName: "note", isSignal: true, isRequired: false, transformFunction: null }, showToggle: { classPropertyName: "showToggle", publicName: "showToggle", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { substituted: "substitutedChange" }, ngImport: i0, template: "@if (items().length) {\n <
|
|
9418
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FormulaBlockComponent, isStandalone: true, selector: "he-formula-block", inputs: { formulas: { classPropertyName: "formulas", publicName: "formulas", isSignal: true, isRequired: false, transformFunction: null }, hasSubstitutions: { classPropertyName: "hasSubstitutions", publicName: "hasSubstitutions", isSignal: true, isRequired: false, transformFunction: null }, emptyTitle: { classPropertyName: "emptyTitle", publicName: "emptyTitle", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, note: { classPropertyName: "note", publicName: "note", isSignal: true, isRequired: false, transformFunction: null }, showToggle: { classPropertyName: "showToggle", publicName: "showToggle", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", substituted: "substitutedChange" }, ngImport: i0, template: "@if (items().length) {\n <he-collapsible-block [heading]=\"blockHeading()\" [collapsible]=\"collapsible()\" [(open)]=\"open\">\n @if (showToggle()) {\n <div blockActions class=\"field\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"toggleId\"\n [checked]=\"substituted()\"\n [disabled]=\"!hasSubstitutions()\"\n (change)=\"toggle()\" />\n <label [for]=\"toggleId\" [title]=\"hasSubstitutions() ? '' : emptyTitle()\">\n <span>{{ substituted() ? 'Substituted' : 'Raw' }}</span>\n </label>\n </div>\n }\n\n <div class=\"formula-block\">\n @if (note()) {\n <p class=\"is-size-8 is-mb-1 | formula-note\">{{ note() }}</p>\n }\n\n @for (item of items(); track $index) {\n @if (item.section) {\n <p class=\"is-size-8 is-uppercase has-text-weight-semibold is-mt-2 | formula-section\">{{ item.section }}</p>\n }\n\n @if (item.contextParts.length) {\n <p class=\"is-size-7 is-mt-1 | formula-context\">\n <ng-container *ngTemplateOutlet=\"textParts; context: { parts: item.contextParts }\" />\n </p>\n }\n\n <div class=\"formula\" [heKatex]=\"item.rendered\"></div>\n\n @if (item.variables.length) {\n <ul class=\"is-size-7 is-mt-1 is-mb-2 is-list-style-disc | formula-variables\">\n @for (variable of item.variables; track $index) {\n <li>\n <div class=\"is-flex is-align-items-baseline is-gap-4\">\n <span class=\"formula-variable-symbol is-nowrap\">\n <span [heKatex]=\"variable.symbol\" [heKatexInline]=\"true\"></span>\n @if (variable.descriptionParts.length) {\n <span>:</span>\n }\n </span>\n @if (variable.descriptionParts.length) {\n <span class=\"is-italic | formula-variable-desc\">\n <ng-container *ngTemplateOutlet=\"textParts; context: { parts: variable.descriptionParts }\" />\n </span>\n }\n @if (variable.note) {\n <span class=\"formula-variable-note\">({{ variable.note }})</span>\n } @else if (variable.missing) {\n <span class=\"has-text-warning\">(missing)</span>\n }\n </div>\n </li>\n }\n </ul>\n }\n }\n </div>\n </he-collapsible-block>\n}\n\n<!-- documentation text: the symbols it names render as math, the rest as markdown -->\n<ng-template #textParts let-parts=\"parts\">\n @for (part of parts; track $index) {\n @if (part.math) {\n <span class=\"formula-inline-math\" [heKatex]=\"part.math\" [heKatexInline]=\"true\"></span>\n } @else {\n <markdown class=\"is-inline-block\" [data]=\"part.text\" />\n }\n }\n</ng-template>\n", styles: [":host{display:block}.formula-section{opacity:.7;letter-spacing:.03em}.formula-note{opacity:.7}.formula-context{opacity:.9}.formula-variables{padding-inline-start:1rem}.formula-variable-symbol{flex-shrink:0}.formula-variable-symbol ::ng-deep .katex{font-size:1em}.formula-variable-desc{opacity:.85}.formula-variable-note{opacity:.7;white-space:nowrap}.formula-context ::ng-deep markdown,.formula-context ::ng-deep markdown *,.formula-variable-desc ::ng-deep markdown,.formula-variable-desc ::ng-deep markdown *{display:inline;margin:0;white-space:pre-wrap}.formula-context .formula-inline-math ::ng-deep .katex,.formula-variable-desc .formula-inline-math ::ng-deep .katex{font-size:1em}.formula{overflow-x:auto;overflow-y:hidden}.formula ::ng-deep .katex-display{margin:.35rem 0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: KatexDirective, selector: "[heKatex]", inputs: ["heKatex", "heKatexInline"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "component", type: CollapsibleBlockComponent, selector: "he-collapsible-block", inputs: ["heading", "collapsible", "open"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9196
9419
|
}
|
|
9197
9420
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FormulaBlockComponent, decorators: [{
|
|
9198
9421
|
type: Component$1,
|
|
9199
|
-
args: [{ selector: 'he-formula-block', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, KatexDirective, MarkdownComponent], template: "@if (items().length) {\n <
|
|
9200
|
-
}], propDecorators: { formulas: [{ type: i0.Input, args: [{ isSignal: true, alias: "formulas", required: false }] }], hasSubstitutions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasSubstitutions", required: false }] }], emptyTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyTitle", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], note: [{ type: i0.Input, args: [{ isSignal: true, alias: "note", required: false }] }], showToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggle", required: false }] }], substituted: [{ type: i0.Input, args: [{ isSignal: true, alias: "substituted", required: false }] }, { type: i0.Output, args: ["substitutedChange"] }] } });
|
|
9422
|
+
args: [{ selector: 'he-formula-block', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, KatexDirective, MarkdownComponent, CollapsibleBlockComponent], template: "@if (items().length) {\n <he-collapsible-block [heading]=\"blockHeading()\" [collapsible]=\"collapsible()\" [(open)]=\"open\">\n @if (showToggle()) {\n <div blockActions class=\"field\">\n <input\n type=\"checkbox\"\n class=\"switch is-small is-rounded\"\n [id]=\"toggleId\"\n [checked]=\"substituted()\"\n [disabled]=\"!hasSubstitutions()\"\n (change)=\"toggle()\" />\n <label [for]=\"toggleId\" [title]=\"hasSubstitutions() ? '' : emptyTitle()\">\n <span>{{ substituted() ? 'Substituted' : 'Raw' }}</span>\n </label>\n </div>\n }\n\n <div class=\"formula-block\">\n @if (note()) {\n <p class=\"is-size-8 is-mb-1 | formula-note\">{{ note() }}</p>\n }\n\n @for (item of items(); track $index) {\n @if (item.section) {\n <p class=\"is-size-8 is-uppercase has-text-weight-semibold is-mt-2 | formula-section\">{{ item.section }}</p>\n }\n\n @if (item.contextParts.length) {\n <p class=\"is-size-7 is-mt-1 | formula-context\">\n <ng-container *ngTemplateOutlet=\"textParts; context: { parts: item.contextParts }\" />\n </p>\n }\n\n <div class=\"formula\" [heKatex]=\"item.rendered\"></div>\n\n @if (item.variables.length) {\n <ul class=\"is-size-7 is-mt-1 is-mb-2 is-list-style-disc | formula-variables\">\n @for (variable of item.variables; track $index) {\n <li>\n <div class=\"is-flex is-align-items-baseline is-gap-4\">\n <span class=\"formula-variable-symbol is-nowrap\">\n <span [heKatex]=\"variable.symbol\" [heKatexInline]=\"true\"></span>\n @if (variable.descriptionParts.length) {\n <span>:</span>\n }\n </span>\n @if (variable.descriptionParts.length) {\n <span class=\"is-italic | formula-variable-desc\">\n <ng-container *ngTemplateOutlet=\"textParts; context: { parts: variable.descriptionParts }\" />\n </span>\n }\n @if (variable.note) {\n <span class=\"formula-variable-note\">({{ variable.note }})</span>\n } @else if (variable.missing) {\n <span class=\"has-text-warning\">(missing)</span>\n }\n </div>\n </li>\n }\n </ul>\n }\n }\n </div>\n </he-collapsible-block>\n}\n\n<!-- documentation text: the symbols it names render as math, the rest as markdown -->\n<ng-template #textParts let-parts=\"parts\">\n @for (part of parts; track $index) {\n @if (part.math) {\n <span class=\"formula-inline-math\" [heKatex]=\"part.math\" [heKatexInline]=\"true\"></span>\n } @else {\n <markdown class=\"is-inline-block\" [data]=\"part.text\" />\n }\n }\n</ng-template>\n", styles: [":host{display:block}.formula-section{opacity:.7;letter-spacing:.03em}.formula-note{opacity:.7}.formula-context{opacity:.9}.formula-variables{padding-inline-start:1rem}.formula-variable-symbol{flex-shrink:0}.formula-variable-symbol ::ng-deep .katex{font-size:1em}.formula-variable-desc{opacity:.85}.formula-variable-note{opacity:.7;white-space:nowrap}.formula-context ::ng-deep markdown,.formula-context ::ng-deep markdown *,.formula-variable-desc ::ng-deep markdown,.formula-variable-desc ::ng-deep markdown *{display:inline;margin:0;white-space:pre-wrap}.formula-context .formula-inline-math ::ng-deep .katex,.formula-variable-desc .formula-inline-math ::ng-deep .katex{font-size:1em}.formula{overflow-x:auto;overflow-y:hidden}.formula ::ng-deep .katex-display{margin:.35rem 0}\n"] }]
|
|
9423
|
+
}], propDecorators: { formulas: [{ type: i0.Input, args: [{ isSignal: true, alias: "formulas", required: false }] }], hasSubstitutions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasSubstitutions", required: false }] }], emptyTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyTitle", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], note: [{ type: i0.Input, args: [{ isSignal: true, alias: "note", required: false }] }], showToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggle", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], substituted: [{ type: i0.Input, args: [{ isSignal: true, alias: "substituted", required: false }] }, { type: i0.Output, args: ["substitutedChange"] }] } });
|
|
9201
9424
|
|
|
9202
9425
|
const isMissing$1 = (value) => value === undefined || value === null || value === '';
|
|
9203
9426
|
// the result symbol (left-hand side) - it is the model's output, not an input that "was not logged", so
|
|
@@ -9350,7 +9573,7 @@ class NodeLogsModelsFormulaComponent {
|
|
|
9350
9573
|
return omitKeys(values, omit);
|
|
9351
9574
|
}
|
|
9352
9575
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsFormulaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9353
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NodeLogsModelsFormulaComponent, isStandalone: true, selector: "he-node-logs-models-formula", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, logs: { classPropertyName: "logs", publicName: "logs", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { substituted: "substitutedChange" }, ngImport: i0, template: "<he-formula-block\n [formulas]=\"renderedFormulas()\"\n [hasSubstitutions]=\"hasSubstitutions()\"\n [(substituted)]=\"substituted\" />\n", dependencies: [{ kind: "component", type: FormulaBlockComponent, selector: "he-formula-block", inputs: ["formulas", "hasSubstitutions", "emptyTitle", "heading", "note", "showToggle", "substituted"], outputs: ["substitutedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9576
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NodeLogsModelsFormulaComponent, isStandalone: true, selector: "he-node-logs-models-formula", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, logs: { classPropertyName: "logs", publicName: "logs", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { substituted: "substitutedChange" }, ngImport: i0, template: "<he-formula-block\n [formulas]=\"renderedFormulas()\"\n [hasSubstitutions]=\"hasSubstitutions()\"\n [(substituted)]=\"substituted\" />\n", dependencies: [{ kind: "component", type: FormulaBlockComponent, selector: "he-formula-block", inputs: ["formulas", "hasSubstitutions", "emptyTitle", "heading", "note", "showToggle", "collapsible", "open", "substituted"], outputs: ["openChange", "substitutedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9354
9577
|
}
|
|
9355
9578
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsFormulaComponent, decorators: [{
|
|
9356
9579
|
type: Component$1,
|
|
@@ -11549,7 +11772,7 @@ class NodeValueDetailsComponent {
|
|
|
11549
11772
|
this.updateKeys(selectedKeys);
|
|
11550
11773
|
}
|
|
11551
11774
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeValueDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11552
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeValueDetailsComponent, isStandalone: true, selector: "he-node-value-details", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, nodeType: { classPropertyName: "nodeType", publicName: "nodeType", isSignal: true, isRequired: true, transformFunction: null }, dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: true, transformFunction: null }, aggregated: { classPropertyName: "aggregated", publicName: "aggregated", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (showInline()) {\n @for (key of keys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n @for (key of additionalKeys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n @if (node().distribution?.length) {\n <p>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + node['@type'] + '#distribution'\" target=\"_blank\">\n <b>distribution</b>\n </a>\n <span class=\"pr-2\">:</span>\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node: node() }\" />\n </p>\n }\n} @else {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n key=\"term\" />\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n <div class=\"columns is-p-0 is-my-0 is-overflow-visible\">\n <div class=\"column is-p-0 is-my-0\"></div>\n <div class=\"column is-p-0 is-my-0 is-narrow is-overflow-visible\">\n <div ngbDropdown class=\"is-overflow-visible\" autoClose=\"outside\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small is-ghost has-text-white\"\n type=\"button\"\n aria-controls=\"config-menu\">\n <span>Customise fields</span>\n <span class=\"icon is-small\">\n <he-svg-icon name=\"settings\" aria-hidden=\"true\" />\n </span>\n </button>\n\n <div ngbDropdownMenu id=\"config-menu\">\n <div\n class=\"dropdown-content is-overflow-y-auto\"\n (click)=\"$event.stopPropagation()\"\n cdkDropList\n (cdkDropListDropped)=\"dropTableKey($event)\">\n @for (key of tableKeys(); track key.key; let keyIndex = $index) {\n <div class=\"dropdown-item cdk-drag-item\" cdkDrag>\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"selector\"\n [id]=\"key.key\"\n [name]=\"key.key\"\n [checked]=\"key.selected\"\n (change)=\"onTableKeyChange(key, keyIndex, $event.target.checked)\" />\n <label class=\"is-pl-2\" [for]=\"key.key\">{{ key.key }}</label>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"table-container is-mt-2\">\n <table class=\"table is-dark is-narrow is-striped\">\n <thead>\n @for (key of visibleTableKeys(); track key) {\n <th>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + type() + '#' + key.split('.')[0]\" target=\"_blank\">\n <b>{{ key.includes('.') ? key.split('.')[1] : key }}</b>\n </a>\n </th>\n }\n </thead>\n <tbody>\n @for (node of nodes(); track node) {\n <tr>\n @for (key of visibleTableKeys(); track key) {\n <td>\n @if (key === 'distribution') {\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node }\" />\n } @else {\n <he-link-key-value\n [node]=\"node\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\"\n [defaultValue]=\"defaultValue(key)\" />\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n}\n\n<ng-template #distributionContent let-node=\"node\">\n @if (node.distribution?.length) {\n @if (showDistribution() === node) {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(undefined)\">Hide</a>\n } @else {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(node)\">Show</a>\n }\n } @else {\n <span>N/A</span>\n }\n</ng-template>\n\n@if (chartDistribution()) {\n <div class=\"has-background-white is-mt-2 is-p-2 is-rounded | chart-container\">\n <he-distribution-chart\n [distribution]=\"chartDistribution()\"\n [value]=\"chartValue()\"\n [label]=\"chartLabel()\"\n [nbBins]=\"10\"\n [maxPercentile]=\"0.99\" />\n </div>\n}\n\n<ng-template #showModels>\n @if (models().length) {\n <p>\n <span class=\"is-inline-block\">\n <b>possible models used</b>\n </span>\n <span class=\"pr-2\">:</span>\n @for (model of models(); track model; let lastModel = $last) {\n <a class=\"is-dark\" [href]=\"model.link\">{{ model.name }}</a>\n @if (!lastModel) {\n <span class=\"is-pr-1 is-inline-block\">;</span>\n }\n }\n </p>\n }\n</ng-template>\n", styles: ["table{background-color:transparent}table::ng-deep he-link-key-value>a:first-child,table::ng-deep he-link-key-value>a:first-child+span{display:none}.dropdown-content{max-height:300px}.cdk-drag-preview{box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;list-style:none}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-item{cursor:move}.chart-container{border-radius:3px}.chart-container he-distribution-chart{height:250px;min-width:400px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "ngmodule", type: NgbTooltipModule }, { kind: "ngmodule", type: NgbDropdownModule }, { kind: "directive", type: i1$1.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i1$1.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i1$1.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "component", type: LinkKeyValueComponent, selector: "he-link-key-value", inputs: ["node", "nodeType", "dataState", "dataKey", "key", "defaultValue"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DistributionChartComponent, selector: "he-distribution-chart", inputs: ["distribution", "value", "label", "nbBins", "maxPercentile", "config"], exportAs: ["distributionChart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11775
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeValueDetailsComponent, isStandalone: true, selector: "he-node-value-details", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, nodeType: { classPropertyName: "nodeType", publicName: "nodeType", isSignal: true, isRequired: true, transformFunction: null }, dataState: { classPropertyName: "dataState", publicName: "dataState", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: true, transformFunction: null }, aggregated: { classPropertyName: "aggregated", publicName: "aggregated", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (showInline()) {\n @for (key of keys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n @for (key of additionalKeys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n @if (node().distribution?.length) {\n <p>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + node['@type'] + '#distribution'\" target=\"_blank\">\n <b>distribution</b>\n </a>\n <span class=\"pr-2\">:</span>\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node: node() }\" />\n </p>\n }\n} @else {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n key=\"term\" />\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n <div class=\"columns is-p-0 is-my-0 is-overflow-visible\">\n <div class=\"column is-p-0 is-my-0\"></div>\n <div class=\"column is-p-0 is-my-0 is-narrow is-overflow-visible\">\n <div ngbDropdown class=\"is-overflow-visible\" autoClose=\"outside\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small is-ghost has-text-white\"\n type=\"button\"\n aria-controls=\"config-menu\">\n <span>Customise fields</span>\n <span class=\"icon is-small\">\n <he-svg-icon name=\"settings\" aria-hidden=\"true\" />\n </span>\n </button>\n\n <div ngbDropdownMenu id=\"config-menu\">\n <div\n class=\"dropdown-content is-overflow-y-auto\"\n (click)=\"$event.stopPropagation()\"\n cdkDropList\n (cdkDropListDropped)=\"dropTableKey($event)\">\n @for (key of tableKeys(); track key.key; let keyIndex = $index) {\n <div class=\"dropdown-item cdk-drag-item\" cdkDrag>\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"selector\"\n [id]=\"key.key\"\n [name]=\"key.key\"\n [checked]=\"key.selected\"\n (change)=\"onTableKeyChange(key, keyIndex, $event.target.checked)\" />\n <label class=\"is-pl-2\" [for]=\"key.key\">{{ key.key }}</label>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"table-container is-mt-2\">\n <table class=\"table is-dark is-narrow is-striped\">\n <thead>\n @for (key of visibleTableKeys(); track key) {\n <th>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + type() + '#' + key.split('.')[0]\" target=\"_blank\">\n <b>{{ key.includes('.') ? key.split('.')[1] : key }}</b>\n </a>\n </th>\n }\n </thead>\n <tbody>\n @for (node of nodes(); track node) {\n <tr>\n @for (key of visibleTableKeys(); track key) {\n <td>\n @if (key === 'distribution') {\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node }\" />\n } @else {\n <he-link-key-value\n [node]=\"node\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\"\n [defaultValue]=\"defaultValue(key)\" />\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n}\n\n<ng-template #distributionContent let-node=\"node\">\n @if (node.distribution?.length) {\n @if (showDistribution() === node) {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(undefined)\">Hide</a>\n } @else {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(node)\">Show</a>\n }\n } @else {\n <span>N/A</span>\n }\n</ng-template>\n\n@if (chartDistribution()) {\n <div class=\"has-background-white is-mt-2 is-p-2 is-rounded | chart-container\">\n <he-distribution-chart\n [distribution]=\"chartDistribution()\"\n [value]=\"chartValue()\"\n [label]=\"chartLabel()\"\n [nbBins]=\"10\"\n [maxPercentile]=\"0.99\" />\n </div>\n}\n\n<ng-template #showModels>\n @if (models().length) {\n <p>\n <span class=\"is-inline-block\">\n <b>possible models used</b>\n </span>\n <span class=\"pr-2\">:</span>\n @for (model of models(); track model; let lastModel = $last) {\n <a class=\"is-dark\" [href]=\"model.link\">{{ model.name }}</a>\n @if (!lastModel) {\n <span class=\"is-pr-1 is-inline-block\">;</span>\n }\n }\n </p>\n }\n</ng-template>\n", styles: ["table{background-color:transparent}table::ng-deep he-link-key-value>a:first-child,table::ng-deep he-link-key-value>a:first-child+span{display:none}.dropdown-content{max-height:300px}.cdk-drag-preview{box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;list-style:none}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-item{cursor:move}.chart-container{border-radius:3px}.chart-container he-distribution-chart{height:250px;min-width:400px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "ngmodule", type: NgbTooltipModule }, { kind: "ngmodule", type: NgbDropdownModule }, { kind: "directive", type: i1$1.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i1$1.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i1$1.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "component", type: LinkKeyValueComponent, selector: "he-link-key-value", inputs: ["node", "nodeType", "dataState", "dataKey", "key", "defaultValue"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: DistributionChartComponent, selector: "he-distribution-chart", inputs: ["distribution", "value", "label", "nbBins", "maxPercentile", "config", "mu", "sd", "intervalMin", "intervalMax", "minX"], exportAs: ["distributionChart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11553
11776
|
}
|
|
11554
11777
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeValueDetailsComponent, decorators: [{
|
|
11555
11778
|
type: Component$1,
|
|
@@ -11565,6 +11788,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
11565
11788
|
], template: "@if (showInline()) {\n @for (key of keys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n @for (key of additionalKeys; track key) {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\" />\n }\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n @if (node().distribution?.length) {\n <p>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + node['@type'] + '#distribution'\" target=\"_blank\">\n <b>distribution</b>\n </a>\n <span class=\"pr-2\">:</span>\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node: node() }\" />\n </p>\n }\n} @else {\n <he-link-key-value\n [node]=\"node()\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n key=\"term\" />\n\n <ng-container *ngTemplateOutlet=\"showModels\" />\n\n <div class=\"columns is-p-0 is-my-0 is-overflow-visible\">\n <div class=\"column is-p-0 is-my-0\"></div>\n <div class=\"column is-p-0 is-my-0 is-narrow is-overflow-visible\">\n <div ngbDropdown class=\"is-overflow-visible\" autoClose=\"outside\" placement=\"bottom-end\">\n <button\n ngbDropdownToggle\n class=\"button is-small is-ghost has-text-white\"\n type=\"button\"\n aria-controls=\"config-menu\">\n <span>Customise fields</span>\n <span class=\"icon is-small\">\n <he-svg-icon name=\"settings\" aria-hidden=\"true\" />\n </span>\n </button>\n\n <div ngbDropdownMenu id=\"config-menu\">\n <div\n class=\"dropdown-content is-overflow-y-auto\"\n (click)=\"$event.stopPropagation()\"\n cdkDropList\n (cdkDropListDropped)=\"dropTableKey($event)\">\n @for (key of tableKeys(); track key.key; let keyIndex = $index) {\n <div class=\"dropdown-item cdk-drag-item\" cdkDrag>\n <div class=\"field is-relative\">\n <input\n type=\"checkbox\"\n class=\"selector\"\n [id]=\"key.key\"\n [name]=\"key.key\"\n [checked]=\"key.selected\"\n (change)=\"onTableKeyChange(key, keyIndex, $event.target.checked)\" />\n <label class=\"is-pl-2\" [for]=\"key.key\">{{ key.key }}</label>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"table-container is-mt-2\">\n <table class=\"table is-dark is-narrow is-striped\">\n <thead>\n @for (key of visibleTableKeys(); track key) {\n <th>\n <a class=\"is-dark\" [href]=\"schemaBaseUrl + '/' + type() + '#' + key.split('.')[0]\" target=\"_blank\">\n <b>{{ key.includes('.') ? key.split('.')[1] : key }}</b>\n </a>\n </th>\n }\n </thead>\n <tbody>\n @for (node of nodes(); track node) {\n <tr>\n @for (key of visibleTableKeys(); track key) {\n <td>\n @if (key === 'distribution') {\n <ng-container *ngTemplateOutlet=\"distributionContent; context: { node }\" />\n } @else {\n <he-link-key-value\n [node]=\"node\"\n [nodeType]=\"nodeType()\"\n [dataState]=\"dataState()\"\n [dataKey]=\"dataKey()\"\n [key]=\"key\"\n [defaultValue]=\"defaultValue(key)\" />\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n}\n\n<ng-template #distributionContent let-node=\"node\">\n @if (node.distribution?.length) {\n @if (showDistribution() === node) {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(undefined)\">Hide</a>\n } @else {\n <a class=\"has-text-white\" (click)=\"showDistribution.set(node)\">Show</a>\n }\n } @else {\n <span>N/A</span>\n }\n</ng-template>\n\n@if (chartDistribution()) {\n <div class=\"has-background-white is-mt-2 is-p-2 is-rounded | chart-container\">\n <he-distribution-chart\n [distribution]=\"chartDistribution()\"\n [value]=\"chartValue()\"\n [label]=\"chartLabel()\"\n [nbBins]=\"10\"\n [maxPercentile]=\"0.99\" />\n </div>\n}\n\n<ng-template #showModels>\n @if (models().length) {\n <p>\n <span class=\"is-inline-block\">\n <b>possible models used</b>\n </span>\n <span class=\"pr-2\">:</span>\n @for (model of models(); track model; let lastModel = $last) {\n <a class=\"is-dark\" [href]=\"model.link\">{{ model.name }}</a>\n @if (!lastModel) {\n <span class=\"is-pr-1 is-inline-block\">;</span>\n }\n }\n </p>\n }\n</ng-template>\n", styles: ["table{background-color:transparent}table::ng-deep he-link-key-value>a:first-child,table::ng-deep he-link-key-value>a:first-child+span{display:none}.dropdown-content{max-height:300px}.cdk-drag-preview{box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;list-style:none}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-item{cursor:move}.chart-container{border-radius:3px}.chart-container he-distribution-chart{height:250px;min-width:400px}\n"] }]
|
|
11566
11789
|
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], nodeType: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeType", required: true }] }], dataState: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataState", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: true }] }], aggregated: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregated", required: false }] }] } });
|
|
11567
11790
|
|
|
11791
|
+
const isMissing = (value) => value === undefined || value === null || value === '';
|
|
11792
|
+
/**
|
|
11793
|
+
* The quantities only a weighting rule binds, so a rule is placed by what it computes rather than
|
|
11794
|
+
* by where the documentation happens to write it. The weight normalisation stores none of its
|
|
11795
|
+
* symbols, so it is named by the one it defines.
|
|
11796
|
+
*/
|
|
11797
|
+
const WEIGHT_KEYS = [
|
|
11798
|
+
'organic_factor',
|
|
11799
|
+
'organic_weight_lookup_value',
|
|
11800
|
+
'irrigated_area',
|
|
11801
|
+
'plantation_lifespan',
|
|
11802
|
+
'world_production'
|
|
11803
|
+
];
|
|
11804
|
+
const WEIGHT_SYMBOLS = ['\\hat{w}_i'];
|
|
11805
|
+
const formulaGroup = (formula) => formula.bindings.some(({ key, symbol }) => WEIGHT_KEYS.includes(key ?? '') || WEIGHT_SYMBOLS.includes(symbol ?? ''))
|
|
11806
|
+
? 'weights'
|
|
11807
|
+
: 'value';
|
|
11808
|
+
/**
|
|
11809
|
+
* A symbol that should carry a value: the result and the inputs, but never a fixed constant or a
|
|
11810
|
+
* quantity the aggregation deliberately does not store.
|
|
11811
|
+
*/
|
|
11812
|
+
const isSubstitutable = (binding) => !!binding.key && binding.constant === undefined && !binding.display;
|
|
11813
|
+
/**
|
|
11814
|
+
* The number of rows a table would have had, which the aggregation records under `<table>_count`
|
|
11815
|
+
* when there were too many contributors to name every one of them.
|
|
11816
|
+
*/
|
|
11817
|
+
const tableCount = (values, key) => {
|
|
11818
|
+
const count = key ? values[`${key}_count`] : undefined;
|
|
11819
|
+
return typeof count === 'number' && count > 0 ? count : undefined;
|
|
11820
|
+
};
|
|
11821
|
+
const rowCount = (values, binding) => binding.column ? tableCount(values, binding.key) : undefined;
|
|
11822
|
+
/**
|
|
11823
|
+
* How a symbol that did not resolve is explained: the contributors were not recorded one by one,
|
|
11824
|
+
* only counted - which is a different thing from a value the aggregation never logged.
|
|
11825
|
+
*/
|
|
11826
|
+
const notListedNote = (values, binding) => {
|
|
11827
|
+
const count = rowCount(values, binding);
|
|
11828
|
+
return isSubstitutable(binding) && isMissing(values[binding.key]) && count
|
|
11829
|
+
? `${count} Cycles, not listed`
|
|
11830
|
+
: undefined;
|
|
11831
|
+
};
|
|
11832
|
+
/**
|
|
11833
|
+
* Whether a symbol that should have resolved did not. A symbol whose contributors were counted
|
|
11834
|
+
* rather than listed is not missing: `notListedNote` says how many there were instead.
|
|
11835
|
+
*/
|
|
11836
|
+
const isMissingValue = (values, binding) => isSubstitutable(binding) && isMissing(values[binding.key]) && !rowCount(values, binding);
|
|
11837
|
+
/**
|
|
11838
|
+
* Whether any symbol of these formulas resolves. When none does, the substituted view would be
|
|
11839
|
+
* identical to the symbolic one.
|
|
11840
|
+
*/
|
|
11841
|
+
const hasAnySubstitution = (values, bindings) => bindings.some(binding => isSubstitutable(binding) && !isMissing(values[binding.key]));
|
|
11842
|
+
// a symbol reading one column of a contributors table: `key` names the table, `column` the field
|
|
11843
|
+
const isTableBinding = (binding) => !!binding.key && !!binding.column && !binding.match;
|
|
11844
|
+
// the packed `log_as_table` string: rows split on `;`, columns on `_`, each column a `key:value`
|
|
11845
|
+
const parseRows = (packed) => typeof packed !== 'string'
|
|
11846
|
+
? []
|
|
11847
|
+
: packed
|
|
11848
|
+
.split(';')
|
|
11849
|
+
.filter(Boolean)
|
|
11850
|
+
.map(row => row.split('_').reduce((columns, pair) => {
|
|
11851
|
+
const at = pair.indexOf(':');
|
|
11852
|
+
return at === -1 ? columns : { ...columns, [pair.slice(0, at)]: pair.slice(at + 1) };
|
|
11853
|
+
}, {}));
|
|
11854
|
+
const ID_COLUMN$1 = 'id';
|
|
11855
|
+
// how many leading segments every id shares, e.g. the product and country of a sub-aggregation
|
|
11856
|
+
const commonPrefix = (ids) => {
|
|
11857
|
+
const [first = [], ...rest] = ids;
|
|
11858
|
+
const shared = first.findIndex((segment, index) => rest.some(other => other[index] !== segment));
|
|
11859
|
+
return shared === -1 ? first.length : shared;
|
|
11860
|
+
};
|
|
11861
|
+
/**
|
|
11862
|
+
* How many trailing segments every id shares, counting only the period and run date they are all
|
|
11863
|
+
* stamped with. Stopping at the first word is what keeps a compound apart from what it is compared
|
|
11864
|
+
* against: `irrigated` and `non-irrigated` share a word, and dropping it would lose the difference.
|
|
11865
|
+
*/
|
|
11866
|
+
const commonPeriod = (ids) => {
|
|
11867
|
+
const [first = [], ...rest] = ids;
|
|
11868
|
+
const shared = [...first]
|
|
11869
|
+
.reverse()
|
|
11870
|
+
.findIndex((segment, index) => !/^\d+$/.test(segment) || rest.some(other => other[other.length - 1 - index] !== segment));
|
|
11871
|
+
return shared === -1 ? first.length : shared;
|
|
11872
|
+
};
|
|
11873
|
+
/**
|
|
11874
|
+
* The part of each id that tells the contributors apart, dropping what they all share - the
|
|
11875
|
+
* product, country and period, which the Cycle being read already names. Falls back to the full id
|
|
11876
|
+
* where that leaves nothing, so a row is never unlabelled.
|
|
11877
|
+
*/
|
|
11878
|
+
const distinguishingLabels = (ids) => {
|
|
11879
|
+
const segments = ids.map(id => id.split('-'));
|
|
11880
|
+
const start = commonPrefix(segments);
|
|
11881
|
+
const end = commonPeriod(segments);
|
|
11882
|
+
return ids.map((id, index) => segments[index].slice(start, segments[index].length - end).join('-') || id);
|
|
11883
|
+
};
|
|
11884
|
+
/**
|
|
11885
|
+
* The contributors table these formulas read from: the first one the aggregation recorded, since
|
|
11886
|
+
* they all list the same Cycles - the zero-filled table is the wider of the two.
|
|
11887
|
+
*
|
|
11888
|
+
* Undefined when nothing was recorded, which is every aggregation that logs no values at all.
|
|
11889
|
+
*/
|
|
11890
|
+
const contributorsTable = (values, formulas) => {
|
|
11891
|
+
const bindings = formulas.flatMap(formula => formula.bindings.filter(isTableBinding));
|
|
11892
|
+
const key = bindings
|
|
11893
|
+
.map(binding => binding.key)
|
|
11894
|
+
.find(name => !isMissing(values[name]) || tableCount(values, name));
|
|
11895
|
+
if (!key)
|
|
11896
|
+
return undefined;
|
|
11897
|
+
const columns = bindings
|
|
11898
|
+
.filter(binding => binding.key === key)
|
|
11899
|
+
.map(({ symbol, description, column }) => ({ symbol, description, column: column }));
|
|
11900
|
+
const parsed = parseRows(values[key]);
|
|
11901
|
+
const labels = distinguishingLabels(parsed.map(row => row[ID_COLUMN$1]));
|
|
11902
|
+
const rows = parsed.map((row, index) => ({
|
|
11903
|
+
id: row[ID_COLUMN$1],
|
|
11904
|
+
label: labels[index],
|
|
11905
|
+
values: columns.map(({ column }) => row[column])
|
|
11906
|
+
}));
|
|
11907
|
+
return { columns, rows, count: tableCount(values, key) };
|
|
11908
|
+
};
|
|
11909
|
+
|
|
11568
11910
|
// The page every aggregation follows, whatever the product.
|
|
11569
11911
|
const GENERAL_PAGE = 'general-process';
|
|
11570
11912
|
// The product-specific page, by the primary product's `termType`. A term type with no page of its
|
|
@@ -11573,16 +11915,17 @@ const PRODUCT_PAGES = {
|
|
|
11573
11915
|
crop: 'crop',
|
|
11574
11916
|
processedFood: 'processed-food'
|
|
11575
11917
|
};
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
}
|
|
11918
|
+
/**
|
|
11919
|
+
* The rules are shown in the order they answer a reader's questions: how this value was calculated,
|
|
11920
|
+
* which values went into it, then how each of those was weighted. Grouping them by what they
|
|
11921
|
+
* compute rather than by the page they are documented on is what puts the two calculations either
|
|
11922
|
+
* side of the values they combine.
|
|
11923
|
+
*/
|
|
11924
|
+
const GROUPS = [
|
|
11925
|
+
{ id: 'value', heading: 'How the value is calculated', pageOrder: pages => pages },
|
|
11926
|
+
// a weight is derived by the product's own rules first, then normalised by the general one
|
|
11927
|
+
{ id: 'weights', heading: 'How the weights are calculated', pageOrder: pages => [...pages].reverse() }
|
|
11928
|
+
];
|
|
11586
11929
|
// A symbol worth listing under its formula: it carries documentation the reader needs. Constants
|
|
11587
11930
|
// (e.g. `365`) are self-evident in the formula itself.
|
|
11588
11931
|
const isDocumented = (binding) => !!binding.symbol && !!binding.description;
|
|
@@ -11597,16 +11940,16 @@ const isCompletenessZeroFill = (formula) => bindsTo(formula, 'zero_filled_weight
|
|
|
11597
11940
|
// The production-share weight is what combines country aggregations into a World one, so it is only
|
|
11598
11941
|
// part of how a World aggregation was produced - a country aggregation never applies it.
|
|
11599
11942
|
const isWorldWeight = (formula) => bindsTo(formula, 'world_production');
|
|
11943
|
+
// The sub-system weight is the product of one sub-aggregation's organic and irrigation factors, so
|
|
11944
|
+
// it is only part of how that sub-aggregation was produced. On the Cycle they are combined into,
|
|
11945
|
+
// each of its symbols holds one value per sub-system rather than the single one bound here.
|
|
11946
|
+
const isSubSystemWeight = (formula) => bindsTo(formula, 'organic_factor');
|
|
11600
11947
|
// The phase weighting splits a plantation's lifespan between its productive and non-productive
|
|
11601
11948
|
// years, so it only ran where the product is a permanent crop.
|
|
11602
11949
|
const isPlantationWeight = (formula) => bindsTo(formula, 'plantation_lifespan');
|
|
11603
11950
|
// The blank node keys whose terms carry a completeness area.
|
|
11604
11951
|
const COMPLETENESS_KEYS = ['products', 'emissions', 'inputs', 'practices'];
|
|
11605
11952
|
const PRODUCTS_KEY = 'products';
|
|
11606
|
-
const isMissing = (value) => value === undefined || value === null || value === '';
|
|
11607
|
-
// a symbol that should carry a value: the result and the inputs, but never a fixed constant or a
|
|
11608
|
-
// quantity the aggregation deliberately does not store
|
|
11609
|
-
const isSubstitutable = (binding) => !!binding.key && binding.constant === undefined && !binding.display;
|
|
11610
11953
|
class NodeAggregatedFormulasComponent {
|
|
11611
11954
|
constructor() {
|
|
11612
11955
|
/**
|
|
@@ -11636,6 +11979,12 @@ class NodeAggregatedFormulasComponent {
|
|
|
11636
11979
|
* is not part of how its values were produced.
|
|
11637
11980
|
*/
|
|
11638
11981
|
this.worldAggregation = input(false, ...(ngDevMode ? [{ debugName: "worldAggregation" }] : []));
|
|
11982
|
+
/**
|
|
11983
|
+
* Whether the Cycle is one of the sub-aggregations an aggregation is combined from, in which case
|
|
11984
|
+
* the sub-system weighting is one of the stages that produced its values. Defaults to showing the
|
|
11985
|
+
* stage, so a caller that cannot tell keeps the rule documented.
|
|
11986
|
+
*/
|
|
11987
|
+
this.subAggregation = input(true, ...(ngDevMode ? [{ debugName: "subAggregation" }] : []));
|
|
11639
11988
|
// show the substituted formula rather than the symbolic one, when there is anything to substitute
|
|
11640
11989
|
this.substituted = model(false, ...(ngDevMode ? [{ debugName: "substituted" }] : []));
|
|
11641
11990
|
/**
|
|
@@ -11649,20 +11998,33 @@ class NodeAggregatedFormulasComponent {
|
|
|
11649
11998
|
// to the symbolic one, so the toggle is disabled rather than silently doing nothing
|
|
11650
11999
|
this.hasSubstitutions = computed(() => {
|
|
11651
12000
|
const values = this.values();
|
|
11652
|
-
return this.sections().some(section => section.formulas.some(formula => formula.bindings
|
|
12001
|
+
return this.sections().some(section => section.formulas.some(formula => hasAnySubstitution(values, formula.bindings)));
|
|
11653
12002
|
}, ...(ngDevMode ? [{ debugName: "hasSubstitutions" }] : []));
|
|
11654
12003
|
/**
|
|
11655
|
-
*
|
|
11656
|
-
* variables documented under each. A variable with nothing to substitute is flagged, so the
|
|
11657
|
-
* reader can tell a value that was not recorded from one that is genuinely absent.
|
|
12004
|
+
* The rules that produced this value, grouped by what each one computes.
|
|
11658
12005
|
*/
|
|
11659
|
-
this.sections = computed(() =>
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
12006
|
+
this.sections = computed(() => GROUPS.map(({ id, heading, pageOrder }) => ({
|
|
12007
|
+
id,
|
|
12008
|
+
heading,
|
|
12009
|
+
formulas: pageOrder(this.pages())
|
|
12010
|
+
.flatMap(page => getFormulas$1(page))
|
|
12011
|
+
.filter(formula => formulaGroup(formula) === id && this.applies(formula))
|
|
12012
|
+
})).filter(section => section.formulas.length > 0), ...(ngDevMode ? [{ debugName: "sections" }] : []));
|
|
12013
|
+
/**
|
|
12014
|
+
* The values this one was combined from, as the aggregation recorded them: one row per Cycle or
|
|
12015
|
+
* sub-aggregation, under the symbols the formulas above read them with. Absent where the
|
|
12016
|
+
* contributors were too many to record, which is every aggregation built straight from source
|
|
12017
|
+
* Cycles - their number is shown instead.
|
|
12018
|
+
*/
|
|
12019
|
+
this.contributors = computed(() => {
|
|
12020
|
+
const table = contributorsTable(this.values(), this.sections().flatMap(section => section.formulas));
|
|
12021
|
+
// the node each row links to is built here rather than in the template, so it keeps its
|
|
12022
|
+
// identity between change detection runs
|
|
12023
|
+
return (table && {
|
|
12024
|
+
...table,
|
|
12025
|
+
rows: table.rows.map(row => ({ ...row, node: { '@type': NodeType.Cycle, '@id': row.id } }))
|
|
12026
|
+
});
|
|
12027
|
+
}, ...(ngDevMode ? [{ debugName: "contributors" }] : []));
|
|
11666
12028
|
this.renderedSections = computed(() => {
|
|
11667
12029
|
const values = this.values();
|
|
11668
12030
|
const showValues = this.substituted() && this.hasSubstitutions();
|
|
@@ -11681,7 +12043,10 @@ class NodeAggregatedFormulasComponent {
|
|
|
11681
12043
|
description: binding.description,
|
|
11682
12044
|
// only an input that should have resolved is flagged - a constant, or a quantity the
|
|
11683
12045
|
// aggregation deliberately does not store, is never substitutable rather than missing
|
|
11684
|
-
missing: showValues &&
|
|
12046
|
+
missing: showValues && isMissingValue(values, binding),
|
|
12047
|
+
// a symbol reading from a table of contributors too long to record says how many there
|
|
12048
|
+
// were, which is not the same as a value the aggregation never logged
|
|
12049
|
+
note: showValues ? notListedNote(values, binding) : undefined
|
|
11685
12050
|
}))
|
|
11686
12051
|
};
|
|
11687
12052
|
})
|
|
@@ -11694,11 +12059,14 @@ class NodeAggregatedFormulasComponent {
|
|
|
11694
12059
|
* a World aggregation, and the phase weighting only splits the lifespan of a plantation crop.
|
|
11695
12060
|
*/
|
|
11696
12061
|
ranForAggregation(formula) {
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
|
|
11701
|
-
|
|
12062
|
+
// the stages that only run for some aggregations, and whether each ran for this one. A formula
|
|
12063
|
+
// matching none of them is part of every aggregation.
|
|
12064
|
+
const stages = [
|
|
12065
|
+
{ applies: isWorldWeight, ran: () => this.worldAggregation() },
|
|
12066
|
+
{ applies: isSubSystemWeight, ran: () => this.subAggregation() },
|
|
12067
|
+
{ applies: isPlantationWeight, ran: () => isPlantation(this.termId() ?? '') }
|
|
12068
|
+
];
|
|
12069
|
+
return stages.find(({ applies }) => applies(formula))?.ran() ?? true;
|
|
11702
12070
|
}
|
|
11703
12071
|
/**
|
|
11704
12072
|
* Whether the rule applies to the kind of data item shown. With no `nodeKey` every rule is kept,
|
|
@@ -11718,12 +12086,133 @@ class NodeAggregatedFormulasComponent {
|
|
|
11718
12086
|
return this.ranForAggregation(formula) && this.appliesToNodeKey(formula);
|
|
11719
12087
|
}
|
|
11720
12088
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregatedFormulasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11721
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregatedFormulasComponent, isStandalone: true, selector: "he-node-aggregated-formulas", inputs: { termType: { classPropertyName: "termType", publicName: "termType", isSignal: true, isRequired: false, transformFunction: null }, termId: { classPropertyName: "termId", publicName: "termId", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, worldAggregation: { classPropertyName: "worldAggregation", publicName: "worldAggregation", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { substituted: "substitutedChange" }, ngImport: i0, template: "@if (renderedSections().length) {\n <div class=\"aggregated-formulas\">\n <p class=\"is-size-7 is-mb-2 | formula-intro\">\n Aggregated values are calculated from the underlying Cycles, not measured. These are the rules that produced this\n one, in the order they are applied.\n </p>\n\n <div class=\"aggregated-formulas-rules\">\n @for (section of renderedSections(); track section.
|
|
12089
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregatedFormulasComponent, isStandalone: true, selector: "he-node-aggregated-formulas", inputs: { termType: { classPropertyName: "termType", publicName: "termType", isSignal: true, isRequired: false, transformFunction: null }, termId: { classPropertyName: "termId", publicName: "termId", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, worldAggregation: { classPropertyName: "worldAggregation", publicName: "worldAggregation", isSignal: true, isRequired: false, transformFunction: null }, subAggregation: { classPropertyName: "subAggregation", publicName: "subAggregation", isSignal: true, isRequired: false, transformFunction: null }, substituted: { classPropertyName: "substituted", publicName: "substituted", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { substituted: "substitutedChange" }, ngImport: i0, template: "@if (renderedSections().length) {\n <div class=\"aggregated-formulas\">\n <p class=\"is-size-7 is-mb-2 | formula-intro\">\n Aggregated values are calculated from the underlying Cycles, not measured. These are the rules that produced this\n one, in the order they are applied.\n </p>\n\n <div class=\"is-pt-2 is-pr-1 is-overflow-y-auto | aggregated-formulas-rules\">\n @for (section of renderedSections(); track section.id; let first = $first) {\n <he-formula-block\n [formulas]=\"section.formulas\"\n [heading]=\"section.heading\"\n [collapsible]=\"true\"\n [showToggle]=\"first\"\n [hasSubstitutions]=\"hasSubstitutions()\"\n [(substituted)]=\"substituted\"\n emptyTitle=\"No recorded values to substitute\" />\n\n <!-- the values combined sit between the two calculations: what went in, above how each was weighted -->\n @if (section.id === 'value' && contributors(); as table) {\n <he-collapsible-block heading=\"Values combined\">\n @if (table.rows.length) {\n <table class=\"table is-narrow is-size-7 w-100 | contributors-table\">\n <thead>\n <tr>\n <th>Cycle</th>\n @for (column of table.columns; track column.symbol) {\n <th class=\"has-text-right\">\n <span [heKatex]=\"column.symbol\" [heKatexInline]=\"true\"></span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table.rows; track row.id) {\n <tr>\n <td [attr.title]=\"row.id\">\n <he-node-link [node]=\"row.node\" linkClass=\"has-text-white\">\n <span class=\"break-word\">{{ row.label }}</span>\n </he-node-link>\n </td>\n @for (value of row.values; track $index) {\n <td class=\"has-text-right is-nowrap\">{{ value | precision: 4 | default: '-' }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"is-size-7\">\n Combined from {{ table.count }} Cycles, too many for the aggregation to record one by one.\n </p>\n }\n </he-collapsible-block>\n }\n }\n </div>\n </div>\n}\n", styles: [".formula-intro{opacity:.85}.contributors-table{background-color:transparent;color:inherit}.contributors-table th,.contributors-table td{border-color:#fff3;color:inherit;padding:.15rem .5rem .15rem 0;vertical-align:top}.contributors-table th{opacity:.7}.contributors-table ::ng-deep .katex{font-size:1em}.aggregated-formulas-rules{max-height:50vh}\n"], dependencies: [{ kind: "directive", type: KatexDirective, selector: "[heKatex]", inputs: ["heKatex", "heKatexInline"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: FormulaBlockComponent, selector: "he-formula-block", inputs: ["formulas", "hasSubstitutions", "emptyTitle", "heading", "note", "showToggle", "collapsible", "open", "substituted"], outputs: ["openChange", "substitutedChange"] }, { kind: "component", type: CollapsibleBlockComponent, selector: "he-collapsible-block", inputs: ["heading", "collapsible", "open"], outputs: ["openChange"] }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11722
12090
|
}
|
|
11723
12091
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregatedFormulasComponent, decorators: [{
|
|
11724
12092
|
type: Component$1,
|
|
11725
|
-
args: [{ selector: 'he-node-aggregated-formulas', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
11726
|
-
|
|
12093
|
+
args: [{ selector: 'he-node-aggregated-formulas', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
12094
|
+
DefaultPipe,
|
|
12095
|
+
PrecisionPipe,
|
|
12096
|
+
KatexDirective,
|
|
12097
|
+
NodeLinkComponent,
|
|
12098
|
+
FormulaBlockComponent,
|
|
12099
|
+
CollapsibleBlockComponent
|
|
12100
|
+
], template: "@if (renderedSections().length) {\n <div class=\"aggregated-formulas\">\n <p class=\"is-size-7 is-mb-2 | formula-intro\">\n Aggregated values are calculated from the underlying Cycles, not measured. These are the rules that produced this\n one, in the order they are applied.\n </p>\n\n <div class=\"is-pt-2 is-pr-1 is-overflow-y-auto | aggregated-formulas-rules\">\n @for (section of renderedSections(); track section.id; let first = $first) {\n <he-formula-block\n [formulas]=\"section.formulas\"\n [heading]=\"section.heading\"\n [collapsible]=\"true\"\n [showToggle]=\"first\"\n [hasSubstitutions]=\"hasSubstitutions()\"\n [(substituted)]=\"substituted\"\n emptyTitle=\"No recorded values to substitute\" />\n\n <!-- the values combined sit between the two calculations: what went in, above how each was weighted -->\n @if (section.id === 'value' && contributors(); as table) {\n <he-collapsible-block heading=\"Values combined\">\n @if (table.rows.length) {\n <table class=\"table is-narrow is-size-7 w-100 | contributors-table\">\n <thead>\n <tr>\n <th>Cycle</th>\n @for (column of table.columns; track column.symbol) {\n <th class=\"has-text-right\">\n <span [heKatex]=\"column.symbol\" [heKatexInline]=\"true\"></span>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table.rows; track row.id) {\n <tr>\n <td [attr.title]=\"row.id\">\n <he-node-link [node]=\"row.node\" linkClass=\"has-text-white\">\n <span class=\"break-word\">{{ row.label }}</span>\n </he-node-link>\n </td>\n @for (value of row.values; track $index) {\n <td class=\"has-text-right is-nowrap\">{{ value | precision: 4 | default: '-' }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"is-size-7\">\n Combined from {{ table.count }} Cycles, too many for the aggregation to record one by one.\n </p>\n }\n </he-collapsible-block>\n }\n }\n </div>\n </div>\n}\n", styles: [".formula-intro{opacity:.85}.contributors-table{background-color:transparent;color:inherit}.contributors-table th,.contributors-table td{border-color:#fff3;color:inherit;padding:.15rem .5rem .15rem 0;vertical-align:top}.contributors-table th{opacity:.7}.contributors-table ::ng-deep .katex{font-size:1em}.aggregated-formulas-rules{max-height:50vh}\n"] }]
|
|
12101
|
+
}], propDecorators: { termType: [{ type: i0.Input, args: [{ isSignal: true, alias: "termType", required: false }] }], termId: [{ type: i0.Input, args: [{ isSignal: true, alias: "termId", required: false }] }], nodeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKey", required: false }] }], values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: false }] }], worldAggregation: [{ type: i0.Input, args: [{ isSignal: true, alias: "worldAggregation", required: false }] }], subAggregation: [{ type: i0.Input, args: [{ isSignal: true, alias: "subAggregation", required: false }] }], substituted: [{ type: i0.Input, args: [{ isSignal: true, alias: "substituted", required: false }] }, { type: i0.Output, args: ["substitutedChange"] }] } });
|
|
12102
|
+
|
|
12103
|
+
// the `.jlog` entries the aggregation records are tagged with its own model name
|
|
12104
|
+
const JLOG_MODEL = 'aggregation';
|
|
12105
|
+
const LOGS_KEY = 'logs';
|
|
12106
|
+
// the table of contributors an aggregated value is recorded with, one row per Cycle it was
|
|
12107
|
+
// combined from: `id:<cycle id>_value:<value>_weight:<weight>;...`
|
|
12108
|
+
const WEIGHTS_KEY = 'weights';
|
|
12109
|
+
const ID_COLUMN = 'id:';
|
|
12110
|
+
/**
|
|
12111
|
+
* The share of world production a country aggregation was weighted by. It is only recorded on a
|
|
12112
|
+
* Cycle that a World aggregation combines, so its presence is what tells the two node-level
|
|
12113
|
+
* entries apart.
|
|
12114
|
+
*/
|
|
12115
|
+
const WORLD_STAGE_KEY = 'world_production';
|
|
12116
|
+
// the sub-system stage: the organic and irrigated factors a sub-aggregation's weight is the product of
|
|
12117
|
+
const SUB_SYSTEM_KEY = 'organic_factor';
|
|
12118
|
+
/**
|
|
12119
|
+
* The lookups an aggregation is weighted by: the shares of the country's area, keyed by country and
|
|
12120
|
+
* period, and the plantation lifespans, keyed by product. Every sub-aggregation of the same country
|
|
12121
|
+
* and period records the same values, so any one of them answers for the aggregation as a whole.
|
|
12122
|
+
*/
|
|
12123
|
+
const LOOKUP_KEYS = [
|
|
12124
|
+
'organic_weight',
|
|
12125
|
+
'organic_weight_lookup_value',
|
|
12126
|
+
'irrigated_weight',
|
|
12127
|
+
'irrigated_area',
|
|
12128
|
+
'total_area',
|
|
12129
|
+
'plantation_lifespan',
|
|
12130
|
+
'plantation_non_productive_lifespan'
|
|
12131
|
+
];
|
|
12132
|
+
/**
|
|
12133
|
+
* A Cycle combined from sub-aggregations has a handful of contributors (organic or conventional,
|
|
12134
|
+
* irrigated or rainfed); one aggregated straight from source Cycles has hundreds, and those record
|
|
12135
|
+
* no aggregation logs at all - so a longer list means there is nothing to fetch.
|
|
12136
|
+
*/
|
|
12137
|
+
const MAX_CONTRIBUTORS = 4;
|
|
12138
|
+
// the quantities of one `.jlog` entry, dropping the `model` marker that tags them
|
|
12139
|
+
const entryValues = (entry) => (entry?.[LOGS_KEY] ?? [])
|
|
12140
|
+
.filter(log => log?.model === JLOG_MODEL)
|
|
12141
|
+
.reduce((values, { model: _model, ...fields }) => ({ ...values, ...fields }), {});
|
|
12142
|
+
/**
|
|
12143
|
+
* The quantities recorded for one blank node. A field of the blank node (e.g. a product's
|
|
12144
|
+
* `economicValueShare`) is logged one level deeper, the way the models' `.jlog` nests it - merge
|
|
12145
|
+
* those in so a formula resolves whichever of the two it describes, the blank node's own values
|
|
12146
|
+
* winning any collision.
|
|
12147
|
+
*/
|
|
12148
|
+
const loggedValues = (entry) => {
|
|
12149
|
+
const nested = Object.entries(entry ?? {})
|
|
12150
|
+
.filter(([key]) => key !== LOGS_KEY)
|
|
12151
|
+
.reduce((values, [, field]) => ({ ...values, ...entryValues(field) }), {});
|
|
12152
|
+
return { ...nested, ...entryValues(entry) };
|
|
12153
|
+
};
|
|
12154
|
+
/**
|
|
12155
|
+
* The quantities describing the Cycle itself, recorded once at the top of its `.jlog` rather than
|
|
12156
|
+
* on each data item: how it was weighted into the aggregation it belongs to, and the shares that
|
|
12157
|
+
* weight was derived from.
|
|
12158
|
+
*
|
|
12159
|
+
* A country aggregation records its share of world production here, weighted by `weight` - the same
|
|
12160
|
+
* key the sub-system stage binds to. Drop it there, so the world share can never stand in for a
|
|
12161
|
+
* sub-system weight.
|
|
12162
|
+
*/
|
|
12163
|
+
const nodeValues = (jlog) => {
|
|
12164
|
+
const values = entryValues(jlog);
|
|
12165
|
+
return WORLD_STAGE_KEY in values
|
|
12166
|
+
? Object.fromEntries(Object.entries(values).filter(([key]) => key !== 'weight'))
|
|
12167
|
+
: values;
|
|
12168
|
+
};
|
|
12169
|
+
/**
|
|
12170
|
+
* Whether the sub-system stage is one of the stages that produced this Cycle's values, which its
|
|
12171
|
+
* own node-level entry says. Everywhere else its symbols hold one value per sub-system rather than
|
|
12172
|
+
* the single one the formula binds, so it describes another Cycle rather than this one.
|
|
12173
|
+
*
|
|
12174
|
+
* With nothing logged at all the stage is left to render symbolically, as every other rule does,
|
|
12175
|
+
* rather than hidden on a guess.
|
|
12176
|
+
*/
|
|
12177
|
+
const isSubAggregation = (jlog) => {
|
|
12178
|
+
const values = nodeValues(jlog);
|
|
12179
|
+
return isEmpty(values) || SUB_SYSTEM_KEY in values;
|
|
12180
|
+
};
|
|
12181
|
+
// the ids of a packed contributors table, in the order they were recorded
|
|
12182
|
+
const tableIds = (packed) => typeof packed === 'string'
|
|
12183
|
+
? packed
|
|
12184
|
+
.split(';')
|
|
12185
|
+
.map(row => row.split('_')[0])
|
|
12186
|
+
.filter(column => column.startsWith(ID_COLUMN))
|
|
12187
|
+
.map(column => column.slice(ID_COLUMN.length))
|
|
12188
|
+
: [];
|
|
12189
|
+
/**
|
|
12190
|
+
* The Cycles this one was combined from, named in the contributors table of any of its data items -
|
|
12191
|
+
* the only place a sub-aggregation is named, as the Cycle links the source Cycles it covers rather
|
|
12192
|
+
* than the sub-aggregations it was built from.
|
|
12193
|
+
*
|
|
12194
|
+
* Empty for a sub-aggregation, which records the lookups itself and was built from source Cycles
|
|
12195
|
+
* that log nothing, and when there are more contributors than there are sub-systems - a longer list
|
|
12196
|
+
* is source Cycles rather than sub-aggregations.
|
|
12197
|
+
*/
|
|
12198
|
+
const contributorIds = (jlog) => {
|
|
12199
|
+
if (SUB_SYSTEM_KEY in nodeValues(jlog))
|
|
12200
|
+
return [];
|
|
12201
|
+
const tables = Object.values(jlog ?? {})
|
|
12202
|
+
.filter(section => !!section && typeof section === 'object' && !Array.isArray(section))
|
|
12203
|
+
.flatMap(section => Object.values(section).map(entry => entryValues(entry)[WEIGHTS_KEY]));
|
|
12204
|
+
const ids = unique(tableIds(tables.find(table => typeof table === 'string')));
|
|
12205
|
+
return ids.length > MAX_CONTRIBUTORS ? [] : ids;
|
|
12206
|
+
};
|
|
12207
|
+
/**
|
|
12208
|
+
* The country shares, taken from the first contributor that records them. They are the same on
|
|
12209
|
+
* every sub-aggregation of the country and period, so one readable Cycle answers for all of them -
|
|
12210
|
+
* and none being readable leaves those symbols symbolic, as they are today.
|
|
12211
|
+
*/
|
|
12212
|
+
const sharedLookups = (jlogs) => (jlogs ?? [])
|
|
12213
|
+
.map(jlog => Object.entries(nodeValues(jlog)).filter(([key]) => LOOKUP_KEYS.includes(key)))
|
|
12214
|
+
.map(entries => Object.fromEntries(entries))
|
|
12215
|
+
.find(values => !isEmpty(values)) ?? {};
|
|
11727
12216
|
|
|
11728
12217
|
// Aggregation has a single "model" - unlike a recalculation, where each term may be produced by a
|
|
11729
12218
|
// different one - so the column is a constant rather than something resolved per row.
|
|
@@ -11748,25 +12237,6 @@ const isWorldAggregation = (node) => {
|
|
|
11748
12237
|
? country['@id'] === WORLD_COUNTRY_ID
|
|
11749
12238
|
: node?.name?.split(' - ')?.[1]?.trim() === WORLD_COUNTRY_NAME;
|
|
11750
12239
|
};
|
|
11751
|
-
// the `.jlog` entries the aggregation records are tagged with its own model name
|
|
11752
|
-
const JLOG_MODEL = 'aggregation';
|
|
11753
|
-
const LOGS_KEY = 'logs';
|
|
11754
|
-
// the quantities of one `.jlog` entry, dropping the `model` marker that tags them
|
|
11755
|
-
const entryValues = (entry) => (entry?.[LOGS_KEY] ?? [])
|
|
11756
|
-
.filter(log => log?.model === JLOG_MODEL)
|
|
11757
|
-
.reduce((values, { model: _model, ...fields }) => ({ ...values, ...fields }), {});
|
|
11758
|
-
/**
|
|
11759
|
-
* The quantities recorded for one blank node. A field of the blank node (e.g. a product's
|
|
11760
|
-
* `economicValueShare`) is logged one level deeper, the way the models' `.jlog` nests it - merge
|
|
11761
|
-
* those in so a formula resolves whichever of the two it describes, the blank node's own values
|
|
11762
|
-
* winning any collision.
|
|
11763
|
-
*/
|
|
11764
|
-
const loggedValues = (entry) => {
|
|
11765
|
-
const nested = Object.entries(entry ?? {})
|
|
11766
|
-
.filter(([key]) => key !== LOGS_KEY)
|
|
11767
|
-
.reduce((values, [, field]) => ({ ...values, ...entryValues(field) }), {});
|
|
11768
|
-
return { ...nested, ...entryValues(entry) };
|
|
11769
|
-
};
|
|
11770
12240
|
const groupObservations = (rows) => {
|
|
11771
12241
|
const counts = rows.map(({ observations }) => observations).filter(count => typeof count === 'number');
|
|
11772
12242
|
if (!counts.length)
|
|
@@ -11827,6 +12297,23 @@ class NodeAggregationLogsComponent {
|
|
|
11827
12297
|
const index = this.jlogParentIndex();
|
|
11828
12298
|
return key && typeof index === 'number' && index >= 0 ? (this.jlog()?.[key]?.[index] ?? {}) : this.jlog();
|
|
11829
12299
|
}, ...(ngDevMode ? [{ debugName: "scopedJlog" }] : []));
|
|
12300
|
+
// the quantities describing the Cycle itself rather than one of its data items, which the
|
|
12301
|
+
// aggregation records once at the top of the `.jlog`
|
|
12302
|
+
this.nodeValues = computed(() => nodeValues(this.scopedJlog()), ...(ngDevMode ? [{ debugName: "nodeValues" }] : []));
|
|
12303
|
+
// whether the sub-system weighting is one of the stages that produced these values
|
|
12304
|
+
this.subAggregation = computed(() => isSubAggregation(this.scopedJlog()), ...(ngDevMode ? [{ debugName: "subAggregation" }] : []));
|
|
12305
|
+
/**
|
|
12306
|
+
* The `.jlog` of every sub-aggregation this Cycle was combined from, for the country shares the
|
|
12307
|
+
* aggregation only records on them. Best effort: a reader without access to a sub-aggregation
|
|
12308
|
+
* gets nothing back, and those symbols stay symbolic - which is how they render today.
|
|
12309
|
+
*/
|
|
12310
|
+
this.contributorsResource = rxResource({
|
|
12311
|
+
params: () => ({ ids: contributorIds(this.scopedJlog()) }),
|
|
12312
|
+
stream: ({ params: { ids } }) => ids.length
|
|
12313
|
+
? forkJoin(ids.map(id => this.nodeLogsModelsService.getJLog$({ '@type': NodeType.Cycle, '@id': id, aggregated: true })))
|
|
12314
|
+
: of([])
|
|
12315
|
+
});
|
|
12316
|
+
this.sharedLookups = computed(() => sharedLookups(this.contributorsResource.value() ?? []), ...(ngDevMode ? [{ debugName: "sharedLookups" }] : []));
|
|
11830
12317
|
// groups kept open, by term id: expanding is view state, so it survives the rows being rebuilt
|
|
11831
12318
|
this.openGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "openGroups" }] : []));
|
|
11832
12319
|
/**
|
|
@@ -11838,10 +12325,13 @@ class NodeAggregationLogsComponent {
|
|
|
11838
12325
|
const blankNodes = (this.node()?.[this.nodeKey()] ?? []);
|
|
11839
12326
|
const logs = this.scopedJlog()?.[this.nodeKey()] ?? {};
|
|
11840
12327
|
const open = this.openGroups();
|
|
12328
|
+
// a data item's own quantities win over the ones describing the whole Cycle, which in turn win
|
|
12329
|
+
// over the country shares read from a sub-aggregation
|
|
12330
|
+
const shared = { ...this.sharedLookups(), ...this.nodeValues() };
|
|
11841
12331
|
return groupBlankNodesByTermIdentity(blankNodes, this.nodeType(), this.nodeKey()).map(group => {
|
|
11842
12332
|
const rows = group.rows.map(row => ({
|
|
11843
12333
|
...row,
|
|
11844
|
-
values: loggedValues(logs[row.index]),
|
|
12334
|
+
values: { ...shared, ...loggedValues(logs[row.index]) },
|
|
11845
12335
|
displayValue: propertyValue$1(row.value?.value, group.termId),
|
|
11846
12336
|
observations: row.value?.observations
|
|
11847
12337
|
}));
|
|
@@ -11863,7 +12353,7 @@ class NodeAggregationLogsComponent {
|
|
|
11863
12353
|
return `${row.index}-${row.label}`;
|
|
11864
12354
|
}
|
|
11865
12355
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregationLogsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11866
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregationLogsComponent, isStandalone: true, selector: "he-node-aggregation-logs", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, termType: { classPropertyName: "termType", publicName: "termType", isSignal: true, isRequired: false, transformFunction: null }, termId: { classPropertyName: "termId", publicName: "termId", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n</div>\n\n<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\"><span>Units</span></th>\n <th class=\"has-border-right\"><span>Aggregated</span></th>\n <th class=\"has-border-right\">\n <span title=\"The number of Cycles the value was aggregated from\">Observations</span>\n </th>\n <th class=\"has-border-right\"><span>Model</span></th>\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 aggregated data 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 <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 </div>\n </td>\n\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0], term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row: group.rows[0] }\" />\n } @else {\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"group.term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n @if (group.valueFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.valueFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n {{ group.value | precision: 3 | default: '-' }}\n </span>\n } @else {\n {{ group.value | precision: 3 | default: '-' }}\n }\n </td>\n <td class=\"has-border-right is-nowrap\">{{ group.observations | default: '-' }}</td>\n <ng-container *ngTemplateOutlet=\"modelCell\" />\n }\n </tr>\n\n @if (!single && group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr class=\"is-sub-row\">\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 <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <he-blank-node-identity\n [segments]=\"row.segments\"\n [scalars]=\"row.scalars\"\n [type]=\"group.type\"\n [fallback]=\"'entry ' + (row.index + 1)\" />\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row, term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row }\" />\n </tr>\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<ng-template #valueCells let-row=\"row\" let-term=\"term\">\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.displayValue | precision: 3 | default: '-' }}\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.observations | default: '-' }}\n </td>\n</ng-template>\n\n<!-- `row` is left out on a term group: the rules are the same for every entry it holds, so the guide\n is shown there too, but the values to substitute belong to one entry - those stay on the sub-rows -->\n<ng-template #modelCell let-row=\"row\">\n <td class=\"has-border-right\">\n <div class=\"is-flex is-align-self-stretch is-align-items-center is-gap-8\">\n <span class=\"is-flex-grow-1 is-nowrap\">{{ modelName }}</span>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (row) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"aggregationRules\"\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({ values: row.values })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n } @else {\n <span class=\"has-text-grey is-nowrap\">Expand for logs</span>\n }\n\n <div class=\"vertical-divider\"></div>\n\n @if (guideEnabled) {\n <he-guide-overlay [pageId]=\"guidePage()\" [width]=\"500\" />\n } @else {\n <a [href]=\"guideHref()\" target=\"_blank\" rel=\"noopener\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </div>\n </div>\n </td>\n</ng-template>\n\n<ng-template #aggregationRules let-values=\"values\">\n <he-node-aggregated-formulas\n [termType]=\"termType()\"\n [termId]=\"termId()\"\n [nodeKey]=\"nodeKey()\"\n [values]=\"values\"\n [worldAggregation]=\"worldAggregation()\" />\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}: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}::ng-deep .table th:last-child,::ng-deep .table td:last-child{min-width:12rem}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeIdentityComponent, selector: "he-blank-node-identity", inputs: ["segments", "scalars", "type", "fallback"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "component", type: NodeAggregatedFormulasComponent, selector: "he-node-aggregated-formulas", inputs: ["termType", "termId", "nodeKey", "values", "worldAggregation", "substituted"], outputs: ["substitutedChange"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12356
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregationLogsComponent, isStandalone: true, selector: "he-node-aggregation-logs", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, termType: { classPropertyName: "termType", publicName: "termType", isSignal: true, isRequired: false, transformFunction: null }, termId: { classPropertyName: "termId", publicName: "termId", isSignal: true, isRequired: false, transformFunction: null }, jlogParentKey: { classPropertyName: "jlogParentKey", publicName: "jlogParentKey", isSignal: true, isRequired: false, transformFunction: null }, jlogParentIndex: { classPropertyName: "jlogParentIndex", publicName: "jlogParentIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n</div>\n\n<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\"><span>Units</span></th>\n <th class=\"has-border-right\"><span>Aggregated</span></th>\n <th class=\"has-border-right\">\n <span title=\"The number of Cycles the value was aggregated from\">Observations</span>\n </th>\n <th class=\"has-border-right\"><span>Model</span></th>\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 aggregated data 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 <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 </div>\n </td>\n\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0], term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row: group.rows[0] }\" />\n } @else {\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"group.term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n @if (group.valueFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.valueFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n {{ group.value | precision: 3 | default: '-' }}\n </span>\n } @else {\n {{ group.value | precision: 3 | default: '-' }}\n }\n </td>\n <td class=\"has-border-right is-nowrap\">{{ group.observations | default: '-' }}</td>\n <ng-container *ngTemplateOutlet=\"modelCell\" />\n }\n </tr>\n\n @if (!single && group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr class=\"is-sub-row\">\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 <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <he-blank-node-identity\n [segments]=\"row.segments\"\n [scalars]=\"row.scalars\"\n [type]=\"group.type\"\n [fallback]=\"'entry ' + (row.index + 1)\" />\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row, term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row }\" />\n </tr>\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<ng-template #valueCells let-row=\"row\" let-term=\"term\">\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.displayValue | precision: 3 | default: '-' }}\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.observations | default: '-' }}\n </td>\n</ng-template>\n\n<!-- `row` is left out on a term group: the rules are the same for every entry it holds, so the guide\n is shown there too, but the values to substitute belong to one entry - those stay on the sub-rows -->\n<ng-template #modelCell let-row=\"row\">\n <td class=\"has-border-right\">\n <div class=\"is-flex is-align-self-stretch is-align-items-center is-gap-8\">\n <span class=\"is-flex-grow-1 is-nowrap\">{{ modelName }}</span>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (row) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"aggregationRules\"\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({ values: row.values })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n } @else {\n <span class=\"has-text-grey is-nowrap\">Expand for logs</span>\n }\n\n <div class=\"vertical-divider\"></div>\n\n @if (guideEnabled) {\n <he-guide-overlay [pageId]=\"guidePage()\" [width]=\"500\" />\n } @else {\n <a [href]=\"guideHref()\" target=\"_blank\" rel=\"noopener\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </div>\n </div>\n </td>\n</ng-template>\n\n<ng-template #aggregationRules let-values=\"values\">\n <he-node-aggregated-formulas\n [termType]=\"termType()\"\n [termId]=\"termId()\"\n [nodeKey]=\"nodeKey()\"\n [values]=\"values\"\n [worldAggregation]=\"worldAggregation()\"\n [subAggregation]=\"subAggregation()\" />\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}: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}::ng-deep .table th:last-child,::ng-deep .table td:last-child{min-width:12rem}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgbPopover, selector: "[ngbPopover]", inputs: ["animation", "autoClose", "ngbPopover", "popoverTitle", "placement", "popperOptions", "triggers", "positionTarget", "container", "disablePopover", "popoverClass", "popoverContext", "openDelay", "closeDelay"], outputs: ["shown", "hidden"], exportAs: ["ngbPopover"] }, { kind: "component", type: DataTableComponent, selector: "he-data-table", inputs: ["minHeight", "maxHeight", "small"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "component", type: BlankNodeIdentityComponent, selector: "he-blank-node-identity", inputs: ["segments", "scalars", "type", "fallback"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "component", type: NodeAggregatedFormulasComponent, selector: "he-node-aggregated-formulas", inputs: ["termType", "termId", "nodeKey", "values", "worldAggregation", "subAggregation", "substituted"], outputs: ["substitutedChange"] }, { kind: "pipe", type: CompoundPipe, name: "compound" }, { kind: "pipe", type: DefaultPipe, name: "default" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11867
12357
|
}
|
|
11868
12358
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregationLogsComponent, decorators: [{
|
|
11869
12359
|
type: Component$1,
|
|
@@ -11879,7 +12369,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
11879
12369
|
BlankNodeIdentityComponent,
|
|
11880
12370
|
GuideOverlayComponent,
|
|
11881
12371
|
NodeAggregatedFormulasComponent
|
|
11882
|
-
], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n</div>\n\n<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\"><span>Units</span></th>\n <th class=\"has-border-right\"><span>Aggregated</span></th>\n <th class=\"has-border-right\">\n <span title=\"The number of Cycles the value was aggregated from\">Observations</span>\n </th>\n <th class=\"has-border-right\"><span>Model</span></th>\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 aggregated data 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 <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 </div>\n </td>\n\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0], term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row: group.rows[0] }\" />\n } @else {\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"group.term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n @if (group.valueFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.valueFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n {{ group.value | precision: 3 | default: '-' }}\n </span>\n } @else {\n {{ group.value | precision: 3 | default: '-' }}\n }\n </td>\n <td class=\"has-border-right is-nowrap\">{{ group.observations | default: '-' }}</td>\n <ng-container *ngTemplateOutlet=\"modelCell\" />\n }\n </tr>\n\n @if (!single && group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr class=\"is-sub-row\">\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 <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <he-blank-node-identity\n [segments]=\"row.segments\"\n [scalars]=\"row.scalars\"\n [type]=\"group.type\"\n [fallback]=\"'entry ' + (row.index + 1)\" />\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row, term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row }\" />\n </tr>\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<ng-template #valueCells let-row=\"row\" let-term=\"term\">\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.displayValue | precision: 3 | default: '-' }}\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.observations | default: '-' }}\n </td>\n</ng-template>\n\n<!-- `row` is left out on a term group: the rules are the same for every entry it holds, so the guide\n is shown there too, but the values to substitute belong to one entry - those stay on the sub-rows -->\n<ng-template #modelCell let-row=\"row\">\n <td class=\"has-border-right\">\n <div class=\"is-flex is-align-self-stretch is-align-items-center is-gap-8\">\n <span class=\"is-flex-grow-1 is-nowrap\">{{ modelName }}</span>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (row) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"aggregationRules\"\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({ values: row.values })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n } @else {\n <span class=\"has-text-grey is-nowrap\">Expand for logs</span>\n }\n\n <div class=\"vertical-divider\"></div>\n\n @if (guideEnabled) {\n <he-guide-overlay [pageId]=\"guidePage()\" [width]=\"500\" />\n } @else {\n <a [href]=\"guideHref()\" target=\"_blank\" rel=\"noopener\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </div>\n </div>\n </td>\n</ng-template>\n\n<ng-template #aggregationRules let-values=\"values\">\n <he-node-aggregated-formulas\n [termType]=\"termType()\"\n [termId]=\"termId()\"\n [nodeKey]=\"nodeKey()\"\n [values]=\"values\"\n [worldAggregation]=\"worldAggregation()\" />\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}: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}::ng-deep .table th:last-child,::ng-deep .table td:last-child{min-width:12rem}\n"] }]
|
|
12372
|
+
], template: "<div class=\"is-flex is-gap-8 is-justify-content-space-between is-align-items-center is-my-2\">\n <div>\n <ng-content />\n </div>\n</div>\n\n<he-data-table class=\"is-mt-2 is-mb-1 is-bordered\" [small]=\"true\" maxHeight=\"320\">\n <table class=\"table is-fullwidth is-narrow is-striped\">\n <thead>\n <tr>\n <th class=\"width-auto has-border-right\"></th>\n <th class=\"has-border-right\"><span>Units</span></th>\n <th class=\"has-border-right\"><span>Aggregated</span></th>\n <th class=\"has-border-right\">\n <span title=\"The number of Cycles the value was aggregated from\">Observations</span>\n </th>\n <th class=\"has-border-right\"><span>Model</span></th>\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 aggregated data 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 <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 </div>\n </td>\n\n @if (single) {\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row: group.rows[0], term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row: group.rows[0] }\" />\n } @else {\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"group.term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n @if (group.valueFormula) {\n <span\n class=\"has-formula\"\n [ngbPopover]=\"group.valueFormula\"\n popoverClass=\"is-narrow\"\n triggers=\"click\"\n container=\"body\">\n {{ group.value | precision: 3 | default: '-' }}\n </span>\n } @else {\n {{ group.value | precision: 3 | default: '-' }}\n }\n </td>\n <td class=\"has-border-right is-nowrap\">{{ group.observations | default: '-' }}</td>\n <ng-container *ngTemplateOutlet=\"modelCell\" />\n }\n </tr>\n\n @if (!single && group.isOpen) {\n @for (row of group.rows; track trackByRow($index, row)) {\n <tr class=\"is-sub-row\">\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 <he-svg-icon class=\"sub-sub-row-icon\" name=\"chevron-double-right\" />\n <he-blank-node-identity\n [segments]=\"row.segments\"\n [scalars]=\"row.scalars\"\n [type]=\"group.type\"\n [fallback]=\"'entry ' + (row.index + 1)\" />\n </div>\n </td>\n <ng-container *ngTemplateOutlet=\"valueCells; context: { row, term: group.term }\" />\n <ng-container *ngTemplateOutlet=\"modelCell; context: { row }\" />\n </tr>\n }\n }\n }\n </tbody>\n </table>\n</he-data-table>\n\n<ng-template #valueCells let-row=\"row\" let-term=\"term\">\n <td class=\"has-border-right\">\n <span class=\"is-nowrap\" [innerHtml]=\"term?.units | compound\"></span>\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.displayValue | precision: 3 | default: '-' }}\n </td>\n <td class=\"has-border-right is-nowrap\">\n {{ row.observations | default: '-' }}\n </td>\n</ng-template>\n\n<!-- `row` is left out on a term group: the rules are the same for every entry it holds, so the guide\n is shown there too, but the values to substitute belong to one entry - those stay on the sub-rows -->\n<ng-template #modelCell let-row=\"row\">\n <td class=\"has-border-right\">\n <div class=\"is-flex is-align-self-stretch is-align-items-center is-gap-8\">\n <span class=\"is-flex-grow-1 is-nowrap\">{{ modelName }}</span>\n\n <div class=\"is-flex is-gap-4 is-flex-shrink-0 is-align-items-center\">\n @if (row) {\n <span\n class=\"is-nowrap is-clickable\"\n [ngbPopover]=\"aggregationRules\"\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({ values: row.values })\">\n <span class=\"has-text-link\">Logs</span>\n </span>\n } @else {\n <span class=\"has-text-grey is-nowrap\">Expand for logs</span>\n }\n\n <div class=\"vertical-divider\"></div>\n\n @if (guideEnabled) {\n <he-guide-overlay [pageId]=\"guidePage()\" [width]=\"500\" />\n } @else {\n <a [href]=\"guideHref()\" target=\"_blank\" rel=\"noopener\" (click)=\"$event.stopPropagation()\">\n <span>Docs</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n }\n </div>\n </div>\n </td>\n</ng-template>\n\n<ng-template #aggregationRules let-values=\"values\">\n <he-node-aggregated-formulas\n [termType]=\"termType()\"\n [termId]=\"termId()\"\n [nodeKey]=\"nodeKey()\"\n [values]=\"values\"\n [worldAggregation]=\"worldAggregation()\"\n [subAggregation]=\"subAggregation()\" />\n</ng-template>\n", styles: [":host{display:block}:host .vertical-divider{width:1px;height:20px;background:#dbe3ea}: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}::ng-deep .table th:last-child,::ng-deep .table td:last-child{min-width:12rem}\n"] }]
|
|
11883
12373
|
}], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], nodeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKey", required: false }] }], termType: [{ type: i0.Input, args: [{ isSignal: true, alias: "termType", required: false }] }], termId: [{ type: i0.Input, args: [{ isSignal: true, alias: "termId", required: false }] }], jlogParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentKey", required: false }] }], jlogParentIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "jlogParentIndex", required: false }] }] } });
|
|
11884
12374
|
|
|
11885
12375
|
const isValidDate = (date) => (date || '').trim().length === 10;
|
|
@@ -12479,18 +12969,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
12479
12969
|
|
|
12480
12970
|
// default for all product termType, can be overwritten
|
|
12481
12971
|
const defaultMinNbObservations = 50;
|
|
12972
|
+
// the `.jlog` section the aggregation stores the quality score in, and the model tagging its entries
|
|
12973
|
+
const jlogKey = 'aggregatedQualityScore';
|
|
12974
|
+
const jlogModel = 'aggregation';
|
|
12975
|
+
const isTrue = (value) => value === true || value === 'True';
|
|
12976
|
+
/**
|
|
12977
|
+
* Whether a quantity was logged: one that was not found is logged as `None`, which the `.jlog`
|
|
12978
|
+
* carries as it is written.
|
|
12979
|
+
*/
|
|
12980
|
+
const hasLogValue = (value) => !isUndefined(value) && !isNaN(+value);
|
|
12482
12981
|
const isScoreValid = {
|
|
12483
|
-
0: ({ all_included }) => all_included
|
|
12982
|
+
0: ({ all_included }) => isTrue(all_included),
|
|
12484
12983
|
1: ({ nb_observations, min_nb_observations }) => +nb_observations >= (+min_nb_observations || defaultMinNbObservations),
|
|
12485
12984
|
2: ({ delta, delta_min, yield_delta, yield_delta_min }) => isUndefined(delta) ? +yield_delta <= +yield_delta_min : +delta <= +delta_min,
|
|
12486
|
-
3: ({ is_complete }) => is_complete
|
|
12985
|
+
3: ({ is_complete }) => isTrue(is_complete),
|
|
12487
12986
|
4: ({ production_delta, production_delta_min }) => +production_delta >= +production_delta_min
|
|
12488
12987
|
};
|
|
12988
|
+
/**
|
|
12989
|
+
* The quality score recorded in the `.jlog`, merged into a single set of values.
|
|
12990
|
+
* Empty for every aggregation that predates it, which only has the text logs.
|
|
12991
|
+
*/
|
|
12992
|
+
const jlogScore = (jlog) => (jlog?.[jlogKey]?.logs ?? [])
|
|
12993
|
+
.filter(({ model }) => model === jlogModel)
|
|
12994
|
+
.reduce((values, { model: _model, ...fields }) => ({ ...values, ...fields }), {});
|
|
12995
|
+
const toValidScores = (logs) => Object.fromEntries(Object.entries(isScoreValid).map(([key, isValid]) => [key, isValid(logs)]));
|
|
12996
|
+
|
|
12489
12997
|
const getCountryName = (node) => node?.site?.country?.name || node.name?.split(' - ')?.[1]?.trim();
|
|
12490
12998
|
class NodeAggregatedQualityScoreComponent {
|
|
12491
12999
|
constructor() {
|
|
12492
13000
|
this.searchService = inject(HeSearchService);
|
|
12493
13001
|
this.nodeService = inject(HeNodeService);
|
|
13002
|
+
this.nodeLogsModelsService = inject(NodeLogsModelsService);
|
|
12494
13003
|
this.node = input.required(...(ngDevMode ? [{ debugName: "node" }] : []));
|
|
12495
13004
|
this.country = input(...(ngDevMode ? [undefined, { debugName: "country" }] : []));
|
|
12496
13005
|
/**
|
|
@@ -12530,22 +13039,34 @@ class NodeAggregatedQualityScoreComponent {
|
|
|
12530
13039
|
: of(undefined)
|
|
12531
13040
|
});
|
|
12532
13041
|
this.countryId = computed(() => this.countryResource.value()?.['@id'], ...(ngDevMode ? [{ debugName: "countryId" }] : []));
|
|
12533
|
-
|
|
13042
|
+
// the score as recorded in the `.jlog`, which is where every new aggregation logs it
|
|
13043
|
+
this.jlogResource = rxResource({
|
|
12534
13044
|
params: () => ({
|
|
12535
13045
|
showInfo: this.showInfo(),
|
|
12536
13046
|
node: this.node()
|
|
12537
13047
|
}),
|
|
12538
|
-
stream: ({ params: { showInfo, node } }) => showInfo
|
|
12539
|
-
|
|
13048
|
+
stream: ({ params: { showInfo, node } }) => showInfo ? this.nodeLogsModelsService.getJLog$(node) : of({})
|
|
13049
|
+
});
|
|
13050
|
+
this.jlogLogs = computed(() => jlogScore(this.jlogResource.value() ?? {}), ...(ngDevMode ? [{ debugName: "jlogLogs" }] : []));
|
|
13051
|
+
this.loadingJLog = computed(() => !this.jlogResource.hasValue() || this.jlogResource.isLoading(), ...(ngDevMode ? [{ debugName: "loadingJLog" }] : []));
|
|
13052
|
+
this.useJLog = computed(() => !isEmpty(this.jlogLogs()), ...(ngDevMode ? [{ debugName: "useJLog" }] : []));
|
|
13053
|
+
// only fetch the legacy text logs once we know the `.jlog` does not carry the score
|
|
13054
|
+
this.logsResource = rxResource({
|
|
13055
|
+
params: () => ({
|
|
13056
|
+
skip: !this.showInfo() || this.loadingJLog() || this.useJLog(),
|
|
13057
|
+
node: this.node()
|
|
13058
|
+
}),
|
|
13059
|
+
stream: ({ params: { skip, node } }) => skip
|
|
13060
|
+
? of({})
|
|
13061
|
+
: this.nodeService
|
|
12540
13062
|
.getLog$({
|
|
12541
13063
|
'@type': node['@type'],
|
|
12542
13064
|
'@id': node['@id']
|
|
12543
13065
|
})
|
|
12544
13066
|
.pipe(map(value => (value ? parseLines(value) : [])), mergeAll(), filter(({ data: { message } }) => !!message), map(({ data: { message } }) => parseMessage(message)), filter(({ id }) => id === this.node()['@id']), reduce((a, b) => ({ ...a, ...b }), {}))
|
|
12545
|
-
: of({})
|
|
12546
13067
|
});
|
|
12547
|
-
this.logs = computed(() => this.logsResource.value() ?? {}, ...(ngDevMode ? [{ debugName: "logs" }] : []));
|
|
12548
|
-
this.validScores = computed(() =>
|
|
13068
|
+
this.logs = computed(() => this.useJLog() ? this.jlogLogs() : (this.logsResource.value() ?? {}), ...(ngDevMode ? [{ debugName: "logs" }] : []));
|
|
13069
|
+
this.validScores = computed(() => toValidScores(this.logs()), ...(ngDevMode ? [{ debugName: "validScores" }] : []));
|
|
12549
13070
|
this.minObservations = computed(() => +this.logs().min_nb_observations || defaultMinNbObservations, ...(ngDevMode ? [{ debugName: "minObservations" }] : []));
|
|
12550
13071
|
this.observations = computed(() => +this.logs().nb_observations, ...(ngDevMode ? [{ debugName: "observations" }] : []));
|
|
12551
13072
|
this.missingEmissionIds = computed(() => this.logs().missing_emissions?.split(';') ?? [], ...(ngDevMode ? [{ debugName: "missingEmissionIds" }] : []));
|
|
@@ -12591,10 +13112,16 @@ class NodeAggregatedQualityScoreComponent {
|
|
|
12591
13112
|
this.isGlobal = computed(() => this.countryId()?.startsWith('region-'), ...(ngDevMode ? [{ debugName: "isGlobal" }] : []));
|
|
12592
13113
|
this.schemaBaseUrl = computed(() => [schemaBaseUrl(), this.node()?.['@type']].join('/'), ...(ngDevMode ? [{ debugName: "schemaBaseUrl" }] : []));
|
|
12593
13114
|
this.schemaUrl = computed(() => `${this.schemaBaseUrl()}#aggregatedQualityScore`, ...(ngDevMode ? [{ debugName: "schemaUrl" }] : []));
|
|
12594
|
-
this.
|
|
13115
|
+
this.hasFaostatYield = computed(() => hasLogValue(this.logs()?.faostat_yield), ...(ngDevMode ? [{ debugName: "hasFaostatYield" }] : []));
|
|
13116
|
+
this.hasProductionQuantity = computed(() => hasLogValue(this.logs()?.region_production_quantity), ...(ngDevMode ? [{ debugName: "hasProductionQuantity" }] : []));
|
|
12595
13117
|
this.regionProductionQuantity = computed(() => +this.logs()?.region_production_quantity, ...(ngDevMode ? [{ debugName: "regionProductionQuantity" }] : []));
|
|
12596
13118
|
this.countriesProductionQuantity = computed(() => +this.logs()?.countries_production_quantity, ...(ngDevMode ? [{ debugName: "countriesProductionQuantity" }] : []));
|
|
12597
|
-
this.loading = computed(() => [
|
|
13119
|
+
this.loading = computed(() => [
|
|
13120
|
+
this.jlogResource.isLoading(),
|
|
13121
|
+
this.logsResource.isLoading(),
|
|
13122
|
+
this.countryResource.isLoading(),
|
|
13123
|
+
this.missingEmissionsResource.isLoading()
|
|
13124
|
+
].some(Boolean), ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
12598
13125
|
}
|
|
12599
13126
|
get hidden() {
|
|
12600
13127
|
return isUndefined(this.score());
|
|
@@ -12606,7 +13133,7 @@ class NodeAggregatedQualityScoreComponent {
|
|
|
12606
13133
|
return term['@id'];
|
|
12607
13134
|
}
|
|
12608
13135
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregatedQualityScoreComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12609
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregatedQualityScoreComponent, isStandalone: true, selector: "he-node-aggregated-quality-score", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, country: { classPropertyName: "country", publicName: "country", isSignal: true, isRequired: false, transformFunction: null }, showInfo: { classPropertyName: "showInfo", publicName: "showInfo", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-none": "this.hidden" } }, ngImport: i0, template: "@if (score() >= 0) {\n @switch (mode()) {\n @case ('tag') {\n <div class=\"tags has-addons\">\n <a class=\"tag\" [href]=\"schemaUrl()\" target=\"_blank\">Data Quality</a>\n <ng-container *ngTemplateOutlet=\"quality\" />\n @if (showInfo()) {\n <span\n class=\"tag pointer\"\n [ngbTooltip]=\"logsTooltip\"\n [placement]=\"placement() + ' auto'\"\n triggers=\"click\"\n container=\"body\"\n autoClose=\"outside\"\n tooltipClass=\"quality-tooltip\">\n @if (loading()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else if (logs()) {\n <he-svg-icon name=\"help-circle\" />\n }\n </span>\n }\n </div>\n }\n @default {\n <ng-container *ngTemplateOutlet=\"quality\" />\n }\n }\n}\n\n<ng-template #quality>\n <span\n [ngStyle]=\"{\n 'background-color': scoreColor()\n }\"\n class=\"tag-score | tag is-primary has-text-white has-text-weight-semibold\">\n <span>{{ scoreLevel() | uppercase }}</span>\n </span>\n</ng-template>\n\n<ng-template #logsTooltip>\n <div>\n <p class=\"mb-2\">\n Up to {{ scoreMax() }} points are awarded for the following criteria, where \"low\" is 0 to\n {{ scoreMax() - 3 }} points, \"medium\" is {{ scoreMax() - 2 }} to {{ scoreMax() - 1 }} points, and \"high\" is\n {{ scoreMax() }} points:\n </p>\n @if (validScores()) {\n <div class=\"table-container\">\n <table class=\"table is-fullwidth has-text-white has-background-secondary\">\n <thead>\n <tr>\n <th class=\"has-text-white\">Condition</th>\n <th class=\"has-text-white\">Met</th>\n @if (isCycle()) {\n <th class=\"has-text-white\">Details</th>\n }\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>No aggregated emissions included in the system boundary are missing</td>\n <td [class.has-text-success]=\"validScores()[0]\" [class.has-text-danger]=\"!validScores()[0]\">\n {{ validScores()[0] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingEmissions()?.length) {\n <span>{{ missingEmissions().length }}</span>\n <span class=\"is-pl-1\">{{ 'emission' | pluralize: missingEmissions().length }} are missing:</span>\n <div class=\"is-mt-2 | missing-emissions\">\n <ul class=\"is-list-style-disc is-pl-4\">\n @for (term of missingEmissions(); track trackByTerm($index, term); let l = $last) {\n <li>\n <he-node-link class=\"is-inline-block is-pl-1\" linkClass=\"is-dark\" [node]=\"term\">\n <span class=\"is-nowrap has-text-ellipsis\">{{ term.name }}</span>\n </he-node-link>\n </li>\n }\n </ul>\n </div>\n } @else if (logs()?.included_emissions) {\n <span>\n All {{ logs().included_emissions }} {{ 'emission' | pluralize: +logs().included_emissions }} for\n this product are included.\n </span>\n }\n </td>\n }\n </tr>\n <tr>\n <td>The aggregation is based on data from over {{ minObservations() }} Cycles</td>\n <td [class.has-text-success]=\"validScores()[1]\" [class.has-text-danger]=\"!validScores()[1]\">\n {{ validScores()[1] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n <span>Based on {{ observations() }} {{ 'Cycle' | pluralize: observations() }}.</span>\n </td>\n }\n </tr>\n @if (isCrop()) {\n <tr>\n <td>\n The difference between yield per hectare here and FAOSTAT is less than \u00B1{{\n logs().yield_delta_min || logs().delta_min | number\n }}%\n </td>\n <td [class.has-text-success]=\"validScores()[2]\" [class.has-text-danger]=\"!validScores()[2]\">\n {{ validScores()[2] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (
|
|
13136
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeAggregatedQualityScoreComponent, isStandalone: true, selector: "he-node-aggregated-quality-score", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, country: { classPropertyName: "country", publicName: "country", isSignal: true, isRequired: false, transformFunction: null }, showInfo: { classPropertyName: "showInfo", publicName: "showInfo", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-none": "this.hidden" } }, ngImport: i0, template: "@if (score() >= 0) {\n @switch (mode()) {\n @case ('tag') {\n <div class=\"tags has-addons\">\n <a class=\"tag\" [href]=\"schemaUrl()\" target=\"_blank\">Data Quality</a>\n <ng-container *ngTemplateOutlet=\"quality\" />\n @if (showInfo()) {\n <span\n class=\"tag pointer\"\n [ngbTooltip]=\"logsTooltip\"\n [placement]=\"placement() + ' auto'\"\n triggers=\"click\"\n container=\"body\"\n autoClose=\"outside\"\n tooltipClass=\"quality-tooltip\">\n @if (loading()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else if (logs()) {\n <he-svg-icon name=\"help-circle\" />\n }\n </span>\n }\n </div>\n }\n @default {\n <ng-container *ngTemplateOutlet=\"quality\" />\n }\n }\n}\n\n<ng-template #quality>\n <span\n [ngStyle]=\"{\n 'background-color': scoreColor()\n }\"\n class=\"tag-score | tag is-primary has-text-white has-text-weight-semibold\">\n <span>{{ scoreLevel() | uppercase }}</span>\n </span>\n</ng-template>\n\n<ng-template #logsTooltip>\n <div>\n <p class=\"mb-2\">\n Up to {{ scoreMax() }} points are awarded for the following criteria, where \"low\" is 0 to\n {{ scoreMax() - 3 }} points, \"medium\" is {{ scoreMax() - 2 }} to {{ scoreMax() - 1 }} points, and \"high\" is\n {{ scoreMax() }} points:\n </p>\n @if (validScores()) {\n <div class=\"table-container\">\n <table class=\"table is-fullwidth has-text-white has-background-secondary\">\n <thead>\n <tr>\n <th class=\"has-text-white\">Condition</th>\n <th class=\"has-text-white\">Met</th>\n @if (isCycle()) {\n <th class=\"has-text-white\">Details</th>\n }\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>No aggregated emissions included in the system boundary are missing</td>\n <td [class.has-text-success]=\"validScores()[0]\" [class.has-text-danger]=\"!validScores()[0]\">\n {{ validScores()[0] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingEmissions()?.length) {\n <span>{{ missingEmissions().length }}</span>\n <span class=\"is-pl-1\">{{ 'emission' | pluralize: missingEmissions().length }} are missing:</span>\n <div class=\"is-mt-2 | missing-emissions\">\n <ul class=\"is-list-style-disc is-pl-4\">\n @for (term of missingEmissions(); track trackByTerm($index, term); let l = $last) {\n <li>\n <he-node-link class=\"is-inline-block is-pl-1\" linkClass=\"is-dark\" [node]=\"term\">\n <span class=\"is-nowrap has-text-ellipsis\">{{ term.name }}</span>\n </he-node-link>\n </li>\n }\n </ul>\n </div>\n } @else if (logs()?.included_emissions) {\n <span>\n All {{ logs().included_emissions }} {{ 'emission' | pluralize: +logs().included_emissions }} for\n this product are included.\n </span>\n }\n </td>\n }\n </tr>\n <tr>\n <td>The aggregation is based on data from over {{ minObservations() }} Cycles</td>\n <td [class.has-text-success]=\"validScores()[1]\" [class.has-text-danger]=\"!validScores()[1]\">\n {{ validScores()[1] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n <span>Based on {{ observations() }} {{ 'Cycle' | pluralize: observations() }}.</span>\n </td>\n }\n </tr>\n @if (isCrop()) {\n <tr>\n <td>\n The difference between yield per hectare here and FAOSTAT is less than \u00B1{{\n logs().yield_delta_min || logs().delta_min | number\n }}%\n </td>\n <td [class.has-text-success]=\"validScores()[2]\" [class.has-text-danger]=\"!validScores()[2]\">\n {{ validScores()[2] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (hasFaostatYield()) {\n <span>FAOSTAT yield =</span>\n <span class=\"is-pl-1\">{{ logs()?.faostat_yield | precision: 3 }}</span>\n <span class=\"is-pl-1\">kg/ha;</span>\n <span class=\"is-pl-1\">Aggregated data yield =</span>\n <span class=\"is-pl-1\">{{ logs()?.product_yield | precision: 3 }}</span>\n <span class=\"is-pl-1\">kg/ha.</span>\n } @else {\n No yield found on FAOSTAT for this product.\n }\n </td>\n }\n </tr>\n }\n <tr>\n <td>\n Data completeness is\n <code class=\"is-p-1\">true</code>\n for all priority areas\n </td>\n <td [class.has-text-success]=\"validScores()[3]\" [class.has-text-danger]=\"!validScores()[3]\">\n {{ validScores()[3] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingCompletenessFields()?.length) {\n <span>{{ missingCompletenessFields().length }}</span>\n <span class=\"is-pl-1\">completeness areas missing data:</span>\n @for (field of missingCompletenessFields(); track field; let l = $last) {\n <a class=\"is-inline-block is-pl-1 is-dark\" [href]=\"completenessUrl(field)\" target=\"_blank\">\n {{ field }}\n </a>\n <span>{{ l ? '.' : ',' }}</span>\n }\n }\n </td>\n }\n </tr>\n @if (isCrop() && isGlobal()) {\n <tr>\n <td>Aggregated countries represent at least 75% of {{ countryName() }} production</td>\n <td [class.has-text-success]=\"validScores()[4]\" [class.has-text-danger]=\"!validScores()[4]\">\n {{ validScores()[4] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (hasProductionQuantity()) {\n <span>{{ countryName() }} production quantity =</span>\n <span class=\"is-pl-1\">{{ regionProductionQuantity() / 1000000 | number: '1.0-0' }}</span>\n <span class=\"is-pl-1\">million tonnes;</span>\n <span class=\"is-pl-1\">Production of countries included in the aggregation =</span>\n <span class=\"is-pl-1\">{{ countriesProductionQuantity() / 1000000 | number: '1.0-0' }}</span>\n <span class=\"is-pl-1\">million tonnes.</span>\n } @else {\n No production quantity found on FAOSTAT for this product.\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block}::ng-deep .quality-tooltip{min-width:500px}.missing-emissions{max-height:250px;overflow-y:auto}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: NodeLinkComponent, selector: "he-node-link", inputs: ["node", "dataState", "showExternalLink", "linkClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NgbTooltipModule }, { kind: "directive", type: i1$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "pipe", type: PluralizePipe, name: "pluralize" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: PrecisionPipe, name: "precision" }, { kind: "pipe", type: UpperCasePipe, name: "uppercase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12610
13137
|
}
|
|
12611
13138
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeAggregatedQualityScoreComponent, decorators: [{
|
|
12612
13139
|
type: Component$1,
|
|
@@ -12620,7 +13147,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
12620
13147
|
NgTemplateOutlet,
|
|
12621
13148
|
NgbTooltipModule,
|
|
12622
13149
|
HESvgIconComponent
|
|
12623
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (score() >= 0) {\n @switch (mode()) {\n @case ('tag') {\n <div class=\"tags has-addons\">\n <a class=\"tag\" [href]=\"schemaUrl()\" target=\"_blank\">Data Quality</a>\n <ng-container *ngTemplateOutlet=\"quality\" />\n @if (showInfo()) {\n <span\n class=\"tag pointer\"\n [ngbTooltip]=\"logsTooltip\"\n [placement]=\"placement() + ' auto'\"\n triggers=\"click\"\n container=\"body\"\n autoClose=\"outside\"\n tooltipClass=\"quality-tooltip\">\n @if (loading()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else if (logs()) {\n <he-svg-icon name=\"help-circle\" />\n }\n </span>\n }\n </div>\n }\n @default {\n <ng-container *ngTemplateOutlet=\"quality\" />\n }\n }\n}\n\n<ng-template #quality>\n <span\n [ngStyle]=\"{\n 'background-color': scoreColor()\n }\"\n class=\"tag-score | tag is-primary has-text-white has-text-weight-semibold\">\n <span>{{ scoreLevel() | uppercase }}</span>\n </span>\n</ng-template>\n\n<ng-template #logsTooltip>\n <div>\n <p class=\"mb-2\">\n Up to {{ scoreMax() }} points are awarded for the following criteria, where \"low\" is 0 to\n {{ scoreMax() - 3 }} points, \"medium\" is {{ scoreMax() - 2 }} to {{ scoreMax() - 1 }} points, and \"high\" is\n {{ scoreMax() }} points:\n </p>\n @if (validScores()) {\n <div class=\"table-container\">\n <table class=\"table is-fullwidth has-text-white has-background-secondary\">\n <thead>\n <tr>\n <th class=\"has-text-white\">Condition</th>\n <th class=\"has-text-white\">Met</th>\n @if (isCycle()) {\n <th class=\"has-text-white\">Details</th>\n }\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>No aggregated emissions included in the system boundary are missing</td>\n <td [class.has-text-success]=\"validScores()[0]\" [class.has-text-danger]=\"!validScores()[0]\">\n {{ validScores()[0] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingEmissions()?.length) {\n <span>{{ missingEmissions().length }}</span>\n <span class=\"is-pl-1\">{{ 'emission' | pluralize: missingEmissions().length }} are missing:</span>\n <div class=\"is-mt-2 | missing-emissions\">\n <ul class=\"is-list-style-disc is-pl-4\">\n @for (term of missingEmissions(); track trackByTerm($index, term); let l = $last) {\n <li>\n <he-node-link class=\"is-inline-block is-pl-1\" linkClass=\"is-dark\" [node]=\"term\">\n <span class=\"is-nowrap has-text-ellipsis\">{{ term.name }}</span>\n </he-node-link>\n </li>\n }\n </ul>\n </div>\n } @else if (logs()?.included_emissions) {\n <span>\n All {{ logs().included_emissions }} {{ 'emission' | pluralize: +logs().included_emissions }} for\n this product are included.\n </span>\n }\n </td>\n }\n </tr>\n <tr>\n <td>The aggregation is based on data from over {{ minObservations() }} Cycles</td>\n <td [class.has-text-success]=\"validScores()[1]\" [class.has-text-danger]=\"!validScores()[1]\">\n {{ validScores()[1] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n <span>Based on {{ observations() }} {{ 'Cycle' | pluralize: observations() }}.</span>\n </td>\n }\n </tr>\n @if (isCrop()) {\n <tr>\n <td>\n The difference between yield per hectare here and FAOSTAT is less than \u00B1{{\n logs().yield_delta_min || logs().delta_min | number\n }}%\n </td>\n <td [class.has-text-success]=\"validScores()[2]\" [class.has-text-danger]=\"!validScores()[2]\">\n {{ validScores()[2] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (
|
|
13150
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (score() >= 0) {\n @switch (mode()) {\n @case ('tag') {\n <div class=\"tags has-addons\">\n <a class=\"tag\" [href]=\"schemaUrl()\" target=\"_blank\">Data Quality</a>\n <ng-container *ngTemplateOutlet=\"quality\" />\n @if (showInfo()) {\n <span\n class=\"tag pointer\"\n [ngbTooltip]=\"logsTooltip\"\n [placement]=\"placement() + ' auto'\"\n triggers=\"click\"\n container=\"body\"\n autoClose=\"outside\"\n tooltipClass=\"quality-tooltip\">\n @if (loading()) {\n <he-svg-icon name=\"loading\" animation=\"spin\" />\n } @else if (logs()) {\n <he-svg-icon name=\"help-circle\" />\n }\n </span>\n }\n </div>\n }\n @default {\n <ng-container *ngTemplateOutlet=\"quality\" />\n }\n }\n}\n\n<ng-template #quality>\n <span\n [ngStyle]=\"{\n 'background-color': scoreColor()\n }\"\n class=\"tag-score | tag is-primary has-text-white has-text-weight-semibold\">\n <span>{{ scoreLevel() | uppercase }}</span>\n </span>\n</ng-template>\n\n<ng-template #logsTooltip>\n <div>\n <p class=\"mb-2\">\n Up to {{ scoreMax() }} points are awarded for the following criteria, where \"low\" is 0 to\n {{ scoreMax() - 3 }} points, \"medium\" is {{ scoreMax() - 2 }} to {{ scoreMax() - 1 }} points, and \"high\" is\n {{ scoreMax() }} points:\n </p>\n @if (validScores()) {\n <div class=\"table-container\">\n <table class=\"table is-fullwidth has-text-white has-background-secondary\">\n <thead>\n <tr>\n <th class=\"has-text-white\">Condition</th>\n <th class=\"has-text-white\">Met</th>\n @if (isCycle()) {\n <th class=\"has-text-white\">Details</th>\n }\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>No aggregated emissions included in the system boundary are missing</td>\n <td [class.has-text-success]=\"validScores()[0]\" [class.has-text-danger]=\"!validScores()[0]\">\n {{ validScores()[0] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingEmissions()?.length) {\n <span>{{ missingEmissions().length }}</span>\n <span class=\"is-pl-1\">{{ 'emission' | pluralize: missingEmissions().length }} are missing:</span>\n <div class=\"is-mt-2 | missing-emissions\">\n <ul class=\"is-list-style-disc is-pl-4\">\n @for (term of missingEmissions(); track trackByTerm($index, term); let l = $last) {\n <li>\n <he-node-link class=\"is-inline-block is-pl-1\" linkClass=\"is-dark\" [node]=\"term\">\n <span class=\"is-nowrap has-text-ellipsis\">{{ term.name }}</span>\n </he-node-link>\n </li>\n }\n </ul>\n </div>\n } @else if (logs()?.included_emissions) {\n <span>\n All {{ logs().included_emissions }} {{ 'emission' | pluralize: +logs().included_emissions }} for\n this product are included.\n </span>\n }\n </td>\n }\n </tr>\n <tr>\n <td>The aggregation is based on data from over {{ minObservations() }} Cycles</td>\n <td [class.has-text-success]=\"validScores()[1]\" [class.has-text-danger]=\"!validScores()[1]\">\n {{ validScores()[1] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n <span>Based on {{ observations() }} {{ 'Cycle' | pluralize: observations() }}.</span>\n </td>\n }\n </tr>\n @if (isCrop()) {\n <tr>\n <td>\n The difference between yield per hectare here and FAOSTAT is less than \u00B1{{\n logs().yield_delta_min || logs().delta_min | number\n }}%\n </td>\n <td [class.has-text-success]=\"validScores()[2]\" [class.has-text-danger]=\"!validScores()[2]\">\n {{ validScores()[2] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (hasFaostatYield()) {\n <span>FAOSTAT yield =</span>\n <span class=\"is-pl-1\">{{ logs()?.faostat_yield | precision: 3 }}</span>\n <span class=\"is-pl-1\">kg/ha;</span>\n <span class=\"is-pl-1\">Aggregated data yield =</span>\n <span class=\"is-pl-1\">{{ logs()?.product_yield | precision: 3 }}</span>\n <span class=\"is-pl-1\">kg/ha.</span>\n } @else {\n No yield found on FAOSTAT for this product.\n }\n </td>\n }\n </tr>\n }\n <tr>\n <td>\n Data completeness is\n <code class=\"is-p-1\">true</code>\n for all priority areas\n </td>\n <td [class.has-text-success]=\"validScores()[3]\" [class.has-text-danger]=\"!validScores()[3]\">\n {{ validScores()[3] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (missingCompletenessFields()?.length) {\n <span>{{ missingCompletenessFields().length }}</span>\n <span class=\"is-pl-1\">completeness areas missing data:</span>\n @for (field of missingCompletenessFields(); track field; let l = $last) {\n <a class=\"is-inline-block is-pl-1 is-dark\" [href]=\"completenessUrl(field)\" target=\"_blank\">\n {{ field }}\n </a>\n <span>{{ l ? '.' : ',' }}</span>\n }\n }\n </td>\n }\n </tr>\n @if (isCrop() && isGlobal()) {\n <tr>\n <td>Aggregated countries represent at least 75% of {{ countryName() }} production</td>\n <td [class.has-text-success]=\"validScores()[4]\" [class.has-text-danger]=\"!validScores()[4]\">\n {{ validScores()[4] ? 'Yes' : 'No' }}\n </td>\n @if (isCycle()) {\n <td>\n @if (hasProductionQuantity()) {\n <span>{{ countryName() }} production quantity =</span>\n <span class=\"is-pl-1\">{{ regionProductionQuantity() / 1000000 | number: '1.0-0' }}</span>\n <span class=\"is-pl-1\">million tonnes;</span>\n <span class=\"is-pl-1\">Production of countries included in the aggregation =</span>\n <span class=\"is-pl-1\">{{ countriesProductionQuantity() / 1000000 | number: '1.0-0' }}</span>\n <span class=\"is-pl-1\">million tonnes.</span>\n } @else {\n No production quantity found on FAOSTAT for this product.\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block}::ng-deep .quality-tooltip{min-width:500px}.missing-emissions{max-height:250px;overflow-y:auto}\n"] }]
|
|
12624
13151
|
}], propDecorators: { hidden: [{
|
|
12625
13152
|
type: HostBinding,
|
|
12626
13153
|
args: ['class.is-none']
|
|
@@ -14211,6 +14738,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
14211
14738
|
args: [{ selector: 'he-sites-maps', changeDetection: ChangeDetectionStrategy.OnPush, imports: [GoogleMap, MapMarker, MapPolygon, AsyncPipe], template: "@if (mapLoaded$ | async) {\n <google-map (mapInitialized)=\"mapLoaded()\" height=\"100%\" width=\"100%\" [zoom]=\"zoom()\" [center]=\"mapCenter()\">\n @for (marker of markers(); track trackByMarker($index, marker)) {\n <map-marker [position]=\"marker.position\" [icon]=\"marker.icon\"></map-marker>\n }\n @for (polygon of sitePolygons(); track trackByPolygon($index, polygon)) {\n <map-polygon [paths]=\"polygon.paths\" [options]=\"polygon.options\" />\n }\n @for (polygon of termPolygons(); track trackByPolygon($index, polygon)) {\n <map-polygon [paths]=\"polygon.paths\" [options]=\"polygon.options\" />\n }\n </google-map>\n}\n\n@if (showNotice()) {\n <p class=\"mt-2 is-italic is-size-7\">The information provided might not be complete</p>\n}\n\n@if (showNoLocation()) {\n <div class=\"no-location has-text-center has-text-light\">\n <span>No precise location data</span>\n </div>\n}\n", styles: [":host{display:block;height:100%;position:relative;width:100%}.no-location{background-color:#0000004d;left:0;height:100%;position:absolute;top:0;width:100%;z-index:9}.no-location>span{display:inline-block;margin-top:12%}\n"] }]
|
|
14212
14739
|
}], ctorParameters: () => [], propDecorators: { map: [{ type: i0.ViewChild, args: [i0.forwardRef(() => GoogleMap), { isSignal: true }] }], loadPolygons: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadPolygons", required: false }] }], sites: [{ type: i0.Input, args: [{ isSignal: true, alias: "sites", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], showNotice: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNotice", required: false }] }] } });
|
|
14213
14740
|
|
|
14741
|
+
/**
|
|
14742
|
+
* The distribution behind an `is outside confidence interval` warning, shown on demand.
|
|
14743
|
+
*
|
|
14744
|
+
* The chart cannot be part of the error message itself: the catalog is framework-agnostic and its
|
|
14745
|
+
* output is injected with `[innerHTML]`, which Angular sanitizes — canvas and inline SVG are
|
|
14746
|
+
* stripped. So the message stays text and this sits beside it.
|
|
14747
|
+
*/
|
|
14748
|
+
class FilesErrorDistributionComponent {
|
|
14749
|
+
constructor() {
|
|
14750
|
+
this.error = input(...(ngDevMode ? [undefined, { debugName: "error" }] : []));
|
|
14751
|
+
this.params = computed(() => this.error()?.params, ...(ngDevMode ? [{ debugName: "params" }] : []));
|
|
14752
|
+
/**
|
|
14753
|
+
* `mu`/`sd` are only sent by the validation service from `@hestia-earth/data-validation` 0.41.1
|
|
14754
|
+
* on. Older warnings carry `min`/`max` alone, which cannot reconstruct the curve — `min` is
|
|
14755
|
+
* clamped at 0 — so the button is hidden rather than opening onto a wrong distribution.
|
|
14756
|
+
*/
|
|
14757
|
+
this.available = computed(() => Number.isFinite(this.params()?.mu) && Number.isFinite(this.params()?.sd) && this.params()?.sd > 0, ...(ngDevMode ? [{ debugName: "available" }] : []));
|
|
14758
|
+
/** What was checked: the grouped input key where there is one, else the term itself. */
|
|
14759
|
+
this.label = computed(() => this.params()?.group || this.params()?.term?.name, ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
14760
|
+
this.country = computed(() => this.params()?.country?.name, ...(ngDevMode ? [{ debugName: "country" }] : []));
|
|
14761
|
+
/**
|
|
14762
|
+
* The reported value to mark. `outliers` holds every value that fell outside for this field —
|
|
14763
|
+
* in practice one, since each warning is raised per value.
|
|
14764
|
+
*/
|
|
14765
|
+
this.value = computed(() => this.params()?.outliers?.[0], ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
14766
|
+
/** `threshold` is the share of the data the shaded interval covers, e.g. `0.95` → `95%`. */
|
|
14767
|
+
this.thresholdPercent = computed(() => Number.isFinite(this.params()?.threshold) ? this.params().threshold * 100 : null, ...(ngDevMode ? [{ debugName: "thresholdPercent" }] : []));
|
|
14768
|
+
this.isPrior = computed(() => this.params()?.source === 'prior', ...(ngDevMode ? [{ debugName: "isPrior" }] : []));
|
|
14769
|
+
/**
|
|
14770
|
+
* The warning is always raised on an Input or Product `value` — a physical amount, which cannot
|
|
14771
|
+
* be negative however far the fitted normal's left tail reaches. The validation service clamps
|
|
14772
|
+
* `min` at 0 for the same reason.
|
|
14773
|
+
*/
|
|
14774
|
+
this.minX = 0;
|
|
14775
|
+
/**
|
|
14776
|
+
* The popover body is the platform's dark blue (`$blue`), so the axis has to be drawn light on
|
|
14777
|
+
* it. The chart's own colours are background-agnostic; only the axis needs saying.
|
|
14778
|
+
*/
|
|
14779
|
+
this.chartConfig = {
|
|
14780
|
+
options: {
|
|
14781
|
+
scales: {
|
|
14782
|
+
x: {
|
|
14783
|
+
ticks: { color: '#fff' },
|
|
14784
|
+
title: { color: '#fff' },
|
|
14785
|
+
grid: { color: 'rgba(255, 255, 255, 0.15)' },
|
|
14786
|
+
border: { color: 'rgba(255, 255, 255, 0.3)' }
|
|
14787
|
+
}
|
|
14788
|
+
}
|
|
14789
|
+
}
|
|
14790
|
+
};
|
|
14791
|
+
}
|
|
14792
|
+
get hidden() {
|
|
14793
|
+
return !this.available();
|
|
14794
|
+
}
|
|
14795
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesErrorDistributionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14796
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FilesErrorDistributionComponent, isStandalone: true, selector: "he-files-error-distribution", inputs: { error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-none": "this.hidden" } }, ngImport: i0, template: "@if (available()) {\n <a\n class=\"is-nowrap\"\n [ngbPopover]=\"distributionPopover\"\n [popoverTitle]=\"'Distribution for ' + label()\"\n triggers=\"click\"\n autoClose=\"outside\"\n placement=\"bottom auto\"\n popoverClass=\"he-distribution-popover\"\n container=\"body\">\n <he-svg-icon name=\"chart\" size=\"24\" />\n <span class=\"is-pl-2\">Show distribution</span>\n </a>\n}\n\n<ng-template #distributionPopover>\n <div>\n <he-distribution-chart\n [mu]=\"params().mu\"\n [sd]=\"params().sd\"\n [intervalMin]=\"params().min\"\n [intervalMax]=\"params().max\"\n [value]=\"value()\"\n [label]=\"label()\"\n [minX]=\"minX\"\n [config]=\"chartConfig\" />\n\n <p class=\"is-size-7\">\n How common each value of\n <b>{{ label() }}</b>\n is\n @if (country()) {\n in\n <b>{{ country() }}</b>\n }\n on the HESTIA platform: the taller the curve, the more common the value. It peaks at the average,\n <b>{{ params().mu | precision }}</b>\n <span>.</span>\n </p>\n\n <p class=\"is-size-7 is-mt-2\">\n The shaded band is the\n @if (thresholdPercent()) {\n {{ thresholdPercent() }}%\n }\n confidence interval, from\n <b>{{ params().min | precision }}</b>\n to\n <b>{{ params().max | precision }}</b>\n <span>. The orange line marks your value.</span>\n </p>\n\n @if (isPrior()) {\n <p class=\"is-size-7 is-mt-2\">\n This is the FAOSTAT prior (national average), not HESTIA Cycle data for this product, so it is weak evidence.\n </p>\n }\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-grow:0}::ng-deep .he-distribution-popover .popover-body{width:320px;max-width:100%}::ng-deep .he-distribution-popover he-distribution-chart{display:block;height:200px}\n"], dependencies: [{ kind: "ngmodule", type: NgbPopoverModule }, { kind: "directive", type: i1$1.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: DistributionChartComponent, selector: "he-distribution-chart", inputs: ["distribution", "value", "label", "nbBins", "maxPercentile", "config", "mu", "sd", "intervalMin", "intervalMax", "minX"], exportAs: ["distributionChart"] }, { kind: "pipe", type: PrecisionPipe, name: "precision" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14797
|
+
}
|
|
14798
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesErrorDistributionComponent, decorators: [{
|
|
14799
|
+
type: Component$1,
|
|
14800
|
+
args: [{ selector: 'he-files-error-distribution', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgbPopoverModule, HESvgIconComponent, DistributionChartComponent, PrecisionPipe], template: "@if (available()) {\n <a\n class=\"is-nowrap\"\n [ngbPopover]=\"distributionPopover\"\n [popoverTitle]=\"'Distribution for ' + label()\"\n triggers=\"click\"\n autoClose=\"outside\"\n placement=\"bottom auto\"\n popoverClass=\"he-distribution-popover\"\n container=\"body\">\n <he-svg-icon name=\"chart\" size=\"24\" />\n <span class=\"is-pl-2\">Show distribution</span>\n </a>\n}\n\n<ng-template #distributionPopover>\n <div>\n <he-distribution-chart\n [mu]=\"params().mu\"\n [sd]=\"params().sd\"\n [intervalMin]=\"params().min\"\n [intervalMax]=\"params().max\"\n [value]=\"value()\"\n [label]=\"label()\"\n [minX]=\"minX\"\n [config]=\"chartConfig\" />\n\n <p class=\"is-size-7\">\n How common each value of\n <b>{{ label() }}</b>\n is\n @if (country()) {\n in\n <b>{{ country() }}</b>\n }\n on the HESTIA platform: the taller the curve, the more common the value. It peaks at the average,\n <b>{{ params().mu | precision }}</b>\n <span>.</span>\n </p>\n\n <p class=\"is-size-7 is-mt-2\">\n The shaded band is the\n @if (thresholdPercent()) {\n {{ thresholdPercent() }}%\n }\n confidence interval, from\n <b>{{ params().min | precision }}</b>\n to\n <b>{{ params().max | precision }}</b>\n <span>. The orange line marks your value.</span>\n </p>\n\n @if (isPrior()) {\n <p class=\"is-size-7 is-mt-2\">\n This is the FAOSTAT prior (national average), not HESTIA Cycle data for this product, so it is weak evidence.\n </p>\n }\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-grow:0}::ng-deep .he-distribution-popover .popover-body{width:320px;max-width:100%}::ng-deep .he-distribution-popover he-distribution-chart{display:block;height:200px}\n"] }]
|
|
14801
|
+
}], propDecorators: { error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], hidden: [{
|
|
14802
|
+
type: HostBinding,
|
|
14803
|
+
args: ['class.is-none']
|
|
14804
|
+
}] } });
|
|
14805
|
+
|
|
14214
14806
|
const stringify = (value) => JSON.stringify(value);
|
|
14215
14807
|
const focusFirstGroupError = (element) => {
|
|
14216
14808
|
const groupError = (element.querySelectorAll('.is-group-error-danger')?.[0] ||
|
|
@@ -14331,7 +14923,7 @@ class FilesFormComponent {
|
|
|
14331
14923
|
return focusFirstError(this.ref.nativeElement);
|
|
14332
14924
|
}
|
|
14333
14925
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14334
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FilesFormComponent, isStandalone: true, selector: "he-files-form", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, showNodeLink: { classPropertyName: "showNodeLink", publicName: "showNodeLink", isSignal: true, isRequired: false, transformFunction: null }, errorGuidePrefix: { classPropertyName: "errorGuidePrefix", publicName: "errorGuidePrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", nodeErorrResolved: "nodeErorrResolved" }, exportAs: ["filesForm"], ngImport: i0, template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#2b8434}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: NodeIconComponent, selector: "he-node-icon", inputs: ["type", "size"] }, { kind: "component", type: SitesMapsComponent, selector: "he-sites-maps", inputs: ["loadPolygons", "sites", "zoom", "showNotice"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: ClipboardComponent, selector: "he-clipboard", inputs: ["icon", "value", "disabled", "hideText", "hideIcon", "size", "clipboardClass", "tooltipPlacement"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14926
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FilesFormComponent, isStandalone: true, selector: "he-files-form", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, showNodeLink: { classPropertyName: "showNodeLink", publicName: "showNodeLink", isSignal: true, isRequired: false, transformFunction: null }, errorGuidePrefix: { classPropertyName: "errorGuidePrefix", publicName: "errorGuidePrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", nodeErorrResolved: "nodeErorrResolved" }, exportAs: ["filesForm"], ngImport: i0, template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-direction-column is-align-items-start is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n <he-files-error-distribution [error]=\"property.error\" />\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#2b8434}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "directive", type: NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: NodeIconComponent, selector: "he-node-icon", inputs: ["type", "size"] }, { kind: "component", type: SitesMapsComponent, selector: "he-sites-maps", inputs: ["loadPolygons", "sites", "zoom", "showNotice"] }, { kind: "component", type: HESvgIconComponent, selector: "he-svg-icon", inputs: ["name", "size", "animation"] }, { kind: "component", type: ClipboardComponent, selector: "he-clipboard", inputs: ["icon", "value", "disabled", "hideText", "hideIcon", "size", "clipboardClass", "tooltipPlacement"] }, { kind: "component", type: GuideOverlayComponent, selector: "he-guide-overlay", inputs: ["pageId", "width", "height", "positions"], outputs: ["widthChange", "heightChange"] }, { kind: "component", type: FilesErrorDistributionComponent, selector: "he-files-error-distribution", inputs: ["error"] }, { kind: "pipe", type: EllipsisPipe, name: "ellipsis" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
14335
14927
|
}
|
|
14336
14928
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FilesFormComponent, decorators: [{
|
|
14337
14929
|
type: Component$1,
|
|
@@ -14346,8 +14938,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
14346
14938
|
HESvgIconComponent,
|
|
14347
14939
|
ClipboardComponent,
|
|
14348
14940
|
GuideOverlayComponent,
|
|
14941
|
+
FilesErrorDistributionComponent,
|
|
14349
14942
|
EllipsisPipe
|
|
14350
|
-
], template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#2b8434}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"] }]
|
|
14943
|
+
], template: "<div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch | files-form-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center is-align-self-stretch is-gap-16 px-4 py-2 has-text-secondary | files-form-header\"\n (click)=\"isOpen.set(!isOpen())\"\n pointer>\n <div class=\"is-flex is-gap-8 is-align-items-center\">\n @if (nodeProperty()) {\n <he-node-icon class=\"is-flex\" [type]=\"schemaType()\" [size]=\"24\" />\n <span class=\"has-text-weight-bold has-text-secondary is-size-5\">{{ schemaType() }}</span>\n @if (nodeProperty().hasError || hasError()) {\n <he-svg-icon name=\"xmark-circle\" class=\"has-text-danger is-flex is-align-items-center\" />\n <span class=\"has-text-danger has-text-weight-bold is-italic\">Error</span>\n } @else if (nodeProperty().hasWarning || hasWarning()) {\n <he-svg-icon name=\"exclamation-triangle\" class=\"has-text-warning is-flex is-align-items-center\" />\n <span class=\"has-text-warning has-text-weight-bold is-italic\">Warning</span>\n }\n }\n </div>\n @if ((showNodeLink() && nodeUrl()) || canOpen()) {\n <div class=\"is-flex is-flex-direction-row is-align-items-center is-gap-16\">\n @if (showNodeLink() && nodeUrl()) {\n <ng-container *ngTemplateOutlet=\"nodeLink; context: { url: nodeUrl(), nodeType: schemaType() }\" />\n }\n @if (canOpen()) {\n <he-svg-icon [name]=\"isOpen() ? 'minus' : 'plus'\" />\n }\n </div>\n }\n </div>\n\n <div class=\"is-flex is-flex-direction-column is-align-items-flex-start is-align-self-stretch\">\n @if (isOpen()) {\n @if (nodeProperty()?.error) {\n <ng-container\n *ngTemplateOutlet=\"\n propertyError;\n context: { property: nodeProperty(), classes: 'is-my-1 is-py-1 is-px-3' }\n \" />\n }\n }\n\n @if (unmatchedErrors().length) {\n @for (property of unmatchedErrors(); track property.id) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-py-1 is-px-3' }\" />\n }\n }\n\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (property of properties(); track trackByProperty($index, property)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: property }\" />\n }\n </div>\n\n @if (isOpen()) {\n <ng-container *ngTemplateOutlet=\"propertyMap; context: { $implicit: nodeProperty() }\" />\n }\n </div>\n\n <ng-content />\n</div>\n\n<ng-template #propertyKeyTooltip let-property=\"property\">\n <markdown [data]=\"property.schema.description\" />\n</ng-template>\n\n<ng-template #propertyKey let-property=\"property\">\n @if (property.schema?.description) {\n <span\n class=\"trigger-popover | property-key\"\n [ngbTooltip]=\"propertyKeyTooltip\"\n [tooltipContext]=\"{ property }\"\n triggers=\"click\"\n autoClose=\"outside\"\n tooltipClass=\"property-tooltip\"\n placement=\"bottom-left auto\"\n container=\"body\"\n (click)=\"$event.stopPropagation()\">\n <span>{{ property.key }}</span>\n </span>\n } @else {\n <span>{{ property.key }}</span>\n }\n</ng-template>\n\n<ng-template #propertyContent let-property=\"property\">\n <div class=\"is-flex is-align-items-center is-flex-wrap-wrap is-gap-4\">\n <div class=\"is-flex has-text-secondary\">\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n <span>:</span>\n </div>\n\n @if (property.isCollapsible && property.showMaxLength) {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value | ellipsis: property.showMaxLength }}\n </span>\n\n <a class=\"is-flex is-size-7\" (click)=\"property.showMaxLength = 0\">Show more</a>\n } @else {\n <span class=\"is-flex is-size-7 | property-value\">\n {{ property.value }}\n </span>\n }\n\n @if (property.schema?.internal && property.key !== 'originalId') {\n <div class=\"property-internal\" ngbTooltip=\"This value is auto-generated.\">\n <he-svg-icon name=\"autogenerate-circle\" />\n </div>\n }\n\n <div class=\"copy-button\">\n <he-clipboard [value]=\"property.value\" [hideText]=\"true\" />\n </div>\n </div>\n\n <div class=\"is-flex is-gap-8\">\n @if (property.externalUrl?.url) {\n <a\n [href]=\"property.externalUrl.url + (property.externalUrl.urlParamValue ? property.value : '')\"\n target=\"_blank\"\n [title]=\"property.externalUrl.title\"\n class=\"ml-2\"\n [ngClass]=\"{ 'is-info': property.key === 'type' }\"\n [attr.disabled]=\"property.externalUrl.urlParamValue && !property.value ? true : null\">\n <he-svg-icon [name]=\"property.externalUrl.icon || 'external-link'\" />\n </a>\n }\n </div>\n</ng-template>\n\n<ng-template #showProperty let-property>\n @if ((isOpen() || property.closedVisible) && !property.isHidden) {\n @if (property.properties.length) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 has-text-secondary w-100 | properties-container--title\"\n (click)=\"property.isOpen = !property.isOpen\"\n pointer\n [class.is-open]=\"property.isOpen\"\n [class.is-group-error-danger]=\"property.hasError\"\n [class.is-group-error-warning]=\"!property.hasError && property.hasWarning\">\n <div class=\"is-flex is-gap-8 has-text-weight-bold\">\n <!-- @if (property.schemaType === SchemaType.Term) {\n <he-node-icon [type]=\"property.schemaType\" />\n } -->\n <ng-container *ngTemplateOutlet=\"propertyKey; context: { property }\" />\n </div>\n <he-svg-icon [name]=\"property.isOpen ? 'minus' : 'plus'\" />\n </div>\n @if (property.isOpen) {\n @if (property.error) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property, classes: 'is-my-1 is-px-3' }\" />\n }\n @if (property.isArray) {\n <div class=\"py-2 px-3 w-100\">\n @if (property.hasError) {\n <div class=\"is-flex is-align-items-center is-size-7 is-italic is-mb-2 has-text-warning\">\n <he-svg-icon name=\"exclamation-triangle\" />\n @if (showAllErrors()) {\n <a class=\"is-pl-2\" (click)=\"showAllErrors.set(false)\">Only show items in error.</a>\n } @else {\n <span class=\"is-pl-2\">Only showing items in error.</span>\n <a class=\"is-pl-1\" (click)=\"showAllErrors.set(true)\">Show all items</a>\n }\n </div>\n }\n\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n @if (prop2.key && (showAllErrors() || !property.hasError || prop2.hasError)) {\n <div class=\"pt-2 my-4 | property-array-container\" [id]=\"prop2.fullKey + '_' + prop2.id\">\n <div class=\"ml-2 is-mb-2 | property-array-number\">\n <span class=\"has-text-info is-px-1 | number-tag\">{{ prop2.key }}</span>\n </div>\n @if (prop2.error) {\n <ng-container\n *ngTemplateOutlet=\"propertyError; context: { property: prop2, classes: 'is-py-1 is-px-3' }\" />\n }\n <div class=\"p-3\">\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop3 of prop2.properties; track trackByProperty($index, prop3)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop3 }\" />\n }\n </div>\n </div>\n </div>\n }\n }\n </div>\n } @else {\n <div class=\"is-flex is-flex-direction-row is-flex-wrap-wrap is-align-self-stretch\">\n @for (prop2 of property.properties; track trackByProperty($index, prop2)) {\n <ng-container *ngTemplateOutlet=\"showProperty; context: { $implicit: prop2 }\" />\n }\n </div>\n }\n }\n </div>\n } @else {\n <div\n class=\"is-flex is-flex-direction-column is-gap-4 | property-container\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n <div\n class=\"is-flex is-flex-direction-row is-align-items-center is-justify-content-space-between is-gap-4 | field-container\">\n @if (property.key) {\n <ng-container *ngTemplateOutlet=\"propertyContent; context: { property }\" />\n }\n </div>\n @if (property.hasError || property.hasWarning) {\n <ng-container *ngTemplateOutlet=\"propertyError; context: { property }\" />\n }\n </div>\n }\n }\n</ng-template>\n\n<ng-template #propertyError let-property=\"property\" let-classes=\"classes\">\n @if (property.error?.message) {\n <div\n class=\"is-flex is-flex-direction-row is-gap-8 is-size-6 is-m-0 w-100 has-text-grey {{ classes }} | property-error\"\n [class.is-error-danger]=\"property.hasError\"\n [class.is-error-warning]=\"!property.hasError && property.hasWarning\">\n @if (property.hasError) {\n <he-svg-icon name=\"xmark-circle\" size=\"24\" class=\"has-text-danger is-flex-grow-0\" />\n } @else {\n <he-svg-icon name=\"exclamation-triangle\" size=\"24\" class=\"has-text-warning is-flex-grow-0\" />\n }\n\n <div class=\"is-flex is-flex-direction-column is-align-items-start is-flex-grow-1\">\n <span [innerHTML]=\"property.error.message\"></span>\n <he-files-error-distribution [error]=\"property.error\" />\n </div>\n\n @if (errorGuidePrefix() && property.errorGuidePageId) {\n <he-guide-overlay class=\"is-flex-grow-0\" [pageId]=\"errorGuidePrefix() + property.errorGuidePageId\" />\n }\n\n @if (property.error.index >= 0) {\n @if (property.hasWarning) {\n <a (click)=\"resolveError(property)\">\n <he-svg-icon name=\"checkmark\" />\n <span class=\"is-pl-2\">Resolved</span>\n </a>\n }\n }\n </div>\n }\n</ng-template>\n\n<ng-template #propertyMap let-property>\n @if (showMap()) {\n <div class=\"is-flex is-flex-direction-column is-flex-wrap-wrap w-100 | properties-container\">\n <div\n class=\"is-flex is-flex-direction-row is-justify-content-space-between is-gap-4 w-100 | properties-container--title\"\n (click)=\"mapVisible.set(!mapVisible())\"\n pointer\n [class.is-open]=\"mapVisible()\">\n <span class=\"is-size-6\">View on Map</span>\n <he-svg-icon [name]=\"mapVisible() ? 'minus' : 'plus'\" />\n </div>\n @if (mapVisible()) {\n <he-sites-maps [sites]=\"[node()]\" [showNotice]=\"false\" />\n }\n </div>\n }\n</ng-template>\n\n<ng-template #nodeLink let-url=\"url\" let-nodeType=\"nodeType\">\n <a class=\"external-link\" [href]=\"url\" target=\"_blank\" (click)=\"$event.stopPropagation()\">\n <span class=\"is-hidden-mobile\">View</span>\n <span class=\"is-hidden-mobile is-pl-1\">{{ nodeType }}</span>\n <he-svg-icon name=\"external-link\" class=\"ml-2\" />\n </a>\n</ng-template>\n", styles: [".notification{color:#0a0a0a!important}.notification.is-success{background-color:#d5f3d8}.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-success>fa-icon,.notification.is-success *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-success>he-svg-icon{color:#2b8434}.notification.is-info{background-color:#d3ebed}.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-info>fa-icon,.notification.is-info *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-info>he-svg-icon{color:#249da5}.notification.is-warning{background-color:#ffdec0}.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-warning>fa-icon,.notification.is-warning *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-warning>he-svg-icon{color:#ff881b}.notification.is-danger{background-color:#ffcdd0}.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>fa-icon,.notification.is-danger>fa-icon,.notification.is-danger *:not(.button):not(.icon):not(.dropdown-item)>he-svg-icon,.notification.is-danger>he-svg-icon{color:#ff3844}he-sites-maps{height:200px}.external-link{color:#4c7194}.files-form-container{box-shadow:2px 2px 4px #00000029;background-color:#fff}.files-form-header{padding:10px 12px;background-color:#dbe3ea;border-top-left-radius:3px;border-top-right-radius:3px}.properties-container--title,.property-container{padding:6px 12px}.property-container{flex:none;flex-grow:1;min-width:50%;max-width:100%;border:1px solid #f5f5f5}.property-container.is-error-danger{border-color:#ff3844}.property-container.is-error-warning{border-color:#ff881b}.properties-container--title{border-top:1px solid #dbe3ea;border-bottom:1px solid #dbe3ea;background:#f5f7f9}.properties-container .properties-container{border-radius:6px;border:1px solid #dbe3ea;margin:4px 0}.properties-container .properties-container--title{border-top:none}.property-internal{color:#249da5}.property-key,.property-value{word-break:break-word}.property-array-container{border-radius:6px;border:1px solid #dbdbdb}.number-tag{border:1px solid #249da5;border-radius:50%}.copy-button{visibility:hidden}.field-container:hover .copy-button{visibility:visible}.is-group-error-danger{background-color:#ffcdd0}.is-group-error-warning{background-color:#ffdec0}.property-error.is-error-danger{background-color:#ffeced}.field-container+.property-error.is-error-danger{background-color:transparent;color:#ff3844!important}.property-error.is-error-warning{background-color:#fff5ec}.field-container+.property-error.is-error-warning{background-color:transparent;color:#ff881b!important}::ng-deep .property-tooltip{background-color:#fff;color:#0a0a0a;border:1px solid #dbdbdb;z-index:11;max-width:50vw;max-height:50vh;overflow:auto}::ng-deep .property-tooltip pre{white-space:pre-wrap}\n"] }]
|
|
14351
14944
|
}], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }, { type: i0.Output, args: ["isOpenChange"] }], node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], showNodeLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNodeLink", required: false }] }], errorGuidePrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorGuidePrefix", required: false }] }], nodeErorrResolved: [{ type: i0.Output, args: ["nodeErorrResolved"] }] } });
|
|
14352
14945
|
|
|
14353
14946
|
class SchemaInfoComponent {
|
|
@@ -17226,5 +17819,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
17226
17819
|
* Generated bundle index. Do not edit.
|
|
17227
17820
|
*/
|
|
17228
17821
|
|
|
17229
|
-
export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FileUploadErrorKeys, FilesDragDropDirective, FilesDropZoneComponent, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, FormulaBlockComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalBarChartComponent, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedFormulasComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeAggregationLogsComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJLogModelsComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorText, evaluateSuccess, exportAsSVG, exportFormats, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupBlankNodesByTermIdentity, groupChanged, groupDataByCategory, groupJLogByField, groupJLogByTerm, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, jLogModelCount, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, locationQuery, logToCsv$2 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeDataVersion, nodeId, nodeIdWithoutDataVersion, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeRequestId, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodeVersionKey, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, sumValues, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toTextParts, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
|
|
17822
|
+
export { ARRAY_DELIMITER, ApplyPurePipe, BarChartComponent, BibliographiesSearchConfirmComponent, BlankNodeStateComponent, BlankNodeStateNoticeComponent, BlankNodeValueDeltaComponent, CapitalizePipe, ChartComponent, ChartConfigurationDirective, ChartExportButtonComponent, ChartTooltipComponent, ClickOutsideDirective, ClipboardComponent, CollapsibleBlockComponent, CollapsibleBoxComponent, CollapsibleBoxStyle, ColorPalette, CompoundDirective, CompoundPipe, ContributionChartComponent, ControlValueAccessor, CycleNodesKeyGroup, CyclesCompletenessComponent, CyclesEmissionsCategoryService, CyclesEmissionsChartComponent, CyclesFunctionalUnitMeasureComponent, CyclesMetadataComponent, CyclesNodesComponent, CyclesNodesTimelineComponent, CyclesResultComponent, DataTableComponent, DefaultPipe, DeltaColour, DistributionChartComponent, DrawerContainerComponent, DurationPipe, EllipsisPipe, EngineModelsLinkComponent, EngineModelsLookupInfoComponent, EngineModelsStageComponent, EngineModelsStageDeepComponent, EngineModelsStageDeepService, EngineModelsVersionInfoComponent, EngineModelsVersionLinkComponent, EngineOrchestratorEditComponent, EngineRequirementsFormComponent, FileSizePipe, FileUploadErrorKeys, FilesDragDropDirective, FilesDropZoneComponent, FilesErrorSummaryComponent, FilesFormComponent, FilesFormEditableComponent, FilesUploadErrorsComponent, FilterAccordionComponent, FormulaBlockComponent, GUIDE_ENABLED, GetPipe, GlossaryMigrationFormat, GuideOverlayComponent, HE_API_BASE_URL, HE_CALCULATIONS_BASE_URL, HE_MAP_LOADED, HeAuthService, HeCommonService, HeEngineService, HeGlossaryService, HeMendeleyService, HeNodeCsvService, HeNodeService, HeNodeStoreService, HeSchemaService, HeSearchService, HeToastService, HorizontalBarChartComponent, HorizontalButtonsGroupComponent, ImpactAssessmentsGraphComponent, ImpactAssessmentsIndicatorBreakdownChartComponent, ImpactAssessmentsIndicatorsChartComponent, ImpactAssessmentsProductsComponent, IsArrayPipe, IsObjectPipe, IssueConfirmComponent, KeyToLabelPipe, Level, LineChartComponent, LinkKeyValueComponent, LogStatus, LongPressDirective, MAX_RESULTS, MapsDrawingComponent, MapsDrawingConfirmComponent, MaxPipe, MeanPipe, MedianPipe, MendeleySearchResult, MinPipe, MobileShellComponent, NavigationMenuComponent, NoExtPipe, NodeAggregatedComponent, NodeAggregatedFormulasComponent, NodeAggregatedInfoComponent, NodeAggregatedQualityScoreComponent, NodeAggregationLogsComponent, NodeCsvExportConfirmComponent, NodeCsvPreviewComponent, NodeCsvSelectHeadersComponent, NodeIconComponent, NodeJLogModelsComponent, NodeJsonldComponent, NodeJsonldSchemaComponent, NodeKeyState, NodeLinkComponent, NodeLogsFileComponent, NodeLogsModelsComponent, NodeLogsTimeComponent, NodeMissingLookupFactorsComponent, NodeQualityScore, NodeRecommendationsComponent, NodeSelectComponent, NodeValueDetailsComponent, PipelineStagesProgressComponent, PluralizePipe, PopoverComponent, PopoverConfirmComponent, PrecisionPipe, RelatedNodeResult, RemoveMarkdownPipe, RepeatPipe, Repository, ResizedDirective, ResizedEvent, ResponsiveService, SchemaInfoComponent, SchemaVersionLinkComponent, SearchExtendComponent, ShelfDialogComponent, ShellComponent, SiteNodesKeyGroup, SitesManagementChartComponent, SitesMapsComponent, SitesNodesComponent, SkeletonTextComponent, SocialTagsComponent, SortByPipe, SortSelectComponent, SumPipe, TagsInputDirective, Template, TermsPropertyContentComponent, TermsSubClassOfContentComponent, TermsUnitsDescriptionComponent, ThousandSuffixesPipe, ThousandsPipe, TimesPipe, ToastComponent, UncapitalizePipe, addPolygonToFeature, afterBarDrawPlugin, allCountriesQuery, allGroups, allOptions, availableProperties, axisHoverPlugin, backgroundHoverPlugin, baseApiUrl, baseUrl, bottom, buildSummary, bytesSize, calculateCycleDuration, calculateCycleDurationEnabled, calculateCycleStartDate, calculateCycleStartDateEnabled, capitalize, changelogUrl, clustererImage, code, colorToRgba, compoundToHtml, computeKeys, computeTerms, contactUsEmail, contactUsLink, convertToSvg, coordinatesToPoint, copyObject, countGroupVisibleNodes, countriesQuery, createMarker, cropsQuery, d3ellipse, d3wrap, dataPathLabel, dataPathToKey, dataVersionHeader, dataVersionHeaderKey, defaultFeature, defaultLabel, defaultSuggestionType, defaultTicksFont, definitionToSchemaType, distinctUntilChangedDeep, downloadFile, downloadPng, downloadSvg, ellipsis, engineGitBaseUrl, engineGitUrl, errorText, evaluateSuccess, exportAsSVG, exportFormats, externalLink, externalNodeLink, fillColor, fillStyle, filterBlankNode$1 as filterBlankNode, filterParams, findConfigModels, findMatchingModel, findModels, findNodeModel, findOrchestratorModel, findProperty, findPropertyById, flatFilterData, flatFilterNode, formatCustomErrorMessage, formatDate, formatError, formatPropertyError, formatter, getColor, getDatesBetween, gitBranch, gitHome, gitlabRawUrl, glossaryBaseUrl, glossaryLink, groupBlankNodesByTermIdentity, groupChanged, groupDataByCategory, groupJLogByField, groupJLogByTerm, groupLogsByTerm, groupNodesByTerm, groupdLogsByKey, grouppedKeys, grouppedValueKeys, groupsLogsByFields, guideModelUrl, guideNamespace, handleAPIError, handleGuideEvent, hasError, hasValidationError, hasWarning, hexToRgba, ignoreKeys$2 as ignoreKeys, increaseScaleLimits, initialFilterState, injectResizeEvent$, inputGroupsTermTypes, isAddPropertyEnabled, isChrome, isDateBetween, isEqual, isExternal, isKeyClosedVisible, isKeyHidden, isMaxStage, isMethodModelAllowed, isNonNodeModelKey, isSchemaIri, isScrolledBelow, isState, isTermTypeAllowed, isValidKey, jLogModelCount, keyToDataPath, levels, listColor, listColorContinuous, listColorWithAlpha, loadMapApi, locationQuery, logToCsv$2 as logToCsv, logValueArray, logsKey, lollipopChartPlugin, lookupUrl, mapFilterData, mapsUrl, markerIcon, markerPie, matchAggregatedQuery, matchAggregatedValidatedQuery, matchBoolPrefixQuery, matchCountry, matchExactQuery, matchGlobalRegion, matchId, matchNameNormalized, matchNestedKey, matchPhrasePrefixQuery, matchPhraseQuery, matchPrimaryProductQuery, matchQuery, matchRegex, matchRegion, matchTermType, matchType, maxAreaSize, measurementValue, mergeDataWithHeaders, methodTierOrder, migrationErrorMessage, migrationsUrl, modelCount, modelKeyParams, modelParams, models, multiMatchQuery, nestedProperty, nestingEnabled, nestingTypeEnabled, noValue, nodeAvailableProperties, nodeById, nodeColours$1 as nodeColours, nodeDataState, nodeDataStates, nodeDataVersion, nodeId, nodeIdWithoutDataVersion, nodeIds, nodeLink, nodeLinkEnabled, nodeLinkTypeEnabled, nodeLogsUrl, nodeQualityScoreColor, nodeQualityScoreLevel, nodeQualityScoreMaxDefault, nodeQualityScoreOrder, nodeRequestId, nodeSecondaryColours, nodeToAggregationFilename, nodeType, nodeTypeDataState, nodeTypeIcon, nodeTypeIconSchema, nodeUrl, nodeUrlParams, nodeVersion, nodeVersionKey, nodesByState, nodesByType, numberGte, optionsFromGroup, parentKey, parentProperty, parseColor, parseData, parseDataPath, parseLines, parseMessage, parseNewValue, pluralize, pointToCoordinates, polygonBounds, polygonToCoordinates, polygonToMap, polygonsFromFeature, populateWithTrackIdsFilterData, postGuideEvent, primaryProduct, productsQuery, propertyError, propertyId, recursiveProperties, refToSchemaType, refreshPropertyKeys, regionsQuery, registerChart, repeat, reportIssueLink, reportIssueUrl, safeJSONParse, safeJSONStringify, schemaBaseUrl, schemaDataBaseUrl, schemaLink, schemaRequiredProperties, schemaTypeToDefaultValue, scrollToEl, scrollTop, searchFilterData, searchableTypes, siblingProperty, simplifyContributions, singleProperty, siteTooBig, siteTypeToColor, siteTypeToIcon, sortProperties, sortedDates, strokeColor, strokeStyle, subValueKeys, suggestMatchQuery, suggestQuery, sumValues, takeAfterViewInit, termLocation, termLocationName, termProperties, termTypeLabel, toSnakeCase, toTextParts, toThousands, typeToNewProperty, typeaheadFocus, uncapitalize, uniqueDatesBetween, updateProperties, valueLink, valueToString, valueTypeToDefault, valueValue, waitFor, wildcardQuery };
|
|
17230
17823
|
//# sourceMappingURL=hestia-earth-ui-components.mjs.map
|