jupiter-dynamic-forms 1.22.4 → 1.22.6
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/dist/core/add-column-dialog.d.ts +3 -0
- package/dist/core/add-column-dialog.d.ts.map +1 -1
- package/dist/core/advanced-filter.d.ts.map +1 -1
- package/dist/core/concept-tree.d.ts +8 -1
- package/dist/core/concept-tree.d.ts.map +1 -1
- package/dist/core/dynamic-form.d.ts +44 -0
- package/dist/core/dynamic-form.d.ts.map +1 -1
- package/dist/core/filter-roles-dialog.d.ts +3 -0
- package/dist/core/filter-roles-dialog.d.ts.map +1 -1
- package/dist/core/form-field.d.ts +4 -0
- package/dist/core/form-field.d.ts.map +1 -1
- package/dist/core/form-section.d.ts +2 -1
- package/dist/core/form-section.d.ts.map +1 -1
- package/dist/index.js +264 -215
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +384 -53
- package/dist/index.mjs.map +1 -1
- package/dist/schema/types.d.ts +8 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/utils/formula-resolution-context.d.ts.map +1 -1
- package/dist/utils/formula-variable-resolver.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1808,6 +1808,7 @@ const field$1 = {
|
|
|
1808
1808
|
selectUnit: "Select Unit",
|
|
1809
1809
|
leaveBlankForInf: "Leave blank for INF",
|
|
1810
1810
|
prefilledLocked: "Pre-filled — cannot be changed here",
|
|
1811
|
+
notApplicablePriorYear: "Not required for the previous year",
|
|
1811
1812
|
invalidNumber: `Can't read "{{value}}" as a number`,
|
|
1812
1813
|
noDecimalsAllowed: "This field doesn't accept decimals",
|
|
1813
1814
|
negativeNotAllowed: "A negative value isn't allowed here",
|
|
@@ -1865,7 +1866,9 @@ const duplicateFactWarning$1 = {
|
|
|
1865
1866
|
message: "The same concept, period and dimensions were found with different values entered in different roles. Only one value can be correct — click a fact below to review and fix it.",
|
|
1866
1867
|
role: "Role:",
|
|
1867
1868
|
value: "Value:",
|
|
1868
|
-
clickToFocus: "Click to go to this fact"
|
|
1869
|
+
clickToFocus: "Click to go to this fact",
|
|
1870
|
+
cellTooltip: "This value differs from the same fact entered elsewhere — click to review",
|
|
1871
|
+
close: "Close"
|
|
1869
1872
|
};
|
|
1870
1873
|
const calculationWarning$1 = {
|
|
1871
1874
|
title: "Calculation warning",
|
|
@@ -2068,6 +2071,7 @@ const field = {
|
|
|
2068
2071
|
selectUnit: "Selecteer eenheid",
|
|
2069
2072
|
leaveBlankForInf: "Leeg laten voor INF",
|
|
2070
2073
|
prefilledLocked: "Vooraf ingevuld — kan hier niet worden gewijzigd",
|
|
2074
|
+
notApplicablePriorYear: "Niet vereist voor het voorgaande jaar",
|
|
2071
2075
|
invalidNumber: "Kan '{{value}}' niet lezen als getal",
|
|
2072
2076
|
noDecimalsAllowed: "Dit veld accepteert geen decimalen",
|
|
2073
2077
|
negativeNotAllowed: "Een negatieve waarde is hier niet toegestaan",
|
|
@@ -2125,7 +2129,9 @@ const duplicateFactWarning = {
|
|
|
2125
2129
|
message: "Hetzelfde concept, dezelfde periode en dimensies zijn gevonden met verschillende waarden in verschillende rollen. Slechts één waarde kan juist zijn — klik op een feit hieronder om het te controleren en te corrigeren.",
|
|
2126
2130
|
role: "Rol:",
|
|
2127
2131
|
value: "Waarde:",
|
|
2128
|
-
clickToFocus: "Klik om naar dit feit te gaan"
|
|
2132
|
+
clickToFocus: "Klik om naar dit feit te gaan",
|
|
2133
|
+
cellTooltip: "Deze waarde wijkt af van hetzelfde feit dat elders is ingevoerd — klik om te controleren",
|
|
2134
|
+
close: "Sluiten"
|
|
2129
2135
|
};
|
|
2130
2136
|
const calculationWarning = {
|
|
2131
2137
|
title: "Berekeningswaarschuwing",
|
|
@@ -2888,6 +2894,7 @@ function collectAllCandidates(formData) {
|
|
|
2888
2894
|
return candidates;
|
|
2889
2895
|
}
|
|
2890
2896
|
function indexConceptTree(concept, conceptByQName, conceptById, conceptIdByQName, conceptIdByQNameHasChildren, childrenIndex) {
|
|
2897
|
+
var _a;
|
|
2891
2898
|
const info = {
|
|
2892
2899
|
conceptId: concept.id,
|
|
2893
2900
|
qname: concept.name,
|
|
@@ -2898,8 +2905,11 @@ function indexConceptTree(concept, conceptByQName, conceptById, conceptIdByQName
|
|
|
2898
2905
|
(conceptByQName.get(concept.name) ?? conceptByQName.set(concept.name, []).get(concept.name)).push(info);
|
|
2899
2906
|
const children = concept.children || [];
|
|
2900
2907
|
const hasOwnChildren = children.length > 0;
|
|
2908
|
+
const existingConceptId = conceptIdByQName.get(concept.name);
|
|
2901
2909
|
const alreadyHasChildren = conceptIdByQNameHasChildren.get(concept.name) === true;
|
|
2902
|
-
|
|
2910
|
+
const existingEffectivePeriodRole = existingConceptId ? (_a = conceptById.get(existingConceptId)) == null ? void 0 : _a.effectivePeriodRole : void 0;
|
|
2911
|
+
const shouldPreferPeriodEnd = hasOwnChildren && alreadyHasChildren && concept.effectivePeriodRole === "periodEndLabel" && existingEffectivePeriodRole === "periodStartLabel";
|
|
2912
|
+
if (!conceptIdByQName.has(concept.name) || hasOwnChildren && !alreadyHasChildren || shouldPreferPeriodEnd) {
|
|
2903
2913
|
conceptIdByQName.set(concept.name, concept.id);
|
|
2904
2914
|
conceptIdByQNameHasChildren.set(concept.name, hasOwnChildren);
|
|
2905
2915
|
}
|
|
@@ -3354,6 +3364,42 @@ function uncoveredExplicitDimensionAxisIds(variable, ctx) {
|
|
|
3354
3364
|
}
|
|
3355
3365
|
return axisIds;
|
|
3356
3366
|
}
|
|
3367
|
+
function coveredExplicitDimensionAxisIds(variable, ctx) {
|
|
3368
|
+
const axisIds = /* @__PURE__ */ new Set();
|
|
3369
|
+
for (const filter2 of variable.filters) {
|
|
3370
|
+
if (filter2.type !== "EXPLICIT_DIMENSION" || !filter2.cover)
|
|
3371
|
+
continue;
|
|
3372
|
+
const axisId = ctx.dimensionQNameToId.get(filter2.attributes["dimension.qname"] ?? "");
|
|
3373
|
+
if (axisId)
|
|
3374
|
+
axisIds.add(axisId);
|
|
3375
|
+
}
|
|
3376
|
+
return axisIds;
|
|
3377
|
+
}
|
|
3378
|
+
function axisIdsOnCandidates(candidates, ctx) {
|
|
3379
|
+
const axisIds = /* @__PURE__ */ new Set();
|
|
3380
|
+
candidates.forEach((candidate) => {
|
|
3381
|
+
var _a;
|
|
3382
|
+
const dimensionData = (_a = getColumn(ctx, candidate)) == null ? void 0 : _a.dimensionData;
|
|
3383
|
+
if (!dimensionData)
|
|
3384
|
+
return;
|
|
3385
|
+
if (dimensionData.axisId)
|
|
3386
|
+
axisIds.add(dimensionData.axisId);
|
|
3387
|
+
(dimensionData.combinations || []).forEach((combo) => {
|
|
3388
|
+
if (combo.axisId)
|
|
3389
|
+
axisIds.add(combo.axisId);
|
|
3390
|
+
});
|
|
3391
|
+
});
|
|
3392
|
+
return axisIds;
|
|
3393
|
+
}
|
|
3394
|
+
function impliedUncoveredAxisIds(variable, candidates, ctx) {
|
|
3395
|
+
const axisIds = uncoveredExplicitDimensionAxisIds(variable, ctx);
|
|
3396
|
+
const covered = coveredExplicitDimensionAxisIds(variable, ctx);
|
|
3397
|
+
axisIdsOnCandidates(candidates, ctx).forEach((axisId) => {
|
|
3398
|
+
if (!covered.has(axisId))
|
|
3399
|
+
axisIds.add(axisId);
|
|
3400
|
+
});
|
|
3401
|
+
return axisIds;
|
|
3402
|
+
}
|
|
3357
3403
|
function candidateMemberIdForAxis(ctx, candidate, axisId) {
|
|
3358
3404
|
var _a;
|
|
3359
3405
|
const column2 = getColumn(ctx, candidate);
|
|
@@ -3363,21 +3409,39 @@ function candidateMemberIdForAxis(ctx, candidate, axisId) {
|
|
|
3363
3409
|
return column2.dimensionData.memberId;
|
|
3364
3410
|
return (_a = (column2.dimensionData.combinations || []).find((combo) => combo.axisId === axisId)) == null ? void 0 : _a.memberId;
|
|
3365
3411
|
}
|
|
3412
|
+
function coveredMemberIdForAxis(variable, axisId, ctx) {
|
|
3413
|
+
for (const filter2 of variable.filters) {
|
|
3414
|
+
if (filter2.type !== "EXPLICIT_DIMENSION" || !filter2.cover || filter2.complement)
|
|
3415
|
+
continue;
|
|
3416
|
+
if (filter2.attributes["member.axis"])
|
|
3417
|
+
continue;
|
|
3418
|
+
if (ctx.dimensionQNameToId.get(filter2.attributes["dimension.qname"] ?? "") !== axisId)
|
|
3419
|
+
continue;
|
|
3420
|
+
const memberId = ctx.memberQNameToId.get(filter2.attributes["member.qname"] ?? "");
|
|
3421
|
+
if (memberId)
|
|
3422
|
+
return memberId;
|
|
3423
|
+
}
|
|
3424
|
+
return void 0;
|
|
3425
|
+
}
|
|
3366
3426
|
function findUncoveredAxisAnchor(variables, axisId, candidatesByName, ctx) {
|
|
3367
3427
|
for (const variable of variables) {
|
|
3368
3428
|
if (variable.bindAsSequence)
|
|
3369
3429
|
continue;
|
|
3370
|
-
if (!uncoveredExplicitDimensionAxisIds(variable, ctx).has(axisId))
|
|
3371
|
-
continue;
|
|
3372
3430
|
const candidates = candidatesByName.get(variable.name) || [];
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3431
|
+
if (impliedUncoveredAxisIds(variable, candidates, ctx).has(axisId)) {
|
|
3432
|
+
const memberIds = new Set(
|
|
3433
|
+
candidates.map((candidate) => candidateMemberIdForAxis(ctx, candidate, axisId)).filter((id) => id !== void 0)
|
|
3434
|
+
);
|
|
3435
|
+
if (memberIds.size === 1)
|
|
3436
|
+
return { memberId: [...memberIds][0], variableName: variable.name, ambiguous: false };
|
|
3437
|
+
const rootMembers = [...memberIds].filter((id) => !ctx.memberIdsWithParent.has(id));
|
|
3438
|
+
if (rootMembers.length === 1)
|
|
3439
|
+
return { memberId: rootMembers[0], variableName: variable.name, ambiguous: true };
|
|
3440
|
+
continue;
|
|
3441
|
+
}
|
|
3442
|
+
const pinnedMemberId = coveredMemberIdForAxis(variable, axisId, ctx);
|
|
3443
|
+
if (pinnedMemberId)
|
|
3444
|
+
return { memberId: pinnedMemberId, variableName: variable.name, ambiguous: false };
|
|
3381
3445
|
}
|
|
3382
3446
|
return void 0;
|
|
3383
3447
|
}
|
|
@@ -3386,13 +3450,15 @@ function computeAssertionNarrowedCandidatesByName(variables, ctx, implicitFilter
|
|
|
3386
3450
|
variables.forEach((variable) => candidatesByName.set(variable.name, resolveNarrowedCandidates(variable, ctx, roleURI)));
|
|
3387
3451
|
if (implicitFiltering) {
|
|
3388
3452
|
const axisIds = /* @__PURE__ */ new Set();
|
|
3389
|
-
variables.forEach(
|
|
3453
|
+
variables.forEach(
|
|
3454
|
+
(variable) => impliedUncoveredAxisIds(variable, candidatesByName.get(variable.name) || [], ctx).forEach((axisId) => axisIds.add(axisId))
|
|
3455
|
+
);
|
|
3390
3456
|
axisIds.forEach((axisId) => {
|
|
3391
3457
|
const anchor = findUncoveredAxisAnchor(variables, axisId, candidatesByName, ctx);
|
|
3392
3458
|
if (!anchor)
|
|
3393
3459
|
return;
|
|
3394
3460
|
variables.forEach((variable) => {
|
|
3395
|
-
const isNarrowableSequence = variable.bindAsSequence &&
|
|
3461
|
+
const isNarrowableSequence = variable.bindAsSequence && impliedUncoveredAxisIds(variable, candidatesByName.get(variable.name) || [], ctx).has(axisId);
|
|
3396
3462
|
const isAmbiguousAnchorItself = anchor.ambiguous && variable.name === anchor.variableName;
|
|
3397
3463
|
if (!isNarrowableSequence && !isAmbiguousAnchorItself)
|
|
3398
3464
|
return;
|
|
@@ -5005,13 +5071,22 @@ let JupiterFormField = class extends LitElement {
|
|
|
5005
5071
|
this._availableUnits = [];
|
|
5006
5072
|
this._numericDraftValue = null;
|
|
5007
5073
|
this._focused = false;
|
|
5074
|
+
this._boundHandlePeriodPopupKeydown = this._handlePeriodPopupKeydown.bind(this);
|
|
5075
|
+
}
|
|
5076
|
+
connectedCallback() {
|
|
5077
|
+
super.connectedCallback();
|
|
5078
|
+
window.addEventListener("keydown", this._boundHandlePeriodPopupKeydown);
|
|
5079
|
+
}
|
|
5080
|
+
disconnectedCallback() {
|
|
5081
|
+
window.removeEventListener("keydown", this._boundHandlePeriodPopupKeydown);
|
|
5082
|
+
super.disconnectedCallback();
|
|
5008
5083
|
}
|
|
5009
5084
|
willUpdate(changedProperties) {
|
|
5010
5085
|
var _a;
|
|
5011
5086
|
if (changedProperties.has("value") || changedProperties.has("field")) {
|
|
5012
5087
|
this._validateField();
|
|
5013
5088
|
}
|
|
5014
|
-
if (changedProperties.has("unit") && this.unit) {
|
|
5089
|
+
if (changedProperties.has("unit") && this.unit && this.hasUpdated) {
|
|
5015
5090
|
console.log(`🏷️ [FormField willUpdate] Unit property changed to: ${this.unit}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
|
|
5016
5091
|
this.dispatchEvent(new CustomEvent("unit-change", {
|
|
5017
5092
|
detail: {
|
|
@@ -5046,6 +5121,14 @@ let JupiterFormField = class extends LitElement {
|
|
|
5046
5121
|
_isRoundingLevelConcept() {
|
|
5047
5122
|
return !!this.conceptId && this.conceptId.includes("DocumentIntendedRoundingLevel");
|
|
5048
5123
|
}
|
|
5124
|
+
// jenv-bw2-i:BalanceSheetBeforeAfterAppropriationResults records the profit-appropriation
|
|
5125
|
+
// decision for the current balance sheet only — the NL taxonomy's validation rules warn when
|
|
5126
|
+
// it's also reported for the comparative year, so the prior-year column doesn't accept it.
|
|
5127
|
+
// `columnId` carries the `_prev` marker `generatePreviousYearColumns` (xbrl-form-builder.ts)
|
|
5128
|
+
// gives every comparative-year column, whether dimensioned (`${id}_prev`) or not (`duration_prev_N`).
|
|
5129
|
+
_isDisabledForPriorYear() {
|
|
5130
|
+
return !!this.conceptId && !!this.columnId && this.conceptId.includes("BalanceSheetBeforeAfterAppropriationResults") && this.columnId.includes("_prev");
|
|
5131
|
+
}
|
|
5049
5132
|
/**
|
|
5050
5133
|
* JDF-110: lock icon (SVG, not emoji) shown on a masterData-prefilled or rounding-level-locked
|
|
5051
5134
|
* cell, so a locked value reads as "filled and protected" rather than empty placeholder text.
|
|
@@ -5689,7 +5772,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
5689
5772
|
const isMonetary = this._isMonetaryType();
|
|
5690
5773
|
return html`<span class="readonly-value ${isEmpty ? "empty" : ""} ${isMonetary ? "monetary" : ""}">${isEmpty ? "—" : displayValue}</span>`;
|
|
5691
5774
|
}
|
|
5692
|
-
_renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false) {
|
|
5775
|
+
_renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false, disabledTooltip) {
|
|
5693
5776
|
if (this.mode === "readonly") {
|
|
5694
5777
|
return this._renderReadonlyValue(effectiveValue);
|
|
5695
5778
|
}
|
|
@@ -5715,6 +5798,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
5715
5798
|
class="${cssClass}"
|
|
5716
5799
|
.value="${effectiveValue ?? ""}"
|
|
5717
5800
|
?disabled="${effectiveDisabled || this.field.disabled}"
|
|
5801
|
+
title="${disabledTooltip || ""}"
|
|
5718
5802
|
@change="${this._handleInput}"
|
|
5719
5803
|
@focus="${this._handleFocus}"
|
|
5720
5804
|
@blur="${this._handleBlur}"
|
|
@@ -5921,18 +6005,14 @@ let JupiterFormField = class extends LitElement {
|
|
|
5921
6005
|
}
|
|
5922
6006
|
return html``;
|
|
5923
6007
|
}
|
|
5924
|
-
// JDF-118: the period popup is a plain Lit overlay, not a native <dialog>, so it doesn't get
|
|
5925
|
-
// Escape-to-close for free the way the info/text dialogs do. Keydown on the overlay catches it
|
|
5926
|
-
// as it bubbles up from whichever control inside the popup has focus.
|
|
5927
6008
|
_handlePeriodPopupKeydown(e2) {
|
|
5928
|
-
if (e2.key === "Escape") {
|
|
5929
|
-
e2.stopPropagation();
|
|
6009
|
+
if (this._showPeriodPopup && e2.key === "Escape") {
|
|
5930
6010
|
this._closePeriodPopup();
|
|
5931
6011
|
}
|
|
5932
6012
|
}
|
|
5933
6013
|
_renderPeriodPopup() {
|
|
5934
6014
|
return html`
|
|
5935
|
-
<div class="period-popup-overlay" @click="${this._handlePopupOverlayClick}"
|
|
6015
|
+
<div class="period-popup-overlay" @click="${this._handlePopupOverlayClick}">
|
|
5936
6016
|
<div class="period-popup" @click="${(e2) => e2.stopPropagation()}">
|
|
5937
6017
|
<div class="period-popup-header">
|
|
5938
6018
|
<div class="period-popup-title">${I18n.t("field.editPeriod")}</div>
|
|
@@ -6066,6 +6146,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
6066
6146
|
const baseConceptId = this._extractBaseConceptId(this.conceptId);
|
|
6067
6147
|
const isPredefinedValue = this.mode !== "admin" && this.masterData && baseConceptId in this.masterData;
|
|
6068
6148
|
const isRoundingLevelLocked = this._isRoundingLevelConcept();
|
|
6149
|
+
const isDisabledForPriorYear = this._isDisabledForPriorYear();
|
|
6069
6150
|
let factValue = null;
|
|
6070
6151
|
if (this.facts && this.facts.length > 0 && !isPredefinedValue) {
|
|
6071
6152
|
const cellContext = {
|
|
@@ -6119,8 +6200,8 @@ let JupiterFormField = class extends LitElement {
|
|
|
6119
6200
|
}
|
|
6120
6201
|
}
|
|
6121
6202
|
const hasUserValue = this.value !== null && this.value !== void 0;
|
|
6122
|
-
const effectiveValue = isPredefinedValue ? this.masterData[baseConceptId] : hasUserValue ? this.value : factValue;
|
|
6123
|
-
const effectiveDisabled = isPredefinedValue || isRoundingLevelLocked || this.disabled || this.mode === "readonly";
|
|
6203
|
+
const effectiveValue = isDisabledForPriorYear ? null : isPredefinedValue ? this.masterData[baseConceptId] : hasUserValue ? this.value : factValue;
|
|
6204
|
+
const effectiveDisabled = isPredefinedValue || isRoundingLevelLocked || isDisabledForPriorYear || this.disabled || this.mode === "readonly";
|
|
6124
6205
|
const isLocked = (isPredefinedValue || isRoundingLevelLocked) && this.mode !== "readonly";
|
|
6125
6206
|
const typeConfigForLock = getInputTypeForConceptType(this.conceptType, this.datatypes);
|
|
6126
6207
|
const effectiveFieldTypeForLock = typeConfigForLock.fieldType || this.field.type || "text";
|
|
@@ -6134,7 +6215,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
6134
6215
|
` : ""}
|
|
6135
6216
|
|
|
6136
6217
|
<div class="field-wrapper">
|
|
6137
|
-
${this._renderInput(effectiveValue, effectiveDisabled, isLocked)}
|
|
6218
|
+
${this._renderInput(effectiveValue, effectiveDisabled, isLocked, isDisabledForPriorYear ? I18n.t("field.notApplicablePriorYear") : void 0)}
|
|
6138
6219
|
|
|
6139
6220
|
${isLocked && !isTextareaField || hasPeriodControl && this.mode !== "readonly" && !isRoundingLevelLocked ? html`
|
|
6140
6221
|
<div class="field-trailing-icons">
|
|
@@ -7061,6 +7142,19 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7061
7142
|
`;
|
|
7062
7143
|
document.head.appendChild(style);
|
|
7063
7144
|
}
|
|
7145
|
+
/**
|
|
7146
|
+
* Dispatches the clicked cell's duplicate-fact mismatch up to `jupiter-dynamic-form`, which owns
|
|
7147
|
+
* the click-to-navigate machinery (role/column reveal, side-panel switch, highlight) already
|
|
7148
|
+
* built for the Validate pre-flight popup — reused here to show this one mismatch's facts.
|
|
7149
|
+
*/
|
|
7150
|
+
_handleDuplicateFactWarningBadgeClick(e2, mismatch) {
|
|
7151
|
+
e2.stopPropagation();
|
|
7152
|
+
this.dispatchEvent(new CustomEvent("duplicate-fact-warning-click", {
|
|
7153
|
+
detail: { mismatch },
|
|
7154
|
+
bubbles: true,
|
|
7155
|
+
composed: true
|
|
7156
|
+
}));
|
|
7157
|
+
}
|
|
7064
7158
|
_openCalculationWarningDialog(e2, mismatch) {
|
|
7065
7159
|
var _a;
|
|
7066
7160
|
e2.stopPropagation();
|
|
@@ -7135,7 +7229,7 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7135
7229
|
|
|
7136
7230
|
<!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
|
|
7137
7231
|
${this.columns.map((column2) => {
|
|
7138
|
-
var _a, _b, _c, _d, _e;
|
|
7232
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7139
7233
|
if (column2.hidden) {
|
|
7140
7234
|
return html`<td class="field-cell hidden-column"></td>`;
|
|
7141
7235
|
}
|
|
@@ -7144,8 +7238,9 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7144
7238
|
const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
|
|
7145
7239
|
const storedDecimals = (_d = (_c = this.decimalsData) == null ? void 0 : _c[this.concept.id]) == null ? void 0 : _d[column2.id];
|
|
7146
7240
|
const calcMismatch = this.mode !== "readonly" ? (_e = this.calculationMismatches) == null ? void 0 : _e.get(`${this.concept.id}__${column2.id}`) : void 0;
|
|
7241
|
+
const dupWarning = this.mode !== "readonly" ? (_f = this.duplicateFactWarnings) == null ? void 0 : _f.get(`${this.concept.id}__${column2.id}`) : void 0;
|
|
7147
7242
|
return html`
|
|
7148
|
-
<td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${isTotal ? "total-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${calcMismatch ? "calc-warning" : ""} ${this.rowFocused ? "row-focused" : ""}">
|
|
7243
|
+
<td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${isTotal ? "total-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${calcMismatch ? "calc-warning" : ""} ${dupWarning ? "duplicate-fact-warning" : ""} ${this.rowFocused ? "row-focused" : ""}">
|
|
7149
7244
|
${calcMismatch ? html`
|
|
7150
7245
|
<button
|
|
7151
7246
|
class="calc-warning-badge"
|
|
@@ -7155,6 +7250,15 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7155
7250
|
@click="${(e2) => this._openCalculationWarningDialog(e2, calcMismatch)}"
|
|
7156
7251
|
>!</button>
|
|
7157
7252
|
` : ""}
|
|
7253
|
+
${dupWarning ? html`
|
|
7254
|
+
<button
|
|
7255
|
+
class="duplicate-warning-badge"
|
|
7256
|
+
type="button"
|
|
7257
|
+
tabindex="-1"
|
|
7258
|
+
title="${I18n.t("duplicateFactWarning.cellTooltip")}"
|
|
7259
|
+
@click="${(e2) => this._handleDuplicateFactWarningBadgeClick(e2, dupWarning)}"
|
|
7260
|
+
>≠</button>
|
|
7261
|
+
` : ""}
|
|
7158
7262
|
${shouldShowField ? html`
|
|
7159
7263
|
<jupiter-form-field
|
|
7160
7264
|
.field="${field2}"
|
|
@@ -7407,6 +7511,38 @@ JupiterConceptTree.styles = css`
|
|
|
7407
7511
|
background: #e65100;
|
|
7408
7512
|
}
|
|
7409
7513
|
|
|
7514
|
+
/* Live counterpart to the Validate pre-flight's duplicate-fact-value check — deliberately a
|
|
7515
|
+
distinct color from calc-warning's amber so the two non-blocking warnings never look like
|
|
7516
|
+
the same issue when both land on the same cell. */
|
|
7517
|
+
.field-cell.duplicate-fact-warning {
|
|
7518
|
+
box-shadow: inset 0 0 0 2px var(--jupiter-duplicate-warning-color, #8e24aa);
|
|
7519
|
+
}
|
|
7520
|
+
|
|
7521
|
+
.duplicate-warning-badge {
|
|
7522
|
+
position: absolute;
|
|
7523
|
+
top: 2px;
|
|
7524
|
+
left: 2px;
|
|
7525
|
+
width: 16px;
|
|
7526
|
+
height: 16px;
|
|
7527
|
+
border-radius: 50%;
|
|
7528
|
+
border: none;
|
|
7529
|
+
background: var(--jupiter-duplicate-warning-color, #8e24aa);
|
|
7530
|
+
color: #fff;
|
|
7531
|
+
font-size: 10px;
|
|
7532
|
+
font-weight: 700;
|
|
7533
|
+
line-height: 1;
|
|
7534
|
+
padding: 0;
|
|
7535
|
+
display: flex;
|
|
7536
|
+
align-items: center;
|
|
7537
|
+
justify-content: center;
|
|
7538
|
+
cursor: pointer;
|
|
7539
|
+
z-index: 3;
|
|
7540
|
+
}
|
|
7541
|
+
|
|
7542
|
+
.duplicate-warning-badge:hover {
|
|
7543
|
+
background: #6a1b9a;
|
|
7544
|
+
}
|
|
7545
|
+
|
|
7410
7546
|
/* Row-level highlight while a field in this row has focus. Applied to every
|
|
7411
7547
|
cell so the row stays identifiable even after the user scrolls the table
|
|
7412
7548
|
horizontally away from the focused input. */
|
|
@@ -7560,6 +7696,9 @@ __decorateClass$7([
|
|
|
7560
7696
|
__decorateClass$7([
|
|
7561
7697
|
n2({ type: Object })
|
|
7562
7698
|
], JupiterConceptTree.prototype, "calculationMismatches", 2);
|
|
7699
|
+
__decorateClass$7([
|
|
7700
|
+
n2({ type: Object })
|
|
7701
|
+
], JupiterConceptTree.prototype, "duplicateFactWarnings", 2);
|
|
7563
7702
|
__decorateClass$7([
|
|
7564
7703
|
n2({ type: String })
|
|
7565
7704
|
], JupiterConceptTree.prototype, "language", 2);
|
|
@@ -7597,6 +7736,7 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7597
7736
|
this._selectedType = "duration";
|
|
7598
7737
|
this._selectedDimensions = /* @__PURE__ */ new Map();
|
|
7599
7738
|
this._typedValueErrors = {};
|
|
7739
|
+
this._boundHandleKeydown = this._handleKeydown.bind(this);
|
|
7600
7740
|
}
|
|
7601
7741
|
updated(changedProperties) {
|
|
7602
7742
|
if (changedProperties.has("open") && this.open) {
|
|
@@ -7608,6 +7748,11 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7608
7748
|
connectedCallback() {
|
|
7609
7749
|
super.connectedCallback();
|
|
7610
7750
|
this._resetForm();
|
|
7751
|
+
window.addEventListener("keydown", this._boundHandleKeydown);
|
|
7752
|
+
}
|
|
7753
|
+
disconnectedCallback() {
|
|
7754
|
+
window.removeEventListener("keydown", this._boundHandleKeydown);
|
|
7755
|
+
super.disconnectedCallback();
|
|
7611
7756
|
}
|
|
7612
7757
|
willUpdate(changedProperties) {
|
|
7613
7758
|
super.willUpdate(changedProperties);
|
|
@@ -7615,6 +7760,11 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7615
7760
|
this._resetForm();
|
|
7616
7761
|
}
|
|
7617
7762
|
}
|
|
7763
|
+
_handleKeydown(event) {
|
|
7764
|
+
if (this.open && event.key === "Escape") {
|
|
7765
|
+
this._handleCancel();
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7618
7768
|
_handleCancel() {
|
|
7619
7769
|
this.open = false;
|
|
7620
7770
|
this.dispatchEvent(new CustomEvent("dialog-cancel", { bubbles: true }));
|
|
@@ -9347,6 +9497,7 @@ let JupiterFormSection = class extends LitElement {
|
|
|
9347
9497
|
.highlightColumnId="${(_b = this._highlightMap.get(instanceConcept.id)) == null ? void 0 : _b.columnId}"
|
|
9348
9498
|
.rowFocused="${this._focusedConceptId === instanceConcept.id}"
|
|
9349
9499
|
.calculationMismatches="${this._calculationMismatches}"
|
|
9500
|
+
.duplicateFactWarnings="${this.duplicateFactWarnings}"
|
|
9350
9501
|
@field-change="${this._handleFieldChange}"
|
|
9351
9502
|
@field-focus="${this._handleFieldFocusForHighlight}"
|
|
9352
9503
|
@period-change="${this._handlePeriodChange}"
|
|
@@ -9982,6 +10133,9 @@ __decorateClass$5([
|
|
|
9982
10133
|
__decorateClass$5([
|
|
9983
10134
|
n2({ type: Object })
|
|
9984
10135
|
], JupiterFormSection.prototype, "totalManuallyEditedData", 2);
|
|
10136
|
+
__decorateClass$5([
|
|
10137
|
+
n2({ type: Object })
|
|
10138
|
+
], JupiterFormSection.prototype, "duplicateFactWarnings", 2);
|
|
9985
10139
|
__decorateClass$5([
|
|
9986
10140
|
r()
|
|
9987
10141
|
], JupiterFormSection.prototype, "_expanded", 2);
|
|
@@ -10187,6 +10341,7 @@ let JupiterAdvancedFilter = class extends LitElement {
|
|
|
10187
10341
|
return;
|
|
10188
10342
|
}
|
|
10189
10343
|
if (e2.key === "Escape") {
|
|
10344
|
+
e2.stopPropagation();
|
|
10190
10345
|
this._showSuggestions = false;
|
|
10191
10346
|
this._activeSuggestionIndex = -1;
|
|
10192
10347
|
return;
|
|
@@ -10501,11 +10656,22 @@ let JupiterFilterRolesDialog = class extends LitElement {
|
|
|
10501
10656
|
this._showFactsOnly = false;
|
|
10502
10657
|
this._conceptSearchText = "";
|
|
10503
10658
|
this._collapsedRoles = /* @__PURE__ */ new Set();
|
|
10659
|
+
this._boundHandleKeydown = this._handleKeydown.bind(this);
|
|
10504
10660
|
}
|
|
10505
10661
|
connectedCallback() {
|
|
10506
10662
|
super.connectedCallback();
|
|
10507
10663
|
this._initializeTempSelection();
|
|
10508
10664
|
this._initializePeriodPreferences();
|
|
10665
|
+
window.addEventListener("keydown", this._boundHandleKeydown);
|
|
10666
|
+
}
|
|
10667
|
+
disconnectedCallback() {
|
|
10668
|
+
window.removeEventListener("keydown", this._boundHandleKeydown);
|
|
10669
|
+
super.disconnectedCallback();
|
|
10670
|
+
}
|
|
10671
|
+
_handleKeydown(event) {
|
|
10672
|
+
if (this.open && event.key === "Escape") {
|
|
10673
|
+
this._handleCancel();
|
|
10674
|
+
}
|
|
10509
10675
|
}
|
|
10510
10676
|
updated(changedProperties) {
|
|
10511
10677
|
if (changedProperties.has("selectedRoleIds") || changedProperties.has("open")) {
|
|
@@ -12939,6 +13105,8 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
12939
13105
|
this._showValidateWarningPopup = false;
|
|
12940
13106
|
this._typedDimensionWarningFacts = [];
|
|
12941
13107
|
this._duplicateFactMismatches = [];
|
|
13108
|
+
this._duplicateFactWarnings = /* @__PURE__ */ new Map();
|
|
13109
|
+
this._duplicateWarningPopupMode = "validate";
|
|
12942
13110
|
this._submitDisabled = false;
|
|
12943
13111
|
this._allSections = [];
|
|
12944
13112
|
this._selectedRoleIds = [];
|
|
@@ -12947,6 +13115,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
12947
13115
|
this._showFactsOnly = false;
|
|
12948
13116
|
this._conceptSearchText = "";
|
|
12949
13117
|
this._lastFocusedFieldIdentity = null;
|
|
13118
|
+
this._dimensionColumnDriftDiagnostics = [];
|
|
12950
13119
|
this._periodPreferences = {};
|
|
12951
13120
|
this._activeSidePanelRoleId = null;
|
|
12952
13121
|
this._sidePanelSearchQuery = "";
|
|
@@ -12996,6 +13165,15 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
12996
13165
|
this.addEventListener("calculation-mismatch-changed", (e2) => {
|
|
12997
13166
|
this._handleCalculationMismatchChanged(e2);
|
|
12998
13167
|
});
|
|
13168
|
+
this.addEventListener("duplicate-fact-warning-click", (e2) => {
|
|
13169
|
+
const { mismatch } = e2.detail || {};
|
|
13170
|
+
if (!mismatch)
|
|
13171
|
+
return;
|
|
13172
|
+
this._typedDimensionWarningFacts = [];
|
|
13173
|
+
this._duplicateFactMismatches = [mismatch];
|
|
13174
|
+
this._duplicateWarningPopupMode = "cellInfo";
|
|
13175
|
+
this._showValidateWarningPopup = true;
|
|
13176
|
+
});
|
|
12999
13177
|
this.addEventListener("total-manually-edited", (e2) => {
|
|
13000
13178
|
const { conceptId, columnId } = e2.detail;
|
|
13001
13179
|
const updated = { ...this._totalManuallyEditedData };
|
|
@@ -13209,6 +13387,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13209
13387
|
if ((_a = this.xbrlInput) == null ? void 0 : _a.initialData) {
|
|
13210
13388
|
this._formData = { ...this._formData, ...this.xbrlInput.initialData };
|
|
13211
13389
|
}
|
|
13390
|
+
this._formData = this._stripPriorYearExcludedFacts(this._formData);
|
|
13212
13391
|
this._initializeGlobalDecimalsFromRoundingData();
|
|
13213
13392
|
this._extractTypedMembersFromFacts();
|
|
13214
13393
|
if (!this._skipDraftLoading) {
|
|
@@ -13889,8 +14068,15 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13889
14068
|
// which reads as "still cut off" when its row height isn't an exact multiple of the container.
|
|
13890
14069
|
_scrollActiveRoleIntoView() {
|
|
13891
14070
|
var _a;
|
|
13892
|
-
const
|
|
13893
|
-
activeItem == null ? void 0 :
|
|
14071
|
+
const rolesList = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".side-panel-roles-list");
|
|
14072
|
+
const activeItem = rolesList == null ? void 0 : rolesList.querySelector(".side-panel-role-item.active");
|
|
14073
|
+
if (!rolesList || !activeItem)
|
|
14074
|
+
return;
|
|
14075
|
+
const listRect = rolesList.getBoundingClientRect();
|
|
14076
|
+
const itemRect = activeItem.getBoundingClientRect();
|
|
14077
|
+
const itemCenter = itemRect.top + itemRect.height / 2;
|
|
14078
|
+
const listCenter = listRect.top + listRect.height / 2;
|
|
14079
|
+
rolesList.scrollTop += itemCenter - listCenter;
|
|
13894
14080
|
}
|
|
13895
14081
|
// Re-locates the fact input identified by _lastFocusedFieldIdentity after a rebuild and restores
|
|
13896
14082
|
// focus to it, mirroring the shadow-DOM traversal scrollToConcept/_handleErrorFieldClick use.
|
|
@@ -14115,6 +14301,29 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14115
14301
|
this._calculationWarnings = next;
|
|
14116
14302
|
this._validateForm();
|
|
14117
14303
|
}
|
|
14304
|
+
// jenv-bw2-i:BalanceSheetBeforeAfterAppropriationResults isn't applicable to the previous-year
|
|
14305
|
+
// column — mirrors `_isDisabledForPriorYear` in form-field.ts (which disables the input itself);
|
|
14306
|
+
// this is the `_formData`/submission-side counterpart so a value already sitting in a draft,
|
|
14307
|
+
// `initialData`, or preserved (hidden-role) data from before that UI restriction existed gets
|
|
14308
|
+
// scrubbed on load and can never resurface in a later draft save or submission.
|
|
14309
|
+
_isPriorYearExcludedFact(conceptId, columnId) {
|
|
14310
|
+
return !!conceptId && !!columnId && conceptId.includes("BalanceSheetBeforeAfterAppropriationResults") && columnId.includes("_prev");
|
|
14311
|
+
}
|
|
14312
|
+
/** Strips any prior-year-excluded concept/column entries from a `FormData` map (immutable). */
|
|
14313
|
+
_stripPriorYearExcludedFacts(data) {
|
|
14314
|
+
const cleaned = {};
|
|
14315
|
+
Object.keys(data).forEach((conceptId) => {
|
|
14316
|
+
const columns = data[conceptId] || {};
|
|
14317
|
+
const keptColumns = {};
|
|
14318
|
+
Object.keys(columns).forEach((columnId) => {
|
|
14319
|
+
if (!this._isPriorYearExcludedFact(conceptId, columnId)) {
|
|
14320
|
+
keptColumns[columnId] = columns[columnId];
|
|
14321
|
+
}
|
|
14322
|
+
});
|
|
14323
|
+
cleaned[conceptId] = keptColumns;
|
|
14324
|
+
});
|
|
14325
|
+
return cleaned;
|
|
14326
|
+
}
|
|
14118
14327
|
/**
|
|
14119
14328
|
* JDF-058: single source of truth for writing a value into `_formData` with the immutable-update
|
|
14120
14329
|
* pattern Lit reactivity needs — shared by a real user keystroke (`_handleFieldChange`) and the
|
|
@@ -14122,6 +14331,10 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14122
14331
|
* duplicated. Returns the value that was previously stored, for event `oldValue` fields.
|
|
14123
14332
|
*/
|
|
14124
14333
|
_writeFormDataValue(conceptId, columnId, value) {
|
|
14334
|
+
var _a;
|
|
14335
|
+
if (this._isPriorYearExcludedFact(conceptId, columnId)) {
|
|
14336
|
+
return (_a = this._formData[conceptId]) == null ? void 0 : _a[columnId];
|
|
14337
|
+
}
|
|
14125
14338
|
const updatedFormData = { ...this._formData };
|
|
14126
14339
|
if (!updatedFormData[conceptId]) {
|
|
14127
14340
|
updatedFormData[conceptId] = {};
|
|
@@ -14174,13 +14387,17 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14174
14387
|
this.requestUpdate();
|
|
14175
14388
|
}
|
|
14176
14389
|
_handleUnitChange(event) {
|
|
14390
|
+
var _a;
|
|
14177
14391
|
console.log(`🏷️ [DynamicForm] _handleUnitChange called with event:`, event);
|
|
14178
14392
|
console.log(`🏷️ [DynamicForm] Event detail:`, event.detail);
|
|
14179
14393
|
const { conceptId, columnId, unit } = event.detail;
|
|
14180
14394
|
console.log(`🏷️ Unit change received: conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
|
|
14395
|
+
const isUnchanged = ((_a = this._unitData[conceptId]) == null ? void 0 : _a[columnId]) === unit;
|
|
14181
14396
|
this._storeUnit(conceptId, columnId, unit);
|
|
14182
|
-
|
|
14183
|
-
|
|
14397
|
+
if (!isUnchanged) {
|
|
14398
|
+
this._dirty = true;
|
|
14399
|
+
this.hasUnsavedChanges = true;
|
|
14400
|
+
}
|
|
14184
14401
|
this.requestUpdate();
|
|
14185
14402
|
}
|
|
14186
14403
|
_storeUnit(conceptId, columnId, unit) {
|
|
@@ -14488,6 +14705,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14488
14705
|
console.log(`🟧 [DynamicForm] Removed ${beforeLength - this._xbrlFormErrors.length} errors`);
|
|
14489
14706
|
}
|
|
14490
14707
|
console.log(`🔍 [Validation] Total errors: ${this._xbrlFormErrors.length}`, this._xbrlFormErrors);
|
|
14708
|
+
this._updateDuplicateFactWarnings(conceptId, columnId);
|
|
14491
14709
|
}
|
|
14492
14710
|
_getSectionTitle(sectionId) {
|
|
14493
14711
|
console.log(`🔍 [_getSectionTitle] Looking for sectionId: "${sectionId}"`);
|
|
@@ -15325,6 +15543,33 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15325
15543
|
}
|
|
15326
15544
|
return String(value);
|
|
15327
15545
|
}
|
|
15546
|
+
/**
|
|
15547
|
+
* Live, blur-triggered counterpart to `_findDuplicateFactMismatches`. Re-runs the full duplicate
|
|
15548
|
+
* check (cheap — the same pass Validate already does) and rebuilds `_duplicateFactWarnings` from
|
|
15549
|
+
* scratch, so a resolved conflict clears itself and a newly created one appears without any
|
|
15550
|
+
* extra bookkeeping. Every fact in every current mismatch group gets flagged, not just the field
|
|
15551
|
+
* that was just blurred, so the user sees all the cells involved in a conflict — including one
|
|
15552
|
+
* they filled in earlier — the moment either side changes, rather than having to revisit them
|
|
15553
|
+
* one by one after Validate. Skipped when the blurred cell has no value and wasn't already
|
|
15554
|
+
* flagged, since a blank cell can never be part of a mismatch (`_collectDuplicateFactCandidates`
|
|
15555
|
+
* ignores blanks) — this keeps tabbing through empty cells cheap.
|
|
15556
|
+
*/
|
|
15557
|
+
_updateDuplicateFactWarnings(conceptId, columnId) {
|
|
15558
|
+
var _a;
|
|
15559
|
+
const value = (_a = this._formData[conceptId]) == null ? void 0 : _a[columnId];
|
|
15560
|
+
const hasMeaningfulValue = value !== void 0 && value !== null && String(value).trim() !== "";
|
|
15561
|
+
const key = `${conceptId}__${columnId}`;
|
|
15562
|
+
if (!hasMeaningfulValue && !this._duplicateFactWarnings.has(key))
|
|
15563
|
+
return;
|
|
15564
|
+
const mismatches = this._findDuplicateFactMismatches();
|
|
15565
|
+
const updated = /* @__PURE__ */ new Map();
|
|
15566
|
+
for (const mismatch of mismatches) {
|
|
15567
|
+
for (const fact of mismatch.facts) {
|
|
15568
|
+
updated.set(`${fact.conceptId}__${fact.columnId}`, mismatch);
|
|
15569
|
+
}
|
|
15570
|
+
}
|
|
15571
|
+
this._duplicateFactWarnings = updated;
|
|
15572
|
+
}
|
|
15328
15573
|
/** Popup header for the Validate pre-flight warning: specific when only one check found something, generic when both did. */
|
|
15329
15574
|
_validateWarningPopupTitle() {
|
|
15330
15575
|
const hasTypedDimensionWarning = this._typedDimensionWarningFacts.length > 0;
|
|
@@ -15352,6 +15597,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15352
15597
|
console.log("⚠️ [Submit] Duplicate facts with mismatched values:", duplicateFactMismatches);
|
|
15353
15598
|
this._typedDimensionWarningFacts = missingTypedDimensionFacts;
|
|
15354
15599
|
this._duplicateFactMismatches = duplicateFactMismatches;
|
|
15600
|
+
this._duplicateWarningPopupMode = "validate";
|
|
15355
15601
|
this._showValidateWarningPopup = true;
|
|
15356
15602
|
this._submitDisabled = false;
|
|
15357
15603
|
this.requestUpdate();
|
|
@@ -15722,6 +15968,10 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15722
15968
|
return;
|
|
15723
15969
|
}
|
|
15724
15970
|
}
|
|
15971
|
+
if (this._isPriorYearExcludedFact(conceptId, columnId)) {
|
|
15972
|
+
console.log(`⏭️ Dropping legacy draft value for ${conceptId}/${columnId} — not applicable to the previous year`);
|
|
15973
|
+
return;
|
|
15974
|
+
}
|
|
15725
15975
|
const instanceKey = draftInstanceId || conceptId;
|
|
15726
15976
|
const baseConceptId = instanceKey.includes("__repeat_") ? instanceKey.split("__repeat_")[0] : instanceKey;
|
|
15727
15977
|
const actualBaseId = this._findActualConceptId(baseConceptId);
|
|
@@ -15758,6 +16008,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15758
16008
|
});
|
|
15759
16009
|
this._formData = { ...this._formData, ...restoredFormData };
|
|
15760
16010
|
console.log(`🔄 Restored ${Object.keys(restoredFormData).length} concepts with data`);
|
|
16011
|
+
this._diagnoseDimensionColumnDrift(formData);
|
|
15761
16012
|
this._seedLegacyManuallyEditedTotals(restoredFormData);
|
|
15762
16013
|
this._initializeGlobalDecimalsFromRoundingData();
|
|
15763
16014
|
this._periodData = {
|
|
@@ -16254,6 +16505,70 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16254
16505
|
}
|
|
16255
16506
|
return null;
|
|
16256
16507
|
}
|
|
16508
|
+
/**
|
|
16509
|
+
* JDF-133 Phase 0: diagnostics-only. Walks the raw draft `formData` array `_restoreFromDraft`
|
|
16510
|
+
* was given — not `restoredFormData`, which has already dropped each entry's own `dimension`
|
|
16511
|
+
* string by the time this runs — and flags any entry whose saved `dimension` tag disagrees with
|
|
16512
|
+
* what its `columnId` resolves to in the schema just rebuilt for this session. Read-only:
|
|
16513
|
+
* populates `_dimensionColumnDriftDiagnostics` and logs, never writes to `_formData` or any
|
|
16514
|
+
* other state a render or a later save could observe. Builds a one-time conceptId->section index
|
|
16515
|
+
* (`_allSections` can run to hundreds of sections/thousands of concepts) rather than repeating
|
|
16516
|
+
* `_findSectionForConcept`'s linear scan once per fact, so this stays cheap enough to run
|
|
16517
|
+
* unconditionally on every restore without being itself a measurable behavior change.
|
|
16518
|
+
*/
|
|
16519
|
+
_diagnoseDimensionColumnDrift(formData) {
|
|
16520
|
+
var _a, _b, _c;
|
|
16521
|
+
const sectionByConceptId = /* @__PURE__ */ new Map();
|
|
16522
|
+
const indexConcepts = (concepts, section2) => {
|
|
16523
|
+
concepts.forEach((concept) => {
|
|
16524
|
+
var _a2;
|
|
16525
|
+
sectionByConceptId.set(concept.id, section2);
|
|
16526
|
+
if ((_a2 = concept.children) == null ? void 0 : _a2.length)
|
|
16527
|
+
indexConcepts(concept.children, section2);
|
|
16528
|
+
});
|
|
16529
|
+
};
|
|
16530
|
+
this._allSections.forEach((section2) => indexConcepts(section2.concepts, section2));
|
|
16531
|
+
const drifted = [];
|
|
16532
|
+
for (const entry of formData) {
|
|
16533
|
+
const savedDimension = entry == null ? void 0 : entry.dimension;
|
|
16534
|
+
if (!savedDimension || typeof savedDimension !== "string")
|
|
16535
|
+
continue;
|
|
16536
|
+
const section2 = sectionByConceptId.get(entry.conceptId);
|
|
16537
|
+
const column2 = (_a = section2 == null ? void 0 : section2.columns) == null ? void 0 : _a.find((c2) => c2.id === entry.columnId);
|
|
16538
|
+
const currentColumnDimension = (_b = column2 == null ? void 0 : column2.dimensionData) == null ? void 0 : _b.dimensionIdKey;
|
|
16539
|
+
if (!currentColumnDimension)
|
|
16540
|
+
continue;
|
|
16541
|
+
if (!this._dimensionKeysMatch(savedDimension, currentColumnDimension)) {
|
|
16542
|
+
drifted.push({
|
|
16543
|
+
conceptId: entry.conceptId,
|
|
16544
|
+
columnId: entry.columnId,
|
|
16545
|
+
roleURI: ((_c = section2 == null ? void 0 : section2.metadata) == null ? void 0 : _c.roleURI) || (section2 == null ? void 0 : section2.id) || "unknown",
|
|
16546
|
+
value: entry.value,
|
|
16547
|
+
savedDimension,
|
|
16548
|
+
currentColumnDimension
|
|
16549
|
+
});
|
|
16550
|
+
}
|
|
16551
|
+
}
|
|
16552
|
+
this._dimensionColumnDriftDiagnostics = drifted;
|
|
16553
|
+
if (drifted.length > 0) {
|
|
16554
|
+
console.warn(
|
|
16555
|
+
`⚠️ [JDF-133] Detected ${drifted.length} fact(s) whose saved dimension tag no longer matches their column's current dimension — see form._dimensionColumnDriftDiagnostics. Diagnostics-only: nothing was changed or corrected.`
|
|
16556
|
+
);
|
|
16557
|
+
console.table(drifted);
|
|
16558
|
+
}
|
|
16559
|
+
}
|
|
16560
|
+
/** Order-independent comparison of two `axisId|memberId::axisId|memberId...` dimensionIdKey-shaped strings. */
|
|
16561
|
+
_dimensionKeysMatch(a2, b2) {
|
|
16562
|
+
const setA = new Set(a2.split("::").filter(Boolean));
|
|
16563
|
+
const setB = new Set(b2.split("::").filter(Boolean));
|
|
16564
|
+
if (setA.size !== setB.size)
|
|
16565
|
+
return false;
|
|
16566
|
+
for (const item of setA) {
|
|
16567
|
+
if (!setB.has(item))
|
|
16568
|
+
return false;
|
|
16569
|
+
}
|
|
16570
|
+
return true;
|
|
16571
|
+
}
|
|
16257
16572
|
_findSectionForConcept(conceptId) {
|
|
16258
16573
|
for (const section2 of this._allSections) {
|
|
16259
16574
|
const concept = this._findConceptInSection(section2.concepts, conceptId);
|
|
@@ -16265,6 +16580,8 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16265
16580
|
}
|
|
16266
16581
|
_addConceptDataToSubmission(concept, columnId, value, submissionData, section2) {
|
|
16267
16582
|
var _a, _b, _c, _d, _e;
|
|
16583
|
+
if (this._isPriorYearExcludedFact(concept.id, columnId))
|
|
16584
|
+
return;
|
|
16268
16585
|
const field2 = concept.fields.find((f2) => f2.columnId === columnId);
|
|
16269
16586
|
if (!field2)
|
|
16270
16587
|
return;
|
|
@@ -16437,26 +16754,25 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16437
16754
|
}
|
|
16438
16755
|
if (concept.fields && concept.fields.length > 0) {
|
|
16439
16756
|
concept.fields.forEach((field2) => {
|
|
16440
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
16757
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
16758
|
+
if (this._isPriorYearExcludedFact(concept.id, field2.columnId)) {
|
|
16759
|
+
return;
|
|
16760
|
+
}
|
|
16441
16761
|
const conceptData = this._formData[concept.id];
|
|
16442
|
-
let fieldValue = conceptData == null ? void 0 : conceptData[field2.columnId];
|
|
16443
16762
|
const baseConceptId = field2.conceptId || concept.id.split("__").slice(0, -1).join("__") || concept.id;
|
|
16444
|
-
|
|
16763
|
+
const masterDataWins = this.mode !== "admin" && !!this._effectiveMasterData && baseConceptId in this._effectiveMasterData;
|
|
16764
|
+
let fieldValue = masterDataWins ? this._effectiveMasterData[baseConceptId] : conceptData == null ? void 0 : conceptData[field2.columnId];
|
|
16765
|
+
if (masterDataWins) {
|
|
16766
|
+
console.log(` 📦 [Submission] Using masterData for: ${baseConceptId} [${field2.columnId}] = ${JSON.stringify(fieldValue)}`);
|
|
16767
|
+
} else if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._isRoundingLevelConcept(baseConceptId) && !this._hasValidGlobalDecimals()) {
|
|
16445
16768
|
const factValue = this._findFactValueForField(concept, field2, section2);
|
|
16446
16769
|
if (factValue !== void 0 && factValue !== null && factValue !== "") {
|
|
16447
16770
|
fieldValue = factValue;
|
|
16448
16771
|
}
|
|
16449
16772
|
}
|
|
16450
|
-
if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._effectiveMasterData) {
|
|
16451
|
-
const masterValue = (_a = this._effectiveMasterData) == null ? void 0 : _a[baseConceptId];
|
|
16452
|
-
if (masterValue !== void 0 && masterValue !== null && masterValue !== "") {
|
|
16453
|
-
fieldValue = masterValue;
|
|
16454
|
-
console.log(` 📦 [Submission] Using masterData for: ${baseConceptId} [${field2.columnId}] = ${JSON.stringify(fieldValue)}`);
|
|
16455
|
-
}
|
|
16456
|
-
}
|
|
16457
16773
|
if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
|
|
16458
16774
|
const column2 = this._findColumnByIdInSection(field2.columnId, section2);
|
|
16459
|
-
const fieldPeriodData = (
|
|
16775
|
+
const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field2.columnId];
|
|
16460
16776
|
const submissionEntry = {
|
|
16461
16777
|
conceptId: concept.id,
|
|
16462
16778
|
draftInstanceId: concept.id,
|
|
@@ -16478,21 +16794,21 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16478
16794
|
submissionEntry.period.endDate = endDate;
|
|
16479
16795
|
}
|
|
16480
16796
|
console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field2.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
|
|
16481
|
-
const fieldUnit = (
|
|
16797
|
+
const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[field2.columnId];
|
|
16482
16798
|
if (fieldUnit) {
|
|
16483
16799
|
submissionEntry.unit = fieldUnit;
|
|
16484
16800
|
console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${field2.columnId}`);
|
|
16485
16801
|
} else {
|
|
16486
16802
|
console.log(`⚠️ [Submission] No unit found in _unitData for ${concept.id}/${field2.columnId}. _unitData state:`, JSON.stringify(this._unitData, null, 2));
|
|
16487
16803
|
}
|
|
16488
|
-
const isMonetary = (
|
|
16489
|
-
const fieldDecimals = (
|
|
16804
|
+
const isMonetary = (_c = concept.type) == null ? void 0 : _c.toLowerCase().includes("monetary");
|
|
16805
|
+
const fieldDecimals = (_d = this._decimalsData[concept.id]) == null ? void 0 : _d[field2.columnId];
|
|
16490
16806
|
const decimalsValue = fieldDecimals || (this.decimals !== "INF" ? this.decimals : void 0);
|
|
16491
16807
|
if (isMonetary && decimalsValue) {
|
|
16492
16808
|
const parsed = parseFloat(decimalsValue);
|
|
16493
16809
|
submissionEntry.decimals = isNaN(parsed) ? decimalsValue : String(-Math.abs(parsed));
|
|
16494
16810
|
}
|
|
16495
|
-
if ((column2 == null ? void 0 : column2.type) === "dimension" && ((
|
|
16811
|
+
if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_e = column2.dimensionData) == null ? void 0 : _e.dimensionIdKey)) {
|
|
16496
16812
|
submissionEntry.dimension = column2.dimensionData.dimensionIdKey;
|
|
16497
16813
|
console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field2.columnId}):`, column2.dimensionData.dimensionIdKey);
|
|
16498
16814
|
} else {
|
|
@@ -16531,12 +16847,12 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16531
16847
|
console.log(`🔍 [DynamicForm] Column details:`, {
|
|
16532
16848
|
id: column2.id,
|
|
16533
16849
|
type: column2.type,
|
|
16534
|
-
hasTypedMembers: (
|
|
16850
|
+
hasTypedMembers: (_f = column2.dimensionData) == null ? void 0 : _f.hasTypedMembers,
|
|
16535
16851
|
dimensionData: column2.dimensionData
|
|
16536
16852
|
});
|
|
16537
16853
|
}
|
|
16538
16854
|
}
|
|
16539
|
-
if (!submissionEntry.typedMembers && ((
|
|
16855
|
+
if (!submissionEntry.typedMembers && ((_g = field2.crossRoleTypedMembers) == null ? void 0 : _g.length)) {
|
|
16540
16856
|
const crossRoleKey = `${concept.id}__${field2.columnId}`;
|
|
16541
16857
|
const crossRoleValues = this._typedMemberData[crossRoleKey];
|
|
16542
16858
|
if (crossRoleValues) {
|
|
@@ -16627,7 +16943,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16627
16943
|
});
|
|
16628
16944
|
}
|
|
16629
16945
|
_handleReset() {
|
|
16630
|
-
this._formData =
|
|
16946
|
+
this._formData = this._stripPriorYearExcludedFacts(this.initialData);
|
|
16631
16947
|
this._touched.clear();
|
|
16632
16948
|
this._dirty = false;
|
|
16633
16949
|
this.hasUnsavedChanges = false;
|
|
@@ -17394,6 +17710,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17394
17710
|
.periodEndDate="${this.periodEndDate}"
|
|
17395
17711
|
.calculationEnabled="${this.calculationEnabled}"
|
|
17396
17712
|
.totalManuallyEditedData="${this._totalManuallyEditedData}"
|
|
17713
|
+
.duplicateFactWarnings="${this._duplicateFactWarnings}"
|
|
17397
17714
|
@field-change="${this._handleFieldChange}"
|
|
17398
17715
|
@period-change="${this._handlePeriodChange}"
|
|
17399
17716
|
@typed-member-change="${this._handleTypedMemberChange}"
|
|
@@ -17601,6 +17918,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17601
17918
|
.periodEndDate="${this.periodEndDate}"
|
|
17602
17919
|
.calculationEnabled="${this.calculationEnabled}"
|
|
17603
17920
|
.totalManuallyEditedData="${this._totalManuallyEditedData}"
|
|
17921
|
+
.duplicateFactWarnings="${this._duplicateFactWarnings}"
|
|
17604
17922
|
@field-change="${this._handleFieldChange}"
|
|
17605
17923
|
@typed-member-change="${this._handleTypedMemberChange}"
|
|
17606
17924
|
@add-concept-repeat="${this._handleAddConceptRepeat}"
|
|
@@ -17653,7 +17971,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17653
17971
|
return { ...this._formData };
|
|
17654
17972
|
}
|
|
17655
17973
|
setData(data) {
|
|
17656
|
-
this._formData =
|
|
17974
|
+
this._formData = this._stripPriorYearExcludedFacts(data);
|
|
17657
17975
|
this._dirty = true;
|
|
17658
17976
|
this.hasUnsavedChanges = true;
|
|
17659
17977
|
this._validateForm();
|
|
@@ -18464,14 +18782,21 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
18464
18782
|
` : ""}
|
|
18465
18783
|
</div>
|
|
18466
18784
|
<div class="error-popup-footer">
|
|
18467
|
-
|
|
18785
|
+
${this._duplicateWarningPopupMode === "validate" ? html`
|
|
18786
|
+
<button class="btn-secondary" @click="${() => {
|
|
18468
18787
|
this._showValidateWarningPopup = false;
|
|
18469
18788
|
this.requestUpdate();
|
|
18470
18789
|
}}">${I18n.t("typedDimensionWarning.cancel")}</button>
|
|
18471
|
-
|
|
18790
|
+
<button class="btn-primary" @click="${() => {
|
|
18472
18791
|
this._showValidateWarningPopup = false;
|
|
18473
18792
|
this._continueSubmit();
|
|
18474
18793
|
}}">${I18n.t("typedDimensionWarning.continue")}</button>
|
|
18794
|
+
` : html`
|
|
18795
|
+
<button class="btn-primary" @click="${() => {
|
|
18796
|
+
this._showValidateWarningPopup = false;
|
|
18797
|
+
this.requestUpdate();
|
|
18798
|
+
}}">${I18n.t("duplicateFactWarning.close")}</button>
|
|
18799
|
+
`}
|
|
18475
18800
|
</div>
|
|
18476
18801
|
</div>
|
|
18477
18802
|
</div>
|
|
@@ -19605,6 +19930,12 @@ __decorateClass([
|
|
|
19605
19930
|
__decorateClass([
|
|
19606
19931
|
r()
|
|
19607
19932
|
], JupiterDynamicForm.prototype, "_duplicateFactMismatches", 2);
|
|
19933
|
+
__decorateClass([
|
|
19934
|
+
r()
|
|
19935
|
+
], JupiterDynamicForm.prototype, "_duplicateFactWarnings", 2);
|
|
19936
|
+
__decorateClass([
|
|
19937
|
+
r()
|
|
19938
|
+
], JupiterDynamicForm.prototype, "_duplicateWarningPopupMode", 2);
|
|
19608
19939
|
__decorateClass([
|
|
19609
19940
|
r()
|
|
19610
19941
|
], JupiterDynamicForm.prototype, "_submitDisabled", 2);
|