@hestia-earth/ui-components 0.42.27 → 0.42.28
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.
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, InjectionToken, inject, ElementRef, output, Directive, DestroyRef, input, computed, HostBinding, Component as Component$1, ChangeDetectionStrategy, Pipe, viewChild, HostListener, model, ViewEncapsulation, signal, effect, contentChild, untracked, viewChildren, forwardRef, LOCALE_ID } from '@angular/core';
|
|
2
|
+
import { Injectable, InjectionToken, inject, ElementRef, PLATFORM_ID, output, Directive, DestroyRef, input, computed, HostBinding, Component as Component$1, ChangeDetectionStrategy, Pipe, viewChild, HostListener, model, ViewEncapsulation, signal, effect, contentChild, untracked, viewChildren, forwardRef, LOCALE_ID } from '@angular/core';
|
|
3
3
|
import { toObservable, toSignal, outputFromObservable, takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
|
|
4
4
|
import * as i1 from '@angular/forms';
|
|
5
5
|
import { FormsModule, NG_VALUE_ACCESSOR, UntypedFormBuilder, Validators, ReactiveFormsModule, FormControl } from '@angular/forms';
|
|
6
|
-
import { NgClass, DecimalPipe, NgTemplateOutlet,
|
|
6
|
+
import { isPlatformBrowser, NgClass, DecimalPipe, NgTemplateOutlet, DOCUMENT, KeyValuePipe, PlatformLocation, NgStyle, UpperCasePipe, JsonPipe, DatePipe, AsyncPipe, formatDate as formatDate$1 } from '@angular/common';
|
|
7
7
|
import * as i1$1 from '@ng-bootstrap/ng-bootstrap';
|
|
8
8
|
import { NgbTooltip, NgbDropdown, NgbDropdownMenu, NgbDropdownToggle, NgbActiveModal, NgbHighlight, NgbModal, NgbDropdownItem, NgbTypeahead, NgbPopover, NgbTooltipModule, NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap';
|
|
9
|
-
import { ReplaySubject, of, mergeMap, shareReplay, delay, map, catchError, distinctUntilChanged, timer, take, first, Subject, combineLatest, filter, fromEvent, startWith, merge, skip, switchMap,
|
|
9
|
+
import { ReplaySubject, of, mergeMap, shareReplay, delay, map, catchError, distinctUntilChanged, timer, take, first, EMPTY, Subject, combineLatest, filter, fromEvent, startWith, merge, skip, switchMap, throttleTime, animationFrameScheduler, debounceTime, takeUntil, lastValueFrom, tap, skipUntil, zip, mergeAll, reduce, forkJoin, throwError, from, firstValueFrom, toArray, distinct, groupBy } from 'rxjs';
|
|
10
10
|
import { HttpClient } from '@angular/common/http';
|
|
11
11
|
import get from 'lodash.get';
|
|
12
12
|
import { SCHEMA_VERSION, SchemaType, NodeType, TermTermType, productTermTermType, nestedSearchableKeys, SiteSiteType, EmissionMethodTier, isExpandable, sortKeysByType, isTypeNode, uniquenessFields, BlankNodesKey, impactAssessmentTermTermType, measurementTermTermType, emissionTermTermType, inputTermTermType, CycleFunctionalUnit, NonBlankNodesKey, jsonldPath, isTypeValid, typeToSchemaType, infrastructureTermTermType, managementTermTermType } from '@hestia-earth/schema';
|
|
@@ -76,16 +76,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
76
76
|
|
|
77
77
|
const gitHome = 'https://gitlab.com/hestia-earth';
|
|
78
78
|
const gitBranch = () => (['dev', 'staging'].some(env => baseUrl().includes(env)) ? 'develop' : 'master');
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Access `window` defensively so this module can be evaluated outside the browser
|
|
81
|
+
* (SSR / prerender / Node). On the server there is no location, so callers fall
|
|
82
|
+
* back to production defaults.
|
|
83
|
+
*/
|
|
84
|
+
const windowRef = () => (typeof window === 'undefined' ? undefined : window);
|
|
85
|
+
const origin = () => windowRef()?.location?.origin ?? '';
|
|
86
|
+
const isChrome = () => windowRef()?.navigator?.userAgent?.includes('Chrome') ?? false;
|
|
87
|
+
const baseUrl = (allowLocalhost = true) => origin().includes('localhost')
|
|
81
88
|
? allowLocalhost
|
|
82
|
-
?
|
|
89
|
+
? origin()
|
|
83
90
|
: 'https://www-dev.hestia.earth'
|
|
84
|
-
:
|
|
85
|
-
?
|
|
91
|
+
: origin().includes('hestia.earth')
|
|
92
|
+
? origin()
|
|
86
93
|
: 'https://www.hestia.earth';
|
|
87
94
|
const baseApiUrl = () => baseUrl(false).replace('www', 'api');
|
|
88
|
-
const isExternal = () => baseUrl() !==
|
|
95
|
+
const isExternal = () => baseUrl() !== origin();
|
|
89
96
|
const schemaBaseUrl = (version) => [baseUrl(), 'schema', version].filter(Boolean).join('/');
|
|
90
97
|
const schemaDataBaseUrl = (version) => [baseUrl(false), 'schema-data', version || SCHEMA_VERSION].filter(Boolean).join('/');
|
|
91
98
|
const glossaryBaseUrl = (allowLocalhost = true) => [baseUrl(allowLocalhost), 'glossary'].filter(Boolean).join('/');
|
|
@@ -120,7 +127,11 @@ const filterParams = (obj) => {
|
|
|
120
127
|
});
|
|
121
128
|
return res;
|
|
122
129
|
};
|
|
123
|
-
const waitFor = (variable, callback) =>
|
|
130
|
+
const waitFor = (variable, callback) => typeof window === 'undefined'
|
|
131
|
+
? undefined
|
|
132
|
+
: get(window, variable, false)
|
|
133
|
+
? callback()
|
|
134
|
+
: setTimeout(() => waitFor(variable, callback), 100);
|
|
124
135
|
const bottom = (element) => element.offsetTop + element.getBoundingClientRect().height;
|
|
125
136
|
const isScrolledBelow = (element) => (element ? window.scrollY > bottom(element) : false);
|
|
126
137
|
const scrollToEl = (id, args = {
|
|
@@ -1545,14 +1556,18 @@ class ResizedEvent {
|
|
|
1545
1556
|
class ResizedDirective {
|
|
1546
1557
|
constructor() {
|
|
1547
1558
|
this.element = inject(ElementRef);
|
|
1559
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
1548
1560
|
this.resized = output();
|
|
1549
|
-
|
|
1561
|
+
// `ResizeObserver` is browser-only; there are no resize events during SSR.
|
|
1562
|
+
if (this.isBrowser) {
|
|
1563
|
+
this.observer = new ResizeObserver(entries => this.observe(entries));
|
|
1564
|
+
}
|
|
1550
1565
|
}
|
|
1551
1566
|
ngOnInit() {
|
|
1552
|
-
this.observer
|
|
1567
|
+
this.observer?.observe(this.element.nativeElement);
|
|
1553
1568
|
}
|
|
1554
1569
|
ngOnDestroy() {
|
|
1555
|
-
this.observer
|
|
1570
|
+
this.observer?.disconnect();
|
|
1556
1571
|
}
|
|
1557
1572
|
observe(entries) {
|
|
1558
1573
|
const domSize = entries[0];
|
|
@@ -1574,6 +1589,10 @@ const distinctUntilChangedDeep = () => distinctUntilChanged((x, y) => isEqual$1(
|
|
|
1574
1589
|
const takeAfterViewInit = (fn, settings = { take: 10 }) => timer(0, 50).pipe(take(settings.take), map(() => fn()), first(returnItem => !!returnItem));
|
|
1575
1590
|
const injectResizeEvent$ = (elementRef) => {
|
|
1576
1591
|
const destroyRef = inject(DestroyRef);
|
|
1592
|
+
// `ResizeObserver` is browser-only; there are no resize events during SSR.
|
|
1593
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
1594
|
+
return EMPTY;
|
|
1595
|
+
}
|
|
1577
1596
|
const resizedEvent$ = new Subject();
|
|
1578
1597
|
let oldRect;
|
|
1579
1598
|
const observer = new ResizeObserver(entries => {
|
|
@@ -1723,7 +1742,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
1723
1742
|
|
|
1724
1743
|
const GUIDE_ENABLED = new InjectionToken('HESTIA_GUIDE_ENABLED');
|
|
1725
1744
|
const guideNamespace = 'he-guide';
|
|
1726
|
-
const postGuideEvent = (data) => window
|
|
1745
|
+
const postGuideEvent = (data) => typeof window === 'undefined'
|
|
1746
|
+
? undefined
|
|
1747
|
+
: window.parent.postMessage({ namespace: guideNamespace, ...data }, '*');
|
|
1727
1748
|
const handleGuideEvent = (handler) => (event) => {
|
|
1728
1749
|
const data = event.data;
|
|
1729
1750
|
if (data.namespace == guideNamespace) {
|
|
@@ -2029,7 +2050,10 @@ const toBreakpoint = ({ min, max }) => [min ? toSize(beakpointWidths[min], 'min'
|
|
|
2029
2050
|
class ResponsiveService {
|
|
2030
2051
|
constructor() {
|
|
2031
2052
|
this.breakPointObserver = inject(BreakpointObserver);
|
|
2032
|
-
this.
|
|
2053
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
2054
|
+
this.windowWidth$ = this.isBrowser
|
|
2055
|
+
? fromEvent(window, 'resize').pipe(startWith(window.innerWidth), map(() => window.innerWidth))
|
|
2056
|
+
: of(0);
|
|
2033
2057
|
this.isMobile$ = this.breakPointObserver.observe(toBreakpoint({ max: Breakpoint.tablet })).pipe(map(state => state.matches), distinctUntilChanged());
|
|
2034
2058
|
this.isTablet$ = this.breakPointObserver
|
|
2035
2059
|
.observe(toBreakpoint({ min: Breakpoint.tablet, max: Breakpoint.desktop }))
|
|
@@ -2047,7 +2071,7 @@ class ResponsiveService {
|
|
|
2047
2071
|
*/
|
|
2048
2072
|
this.is1080p$ = this.breakPointObserver.observe(toSize(1920, 'min')).pipe(map(state => state.matches), distinctUntilChanged());
|
|
2049
2073
|
this.isRetinaDisplay = () => {
|
|
2050
|
-
if (window.matchMedia) {
|
|
2074
|
+
if (this.isBrowser && window.matchMedia) {
|
|
2051
2075
|
const mq = window.matchMedia([
|
|
2052
2076
|
'min--moz-device-pixel-ratio: 1.3',
|
|
2053
2077
|
'-o-min-device-pixel-ratio: 2.6/2',
|
|
@@ -2117,6 +2141,8 @@ class DrawerContainerComponent {
|
|
|
2117
2141
|
constructor() {
|
|
2118
2142
|
this.responsiveService = inject(ResponsiveService);
|
|
2119
2143
|
this.localStorage = inject(LocalStorageService);
|
|
2144
|
+
this.document = inject(DOCUMENT);
|
|
2145
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
2120
2146
|
this.contentContainer = viewChild('contentContainer', { ...(ngDevMode ? { debugName: "contentContainer" } : {}), read: ElementRef });
|
|
2121
2147
|
this.menuState = signal('close', ...(ngDevMode ? [{ debugName: "menuState" }] : []));
|
|
2122
2148
|
/**
|
|
@@ -2199,7 +2225,9 @@ class DrawerContainerComponent {
|
|
|
2199
2225
|
this.destroy$ = new Subject();
|
|
2200
2226
|
this._updateSidenavEvent$ = toObservable(this.isResizing).pipe(switchMap(listen => (listen ? moveEvent() : EMPTY)), throttleTime(0, animationFrameScheduler));
|
|
2201
2227
|
this._contentContainer$ = toObservable(this.contentContainer).pipe(filter(v => !!v));
|
|
2202
|
-
this._hostComponentWidth$ =
|
|
2228
|
+
this._hostComponentWidth$ = this.isBrowser
|
|
2229
|
+
? fromEvent(window, 'resize').pipe(startWith(window.innerWidth))
|
|
2230
|
+
: of(0);
|
|
2203
2231
|
/**
|
|
2204
2232
|
* we use combineLatest instead of computed to avoid the animation flickering (wait for all sources to emit)
|
|
2205
2233
|
*/
|
|
@@ -2221,13 +2249,13 @@ class DrawerContainerComponent {
|
|
|
2221
2249
|
effect(() => {
|
|
2222
2250
|
const position = this.position();
|
|
2223
2251
|
const width = this.sidenavWidth();
|
|
2224
|
-
document.body.style.setProperty(`--sidenav-${position}-width`, `${width}px`);
|
|
2252
|
+
this.document.body.style.setProperty(`--sidenav-${position}-width`, `${width}px`);
|
|
2225
2253
|
});
|
|
2226
2254
|
effect(() => {
|
|
2227
2255
|
const expanded = this.expanded();
|
|
2228
2256
|
const position = this.position();
|
|
2229
2257
|
const value = this.contentContainerTransform();
|
|
2230
|
-
document.body.style.setProperty(`--content-transition-${position}-x`, `${expanded ? value : 0}px`);
|
|
2258
|
+
this.document.body.style.setProperty(`--content-transition-${position}-x`, `${expanded ? value : 0}px`);
|
|
2231
2259
|
});
|
|
2232
2260
|
// initial load of configuration
|
|
2233
2261
|
effect(() => this.storageKey() && this.storeConfiguration());
|
|
@@ -2304,6 +2332,8 @@ class DrawerContainerComponent {
|
|
|
2304
2332
|
this.menuState.set(didOpen ? 'open' : 'close');
|
|
2305
2333
|
}
|
|
2306
2334
|
_getContentLeftSideSpace(element) {
|
|
2335
|
+
if (!this.isBrowser)
|
|
2336
|
+
return 0;
|
|
2307
2337
|
const position = this.position();
|
|
2308
2338
|
const styles = window.getComputedStyle(element.nativeElement, null);
|
|
2309
2339
|
const padding = styles.getPropertyValue('padding-' + position);
|
|
@@ -3006,6 +3036,12 @@ const loadSvgSprite = () => {
|
|
|
3006
3036
|
const http = inject(HttpClient);
|
|
3007
3037
|
const document = inject(DOCUMENT);
|
|
3008
3038
|
const platformLocation = inject(PlatformLocation);
|
|
3039
|
+
// The sprite is injected into the DOM for the browser to render `<use>` refs.
|
|
3040
|
+
// During SSR/prerender there is no asset server to fetch it from, and the
|
|
3041
|
+
// client re-injects it on hydration, so skip the fetch on the server.
|
|
3042
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
3043
|
+
return Promise.resolve();
|
|
3044
|
+
}
|
|
3009
3045
|
const baseUrl = platformLocation.getBaseHrefFromDOM();
|
|
3010
3046
|
return lastValueFrom(http.get(`${baseUrl}assets/svg-icons/icons-sprite.svg`, { responseType: 'text' }).pipe(tap(svgContent => {
|
|
3011
3047
|
const div = document.createElement('div');
|
|
@@ -3464,10 +3500,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
3464
3500
|
class SocialTagsComponent {
|
|
3465
3501
|
constructor() {
|
|
3466
3502
|
this.meta = inject(Meta);
|
|
3503
|
+
this.document = inject(DOCUMENT);
|
|
3467
3504
|
this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
3468
3505
|
this.classes = 'is-hidden';
|
|
3469
3506
|
this.configs = computed(() => ({
|
|
3470
|
-
'og:url':
|
|
3507
|
+
'og:url': this.document.location.href.split('?')[0],
|
|
3471
3508
|
...this.config
|
|
3472
3509
|
}), ...(ngDevMode ? [{ debugName: "configs" }] : []));
|
|
3473
3510
|
this.meta.addTag({ charset: 'UTF-8' });
|
|
@@ -3562,8 +3599,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
3562
3599
|
/* eslint-disable @angular-eslint/directive-selector */
|
|
3563
3600
|
class DocumentClickService {
|
|
3564
3601
|
constructor() {
|
|
3602
|
+
this.document = inject(DOCUMENT);
|
|
3565
3603
|
this.documentClick$ = new Subject();
|
|
3566
|
-
|
|
3604
|
+
// Document click events only exist in the browser; skip on the server (SSR).
|
|
3605
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3608
|
+
fromEvent(this.document, 'click')
|
|
3567
3609
|
.pipe(takeUntilDestroyed(), tap(event => this.documentClick$.next(event)))
|
|
3568
3610
|
.subscribe();
|
|
3569
3611
|
}
|
|
@@ -8933,16 +8975,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
8933
8975
|
|
|
8934
8976
|
class GuideOverlayService {
|
|
8935
8977
|
constructor() {
|
|
8978
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
8936
8979
|
this.message = signal(null, ...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
8937
8980
|
this.messageListener = ({ data }) => {
|
|
8938
8981
|
if (data.namespace == guideNamespace) {
|
|
8939
8982
|
this.message.set(data);
|
|
8940
8983
|
}
|
|
8941
8984
|
};
|
|
8942
|
-
|
|
8985
|
+
// `postMessage` communication only exists in the browser; skip on the server (SSR).
|
|
8986
|
+
if (this.isBrowser) {
|
|
8987
|
+
window.addEventListener('message', this.messageListener);
|
|
8988
|
+
}
|
|
8943
8989
|
}
|
|
8944
8990
|
ngOnDestroy() {
|
|
8945
|
-
|
|
8991
|
+
if (this.isBrowser) {
|
|
8992
|
+
window.removeEventListener('message', this.messageListener);
|
|
8993
|
+
}
|
|
8946
8994
|
}
|
|
8947
8995
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GuideOverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8948
8996
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GuideOverlayService, providedIn: 'root' }); }
|
|
@@ -9290,6 +9338,10 @@ const isMissing = (value) => value === undefined || value === null || value ===
|
|
|
9290
9338
|
// the result symbol (left-hand side) - it is the model's output, not an input that "was not logged", so
|
|
9291
9339
|
// it is excluded from the missing-values notice (e.g. a failed model has no result value)
|
|
9292
9340
|
const resultKey = 'value';
|
|
9341
|
+
// the reserved table key a `\sum` over per-contributor products binds to (e.g. `[contributions:value]`).
|
|
9342
|
+
// its rows come from the ImpactAssessment's contribution data (register_contribution), not the jlog, so
|
|
9343
|
+
// these "characterisation = Σ contributions" models render fully without duplicating values into the logs
|
|
9344
|
+
const contributionsKey = 'contributions';
|
|
9293
9345
|
// the "value formula" computes the model's result (`key: "value"`); any others are sub-formulas that
|
|
9294
9346
|
// compute its components (possibly chained: a sub-formula's result feeds another sub-formula)
|
|
9295
9347
|
const isValueFormula = (formula) => formula.bindings.some(binding => binding.key === resultKey);
|
|
@@ -9352,15 +9404,42 @@ class NodeLogsModelsFormulaComponent {
|
|
|
9352
9404
|
// the value the model returned (the recalculated node value): the result symbol (`key: "value"`) is
|
|
9353
9405
|
// usually not logged, so it falls back to this
|
|
9354
9406
|
this.value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
9407
|
+
// the ImpactAssessment the model ran on: lets a contribution-based `\sum` pull its per-contributor
|
|
9408
|
+
// summands from the stored contribution data instead of duplicating them into the jlog
|
|
9409
|
+
this.node = input(...(ngDevMode ? [undefined, { debugName: "node" }] : []));
|
|
9410
|
+
this.nodeService = inject(HeNodeService);
|
|
9355
9411
|
// show the substituted formula (values in place of symbols) rather than the raw symbolic one
|
|
9356
9412
|
this.substituted = signal(false, ...(ngDevMode ? [{ debugName: "substituted" }] : []));
|
|
9357
9413
|
// a unique id per instance so the switch label only toggles its own checkbox (several popovers can co-exist)
|
|
9358
9414
|
this.toggleId = uuid('formulaSubstituted-');
|
|
9359
9415
|
this.formulas = computed(() => getModelFormulas(this.model()), ...(ngDevMode ? [{ debugName: "formulas" }] : []));
|
|
9416
|
+
// whether any formula sums over per-contributor products (bound to the reserved `contributions` table)
|
|
9417
|
+
this.hasContributionBinding = computed(() => this.formulas().some(formula => formula.bindings.some(binding => binding.key === contributionsKey)), ...(ngDevMode ? [{ debugName: "hasContributionBinding" }] : []));
|
|
9418
|
+
// only fetch contributions when a formula actually needs them and we have an ImpactAssessment to fetch for
|
|
9419
|
+
this.contributionResource = rxResource({
|
|
9420
|
+
params: () => (this.hasContributionBinding() && this.node() ? { node: this.node() } : undefined),
|
|
9421
|
+
stream: ({ params: { node } }) => this.nodeService.getContributions$(node)
|
|
9422
|
+
});
|
|
9423
|
+
// the contributions to this indicator term, grouped by method model (empty until loaded / when N/A)
|
|
9424
|
+
this.termContributions = computed(() => {
|
|
9425
|
+
const node = this.node();
|
|
9426
|
+
const contributions = this.contributionResource.value();
|
|
9427
|
+
if (!node || !contributions)
|
|
9428
|
+
return {};
|
|
9429
|
+
return simplifyContributions(node, contributions)[this.model()?.term ?? ''] ?? {};
|
|
9430
|
+
}, ...(ngDevMode ? [{ debugName: "termContributions" }] : []));
|
|
9431
|
+
// the per-contributor summands for this model, shaped as `\sum` rows: { id: contributor term, value }
|
|
9432
|
+
this.contributionRows = computed(() => {
|
|
9433
|
+
const byIndicator = this.termContributions()[this.model()?.model ?? ''] ?? {};
|
|
9434
|
+
return Object.entries(byIndicator).map(([id, value]) => ({ id, value }));
|
|
9435
|
+
}, ...(ngDevMode ? [{ debugName: "contributionRows" }] : []));
|
|
9360
9436
|
this.values = computed(() => {
|
|
9361
9437
|
const values = logValues(this.logs());
|
|
9362
9438
|
// the result (`value`) is usually the model's returned value rather than a logged field
|
|
9363
|
-
|
|
9439
|
+
const withResult = isMissing(values.value) && !isMissing(this.value()) ? { ...values, value: this.value() } : values;
|
|
9440
|
+
// feed a contribution-based `\sum` from the stored contributions (nothing to merge for other formulas)
|
|
9441
|
+
const rows = this.contributionRows();
|
|
9442
|
+
return rows.length ? { ...withResult, [contributionsKey]: rows } : withResult;
|
|
9364
9443
|
}, ...(ngDevMode ? [{ debugName: "values" }] : []));
|
|
9365
9444
|
this.valueFormula = computed(() => this.formulas().find(isValueFormula), ...(ngDevMode ? [{ debugName: "valueFormula" }] : []));
|
|
9366
9445
|
// the value formula's own symbol keys - kept symbolic in the sub-formulas (they are substituted only in
|
|
@@ -9411,12 +9490,12 @@ class NodeLogsModelsFormulaComponent {
|
|
|
9411
9490
|
this.substituted.update(value => !value);
|
|
9412
9491
|
}
|
|
9413
9492
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsFormulaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9414
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.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 } }, ngImport: i0, template: "@if (formulas().length) {\n <div class=\"formula-block is-mb-2 has-text-white\">\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 class=\"is-uppercase has-text-weight-semibold\">Formula{{ formulas().length > 1 ? 's' : '' }}</span>\n <div 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() ? '' : 'No logged values to substitute'\">\n <span>{{ substituted() ? 'Substituted' : 'Raw' }}</span>\n </label>\n </div>\n </div>\n\n @for (item of renderedFormulas(); track $index) {\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.description) {\n <span>:</span>\n }\n </span>\n @if (variable.description) {\n <markdown class=\"is-inline-block is-italic | formula-variable-desc\" [data]=\"variable.description\" />\n }\n @if (variable.missing) {\n <span class=\"has-text-warning\">(missing)</span>\n }\n </div>\n </li>\n }\n </ul>\n }\n }\n </div>\n}\n", styles: [".formula-block{border-bottom:1px solid rgba(255,255,255,.2)}.formula-variable-symbol{flex-shrink:0}.formula-variable-symbol ::ng-deep .katex{font-size:1em}.formula-variable-desc{opacity:.85}.formula-variable-desc ::ng-deep *{display:inline;margin:0}.formula{overflow-x:auto;overflow-y:hidden}.formula ::ng-deep .katex-display{margin:.35rem 0}\n"], dependencies: [{ 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9493
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.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 } }, ngImport: i0, template: "@if (formulas().length) {\n <div class=\"formula-block is-mb-2 has-text-white\">\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 class=\"is-uppercase has-text-weight-semibold\">Formula{{ formulas().length > 1 ? 's' : '' }}</span>\n <div 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() ? '' : 'No logged values to substitute'\">\n <span>{{ substituted() ? 'Substituted' : 'Raw' }}</span>\n </label>\n </div>\n </div>\n\n @for (item of renderedFormulas(); track $index) {\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.description) {\n <span>:</span>\n }\n </span>\n @if (variable.description) {\n <markdown class=\"is-inline-block is-italic | formula-variable-desc\" [data]=\"variable.description\" />\n }\n @if (variable.missing) {\n <span class=\"has-text-warning\">(missing)</span>\n }\n </div>\n </li>\n }\n </ul>\n }\n }\n </div>\n}\n", styles: [".formula-block{border-bottom:1px solid rgba(255,255,255,.2)}.formula-variable-symbol{flex-shrink:0}.formula-variable-symbol ::ng-deep .katex{font-size:1em}.formula-variable-desc{opacity:.85}.formula-variable-desc ::ng-deep *{display:inline;margin:0}.formula{overflow-x:auto;overflow-y:hidden}.formula ::ng-deep .katex-display{margin:.35rem 0}\n"], dependencies: [{ 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9415
9494
|
}
|
|
9416
9495
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsFormulaComponent, decorators: [{
|
|
9417
9496
|
type: Component$1,
|
|
9418
9497
|
args: [{ selector: 'he-node-logs-models-formula', changeDetection: ChangeDetectionStrategy.OnPush, imports: [KatexDirective, MarkdownComponent], template: "@if (formulas().length) {\n <div class=\"formula-block is-mb-2 has-text-white\">\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 class=\"is-uppercase has-text-weight-semibold\">Formula{{ formulas().length > 1 ? 's' : '' }}</span>\n <div 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() ? '' : 'No logged values to substitute'\">\n <span>{{ substituted() ? 'Substituted' : 'Raw' }}</span>\n </label>\n </div>\n </div>\n\n @for (item of renderedFormulas(); track $index) {\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.description) {\n <span>:</span>\n }\n </span>\n @if (variable.description) {\n <markdown class=\"is-inline-block is-italic | formula-variable-desc\" [data]=\"variable.description\" />\n }\n @if (variable.missing) {\n <span class=\"has-text-warning\">(missing)</span>\n }\n </div>\n </li>\n }\n </ul>\n }\n }\n </div>\n}\n", styles: [".formula-block{border-bottom:1px solid rgba(255,255,255,.2)}.formula-variable-symbol{flex-shrink:0}.formula-variable-symbol ::ng-deep .katex{font-size:1em}.formula-variable-desc{opacity:.85}.formula-variable-desc ::ng-deep *{display:inline;margin:0}.formula{overflow-x:auto;overflow-y:hidden}.formula ::ng-deep .katex-display{margin:.35rem 0}\n"] }]
|
|
9419
|
-
}], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], logs: [{ type: i0.Input, args: [{ isSignal: true, alias: "logs", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }] } });
|
|
9498
|
+
}], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], logs: [{ type: i0.Input, args: [{ isSignal: true, alias: "logs", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }] } });
|
|
9420
9499
|
|
|
9421
9500
|
class NodeLogsModelsDetailsComponent {
|
|
9422
9501
|
constructor() {
|
|
@@ -9460,7 +9539,7 @@ class NodeLogsModelsDetailsComponent {
|
|
|
9460
9539
|
this.openKeys.set(next);
|
|
9461
9540
|
}
|
|
9462
9541
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9463
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsDetailsComponent, isStandalone: true, selector: "he-node-logs-models-details", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, hasContributions: { classPropertyName: "hasContributions", publicName: "hasContributions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@for (section of sections(); track section.key; let last = $last) {\n <div class=\"log-section\" [class.has-border-bottom]=\"!last || isOpen(section.key)\">\n @if (section.key === 'formula' && isOpen('formula')) {\n <!-- the formula component renders its own \"Formula BETA\" title + Raw/Substituted switch on one\n line, so keep the toggle chevron inline with it rather than adding a duplicate header -->\n <div class=\"log-section-header is-flex is-align-items-flex-start is-gap-4\">\n <a class=\"has-text-white\" (click)=\"toggle('formula')\">\n <he-svg-icon name=\"chevron-down\" size=\"16\" />\n </a>\n <div class=\"is-flex-grow-1\">\n <he-node-logs-models-formula
|
|
9542
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NodeLogsModelsDetailsComponent, isStandalone: true, selector: "he-node-logs-models-details", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, nodeKey: { classPropertyName: "nodeKey", publicName: "nodeKey", isSignal: true, isRequired: false, transformFunction: null }, hasContributions: { classPropertyName: "hasContributions", publicName: "hasContributions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@for (section of sections(); track section.key; let last = $last) {\n <div class=\"log-section\" [class.has-border-bottom]=\"!last || isOpen(section.key)\">\n @if (section.key === 'formula' && isOpen('formula')) {\n <!-- the formula component renders its own \"Formula BETA\" title + Raw/Substituted switch on one\n line, so keep the toggle chevron inline with it rather than adding a duplicate header -->\n <div class=\"log-section-header is-flex is-align-items-flex-start is-gap-4\">\n <a class=\"has-text-white\" (click)=\"toggle('formula')\">\n <he-svg-icon name=\"chevron-down\" size=\"16\" />\n </a>\n <div class=\"is-flex-grow-1\">\n <he-node-logs-models-formula\n [model]=\"model().model\"\n [logs]=\"model().logs\"\n [value]=\"value()\"\n [node]=\"node()\" />\n </div>\n </div>\n } @else {\n <a\n class=\"log-section-header is-flex is-align-items-center is-gap-4 has-text-white is-size-8 is-uppercase has-text-weight-semibold\"\n (click)=\"toggle(section.key)\">\n <he-svg-icon [name]=\"isOpen(section.key) ? 'chevron-down' : 'chevron-right'\" size=\"16\" />\n <span>{{ section.label }}</span>\n </a>\n\n @if (isOpen(section.key)) {\n <div class=\"log-section-body is-pb-2\">\n @switch (section.key) {\n @case ('logs') {\n <he-node-logs-models-logs [logs]=\"model().logs\" [renderRaw]=\"false\" />\n }\n @case ('raw') {\n <div class=\"is-flex is-justify-content-flex-end is-mb-1\">\n <he-clipboard clipboardClass=\"is-size-7 is-p-1\" [value]=\"rawJson()\" [hideText]=\"true\" />\n </div>\n <pre class=\"raw-log\">{{ rawJson() }}</pre>\n }\n @case ('contributions') {\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model()\" />\n }\n }\n </div>\n }\n }\n </div>\n}\n", styles: [".log-section{border-color:#fff3!important}.log-section-header{cursor:pointer;padding:.5rem 0}.log-section-header ::ng-deep .formula-block{margin-bottom:0;border-bottom:none}.raw-log{max-height:300px;overflow:auto;white-space:pre;font-size:.75rem;background:#00000059;color:inherit;padding:.5rem;border-radius:3px}\n"], dependencies: [{ kind: "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: NodeLogsModelsFormulaComponent, selector: "he-node-logs-models-formula", inputs: ["model", "logs", "value", "node"] }, { kind: "component", type: NodeLogsModelsLogsComponent, selector: "he-node-logs-models-logs", inputs: ["logs", "renderRaw"] }, { kind: "component", type: NodeLogsModelsContributionsComponent, selector: "he-node-logs-models-contributions", inputs: ["node", "nodeKey", "model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9464
9543
|
}
|
|
9465
9544
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NodeLogsModelsDetailsComponent, decorators: [{
|
|
9466
9545
|
type: Component$1,
|
|
@@ -9470,7 +9549,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
9470
9549
|
NodeLogsModelsFormulaComponent,
|
|
9471
9550
|
NodeLogsModelsLogsComponent,
|
|
9472
9551
|
NodeLogsModelsContributionsComponent
|
|
9473
|
-
], template: "@for (section of sections(); track section.key; let last = $last) {\n <div class=\"log-section\" [class.has-border-bottom]=\"!last || isOpen(section.key)\">\n @if (section.key === 'formula' && isOpen('formula')) {\n <!-- the formula component renders its own \"Formula BETA\" title + Raw/Substituted switch on one\n line, so keep the toggle chevron inline with it rather than adding a duplicate header -->\n <div class=\"log-section-header is-flex is-align-items-flex-start is-gap-4\">\n <a class=\"has-text-white\" (click)=\"toggle('formula')\">\n <he-svg-icon name=\"chevron-down\" size=\"16\" />\n </a>\n <div class=\"is-flex-grow-1\">\n <he-node-logs-models-formula
|
|
9552
|
+
], template: "@for (section of sections(); track section.key; let last = $last) {\n <div class=\"log-section\" [class.has-border-bottom]=\"!last || isOpen(section.key)\">\n @if (section.key === 'formula' && isOpen('formula')) {\n <!-- the formula component renders its own \"Formula BETA\" title + Raw/Substituted switch on one\n line, so keep the toggle chevron inline with it rather than adding a duplicate header -->\n <div class=\"log-section-header is-flex is-align-items-flex-start is-gap-4\">\n <a class=\"has-text-white\" (click)=\"toggle('formula')\">\n <he-svg-icon name=\"chevron-down\" size=\"16\" />\n </a>\n <div class=\"is-flex-grow-1\">\n <he-node-logs-models-formula\n [model]=\"model().model\"\n [logs]=\"model().logs\"\n [value]=\"value()\"\n [node]=\"node()\" />\n </div>\n </div>\n } @else {\n <a\n class=\"log-section-header is-flex is-align-items-center is-gap-4 has-text-white is-size-8 is-uppercase has-text-weight-semibold\"\n (click)=\"toggle(section.key)\">\n <he-svg-icon [name]=\"isOpen(section.key) ? 'chevron-down' : 'chevron-right'\" size=\"16\" />\n <span>{{ section.label }}</span>\n </a>\n\n @if (isOpen(section.key)) {\n <div class=\"log-section-body is-pb-2\">\n @switch (section.key) {\n @case ('logs') {\n <he-node-logs-models-logs [logs]=\"model().logs\" [renderRaw]=\"false\" />\n }\n @case ('raw') {\n <div class=\"is-flex is-justify-content-flex-end is-mb-1\">\n <he-clipboard clipboardClass=\"is-size-7 is-p-1\" [value]=\"rawJson()\" [hideText]=\"true\" />\n </div>\n <pre class=\"raw-log\">{{ rawJson() }}</pre>\n }\n @case ('contributions') {\n <he-node-logs-models-contributions [node]=\"node()\" [nodeKey]=\"nodeKey()\" [model]=\"model()\" />\n }\n }\n </div>\n }\n }\n </div>\n}\n", styles: [".log-section{border-color:#fff3!important}.log-section-header{cursor:pointer;padding:.5rem 0}.log-section-header ::ng-deep .formula-block{margin-bottom:0;border-bottom:none}.raw-log{max-height:300px;overflow:auto;white-space:pre;font-size:.75rem;background:#00000059;color:inherit;padding:.5rem;border-radius:3px}\n"] }]
|
|
9474
9553
|
}], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], nodeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeKey", required: false }] }], hasContributions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasContributions", required: false }] }] } });
|
|
9475
9554
|
|
|
9476
9555
|
/**
|
|
@@ -14234,7 +14313,7 @@ ${JSON.stringify(error)}
|
|
|
14234
14313
|
|
|
14235
14314
|
## Details
|
|
14236
14315
|
|
|
14237
|
-
* Path: [open](${window.location.href})
|
|
14316
|
+
* Path: [open](${typeof window === 'undefined' ? baseUrl() : window.location.href})
|
|
14238
14317
|
* Stage: \`${fileStatus?.replace('Done', '')?.replace('Error', '')}\`
|
|
14239
14318
|
|
|
14240
14319
|
/label ~"Type::bug"
|
|
@@ -14823,7 +14902,7 @@ const mergedNodes = (selection, { tooltipOperator }) => {
|
|
|
14823
14902
|
.attr('stroke-width', '2')
|
|
14824
14903
|
.attr('rx', '3px')
|
|
14825
14904
|
.attr('ry', '3px')
|
|
14826
|
-
.style('user-select', window.innerWidth < 768 ? 'none' : null);
|
|
14905
|
+
.style('user-select', typeof window !== 'undefined' && window.innerWidth < 768 ? 'none' : null);
|
|
14827
14906
|
selection.filter(d => !d.data.group && d.data.id !== nonLCAIndicatorsId).call(addTooltip, { tooltipOperator });
|
|
14828
14907
|
selection
|
|
14829
14908
|
.selectAll('.node-label')
|