jupiter-dynamic-forms 1.9.6 → 1.9.8

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.mjs CHANGED
@@ -559,8 +559,9 @@ class XBRLFormBuilder {
559
559
  * @param periodStartDate - Start date for the reporting period
560
560
  * @param periodEndDate - End date for the reporting period
561
561
  * @param language - ISO language code for labels (e.g., 'en', 'nl', 'de')
562
+ * @param periodPreferences - User preferences for which period columns to show per role
562
563
  */
563
- static buildFormSchema(xbrlInput, periodStartDate, periodEndDate, language = "en") {
564
+ static buildFormSchema(xbrlInput, periodStartDate, periodEndDate, language = "en", periodPreferences) {
564
565
  var _a;
565
566
  if (!xbrlInput.presentation || xbrlInput.presentation.length === 0) {
566
567
  throw new Error("XBRL presentation data is required");
@@ -572,7 +573,7 @@ class XBRLFormBuilder {
572
573
  return a2.role.localeCompare(b2.role);
573
574
  });
574
575
  sortedRoles.forEach((role) => {
575
- const section = this.buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language);
576
+ const section = this.buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language, periodPreferences);
576
577
  this.assignFieldColumnIds(section);
577
578
  sections.push(section);
578
579
  });
@@ -587,7 +588,7 @@ class XBRLFormBuilder {
587
588
  /**
588
589
  * Build a form section from a presentation role
589
590
  */
590
- static buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language = "en") {
591
+ static buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language = "en", periodPreferences) {
591
592
  var _a;
592
593
  const title = this.extractRoleTitle(role.role);
593
594
  const nonAbstractConcepts = this.getAllNonAbstractConcepts(role);
@@ -595,7 +596,8 @@ class XBRLFormBuilder {
595
596
  nonAbstractConcepts.filter((concept) => concept.periodType).map((concept) => concept.periodType)
596
597
  );
597
598
  const hypercubeRole = hypercubeData == null ? void 0 : hypercubeData.roles.find((hr) => hr.roleId === role.id);
598
- const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes);
599
+ const rolePreferences = periodPreferences == null ? void 0 : periodPreferences[role.id];
600
+ const columns = this.generateDefaultColumnsForRole(role, periodStartDate || "2025-01-01", periodEndDate || "2025-12-31", hypercubeRole, nonAbstractConcepts, periodTypes, rolePreferences);
599
601
  const availableColumnIds = columns.map((col) => col.id);
600
602
  const roleInfo = { periodTypes, availableColumnIds };
601
603
  const conceptTrees = [];
@@ -617,7 +619,14 @@ class XBRLFormBuilder {
617
619
  metadata: {
618
620
  roleURI: role.roleURI,
619
621
  originalRole: role.role
620
- }
622
+ },
623
+ showPeriodControl: periodTypes.size > 1,
624
+ showPreviousYear: role.showPreviousYear === true,
625
+ // Read from presentation.json
626
+ instant: role.instant === true,
627
+ // Read from presentation.json
628
+ duration: role.duration === true
629
+ // Read from presentation.json
621
630
  };
622
631
  }
623
632
  /**
@@ -630,16 +639,23 @@ class XBRLFormBuilder {
630
639
  let columnIds = [];
631
640
  if ((roleInfo == null ? void 0 : roleInfo.availableColumnIds) && roleInfo.availableColumnIds.length > 0) {
632
641
  columnIds = roleInfo.availableColumnIds.filter((colId) => {
642
+ const isInstantColumn = colId.includes("instant") || colId === "instant";
643
+ const isDurationColumn = colId.includes("duration") || colId === "duration";
633
644
  if (concept.periodType === "instant") {
634
- return colId.includes("instant") || colId === "instant";
645
+ return isInstantColumn;
635
646
  } else if (concept.periodType === "duration") {
636
- return colId.includes("duration") || colId === "duration";
647
+ return isDurationColumn;
637
648
  } else {
638
- return true;
649
+ return !isInstantColumn && !isDurationColumn;
639
650
  }
640
651
  });
641
- if (columnIds.length === 0) {
642
- columnIds = roleInfo.availableColumnIds;
652
+ if (columnIds.length === 0 && roleInfo.availableColumnIds.length > 0) {
653
+ const hasPeriodColumns = roleInfo.availableColumnIds.some(
654
+ (colId) => colId.includes("instant") || colId.includes("duration")
655
+ );
656
+ if (!hasPeriodColumns) {
657
+ columnIds = roleInfo.availableColumnIds;
658
+ }
643
659
  }
644
660
  } else {
645
661
  if (!(roleInfo == null ? void 0 : roleInfo.periodTypes) || roleInfo.periodTypes.size === 0) {
@@ -685,6 +701,8 @@ class XBRLFormBuilder {
685
701
  name: concept.conceptName,
686
702
  label,
687
703
  description: `${concept.conceptName} (${concept.type})`,
704
+ type: concept.type,
705
+ // XBRL concept type for input field rendering
688
706
  level,
689
707
  children,
690
708
  fields,
@@ -834,7 +852,7 @@ class XBRLFormBuilder {
834
852
  /**
835
853
  * Generate default columns based on period types of non-abstract concepts in a role
836
854
  */
