jupiter-dynamic-forms 1.20.9 → 1.21.0
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/dynamic-form.d.ts +6 -2
- package/dist/core/dynamic-form.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +105 -38
- package/dist/index.mjs.map +1 -1
- package/dist/schema/types.d.ts +11 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -16185,9 +16185,10 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16185
16185
|
}
|
|
16186
16186
|
return false;
|
|
16187
16187
|
}
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
16188
|
+
// Every column carrying all of `dims`. More than one is normal: a previous-year column copies
|
|
16189
|
+
// its current-year column's dimensions and differs only in period, which callers don't pass.
|
|
16190
|
+
_findColumnsByDimensions(columns, dims) {
|
|
16191
|
+
return columns.filter((col) => {
|
|
16191
16192
|
if (col.type !== "dimension" || !col.dimensionData)
|
|
16192
16193
|
return false;
|
|
16193
16194
|
const combos = col.dimensionData.combinations;
|
|
@@ -16199,12 +16200,60 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16199
16200
|
);
|
|
16200
16201
|
}
|
|
16201
16202
|
return dims.length === 1 && this._normalizeAxisId(col.dimensionData.axisId ?? "") === this._normalizeAxisId(dims[0].axis) && this._normalizeMemberId(col.dimensionData.memberId ?? "") === this._normalizeMemberId(dims[0].member);
|
|
16202
|
-
})
|
|
16203
|
+
});
|
|
16204
|
+
}
|
|
16205
|
+
// Which of `candidates` a scrollToConcept call points at in one row. Narrowed first by
|
|
16206
|
+
// `period` (the columns whose fact has that period), then by `targetValue` (the column whose
|
|
16207
|
+
// stored fact equals it — exactly before up-to-scale, visible before hidden); a step that
|
|
16208
|
+
// singles nothing out is skipped. Else the first candidate.
|
|
16209
|
+
_pickColumn(section2, concept, candidates, targetValue, period, hiddenColumnIds) {
|
|
16210
|
+
var _a;
|
|
16211
|
+
let pool = candidates;
|
|
16212
|
+
if (period && pool.length > 1) {
|
|
16213
|
+
const inPeriod = pool.filter((c2) => this._periodMatches(this._cellPeriod(section2, concept, c2.id), period));
|
|
16214
|
+
if (inPeriod.length)
|
|
16215
|
+
pool = inPeriod;
|
|
16216
|
+
}
|
|
16217
|
+
const rowData = this._formData[concept.id];
|
|
16218
|
+
if (pool.length > 1 && targetValue !== null && rowData) {
|
|
16219
|
+
const filled = pool.filter((c2) => rowData[c2.id] !== void 0 && rowData[c2.id] !== null && rowData[c2.id] !== "");
|
|
16220
|
+
const exact = filled.filter((c2) => String(rowData[c2.id]) === targetValue || Number(rowData[c2.id]) === Number(targetValue));
|
|
16221
|
+
const holders = exact.length ? exact : filled.filter((c2) => this._valueLooselyMatches(rowData[c2.id], targetValue));
|
|
16222
|
+
const holder = holders.find((c2) => !(hiddenColumnIds == null ? void 0 : hiddenColumnIds.has(c2.id))) ?? holders[0];
|
|
16223
|
+
if (holder)
|
|
16224
|
+
return holder.id;
|
|
16225
|
+
}
|
|
16226
|
+
return (_a = pool[0]) == null ? void 0 : _a.id;
|
|
16227
|
+
}
|
|
16228
|
+
// The period Save Draft/Submit write for this cell's fact (same fallback chain as
|
|
16229
|
+
// _processConceptsForSubmission), so a period the host read off a saved fact compares equal —
|
|
16230
|
+
// including user-edited periods and periodStartLabel rows' "day before start" instants.
|
|
16231
|
+
_cellPeriod(section2, concept, columnId) {
|
|
16232
|
+
var _a, _b;
|
|
16233
|
+
const column2 = this._findColumnByIdInSection(columnId, section2);
|
|
16234
|
+
const field2 = ((_a = concept.fields) == null ? void 0 : _a.find((f2) => f2.columnId === columnId)) ?? { columnId };
|
|
16235
|
+
const fieldPeriodData = (_b = this._periodData[concept.id]) == null ? void 0 : _b[columnId];
|
|
16236
|
+
if (concept.periodType === "instant") {
|
|
16237
|
+
return { instant: this._resolveSubmissionInstantDate(concept, field2, fieldPeriodData, column2) };
|
|
16238
|
+
}
|
|
16239
|
+
return {
|
|
16240
|
+
startDate: (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate,
|
|
16241
|
+
endDate: (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate
|
|
16242
|
+
};
|
|
16243
|
+
}
|
|
16244
|
+
// Every date the host gave equals the cell's; an instant only matches an instant cell, a
|
|
16245
|
+
// start/end only a duration cell. Compared as YYYY-MM-DD so a time part doesn't matter.
|
|
16246
|
+
_periodMatches(cell, period) {
|
|
16247
|
+
const day = (d2) => d2 == null ? void 0 : d2.slice(0, 10);
|
|
16248
|
+
const instant = period.instant ?? period.date;
|
|
16249
|
+
if (instant)
|
|
16250
|
+
return day(cell.instant) === day(instant);
|
|
16251
|
+
return !cell.instant && (!period.startDate || day(cell.startDate) === day(period.startDate)) && (!period.endDate || day(cell.endDate) === day(period.endDate));
|
|
16203
16252
|
}
|
|
16204
16253
|
// Step 1 of scrollToConcept: pick the section + concept row to navigate to. Precedence:
|
|
16205
16254
|
// exactConceptId (caller resolved the row) → role (JDF-087: caller named the role) → the
|
|
16206
16255
|
// original whole-form search (visible sections first, then the rest).
|
|
16207
|
-
_resolveScrollTarget(conceptName, dimensions, columnId, exactConceptId, role, targetValue) {
|
|
16256
|
+
_resolveScrollTarget(conceptName, dimensions, columnId, exactConceptId, role, targetValue, period) {
|
|
16208
16257
|
var _a;
|
|
16209
16258
|
const sectionsToSearch = [
|
|
16210
16259
|
...((_a = this._currentSchema) == null ? void 0 : _a.sections) ?? [],
|
|
@@ -16227,7 +16276,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16227
16276
|
const matches = rankMatchingSections(role, sectionsToSearch);
|
|
16228
16277
|
console.log(`[scrollToConcept] role="${role}" matched ${matches.length} section(s): ${matches.slice(0, 5).map((m) => `${m.section.id} (tier ${m.tier})`).join(", ")}`);
|
|
16229
16278
|
for (const { section: section2, tier } of matches) {
|
|
16230
|
-
const hit = this._resolveConceptInSection(section2, conceptName, dimensions, columnId, targetValue);
|
|
16279
|
+
const hit = this._resolveConceptInSection(section2, conceptName, dimensions, columnId, targetValue, period);
|
|
16231
16280
|
if (!hit)
|
|
16232
16281
|
continue;
|
|
16233
16282
|
if (tier >= ROLE_MATCH_TIER.SUBSTRING) {
|
|
@@ -16237,67 +16286,75 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16237
16286
|
}
|
|
16238
16287
|
console.warn(`[scrollToConcept] "${conceptName}" not found in any section matching role="${role}" — falling back to whole-form search`);
|
|
16239
16288
|
}
|
|
16289
|
+
let columnOnly = null;
|
|
16240
16290
|
let tentative = null;
|
|
16241
16291
|
for (const section2 of sectionsToSearch) {
|
|
16242
|
-
const hit = this._resolveConceptInSection(section2, conceptName, dimensions, columnId, targetValue);
|
|
16292
|
+
const hit = this._resolveConceptInSection(section2, conceptName, dimensions, columnId, targetValue, period);
|
|
16243
16293
|
if (!hit)
|
|
16244
16294
|
continue;
|
|
16245
|
-
if (hit.strong)
|
|
16295
|
+
if (hit.strong && hit.inPeriod)
|
|
16246
16296
|
return { section: section2, concept: hit.concept, viaRole: false };
|
|
16247
|
-
|
|
16297
|
+
if (hit.strong)
|
|
16298
|
+
columnOnly ?? (columnOnly = { section: section2, concept: hit.concept });
|
|
16299
|
+
else
|
|
16300
|
+
tentative ?? (tentative = { section: section2, concept: hit.concept });
|
|
16248
16301
|
}
|
|
16249
|
-
|
|
16302
|
+
const fallback = columnOnly ?? tentative;
|
|
16303
|
+
return fallback ? { ...fallback, viaRole: false } : null;
|
|
16250
16304
|
}
|
|
16251
16305
|
// Finds conceptName's row in one section. `strong` is false when the concept is there but the
|
|
16252
16306
|
// requested column (columnId, or one matching `dimensions`) isn't — the whole-form search keeps
|
|
16253
16307
|
// such a hit only as a fallback while it looks for a section where the column is present.
|
|
16254
|
-
|
|
16308
|
+
// `inPeriod` is false when `period` was given but none of those columns has it (same idea).
|
|
16309
|
+
_resolveConceptInSection(section2, conceptName, dimensions, columnId, targetValue, period) {
|
|
16255
16310
|
const candidates = this._findAllConceptsByName(section2.concepts, conceptName);
|
|
16256
16311
|
if (!candidates.length)
|
|
16257
16312
|
return null;
|
|
16258
16313
|
const hasValueMatch = targetValue !== null;
|
|
16259
16314
|
const cols = section2.columns ?? this._columns;
|
|
16260
|
-
const
|
|
16315
|
+
const resolvedColumnIds = columnId ? [columnId] : (dimensions == null ? void 0 : dimensions.length) ? this._findColumnsByDimensions(cols, dimensions).map((c2) => c2.id) : [];
|
|
16316
|
+
const cellMatches = (row, id, usePeriod) => {
|
|
16317
|
+
var _a;
|
|
16318
|
+
const cellValue = (_a = this._formData[row.id]) == null ? void 0 : _a[id];
|
|
16319
|
+
if (cellValue === void 0 || cellValue === null || cellValue === "")
|
|
16320
|
+
return false;
|
|
16321
|
+
if (hasValueMatch && !this._valueLooselyMatches(cellValue, targetValue))
|
|
16322
|
+
return false;
|
|
16323
|
+
return !usePeriod || this._periodMatches(this._cellPeriod(section2, row, id), period);
|
|
16324
|
+
};
|
|
16325
|
+
const rowMatches = (row, usePeriod) => {
|
|
16326
|
+
if (resolvedColumnIds.length)
|
|
16327
|
+
return resolvedColumnIds.some((id) => cellMatches(row, id, usePeriod));
|
|
16328
|
+
if (!hasValueMatch && !usePeriod)
|
|
16329
|
+
return false;
|
|
16330
|
+
return Object.keys(this._formData[row.id] ?? {}).some((id) => cellMatches(row, id, usePeriod));
|
|
16331
|
+
};
|
|
16261
16332
|
let picked;
|
|
16262
16333
|
if (candidates.length > 1) {
|
|
16263
|
-
picked = candidates.find((c2) =>
|
|
16264
|
-
const rowData = this._formData[c2.id];
|
|
16265
|
-
if (!rowData)
|
|
16266
|
-
return false;
|
|
16267
|
-
if (resolvedColumnId) {
|
|
16268
|
-
const cellValue = rowData[resolvedColumnId];
|
|
16269
|
-
if (cellValue === void 0 || cellValue === null || cellValue === "")
|
|
16270
|
-
return false;
|
|
16271
|
-
return !hasValueMatch || this._valueLooselyMatches(cellValue, targetValue);
|
|
16272
|
-
}
|
|
16273
|
-
if (hasValueMatch) {
|
|
16274
|
-
return Object.values(rowData).some(
|
|
16275
|
-
(v) => v !== void 0 && v !== null && v !== "" && this._valueLooselyMatches(v, targetValue)
|
|
16276
|
-
);
|
|
16277
|
-
}
|
|
16278
|
-
return false;
|
|
16279
|
-
});
|
|
16334
|
+
picked = (period ? candidates.find((c2) => rowMatches(c2, true)) : void 0) ?? candidates.find((c2) => rowMatches(c2, false));
|
|
16280
16335
|
console.log(`[scrollToConcept] Section "${section2.id}" has ${candidates.length} rows named "${conceptName}" | disambiguated=${(picked == null ? void 0 : picked.id) ?? "none (using first)"}`);
|
|
16281
16336
|
}
|
|
16282
16337
|
const found = picked ?? candidates[0];
|
|
16338
|
+
const inPeriod = (ids) => !period || ids.some((id) => this._periodMatches(this._cellPeriod(section2, found, id), period));
|
|
16283
16339
|
if (columnId) {
|
|
16284
16340
|
const hasColumn = cols.some((c2) => c2.id === columnId);
|
|
16285
16341
|
console.log(`[scrollToConcept] Section "${section2.id}" has concept "${found.id}" | columnId="${columnId}" present=${hasColumn}`);
|
|
16286
|
-
return { concept: found, strong: hasColumn };
|
|
16342
|
+
return { concept: found, strong: hasColumn, inPeriod: inPeriod(hasColumn ? [columnId] : []) };
|
|
16287
16343
|
}
|
|
16288
16344
|
if (dimensions == null ? void 0 : dimensions.length) {
|
|
16289
|
-
console.log(`[scrollToConcept] Section "${section2.id}" has concept "${found.id}" | colMatch=${
|
|
16290
|
-
return { concept: found, strong:
|
|
16345
|
+
console.log(`[scrollToConcept] Section "${section2.id}" has concept "${found.id}" | colMatch=${resolvedColumnIds.join(",") || "null"} | cols=${cols.map((c2) => c2.id).join(",")}`);
|
|
16346
|
+
return { concept: found, strong: resolvedColumnIds.length > 0, inPeriod: inPeriod(resolvedColumnIds) };
|
|
16291
16347
|
}
|
|
16292
16348
|
console.log(`[scrollToConcept] Section "${section2.id}" has concept "${found.id}" (no dims, taking first)`);
|
|
16293
|
-
return { concept: found, strong: true };
|
|
16349
|
+
return { concept: found, strong: true, inPeriod: inPeriod(cols.map((c2) => c2.id)) };
|
|
16294
16350
|
}
|
|
16295
16351
|
async scrollToConcept(conceptName, dimensions, match, columnId, exactConceptId, role) {
|
|
16296
16352
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
16297
|
-
console.log(`[scrollToConcept] ▶ START conceptName=${conceptName} value=${match == null ? void 0 : match.value} dims=${JSON.stringify(dimensions)} columnId=${columnId} exactConceptId=${exactConceptId} role=${role}`);
|
|
16353
|
+
console.log(`[scrollToConcept] ▶ START conceptName=${conceptName} value=${match == null ? void 0 : match.value} period=${JSON.stringify(match == null ? void 0 : match.period)} dims=${JSON.stringify(dimensions)} columnId=${columnId} exactConceptId=${exactConceptId} role=${role}`);
|
|
16298
16354
|
const hasValueMatch = (match == null ? void 0 : match.value) !== void 0 && (match == null ? void 0 : match.value) !== null;
|
|
16299
16355
|
const targetValue = hasValueMatch ? String(match.value) : null;
|
|
16300
|
-
const
|
|
16356
|
+
const period = (match == null ? void 0 : match.period) && (match.period.instant || match.period.date || match.period.startDate || match.period.endDate) ? match.period : void 0;
|
|
16357
|
+
const resolved = this._resolveScrollTarget(conceptName, dimensions, columnId, exactConceptId, role, targetValue, period);
|
|
16301
16358
|
if (!resolved) {
|
|
16302
16359
|
console.warn(`[scrollToConcept] Concept not found: ${conceptName}`);
|
|
16303
16360
|
return;
|
|
@@ -16331,7 +16388,16 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16331
16388
|
if (columnId) {
|
|
16332
16389
|
targetColumnId = columnId;
|
|
16333
16390
|
} else if (dimensions == null ? void 0 : dimensions.length) {
|
|
16334
|
-
targetColumnId = this.
|
|
16391
|
+
targetColumnId = this._pickColumn(
|
|
16392
|
+
targetSection,
|
|
16393
|
+
targetConcept,
|
|
16394
|
+
this._findColumnsByDimensions(columns, dimensions),
|
|
16395
|
+
targetValue,
|
|
16396
|
+
period,
|
|
16397
|
+
hiddenColumnIds
|
|
16398
|
+
) ?? null;
|
|
16399
|
+
} else if (period && columns.some((c2) => this._periodMatches(this._cellPeriod(targetSection, targetConcept, c2.id), period))) {
|
|
16400
|
+
targetColumnId = this._pickColumn(targetSection, targetConcept, columns, targetValue, period, hiddenColumnIds) ?? null;
|
|
16335
16401
|
} else if (!hasValueMatch) {
|
|
16336
16402
|
targetColumnId = ((_c = columns.find((c2) => !(hiddenColumnIds == null ? void 0 : hiddenColumnIds.has(c2.id))) ?? columns[0]) == null ? void 0 : _c.id) ?? null;
|
|
16337
16403
|
}
|
|
@@ -16356,7 +16422,8 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16356
16422
|
this._showColumn(targetSection.id, columnToShow);
|
|
16357
16423
|
}
|
|
16358
16424
|
}
|
|
16359
|
-
|
|
16425
|
+
const periodPinned = !!period && !!targetColumnId && this._periodMatches(this._cellPeriod(targetSection, targetConcept, targetColumnId), period);
|
|
16426
|
+
console.log(`[scrollToConcept] targetColumnId=${targetColumnId} hasValueMatch=${hasValueMatch} targetValue=${targetValue} periodPinned=${periodPinned}`);
|
|
16360
16427
|
this._conceptSearchText = conceptName.includes(":") ? conceptName.split(":").pop() : conceptName;
|
|
16361
16428
|
this.requestUpdate();
|
|
16362
16429
|
await this.updateComplete;
|
|
@@ -16417,7 +16484,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16417
16484
|
if (targetFieldEl)
|
|
16418
16485
|
return;
|
|
16419
16486
|
const columnMatch = targetColumnId ? fieldEl.conceptId === conceptId && fieldEl.columnId === targetColumnId : fieldEl.conceptId === conceptId;
|
|
16420
|
-
const valueMatch = !hasValueMatch || valueMatchesTarget(fieldEl, targetValue);
|
|
16487
|
+
const valueMatch = !hasValueMatch || periodPinned || valueMatchesTarget(fieldEl, targetValue);
|
|
16421
16488
|
if (columnMatch) {
|
|
16422
16489
|
phase1FieldCount++;
|
|
16423
16490
|
console.log(`[scrollToConcept] Phase1 candidate: conceptId=${fieldEl.conceptId} columnId=${fieldEl.columnId} value=${fieldEl.value} scale=${getFieldScaleFactor(fieldEl)} valueMatch=${valueMatch}`);
|