jupiter-dynamic-forms 1.4.0 → 1.5.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 +6 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +317 -76
- package/dist/index.mjs.map +1 -1
- package/dist/utils/xbrl-form-builder.d.ts +16 -0
- package/dist/utils/xbrl-form-builder.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -570,7 +570,16 @@ class XBRLFormBuilder {
|
|
|
570
570
|
const periodTypes = new Set(
|
|
571
571
|
nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
|
|
572
572
|
);
|
|
573
|
-
const
|
|
573
|
+
const hypercubeRole = hypercubeData == null ? void 0 : hypercubeData.roles.find((hr) => hr.roleId === role.id);
|
|
574
|
+
if (hypercubeRole) {
|
|
575
|
+
console.log(`🏷️ Found matching hypercube role "${role.id}"`);
|
|
576
|
+
} else {
|
|
577
|
+
console.log(`❌ No hypercube role found for "${role.id}"`);
|
|
578
|
+
}
|
|
579
|
+
const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes);
|
|
580
|
+
const availableColumnIds = columns.map((col) => col.id);
|
|
581
|
+
console.log(`📋 Available column IDs for role "${role.id}":`, availableColumnIds);
|
|
582
|
+
const roleInfo = { periodTypes, availableColumnIds };
|
|
574
583
|
const conceptTrees = [];
|
|
575
584
|
if ((_a = role.presentationLinkbase) == null ? void 0 : _a.concepts) {
|
|
576
585
|
role.presentationLinkbase.concepts.forEach((concept) => {
|
|
@@ -580,13 +589,6 @@ class XBRLFormBuilder {
|
|
|
580
589
|
}
|
|
581
590
|
});
|
|
582
591
|
}
|
|
583
|
-
const hypercubeRole = hypercubeData == null ? void 0 : hypercubeData.roles.find((hr) => hr.roleId === role.id);
|
|
584
|
-
if (hypercubeRole) {
|
|
585
|
-
console.log(`🏷️ Found matching hypercube role "${role.id}"`);
|
|
586
|
-
} else {
|
|
587
|
-
console.log(`❌ No hypercube role found for "${role.id}"`);
|
|
588
|
-
}
|
|
589
|
-
const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes);
|
|
590
592
|
return {
|
|
591
593
|
id: role.id,
|
|
592
594
|
title,
|
|
@@ -603,27 +605,42 @@ class XBRLFormBuilder {
|
|
|
603
605
|
const label = this.getPreferredLabel(concept.labels);
|
|
604
606
|
const fields = [];
|
|
605
607
|
if (!concept.elementAbstract) {
|
|
606
|
-
let
|
|
607
|
-
if ((roleInfo == null ? void 0 : roleInfo.
|
|
608
|
-
|
|
609
|
-
|
|
608
|
+
let columnIds = [];
|
|
609
|
+
if ((roleInfo == null ? void 0 : roleInfo.availableColumnIds) && roleInfo.availableColumnIds.length > 0) {
|
|
610
|
+
columnIds = roleInfo.availableColumnIds.filter((colId) => {
|
|
611
|
+
if (concept.periodType === "instant") {
|
|
612
|
+
return colId.includes("instant") || colId === "instant";
|
|
613
|
+
} else if (concept.periodType === "duration") {
|
|
614
|
+
return colId.includes("duration") || colId === "duration";
|
|
615
|
+
} else {
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
if (columnIds.length === 0) {
|
|
620
|
+
columnIds = roleInfo.availableColumnIds;
|
|
610
621
|
}
|
|
611
|
-
}
|
|
612
|
-
if (shouldCreateField) {
|
|
613
|
-
let columnId;
|
|
622
|
+
} else {
|
|
614
623
|
if (!(roleInfo == null ? void 0 : roleInfo.periodTypes) || roleInfo.periodTypes.size === 0) {
|
|
615
|
-
|
|
624
|
+
columnIds = ["default"];
|
|
616
625
|
} else if (roleInfo.periodTypes.size === 1 && roleInfo.periodTypes.has("instant")) {
|
|
617
|
-
|
|
626
|
+
columnIds = ["instant"];
|
|
618
627
|
} else if (roleInfo.periodTypes.size === 1 && roleInfo.periodTypes.has("duration")) {
|
|
619
|
-
|
|
628
|
+
columnIds = ["duration"];
|
|
620
629
|
} else {
|
|
621
|
-
|
|
630
|
+
if (concept.periodType === "instant") {
|
|
631
|
+
columnIds = ["instant"];
|
|
632
|
+
} else if (concept.periodType === "duration") {
|
|
633
|
+
columnIds = ["duration"];
|
|
634
|
+
} else {
|
|
635
|
+
columnIds = ["duration", "instant"];
|
|
636
|
+
}
|
|
622
637
|
}
|
|
638
|
+
}
|
|
639
|
+
columnIds.forEach((columnId) => {
|
|
623
640
|
const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
|
|
624
641
|
if (field)
|
|
625
642
|
fields.push(field);
|
|
626
|
-
}
|
|
643
|
+
});
|
|
627
644
|
}
|
|
628
645
|
const children = [];
|
|
629
646
|
if (concept.children && concept.children.length > 0) {
|
|
@@ -634,6 +651,10 @@ class XBRLFormBuilder {
|
|
|
634
651
|
}
|
|
635
652
|
});
|
|
636
653
|
}
|
|
654
|
+
const hasContent = fields.length > 0 || children.length > 0;
|
|
655
|
+
if (!hasContent) {
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
637
658
|
return {
|
|
638
659
|
id: this.createUniqueConceptId(concept),
|
|
639
660
|
// Use unique ID for form management
|
|
@@ -788,7 +809,7 @@ class XBRLFormBuilder {
|
|
|
788
809
|
* Generate default columns based on period types of non-abstract concepts in a role
|
|
789
810
|
*/
|
|
790
811
|
static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes) {
|
|
791
|
-
var _a, _b, _c
|
|
812
|
+
var _a, _b, _c;
|
|
792
813
|
const concepts = nonAbstractConcepts || this.getAllNonAbstractConcepts(role);
|
|
793
814
|
const periodTypes = rolePeriodTypes || new Set(
|
|
794
815
|
concepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
|
|
@@ -805,7 +826,7 @@ class XBRLFormBuilder {
|
|
|
805
826
|
removable: false
|
|
806
827
|
}];
|
|
807
828
|
}
|
|
808
|
-
let
|
|
829
|
+
let dimensionColumns = [];
|
|
809
830
|
if (((_a = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _a.length) === 1) {
|
|
810
831
|
const item = hypercubeRole.items[0];
|
|
811
832
|
console.log(`🔍 Processing hypercube item for role "${role.role}":`, {
|
|
@@ -814,43 +835,104 @@ class XBRLFormBuilder {
|
|
|
814
835
|
dimensions: item.dimensions.length
|
|
815
836
|
});
|
|
816
837
|
if (item.dimensions.length === 1) {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
conceptName: dimension.conceptName,
|
|
821
|
-
membersCount: dimension.members.length
|
|
822
|
-
});
|
|
823
|
-
if (dimension.members.length > 0) {
|
|
824
|
-
const axisLabel = ((_c = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _c.label) || dimension.conceptName;
|
|
825
|
-
const firstMember = dimension.members[0];
|
|
826
|
-
const memberLabel = ((_d = firstMember.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _d.label) || firstMember.conceptName;
|
|
827
|
-
dimensionInfo = {
|
|
828
|
-
axisId: dimension.id,
|
|
829
|
-
axisLabel,
|
|
830
|
-
memberId: firstMember.id,
|
|
831
|
-
memberLabel,
|
|
832
|
-
dimensionKey: `${axisLabel} | ${memberLabel}`,
|
|
833
|
-
dimensionIdKey: `${dimension.id} | ${firstMember.id}`
|
|
834
|
-
};
|
|
835
|
-
console.log(`📊 Generated dimension info:`, dimensionInfo);
|
|
836
|
-
}
|
|
837
|
-
} else {
|
|
838
|
-
console.log(`⚠️ Multiple dimensions found (${item.dimensions.length}), skipping for now`);
|
|
838
|
+
dimensionColumns = this.generateSingleDimensionColumns(item.dimensions[0], periodStartDate, periodEndDate, periodTypes);
|
|
839
|
+
} else if (item.dimensions.length > 1) {
|
|
840
|
+
dimensionColumns = this.generateMultiDimensionColumns(item.dimensions, periodStartDate, periodEndDate, periodTypes);
|
|
839
841
|
}
|
|
840
|
-
} else if (((
|
|
842
|
+
} else if (((_c = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _c.length) && hypercubeRole.items.length > 1) {
|
|
841
843
|
console.log(`⚠️ Multiple items found (${hypercubeRole.items.length}), skipping for now`);
|
|
842
844
|
}
|
|
843
845
|
console.log(`📅 Found period types: ${Array.from(periodTypes).join(", ")}`);
|
|
844
846
|
const columns = [];
|
|
847
|
+
if (dimensionColumns.length > 0) {
|
|
848
|
+
columns.push(...dimensionColumns);
|
|
849
|
+
} else {
|
|
850
|
+
if (periodTypes.size === 0) {
|
|
851
|
+
console.log("📅 No period types found, using default column");
|
|
852
|
+
columns.push({
|
|
853
|
+
id: "default",
|
|
854
|
+
title: "Value",
|
|
855
|
+
description: "Default value column",
|
|
856
|
+
type: "base",
|
|
857
|
+
order: 0,
|
|
858
|
+
removable: false
|
|
859
|
+
});
|
|
860
|
+
} else if (periodTypes.size === 1 && periodTypes.has("instant")) {
|
|
861
|
+
console.log("📅 All concepts are instant type, creating single column");
|
|
862
|
+
columns.push({
|
|
863
|
+
id: "instant",
|
|
864
|
+
title: `As of ${this.formatDateForDisplay(periodStartDate)}`,
|
|
865
|
+
description: `Values as of ${periodStartDate}`,
|
|
866
|
+
type: "base",
|
|
867
|
+
order: 0,
|
|
868
|
+
removable: false
|
|
869
|
+
});
|
|
870
|
+
} else if (periodTypes.size === 1 && periodTypes.has("duration")) {
|
|
871
|
+
console.log("📅 All concepts are duration type, creating single column with period range");
|
|
872
|
+
columns.push({
|
|
873
|
+
id: "duration",
|
|
874
|
+
title: `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`,
|
|
875
|
+
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
876
|
+
type: "base",
|
|
877
|
+
order: 0,
|
|
878
|
+
removable: false
|
|
879
|
+
});
|
|
880
|
+
} else {
|
|
881
|
+
console.log("📅 Mixed period types found, creating both duration and instant columns");
|
|
882
|
+
columns.push({
|
|
883
|
+
id: "duration",
|
|
884
|
+
title: `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`,
|
|
885
|
+
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
886
|
+
type: "base",
|
|
887
|
+
order: 0,
|
|
888
|
+
removable: false
|
|
889
|
+
});
|
|
890
|
+
columns.push({
|
|
891
|
+
id: "instant",
|
|
892
|
+
title: `As of ${this.formatDateForDisplay(periodStartDate)}`,
|
|
893
|
+
description: `Values as of ${periodStartDate}`,
|
|
894
|
+
type: "base",
|
|
895
|
+
order: 1,
|
|
896
|
+
removable: false
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
console.log(`📊 Generated ${columns.length} columns for role "${role.role}":`, columns.map((c2) => c2.title));
|
|
901
|
+
return columns;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Generate columns for single dimension scenarios
|
|
905
|
+
*/
|
|
906
|
+
static generateSingleDimensionColumns(dimension, periodStartDate, periodEndDate, periodTypes) {
|
|
907
|
+
var _a, _b;
|
|
908
|
+
console.log(`📊 Found single dimension:`, {
|
|
909
|
+
id: dimension.id,
|
|
910
|
+
conceptName: dimension.conceptName,
|
|
911
|
+
membersCount: dimension.members.length
|
|
912
|
+
});
|
|
913
|
+
if (dimension.members.length === 0) {
|
|
914
|
+
return [];
|
|
915
|
+
}
|
|
916
|
+
const axisLabel = ((_a = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a.label) || dimension.conceptName;
|
|
917
|
+
const firstMember = dimension.members[0];
|
|
918
|
+
const memberLabel = ((_b = firstMember.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _b.label) || firstMember.conceptName;
|
|
919
|
+
const dimensionInfo = {
|
|
920
|
+
axisId: dimension.id,
|
|
921
|
+
axisLabel,
|
|
922
|
+
memberId: firstMember.id,
|
|
923
|
+
memberLabel,
|
|
924
|
+
dimensionKey: `${axisLabel} | ${memberLabel}`,
|
|
925
|
+
dimensionIdKey: `${dimension.id} | ${firstMember.id}`
|
|
926
|
+
};
|
|
927
|
+
console.log(`📊 Generated dimension info:`, dimensionInfo);
|
|
928
|
+
const columns = [];
|
|
845
929
|
if (periodTypes.size === 0) {
|
|
846
|
-
console.log("📅 No period types found, using default column");
|
|
847
|
-
const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel}` : "Value";
|
|
848
930
|
columns.push({
|
|
849
931
|
id: "default",
|
|
850
|
-
title:
|
|
932
|
+
title: dimensionInfo.memberLabel,
|
|
851
933
|
description: "Default value column",
|
|
852
|
-
type:
|
|
853
|
-
dimensionData:
|
|
934
|
+
type: "dimension",
|
|
935
|
+
dimensionData: {
|
|
854
936
|
dimensionId: "default",
|
|
855
937
|
axisId: dimensionInfo.axisId,
|
|
856
938
|
memberId: dimensionInfo.memberId,
|
|
@@ -860,19 +942,17 @@ class XBRLFormBuilder {
|
|
|
860
942
|
axisLabel: dimensionInfo.axisLabel,
|
|
861
943
|
memberKey: dimensionInfo.dimensionKey,
|
|
862
944
|
dimensionIdKey: dimensionInfo.dimensionIdKey
|
|
863
|
-
}
|
|
945
|
+
},
|
|
864
946
|
order: 0,
|
|
865
947
|
removable: false
|
|
866
948
|
});
|
|
867
949
|
} else if (periodTypes.size === 1 && periodTypes.has("instant")) {
|
|
868
|
-
console.log("📅 All concepts are instant type, creating single column");
|
|
869
|
-
const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)})` : `As of ${this.formatDateForDisplay(periodStartDate)}`;
|
|
870
950
|
columns.push({
|
|
871
951
|
id: "instant",
|
|
872
|
-
title:
|
|
952
|
+
title: `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)})`,
|
|
873
953
|
description: `Values as of ${periodStartDate}`,
|
|
874
|
-
type:
|
|
875
|
-
dimensionData:
|
|
954
|
+
type: "dimension",
|
|
955
|
+
dimensionData: {
|
|
876
956
|
dimensionId: "instant",
|
|
877
957
|
axisId: dimensionInfo.axisId,
|
|
878
958
|
memberId: dimensionInfo.memberId,
|
|
@@ -882,19 +962,17 @@ class XBRLFormBuilder {
|
|
|
882
962
|
axisLabel: dimensionInfo.axisLabel,
|
|
883
963
|
memberKey: dimensionInfo.dimensionKey,
|
|
884
964
|
dimensionIdKey: dimensionInfo.dimensionIdKey
|
|
885
|
-
}
|
|
965
|
+
},
|
|
886
966
|
order: 0,
|
|
887
967
|
removable: false
|
|
888
968
|
});
|
|
889
969
|
} else if (periodTypes.size === 1 && periodTypes.has("duration")) {
|
|
890
|
-
console.log("📅 All concepts are duration type, creating single column with period range");
|
|
891
|
-
const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})` : `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`;
|
|
892
970
|
columns.push({
|
|
893
971
|
id: "duration",
|
|
894
|
-
title:
|
|
972
|
+
title: `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})`,
|
|
895
973
|
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
896
|
-
type:
|
|
897
|
-
dimensionData:
|
|
974
|
+
type: "dimension",
|
|
975
|
+
dimensionData: {
|
|
898
976
|
dimensionId: "duration",
|
|
899
977
|
axisId: dimensionInfo.axisId,
|
|
900
978
|
memberId: dimensionInfo.memberId,
|
|
@@ -904,21 +982,18 @@ class XBRLFormBuilder {
|
|
|
904
982
|
axisLabel: dimensionInfo.axisLabel,
|
|
905
983
|
memberKey: dimensionInfo.dimensionKey,
|
|
906
984
|
dimensionIdKey: dimensionInfo.dimensionIdKey
|
|
907
|
-
}
|
|
985
|
+
},
|
|
908
986
|
order: 0,
|
|
909
987
|
removable: false
|
|
910
988
|
});
|
|
911
|
-
console.log("📅 Created duration column:", columns.map((c2) => ({ id: c2.id, title: c2.title })));
|
|
912
989
|
} else {
|
|
913
|
-
console.log("📅 Mixed period types found, creating single column with period range");
|
|
914
|
-
const columnTitle = dimensionInfo ? `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})` : `${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)}`;
|
|
915
990
|
columns.push({
|
|
916
|
-
id: "
|
|
917
|
-
title:
|
|
991
|
+
id: "duration",
|
|
992
|
+
title: `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})`,
|
|
918
993
|
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
919
|
-
type:
|
|
920
|
-
dimensionData:
|
|
921
|
-
dimensionId: "
|
|
994
|
+
type: "dimension",
|
|
995
|
+
dimensionData: {
|
|
996
|
+
dimensionId: "duration",
|
|
922
997
|
axisId: dimensionInfo.axisId,
|
|
923
998
|
memberId: dimensionInfo.memberId,
|
|
924
999
|
memberValue: dimensionInfo.memberLabel,
|
|
@@ -927,17 +1002,183 @@ class XBRLFormBuilder {
|
|
|
927
1002
|
axisLabel: dimensionInfo.axisLabel,
|
|
928
1003
|
memberKey: dimensionInfo.dimensionKey,
|
|
929
1004
|
dimensionIdKey: dimensionInfo.dimensionIdKey
|
|
930
|
-
}
|
|
1005
|
+
},
|
|
931
1006
|
order: 0,
|
|
932
1007
|
removable: false
|
|
933
1008
|
});
|
|
1009
|
+
columns.push({
|
|
1010
|
+
id: "instant",
|
|
1011
|
+
title: `${dimensionInfo.memberLabel} (${this.formatDateForDisplay(periodStartDate)})`,
|
|
1012
|
+
description: `Values as of ${periodStartDate}`,
|
|
1013
|
+
type: "dimension",
|
|
1014
|
+
dimensionData: {
|
|
1015
|
+
dimensionId: "instant",
|
|
1016
|
+
axisId: dimensionInfo.axisId,
|
|
1017
|
+
memberId: dimensionInfo.memberId,
|
|
1018
|
+
memberValue: dimensionInfo.memberLabel,
|
|
1019
|
+
memberLabel: dimensionInfo.memberLabel,
|
|
1020
|
+
axis: dimensionInfo.axisLabel,
|
|
1021
|
+
axisLabel: dimensionInfo.axisLabel,
|
|
1022
|
+
memberKey: dimensionInfo.dimensionKey,
|
|
1023
|
+
dimensionIdKey: dimensionInfo.dimensionIdKey
|
|
1024
|
+
},
|
|
1025
|
+
order: 1,
|
|
1026
|
+
removable: false
|
|
1027
|
+
});
|
|
934
1028
|
}
|
|
935
|
-
if (dimensionInfo) {
|
|
936
|
-
console.log(`📊 Applied dimension to ${columns.length} columns: ${dimensionInfo.dimensionKey}`);
|
|
937
|
-
}
|
|
938
|
-
console.log(`📊 Generated ${columns.length} columns for role "${role.role}":`, columns.map((c2) => c2.title));
|
|
939
1029
|
return columns;
|
|
940
1030
|
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Generate columns for multi-dimension scenarios - creates combinations of all dimension members
|
|
1033
|
+
*/
|
|
1034
|
+
static generateMultiDimensionColumns(dimensions, periodStartDate, periodEndDate, periodTypes) {
|
|
1035
|
+
console.log(`📊 Processing ${dimensions.length} dimensions for multi-dimensional columns`);
|
|
1036
|
+
const dimensionInfos = dimensions.map((dimension) => {
|
|
1037
|
+
var _a;
|
|
1038
|
+
const axisLabel = ((_a = dimension.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a.label) || dimension.conceptName;
|
|
1039
|
+
const allMembers = this.getAllDimensionMembers(dimension.members);
|
|
1040
|
+
return {
|
|
1041
|
+
id: dimension.id,
|
|
1042
|
+
axisLabel,
|
|
1043
|
+
members: allMembers.map((member) => {
|
|
1044
|
+
var _a2;
|
|
1045
|
+
return {
|
|
1046
|
+
id: member.id,
|
|
1047
|
+
label: ((_a2 = member.labels.find((l2) => l2.role === "http://www.xbrl.org/2003/role/label")) == null ? void 0 : _a2.label) || member.conceptName
|
|
1048
|
+
};
|
|
1049
|
+
})
|
|
1050
|
+
};
|
|
1051
|
+
});
|
|
1052
|
+
const combinations = this.generateDimensionCombinations(dimensionInfos);
|
|
1053
|
+
console.log(`📊 Generated ${combinations.length} dimension combinations`);
|
|
1054
|
+
const columns = [];
|
|
1055
|
+
combinations.forEach((combination, index) => {
|
|
1056
|
+
const columnTitle = combination.map((c2) => c2.memberLabel).join(" | ");
|
|
1057
|
+
const dimensionData = {
|
|
1058
|
+
dimensionId: `multi_${index}`,
|
|
1059
|
+
memberValue: columnTitle,
|
|
1060
|
+
// Required field
|
|
1061
|
+
memberLabel: columnTitle,
|
|
1062
|
+
// Required field
|
|
1063
|
+
combinations: combination.map((c2) => ({
|
|
1064
|
+
axisId: c2.axisId,
|
|
1065
|
+
axisLabel: c2.axisLabel,
|
|
1066
|
+
memberId: c2.memberId,
|
|
1067
|
+
memberLabel: c2.memberLabel
|
|
1068
|
+
})),
|
|
1069
|
+
memberKey: columnTitle,
|
|
1070
|
+
dimensionIdKey: combination.map((c2) => `${c2.axisId}|${c2.memberId}`).join("::")
|
|
1071
|
+
};
|
|
1072
|
+
if (periodTypes.size === 0 || periodTypes.size === 1 && periodTypes.has("duration")) {
|
|
1073
|
+
columns.push({
|
|
1074
|
+
id: `duration_${index}`,
|
|
1075
|
+
title: `${columnTitle} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})`,
|
|
1076
|
+
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
1077
|
+
type: "dimension",
|
|
1078
|
+
dimensionData: {
|
|
1079
|
+
...dimensionData,
|
|
1080
|
+
dimensionId: `duration_${index}`
|
|
1081
|
+
},
|
|
1082
|
+
order: index * 2,
|
|
1083
|
+
removable: false
|
|
1084
|
+
});
|
|
1085
|
+
} else if (periodTypes.size === 1 && periodTypes.has("instant")) {
|
|
1086
|
+
columns.push({
|
|
1087
|
+
id: `instant_${index}`,
|
|
1088
|
+
title: `${columnTitle} (${this.formatDateForDisplay(periodStartDate)})`,
|
|
1089
|
+
description: `Values as of ${periodStartDate}`,
|
|
1090
|
+
type: "dimension",
|
|
1091
|
+
dimensionData: {
|
|
1092
|
+
...dimensionData,
|
|
1093
|
+
dimensionId: `instant_${index}`
|
|
1094
|
+
},
|
|
1095
|
+
order: index * 2,
|
|
1096
|
+
removable: false
|
|
1097
|
+
});
|
|
1098
|
+
} else {
|
|
1099
|
+
columns.push({
|
|
1100
|
+
id: `duration_${index}`,
|
|
1101
|
+
title: `${columnTitle} (${this.formatDateForDisplay(periodStartDate)} / ${this.formatDateForDisplay(periodEndDate)})`,
|
|
1102
|
+
description: `Period: ${periodStartDate} to ${periodEndDate}`,
|
|
1103
|
+
type: "dimension",
|
|
1104
|
+
dimensionData: {
|
|
1105
|
+
...dimensionData,
|
|
1106
|
+
dimensionId: `duration_${index}`
|
|
1107
|
+
},
|
|
1108
|
+
order: index * 2,
|
|
1109
|
+
removable: false
|
|
1110
|
+
});
|
|
1111
|
+
columns.push({
|
|
1112
|
+
id: `instant_${index}`,
|
|
1113
|
+
title: `${columnTitle} (${this.formatDateForDisplay(periodStartDate)})`,
|
|
1114
|
+
description: `Values as of ${periodStartDate}`,
|
|
1115
|
+
type: "dimension",
|
|
1116
|
+
dimensionData: {
|
|
1117
|
+
...dimensionData,
|
|
1118
|
+
dimensionId: `instant_${index}`
|
|
1119
|
+
},
|
|
1120
|
+
order: index * 2 + 1,
|
|
1121
|
+
removable: false
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
console.log(`📊 Generated ${columns.length} multi-dimensional columns`);
|
|
1126
|
+
return columns;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Get all members including children recursively
|
|
1130
|
+
*/
|
|
1131
|
+
static getAllDimensionMembers(members) {
|
|
1132
|
+
const allMembers = [];
|
|
1133
|
+
members.forEach((member) => {
|
|
1134
|
+
allMembers.push(member);
|
|
1135
|
+
if (member.children && member.children.length > 0) {
|
|
1136
|
+
allMembers.push(...this.getAllDimensionMembers(member.children));
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
return allMembers;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Generate all combinations of dimension members
|
|
1143
|
+
*/
|
|
1144
|
+
static generateDimensionCombinations(dimensionInfos) {
|
|
1145
|
+
if (dimensionInfos.length === 0)
|
|
1146
|
+
return [];
|
|
1147
|
+
if (dimensionInfos.length === 1) {
|
|
1148
|
+
return dimensionInfos[0].members.map((member) => [{
|
|
1149
|
+
axisId: dimensionInfos[0].id,
|
|
1150
|
+
axisLabel: dimensionInfos[0].axisLabel,
|
|
1151
|
+
memberId: member.id,
|
|
1152
|
+
memberLabel: member.label
|
|
1153
|
+
}]);
|
|
1154
|
+
}
|
|
1155
|
+
const [firstDimension, ...restDimensions] = dimensionInfos;
|
|
1156
|
+
const restCombinations = this.generateDimensionCombinations(restDimensions);
|
|
1157
|
+
const combinations = [];
|
|
1158
|
+
firstDimension.members.forEach((member) => {
|
|
1159
|
+
if (restCombinations.length === 0) {
|
|
1160
|
+
combinations.push([{
|
|
1161
|
+
axisId: firstDimension.id,
|
|
1162
|
+
axisLabel: firstDimension.axisLabel,
|
|
1163
|
+
memberId: member.id,
|
|
1164
|
+
memberLabel: member.label
|
|
1165
|
+
}]);
|
|
1166
|
+
} else {
|
|
1167
|
+
restCombinations.forEach((restCombination) => {
|
|
1168
|
+
combinations.push([
|
|
1169
|
+
{
|
|
1170
|
+
axisId: firstDimension.id,
|
|
1171
|
+
axisLabel: firstDimension.axisLabel,
|
|
1172
|
+
memberId: member.id,
|
|
1173
|
+
memberLabel: member.label
|
|
1174
|
+
},
|
|
1175
|
+
...restCombination
|
|
1176
|
+
]);
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
return combinations;
|
|
1181
|
+
}
|
|
941
1182
|
/**
|
|
942
1183
|
* Format date for display in column headers
|
|
943
1184
|
*/
|