837
- static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes) {
855
+ static generateDefaultColumnsForRole(role, periodStartDate, periodEndDate, hypercubeRole, nonAbstractConcepts, rolePeriodTypes, periodPreferences) {
838
856
  var _a, _b;
839
857
  const concepts = nonAbstractConcepts || this.getAllNonAbstractConcepts(role);
840
858
  const periodTypes = rolePeriodTypes || new Set(
@@ -858,6 +876,9 @@ class XBRLFormBuilder {
858
876
  } else if (item.dimensions.length > 1) {
859
877
  dimensionColumns = this.generateMultiDimensionColumns(item.dimensions, periodStartDate, periodEndDate, periodTypes);
860
878
  }
879
+ if (periodPreferences) {
880
+ dimensionColumns = this.filterColumnsByPeriodPreferences(dimensionColumns, periodPreferences);
881
+ }
861
882
  } else if (((_b = hypercubeRole == null ? void 0 : hypercubeRole.items) == null ? void 0 : _b.length) && hypercubeRole.items.length > 1)
862
883
  ;
863
884
  const columns = [];
@@ -876,8 +897,8 @@ class XBRLFormBuilder {
876
897
  } else if (periodTypes.size === 1 && periodTypes.has("instant")) {
877
898
  columns.push({
878
899
  id: "instant",
879
- title: `Current`,
880
- description: `Values as of ${periodStartDate}`,
900
+ title: periodEndDate,
901
+ description: "",
881
902
  type: "base",
882
903
  order: 0,
883
904
  removable: false
@@ -885,8 +906,8 @@ class XBRLFormBuilder {
885
906
  } else if (periodTypes.size === 1 && periodTypes.has("duration")) {
886
907
  columns.push({
887
908
  id: "duration",
888
- title: `Current Period`,
889
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
909
+ title: `${periodStartDate} / ${periodEndDate}`,
910
+ description: "",
890
911
  type: "base",
891
912
  order: 0,
892
913
  removable: false
@@ -894,23 +915,122 @@ class XBRLFormBuilder {
894
915
  } else {
895
916
  columns.push({
896
917
  id: "duration",
897
- title: `Current Period`,
898
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
918
+ title: `${periodStartDate} / ${periodEndDate}`,
919
+ description: "",
899
920
  type: "base",
900
921
  order: 0,
901
922
  removable: false
902
923
  });
903
924
  columns.push({
904
925
  id: "instant",
905
- title: `Current`,
906
- description: `Values as of ${periodStartDate}`,
926
+ title: periodEndDate,
927
+ description: "",
907
928
  type: "base",
908
929
  order: 1,
909
930
  removable: false
910
931
  });
911
932
  }
912
933
  }
913
- return columns;
934
+ let filteredColumns = columns;
935
+ if (periodPreferences) {
936
+ filteredColumns = this.filterColumnsByPeriodPreferences(columns, periodPreferences);
937
+ }
938
+ if (periodPreferences == null ? void 0 : periodPreferences.showPreviousYear) {
939
+ const previousYearColumns = this.generatePreviousYearColumns(filteredColumns, periodStartDate, periodEndDate);
940
+ filteredColumns = [...filteredColumns, ...previousYearColumns];
941
+ }
942
+ return filteredColumns;
943
+ }
944
+ /**
945
+ * Calculate previous year date by subtracting one year
946
+ */
947
+ static getPreviousYearDate(dateString) {
948
+ try {
949
+ const date = new Date(dateString);
950
+ date.setFullYear(date.getFullYear() - 1);
951
+ return date.toISOString().split("T")[0];
952
+ } catch (error) {
953
+ console.error(`Error calculating previous year for date ${dateString}:`, error);
954
+ return dateString;
955
+ }
956
+ }
957
+ /**
958
+ * Generate previous year columns based on current year columns
959
+ */
960
+ static generatePreviousYearColumns(currentYearColumns, periodStartDate, periodEndDate) {
961
+ const previousYearColumns = [];
962
+ const prevStartDate = this.getPreviousYearDate(periodStartDate);
963
+ const prevEndDate = this.getPreviousYearDate(periodEndDate);
964
+ currentYearColumns.forEach((column, index) => {
965
+ let prevTitle = column.title;
966
+ let prevDescription = "";
967
+ let prevId = "";
968
+ if (column.dimensionData) {
969
+ prevTitle = column.title;
970
+ if (column.description && column.description.includes("/")) {
971
+ prevDescription = `${prevStartDate} / ${prevEndDate}`;
972
+ } else {
973
+ prevDescription = prevEndDate;
974
+ }
975
+ prevId = `${column.id}_prev`;
976
+ } else {
977
+ if (column.id === "instant" || column.id.includes("instant")) {
978
+ prevTitle = prevEndDate;
979
+ prevDescription = "";
980
+ prevId = `instant_prev_${index}`;
981
+ } else if (column.id === "duration" || column.id.includes("duration")) {
982
+ prevTitle = `${prevStartDate} / ${prevEndDate}`;
983
+ prevDescription = "";
984
+ prevId = `duration_prev_${index}`;
985
+ } else if (column.title.includes("/")) {
986
+ prevTitle = `${prevStartDate} / ${prevEndDate}`;
987
+ prevDescription = "";
988
+ prevId = `${column.id}_prev`;
989
+ } else {
990
+ prevTitle = prevEndDate;
991
+ prevDescription = "";
992
+ prevId = `${column.id}_prev`;
993
+ }
994
+ }
995
+ previousYearColumns.push({
996
+ ...column,
997
+ id: prevId,
998
+ title: prevTitle,
999
+ description: prevDescription,
1000
+ order: column.order + 100,
1001
+ // Place after current year columns
1002
+ removable: true,
1003
+ periodStartDate: prevStartDate,
1004
+ // Set previous year start date
1005
+ periodEndDate: prevEndDate,
1006
+ // Set previous year end date
1007
+ dimensionData: column.dimensionData ? {
1008
+ ...column.dimensionData,
1009
+ dimensionId: `${column.dimensionData.dimensionId}_prev`
1010
+ } : void 0
1011
+ });
1012
+ });
1013
+ return previousYearColumns;
1014
+ }
1015
+ /**
1016
+ * Filter columns based on user's period preferences
1017
+ */
1018
+ static filterColumnsByPeriodPreferences(columns, preferences) {
1019
+ return columns.filter((column) => {
1020
+ var _a, _b, _c, _d;
1021
+ const isDuration = column.id.includes("duration") || ((_b = (_a = column.dimensionData) == null ? void 0 : _a.dimensionId) == null ? void 0 : _b.includes("duration"));
1022
+ const isInstant = column.id.includes("instant") || ((_d = (_c = column.dimensionData) == null ? void 0 : _c.dimensionId) == null ? void 0 : _d.includes("instant"));
1023
+ if (!isDuration && !isInstant) {
1024
+ return true;
1025
+ }
1026
+ if (isDuration && !preferences.showDuration) {
1027
+ return false;
1028
+ }
1029
+ if (isInstant && !preferences.showInstant) {
1030
+ return false;
1031
+ }
1032
+ return true;
1033
+ });
914
1034
  }
915
1035
  /**
916
1036
  * Generate columns for single dimension scenarios
@@ -959,7 +1079,7 @@ class XBRLFormBuilder {
959
1079
  columns2.push({
960
1080
  id: "typed-instant",
961
1081
  title: `${axisLabel2} [Typed Input Available]`,
962
- description: `Typed values as of ${periodStartDate}`,
1082
+ description: periodEndDate,
963
1083
  type: "dimension",
964
1084
  dimensionData: {
965
1085
  dimensionId: "typed-instant",
@@ -987,7 +1107,7 @@ class XBRLFormBuilder {
987
1107
  columns2.push({
988
1108
  id: "typed-duration",
989
1109
  title: `${axisLabel2} [Typed Input Available]`,
990
- description: `Typed values for period ${periodStartDate} to ${periodEndDate}`,
1110
+ description: `${periodStartDate} / ${periodEndDate}`,
991
1111
  type: "dimension",
992
1112
  dimensionData: {
993
1113
  dimensionId: "typed-duration",
@@ -1015,7 +1135,7 @@ class XBRLFormBuilder {
1015
1135
  columns2.push({
1016
1136
  id: "typed-duration",
1017
1137
  title: `${axisLabel2} [Typed Input Available]`,
1018
- description: `Typed values for period ${periodStartDate} to ${periodEndDate}`,
1138
+ description: `${periodStartDate} / ${periodEndDate}`,
1019
1139
  type: "dimension",
1020
1140
  dimensionData: {
1021
1141
  dimensionId: "typed-duration",
@@ -1042,7 +1162,7 @@ class XBRLFormBuilder {
1042
1162
  columns2.push({
1043
1163
  id: "typed-instant",
1044
1164
  title: `${axisLabel2} [Typed Input Available]`,
1045
- description: `Typed values as of ${periodStartDate}`,
1165
+ description: periodEndDate,
1046
1166
  type: "dimension",
1047
1167
  dimensionData: {
1048
1168
  dimensionId: "typed-instant",
@@ -1111,7 +1231,7 @@ class XBRLFormBuilder {
1111
1231
  columns.push({
1112
1232
  id: "instant",
1113
1233
  title: `${dimensionInfo.memberLabel}`,
1114
- description: `Values as of ${periodStartDate}`,
1234
+ description: periodEndDate,
1115
1235
  type: "dimension",
1116
1236
  dimensionData: {
1117
1237
  dimensionId: "instant",
@@ -1131,7 +1251,7 @@ class XBRLFormBuilder {
1131
1251
  columns.push({
1132
1252
  id: "duration",
1133
1253
  title: `${dimensionInfo.memberLabel}`,
1134
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
1254
+ description: `${periodStartDate} / ${periodEndDate}`,
1135
1255
  type: "dimension",
1136
1256
  dimensionData: {
1137
1257
  dimensionId: "duration",
@@ -1151,7 +1271,7 @@ class XBRLFormBuilder {
1151
1271
  columns.push({
1152
1272
  id: "duration",
1153
1273
  title: `${dimensionInfo.memberLabel}`,
1154
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
1274
+ description: `${periodStartDate} / ${periodEndDate}`,
1155
1275
  type: "dimension",
1156
1276
  dimensionData: {
1157
1277
  dimensionId: "duration",
@@ -1170,7 +1290,7 @@ class XBRLFormBuilder {
1170
1290
  columns.push({
1171
1291
  id: "instant",
1172
1292
  title: `${dimensionInfo.memberLabel}`,
1173
- description: `Values as of ${periodStartDate}`,
1293
+ description: periodEndDate,
1174
1294
  type: "dimension",
1175
1295
  dimensionData: {
1176
1296
  dimensionId: "instant",
@@ -1271,7 +1391,7 @@ class XBRLFormBuilder {
1271
1391
  columns.push({
1272
1392
  id: `duration_${index}`,
1273
1393
  title: `${columnTitle}`,
1274
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
1394
+ description: `${periodStartDate} / ${periodEndDate}`,
1275
1395
  type: "dimension",
1276
1396
  dimensionData: {
1277
1397
  ...dimensionData,
@@ -1284,7 +1404,7 @@ class XBRLFormBuilder {
1284
1404
  columns.push({
1285
1405
  id: `instant_${index}`,
1286
1406
  title: `${columnTitle}`,
1287
- description: `Values as of ${periodStartDate}`,
1407
+ description: periodEndDate,
1288
1408
  type: "dimension",
1289
1409
  dimensionData: {
1290
1410
  ...dimensionData,
@@ -1297,7 +1417,7 @@ class XBRLFormBuilder {
1297
1417
  columns.push({
1298
1418
  id: `duration_${index}`,
1299
1419
  title: `${columnTitle}`,
1300
- description: `Period: ${periodStartDate} to ${periodEndDate}`,
1420
+ description: `${periodStartDate} / ${periodEndDate}`,
1301
1421
  type: "dimension",
1302
1422
  dimensionData: {
1303
1423
  ...dimensionData,
@@ -1309,7 +1429,7 @@ class XBRLFormBuilder {
1309
1429
  columns.push({
1310
1430
  id: `instant_${index}`,
1311
1431
  title: `${columnTitle}`,
1312
- description: `Values as of ${periodStartDate}`,
1432
+ description: periodEndDate,
1313
1433
  type: "dimension",
1314
1434
  dimensionData: {
1315
1435
  ...dimensionData,
@@ -1438,6 +1558,249 @@ class XBRLFormBuilder {
1438
1558
  }];
1439
1559
  }
1440
1560
  }
1561
+ const TYPE_INPUT_MAP = {
1562
+ // ==========================================
1563
+ // Dutch XBRL Types (nl-types namespace)
1564
+ // ==========================================
1565
+ // Text area for long-form explanations
1566
+ "nl-types:formattedExplanationItemType": {
1567
+ fieldType: "textarea",
1568
+ placeholder: "Enter detailed explanation..."
1569
+ },
1570
+ // Monetary values without decimals (whole numbers only)
1571
+ "nl-types:monetaryNoDecimals20ItemType": {
1572
+ fieldType: "number",
1573
+ htmlInputType: "number",
1574
+ allowDecimals: false,
1575
+ step: 1,
1576
+ placeholder: "Enter amount (no decimals)"
1577
+ },
1578
+ // ==========================================
1579
+ // Standard XBRL Types (xbrli namespace)
1580
+ // ==========================================
1581
+ // Monetary with decimals
1582
+ "xbrli:monetaryItemType": {
1583
+ fieldType: "currency",
1584
+ htmlInputType: "number",
1585
+ allowDecimals: true,
1586
+ step: 0.01,
1587
+ placeholder: "0.00"
1588
+ },
1589
+ // String/text types
1590
+ "xbrli:stringItemType": {
1591
+ fieldType: "text",
1592
+ htmlInputType: "text",
1593
+ placeholder: "Enter text"
1594
+ },
1595
+ // Date types
1596
+ "xbrli:dateItemType": {
1597
+ fieldType: "date",
1598
+ htmlInputType: "date"
1599
+ },
1600
+ "xbrli:dateTimeItemType": {
1601
+ fieldType: "datetime",
1602
+ htmlInputType: "datetime-local"
1603
+ },
1604
+ // Numeric types - integers
1605
+ "xbrli:integerItemType": {
1606
+ fieldType: "integer",
1607
+ htmlInputType: "number",
1608
+ allowDecimals: false,
1609
+ step: 1,
1610
+ placeholder: "Enter whole number"
1611
+ },
1612
+ "xbrli:nonNegativeIntegerItemType": {
1613
+ fieldType: "integer",
1614
+ htmlInputType: "number",
1615
+ allowDecimals: false,
1616
+ min: 0,
1617
+ step: 1,
1618
+ placeholder: "Enter positive number"
1619
+ },
1620
+ "xbrli:positiveIntegerItemType": {
1621
+ fieldType: "integer",
1622
+ htmlInputType: "number",
1623
+ allowDecimals: false,
1624
+ min: 1,
1625
+ step: 1,
1626
+ placeholder: "Enter positive number"
1627
+ },
1628
+ // Numeric types - decimals
1629
+ "xbrli:decimalItemType": {
1630
+ fieldType: "decimal",
1631
+ htmlInputType: "number",
1632
+ allowDecimals: true,
1633
+ step: "any",
1634
+ placeholder: "Enter decimal value"
1635
+ },
1636
+ // Shares (typically whole numbers or with limited decimals)
1637
+ "xbrli:sharesItemType": {
1638
+ fieldType: "number",
1639
+ htmlInputType: "number",
1640
+ allowDecimals: true,
1641
+ min: 0,
1642
+ step: 0.01,
1643
+ placeholder: "Enter number of shares"
1644
+ },
1645
+ "xbrli:shares": {
1646
+ fieldType: "number",
1647
+ htmlInputType: "number",
1648
+ allowDecimals: true,
1649
+ min: 0,
1650
+ step: 0.01,
1651
+ placeholder: "Enter number of shares"
1652
+ },
1653
+ // Year (gYear)
1654
+ "xbrli:gYearItemType": {
1655
+ fieldType: "number",
1656
+ htmlInputType: "number",
1657
+ allowDecimals: false,
1658
+ min: 1900,
1659
+ max: 2100,
1660
+ step: 1,
1661
+ placeholder: "YYYY"
1662
+ },
1663
+ // Boolean types
1664
+ "xbrli:booleanItemType": {
1665
+ fieldType: "boolean"
1666
+ },
1667
+ // ==========================================
1668
+ // Percentage types
1669
+ // ==========================================
1670
+ "xbrli:pureItemType": {
1671
+ fieldType: "percentage",
1672
+ htmlInputType: "number",
1673
+ allowDecimals: true,
1674
+ step: 0.01,
1675
+ placeholder: "Enter percentage"
1676
+ },
1677
+ "xbrli:percentItemType": {
1678
+ fieldType: "percentage",
1679
+ htmlInputType: "number",
1680
+ allowDecimals: true,
1681
+ step: 0.01,
1682
+ placeholder: "Enter percentage"
1683
+ },
1684
+ // ==========================================
1685
+ // Contact/Communication types
1686
+ // ==========================================
1687
+ "xbrli:emailItemType": {
1688
+ fieldType: "email",
1689
+ htmlInputType: "email",
1690
+ placeholder: "email@example.com"
1691
+ },
1692
+ "xbrli:urlItemType": {
1693
+ fieldType: "url",
1694
+ htmlInputType: "url",
1695
+ placeholder: "https://example.com"
1696
+ },
1697
+ "xbrli:telephoneItemType": {
1698
+ fieldType: "tel",
1699
+ htmlInputType: "tel",
1700
+ placeholder: "+1 (555) 000-0000"
1701
+ }
1702
+ };
1703
+ function getInputTypeForConceptType(conceptType) {
1704
+ if (!conceptType) {
1705
+ return {
1706
+ fieldType: "text",
1707
+ htmlInputType: "text",
1708
+ placeholder: "Enter value"
1709
+ };
1710
+ }
1711
+ if (TYPE_INPUT_MAP[conceptType]) {
1712
+ return TYPE_INPUT_MAP[conceptType];
1713
+ }
1714
+ const lowerType = conceptType.toLowerCase();
1715
+ if (lowerType.includes("monetary")) {
1716
+ if (lowerType.includes("nodecimals") || lowerType.includes("no-decimals")) {
1717
+ return {
1718
+ fieldType: "number",
1719
+ htmlInputType: "number",
1720
+ allowDecimals: false,
1721
+ step: 1,
1722
+ placeholder: "Enter amount (no decimals)"
1723
+ };
1724
+ }
1725
+ return {
1726
+ fieldType: "currency",
1727
+ htmlInputType: "number",
1728
+ allowDecimals: true,
1729
+ step: 0.01,
1730
+ placeholder: "0.00"
1731
+ };
1732
+ }
1733
+ if (lowerType.includes("explanation") || lowerType.includes("description") || lowerType.includes("notes") || lowerType.includes("formatted")) {
1734
+ return {
1735
+ fieldType: "textarea",
1736
+ placeholder: "Enter detailed information..."
1737
+ };
1738
+ }
1739
+ if (lowerType.includes("date")) {
1740
+ if (lowerType.includes("time")) {
1741
+ return {
1742
+ fieldType: "datetime",
1743
+ htmlInputType: "datetime-local"
1744
+ };
1745
+ }
1746
+ return {
1747
+ fieldType: "date",
1748
+ htmlInputType: "date"
1749
+ };
1750
+ }
1751
+ if (lowerType.includes("boolean") || lowerType.includes("bool")) {
1752
+ return {
1753
+ fieldType: "boolean"
1754
+ };
1755
+ }
1756
+ if (lowerType.includes("integer") || lowerType.includes("int")) {
1757
+ const isNonNegative = lowerType.includes("nonnegative") || lowerType.includes("non-negative");
1758
+ const isPositive = lowerType.includes("positive");
1759
+ return {
1760
+ fieldType: "integer",
1761
+ htmlInputType: "number",
1762
+ allowDecimals: false,
1763
+ min: isPositive ? 1 : isNonNegative ? 0 : void 0,
1764
+ step: 1,
1765
+ placeholder: "Enter whole number"
1766
+ };
1767
+ }
1768
+ if (lowerType.includes("decimal") || lowerType.includes("numeric") || lowerType.includes("number")) {
1769
+ return {
1770
+ fieldType: "decimal",
1771
+ htmlInputType: "number",
1772
+ allowDecimals: true,
1773
+ step: "any",
1774
+ placeholder: "Enter decimal value"
1775
+ };
1776
+ }
1777
+ if (lowerType.includes("percent") || lowerType.includes("pure")) {
1778
+ return {
1779
+ fieldType: "percentage",
1780
+ htmlInputType: "number",
1781
+ allowDecimals: true,
1782
+ step: 0.01,
1783
+ placeholder: "Enter percentage"
1784
+ };
1785
+ }
1786
+ return {
1787
+ fieldType: "text",
1788
+ htmlInputType: "text",
1789
+ placeholder: "Enter value"
1790
+ };
1791
+ }
1792
+ function isTextareaType(fieldType) {
1793
+ return fieldType === "textarea";
1794
+ }
1795
+ function isCheckboxType(fieldType) {
1796
+ return fieldType === "boolean";
1797
+ }
1798
+ function isNumericType(fieldType) {
1799
+ return ["number", "decimal", "integer", "currency", "percentage"].includes(fieldType);
1800
+ }
1801
+ function isSelectType(fieldType) {
1802
+ return fieldType === "select";
1803
+ }
1441
1804
  var __defProp$5 = Object.defineProperty;
1442
1805
  var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
1443
1806
  var __decorateClass$5 = (decorators, target, key, kind) => {
@@ -1526,78 +1889,89 @@ let JupiterFormField = class extends LitElement {
1526
1889
  const cssClass = `field-input ${hasErrors ? "error" : hasWarnings ? "warning" : ""}`;
1527
1890
  const fieldId = `${this.conceptId}__${this.columnId}`;
1528
1891
  const fieldName = `data[${this.conceptId}][${this.columnId}]`;
1529
- switch (this.field.type) {
1530
- case "textarea":
1531
- return html`
1532
- <textarea
1533
- id="${fieldId}"
1534
- name="${fieldName}"
1535
- class="${cssClass}"
1536
- .value="${this.value || ""}"
1537
- ?disabled="${this.disabled || this.field.disabled}"
1538
- placeholder="${this.field.placeholder || ""}"
1539
- @input="${this._handleInput}"
1540
- @focus="${this._handleFocus}"
1541
- @blur="${this._handleBlur}"
1542
- ></textarea>
1543
- `;
1544
- case "select":
1545
- return html`
1546
- <select
1547
- id="${fieldId}"
1548
- name="${fieldName}"
1549
- class="${cssClass}"
1550
- .value="${this.value || ""}"
1551
- ?disabled="${this.disabled || this.field.disabled}"
1552
- @change="${this._handleInput}"
1553
- @focus="${this._handleFocus}"
1554
- @blur="${this._handleBlur}"
1555
- >
1556
- <option value="">Select...</option>
1557
- ${(_a = this.field.options) == null ? void 0 : _a.map((option) => html`
1558
- <option
1559
- value="${option.value}"
1560
- ?disabled="${option.disabled}"
1561
- ?selected="${this.value === option.value}"
1562
- >
1563
- ${option.label}
1564
- </option>
1565
- `)}
1566
- </select>
1567
- `;
1568
- case "boolean":
1569
- return html`
1570
- <div class="checkbox-container">
1571
- <input
1572
- id="${fieldId}"
1573
- name="${fieldName}"
1574
- type="checkbox"
1575
- class="field-input"
1576
- .checked="${Boolean(this.value)}"
1577
- ?disabled="${this.disabled || this.field.disabled}"
1578
- @change="${this._handleInput}"
1579
- @focus="${this._handleFocus}"
1580
- @blur="${this._handleBlur}"
1581
- />
1582
- <span>${this.field.label}</span>
1583
- </div>
1584
- `;
1585
- default:
1586
- return html`
1892
+ const typeConfig = getInputTypeForConceptType(this.conceptType);
1893
+ if (this.conceptType)
1894
+ ;
1895
+ const effectiveFieldType = typeConfig.fieldType || this.field.type || "text";
1896
+ if (effectiveFieldType === "textarea" || isTextareaType(effectiveFieldType)) {
1897
+ return html`
1898
+ <textarea
1899
+ id="${fieldId}"
1900
+ name="${fieldName}"
1901
+ class="${cssClass}"
1902
+ .value="${this.value || ""}"
1903
+ ?disabled="${this.disabled || this.field.disabled}"
1904
+ placeholder="${typeConfig.placeholder || this.field.placeholder || ""}"
1905
+ @input="${this._handleInput}"
1906
+ @focus="${this._handleFocus}"
1907
+ @blur="${this._handleBlur}"
1908
+ ></textarea>
1909
+ `;
1910
+ }
1911
+ if (effectiveFieldType === "select" || this.field.type === "select") {
1912
+ return html`
1913
+ <select
1914
+ id="${fieldId}"
1915
+ name="${fieldName}"
1916
+ class="${cssClass}"
1917
+ .value="${this.value || ""}"
1918
+ ?disabled="${this.disabled || this.field.disabled}"
1919
+ @change="${this._handleInput}"
1920
+ @focus="${this._handleFocus}"
1921
+ @blur="${this._handleBlur}"
1922
+ >
1923
+ <option value="">Select...</option>
1924
+ ${(_a = this.field.options) == null ? void 0 : _a.map((option) => html`
1925
+ <option
1926
+ value="${option.value}"
1927
+ ?disabled="${option.disabled}"
1928
+ ?selected="${this.value === option.value}"
1929
+ >
1930
+ ${option.label}
1931
+ </option>
1932
+ `)}
1933
+ </select>
1934
+ `;
1935
+ }
1936
+ if (effectiveFieldType === "boolean" || isCheckboxType(effectiveFieldType)) {
1937
+ return html`
1938
+ <div class="checkbox-container">
1587
1939
  <input
1588
1940
  id="${fieldId}"
1589
1941
  name="${fieldName}"
1590
- type="${this._getInputType()}"
1591
- class="${cssClass}"
1592
- .value="${this.value || ""}"
1942
+ type="checkbox"
1943
+ class="field-input"
1944
+ .checked="${Boolean(this.value)}"
1593
1945
  ?disabled="${this.disabled || this.field.disabled}"
1594
- placeholder="${this.field.placeholder || ""}"
1595
- @input="${this._handleInput}"
1946
+ @change="${this._handleInput}"
1596
1947
  @focus="${this._handleFocus}"
1597
1948
  @blur="${this._handleBlur}"
1598
1949
  />
1599
- `;
1950
+ <span>${this.field.label}</span>
1951
+ </div>
1952
+ `;
1600
1953
  }
1954
+ const inputType = typeConfig.htmlInputType || this._getInputType();
1955
+ const step = typeConfig.step !== void 0 ? typeConfig.step : isNumericType(effectiveFieldType) ? "any" : void 0;
1956
+ const min = typeConfig.min;
1957
+ const max = typeConfig.max;
1958
+ return html`
1959
+ <input
1960
+ id="${fieldId}"
1961
+ name="${fieldName}"
1962
+ type="${inputType}"
1963
+ class="${cssClass}"
1964
+ .value="${this.value || ""}"
1965
+ ?disabled="${this.disabled || this.field.disabled}"
1966
+ placeholder="${typeConfig.placeholder || this.field.placeholder || ""}"
1967
+ step="${step !== void 0 ? step : ""}"
1968
+ min="${min !== void 0 ? min : ""}"
1969
+ max="${max !== void 0 ? max : ""}"
1970
+ @input="${this._handleInput}"
1971
+ @focus="${this._handleFocus}"
1972
+ @blur="${this._handleBlur}"
1973
+ />
1974
+ `;
1601
1975
  }
1602
1976
  _getInputType() {
1603
1977
  switch (this.field.type) {
@@ -1757,6 +2131,9 @@ __decorateClass$5([
1757
2131
  __decorateClass$5([
1758
2132
  n2({ type: String })
1759
2133
  ], JupiterFormField.prototype, "conceptId", 2);
2134
+ __decorateClass$5([
2135
+ n2({ type: String })
2136
+ ], JupiterFormField.prototype, "conceptType", 2);
1760
2137
  __decorateClass$5([
1761
2138
  n2({ type: String })
1762
2139
  ], JupiterFormField.prototype, "columnId", 2);
@@ -1868,6 +2245,7 @@ let JupiterConceptTree = class extends LitElement {
1868
2245
  <jupiter-form-field
1869
2246
  .field="${field}"
1870
2247
  .conceptId="${this.concept.id}"
2248
+ .conceptType="${this.concept.type}"
1871
2249
  .columnId="${column.id}"
1872
2250
  .value="${this._getFieldValue(field)}"
1873
2251
  .disabled="${this.disabled}"
@@ -2626,6 +3004,7 @@ let JupiterFormSection = class extends LitElement {
2626
3004
  this.locale = "en-US";
2627
3005
  this.isFirstSection = false;
2628
3006
  this.availableDimensions = [];
3007
+ this.hideHeader = false;
2629
3008
  this._expanded = true;
2630
3009
  this._showAddColumnDialog = false;
2631
3010
  this._sectionPeriodType = "duration";
@@ -2661,23 +3040,14 @@ let JupiterFormSection = class extends LitElement {
2661
3040
  return;
2662
3041
  }
2663
3042
  const periodTypes = new Set(nonAbstractConcepts.map((c2) => c2.periodType).filter(Boolean));
2664
- console.log(`🏷️ Section ${this.section.id}: Found period types:`, Array.from(periodTypes));
2665
- console.log(
2666
- `📝 Section ${this.section.id}: Non-abstract concepts and their period types:`,
2667
- nonAbstractConcepts.map((c2) => ({ name: c2.name, periodType: c2.periodType, abstract: c2.abstract }))
2668
- );
2669
3043
  if (periodTypes.size === 0) {
2670
3044
  this._sectionPeriodType = "duration";
2671
- console.log(`📊 Section ${this.section.id}: No period types defined, defaulting to duration`);
2672
3045
  } else if (periodTypes.size === 1) {
2673
3046
  const singleType = Array.from(periodTypes)[0];
2674
3047
  this._sectionPeriodType = singleType === "instant" ? "instant" : "duration";
2675
- console.log(`📊 Section ${this.section.id}: Single period type '${singleType}', setting to '${this._sectionPeriodType}'`);
2676
3048
  } else {
2677
3049
  this._sectionPeriodType = "mixed";
2678
- console.log(`📊 Section ${this.section.id}: Mixed period types, setting to 'mixed'`);
2679
3050
  }
2680
- console.log(`✅ Section ${this.section.id}: Final period type: ${this._sectionPeriodType}`);
2681
3051
  }
2682
3052
  _getAllNonAbstractConcepts(concepts) {
2683
3053
  const result = [];
@@ -2695,6 +3065,9 @@ let JupiterFormSection = class extends LitElement {
2695
3065
  if (!this.collapsible)
2696
3066
  return;
2697
3067
  this._expanded = !this._expanded;
3068
+ if (this._expanded) {
3069
+ this._expandAllTrees();
3070
+ }
2698
3071
  this.dispatchEvent(new CustomEvent("section-expand", {
2699
3072
  detail: {
2700
3073
  sectionId: this.section.id,
@@ -2799,29 +3172,6 @@ let JupiterFormSection = class extends LitElement {
2799
3172
  this._allTreeExpanded = false;
2800
3173
  this.requestUpdate();
2801
3174
  }
2802
- _toggleAllTrees(event) {
2803
- event.stopPropagation();
2804
- if (!this._expanded) {
2805
- this._expanded = true;
2806
- }
2807
- if (this._allTreeExpanded) {
2808
- this._collapseAllTrees();
2809
- } else {
2810
- this._expandAllTrees();
2811
- }
2812
- }
2813
- _handleTreeCheckboxChange(event) {
2814
- event.stopPropagation();
2815
- const checkbox = event.target;
2816
- if (!this._expanded) {
2817
- this._expanded = true;
2818
- }
2819
- if (checkbox.checked) {
2820
- this._expandAllTrees();
2821
- } else {
2822
- this._collapseAllTrees();
2823
- }
2824
- }
2825
3175
  _handleConceptExpand(event) {
2826
3176
  event.stopPropagation();
2827
3177
  const { conceptId, expanded } = event.detail;
@@ -2881,36 +3231,29 @@ let JupiterFormSection = class extends LitElement {
2881
3231
  `;
2882
3232
  }
2883
3233
  return html`
2884
- <div class="section-header ${!this.collapsible ? "not-collapsible" : ""}"
2885
- @click="${this._toggleExpanded}">
2886
- <div>
2887
- <h3 class="section-title">${this.section.title}</h3>
2888
- ${this.section.description ? html`
2889
- <p class="section-description">${this.section.description}</p>
2890
- ` : ""}
2891
- </div>
2892
- <div class="section-header-controls">
2893
- <div class="tree-control">
2894
- <input
2895
- type="checkbox"
2896
- class="tree-control-checkbox"
2897
- .checked="${this._allTreeExpanded}"
2898
- @change="${this._handleTreeCheckboxChange}"
2899
- />
2900
- <span class="tree-control-label" @click="${this._toggleAllTrees}">${this._allTreeExpanded ? "Collapse Tree" : "Expand Tree"}</span>
3234
+ ${!this.hideHeader ? html`
3235
+ <div class="section-header ${!this.collapsible ? "not-collapsible" : ""}"
3236
+ @click="${this._toggleExpanded}">
3237
+ <div>
3238
+ <h3 class="section-title">${this.section.title}</h3>
3239
+ ${this.section.description ? html`
3240
+ <p class="section-description">${this.section.description}</p>
3241
+ ` : ""}
2901
3242
  </div>
2902
- <div class="section-toggle ${this.collapsible ? this._expanded ? "expanded" : "" : "hidden"}">
2903
- ${this.collapsible ? "" : ""}
3243
+ <div class="section-header-controls">
3244
+ <div class="section-toggle ${this.collapsible ? this._expanded ? "expanded" : "" : "hidden"}">
3245
+ ${this.collapsible ? "▶" : ""}
3246
+ </div>
2904
3247
  </div>
2905
3248
  </div>
2906
- </div>
3249
+ ` : ""}
2907
3250
 
2908
3251
  <div class="section-content ${!this._expanded ? "collapsed" : ""}">
2909
3252
  <div class="table-container">
2910
3253
  <table class="form-table">
2911
3254
  <thead class="table-header">
2912
3255
  <tr class="header-row">
2913
- <th class="header-cell concept-column">Concept</th>
3256
+ <th class="header-cell concept-column"></th>
2914
3257
  ${this.columns.map((column) => {
2915
3258
  var _a, _b, _c;
2916
3259
  return html`
@@ -2952,7 +3295,7 @@ let JupiterFormSection = class extends LitElement {
2952
3295
  </th>
2953
3296
  `;
2954
3297
  })}
2955
- <th class="header-cell">
3298
+ <th class="header-cell add-column-only">
2956
3299
  <button class="add-column-btn" @click="${(e2) => {
2957
3300
  e2.stopPropagation();
2958
3301
  this._handleAddColumn();
@@ -3063,37 +3406,6 @@ JupiterFormSection.styles = css`
3063
3406
  gap: 12px;
3064
3407
  }
3065
3408
 
3066
- .tree-control {
3067
- display: flex;
3068
- align-items: center;
3069
- gap: 6px;
3070
- font-size: 12px;
3071
- color: var(--jupiter-text-secondary, #666);
3072
- background: var(--jupiter-button-background, #fff);
3073
- border: 1px solid var(--jupiter-border-color, #ddd);
3074
- border-radius: 4px;
3075
- padding: 4px 8px;
3076
- cursor: pointer;
3077
- transition: all 0.2s ease;
3078
- }
3079
-
3080
- .tree-control:hover {
3081
- background: var(--jupiter-button-hover-background, #f5f5f5);
3082
- border-color: var(--jupiter-primary-color, #007bff);
3083
- }
3084
-
3085
- .tree-control-checkbox {
3086
- width: 14px;
3087
- height: 14px;
3088
- cursor: pointer;
3089
- }
3090
-
3091
- .tree-control-label {
3092
- cursor: pointer;
3093
- font-weight: 500;
3094
- white-space: nowrap;
3095
- }
3096
-
3097
3409
  .section-content {
3098
3410
  display: block;
3099
3411
  transition: max-height 0.3s ease;
@@ -3152,6 +3464,13 @@ JupiterFormSection.styles = css`
3152
3464
  position: relative;
3153
3465
  }
3154
3466
 
3467
+ /* Special styling for the Add Column button-only column */
3468
+ .header-cell.add-column-only {
3469
+ width: 15%;
3470
+ min-width: 100px;
3471
+ max-width: 150px;
3472
+ }
3473
+
3155
3474
  .remove-column-btn {
3156
3475
  position: absolute;
3157
3476
  top: 4px;
@@ -3279,6 +3598,9 @@ __decorateClass$2([
3279
3598
  __decorateClass$2([
3280
3599
  n2({ type: Array })
3281
3600
  ], JupiterFormSection.prototype, "availableDimensions", 2);
3601
+ __decorateClass$2([
3602
+ n2({ type: Boolean })
3603
+ ], JupiterFormSection.prototype, "hideHeader", 2);
3282
3604
  __decorateClass$2([
3283
3605
  r()
3284
3606
  ], JupiterFormSection.prototype, "_expanded", 2);
@@ -3314,13 +3636,16 @@ let JupiterFilterRolesDialog = class extends LitElement {
3314
3636
  this.open = false;
3315
3637
  this.availableRoles = [];
3316
3638
  this.selectedRoleIds = [];
3639
+ this.periodPreferences = {};
3317
3640
  this._tempSelectedRoles = /* @__PURE__ */ new Set();
3318
3641
  this._searchQuery = "";
3319
3642
  this._filteredRoles = [];
3643
+ this._tempPeriodPreferences = {};
3320
3644
  }
3321
3645
  connectedCallback() {
3322
3646
  super.connectedCallback();
3323
3647
  this._initializeTempSelection();
3648
+ this._initializePeriodPreferences();
3324
3649
  }
3325
3650
  updated(changedProperties) {
3326
3651
  if (changedProperties.has("selectedRoleIds") || changedProperties.has("open")) {
@@ -3329,6 +3654,9 @@ let JupiterFilterRolesDialog = class extends LitElement {
3329
3654
  if (changedProperties.has("availableRoles") || changedProperties.has("_searchQuery")) {
3330
3655
  this._updateFilteredRoles();
3331
3656
  }
3657
+ if (changedProperties.has("availableRoles") || changedProperties.has("periodPreferences") || changedProperties.has("open")) {
3658
+ this._initializePeriodPreferences();
3659
+ }
3332
3660
  }
3333
3661
  _updateFilteredRoles() {
3334
3662
  if (!this._searchQuery.trim()) {
@@ -3396,6 +3724,64 @@ let JupiterFilterRolesDialog = class extends LitElement {
3396
3724
  _initializeTempSelection() {
3397
3725
  this._tempSelectedRoles = new Set(this.selectedRoleIds);
3398
3726
  }
3727
+ _initializePeriodPreferences() {
3728
+ const preferences = {};
3729
+ this.availableRoles.forEach((role) => {
3730
+ const existingPrefs = this.periodPreferences[role.id];
3731
+ if (existingPrefs) {
3732
+ preferences[role.id] = { ...existingPrefs };
3733
+ } else {
3734
+ const hasMixedPeriods = role.showPeriodControl === true;
3735
+ let showDuration;
3736
+ let showInstant;
3737
+ if (role.duration !== void 0 || role.instant !== void 0) {
3738
+ showDuration = role.duration === true;
3739
+ showInstant = role.instant === true;
3740
+ } else {
3741
+ showDuration = hasMixedPeriods || this._hasConceptsWithPeriodType(role, "duration");
3742
+ showInstant = hasMixedPeriods || this._hasConceptsWithPeriodType(role, "instant");
3743
+ }
3744
+ preferences[role.id] = {
3745
+ showDuration,
3746
+ showInstant,
3747
+ showPreviousYear: role.showPreviousYear === true
3748
+ // Read from role data in presentation.json
3749
+ };
3750
+ }
3751
+ });
3752
+ this._tempPeriodPreferences = preferences;
3753
+ }
3754
+ _hasConceptsWithPeriodType(role, periodType) {
3755
+ const checkConcepts = (concepts) => {
3756
+ return concepts.some((concept) => {
3757
+ if (!concept.abstract && concept.periodType === periodType) {
3758
+ return true;
3759
+ }
3760
+ if (concept.children) {
3761
+ return checkConcepts(concept.children);
3762
+ }
3763
+ return false;
3764
+ });
3765
+ };
3766
+ return checkConcepts(role.concepts);
3767
+ }
3768
+ _handlePeriodCheckboxChange(event, roleId, periodType) {
3769
+ event.stopPropagation();
3770
+ const checkbox = event.target;
3771
+ const newPreferences = { ...this._tempPeriodPreferences };
3772
+ if (!newPreferences[roleId]) {
3773
+ newPreferences[roleId] = { showDuration: true, showInstant: true, showPreviousYear: false };
3774
+ }
3775
+ if (periodType === "duration") {
3776
+ newPreferences[roleId].showDuration = checkbox.checked;
3777
+ } else if (periodType === "instant") {
3778
+ newPreferences[roleId].showInstant = checkbox.checked;
3779
+ } else if (periodType === "previousYear") {
3780
+ newPreferences[roleId].showPreviousYear = checkbox.checked;
3781
+ }
3782
+ this._tempPeriodPreferences = newPreferences;
3783
+ this.requestUpdate();
3784
+ }
3399
3785
  _handleCheckboxChange(event, roleId) {
3400
3786
  const checkbox = event.target;
3401
3787
  const newSelection = new Set(this._tempSelectedRoles);
@@ -3440,7 +3826,10 @@ let JupiterFilterRolesDialog = class extends LitElement {
3440
3826
  _handleApply() {
3441
3827
  const selectedRoles = Array.from(this._tempSelectedRoles);
3442
3828
  this.dispatchEvent(new CustomEvent("roles-filter-apply", {
3443
- detail: { selectedRoleIds: selectedRoles },
3829
+ detail: {
3830
+ selectedRoleIds: selectedRoles,
3831
+ periodPreferences: this._tempPeriodPreferences
3832
+ },
3444
3833
  bubbles: true
3445
3834
  }));
3446
3835
  }
@@ -3543,6 +3932,8 @@ let JupiterFilterRolesDialog = class extends LitElement {
3543
3932
  ${this._filteredRoles.map((role) => {
3544
3933
  var _a;
3545
3934
  const isSelected = this._tempSelectedRoles.has(role.id);
3935
+ const showPeriodControls = role.showPeriodControl === true;
3936
+ const preferences = this._tempPeriodPreferences[role.id] || { showDuration: true, showInstant: true };
3546
3937
  return html`
3547
3938
  <div class="role-item">
3548
3939
  <input
@@ -3556,6 +3947,47 @@ let JupiterFilterRolesDialog = class extends LitElement {
3556
3947
  ${((_a = role.metadata) == null ? void 0 : _a.roleURI) ? html`
3557
3948
  <p class="role-description">URI: ${role.metadata.roleURI}</p>
3558
3949
  ` : ""}
3950
+
3951
+ ${showPeriodControls ? html`
3952
+ <div class="period-controls">
3953
+ <p class="period-controls-label">Show Period Column:</p>
3954
+ <div class="period-checkboxes">
3955
+ <label class="period-checkbox-item">
3956
+ <input
3957
+ type="checkbox"
3958
+ class="period-checkbox"
3959
+ .checked="${preferences.showDuration}"
3960
+ @change="${(e2) => this._handlePeriodCheckboxChange(e2, role.id, "duration")}"
3961
+ />
3962
+ <span class="period-checkbox-label">Duration</span>
3963
+ </label>
3964
+ <label class="period-checkbox-item">
3965
+ <input
3966
+ type="checkbox"
3967
+ class="period-checkbox"
3968
+ .checked="${preferences.showInstant}"
3969
+ @change="${(e2) => this._handlePeriodCheckboxChange(e2, role.id, "instant")}"
3970
+ />
3971
+ <span class="period-checkbox-label">Instant</span>
3972
+ </label>
3973
+ </div>
3974
+ </div>
3975
+ ` : ""}
3976
+
3977
+ <div class="period-controls">
3978
+ <p class="period-controls-label">Additional Options:</p>
3979
+ <div class="period-checkboxes">
3980
+ <label class="period-checkbox-item">
3981
+ <input
3982
+ type="checkbox"
3983
+ class="period-checkbox"
3984
+ .checked="${preferences.showPreviousYear}"
3985
+ @change="${(e2) => this._handlePeriodCheckboxChange(e2, role.id, "previousYear")}"
3986
+ />
3987
+ <span class="period-checkbox-label">Show previous year</span>
3988
+ </label>
3989
+ </div>
3990
+ </div>
3559
3991
  </div>
3560
3992
  </div>
3561
3993
  `;
@@ -3563,12 +3995,7 @@ let JupiterFilterRolesDialog = class extends LitElement {
3563
3995
  `}
3564
3996
  </div>
3565
3997
 
3566
- <div class="selected-count">
3567
- ${selectedCount} of ${totalCount} roles selected
3568
- ${hasSearchQuery && filteredCount !== totalCount ? html`
3569
- <br><small>(${this._getSelectedFilteredCount()} of ${filteredCount} filtered roles selected)</small>
3570
- ` : ""}
3571
- </div>
3998
+
3572
3999
  </div>
3573
4000
 
3574
4001
  <!-- Dialog Actions -->
@@ -3826,6 +4253,44 @@ JupiterFilterRolesDialog.styles = css`
3826
4253
  margin-bottom: 4px;
3827
4254
  }
3828
4255
 
4256
+ .period-controls {
4257
+ margin-top: 8px;
4258
+ padding: 8px;
4259
+ background: var(--jupiter-background-light, #f8f9fa);
4260
+ border-radius: 4px;
4261
+ border: 1px solid var(--jupiter-border-color, #e0e0e0);
4262
+ }
4263
+
4264
+ .period-controls-label {
4265
+ font-size: 12px;
4266
+ font-weight: 600;
4267
+ color: var(--jupiter-text-primary, #333);
4268
+ margin: 0 0 6px 0;
4269
+ }
4270
+
4271
+ .period-checkboxes {
4272
+ display: flex;
4273
+ gap: 16px;
4274
+ flex-wrap: wrap;
4275
+ }
4276
+
4277
+ .period-checkbox-item {
4278
+ display: flex;
4279
+ align-items: center;
4280
+ gap: 6px;
4281
+ }
4282
+
4283
+ .period-checkbox {
4284
+ cursor: pointer;
4285
+ }
4286
+
4287
+ .period-checkbox-label {
4288
+ font-size: 13px;
4289
+ color: var(--jupiter-text-primary, #333);
4290
+ cursor: pointer;
4291
+ user-select: none;
4292
+ }
4293
+
3829
4294
  .selected-count {
3830
4295
  font-size: 13px;
3831
4296
  color: var(--jupiter-text-secondary, #666);
@@ -3885,6 +4350,9 @@ __decorateClass$1([
3885
4350
  __decorateClass$1([
3886
4351
  n2({ type: Array })
3887
4352
  ], JupiterFilterRolesDialog.prototype, "selectedRoleIds", 2);
4353
+ __decorateClass$1([
4354
+ n2({ type: Object })
4355
+ ], JupiterFilterRolesDialog.prototype, "periodPreferences", 2);
3888
4356
  __decorateClass$1([
3889
4357
  r()
3890
4358
  ], JupiterFilterRolesDialog.prototype, "_tempSelectedRoles", 2);
@@ -3894,6 +4362,9 @@ __decorateClass$1([
3894
4362
  __decorateClass$1([
3895
4363
  r()
3896
4364
  ], JupiterFilterRolesDialog.prototype, "_filteredRoles", 2);
4365
+ __decorateClass$1([
4366
+ r()
4367
+ ], JupiterFilterRolesDialog.prototype, "_tempPeriodPreferences", 2);
3897
4368
  JupiterFilterRolesDialog = __decorateClass$1([
3898
4369
  t$1("jupiter-filter-roles-dialog")
3899
4370
  ], JupiterFilterRolesDialog);
@@ -3918,6 +4389,9 @@ let JupiterDynamicForm = class extends LitElement {
3918
4389
  this.periodStartDate = "2025-01-01";
3919
4390
  this.periodEndDate = "2025-12-31";
3920
4391
  this.language = "en";
4392
+ this.display = "accordion";
4393
+ this.mode = "inputForm";
4394
+ this.financialStatementsTypeAxis = [];
3921
4395
  this._formData = {};
3922
4396
  this._preservedFormData = {};
3923
4397
  this._typedMemberData = {};
@@ -3931,13 +4405,19 @@ let JupiterDynamicForm = class extends LitElement {
3931
4405
  this._allSections = [];
3932
4406
  this._selectedRoleIds = [];
3933
4407
  this._showFilterDialog = false;
4408
+ this._periodPreferences = {};
4409
+ this._activeSidePanelRoleId = null;
4410
+ this._adminRoleConfigs = {};
3934
4411
  }
3935
4412
  connectedCallback() {
3936
4413
  super.connectedCallback();
3937
4414
  this._initializeForm();
3938
4415
  }
3939
4416
  updated(changedProperties) {
3940
- if (changedProperties.has("xbrlInput") || changedProperties.has("schema")) {
4417
+ if (changedProperties.has("financialStatementsTypeAxis")) {
4418
+ console.log("🔄 financialStatementsTypeAxis changed:", this.financialStatementsTypeAxis);
4419
+ }
4420
+ if (changedProperties.has("xbrlInput") || changedProperties.has("schema") || changedProperties.has("language") || changedProperties.has("periodStartDate") || changedProperties.has("periodEndDate") || changedProperties.has("financialStatementsTypeAxis")) {
3941
4421
  this._initializeForm();
3942
4422
  }
3943
4423
  }
@@ -3948,21 +4428,26 @@ let JupiterDynamicForm = class extends LitElement {
3948
4428
  console.log("🔄 Initializing form from XBRL input:", this.xbrlInput);
3949
4429
  console.log("📅 Using period dates:", this.periodStartDate, "to", this.periodEndDate);
3950
4430
  console.log("🌐 Using language:", this.language);
4431
+ this._initializePeriodPreferencesFromData();
4432
+ console.log("⚙️ Using period preferences:", this._periodPreferences);
3951
4433
  this._currentSchema = XBRLFormBuilder.buildFormSchema(
3952
4434
  this.xbrlInput,
3953
4435
  this.periodStartDate,
3954
4436
  this.periodEndDate,
3955
- this.language
4437
+ this.language,
4438
+ this._periodPreferences
3956
4439
  );
3957
4440
  console.log("✅ Generated schema with sections:", this._currentSchema.sections.length);
3958
4441
  this._allSections = [...this._currentSchema.sections];
4442
+ if (this.financialStatementsTypeAxis && this.financialStatementsTypeAxis.length > 0) {
4443
+ console.log("🔍 Applying financialStatementsTypeAxis filter:", this.financialStatementsTypeAxis);
4444
+ console.log("📊 Sections before filter:", this._allSections.length);
4445
+ this._allSections = this._filterRolesByFinancialStatementsType(this._allSections);
4446
+ console.log("📊 Sections after filter:", this._allSections.length);
4447
+ }
3959
4448
  if (this._selectedRoleIds.length === 0) {
3960
- this._selectedRoleIds = [];
3961
- this._showFilterDialog = true;
3962
- this._currentSchema = {
3963
- ...this._currentSchema,
3964
- sections: []
3965
- };
4449
+ this._selectedRoleIds = this._allSections.map((section) => section.id);
4450
+ console.log("✅ Auto-selected all roles:", this._selectedRoleIds.length);
3966
4451
  }
3967
4452
  this._applyRoleFilter();
3968
4453
  this._columns = [
@@ -4020,6 +4505,28 @@ let JupiterDynamicForm = class extends LitElement {
4020
4505
  }
4021
4506
  ];
4022
4507
  }
4508
+ /**
4509
+ * Initialize period preferences from presentation data
4510
+ * Reads showPreviousYear, instant, and duration attributes from each role to set initial preferences
4511
+ */
4512
+ _initializePeriodPreferencesFromData() {
4513
+ var _a, _b, _c;
4514
+ if (!((_c = (_b = (_a = this.xbrlInput) == null ? void 0 : _a.presentation) == null ? void 0 : _b[0]) == null ? void 0 : _c.roles)) {
4515
+ return;
4516
+ }
4517
+ const preferences = {};
4518
+ this.xbrlInput.presentation[0].roles.forEach((role) => {
4519
+ const showPreviousYear = role.showPreviousYear === true;
4520
+ const instant = role.instant !== void 0 ? role.instant === true : true;
4521
+ const duration = role.duration !== void 0 ? role.duration === true : true;
4522
+ preferences[role.id] = {
4523
+ showDuration: duration,
4524
+ showInstant: instant,
4525
+ showPreviousYear
4526
+ };
4527
+ });
4528
+ this._periodPreferences = preferences;
4529
+ }
4023
4530
  _applyRoleFilter() {
4024
4531
  if (!this._currentSchema || !this._allSections.length)
4025
4532
  return;
@@ -4030,17 +4537,88 @@ let JupiterDynamicForm = class extends LitElement {
4030
4537
  ...this._currentSchema,
4031
4538
  sections: []
4032
4539
  };
4540
+ this.requestUpdate();
4033
4541
  return;
4034
4542
  }
4035
4543
  this._preserveDataForHiddenSections();
4036
4544
  const filteredSections = this._allSections.filter(
4037
4545
  (section) => this._selectedRoleIds.includes(section.id)
4038
4546
  );
4547
+ console.log(`📊 Filtered sections: ${filteredSections.length} (IDs: ${filteredSections.map((s2) => s2.id).join(", ")})`);
4039
4548
  this._restoreDataForVisibleSections(filteredSections);
4040
4549
  this._currentSchema = {
4041
4550
  ...this._currentSchema,
4042
4551
  sections: filteredSections
4043
4552
  };
4553
+ console.log(`✅ Schema updated. Current sections count: ${this._currentSchema.sections.length}`);
4554
+ this.requestUpdate();
4555
+ }
4556
+ /**
4557
+ * Filter roles based on financialStatementsTypeAxis property
4558
+ * Rules:
4559
+ * 1. Show roles that have no entry in hypercubes.json
4560
+ * 2. Show roles that don't have financialStatementsTypeAxis dimension
4561
+ * 3. For roles with financialStatementsTypeAxis, show only if at least one member matches the provided values
4562
+ */
4563
+ _filterRolesByFinancialStatementsType(sections) {
4564
+ var _a;
4565
+ if (!this.financialStatementsTypeAxis || this.financialStatementsTypeAxis.length === 0) {
4566
+ return sections;
4567
+ }
4568
+ if (!((_a = this.xbrlInput) == null ? void 0 : _a.hypercubes) || this.xbrlInput.hypercubes.length === 0) {
4569
+ return sections;
4570
+ }
4571
+ const hypercubeData = this.xbrlInput.hypercubes[0];
4572
+ const financialStatementsAxisId = "bw2-titel9_FinancialStatementsTypeAxis";
4573
+ console.log("🔍 Filter values:", this.financialStatementsTypeAxis);
4574
+ return sections.filter((section) => {
4575
+ var _a2;
4576
+ const hypercubeRole = (_a2 = hypercubeData.roles) == null ? void 0 : _a2.find((r2) => r2.roleId === section.id);
4577
+ if (!hypercubeRole || !hypercubeRole.items || hypercubeRole.items.length === 0) {
4578
+ console.log(`✅ ${section.title}: No hypercube entry - INCLUDED`);
4579
+ return true;
4580
+ }
4581
+ let hasFinancialStatementsAxis = false;
4582
+ let hasMatchingMember = false;
4583
+ for (const item of hypercubeRole.items) {
4584
+ if (!item.dimensions || item.dimensions.length === 0) {
4585
+ continue;
4586
+ }
4587
+ const financialStatementsTypeDimension = item.dimensions.find(
4588
+ (dim) => {
4589
+ var _a3;
4590
+ return dim.id === financialStatementsAxisId || ((_a3 = dim.conceptName) == null ? void 0 : _a3.includes("FinancialStatementsTypeAxis"));
4591
+ }
4592
+ );
4593
+ if (financialStatementsTypeDimension) {
4594
+ hasFinancialStatementsAxis = true;
4595
+ if (financialStatementsTypeDimension.members && financialStatementsTypeDimension.members.length > 0) {
4596
+ const itemHasMatch = financialStatementsTypeDimension.members.some((member) => {
4597
+ if (member.conceptName) {
4598
+ const conceptNameParts = member.conceptName.split(":");
4599
+ const memberValue = conceptNameParts.length > 1 ? conceptNameParts[1] : member.conceptName;
4600
+ const matches = this.financialStatementsTypeAxis.some((filterValue) => {
4601
+ const filterParts = filterValue.split(":");
4602
+ const filterMemberValue = filterParts.length > 1 ? filterParts[1] : filterValue;
4603
+ const isMatch = memberValue === filterMemberValue;
4604
+ return isMatch;
4605
+ });
4606
+ return matches;
4607
+ }
4608
+ return this.financialStatementsTypeAxis.includes(member.id);
4609
+ });
4610
+ if (itemHasMatch) {
4611
+ hasMatchingMember = true;
4612
+ break;
4613
+ }
4614
+ }
4615
+ }
4616
+ }
4617
+ if (!hasFinancialStatementsAxis) {
4618
+ return true;
4619
+ }
4620
+ return hasMatchingMember;
4621
+ });
4044
4622
  }
4045
4623
  _preserveDataForHiddenSections() {
4046
4624
  var _a;
@@ -4054,7 +4632,6 @@ let JupiterDynamicForm = class extends LitElement {
4054
4632
  this._preserveSectionData(section);
4055
4633
  }
4056
4634
  });
4057
- console.log(`📦 Preserved data for ${sectionsThatWillBeHidden.length} hidden sections:`, sectionsThatWillBeHidden);
4058
4635
  }
4059
4636
  _restoreDataForVisibleSections(visibleSections) {
4060
4637
  visibleSections.forEach((section) => {
@@ -4070,12 +4647,10 @@ let JupiterDynamicForm = class extends LitElement {
4070
4647
  _preserveConceptData(concept) {
4071
4648
  if (this._formData[concept.id]) {
4072
4649
  this._preservedFormData[concept.id] = { ...this._formData[concept.id] };
4073
- console.log(`💾 Preserved form data for concept: ${concept.id}`);
4074
4650
  }
4075
4651
  concept.fields.forEach((field) => {
4076
4652
  if (this._typedMemberData[field.columnId]) {
4077
4653
  this._preservedTypedMemberData[field.columnId] = { ...this._typedMemberData[field.columnId] };
4078
- console.log(`💾 Preserved typed data for column: ${field.columnId}`);
4079
4654
  }
4080
4655
  });
4081
4656
  if (concept.children) {
@@ -4092,12 +4667,10 @@ let JupiterDynamicForm = class extends LitElement {
4092
4667
  _restoreConceptData(concept) {
4093
4668
  if (this._preservedFormData[concept.id]) {
4094
4669
  this._formData[concept.id] = { ...this._preservedFormData[concept.id] };
4095
- console.log(`🔄 Restored form data for concept: ${concept.id}`);
4096
4670
  }
4097
4671
  concept.fields.forEach((field) => {
4098
4672
  if (this._preservedTypedMemberData[field.columnId]) {
4099
4673
  this._typedMemberData[field.columnId] = { ...this._preservedTypedMemberData[field.columnId] };
4100
- console.log(`🔄 Restored typed data for column: ${field.columnId}`);
4101
4674
  }
4102
4675
  });
4103
4676
  if (concept.children) {
@@ -4117,16 +4690,24 @@ let JupiterDynamicForm = class extends LitElement {
4117
4690
  console.log(`🚫 Filter dialog cancelled. Current selection: ${this._selectedRoleIds.length}/${this._allSections.length}`);
4118
4691
  }
4119
4692
  _handleRoleFilterApply(event) {
4120
- const { selectedRoleIds } = event.detail;
4693
+ const { selectedRoleIds, periodPreferences } = event.detail;
4121
4694
  this._selectedRoleIds = selectedRoleIds;
4122
- this._applyRoleFilter();
4695
+ const preferencesChanged = JSON.stringify(this._periodPreferences) !== JSON.stringify(periodPreferences);
4696
+ if (preferencesChanged) {
4697
+ this._periodPreferences = periodPreferences;
4698
+ console.log("📊 Period preferences updated:", this._periodPreferences);
4699
+ this._initializeForm();
4700
+ } else {
4701
+ this._applyRoleFilter();
4702
+ }
4123
4703
  this._showFilterDialog = false;
4124
4704
  console.log(`🎯 Applied role filter: ${selectedRoleIds.length}/${this._allSections.length} roles selected`);
4125
4705
  this.dispatchEvent(new CustomEvent("roles-filter-changed", {
4126
4706
  detail: {
4127
4707
  selectedRoleIds,
4128
4708
  totalRoles: this._allSections.length,
4129
- visibleRoles: selectedRoleIds.length
4709
+ visibleRoles: selectedRoleIds.length,
4710
+ periodPreferences
4130
4711
  },
4131
4712
  bubbles: true
4132
4713
  }));
@@ -4247,9 +4828,7 @@ let JupiterDynamicForm = class extends LitElement {
4247
4828
  }
4248
4829
  _getAvailableDimensionsForSection(sectionId) {
4249
4830
  var _a, _b, _c;
4250
- console.log(`🔍 Getting dimensions for section: ${sectionId}`);
4251
4831
  if (!((_b = (_a = this.xbrlInput) == null ? void 0 : _a.hypercubes) == null ? void 0 : _b[0])) {
4252
- console.log("❌ No hypercubes data available");
4253
4832
  return [];
4254
4833
  }
4255
4834
  const hypercubeRole = this.xbrlInput.hypercubes[0].roles.find((hr) => hr.roleId === sectionId);
@@ -4257,7 +4836,6 @@ let JupiterDynamicForm = class extends LitElement {
4257
4836
  console.log(`❌ No hypercube items found for role: ${sectionId}`);
4258
4837
  return [];
4259
4838
  }
4260
- console.log(`✅ Found hypercube role with ${hypercubeRole.items.length} items`);
4261
4839
  const availableDimensions = [];
4262
4840
  hypercubeRole.items.forEach((item) => {
4263
4841
  if (item.dimensions && item.dimensions.length > 0) {
@@ -4291,7 +4869,6 @@ let JupiterDynamicForm = class extends LitElement {
4291
4869
  });
4292
4870
  }
4293
4871
  });
4294
- console.log(`📈 Found ${availableDimensions.length} dimensions for section ${sectionId}:`, availableDimensions.map((d2) => d2.axisLabel));
4295
4872
  return availableDimensions;
4296
4873
  }
4297
4874
  _addColumnFromRequest(request, sectionId) {
@@ -4301,11 +4878,11 @@ let JupiterDynamicForm = class extends LitElement {
4301
4878
  let title = "";
4302
4879
  let description = "";
4303
4880
  if (request.periodType === "instant") {
4304
- title = "Current";
4305
- description = `Values as of ${request.instantDate}`;
4881
+ title = request.instantDate || "";
4882
+ description = "";
4306
4883
  } else if (request.periodType === "duration" || request.periodType === "mixed") {
4307
- title = "Current Period";
4308
- description = `Period: ${request.startDate} to ${request.endDate}`;
4884
+ title = `${request.startDate} / ${request.endDate}`;
4885
+ description = "";
4309
4886
  }
4310
4887
  let dimensionData = {
4311
4888
  dimensionId: "period",
@@ -4383,7 +4960,6 @@ let JupiterDynamicForm = class extends LitElement {
4383
4960
  if (dimSelection.isTyped) {
4384
4961
  typedMembers[dimSelection.axisId] = dimSelection.typedValue || "";
4385
4962
  hasTypedDimensions = true;
4386
- console.log(`💾 Initializing typed member data: ${dimSelection.axisLabel} = "${dimSelection.typedValue || "(empty - will be entered in column header)"}"`);
4387
4963
  }
4388
4964
  }
4389
4965
  if (hasTypedDimensions) {
@@ -4398,9 +4974,7 @@ let JupiterDynamicForm = class extends LitElement {
4398
4974
  memberLabel: dim.axisLabel
4399
4975
  // Use axisLabel as memberLabel
4400
4976
  }));
4401
- console.log(`� Added typed members to column dimension data:`, newColumn.dimensionData.typedMembers);
4402
4977
  }
4403
- console.log(`� Initialized typed member data for column ${newColumnId}:`, typedMembers);
4404
4978
  }
4405
4979
  }
4406
4980
  if (this._currentSchema) {
@@ -4546,6 +5120,10 @@ let JupiterDynamicForm = class extends LitElement {
4546
5120
  _handleSubmit() {
4547
5121
  console.log("📝 Form submission started...");
4548
5122
  this._submitted = true;
5123
+ if (this.mode === "admin") {
5124
+ this._handleAdminModeSubmit();
5125
+ return;
5126
+ }
4549
5127
  this._validateForm();
4550
5128
  const submissionData = this._generateSubmissionData();
4551
5129
  console.log("📊 Form Submission Data:", JSON.stringify(submissionData, null, 2));
@@ -4640,18 +5218,20 @@ let JupiterDynamicForm = class extends LitElement {
4640
5218
  if (!field)
4641
5219
  return;
4642
5220
  const isInstant = concept.periodType === "instant";
5221
+ const column = this._findColumnByIdInAllSections(columnId);
5222
+ alert("hi");
5223
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${columnId}, Column Period: ${(column == null ? void 0 : column.periodStartDate) || "none"} - ${(column == null ? void 0 : column.periodEndDate) || "none"}`);
4643
5224
  const entry = {
4644
5225
  conceptId: concept.originalConceptId || concept.id,
4645
5226
  value,
4646
5227
  period: {
4647
5228
  type: concept.periodType || "duration",
4648
- ...isInstant ? { date: field.periodStartDate || this.periodStartDate } : {
4649
- startDate: field.periodStartDate || this.periodStartDate,
4650
- endDate: field.periodEndDate || this.periodEndDate
5229
+ ...isInstant ? { date: (column == null ? void 0 : column.periodEndDate) || field.periodStartDate || this.periodStartDate } : {
5230
+ startDate: (column == null ? void 0 : column.periodStartDate) || field.periodStartDate || this.periodStartDate,
5231
+ endDate: (column == null ? void 0 : column.periodEndDate) || field.periodEndDate || this.periodEndDate
4651
5232
  }
4652
5233
  }
4653
5234
  };
4654
- const column = this._findColumnByIdInAllSections(columnId);
4655
5235
  if ((_a = column == null ? void 0 : column.dimensionData) == null ? void 0 : _a.memberLabel) {
4656
5236
  entry.dimension = column.dimensionData.memberLabel;
4657
5237
  }
@@ -4671,7 +5251,8 @@ let JupiterDynamicForm = class extends LitElement {
4671
5251
  _removeDuplicateSubmissions(submissionData) {
4672
5252
  const uniqueEntries = /* @__PURE__ */ new Map();
4673
5253
  submissionData.forEach((entry) => {
4674
- const key = `${entry.conceptId}_${entry.value}_${entry.dimension || "no-dimension"}`;
5254
+ const periodKey = entry.period.type === "instant" ? entry.period.date : `${entry.period.startDate}_${entry.period.endDate}`;
5255
+ const key = `${entry.conceptId}_${entry.value}_${entry.dimension || "no-dimension"}_${periodKey}`;
4675
5256
  if (!uniqueEntries.has(key)) {
4676
5257
  uniqueEntries.set(key, entry);
4677
5258
  }
@@ -4783,10 +5364,7 @@ let JupiterDynamicForm = class extends LitElement {
4783
5364
  }
4784
5365
  }
4785
5366
  if (concept.fields && concept.fields.length > 1) {
4786
- console.log(`🔍 [DEBUG] Processing concept ${concept.originalConceptId}, fields count: ${concept.fields.length}`);
4787
5367
  concept.fields.forEach((field, index) => {
4788
- var _a;
4789
- console.log(` Field ${index}: columnId=${field.columnId}, value=${(_a = this._formData[concept.id]) == null ? void 0 : _a[field.columnId]}`);
4790
5368
  });
4791
5369
  }
4792
5370
  if (concept.fields && concept.fields.length > 0) {
@@ -4795,11 +5373,7 @@ let JupiterDynamicForm = class extends LitElement {
4795
5373
  const conceptData = this._formData[concept.id];
4796
5374
  const fieldValue = conceptData == null ? void 0 : conceptData[field.columnId];
4797
5375
  if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
4798
- if (sectionTitle === targetRole) {
4799
- console.warn(`[DUPLICATE DEBUG] Creating submission entry for concept ${concept.originalConceptId || concept.id}, field columnId=${field.columnId}, value=${fieldValue}`);
4800
- }
4801
5376
  const column = this._findColumnByIdInSection(field.columnId, section);
4802
- console.log(`🔍 [DynamicForm] Processing field for concept ${concept.originalConceptId || concept.id}, field columnId: ${field.columnId}, found column in section ${section == null ? void 0 : section.id}: ${!!column}, column title: ${column == null ? void 0 : column.title}`);
4803
5377
  const submissionEntry = {
4804
5378
  conceptId: concept.id,
4805
5379
  value: fieldValue,
@@ -4808,11 +5382,12 @@ let JupiterDynamicForm = class extends LitElement {
4808
5382
  }
4809
5383
  };
4810
5384
  if (concept.periodType === "instant") {
4811
- submissionEntry.period.date = field.periodStartDate || this.periodStartDate;
5385
+ submissionEntry.period.date = (column == null ? void 0 : column.periodEndDate) || field.periodStartDate || this.periodStartDate;
4812
5386
  } else {
4813
- submissionEntry.period.startDate = field.periodStartDate || this.periodStartDate;
4814
- submissionEntry.period.endDate = field.periodEndDate || this.periodEndDate;
5387
+ submissionEntry.period.startDate = (column == null ? void 0 : column.periodStartDate) || field.periodStartDate || this.periodStartDate;
5388
+ submissionEntry.period.endDate = (column == null ? void 0 : column.periodEndDate) || field.periodEndDate || this.periodEndDate;
4815
5389
  }
5390
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field.columnId}, Column Period: ${(column == null ? void 0 : column.periodStartDate) || "none"} - ${(column == null ? void 0 : column.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
4816
5391
  if ((column == null ? void 0 : column.type) === "dimension" && ((_a = column.dimensionData) == null ? void 0 : _a.dimensionIdKey)) {
4817
5392
  submissionEntry.dimension = column.dimensionData.dimensionIdKey;
4818
5393
  console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field.columnId}):`, column.dimensionData.dimensionIdKey);
@@ -4891,6 +5466,233 @@ let JupiterDynamicForm = class extends LitElement {
4891
5466
  submitted: this._submitted
4892
5467
  };
4893
5468
  }
5469
+ _handleSidePanelRoleClick(roleId) {
5470
+ this._activeSidePanelRoleId = roleId;
5471
+ }
5472
+ _renderAdminModeContent(section) {
5473
+ var _a, _b, _c;
5474
+ if (!section) {
5475
+ return html`
5476
+ <div class="admin-mode-container">
5477
+ <p>No role selected</p>
5478
+ </div>
5479
+ `;
5480
+ }
5481
+ const showPreviousYearChecked = ((_a = this._adminRoleConfigs[section.id]) == null ? void 0 : _a.showPreviousYear) ?? section.showPreviousYear ?? false;
5482
+ const instantChecked = ((_b = this._adminRoleConfigs[section.id]) == null ? void 0 : _b.instant) ?? section.instant ?? false;
5483
+ const durationChecked = ((_c = this._adminRoleConfigs[section.id]) == null ? void 0 : _c.duration) ?? section.duration ?? false;
5484
+ const hasMixedPeriodTypes = section.showPeriodControl === true;
5485
+ return html`
5486
+ <div class="admin-mode-container">
5487
+ <h2 class="admin-mode-title">Role Configuration: ${section.title}</h2>
5488
+ <div class="admin-roles-list">
5489
+ <div class="admin-role-item">
5490
+ <div class="admin-role-checkbox">
5491
+ <input
5492
+ type="checkbox"
5493
+ id="admin-prev-year-${section.id}"
5494
+ .checked="${showPreviousYearChecked}"
5495
+ @change="${(e2) => this._handleAdminCheckboxChange(section.id, "showPreviousYear", e2.target.checked)}"
5496
+ />
5497
+ <label for="admin-prev-year-${section.id}">Show Previous Year Column</label>
5498
+ </div>
5499
+ </div>
5500
+
5501
+ ${hasMixedPeriodTypes ? html`
5502
+ <div class="admin-role-item">
5503
+ <div class="admin-role-checkbox">
5504
+ <input
5505
+ type="checkbox"
5506
+ id="admin-instant-${section.id}"
5507
+ .checked="${instantChecked}"
5508
+ @change="${(e2) => this._handleAdminCheckboxChange(section.id, "instant", e2.target.checked)}"
5509
+ />
5510
+ <label for="admin-instant-${section.id}">Show Instant Column</label>
5511
+ </div>
5512
+ </div>
5513
+
5514
+ <div class="admin-role-item">
5515
+ <div class="admin-role-checkbox">
5516
+ <input
5517
+ type="checkbox"
5518
+ id="admin-duration-${section.id}"
5519
+ .checked="${durationChecked}"
5520
+ @change="${(e2) => this._handleAdminCheckboxChange(section.id, "duration", e2.target.checked)}"
5521
+ />
5522
+ <label for="admin-duration-${section.id}">Show Duration Column</label>
5523
+ </div>
5524
+ </div>
5525
+ ` : ""}
5526
+ </div>
5527
+ </div>
5528
+ `;
5529
+ }
5530
+ _handleAdminCheckboxChange(roleId, field, checked) {
5531
+ const currentConfig = this._adminRoleConfigs[roleId] || { showPreviousYear: false };
5532
+ this._adminRoleConfigs = {
5533
+ ...this._adminRoleConfigs,
5534
+ [roleId]: {
5535
+ ...currentConfig,
5536
+ [field]: checked
5537
+ }
5538
+ };
5539
+ }
5540
+ _handleAdminModeSubmit() {
5541
+ var _a, _b, _c, _d;
5542
+ if (!((_c = (_b = (_a = this.xbrlInput) == null ? void 0 : _a.presentation) == null ? void 0 : _b[0]) == null ? void 0 : _c.roles)) {
5543
+ console.error("No presentation data available");
5544
+ return;
5545
+ }
5546
+ const updatedPresentationData = JSON.parse(JSON.stringify(this.xbrlInput.presentation[0]));
5547
+ const selectedRoleIds = new Set(
5548
+ ((_d = this._currentSchema) == null ? void 0 : _d.sections.map((s2) => s2.id)) || []
5549
+ );
5550
+ updatedPresentationData.roles = updatedPresentationData.roles.map((role) => {
5551
+ const isSelected = selectedRoleIds.has(role.id);
5552
+ const config = this._adminRoleConfigs[role.id];
5553
+ const updatedRole = {
5554
+ ...role,
5555
+ display: isSelected ? "yes" : "no"
5556
+ };
5557
+ if (config !== void 0 && isSelected) {
5558
+ updatedRole.showPreviousYear = config.showPreviousYear;
5559
+ if (config.instant !== void 0) {
5560
+ updatedRole.instant = config.instant;
5561
+ }
5562
+ if (config.duration !== void 0) {
5563
+ updatedRole.duration = config.duration;
5564
+ }
5565
+ }
5566
+ return updatedRole;
5567
+ });
5568
+ this.dispatchEvent(new CustomEvent("admin-config-updated", {
5569
+ detail: {
5570
+ presentationData: updatedPresentationData,
5571
+ roleConfigs: this._adminRoleConfigs
5572
+ },
5573
+ bubbles: true,
5574
+ composed: true
5575
+ }));
5576
+ console.log("✅ Admin configuration saved successfully");
5577
+ }
5578
+ _renderAccordionLayout(schema, config, showValidationSummary, errorCount) {
5579
+ return html`
5580
+ <div class="form-sections">
5581
+ <!-- Validation Summary -->
5582
+ ${showValidationSummary ? html`
5583
+ <div class="validation-summary">
5584
+ <h4 class="validation-summary-title">Please fix the following errors:</h4>
5585
+ <ul class="validation-summary-list">
5586
+ ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
5587
+ <li class="validation-summary-item">${error.message}</li>
5588
+ `)}
5589
+ </ul>
5590
+ </div>
5591
+ ` : ""}
5592
+
5593
+ <!-- Form Sections or No Selection Message (hidden in admin mode) -->
5594
+ ${this.mode === "admin" ? schema.sections.map((section, index) => html`
5595
+ <div class="admin-mode-placeholder">
5596
+ ${this._renderAdminModeContent(section)}
5597
+ </div>
5598
+ `) : schema.sections.length === 0 ? html`
5599
+ <div class="no-roles-message">
5600
+ <h3>No Roles Selected</h3>
5601
+ <p>Please use the "Filter Roles" button below to select which sections you want to work with.</p>
5602
+ <p>Available roles: ${this._allSections.length}</p>
5603
+ </div>
5604
+ ` : schema.sections.map((section, index) => html`
5605
+ <jupiter-form-section
5606
+ .section="${section}"
5607
+ .columns="${section.columns || this._columns}"
5608
+ .formData="${this._formData}"
5609
+ .typedMemberData="${this._typedMemberData}"
5610
+ .disabled="${this.disabled || this.readonly}"
5611
+ .collapsible="${config.collapsibleSections !== false}"
5612
+ .locale="${config.locale || "en-US"}"
5613
+ .isFirstSection="${index === 0}"
5614
+ .availableDimensions="${this._getAvailableDimensionsForSection(section.id)}"
5615
+ @field-change="${this._handleFieldChange}"
5616
+ @typed-member-change="${this._handleTypedMemberChange}"
5617
+ @section-expand="${this._handleSectionExpand}"
5618
+ @concept-expand="${this._handleConceptExpand}"
5619
+ @column-remove="${this._handleColumnRemove}"
5620
+ @column-add-request="${this._handleColumnAddRequest}"
5621
+ ></jupiter-form-section>
5622
+ `)}
5623
+ </div>
5624
+ `;
5625
+ }
5626
+ _renderSidePanelLayout(schema, config, showValidationSummary, errorCount) {
5627
+ const visibleSections = schema.sections;
5628
+ if (!this._activeSidePanelRoleId || !visibleSections.find((s2) => s2.id === this._activeSidePanelRoleId)) {
5629
+ this._activeSidePanelRoleId = visibleSections.length > 0 ? visibleSections[0].id : null;
5630
+ }
5631
+ const activeSection = visibleSections.find((s2) => s2.id === this._activeSidePanelRoleId);
5632
+ return html`
5633
+ <div class="side-panel-layout">
5634
+ <!-- Left: Roles List (filtered) -->
5635
+ <div class="side-panel-roles-list">
5636
+ ${visibleSections.map((section) => html`
5637
+ <div
5638
+ class="side-panel-role-item ${section.id === this._activeSidePanelRoleId ? "active" : ""}"
5639
+ @click="${() => this._handleSidePanelRoleClick(section.id)}"
5640
+ >
5641
+ ${section.title}
5642
+ </div>
5643
+ `)}
5644
+ </div>
5645
+
5646
+ <!-- Right: Active Section Content -->
5647
+ <div class="side-panel-content">
5648
+ <div class="form-sections">
5649
+ <!-- Validation Summary -->
5650
+ ${showValidationSummary ? html`
5651
+ <div class="validation-summary">
5652
+ <h4 class="validation-summary-title">Please fix the following errors:</h4>
5653
+ <ul class="validation-summary-list">
5654
+ ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
5655
+ <li class="validation-summary-item">${error.message}</li>
5656
+ `)}
5657
+ </ul>
5658
+ </div>
5659
+ ` : ""}
5660
+
5661
+ <!-- Active Section (hidden in admin mode) -->
5662
+ ${this.mode === "admin" ? html`
5663
+ <div class="admin-mode-placeholder">
5664
+ ${this._renderAdminModeContent(activeSection)}
5665
+ </div>
5666
+ ` : activeSection ? html`
5667
+ <jupiter-form-section
5668
+ .section="${activeSection}"
5669
+ .columns="${activeSection.columns || this._columns}"
5670
+ .formData="${this._formData}"
5671
+ .typedMemberData="${this._typedMemberData}"
5672
+ .disabled="${this.disabled || this.readonly}"
5673
+ .collapsible="${false}"
5674
+ .hideHeader="${true}"
5675
+ .locale="${config.locale || "en-US"}"
5676
+ .isFirstSection="${true}"
5677
+ .availableDimensions="${this._getAvailableDimensionsForSection(activeSection.id)}"
5678
+ @field-change="${this._handleFieldChange}"
5679
+ @typed-member-change="${this._handleTypedMemberChange}"
5680
+ @section-expand="${this._handleSectionExpand}"
5681
+ @concept-expand="${this._handleConceptExpand}"
5682
+ @column-remove="${this._handleColumnRemove}"
5683
+ @column-add-request="${this._handleColumnAddRequest}"
5684
+ ></jupiter-form-section>
5685
+ ` : html`
5686
+ <div class="no-roles-message">
5687
+ <h3>No Role Selected</h3>
5688
+ <p>Please select a role from the list on the left.</p>
5689
+ </div>
5690
+ `}
5691
+ </div>
5692
+ </div>
5693
+ </div>
5694
+ `;
5695
+ }
4894
5696
  // Public API methods
4895
5697
  getData() {
4896
5698
  return { ...this._formData };
@@ -4921,55 +5723,18 @@ let JupiterDynamicForm = class extends LitElement {
4921
5723
  }
4922
5724
  return html`
4923
5725
  <div class="form-container">
4924
- <!-- Form Header -->
4925
- <div class="form-header">
4926
- <h1 class="form-title">${schema.title}</h1>
4927
- ${schema.description ? html`
4928
- <p class="form-description">${schema.description}</p>
4929
- ` : ""}
4930
- </div>
5726
+ <!-- Form Header - Hidden in side panel mode -->
5727
+ ${this.display !== "sidePanel" ? html`
5728
+ <div class="form-header">
5729
+ <h1 class="form-title">${schema.title}</h1>
5730
+ ${schema.description ? html`
5731
+ <p class="form-description">${schema.description}</p>
5732
+ ` : ""}
5733
+ </div>
5734
+ ` : ""}
4931
5735
 
4932
5736
  <!-- Form Content -->
4933
- <div class="form-sections">
4934
- <!-- Validation Summary -->
4935
- ${showValidationSummary ? html`
4936
- <div class="validation-summary">
4937
- <h4 class="validation-summary-title">Please fix the following errors:</h4>
4938
- <ul class="validation-summary-list">
4939
- ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
4940
- <li class="validation-summary-item">${error.message}</li>
4941
- `)}
4942
- </ul>
4943
- </div>
4944
- ` : ""}
4945
-
4946
- <!-- Form Sections or No Selection Message -->
4947
- ${schema.sections.length === 0 ? html`
4948
- <div class="no-roles-message">
4949
- <h3>No Roles Selected</h3>
4950
- <p>Please use the "Filter Roles" button below to select which sections you want to work with.</p>
4951
- <p>Available roles: ${this._allSections.length}</p>
4952
- </div>
4953
- ` : schema.sections.map((section, index) => html`
4954
- <jupiter-form-section
4955
- .section="${section}"
4956
- .columns="${section.columns || this._columns}"
4957
- .formData="${this._formData}"
4958
- .typedMemberData="${this._typedMemberData}"
4959
- .disabled="${this.disabled || this.readonly}"
4960
- .collapsible="${config.collapsibleSections !== false}"
4961
- .locale="${config.locale || "en-US"}"
4962
- .isFirstSection="${index === 0}"
4963
- .availableDimensions="${this._getAvailableDimensionsForSection(section.id)}"
4964
- @field-change="${this._handleFieldChange}"
4965
- @typed-member-change="${this._handleTypedMemberChange}"
4966
- @section-expand="${this._handleSectionExpand}"
4967
- @concept-expand="${this._handleConceptExpand}"
4968
- @column-remove="${this._handleColumnRemove}"
4969
- @column-add-request="${this._handleColumnAddRequest}"
4970
- ></jupiter-form-section>
4971
- `)}
4972
- </div>
5737
+ ${this.display === "sidePanel" ? this._renderSidePanelLayout(schema, config, showValidationSummary, errorCount) : this._renderAccordionLayout(schema, config, showValidationSummary, errorCount)}
4973
5738
 
4974
5739
  <!-- Form Actions - Fixed Footer -->
4975
5740
  <div class="form-actions">
@@ -5017,6 +5782,7 @@ let JupiterDynamicForm = class extends LitElement {
5017
5782
  ?open="${this._showFilterDialog}"
5018
5783
  .availableRoles="${this._allSections}"
5019
5784
  .selectedRoleIds="${this._selectedRoleIds}"
5785
+ .periodPreferences="${this._periodPreferences}"
5020
5786
  @dialog-cancel="${this._handleFilterDialogCancel}"
5021
5787
  @roles-filter-apply="${this._handleRoleFilterApply}"
5022
5788
  @click="${this._handleFilterDialogCancel}"
@@ -5216,6 +5982,119 @@ JupiterDynamicForm.styles = css`
5216
5982
  margin: 8px 0;
5217
5983
  line-height: 1.5;
5218
5984
  }
5985
+
5986
+ /* Side Panel Layout Styles */
5987
+ .side-panel-layout {
5988
+ display: flex;
5989
+ height: calc(100vh - 80px); /* Account for footer only */
5990
+ gap: 0;
5991
+ }
5992
+
5993
+ .side-panel-roles-list {
5994
+ width: 280px;
5995
+ min-width: 280px;
5996
+ border-right: 1px solid var(--jupiter-border-color, #ddd);
5997
+ overflow-y: auto;
5998
+ background: var(--jupiter-background-light, #f8f9fa);
5999
+ }
6000
+
6001
+ .side-panel-role-item {
6002
+ padding: 12px 16px;
6003
+ cursor: pointer;
6004
+ border-bottom: 1px solid var(--jupiter-border-color, #e0e0e0);
6005
+ transition: background-color 0.2s ease;
6006
+ font-size: 14px;
6007
+ color: var(--jupiter-text-primary, #333);
6008
+ line-height: 1.4;
6009
+ }
6010
+
6011
+ .side-panel-role-item:hover {
6012
+ background: var(--jupiter-hover-background, #e8e8e8);
6013
+ }
6014
+
6015
+ .side-panel-role-item.active {
6016
+ background: var(--jupiter-primary-color, #1976d2);
6017
+ color: white;
6018
+ font-weight: 500;
6019
+ }
6020
+
6021
+ .side-panel-content {
6022
+ flex: 1;
6023
+ overflow-y: auto;
6024
+ padding: 0;
6025
+ }
6026
+
6027
+ .side-panel-content .form-sections {
6028
+ padding: 0 24px 24px 24px;
6029
+ padding-top: 0;
6030
+ }
6031
+
6032
+ /* Admin Mode Styles */
6033
+ .admin-mode-placeholder {
6034
+ padding: 0;
6035
+ background: white;
6036
+ min-height: 300px;
6037
+ }
6038
+
6039
+ .admin-mode-container {
6040
+ max-width: 1200px;
6041
+ margin: 0 auto;
6042
+ padding: 24px;
6043
+ }
6044
+
6045
+ .admin-mode-title {
6046
+ font-size: 20px;
6047
+ font-weight: 600;
6048
+ margin: 0 0 24px 0;
6049
+ color: var(--jupiter-text-primary, #333);
6050
+ }
6051
+
6052
+ .admin-roles-list {
6053
+ display: flex;
6054
+ flex-direction: column;
6055
+ gap: 12px;
6056
+ }
6057
+
6058
+ .admin-role-item {
6059
+ display: flex;
6060
+ align-items: center;
6061
+ padding: 16px;
6062
+ background: var(--jupiter-background-light, #f8f9fa);
6063
+ border: 1px solid var(--jupiter-border-color, #ddd);
6064
+ border-radius: 6px;
6065
+ transition: background-color 0.2s ease;
6066
+ }
6067
+
6068
+ .admin-role-item:hover {
6069
+ background: var(--jupiter-hover-background, #e8e8e8);
6070
+ }
6071
+
6072
+ .admin-role-title {
6073
+ flex: 1;
6074
+ font-size: 14px;
6075
+ font-weight: 500;
6076
+ color: var(--jupiter-text-primary, #333);
6077
+ }
6078
+
6079
+ .admin-role-checkbox {
6080
+ display: flex;
6081
+ align-items: center;
6082
+ gap: 8px;
6083
+ margin-left: 16px;
6084
+ }
6085
+
6086
+ .admin-role-checkbox input[type="checkbox"] {
6087
+ width: 18px;
6088
+ height: 18px;
6089
+ cursor: pointer;
6090
+ }
6091
+
6092
+ .admin-role-checkbox label {
6093
+ font-size: 13px;
6094
+ color: var(--jupiter-text-secondary, #666);
6095
+ cursor: pointer;
6096
+ user-select: none;
6097
+ }
5219
6098
  `;
5220
6099
  __decorateClass([
5221
6100
  n2({ type: Object })
@@ -5244,6 +6123,15 @@ __decorateClass([
5244
6123
  __decorateClass([
5245
6124
  n2({ type: String })
5246
6125
  ], JupiterDynamicForm.prototype, "language", 2);
6126
+ __decorateClass([
6127
+ n2({ type: String })
6128
+ ], JupiterDynamicForm.prototype, "display", 2);
6129
+ __decorateClass([
6130
+ n2({ type: String })
6131
+ ], JupiterDynamicForm.prototype, "mode", 2);
6132
+ __decorateClass([
6133
+ n2({ type: Array })
6134
+ ], JupiterDynamicForm.prototype, "financialStatementsTypeAxis", 2);
5247
6135
  __decorateClass([
5248
6136
  r()
5249
6137
  ], JupiterDynamicForm.prototype, "_formData", 2);
@@ -5286,6 +6174,15 @@ __decorateClass([
5286
6174
  __decorateClass([
5287
6175
  r()
5288
6176
  ], JupiterDynamicForm.prototype, "_showFilterDialog", 2);
6177
+ __decorateClass([
6178
+ r()
6179
+ ], JupiterDynamicForm.prototype, "_periodPreferences", 2);
6180
+ __decorateClass([
6181
+ r()
6182
+ ], JupiterDynamicForm.prototype, "_activeSidePanelRoleId", 2);
6183
+ __decorateClass([
6184
+ r()
6185
+ ], JupiterDynamicForm.prototype, "_adminRoleConfigs", 2);
5289
6186
  JupiterDynamicForm = __decorateClass([
5290
6187
  t$1("jupiter-dynamic-form")
5291
6188
  ], JupiterDynamicForm);
@@ -5298,6 +6195,12 @@ export {
5298
6195
  JupiterFilterRolesDialog,
5299
6196
  JupiterFormField,
5300
6197
  JupiterFormSection,
6198
+ TYPE_INPUT_MAP,
6199
+ getInputTypeForConceptType,
6200
+ isCheckboxType,
6201
+ isNumericType,
6202
+ isSelectType,
6203
+ isTextareaType,
5301
6204
  version
5302
6205
  };
5303
6206
  //# sourceMappingURL=index.mjs.map