jupiter-dynamic-forms 1.22.5 → 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/dynamic-form.d.ts +27 -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 +3 -0
- package/dist/core/form-field.d.ts.map +1 -1
- package/dist/index.js +25 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +173 -19
- 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 +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2894,6 +2894,7 @@ function collectAllCandidates(formData) {
|
|
|
2894
2894
|
return candidates;
|
|
2895
2895
|
}
|
|
2896
2896
|
function indexConceptTree(concept, conceptByQName, conceptById, conceptIdByQName, conceptIdByQNameHasChildren, childrenIndex) {
|
|
2897
|
+
var _a;
|
|
2897
2898
|
const info = {
|
|
2898
2899
|
conceptId: concept.id,
|
|
2899
2900
|
qname: concept.name,
|
|
@@ -2904,8 +2905,11 @@ function indexConceptTree(concept, conceptByQName, conceptById, conceptIdByQName
|
|
|
2904
2905
|
(conceptByQName.get(concept.name) ?? conceptByQName.set(concept.name, []).get(concept.name)).push(info);
|
|
2905
2906
|
const children = concept.children || [];
|
|
2906
2907
|
const hasOwnChildren = children.length > 0;
|
|
2908
|
+
const existingConceptId = conceptIdByQName.get(concept.name);
|
|
2907
2909
|
const alreadyHasChildren = conceptIdByQNameHasChildren.get(concept.name) === true;
|
|
2908
|
-
|
|
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) {
|
|
2909
2913
|
conceptIdByQName.set(concept.name, concept.id);
|
|
2910
2914
|
conceptIdByQNameHasChildren.set(concept.name, hasOwnChildren);
|
|
2911
2915
|
}
|
|
@@ -3360,6 +3364,42 @@ function uncoveredExplicitDimensionAxisIds(variable, ctx) {
|
|
|
3360
3364
|
}
|
|
3361
3365
|
return axisIds;
|
|
3362
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
|
+
}
|
|
3363
3403
|
function candidateMemberIdForAxis(ctx, candidate, axisId) {
|
|
3364
3404
|
var _a;
|
|
3365
3405
|
const column2 = getColumn(ctx, candidate);
|
|
@@ -3369,21 +3409,39 @@ function candidateMemberIdForAxis(ctx, candidate, axisId) {
|
|
|
3369
3409
|
return column2.dimensionData.memberId;
|
|
3370
3410
|
return (_a = (column2.dimensionData.combinations || []).find((combo) => combo.axisId === axisId)) == null ? void 0 : _a.memberId;
|
|
3371
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
|
+
}
|
|
3372
3426
|
function findUncoveredAxisAnchor(variables, axisId, candidatesByName, ctx) {
|
|
3373
3427
|
for (const variable of variables) {
|
|
3374
3428
|
if (variable.bindAsSequence)
|
|
3375
3429
|
continue;
|
|
3376
|
-
if (!uncoveredExplicitDimensionAxisIds(variable, ctx).has(axisId))
|
|
3377
|
-
continue;
|
|
3378
3430
|
const candidates = candidatesByName.get(variable.name) || [];
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
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 };
|
|
3387
3445
|
}
|
|
3388
3446
|
return void 0;
|
|
3389
3447
|
}
|
|
@@ -3392,13 +3450,15 @@ function computeAssertionNarrowedCandidatesByName(variables, ctx, implicitFilter
|
|
|
3392
3450
|
variables.forEach((variable) => candidatesByName.set(variable.name, resolveNarrowedCandidates(variable, ctx, roleURI)));
|
|
3393
3451
|
if (implicitFiltering) {
|
|
3394
3452
|
const axisIds = /* @__PURE__ */ new Set();
|
|
3395
|
-
variables.forEach(
|
|
3453
|
+
variables.forEach(
|
|
3454
|
+
(variable) => impliedUncoveredAxisIds(variable, candidatesByName.get(variable.name) || [], ctx).forEach((axisId) => axisIds.add(axisId))
|
|
3455
|
+
);
|
|
3396
3456
|
axisIds.forEach((axisId) => {
|
|
3397
3457
|
const anchor = findUncoveredAxisAnchor(variables, axisId, candidatesByName, ctx);
|
|
3398
3458
|
if (!anchor)
|
|
3399
3459
|
return;
|
|
3400
3460
|
variables.forEach((variable) => {
|
|
3401
|
-
const isNarrowableSequence = variable.bindAsSequence &&
|
|
3461
|
+
const isNarrowableSequence = variable.bindAsSequence && impliedUncoveredAxisIds(variable, candidatesByName.get(variable.name) || [], ctx).has(axisId);
|
|
3402
3462
|
const isAmbiguousAnchorItself = anchor.ambiguous && variable.name === anchor.variableName;
|
|
3403
3463
|
if (!isNarrowableSequence && !isAmbiguousAnchorItself)
|
|
3404
3464
|
return;
|
|
@@ -5011,6 +5071,15 @@ let JupiterFormField = class extends LitElement {
|
|
|
5011
5071
|
this._availableUnits = [];
|
|
5012
5072
|
this._numericDraftValue = null;
|
|
5013
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();
|
|
5014
5083
|
}
|
|
5015
5084
|
willUpdate(changedProperties) {
|
|
5016
5085
|
var _a;
|
|
@@ -5936,18 +6005,14 @@ let JupiterFormField = class extends LitElement {
|
|
|
5936
6005
|
}
|
|
5937
6006
|
return html``;
|
|
5938
6007
|
}
|
|
5939
|
-
// JDF-118: the period popup is a plain Lit overlay, not a native <dialog>, so it doesn't get
|
|
5940
|
-
// Escape-to-close for free the way the info/text dialogs do. Keydown on the overlay catches it
|
|
5941
|
-
// as it bubbles up from whichever control inside the popup has focus.
|
|
5942
6008
|
_handlePeriodPopupKeydown(e2) {
|
|
5943
|
-
if (e2.key === "Escape") {
|
|
5944
|
-
e2.stopPropagation();
|
|
6009
|
+
if (this._showPeriodPopup && e2.key === "Escape") {
|
|
5945
6010
|
this._closePeriodPopup();
|
|
5946
6011
|
}
|
|
5947
6012
|
}
|
|
5948
6013
|
_renderPeriodPopup() {
|
|
5949
6014
|
return html`
|
|
5950
|
-
<div class="period-popup-overlay" @click="${this._handlePopupOverlayClick}"
|
|
6015
|
+
<div class="period-popup-overlay" @click="${this._handlePopupOverlayClick}">
|
|
5951
6016
|
<div class="period-popup" @click="${(e2) => e2.stopPropagation()}">
|
|
5952
6017
|
<div class="period-popup-header">
|
|
5953
6018
|
<div class="period-popup-title">${I18n.t("field.editPeriod")}</div>
|
|
@@ -7671,6 +7736,7 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7671
7736
|
this._selectedType = "duration";
|
|
7672
7737
|
this._selectedDimensions = /* @__PURE__ */ new Map();
|
|
7673
7738
|
this._typedValueErrors = {};
|
|
7739
|
+
this._boundHandleKeydown = this._handleKeydown.bind(this);
|
|
7674
7740
|
}
|
|
7675
7741
|
updated(changedProperties) {
|
|
7676
7742
|
if (changedProperties.has("open") && this.open) {
|
|
@@ -7682,6 +7748,11 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7682
7748
|
connectedCallback() {
|
|
7683
7749
|
super.connectedCallback();
|
|
7684
7750
|
this._resetForm();
|
|
7751
|
+
window.addEventListener("keydown", this._boundHandleKeydown);
|
|
7752
|
+
}
|
|
7753
|
+
disconnectedCallback() {
|
|
7754
|
+
window.removeEventListener("keydown", this._boundHandleKeydown);
|
|
7755
|
+
super.disconnectedCallback();
|
|
7685
7756
|
}
|
|
7686
7757
|
willUpdate(changedProperties) {
|
|
7687
7758
|
super.willUpdate(changedProperties);
|
|
@@ -7689,6 +7760,11 @@ let JupiterAddColumnDialog = class extends LitElement {
|
|
|
7689
7760
|
this._resetForm();
|
|
7690
7761
|
}
|
|
7691
7762
|
}
|
|
7763
|
+
_handleKeydown(event) {
|
|
7764
|
+
if (this.open && event.key === "Escape") {
|
|
7765
|
+
this._handleCancel();
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7692
7768
|
_handleCancel() {
|
|
7693
7769
|
this.open = false;
|
|
7694
7770
|
this.dispatchEvent(new CustomEvent("dialog-cancel", { bubbles: true }));
|
|
@@ -10265,6 +10341,7 @@ let JupiterAdvancedFilter = class extends LitElement {
|
|
|
10265
10341
|
return;
|
|
10266
10342
|
}
|
|
10267
10343
|
if (e2.key === "Escape") {
|
|
10344
|
+
e2.stopPropagation();
|
|
10268
10345
|
this._showSuggestions = false;
|
|
10269
10346
|
this._activeSuggestionIndex = -1;
|
|
10270
10347
|
return;
|
|
@@ -10579,11 +10656,22 @@ let JupiterFilterRolesDialog = class extends LitElement {
|
|
|
10579
10656
|
this._showFactsOnly = false;
|
|
10580
10657
|
this._conceptSearchText = "";
|
|
10581
10658
|
this._collapsedRoles = /* @__PURE__ */ new Set();
|
|
10659
|
+
this._boundHandleKeydown = this._handleKeydown.bind(this);
|
|
10582
10660
|
}
|
|
10583
10661
|
connectedCallback() {
|
|
10584
10662
|
super.connectedCallback();
|
|
10585
10663
|
this._initializeTempSelection();
|
|
10586
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
|
+
}
|
|
10587
10675
|
}
|
|
10588
10676
|
updated(changedProperties) {
|
|
10589
10677
|
if (changedProperties.has("selectedRoleIds") || changedProperties.has("open")) {
|
|
@@ -13027,6 +13115,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13027
13115
|
this._showFactsOnly = false;
|
|
13028
13116
|
this._conceptSearchText = "";
|
|
13029
13117
|
this._lastFocusedFieldIdentity = null;
|
|
13118
|
+
this._dimensionColumnDriftDiagnostics = [];
|
|
13030
13119
|
this._periodPreferences = {};
|
|
13031
13120
|
this._activeSidePanelRoleId = null;
|
|
13032
13121
|
this._sidePanelSearchQuery = "";
|
|
@@ -15919,6 +16008,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15919
16008
|
});
|
|
15920
16009
|
this._formData = { ...this._formData, ...restoredFormData };
|
|
15921
16010
|
console.log(`🔄 Restored ${Object.keys(restoredFormData).length} concepts with data`);
|
|
16011
|
+
this._diagnoseDimensionColumnDrift(formData);
|
|
15922
16012
|
this._seedLegacyManuallyEditedTotals(restoredFormData);
|
|
15923
16013
|
this._initializeGlobalDecimalsFromRoundingData();
|
|
15924
16014
|
this._periodData = {
|
|
@@ -16415,6 +16505,70 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16415
16505
|
}
|
|
16416
16506
|
return null;
|
|
16417
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
|
+
}
|
|
16418
16572
|
_findSectionForConcept(conceptId) {
|
|
16419
16573
|
for (const section2 of this._allSections) {
|
|
16420
16574
|
const concept = this._findConceptInSection(section2.concepts, conceptId);
|