jupiter-dynamic-forms 1.1.0 → 1.2.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/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -3
- package/dist/index.mjs.map +1 -1
- package/dist/schema/types.d.ts +1 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/utils/xbrl-form-builder.d.ts +26 -2
- package/dist/utils/xbrl-form-builder.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -535,6 +535,7 @@ class XBRLFormBuilder {
|
|
|
535
535
|
const sections = [];
|
|
536
536
|
presentationData.roles.forEach((role) => {
|
|
537
537
|
const section = this.buildSectionFromRole(role, periodStartDate, periodEndDate);
|
|
538
|
+
this.assignFieldColumnIds(section);
|
|
538
539
|
sections.push(section);
|
|
539
540
|
});
|
|
540
541
|
return {
|
|
@@ -560,11 +561,13 @@ class XBRLFormBuilder {
|
|
|
560
561
|
}
|
|
561
562
|
});
|
|
562
563
|
}
|
|
564
|
+
const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31");
|
|
563
565
|
return {
|
|
564
566
|
id: role.id,
|
|
565
567
|
title,
|
|
566
568
|
description: `Section for ${title}`,
|
|
567
569
|
concepts: conceptTrees,
|
|
570
|
+
columns,
|
|
568
571
|
expanded: false
|
|
569
572
|
};
|
|
570
573
|
}
|
|
@@ -607,11 +610,18 @@ class XBRLFormBuilder {
|
|
|
607
610
|
static createFieldFromConcept(concept, periodStartDate, periodEndDate) {
|
|
608
611
|
const fieldType = this.mapXBRLTypeToFieldType(concept.type);
|
|
609
612
|
const label = this.getPreferredLabel(concept.labels);
|
|
613
|
+
let columnId = "default";
|
|
614
|
+
if (concept.periodType === "instant") {
|
|
615
|
+
columnId = "instant";
|
|
616
|
+
} else if (concept.periodType === "duration") {
|
|
617
|
+
columnId = "duration_start";
|
|
618
|
+
} else {
|
|
619
|
+
columnId = "default";
|
|
620
|
+
}
|
|
610
621
|
const field = {
|
|
611
622
|
id: `${concept.id}_field`,
|
|
612
623
|
conceptId: concept.id,
|
|
613
|
-
columnId
|
|
614
|
-
// Default column, will be expanded later
|
|
624
|
+
columnId,
|
|
615
625
|
type: fieldType,
|
|
616
626
|
label,
|
|
617
627
|
placeholder: `Enter ${label.toLowerCase()}`,
|
|
@@ -660,6 +670,162 @@ class XBRLFormBuilder {
|
|
|
660
670
|
return terse.label;
|
|
661
671
|
return labels[0].label;
|
|
662
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Assign appropriate column IDs to fields based on section's generated columns
|
|
675
|
+
*/
|
|
676
|
+
static assignFieldColumnIds(section) {
|
|
677
|
+
if (!section.columns || section.columns.length === 0) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const columnIds = section.columns.map((col) => col.id);
|
|
681
|
+
section.concepts.forEach((conceptTree) => {
|
|
682
|
+
this.assignColumnIdsToConceptFields(conceptTree, columnIds);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Recursively assign column IDs to fields in a concept tree
|
|
687
|
+
*/
|
|
688
|
+
static assignColumnIdsToConceptFields(conceptTree, columnIds) {
|
|
689
|
+
conceptTree.fields.forEach((field) => {
|
|
690
|
+
if (columnIds.includes("instant") && field.columnId === "instant") {
|
|
691
|
+
field.columnId = "instant";
|
|
692
|
+
} else if (columnIds.includes("duration_start") && field.columnId === "duration_start") {
|
|
693
|
+
field.columnId = "duration_start";
|
|
694
|
+
} else if (columnIds.includes("period_start") && (field.columnId === "duration_start" || field.columnId === "instant")) {
|
|
695
|
+
field.columnId = "period_start";
|
|
696
|
+
} else if (columnIds.length > 0) {
|
|
697
|
+
field.columnId = columnIds[0];
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
if (conceptTree.children) {
|
|
701
|
+
conceptTree.children.forEach((child) => {
|
|
702
|
+
this.assignColumnIdsToConceptFields(child, columnIds);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Get all non-abstract concepts from a role recursively
|
|
708
|
+
*/
|
|
709
|
+
static getAllNonAbstractConcepts(role) {
|
|
710
|
+
var _a;
|
|
711
|
+
const nonAbstractConcepts = [];
|
|
712
|
+
if ((_a = role.presentationLinkbase) == null ? void 0 : _a.concepts) {
|
|
713
|
+
role.presentationLinkbase.concepts.forEach((concept) => {
|
|
714
|
+
this.collectNonAbstractConcepts(concept, nonAbstractConcepts);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
return nonAbstractConcepts;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Recursively collect non-abstract concepts from a concept tree
|
|
721
|
+
*/
|
|
722
|
+
static collectNonAbstractConcepts(concept, collection) {
|
|
723
|
+
if (!concept.elementAbstract) {
|
|
724
|
+
collection.push(concept);
|
|
725
|
+
}
|
|
726
|
+
if (concept.children && concept.children.length > 0) {
|
|
727
|
+
concept.children.forEach((child) => {
|
|
728
|
+
this.collectNonAbstractConcepts(child, collection);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Generate default columns based on period types of non-abstract concepts in a role
|
|
734
|
+
*/
|
|
735
|
+
static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate) {
|
|
736
|
+
const nonAbstractConcepts = this.getAllNonAbstractConcepts(role);
|
|
737
|
+
console.log(`📊 Analyzing role "${role.role}" with ${nonAbstractConcepts.length} non-abstract concepts`);
|
|
738
|
+
if (nonAbstractConcepts.length === 0) {
|
|
739
|
+
console.log("📊 No non-abstract concepts found, using default column");
|
|
740
|
+
return [{
|
|
741
|
+
id: "default",
|
|
742
|
+
title: "Value",
|
|
743
|
+
description: "Default value column",
|
|
744
|
+
type: "base",
|
|
745
|
+
order: 0,
|
|
746
|
+
removable: false
|
|
747
|
+
}];
|
|
748
|
+
}
|
|
749
|
+
const periodTypes = new Set(
|
|
750
|
+
nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
|
|
751
|
+
);
|
|
752
|
+
console.log(`📅 Found period types: ${Array.from(periodTypes).join(", ")}`);
|
|
753
|
+
const columns = [];
|
|
754
|
+
if (periodTypes.size === 0) {
|
|
755
|
+
console.log("📅 No period types found, using default column");
|
|
756
|
+
columns.push({
|
|
757
|
+
id: "default",
|
|
758
|
+
title: "Value",
|
|
759
|
+
description: "Default value column",
|
|
760
|
+
type: "base",
|
|
761
|
+
order: 0,
|
|
762
|
+
removable: false
|
|
763
|
+
});
|
|
764
|
+
} else if (periodTypes.size === 1 && periodTypes.has("instant")) {
|
|
765
|
+
console.log("📅 All concepts are instant type, creating single column");
|
|
766
|
+
columns.push({
|
|
767
|
+
id: "instant",
|
|
768
|
+
title: `As of ${this.formatDateForDisplay(periodStartDate)}`,
|
|
769
|
+
description: `Values as of ${periodStartDate}`,
|
|
770
|
+
type: "base",
|
|
771
|
+
order: 0,
|
|
772
|
+
removable: false
|
|
773
|
+
});
|
|
774
|
+
} else if (periodTypes.size === 1 && periodTypes.has("duration")) {
|
|
775
|
+
console.log("📅 All concepts are duration type, creating two columns");
|
|
776
|
+
columns.push({
|
|
777
|
+
id: "duration_start",
|
|
778
|
+
title: `From ${this.formatDateForDisplay(periodStartDate)}`,
|
|
779
|
+
description: `Period start: ${periodStartDate}`,
|
|
780
|
+
type: "base",
|
|
781
|
+
order: 0,
|
|
782
|
+
removable: false
|
|
783
|
+
});
|
|
784
|
+
columns.push({
|
|
785
|
+
id: "duration_end",
|
|
786
|
+
title: `To ${this.formatDateForDisplay(periodEndDate)}`,
|
|
787
|
+
description: `Period end: ${periodEndDate}`,
|
|
788
|
+
type: "base",
|
|
789
|
+
order: 1,
|
|
790
|
+
removable: false
|
|
791
|
+
});
|
|
792
|
+
} else {
|
|
793
|
+
console.log("📅 Mixed period types found, creating two columns for full range");
|
|
794
|
+
columns.push({
|
|
795
|
+
id: "period_start",
|
|
796
|
+
title: `From ${this.formatDateForDisplay(periodStartDate)}`,
|
|
797
|
+
description: `Period start: ${periodStartDate}`,
|
|
798
|
+
type: "base",
|
|
799
|
+
order: 0,
|
|
800
|
+
removable: false
|
|
801
|
+
});
|
|
802
|
+
columns.push({
|
|
803
|
+
id: "period_end",
|
|
804
|
+
title: `To ${this.formatDateForDisplay(periodEndDate)}`,
|
|
805
|
+
description: `Period end: ${periodEndDate}`,
|
|
806
|
+
type: "base",
|
|
807
|
+
order: 1,
|
|
808
|
+
removable: false
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
console.log(`📊 Generated ${columns.length} columns for role "${role.role}":`, columns.map((c2) => c2.title));
|
|
812
|
+
return columns;
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Format date for display in column headers
|
|
816
|
+
*/
|
|
817
|
+
static formatDateForDisplay(dateString) {
|
|
818
|
+
try {
|
|
819
|
+
const date = new Date(dateString);
|
|
820
|
+
return date.toLocaleDateString("en-US", {
|
|
821
|
+
year: "numeric",
|
|
822
|
+
month: "short",
|
|
823
|
+
day: "numeric"
|
|
824
|
+
});
|
|
825
|
+
} catch {
|
|
826
|
+
return dateString;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
663
829
|
/**
|
|
664
830
|
* Extract entity name from entrypoint URL
|
|
665
831
|
*/
|
|
@@ -1847,7 +2013,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
1847
2013
|
${schema.sections.map((section) => html`
|
|
1848
2014
|
<jupiter-form-section
|
|
1849
2015
|
.section="${section}"
|
|
1850
|
-
.columns="${this._columns}"
|
|
2016
|
+
.columns="${section.columns || this._columns}"
|
|
1851
2017
|
.formData="${this._formData}"
|
|
1852
2018
|
.disabled="${this.disabled || this.readonly}"
|
|
1853
2019
|
.collapsible="${config.collapsibleSections !== false}"
|