jupiter-dynamic-forms 1.13.0 → 1.14.1

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
@@ -346,9 +346,9 @@ class FormValidator {
346
346
  static validateField(fieldId, conceptId, columnId, value, fieldType, rules = []) {
347
347
  const errors = [];
348
348
  for (const rule of rules) {
349
- const error = this.validateRule(fieldId, conceptId, columnId, value, fieldType, rule);
350
- if (error) {
351
- errors.push(error);
349
+ const error2 = this.validateRule(fieldId, conceptId, columnId, value, fieldType, rule);
350
+ if (error2) {
351
+ errors.push(error2);
352
352
  }
353
353
  }
354
354
  return errors;
@@ -579,18 +579,25 @@ class XBRLFormBuilder {
579
579
  * @param periodPreferences - User preferences for which period columns to show per role
580
580
  */
581
581
  static buildFormSchema(xbrlInput, periodStartDate, periodEndDate, language = "en", periodPreferences) {
582
- var _a;
582
+ var _a, _b;
583
583
  if (!xbrlInput.presentation || xbrlInput.presentation.length === 0) {
584
584
  throw new Error("XBRL presentation data is required");
585
585
  }
586
586
  const presentationData = xbrlInput.presentation[0];
587
587
  const hypercubeData = (_a = xbrlInput.hypercubes) == null ? void 0 : _a[0];
588
+ const datatypes = Array.isArray(xbrlInput.datatypes) ? xbrlInput.datatypes : ((_b = xbrlInput.datatypes) == null ? void 0 : _b.concepts) || [];
588
589
  const sections = [];
589
590
  const sortedRoles = [...presentationData.roles].sort((a2, b2) => {
590
591
  return a2.role.localeCompare(b2.role);
591
592
  });
592
593
  sortedRoles.forEach((role) => {
593
594
  const section2 = this.buildSectionFromRole(role, periodStartDate, periodEndDate, hypercubeData, language, periodPreferences);
595
+ if (datatypes && datatypes.length > 0) {
596
+ section2.datatypes = datatypes;
597
+ console.log(`✅ [buildFormSchema] Attached ${datatypes.length} datatypes to section ${section2.id}`);
598
+ } else {
599
+ console.warn(`⚠️ [buildFormSchema] No datatypes available for section ${section2.id}`);
600
+ }
594
601
  this.assignFieldColumnIds(section2);
595
602
  sections.push(section2);
596
603
  });
@@ -660,9 +667,9 @@ class XBRLFormBuilder {
660
667
  columnIds = ["duration"];
661
668
  }
662
669
  columnIds.forEach((columnId) => {
663
- const field = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
664
- if (field)
665
- fields.push(field);
670
+ const field2 = this.createFieldFromConcept(concept, periodStartDate, periodEndDate, columnId);
671
+ if (field2)
672
+ fields.push(field2);
666
673
  });
667
674
  }
668
675
  const children = [];
@@ -709,7 +716,7 @@ class XBRLFormBuilder {
709
716
  } else {
710
717
  columnId = "duration";
711
718
  }
712
- const field = {
719
+ const field2 = {
713
720
  id: `${concept.id}_${columnId}_field`,
714
721
  conceptId: concept.id,
715
722
  columnId,
@@ -728,9 +735,9 @@ class XBRLFormBuilder {
728
735
  periodInstantDate: concept.periodType === "instant" ? periodEndDate || periodStartDate || "2025-01-01" : void 0
729
736
  };
730
737
  if (concept.id === "nl-cd_DescriptionLocationNL__a64trl") {
731
- console.log(`🏗️ [Field Creation] Concept: ${concept.id}, periodType from concept: ${concept.periodType}, Field periodType: ${field.periodType}, ColumnId: ${columnId}`);
738
+ console.log(`🏗️ [Field Creation] Concept: ${concept.id}, periodType from concept: ${concept.periodType}, Field periodType: ${field2.periodType}, ColumnId: ${columnId}`);
732
739
  }
733
- return field;
740
+ return field2;
734
741
  }
735
742
  /**
736
743
  * Map XBRL data type to form field type
@@ -786,8 +793,8 @@ class XBRLFormBuilder {
786
793
  * Recursively assign column IDs to fields in a concept tree
787
794
  */
788
795
  static assignColumnIdsToConceptFields(conceptTree, columnIds) {
789
- conceptTree.fields = conceptTree.fields.filter((field) => {
790
- return columnIds.includes(field.columnId);
796
+ conceptTree.fields = conceptTree.fields.filter((field2) => {
797
+ return columnIds.includes(field2.columnId);
791
798
  });
792
799
  if (conceptTree.children) {
793
800
  conceptTree.children.forEach((child) => {
@@ -911,8 +918,8 @@ class XBRLFormBuilder {
911
918
  const date = new Date(dateString);
912
919
  date.setFullYear(date.getFullYear() - 1);
913
920
  return date.toISOString().split("T")[0];
914
- } catch (error) {
915
- console.error(`Error calculating previous year for date ${dateString}:`, error);
921
+ } catch (error2) {
922
+ console.error(`Error calculating previous year for date ${dateString}:`, error2);
916
923
  return dateString;
917
924
  }
918
925
  }
@@ -1500,6 +1507,25 @@ const column$1 = {
1500
1507
  const section$1 = {
1501
1508
  enterPlaceholder: "Enter"
1502
1509
  };
1510
+ const field$1 = {
1511
+ selectOption: "Select an option...",
1512
+ select: "Select...",
1513
+ enterDetailedExplanation: "Enter detailed explanation...",
1514
+ enterAmountNoDecimals: "Enter amount (no decimals)",
1515
+ enterCurrency: "0.00",
1516
+ enterText: "Enter text",
1517
+ enterWholeNumber: "Enter whole number",
1518
+ enterPositiveNumber: "Enter positive number",
1519
+ enterDecimalValue: "Enter decimal value",
1520
+ enterNumberOfShares: "Enter number of shares",
1521
+ yearFormat: "YYYY",
1522
+ enterPercentage: "Enter percentage",
1523
+ emailPlaceholder: "email@example.com",
1524
+ urlPlaceholder: "https://example.com",
1525
+ phonePlaceholder: "+1 (555) 000-0000",
1526
+ enterValue: "Enter value",
1527
+ enterDetailedInformation: "Enter detailed information..."
1528
+ };
1503
1529
  const admin$1 = {
1504
1530
  title: "Configure Roles",
1505
1531
  description: "Select which roles should display the 'Show Previous Year' checkbox and configure period type columns."
@@ -1508,13 +1534,26 @@ const validation$1 = {
1508
1534
  summary: "Please fix the following errors before submitting:",
1509
1535
  errorsFound: "errors found"
1510
1536
  };
1537
+ const error$1 = {
1538
+ popup: {
1539
+ title: "Validation Errors",
1540
+ message: "Please fix the following validation errors before saving:",
1541
+ field: "Field:",
1542
+ value: "Value:",
1543
+ errors: "Errors:",
1544
+ clickToFocus: "Click to focus this field",
1545
+ ok: "OK"
1546
+ }
1547
+ };
1511
1548
  const enTranslations = {
1512
1549
  form: form$1,
1513
1550
  filter: filter$1,
1514
1551
  column: column$1,
1515
1552
  section: section$1,
1553
+ field: field$1,
1516
1554
  admin: admin$1,
1517
- validation: validation$1
1555
+ validation: validation$1,
1556
+ error: error$1
1518
1557
  };
1519
1558
  const form = {
1520
1559
  loading: "Formulier laden...",
@@ -1581,6 +1620,25 @@ const column = {
1581
1620
  const section = {
1582
1621
  enterPlaceholder: "Invoeren"
1583
1622
  };
1623
+ const field = {
1624
+ selectOption: "Selecteer een optie...",
1625
+ select: "Selecteer...",
1626
+ enterDetailedExplanation: "Voer gedetailleerde uitleg in...",
1627
+ enterAmountNoDecimals: "Voer bedrag in (geen decimalen)",
1628
+ enterCurrency: "0,00",
1629
+ enterText: "Voer tekst in",
1630
+ enterWholeNumber: "Voer geheel getal in",
1631
+ enterPositiveNumber: "Voer positief getal in",
1632
+ enterDecimalValue: "Voer decimale waarde in",
1633
+ enterNumberOfShares: "Voer aantal aandelen in",
1634
+ yearFormat: "JJJJ",
1635
+ enterPercentage: "Voer percentage in",
1636
+ emailPlaceholder: "email@voorbeeld.nl",
1637
+ urlPlaceholder: "https://voorbeeld.nl",
1638
+ phonePlaceholder: "+31 (0)20 123 4567",
1639
+ enterValue: "Voer waarde in",
1640
+ enterDetailedInformation: "Voer gedetailleerde informatie in..."
1641
+ };
1584
1642
  const admin = {
1585
1643
  title: "Rollen configureren",
1586
1644
  description: "Selecteer welke rollen het selectievakje 'Vorig jaar weergeven' moeten weergeven en configureer periodetype kolommen."
@@ -1589,13 +1647,26 @@ const validation = {
1589
1647
  summary: "Corrigeer de volgende fouten voordat u indient:",
1590
1648
  errorsFound: "fouten gevonden"
1591
1649
  };
1650
+ const error = {
1651
+ popup: {
1652
+ title: "Validatiefouten",
1653
+ message: "Corrigeer de volgende validatiefouten voordat u opslaat:",
1654
+ field: "Veld:",
1655
+ value: "Waarde:",
1656
+ errors: "Fouten:",
1657
+ clickToFocus: "Klik om dit veld te focussen",
1658
+ ok: "OK"
1659
+ }
1660
+ };
1592
1661
  const nlTranslations = {
1593
1662
  form,
1594
1663
  filter,
1595
1664
  column,
1596
1665
  section,
1666
+ field,
1597
1667
  admin,
1598
- validation
1668
+ validation,
1669
+ error
1599
1670
  };
1600
1671
  const translations = {
1601
1672
  en: enTranslations,
@@ -1707,8 +1778,8 @@ class DraftStorageService {
1707
1778
  customColumns: metadata.customColumns.length
1708
1779
  });
1709
1780
  return true;
1710
- } catch (error) {
1711
- console.error("❌ Failed to save draft:", error);
1781
+ } catch (error2) {
1782
+ console.error("❌ Failed to save draft:", error2);
1712
1783
  return false;
1713
1784
  }
1714
1785
  }
@@ -1736,8 +1807,8 @@ class DraftStorageService {
1736
1807
  metadata,
1737
1808
  version: this.STORAGE_VERSION
1738
1809
  };
1739
- } catch (error) {
1740
- console.error("❌ Failed to load draft:", error);
1810
+ } catch (error2) {
1811
+ console.error("❌ Failed to load draft:", error2);
1741
1812
  return null;
1742
1813
  }
1743
1814
  }
@@ -1756,8 +1827,8 @@ class DraftStorageService {
1756
1827
  if (!metadataStr)
1757
1828
  return null;
1758
1829
  return JSON.parse(metadataStr);
1759
- } catch (error) {
1760
- console.error("❌ Failed to load draft metadata:", error);
1830
+ } catch (error2) {
1831
+ console.error("❌ Failed to load draft metadata:", error2);
1761
1832
  return null;
1762
1833
  }
1763
1834
  }
@@ -1770,8 +1841,8 @@ class DraftStorageService {
1770
1841
  this._storage.removeItem(this.DRAFT_METADATA_KEY);
1771
1842
  console.log("🗑️ Draft cleared successfully");
1772
1843
  return true;
1773
- } catch (error) {
1774
- console.error("❌ Failed to clear draft:", error);
1844
+ } catch (error2) {
1845
+ console.error("❌ Failed to clear draft:", error2);
1775
1846
  return false;
1776
1847
  }
1777
1848
  }
@@ -1831,16 +1902,18 @@ class DraftStorageService {
1831
1902
  /**
1832
1903
  * Create metadata snapshot from current form state
1833
1904
  */
1834
- createMetadataSnapshot(periodStartDate, periodEndDate, language, selectedRoleIds, allSections, typedMemberData, periodPreferences, periodData) {
1905
+ createMetadataSnapshot(periodStartDate, periodEndDate, language, selectedRoleIds, allSections, typedMemberData, periodPreferences, periodData, unitData) {
1835
1906
  return {
1836
1907
  periodStartDate,
1837
1908
  periodEndDate,
1838
1909
  language,
1839
1910
  selectedRoleIds,
1911
+ // Store enhanced structure (with roleURI and order) or legacy string array
1840
1912
  customColumns: this.extractCustomColumns(allSections),
1841
1913
  typedMemberData,
1842
1914
  periodPreferences,
1843
1915
  periodData,
1916
+ unitData,
1844
1917
  schemaVersion: this.STORAGE_VERSION
1845
1918
  };
1846
1919
  }
@@ -1863,6 +1936,204 @@ class DraftStorageService {
1863
1936
  return { compatible, warnings };
1864
1937
  }
1865
1938
  }
1939
+ class XBRLValidator {
1940
+ /**
1941
+ * Validates a value against XBRL datatype validation rules
1942
+ * Only validates when value is not blank
1943
+ *
1944
+ * @param conceptType - The XBRL concept type (e.g., "nl-types:houseNumberNLItemType")
1945
+ * @param value - The input value to validate
1946
+ * @param datatypes - Array of XBRL datatypes from taxonomy
1947
+ * @returns Validation result with errors if any
1948
+ */
1949
+ static validateConceptValue(conceptType, value, datatypes) {
1950
+ const errors = [];
1951
+ if (value === null || value === void 0 || value === "") {
1952
+ return { valid: true, errors: [] };
1953
+ }
1954
+ if (!conceptType || !datatypes || datatypes.length === 0) {
1955
+ return { valid: true, errors: [] };
1956
+ }
1957
+ const datatype = this.findDatatype(conceptType, datatypes);
1958
+ if (!datatype || !datatype.validation) {
1959
+ return { valid: true, errors: [] };
1960
+ }
1961
+ const validation2 = datatype.validation;
1962
+ const stringValue = String(value);
1963
+ if (validation2.pattern) {
1964
+ const patternError = this.validatePattern(stringValue, validation2.pattern);
1965
+ if (patternError) {
1966
+ errors.push(patternError);
1967
+ }
1968
+ }
1969
+ if (validation2.length !== void 0) {
1970
+ const lengthError = this.validateExactLength(stringValue, validation2.length);
1971
+ if (lengthError) {
1972
+ errors.push(lengthError);
1973
+ }
1974
+ }
1975
+ if (validation2.minLength !== void 0) {
1976
+ const minLengthError = this.validateMinLength(stringValue, validation2.minLength);
1977
+ if (minLengthError) {
1978
+ errors.push(minLengthError);
1979
+ }
1980
+ }
1981
+ if (validation2.maxLength !== void 0) {
1982
+ const maxLengthError = this.validateMaxLength(stringValue, validation2.maxLength);
1983
+ if (maxLengthError) {
1984
+ errors.push(maxLengthError);
1985
+ }
1986
+ }
1987
+ if (validation2.totalDigits !== void 0) {
1988
+ const totalDigitsError = this.validateTotalDigits(stringValue, validation2.totalDigits);
1989
+ if (totalDigitsError) {
1990
+ errors.push(totalDigitsError);
1991
+ }
1992
+ }
1993
+ return {
1994
+ valid: errors.length === 0,
1995
+ errors
1996
+ };
1997
+ }
1998
+ /**
1999
+ * Finds the datatype definition for a given concept type
2000
+ * Handles both exact matches and base type chain resolution
2001
+ */
2002
+ static findDatatype(conceptType, datatypes) {
2003
+ let datatype = datatypes.find((dt) => dt.type === conceptType);
2004
+ if (datatype) {
2005
+ return datatype;
2006
+ }
2007
+ const visited = /* @__PURE__ */ new Set();
2008
+ let currentType = conceptType;
2009
+ while (currentType && !visited.has(currentType)) {
2010
+ visited.add(currentType);
2011
+ datatype = datatypes.find((dt) => dt.type === currentType);
2012
+ if (datatype) {
2013
+ if (datatype.validation) {
2014
+ return datatype;
2015
+ }
2016
+ currentType = datatype.basetype;
2017
+ } else {
2018
+ break;
2019
+ }
2020
+ }
2021
+ return void 0;
2022
+ }
2023
+ /**
2024
+ * Validates that value matches the regex pattern
2025
+ */
2026
+ static validatePattern(value, pattern) {
2027
+ try {
2028
+ const regex = new RegExp(`^${pattern}$`);
2029
+ if (!regex.test(value)) {
2030
+ return {
2031
+ type: "pattern",
2032
+ message: `Value does not match required pattern: ${pattern}`,
2033
+ expectedValue: pattern,
2034
+ actualValue: value
2035
+ };
2036
+ }
2037
+ } catch (error2) {
2038
+ console.error(`Invalid regex pattern: ${pattern}`, error2);
2039
+ return {
2040
+ type: "pattern",
2041
+ message: `Invalid pattern configuration: ${pattern}`,
2042
+ expectedValue: pattern,
2043
+ actualValue: value
2044
+ };
2045
+ }
2046
+ return null;
2047
+ }
2048
+ /**
2049
+ * Validates that value has exact length
2050
+ */
2051
+ static validateExactLength(value, requiredLength) {
2052
+ if (value.length !== requiredLength) {
2053
+ return {
2054
+ type: "length",
2055
+ message: `Value must be exactly ${requiredLength} characters (current: ${value.length})`,
2056
+ expectedValue: requiredLength,
2057
+ actualValue: value.length
2058
+ };
2059
+ }
2060
+ return null;
2061
+ }
2062
+ /**
2063
+ * Validates minimum length
2064
+ */
2065
+ static validateMinLength(value, minLength) {
2066
+ if (value.length < minLength) {
2067
+ return {
2068
+ type: "minLength",
2069
+ message: `Value must be at least ${minLength} characters (current: ${value.length})`,
2070
+ expectedValue: minLength,
2071
+ actualValue: value.length
2072
+ };
2073
+ }
2074
+ return null;
2075
+ }
2076
+ /**
2077
+ * Validates maximum length
2078
+ */
2079
+ static validateMaxLength(value, maxLength) {
2080
+ if (value.length > maxLength) {
2081
+ return {
2082
+ type: "maxLength",
2083
+ message: `Value must not exceed ${maxLength} characters (current: ${value.length})`,
2084
+ expectedValue: maxLength,
2085
+ actualValue: value.length
2086
+ };
2087
+ }
2088
+ return null;
2089
+ }
2090
+ /**
2091
+ * Validates total digits (for numeric values)
2092
+ */
2093
+ static validateTotalDigits(value, totalDigits) {
2094
+ const digitsOnly = value.replace(/[^\d]/g, "");
2095
+ if (digitsOnly.length > totalDigits) {
2096
+ return {
2097
+ type: "totalDigits",
2098
+ message: `Value must not exceed ${totalDigits} total digits (current: ${digitsOnly.length})`,
2099
+ expectedValue: totalDigits,
2100
+ actualValue: digitsOnly.length
2101
+ };
2102
+ }
2103
+ return null;
2104
+ }
2105
+ /**
2106
+ * Gets a human-readable summary of validation rules for a concept type
2107
+ * Useful for displaying validation hints to users
2108
+ */
2109
+ static getValidationRulesSummary(conceptType, datatypes) {
2110
+ if (!conceptType || !datatypes) {
2111
+ return [];
2112
+ }
2113
+ const datatype = this.findDatatype(conceptType, datatypes);
2114
+ if (!datatype || !datatype.validation) {
2115
+ return [];
2116
+ }
2117
+ const validation2 = datatype.validation;
2118
+ const rules = [];
2119
+ if (validation2.pattern) {
2120
+ rules.push(`Must match pattern: ${validation2.pattern}`);
2121
+ }
2122
+ if (validation2.length !== void 0) {
2123
+ rules.push(`Must be exactly ${validation2.length} characters`);
2124
+ }
2125
+ if (validation2.minLength !== void 0) {
2126
+ rules.push(`Minimum ${validation2.minLength} characters`);
2127
+ }
2128
+ if (validation2.maxLength !== void 0) {
2129
+ rules.push(`Maximum ${validation2.maxLength} characters`);
2130
+ }
2131
+ if (validation2.totalDigits !== void 0) {
2132
+ rules.push(`Maximum ${validation2.totalDigits} total digits`);
2133
+ }
2134
+ return rules;
2135
+ }
2136
+ }
1866
2137
  const TYPE_INPUT_MAP = {
1867
2138
  // ==========================================
1868
2139
  // Dutch XBRL Types (nl-types namespace)
@@ -1870,7 +2141,7 @@ const TYPE_INPUT_MAP = {
1870
2141
  // Text area for long-form explanations
1871
2142
  "nl-types:formattedExplanationItemType": {
1872
2143
  fieldType: "textarea",
1873
- placeholder: "Enter detailed explanation..."
2144
+ placeholder: I18n.t("field.enterDetailedExplanation")
1874
2145
  },
1875
2146
  // Monetary values without decimals (whole numbers only)
1876
2147
  "nl-types:monetaryNoDecimals20ItemType": {
@@ -1878,7 +2149,7 @@ const TYPE_INPUT_MAP = {
1878
2149
  htmlInputType: "number",
1879
2150
  allowDecimals: false,
1880
2151
  step: 1,
1881
- placeholder: "Enter amount (no decimals)"
2152
+ placeholder: I18n.t("field.enterAmountNoDecimals")
1882
2153
  },
1883
2154
  // ==========================================
1884
2155
  // Standard XBRL Types (xbrli namespace)
@@ -1889,13 +2160,13 @@ const TYPE_INPUT_MAP = {
1889
2160
  htmlInputType: "number",
1890
2161
  allowDecimals: true,
1891
2162
  step: 0.01,
1892
- placeholder: "0.00"
2163
+ placeholder: I18n.t("field.enterCurrency")
1893
2164
  },
1894
2165
  // String/text types
1895
2166
  "xbrli:stringItemType": {
1896
2167
  fieldType: "text",
1897
2168
  htmlInputType: "text",
1898
- placeholder: "Enter text"
2169
+ placeholder: I18n.t("field.enterText")
1899
2170
  },
1900
2171
  // Date types
1901
2172
  "xbrli:dateItemType": {
@@ -1912,7 +2183,7 @@ const TYPE_INPUT_MAP = {
1912
2183
  htmlInputType: "number",
1913
2184
  allowDecimals: false,
1914
2185
  step: 1,
1915
- placeholder: "Enter whole number"
2186
+ placeholder: I18n.t("field.enterWholeNumber")
1916
2187
  },
1917
2188
  "xbrli:nonNegativeIntegerItemType": {
1918
2189
  fieldType: "integer",
@@ -1920,7 +2191,7 @@ const TYPE_INPUT_MAP = {
1920
2191
  allowDecimals: false,
1921
2192
  min: 0,
1922
2193
  step: 1,
1923
- placeholder: "Enter positive number"
2194
+ placeholder: I18n.t("field.enterPositiveNumber")
1924
2195
  },
1925
2196
  "xbrli:positiveIntegerItemType": {
1926
2197
  fieldType: "integer",
@@ -1928,7 +2199,7 @@ const TYPE_INPUT_MAP = {
1928
2199
  allowDecimals: false,
1929
2200
  min: 1,
1930
2201
  step: 1,
1931
- placeholder: "Enter positive number"
2202
+ placeholder: I18n.t("field.enterPositiveNumber")
1932
2203
  },
1933
2204
  // Numeric types - decimals
1934
2205
  "xbrli:decimalItemType": {
@@ -1936,7 +2207,7 @@ const TYPE_INPUT_MAP = {
1936
2207
  htmlInputType: "number",
1937
2208
  allowDecimals: true,
1938
2209
  step: "any",
1939
- placeholder: "Enter decimal value"
2210
+ placeholder: I18n.t("field.enterDecimalValue")
1940
2211
  },
1941
2212
  // Shares (typically whole numbers or with limited decimals)
1942
2213
  "xbrli:sharesItemType": {
@@ -1945,7 +2216,7 @@ const TYPE_INPUT_MAP = {
1945
2216
  allowDecimals: true,
1946
2217
  min: 0,
1947
2218
  step: 0.01,
1948
- placeholder: "Enter number of shares"
2219
+ placeholder: I18n.t("field.enterNumberOfShares")
1949
2220
  },
1950
2221
  "xbrli:shares": {
1951
2222
  fieldType: "number",
@@ -1953,7 +2224,7 @@ const TYPE_INPUT_MAP = {
1953
2224
  allowDecimals: true,
1954
2225
  min: 0,
1955
2226
  step: 0.01,
1956
- placeholder: "Enter number of shares"
2227
+ placeholder: I18n.t("field.enterNumberOfShares")
1957
2228
  },
1958
2229
  // Year (gYear)
1959
2230
  "xbrli:gYearItemType": {
@@ -1963,7 +2234,7 @@ const TYPE_INPUT_MAP = {
1963
2234
  min: 1900,
1964
2235
  max: 2100,
1965
2236
  step: 1,
1966
- placeholder: "YYYY"
2237
+ placeholder: I18n.t("field.yearFormat")
1967
2238
  },
1968
2239
  // Boolean types
1969
2240
  "xbrli:booleanItemType": {
@@ -1977,14 +2248,14 @@ const TYPE_INPUT_MAP = {
1977
2248
  htmlInputType: "number",
1978
2249
  allowDecimals: true,
1979
2250
  step: 0.01,
1980
- placeholder: "Enter percentage"
2251
+ placeholder: I18n.t("field.enterPercentage")
1981
2252
  },
1982
2253
  "xbrli:percentItemType": {
1983
2254
  fieldType: "percentage",
1984
2255
  htmlInputType: "number",
1985
2256
  allowDecimals: true,
1986
2257
  step: 0.01,
1987
- placeholder: "Enter percentage"
2258
+ placeholder: I18n.t("field.enterPercentage")
1988
2259
  },
1989
2260
  // ==========================================
1990
2261
  // Contact/Communication types
@@ -1992,27 +2263,36 @@ const TYPE_INPUT_MAP = {
1992
2263
  "xbrli:emailItemType": {
1993
2264
  fieldType: "email",
1994
2265
  htmlInputType: "email",
1995
- placeholder: "email@example.com"
2266
+ placeholder: I18n.t("field.emailPlaceholder")
1996
2267
  },
1997
2268
  "xbrli:urlItemType": {
1998
2269
  fieldType: "url",
1999
2270
  htmlInputType: "url",
2000
- placeholder: "https://example.com"
2271
+ placeholder: I18n.t("field.urlPlaceholder")
2001
2272
  },
2002
2273
  "xbrli:telephoneItemType": {
2003
2274
  fieldType: "tel",
2004
2275
  htmlInputType: "tel",
2005
- placeholder: "+1 (555) 000-0000"
2276
+ placeholder: I18n.t("field.phonePlaceholder")
2006
2277
  }
2007
2278
  };
2008
- function getInputTypeForConceptType(conceptType) {
2279
+ function getInputTypeForConceptType(conceptType, datatypes) {
2009
2280
  if (!conceptType) {
2010
2281
  return {
2011
2282
  fieldType: "text",
2012
2283
  htmlInputType: "text",
2013
- placeholder: "Enter value"
2284
+ placeholder: I18n.t("field.enterValue")
2014
2285
  };
2015
2286
  }
2287
+ if (datatypes && datatypes.length > 0) {
2288
+ const baseTypeChain = resolveBaseTypeChain(conceptType, datatypes);
2289
+ if (baseTypeChain.length > 0) {
2290
+ const config = determineInputTypeFromBaseChain(baseTypeChain, datatypes);
2291
+ console.log(`🔍 [Type Resolution] ${conceptType} → Chain:`, baseTypeChain, "→ Type:", config.fieldType, config.enumerations ? `(${config.enumerations.length} options)` : "");
2292
+ return config;
2293
+ }
2294
+ }
2295
+ console.log(`⚠️ [Type Resolution Fallback] Using pattern matching for: ${conceptType}`);
2016
2296
  if (TYPE_INPUT_MAP[conceptType]) {
2017
2297
  return TYPE_INPUT_MAP[conceptType];
2018
2298
  }
@@ -2024,7 +2304,7 @@ function getInputTypeForConceptType(conceptType) {
2024
2304
  htmlInputType: "number",
2025
2305
  allowDecimals: false,
2026
2306
  step: 1,
2027
- placeholder: "Enter amount (no decimals)"
2307
+ placeholder: I18n.t("field.enterAmountNoDecimals")
2028
2308
  };
2029
2309
  }
2030
2310
  return {
@@ -2032,13 +2312,13 @@ function getInputTypeForConceptType(conceptType) {
2032
2312
  htmlInputType: "number",
2033
2313
  allowDecimals: true,
2034
2314
  step: 0.01,
2035
- placeholder: "0.00"
2315
+ placeholder: I18n.t("field.enterCurrency")
2036
2316
  };
2037
2317
  }
2038
2318
  if (lowerType.includes("explanation") || lowerType.includes("description") || lowerType.includes("notes") || lowerType.includes("formatted")) {
2039
2319
  return {
2040
2320
  fieldType: "textarea",
2041
- placeholder: "Enter detailed information..."
2321
+ placeholder: I18n.t("field.enterDetailedInformation")
2042
2322
  };
2043
2323
  }
2044
2324
  if (lowerType.includes("date")) {
@@ -2067,7 +2347,7 @@ function getInputTypeForConceptType(conceptType) {
2067
2347
  allowDecimals: false,
2068
2348
  min: isPositive ? 1 : isNonNegative ? 0 : void 0,
2069
2349
  step: 1,
2070
- placeholder: "Enter whole number"
2350
+ placeholder: I18n.t("field.enterWholeNumber")
2071
2351
  };
2072
2352
  }
2073
2353
  if (lowerType.includes("decimal") || lowerType.includes("numeric") || lowerType.includes("number")) {
@@ -2076,7 +2356,7 @@ function getInputTypeForConceptType(conceptType) {
2076
2356
  htmlInputType: "number",
2077
2357
  allowDecimals: true,
2078
2358
  step: "any",
2079
- placeholder: "Enter decimal value"
2359
+ placeholder: I18n.t("field.enterDecimalValue")
2080
2360
  };
2081
2361
  }
2082
2362
  if (lowerType.includes("percent") || lowerType.includes("pure")) {
@@ -2085,13 +2365,13 @@ function getInputTypeForConceptType(conceptType) {
2085
2365
  htmlInputType: "number",
2086
2366
  allowDecimals: true,
2087
2367
  step: 0.01,
2088
- placeholder: "Enter percentage"
2368
+ placeholder: I18n.t("field.enterPercentage")
2089
2369
  };
2090
2370
  }
2091
2371
  return {
2092
2372
  fieldType: "text",
2093
2373
  htmlInputType: "text",
2094
- placeholder: "Enter value"
2374
+ placeholder: I18n.t("field.enterValue")
2095
2375
  };
2096
2376
  }
2097
2377
  function isTextareaType(fieldType) {
@@ -2106,6 +2386,145 @@ function isNumericType(fieldType) {
2106
2386
  function isSelectType(fieldType) {
2107
2387
  return fieldType === "select";
2108
2388
  }
2389
+ function resolveBaseTypeChain(typeName, datatypes) {
2390
+ const baseTypeChain = [];
2391
+ if (!typeName) {
2392
+ return baseTypeChain;
2393
+ }
2394
+ if (!datatypes || datatypes.length === 0) {
2395
+ baseTypeChain.push(typeName);
2396
+ return baseTypeChain;
2397
+ }
2398
+ let currentType = typeName;
2399
+ const visitedTypes = /* @__PURE__ */ new Set();
2400
+ while (currentType) {
2401
+ baseTypeChain.push(currentType);
2402
+ if (visitedTypes.has(currentType)) {
2403
+ console.warn(`Circular reference detected in datatype hierarchy for type: ${currentType}`);
2404
+ break;
2405
+ }
2406
+ visitedTypes.add(currentType);
2407
+ const foundDatatype = datatypes.find((dt) => dt.type === currentType);
2408
+ if (!foundDatatype || !foundDatatype.basetype || foundDatatype.basetype.trim() === "") {
2409
+ break;
2410
+ }
2411
+ currentType = foundDatatype.basetype;
2412
+ }
2413
+ return baseTypeChain;
2414
+ }
2415
+ function collectEnumerationsFromChain(baseTypeChain, datatypes) {
2416
+ if (!baseTypeChain || baseTypeChain.length === 0 || !datatypes || datatypes.length === 0) {
2417
+ return void 0;
2418
+ }
2419
+ for (const typeName of baseTypeChain) {
2420
+ const datatype = datatypes.find((dt) => dt.type === typeName);
2421
+ if (datatype && datatype.enumerations && datatype.enumerations.length > 0) {
2422
+ return datatype.enumerations.map((enumItem) => ({
2423
+ id: enumItem.id || enumItem.value,
2424
+ // Use value as fallback if id not present
2425
+ value: enumItem.value,
2426
+ label: enumItem.value
2427
+ // Use value as display label
2428
+ }));
2429
+ }
2430
+ }
2431
+ return void 0;
2432
+ }
2433
+ function determineInputTypeFromBaseChain(baseTypeChain, datatypes) {
2434
+ if (!baseTypeChain || baseTypeChain.length === 0) {
2435
+ return {
2436
+ fieldType: "text",
2437
+ htmlInputType: "text",
2438
+ placeholder: I18n.t("field.enterValue")
2439
+ };
2440
+ }
2441
+ if (datatypes && datatypes.length > 0) {
2442
+ const enumerations = collectEnumerationsFromChain(baseTypeChain, datatypes);
2443
+ if (enumerations && enumerations.length > 0) {
2444
+ return {
2445
+ fieldType: "select",
2446
+ enumerations,
2447
+ placeholder: I18n.t("field.selectOption")
2448
+ };
2449
+ }
2450
+ }
2451
+ const chainLower = baseTypeChain.map((type) => type.toLowerCase());
2452
+ const chainString = chainLower.join("|");
2453
+ if (baseTypeChain.some((type) => type === "nl-types:formattedExplanationItemType") || chainString.includes("formattedexplanation") || chainString.includes("formatted") && chainString.includes("explanation")) {
2454
+ return {
2455
+ fieldType: "textarea",
2456
+ placeholder: I18n.t("field.enterDetailedExplanation")
2457
+ };
2458
+ }
2459
+ if (chainLower.some((type) => type.includes("date"))) {
2460
+ if (chainString.includes("datetime") || chainString.includes("time")) {
2461
+ return {
2462
+ fieldType: "datetime",
2463
+ htmlInputType: "datetime-local"
2464
+ };
2465
+ }
2466
+ return {
2467
+ fieldType: "date",
2468
+ htmlInputType: "date"
2469
+ };
2470
+ }
2471
+ if (chainLower.some((type) => type.includes("boolean") || type.includes("bool"))) {
2472
+ return {
2473
+ fieldType: "boolean"
2474
+ };
2475
+ }
2476
+ if (chainLower.some((type) => type.includes("integer") || type === "integer")) {
2477
+ const isNonNegative = chainString.includes("nonnegative") || chainString.includes("non-negative");
2478
+ const isPositive = chainString.includes("positive");
2479
+ return {
2480
+ fieldType: "integer",
2481
+ htmlInputType: "number",
2482
+ allowDecimals: false,
2483
+ min: isPositive ? 1 : isNonNegative ? 0 : void 0,
2484
+ step: 1,
2485
+ placeholder: I18n.t("field.enterWholeNumber")
2486
+ };
2487
+ }
2488
+ if (chainLower.some((type) => type.includes("decimal") || type === "decimal")) {
2489
+ if (chainString.includes("monetary") || chainString.includes("currency")) {
2490
+ if (chainString.includes("nodecimals") || chainString.includes("no-decimals") || chainString.includes("nodecimals20")) {
2491
+ return {
2492
+ fieldType: "number",
2493
+ htmlInputType: "number",
2494
+ allowDecimals: false,
2495
+ step: 1,
2496
+ placeholder: I18n.t("field.enterAmountNoDecimals")
2497
+ };
2498
+ }
2499
+ return {
2500
+ fieldType: "currency",
2501
+ htmlInputType: "number",
2502
+ allowDecimals: true,
2503
+ step: 0.01,
2504
+ placeholder: I18n.t("field.enterCurrency")
2505
+ };
2506
+ }
2507
+ return {
2508
+ fieldType: "decimal",
2509
+ htmlInputType: "number",
2510
+ allowDecimals: true,
2511
+ step: "any",
2512
+ placeholder: I18n.t("field.enterDecimalValue")
2513
+ };
2514
+ }
2515
+ if (baseTypeChain.some((type) => type === "xbrli:stringItemType") || chainLower.some((type) => type === "string" || type.includes("stringitem"))) {
2516
+ return {
2517
+ fieldType: "text",
2518
+ htmlInputType: "text",
2519
+ placeholder: I18n.t("field.enterText")
2520
+ };
2521
+ }
2522
+ return {
2523
+ fieldType: "text",
2524
+ htmlInputType: "text",
2525
+ placeholder: I18n.t("field.enterValue")
2526
+ };
2527
+ }
2109
2528
  var __defProp$5 = Object.defineProperty;
2110
2529
  var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
2111
2530
  var __decorateClass$5 = (decorators, target, key, kind) => {
@@ -2120,18 +2539,35 @@ var __decorateClass$5 = (decorators, target, key, kind) => {
2120
2539
  let JupiterFormField = class extends LitElement {
2121
2540
  constructor() {
2122
2541
  super(...arguments);
2542
+ this.defaultUnits = [];
2123
2543
  this.value = null;
2124
2544
  this.disabled = false;
2125
2545
  this.locale = "en-US";
2126
2546
  this.hideLabel = false;
2127
2547
  this._errors = [];
2548
+ this._xbrlErrors = [];
2128
2549
  this._touched = false;
2129
2550
  this._showPeriodPopup = false;
2551
+ this._availableUnits = [];
2130
2552
  }
2131
2553
  willUpdate(changedProperties) {
2554
+ var _a;
2132
2555
  if (changedProperties.has("value") || changedProperties.has("field")) {
2133
2556
  this._validateField();
2134
2557
  }
2558
+ if (changedProperties.has("unit") && this.unit) {
2559
+ console.log(`🏷️ [FormField willUpdate] Unit property changed to: ${this.unit}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
2560
+ this.dispatchEvent(new CustomEvent("unit-change", {
2561
+ detail: {
2562
+ fieldId: (_a = this.field) == null ? void 0 : _a.id,
2563
+ conceptId: this.conceptId,
2564
+ columnId: this.columnId,
2565
+ unit: this.unit
2566
+ },
2567
+ bubbles: true,
2568
+ composed: true
2569
+ }));
2570
+ }
2135
2571
  if (changedProperties.has("field") && this.field) {
2136
2572
  if (this.conceptId.includes("DescriptionLocationNL") || this.columnId.startsWith("col-")) {
2137
2573
  console.log(`📅 [FormField willUpdate] Concept ${this.conceptId}, Column ${this.columnId}: field.periodType=${this.field.periodType}, field.periodStartDate=${this.field.periodStartDate}, field.periodEndDate=${this.field.periodEndDate}, field.periodInstantDate=${this.field.periodInstantDate}`);
@@ -2184,21 +2620,138 @@ let JupiterFormField = class extends LitElement {
2184
2620
  }
2185
2621
  _handleBlur() {
2186
2622
  this._touched = true;
2623
+ this._validateXBRLDatatype();
2624
+ console.log(`🟦 [FormField] Blur event - fieldId: ${this.field.id}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
2625
+ console.log(`🟦 [FormField] Current _xbrlErrors:`, this._xbrlErrors);
2626
+ console.log(`🟦 [FormField] Current value:`, this.value);
2187
2627
  this.dispatchEvent(new CustomEvent("field-blur", {
2188
2628
  detail: {
2189
2629
  fieldId: this.field.id,
2190
2630
  conceptId: this.conceptId,
2191
- columnId: this.columnId
2631
+ columnId: this.columnId,
2632
+ xbrlValidationErrors: this._xbrlErrors
2192
2633
  },
2193
- bubbles: true
2634
+ bubbles: true,
2635
+ composed: true
2636
+ // CRITICAL: Allow event to cross Shadow DOM boundaries
2194
2637
  }));
2638
+ console.log(`🟦 [FormField] Dispatched field-blur event with ${this._xbrlErrors.length} errors`);
2639
+ }
2640
+ /**
2641
+ * Validates the current value against XBRL datatype validation rules
2642
+ * Called on blur event when user loses focus on the input field
2643
+ */
2644
+ _validateXBRLDatatype() {
2645
+ this._xbrlErrors = [];
2646
+ if (this.value === null || this.value === void 0 || this.value === "") {
2647
+ return;
2648
+ }
2649
+ if (!this.conceptType || !this.datatypes || this.datatypes.length === 0) {
2650
+ return;
2651
+ }
2652
+ const validationResult = XBRLValidator.validateConceptValue(
2653
+ this.conceptType,
2654
+ this.value,
2655
+ this.datatypes
2656
+ );
2657
+ if (!validationResult.valid) {
2658
+ this._xbrlErrors = validationResult.errors;
2659
+ console.log(`❌ [FormField] XBRL Validation failed for ${this.conceptId}:`, {
2660
+ conceptType: this.conceptType,
2661
+ value: this.value,
2662
+ errors: this._xbrlErrors
2663
+ });
2664
+ } else {
2665
+ console.log(`✅ [FormField] XBRL Validation passed for ${this.conceptId}`);
2666
+ }
2195
2667
  }
2196
2668
  _handlePeriodIconClick() {
2669
+ this._availableUnits = this._collectUnitsForConceptType();
2670
+ console.log(`📊 [FormField] Collected ${this._availableUnits.length} units for concept ${this.conceptId}:`, this._availableUnits);
2671
+ console.log(`📊 [FormField] Current unit value: ${this.unit}`);
2672
+ console.log(`📊 [FormField] ConceptId: ${this.conceptId}, ColumnId: ${this.columnId}`);
2673
+ if (!this.unit && this._availableUnits.length > 0) {
2674
+ let unitToSelect = null;
2675
+ const defaultUnit = this._availableUnits.find((u2) => u2.isDefault === true);
2676
+ if (defaultUnit) {
2677
+ unitToSelect = defaultUnit.id;
2678
+ console.log(`🎯 [FormField] Auto-selecting default unit: ${defaultUnit.id} (${defaultUnit.label})`);
2679
+ } else if (this._availableUnits.length === 1) {
2680
+ unitToSelect = this._availableUnits[0].id;
2681
+ console.log(`🎯 [FormField] Auto-selecting single available unit: ${unitToSelect}`);
2682
+ }
2683
+ if (unitToSelect) {
2684
+ this.unit = unitToSelect;
2685
+ this.dispatchEvent(new CustomEvent("unit-change", {
2686
+ detail: {
2687
+ fieldId: this.field.id,
2688
+ conceptId: this.conceptId,
2689
+ columnId: this.columnId,
2690
+ unit: this.unit
2691
+ },
2692
+ bubbles: true,
2693
+ composed: true
2694
+ }));
2695
+ }
2696
+ } else if (this.unit) {
2697
+ console.log(`📊 [FormField] Unit already set, dispatching unit-change to ensure parent stores it: ${this.unit}`);
2698
+ this.dispatchEvent(new CustomEvent("unit-change", {
2699
+ detail: {
2700
+ fieldId: this.field.id,
2701
+ conceptId: this.conceptId,
2702
+ columnId: this.columnId,
2703
+ unit: this.unit
2704
+ },
2705
+ bubbles: true,
2706
+ composed: true
2707
+ }));
2708
+ }
2197
2709
  this._showPeriodPopup = true;
2198
2710
  }
2711
+ /**
2712
+ * Collects units from the concept's type or its basetype chain
2713
+ * @returns Array of unit objects with id, label, and isDefault
2714
+ */
2715
+ _collectUnitsForConceptType() {
2716
+ if (!this.conceptType || !this.datatypes) {
2717
+ return [];
2718
+ }
2719
+ const baseTypeChain = resolveBaseTypeChain(this.conceptType, this.datatypes);
2720
+ console.log(`🔍 [Unit Resolution] Concept: ${this.conceptId}, Type: ${this.conceptType}, BaseType Chain:`, baseTypeChain);
2721
+ for (const typeName of baseTypeChain) {
2722
+ const datatype = this.datatypes.find((dt) => dt.type === typeName);
2723
+ if (datatype && datatype.units && Array.isArray(datatype.units) && datatype.units.length > 0) {
2724
+ console.log(`✅ [Unit Resolution] Found ${datatype.units.length} units in type: ${typeName}`);
2725
+ return datatype.units;
2726
+ }
2727
+ }
2728
+ console.log(`ℹ️ [Unit Resolution] No units found for concept ${this.conceptId}`);
2729
+ return [];
2730
+ }
2199
2731
  _closePeriodPopup() {
2200
2732
  this._showPeriodPopup = false;
2201
2733
  }
2734
+ _handleUnitChange(event) {
2735
+ const target = event.target;
2736
+ const value = target.value;
2737
+ console.log(`🏷️ [FormField] Unit change detected: value=${value}, conceptId=${this.conceptId}, columnId=${this.columnId}`);
2738
+ console.log(`🏷️ [FormField] Previous unit value: ${this.unit}`);
2739
+ this.unit = value;
2740
+ console.log(`🏷️ [FormField] Updated unit value to: ${this.unit}`);
2741
+ const eventDetail = {
2742
+ fieldId: this.field.id,
2743
+ conceptId: this.conceptId,
2744
+ columnId: this.columnId,
2745
+ unit: this.unit
2746
+ };
2747
+ console.log(`🏷️ [FormField] Dispatching unit-change event with detail:`, eventDetail);
2748
+ this.dispatchEvent(new CustomEvent("unit-change", {
2749
+ detail: eventDetail,
2750
+ bubbles: true,
2751
+ composed: true
2752
+ }));
2753
+ console.log(`🏷️ [FormField] unit-change event dispatched`);
2754
+ }
2202
2755
  _handlePopupOverlayClick(e2) {
2203
2756
  if (e2.target === e2.currentTarget) {
2204
2757
  this._closePeriodPopup();
@@ -2224,7 +2777,8 @@ let JupiterFormField = class extends LitElement {
2224
2777
  periodType: this.field.periodType,
2225
2778
  periodStartDate: this.periodStartDate,
2226
2779
  periodEndDate: this.periodEndDate,
2227
- periodInstantDate: this.periodInstantDate
2780
+ periodInstantDate: this.periodInstantDate,
2781
+ unit: this.unit
2228
2782
  },
2229
2783
  bubbles: true,
2230
2784
  composed: true
@@ -2237,13 +2791,12 @@ let JupiterFormField = class extends LitElement {
2237
2791
  });
2238
2792
  }
2239
2793
  _renderInput() {
2240
- var _a;
2241
2794
  const hasErrors = this._errors.some((e2) => e2.severity === "error");
2242
2795
  const hasWarnings = this._errors.some((e2) => e2.severity === "warning");
2243
2796
  const cssClass = `field-input ${hasErrors ? "error" : hasWarnings ? "warning" : ""}`;
2244
2797
  const fieldId = `${this.conceptId}__${this.columnId}`;
2245
2798
  const fieldName = `data[${this.conceptId}][${this.columnId}]`;
2246
- const typeConfig = getInputTypeForConceptType(this.conceptType);
2799
+ const typeConfig = getInputTypeForConceptType(this.conceptType, this.datatypes);
2247
2800
  if (this.conceptType)
2248
2801
  ;
2249
2802
  const effectiveFieldType = typeConfig.fieldType || this.field.type || "text";
@@ -2263,6 +2816,7 @@ let JupiterFormField = class extends LitElement {
2263
2816
  `;
2264
2817
  }
2265
2818
  if (effectiveFieldType === "select" || this.field.type === "select") {
2819
+ const selectOptions = typeConfig.enumerations || this.field.options || [];
2266
2820
  return html`
2267
2821
  <select
2268
2822
  id="${fieldId}"
@@ -2274,16 +2828,21 @@ let JupiterFormField = class extends LitElement {
2274
2828
  @focus="${this._handleFocus}"
2275
2829
  @blur="${this._handleBlur}"
2276
2830
  >
2277
- <option value="">Select...</option>
2278
- ${(_a = this.field.options) == null ? void 0 : _a.map((option) => html`
2279
- <option
2280
- value="${option.value}"
2281
- ?disabled="${option.disabled}"
2282
- ?selected="${this.value === option.value}"
2283
- >
2284
- ${option.label}
2285
- </option>
2286
- `)}
2831
+ <option value="">${typeConfig.placeholder || I18n.t("field.select")}</option>
2832
+ ${selectOptions.map((option) => {
2833
+ const optionValue = option.value;
2834
+ const optionLabel = option.label || option.value;
2835
+ const isDisabled = option.disabled || false;
2836
+ return html`
2837
+ <option
2838
+ value="${optionValue}"
2839
+ ?disabled="${isDisabled}"
2840
+ ?selected="${this.value === optionValue}"
2841
+ >
2842
+ ${optionLabel}
2843
+ </option>
2844
+ `;
2845
+ })}
2287
2846
  </select>
2288
2847
  `;
2289
2848
  }
@@ -2431,6 +2990,25 @@ let JupiterFormField = class extends LitElement {
2431
2990
  />
2432
2991
  </div>
2433
2992
  `}
2993
+
2994
+ ${this._availableUnits.length > 0 ? html`
2995
+ <div class="period-controls">
2996
+ <label>Unit:</label>
2997
+ <select
2998
+ .value="${this.unit || ""}"
2999
+ @change="${this._handleUnitChange}"
3000
+ ?disabled="${this.disabled}"
3001
+ class="unit-select"
3002
+ >
3003
+ <option value="">Select Unit</option>
3004
+ ${this._availableUnits.map((unit) => html`
3005
+ <option value="${unit.id}" ?selected="${this.unit === unit.id}">
3006
+ ${unit.label || unit.id}
3007
+ </option>
3008
+ `)}
3009
+ </select>
3010
+ </div>
3011
+ ` : ""}
2434
3012
  </div>
2435
3013
  </div>
2436
3014
  </div>
@@ -2464,9 +3042,19 @@ let JupiterFormField = class extends LitElement {
2464
3042
 
2465
3043
  ${this._errors.length > 0 && this._touched ? html`
2466
3044
  <div class="field-errors">
2467
- ${this._errors.map((error) => html`
2468
- <span class="field-error ${error.severity}">
2469
- ${error.message}
3045
+ ${this._errors.map((error2) => html`
3046
+ <span class="field-error ${error2.severity}">
3047
+ ${error2.message}
3048
+ </span>
3049
+ `)}
3050
+ </div>
3051
+ ` : ""}
3052
+
3053
+ ${this._xbrlErrors.length > 0 && this._touched ? html`
3054
+ <div class="field-errors">
3055
+ ${this._xbrlErrors.map((error2) => html`
3056
+ <span class="field-error error">
3057
+ ${error2.message}
2470
3058
  </span>
2471
3059
  `)}
2472
3060
  </div>
@@ -2617,6 +3205,28 @@ JupiterFormField.styles = css`
2617
3205
  box-shadow: 0 0 0 2px var(--jupiter-primary-color-light, rgba(25, 118, 210, 0.2));
2618
3206
  }
2619
3207
 
3208
+ .period-popup-content .period-controls .unit-select {
3209
+ padding: 8px 10px;
3210
+ font-size: 14px;
3211
+ border: 1px solid var(--jupiter-border-color, #ddd);
3212
+ border-radius: 4px;
3213
+ background: var(--jupiter-input-background, #fff);
3214
+ color: var(--jupiter-text-primary, #333);
3215
+ cursor: pointer;
3216
+ }
3217
+
3218
+ .period-popup-content .period-controls .unit-select:focus {
3219
+ outline: none;
3220
+ border-color: var(--jupiter-primary-color, #1976d2);
3221
+ box-shadow: 0 0 0 2px var(--jupiter-primary-color-light, rgba(25, 118, 210, 0.2));
3222
+ }
3223
+
3224
+ .period-popup-content .period-controls .unit-select:disabled {
3225
+ background: var(--jupiter-disabled-background, #f5f5f5);
3226
+ color: var(--jupiter-disabled-text, #999);
3227
+ cursor: not-allowed;
3228
+ }
3229
+
2620
3230
  .field-input {
2621
3231
  width: 100%;
2622
3232
  padding: 6px 8px; /* Reduced padding for table cells */
@@ -2733,6 +3343,12 @@ __decorateClass$5([
2733
3343
  __decorateClass$5([
2734
3344
  n2({ type: String })
2735
3345
  ], JupiterFormField.prototype, "conceptType", 2);
3346
+ __decorateClass$5([
3347
+ n2({ type: Array })
3348
+ ], JupiterFormField.prototype, "datatypes", 2);
3349
+ __decorateClass$5([
3350
+ n2({ type: Array })
3351
+ ], JupiterFormField.prototype, "defaultUnits", 2);
2736
3352
  __decorateClass$5([
2737
3353
  n2({ type: String })
2738
3354
  ], JupiterFormField.prototype, "columnId", 2);
@@ -2757,15 +3373,24 @@ __decorateClass$5([
2757
3373
  __decorateClass$5([
2758
3374
  n2({ type: String })
2759
3375
  ], JupiterFormField.prototype, "periodInstantDate", 2);
3376
+ __decorateClass$5([
3377
+ n2({ type: String })
3378
+ ], JupiterFormField.prototype, "unit", 2);
2760
3379
  __decorateClass$5([
2761
3380
  r()
2762
3381
  ], JupiterFormField.prototype, "_errors", 2);
3382
+ __decorateClass$5([
3383
+ r()
3384
+ ], JupiterFormField.prototype, "_xbrlErrors", 2);
2763
3385
  __decorateClass$5([
2764
3386
  r()
2765
3387
  ], JupiterFormField.prototype, "_touched", 2);
2766
3388
  __decorateClass$5([
2767
3389
  r()
2768
3390
  ], JupiterFormField.prototype, "_showPeriodPopup", 2);
3391
+ __decorateClass$5([
3392
+ r()
3393
+ ], JupiterFormField.prototype, "_availableUnits", 2);
2769
3394
  JupiterFormField = __decorateClass$5([
2770
3395
  t$1("jupiter-form-field")
2771
3396
  ], JupiterFormField);
@@ -2785,6 +3410,9 @@ let JupiterConceptTree = class extends LitElement {
2785
3410
  super(...arguments);
2786
3411
  this.columns = [];
2787
3412
  this.formData = {};
3413
+ this.periodData = {};
3414
+ this.unitData = {};
3415
+ this.defaultUnits = [];
2788
3416
  this.disabled = false;
2789
3417
  this.locale = "en-US";
2790
3418
  this.expandedConcepts = /* @__PURE__ */ new Set();
@@ -2812,11 +3440,11 @@ let JupiterConceptTree = class extends LitElement {
2812
3440
  }
2813
3441
  _getFieldForColumn(columnId) {
2814
3442
  var _a;
2815
- return (_a = this.concept.fields) == null ? void 0 : _a.find((field) => field.columnId === columnId);
3443
+ return (_a = this.concept.fields) == null ? void 0 : _a.find((field2) => field2.columnId === columnId);
2816
3444
  }
2817
- _getFieldValue(field) {
3445
+ _getFieldValue(field2) {
2818
3446
  var _a;
2819
- return (_a = this.formData[this.concept.id]) == null ? void 0 : _a[field.columnId];
3447
+ return (_a = this.formData[this.concept.id]) == null ? void 0 : _a[field2.columnId];
2820
3448
  }
2821
3449
  _handleFieldChange(event) {
2822
3450
  event.stopPropagation();
@@ -2859,20 +3487,25 @@ let JupiterConceptTree = class extends LitElement {
2859
3487
 
2860
3488
  <!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
2861
3489
  ${this.columns.map((column2) => {
2862
- const field = this._getFieldForColumn(column2.id);
2863
- const shouldShowField = !isAbstract && field;
3490
+ var _a, _b;
3491
+ const field2 = this._getFieldForColumn(column2.id);
3492
+ const shouldShowField = !isAbstract && field2;
3493
+ const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
2864
3494
  return html`
2865
3495
  <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""}">
2866
3496
  ${shouldShowField ? html`
2867
3497
  <jupiter-form-field
2868
- .field="${field}"
3498
+ .field="${field2}"
2869
3499
  .conceptId="${this.concept.id}"
2870
3500
  .conceptType="${this.concept.type}"
3501
+ .datatypes="${this.datatypes}"
3502
+ .defaultUnits="${this.defaultUnits}"
2871
3503
  .columnId="${column2.id}"
2872
- .value="${this._getFieldValue(field)}"
2873
- .periodStartDate="${field.periodStartDate || column2.periodStartDate}"
2874
- .periodEndDate="${field.periodEndDate || column2.periodEndDate}"
2875
- .periodInstantDate="${field.periodInstantDate || (field.periodType === "instant" ? field.periodEndDate || field.periodStartDate : void 0)}"
3504
+ .value="${this._getFieldValue(field2)}"
3505
+ .unit="${storedUnit || ""}"
3506
+ .periodStartDate="${field2.periodStartDate || column2.periodStartDate}"
3507
+ .periodEndDate="${field2.periodEndDate || column2.periodEndDate}"
3508
+ .periodInstantDate="${field2.periodInstantDate || (field2.periodType === "instant" ? field2.periodEndDate || field2.periodStartDate : void 0)}"
2876
3509
  .disabled="${this.disabled}"
2877
3510
  .locale="${this.locale}"
2878
3511
  .hideLabel="${true}"
@@ -2998,6 +3631,15 @@ __decorateClass$4([
2998
3631
  __decorateClass$4([
2999
3632
  n2({ type: Object })
3000
3633
  ], JupiterConceptTree.prototype, "formData", 2);
3634
+ __decorateClass$4([
3635
+ n2({ type: Object })
3636
+ ], JupiterConceptTree.prototype, "periodData", 2);
3637
+ __decorateClass$4([
3638
+ n2({ type: Object })
3639
+ ], JupiterConceptTree.prototype, "unitData", 2);
3640
+ __decorateClass$4([
3641
+ n2({ type: Array })
3642
+ ], JupiterConceptTree.prototype, "defaultUnits", 2);
3001
3643
  __decorateClass$4([
3002
3644
  n2({ type: Boolean })
3003
3645
  ], JupiterConceptTree.prototype, "disabled", 2);
@@ -3007,6 +3649,9 @@ __decorateClass$4([
3007
3649
  __decorateClass$4([
3008
3650
  n2({ type: Set })
3009
3651
  ], JupiterConceptTree.prototype, "expandedConcepts", 2);
3652
+ __decorateClass$4([
3653
+ n2({ type: Array })
3654
+ ], JupiterConceptTree.prototype, "datatypes", 2);
3010
3655
  __decorateClass$4([
3011
3656
  r()
3012
3657
  ], JupiterConceptTree.prototype, "_expanded", 2);
@@ -3061,9 +3706,9 @@ let JupiterAddColumnDialog = class extends LitElement {
3061
3706
  if (!this._isFormValid())
3062
3707
  return;
3063
3708
  const request = {
3064
- periodType: this.periodType === "mixed" ? this._selectedType : this.periodType
3709
+ periodType: this.periodType === "mixed" ? "duration" : this.periodType
3065
3710
  };
3066
- if (this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant") {
3711
+ if (this.periodType === "instant") {
3067
3712
  request.instantDate = this._instantDate;
3068
3713
  } else {
3069
3714
  request.startDate = this._startDate;
@@ -3078,13 +3723,7 @@ let JupiterAddColumnDialog = class extends LitElement {
3078
3723
  }));
3079
3724
  }
3080
3725
  _isFormValid() {
3081
- if (this.periodType === "mixed") {
3082
- if (this._selectedType === "instant") {
3083
- return !!this._instantDate;
3084
- } else {
3085
- return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
3086
- }
3087
- } else if (this.periodType === "duration") {
3726
+ if (this.periodType === "mixed" || this.periodType === "duration") {
3088
3727
  return !!this._startDate && !!this._endDate && this._startDate <= this._endDate;
3089
3728
  } else if (this.periodType === "instant") {
3090
3729
  return !!this._instantDate;
@@ -3182,22 +3821,7 @@ let JupiterAddColumnDialog = class extends LitElement {
3182
3821
  </div>
3183
3822
 
3184
3823
  <div class="dialog-content">
3185
- ${this.periodType === "mixed" ? html`
3186
- <div class="form-group">
3187
- <label class="form-label required">${I18n.t("column.columnType")}</label>
3188
- <select
3189
- class="form-input"
3190
- .value="${this._selectedType}"
3191
- @change="${this._handleSelectedTypeChange}"
3192
- required
3193
- >
3194
- <option value="instant">${I18n.t("column.instantSingleDate")}</option>
3195
- <option value="duration">${I18n.t("column.durationDates")}</option>
3196
- </select>
3197
- </div>
3198
- ` : ""}
3199
-
3200
- ${this.periodType === "instant" || this.periodType === "mixed" && this._selectedType === "instant" ? html`
3824
+ ${this.periodType === "instant" ? html`
3201
3825
  <div class="form-group">
3202
3826
  <label class="form-label required">${I18n.t("column.instantDate")}</label>
3203
3827
  <input
@@ -3624,7 +4248,10 @@ let JupiterFormSection = class extends LitElement {
3624
4248
  super(...arguments);
3625
4249
  this.columns = [];
3626
4250
  this.formData = {};
4251
+ this.periodData = {};
4252
+ this.unitData = {};
3627
4253
  this.typedMemberData = {};
4254
+ this.defaultUnits = [];
3628
4255
  this.disabled = false;
3629
4256
  this.collapsible = true;
3630
4257
  this.locale = "en-US";
@@ -3984,7 +4611,11 @@ let JupiterFormSection = class extends LitElement {
3984
4611
  <jupiter-concept-tree
3985
4612
  .concept="${concept}"
3986
4613
  .columns="${this.columns}"
4614
+ .datatypes="${this.datatypes}"
3987
4615
  .formData="${this.formData}"
4616
+ .periodData="${this.periodData}"
4617
+ .unitData="${this.unitData}"
4618
+ .defaultUnits="${this.defaultUnits}"
3988
4619
  .disabled="${this.disabled}"
3989
4620
  .locale="${this.locale}"
3990
4621
  .expandedConcepts="${this._expandedConcepts}"
@@ -4275,12 +4906,24 @@ __decorateClass$2([
4275
4906
  __decorateClass$2([
4276
4907
  n2({ type: Array })
4277
4908
  ], JupiterFormSection.prototype, "columns", 2);
4909
+ __decorateClass$2([
4910
+ n2({ type: Array })
4911
+ ], JupiterFormSection.prototype, "datatypes", 2);
4278
4912
  __decorateClass$2([
4279
4913
  n2({ type: Object })
4280
4914
  ], JupiterFormSection.prototype, "formData", 2);
4915
+ __decorateClass$2([
4916
+ n2({ type: Object })
4917
+ ], JupiterFormSection.prototype, "periodData", 2);
4918
+ __decorateClass$2([
4919
+ n2({ type: Object })
4920
+ ], JupiterFormSection.prototype, "unitData", 2);
4281
4921
  __decorateClass$2([
4282
4922
  n2({ type: Object })
4283
4923
  ], JupiterFormSection.prototype, "typedMemberData", 2);
4924
+ __decorateClass$2([
4925
+ n2({ type: Array })
4926
+ ], JupiterFormSection.prototype, "defaultUnits", 2);
4284
4927
  __decorateClass$2([
4285
4928
  n2({ type: Boolean })
4286
4929
  ], JupiterFormSection.prototype, "disabled", 2);
@@ -4341,10 +4984,17 @@ let JupiterFilterRolesDialog = class extends LitElement {
4341
4984
  this.availableRoles = [];
4342
4985
  this.selectedRoleIds = [];
4343
4986
  this.periodPreferences = {};
4987
+ this.mode = "user";
4344
4988
  this._tempSelectedRoles = /* @__PURE__ */ new Set();
4345
4989
  this._searchQuery = "";
4346
4990
  this._filteredRoles = [];
4347
4991
  this._tempPeriodPreferences = {};
4992
+ this._selectedAvailableRole = null;
4993
+ this._selectedChosenRole = null;
4994
+ this._chosenSearchQuery = "";
4995
+ this._draggedRoleId = null;
4996
+ this._dragOverRoleId = null;
4997
+ this._chosenRoleOrder = [];
4348
4998
  }
4349
4999
  connectedCallback() {
4350
5000
  super.connectedCallback();
@@ -4411,6 +5061,19 @@ let JupiterFilterRolesDialog = class extends LitElement {
4411
5061
  searchInput.focus();
4412
5062
  }
4413
5063
  }
5064
+ _handleChosenSearchInput(event) {
5065
+ const input = event.target;
5066
+ this._chosenSearchQuery = input.value;
5067
+ }
5068
+ _clearChosenSearch() {
5069
+ var _a;
5070
+ this._chosenSearchQuery = "";
5071
+ const searchInput = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".chosen-search-input");
5072
+ if (searchInput) {
5073
+ searchInput.value = "";
5074
+ searchInput.focus();
5075
+ }
5076
+ }
4414
5077
  _highlightSearchTerm(text) {
4415
5078
  if (!this._searchQuery.trim()) {
4416
5079
  return text;
@@ -4427,6 +5090,7 @@ let JupiterFilterRolesDialog = class extends LitElement {
4427
5090
  }
4428
5091
  _initializeTempSelection() {
4429
5092
  this._tempSelectedRoles = new Set(this.selectedRoleIds);
5093
+ this._chosenRoleOrder = [...this.selectedRoleIds];
4430
5094
  }
4431
5095
  _initializePeriodPreferences() {
4432
5096
  const preferences = {};
@@ -4528,10 +5192,20 @@ let JupiterFilterRolesDialog = class extends LitElement {
4528
5192
  }));
4529
5193
  }
4530
5194
  _handleApply() {
4531
- const selectedRoles = Array.from(this._tempSelectedRoles);
5195
+ const orderedRolesWithMetadata = this._chosenRoleOrder.map((roleId, index) => {
5196
+ var _a;
5197
+ const role = this.availableRoles.find((r2) => r2.id === roleId);
5198
+ return {
5199
+ roleId,
5200
+ roleURI: ((_a = role == null ? void 0 : role.metadata) == null ? void 0 : _a.roleURI) || "",
5201
+ order: index
5202
+ };
5203
+ });
5204
+ console.log("✅ Apply Filter - Enhanced structure being emitted:", orderedRolesWithMetadata);
5205
+ console.log("📋 Order array:", this._chosenRoleOrder);
4532
5206
  this.dispatchEvent(new CustomEvent("roles-filter-apply", {
4533
5207
  detail: {
4534
- selectedRoleIds: selectedRoles,
5208
+ selectedRoleIds: orderedRolesWithMetadata,
4535
5209
  periodPreferences: this._tempPeriodPreferences
4536
5210
  },
4537
5211
  bubbles: true
@@ -4542,6 +5216,128 @@ let JupiterFilterRolesDialog = class extends LitElement {
4542
5216
  this._handleCancel();
4543
5217
  }
4544
5218
  }
5219
+ // Picklist methods for admin mode
5220
+ _handleAvailableRoleClick(roleId) {
5221
+ this._selectedAvailableRole = roleId;
5222
+ this._selectedChosenRole = null;
5223
+ this.requestUpdate();
5224
+ }
5225
+ _handleChosenRoleClick(roleId) {
5226
+ this._selectedChosenRole = roleId;
5227
+ this._selectedAvailableRole = null;
5228
+ this.requestUpdate();
5229
+ }
5230
+ _moveToChosen() {
5231
+ if (!this._selectedAvailableRole)
5232
+ return;
5233
+ const newSelection = new Set(this._tempSelectedRoles);
5234
+ newSelection.add(this._selectedAvailableRole);
5235
+ this._tempSelectedRoles = newSelection;
5236
+ if (!this._chosenRoleOrder.includes(this._selectedAvailableRole)) {
5237
+ this._chosenRoleOrder = [...this._chosenRoleOrder, this._selectedAvailableRole];
5238
+ }
5239
+ this._selectedAvailableRole = null;
5240
+ this.requestUpdate();
5241
+ }
5242
+ _moveToAvailable() {
5243
+ if (!this._selectedChosenRole)
5244
+ return;
5245
+ const newSelection = new Set(this._tempSelectedRoles);
5246
+ newSelection.delete(this._selectedChosenRole);
5247
+ this._tempSelectedRoles = newSelection;
5248
+ this._chosenRoleOrder = this._chosenRoleOrder.filter((id) => id !== this._selectedChosenRole);
5249
+ this._selectedChosenRole = null;
5250
+ this.requestUpdate();
5251
+ }
5252
+ _moveAllToChosen() {
5253
+ const newSelection = new Set(this._tempSelectedRoles);
5254
+ this._filteredRoles.forEach((role) => {
5255
+ newSelection.add(role.id);
5256
+ if (!this._chosenRoleOrder.includes(role.id)) {
5257
+ this._chosenRoleOrder.push(role.id);
5258
+ }
5259
+ });
5260
+ this._tempSelectedRoles = newSelection;
5261
+ this._selectedAvailableRole = null;
5262
+ this.requestUpdate();
5263
+ }
5264
+ _moveAllToAvailable() {
5265
+ this._tempSelectedRoles = /* @__PURE__ */ new Set();
5266
+ this._chosenRoleOrder = [];
5267
+ this._selectedChosenRole = null;
5268
+ this.requestUpdate();
5269
+ }
5270
+ _getAvailableRoles() {
5271
+ return this._filteredRoles.filter((role) => !this._tempSelectedRoles.has(role.id));
5272
+ }
5273
+ _getChosenRoles() {
5274
+ const chosenRoles = this.availableRoles.filter((role) => this._tempSelectedRoles.has(role.id));
5275
+ const orderedRoles = this._chosenRoleOrder.map((roleId) => chosenRoles.find((role) => role.id === roleId)).filter((role) => role !== void 0);
5276
+ const unorderedRoles = chosenRoles.filter((role) => !this._chosenRoleOrder.includes(role.id));
5277
+ const allOrderedRoles = [...orderedRoles, ...unorderedRoles];
5278
+ if (!this._chosenSearchQuery.trim()) {
5279
+ return allOrderedRoles;
5280
+ }
5281
+ const query = this._chosenSearchQuery.toLowerCase().trim();
5282
+ return allOrderedRoles.filter((role) => {
5283
+ var _a;
5284
+ const titleMatch = role.title.toLowerCase().includes(query);
5285
+ const idMatch = role.id.toLowerCase().includes(query);
5286
+ const descriptionMatch = ((_a = role.description) == null ? void 0 : _a.toLowerCase().includes(query)) || false;
5287
+ const uriMatch = this._searchInRoleURI(role, query);
5288
+ return titleMatch || idMatch || descriptionMatch || uriMatch;
5289
+ });
5290
+ }
5291
+ // Drag and drop handlers
5292
+ _handleDragStart(event, roleId) {
5293
+ this._draggedRoleId = roleId;
5294
+ if (event.dataTransfer) {
5295
+ event.dataTransfer.effectAllowed = "move";
5296
+ event.dataTransfer.setData("text/plain", roleId);
5297
+ }
5298
+ this.requestUpdate();
5299
+ }
5300
+ _handleDragOver(event, roleId) {
5301
+ event.preventDefault();
5302
+ if (event.dataTransfer) {
5303
+ event.dataTransfer.dropEffect = "move";
5304
+ }
5305
+ if (this._draggedRoleId && this._draggedRoleId !== roleId) {
5306
+ this._dragOverRoleId = roleId;
5307
+ this.requestUpdate();
5308
+ }
5309
+ }
5310
+ _handleDragLeave(event) {
5311
+ this._dragOverRoleId = null;
5312
+ this.requestUpdate();
5313
+ }
5314
+ _handleDrop(event, targetRoleId) {
5315
+ event.preventDefault();
5316
+ if (!this._draggedRoleId || this._draggedRoleId === targetRoleId) {
5317
+ this._draggedRoleId = null;
5318
+ this._dragOverRoleId = null;
5319
+ this.requestUpdate();
5320
+ return;
5321
+ }
5322
+ const newOrder = [...this._chosenRoleOrder];
5323
+ const draggedIndex = newOrder.indexOf(this._draggedRoleId);
5324
+ const targetIndex = newOrder.indexOf(targetRoleId);
5325
+ if (draggedIndex !== -1 && targetIndex !== -1) {
5326
+ newOrder.splice(draggedIndex, 1);
5327
+ const newTargetIndex = draggedIndex < targetIndex ? targetIndex - 1 : targetIndex;
5328
+ newOrder.splice(newTargetIndex, 0, this._draggedRoleId);
5329
+ this._chosenRoleOrder = newOrder;
5330
+ console.log("🔄 Reordered roles:", this._chosenRoleOrder);
5331
+ }
5332
+ this._draggedRoleId = null;
5333
+ this._dragOverRoleId = null;
5334
+ this.requestUpdate();
5335
+ }
5336
+ _handleDragEnd(event) {
5337
+ this._draggedRoleId = null;
5338
+ this._dragOverRoleId = null;
5339
+ this.requestUpdate();
5340
+ }
4545
5341
  render() {
4546
5342
  const selectedCount = this._tempSelectedRoles.size;
4547
5343
  const totalCount = this.availableRoles.length;
@@ -4560,6 +5356,152 @@ let JupiterFilterRolesDialog = class extends LitElement {
4560
5356
 
4561
5357
  <!-- Dialog Content -->
4562
5358
  <div class="dialog-content">
5359
+ ${this.mode === "admin" ? html`
5360
+ <!-- Admin Mode: Picklist Layout -->
5361
+ <div class="picklist-container">
5362
+ <!-- Available Roles Panel -->
5363
+ <div class="picklist-panel">
5364
+ <div class="picklist-header">
5365
+ Available Roles (${this._getAvailableRoles().length})
5366
+ </div>
5367
+ <div class="picklist-search">
5368
+ <div class="search-container">
5369
+ <input
5370
+ type="text"
5371
+ class="search-input"
5372
+ placeholder="${I18n.t("filter.searchPlaceholder")}"
5373
+ .value="${this._searchQuery}"
5374
+ @input="${this._handleSearchInput}"
5375
+ />
5376
+ ${this._searchQuery ? html`
5377
+ <button class="clear-search" @click="${this._clearSearch}" title="${I18n.t("filter.clearSearch")}">
5378
+ ×
5379
+ </button>
5380
+ ` : html`
5381
+ <svg class="search-icon" viewBox="0 0 24 24">
5382
+ <path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
5383
+ </svg>
5384
+ `}
5385
+ </div>
5386
+ </div>
5387
+ <div class="picklist-list">
5388
+ ${this._getAvailableRoles().map((role) => {
5389
+ var _a;
5390
+ return html`
5391
+ <div
5392
+ class="picklist-item ${this._selectedAvailableRole === role.id ? "selected" : ""}"
5393
+ @click="${() => this._handleAvailableRoleClick(role.id)}"
5394
+ @dblclick="${() => {
5395
+ this._handleAvailableRoleClick(role.id);
5396
+ this._moveToChosen();
5397
+ }}"
5398
+ >
5399
+ <div class="picklist-item-label">${role.title}</div>
5400
+ ${((_a = role.metadata) == null ? void 0 : _a.roleURI) ? html`
5401
+ <div class="picklist-item-value">${role.metadata.roleURI}</div>
5402
+ ` : ""}
5403
+ </div>
5404
+ `;
5405
+ })}
5406
+ </div>
5407
+ <div class="picklist-count">
5408
+ ${this._getAvailableRoles().length} role(s)
5409
+ </div>
5410
+ </div>
5411
+
5412
+ <!-- Control Buttons -->
5413
+ <div class="picklist-controls">
5414
+ <button
5415
+ class="picklist-button"
5416
+ @click="${this._moveToChosen}"
5417
+ ?disabled="${!this._selectedAvailableRole}"
5418
+ title="Add selected role"
5419
+ >
5420
+
5421
+ </button>
5422
+ <button
5423
+ class="picklist-button"
5424
+ @click="${this._moveAllToChosen}"
5425
+ ?disabled="${this._getAvailableRoles().length === 0}"
5426
+ title="Add all roles"
5427
+ >
5428
+ »
5429
+ </button>
5430
+ <button
5431
+ class="picklist-button"
5432
+ @click="${this._moveToAvailable}"
5433
+ ?disabled="${!this._selectedChosenRole}"
5434
+ title="Remove selected role"
5435
+ >
5436
+
5437
+ </button>
5438
+ <button
5439
+ class="picklist-button"
5440
+ @click="${this._moveAllToAvailable}"
5441
+ ?disabled="${this._tempSelectedRoles.size === 0}"
5442
+ title="Remove all roles"
5443
+ >
5444
+ «
5445
+ </button>
5446
+ </div>
5447
+
5448
+ <!-- Chosen Roles Panel -->
5449
+ <div class="picklist-panel">
5450
+ <div class="picklist-header">
5451
+ Chosen Roles (${this._tempSelectedRoles.size})
5452
+ </div>
5453
+ <div class="picklist-search">
5454
+ <div class="search-container">
5455
+ <input
5456
+ type="text"
5457
+ class="search-input chosen-search-input"
5458
+ placeholder="${I18n.t("filter.searchPlaceholder")}"
5459
+ .value="${this._chosenSearchQuery}"
5460
+ @input="${this._handleChosenSearchInput}"
5461
+ />
5462
+ ${this._chosenSearchQuery ? html`
5463
+ <button class="clear-search" @click="${this._clearChosenSearch}" title="${I18n.t("filter.clearSearch")}">
5464
+ ×
5465
+ </button>
5466
+ ` : html`
5467
+ <svg class="search-icon" viewBox="0 0 24 24">
5468
+ <path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
5469
+ </svg>
5470
+ `}
5471
+ </div>
5472
+ </div>
5473
+ <div class="picklist-list">
5474
+ ${this._getChosenRoles().map((role) => {
5475
+ var _a;
5476
+ return html`
5477
+ <div
5478
+ class="picklist-item ${this._selectedChosenRole === role.id ? "selected" : ""} ${this._draggedRoleId === role.id ? "dragging" : ""} ${this._dragOverRoleId === role.id ? "drag-over" : ""}"
5479
+ draggable="true"
5480
+ @click="${() => this._handleChosenRoleClick(role.id)}"
5481
+ @dblclick="${() => {
5482
+ this._handleChosenRoleClick(role.id);
5483
+ this._moveToAvailable();
5484
+ }}"
5485
+ @dragstart="${(e2) => this._handleDragStart(e2, role.id)}"
5486
+ @dragover="${(e2) => this._handleDragOver(e2, role.id)}"
5487
+ @dragleave="${(e2) => this._handleDragLeave(e2)}"
5488
+ @drop="${(e2) => this._handleDrop(e2, role.id)}"
5489
+ @dragend="${(e2) => this._handleDragEnd(e2)}"
5490
+ >
5491
+ <div class="picklist-item-label">${role.title}</div>
5492
+ ${((_a = role.metadata) == null ? void 0 : _a.roleURI) ? html`
5493
+ <div class="picklist-item-value">${role.metadata.roleURI}</div>
5494
+ ` : ""}
5495
+ </div>
5496
+ `;
5497
+ })}
5498
+ </div>
5499
+ <div class="picklist-count">
5500
+ ${this._tempSelectedRoles.size} role(s) selected
5501
+ </div>
5502
+ </div>
5503
+ </div>
5504
+ ` : html`
4563
5505
  <p class="description">
4564
5506
  ${I18n.t("filter.description")}
4565
5507
  </p>
@@ -4671,8 +5613,7 @@ let JupiterFilterRolesDialog = class extends LitElement {
4671
5613
  })}
4672
5614
  `}
4673
5615
  </div>
4674
-
4675
-
5616
+ `}
4676
5617
  </div>
4677
5618
 
4678
5619
  <!-- Dialog Actions -->
@@ -5017,6 +5958,126 @@ JupiterFilterRolesDialog.styles = css`
5017
5958
  opacity: 0.6;
5018
5959
  cursor: not-allowed;
5019
5960
  }
5961
+
5962
+ /* Picklist Styles for Admin Mode */
5963
+ .picklist-container {
5964
+ display: flex;
5965
+ gap: 16px;
5966
+ height: 500px;
5967
+ }
5968
+
5969
+ .picklist-panel {
5970
+ flex: 1;
5971
+ display: flex;
5972
+ flex-direction: column;
5973
+ border: 1px solid var(--jupiter-border-color, #ddd);
5974
+ border-radius: 4px;
5975
+ overflow: hidden;
5976
+ }
5977
+
5978
+ .picklist-header {
5979
+ padding: 12px;
5980
+ background: var(--jupiter-background-light, #f8f9fa);
5981
+ border-bottom: 1px solid var(--jupiter-border-color, #ddd);
5982
+ font-weight: 600;
5983
+ color: var(--jupiter-text-primary, #333);
5984
+ font-size: 14px;
5985
+ }
5986
+
5987
+ .picklist-search {
5988
+ padding: 12px;
5989
+ border-bottom: 1px solid var(--jupiter-border-color, #ddd);
5990
+ }
5991
+
5992
+ .picklist-list {
5993
+ flex: 1;
5994
+ overflow-y: auto;
5995
+ padding: 8px;
5996
+ }
5997
+
5998
+ .picklist-item {
5999
+ padding: 10px 12px;
6000
+ margin-bottom: 4px;
6001
+ border: 1px solid var(--jupiter-border-color, #ddd);
6002
+ border-radius: 4px;
6003
+ cursor: pointer;
6004
+ transition: all 0.2s ease;
6005
+ background: var(--jupiter-background, #fff);
6006
+ }
6007
+
6008
+ .picklist-item:hover {
6009
+ background: var(--jupiter-hover-background, #f5f5f5);
6010
+ border-color: var(--jupiter-primary-color, #1976d2);
6011
+ }
6012
+
6013
+ .picklist-item.selected {
6014
+ background: var(--jupiter-primary-color, #1976d2);
6015
+ color: white;
6016
+ border-color: var(--jupiter-primary-color, #1976d2);
6017
+ }
6018
+
6019
+ .picklist-item.dragging {
6020
+ opacity: 0.5;
6021
+ cursor: move;
6022
+ }
6023
+
6024
+ .picklist-item.drag-over {
6025
+ border-top: 3px solid var(--jupiter-primary-color, #1976d2);
6026
+ margin-top: 3px;
6027
+ }
6028
+
6029
+ .picklist-item[draggable="true"] {
6030
+ cursor: move;
6031
+ }
6032
+
6033
+ .picklist-item-label {
6034
+ font-weight: 500;
6035
+ font-size: 14px;
6036
+ margin-bottom: 4px;
6037
+ }
6038
+
6039
+ .picklist-item-value {
6040
+ font-size: 11px;
6041
+ opacity: 0.8;
6042
+ word-break: break-all;
6043
+ }
6044
+
6045
+ .picklist-controls {
6046
+ display: flex;
6047
+ flex-direction: column;
6048
+ justify-content: center;
6049
+ gap: 8px;
6050
+ padding: 0 8px;
6051
+ }
6052
+
6053
+ .picklist-button {
6054
+ background: var(--jupiter-primary-color, #1976d2);
6055
+ color: white;
6056
+ border: none;
6057
+ padding: 8px 16px;
6058
+ border-radius: 4px;
6059
+ cursor: pointer;
6060
+ font-size: 14px;
6061
+ transition: background-color 0.2s ease;
6062
+ }
6063
+
6064
+ .picklist-button:hover:not(:disabled) {
6065
+ background: var(--jupiter-primary-color-dark, #1565c0);
6066
+ }
6067
+
6068
+ .picklist-button:disabled {
6069
+ opacity: 0.4;
6070
+ cursor: not-allowed;
6071
+ }
6072
+
6073
+ .picklist-count {
6074
+ padding: 8px 12px;
6075
+ font-size: 12px;
6076
+ color: var(--jupiter-text-secondary, #666);
6077
+ background: var(--jupiter-background-light, #f8f9fa);
6078
+ border-top: 1px solid var(--jupiter-border-color, #ddd);
6079
+ text-align: center;
6080
+ }
5020
6081
  `;
5021
6082
  __decorateClass$1([
5022
6083
  n2({ type: Boolean, reflect: true })
@@ -5030,6 +6091,9 @@ __decorateClass$1([
5030
6091
  __decorateClass$1([
5031
6092
  n2({ type: Object })
5032
6093
  ], JupiterFilterRolesDialog.prototype, "periodPreferences", 2);
6094
+ __decorateClass$1([
6095
+ n2({ type: String })
6096
+ ], JupiterFilterRolesDialog.prototype, "mode", 2);
5033
6097
  __decorateClass$1([
5034
6098
  r()
5035
6099
  ], JupiterFilterRolesDialog.prototype, "_tempSelectedRoles", 2);
@@ -5042,6 +6106,24 @@ __decorateClass$1([
5042
6106
  __decorateClass$1([
5043
6107
  r()
5044
6108
  ], JupiterFilterRolesDialog.prototype, "_tempPeriodPreferences", 2);
6109
+ __decorateClass$1([
6110
+ r()
6111
+ ], JupiterFilterRolesDialog.prototype, "_selectedAvailableRole", 2);
6112
+ __decorateClass$1([
6113
+ r()
6114
+ ], JupiterFilterRolesDialog.prototype, "_selectedChosenRole", 2);
6115
+ __decorateClass$1([
6116
+ r()
6117
+ ], JupiterFilterRolesDialog.prototype, "_chosenSearchQuery", 2);
6118
+ __decorateClass$1([
6119
+ r()
6120
+ ], JupiterFilterRolesDialog.prototype, "_draggedRoleId", 2);
6121
+ __decorateClass$1([
6122
+ r()
6123
+ ], JupiterFilterRolesDialog.prototype, "_dragOverRoleId", 2);
6124
+ __decorateClass$1([
6125
+ r()
6126
+ ], JupiterFilterRolesDialog.prototype, "_chosenRoleOrder", 2);
5045
6127
  JupiterFilterRolesDialog = __decorateClass$1([
5046
6128
  t$1("jupiter-filter-roles-dialog")
5047
6129
  ], JupiterFilterRolesDialog);
@@ -5069,11 +6151,14 @@ let JupiterDynamicForm = class extends LitElement {
5069
6151
  this.display = "accordion";
5070
6152
  this.mode = "inputForm";
5071
6153
  this.financialStatementsTypeAxis = [];
6154
+ this.defaultUnits = [];
5072
6155
  this._formData = {};
5073
6156
  this._draftLoaded = false;
5074
6157
  this._preservedFormData = {};
5075
6158
  this._periodData = {};
5076
6159
  this._preservedPeriodData = {};
6160
+ this._unitData = {};
6161
+ this._preservedUnitData = {};
5077
6162
  this._typedMemberData = {};
5078
6163
  this._preservedTypedMemberData = {};
5079
6164
  this._columns = [];
@@ -5082,6 +6167,8 @@ let JupiterDynamicForm = class extends LitElement {
5082
6167
  this._dirty = false;
5083
6168
  this._valid = true;
5084
6169
  this._submitted = false;
6170
+ this._xbrlFormErrors = [];
6171
+ this._showErrorPopup = false;
5085
6172
  this._allSections = [];
5086
6173
  this._selectedRoleIds = [];
5087
6174
  this._showFilterDialog = false;
@@ -5100,6 +6187,17 @@ let JupiterDynamicForm = class extends LitElement {
5100
6187
  console.log(`🌍 [GLOBAL DynamicForm] Event detail:`, customEvent.detail);
5101
6188
  this._handlePeriodChange(customEvent);
5102
6189
  });
6190
+ this.addEventListener("unit-change", (e2) => {
6191
+ console.log(`🏷️ [GLOBAL DynamicForm] Caught unit-change event on element:`, e2);
6192
+ const customEvent = e2;
6193
+ console.log(`🏷️ [GLOBAL DynamicForm] Event detail:`, customEvent.detail);
6194
+ this._handleUnitChange(customEvent);
6195
+ });
6196
+ this.addEventListener("field-blur", (e2) => {
6197
+ console.log("🚨 [DynamicForm] field-blur event listener triggered!", e2);
6198
+ const customEvent = e2;
6199
+ this._handleFieldBlur(customEvent);
6200
+ });
5103
6201
  this._initializeForm();
5104
6202
  }
5105
6203
  updated(changedProperties) {
@@ -5109,10 +6207,46 @@ let JupiterDynamicForm = class extends LitElement {
5109
6207
  if (changedProperties.has("financialStatementsTypeAxis")) {
5110
6208
  console.log("🔄 financialStatementsTypeAxis changed:", this.financialStatementsTypeAxis);
5111
6209
  }
6210
+ if ((changedProperties.has("xbrlInput") || changedProperties.has("defaultUnits")) && this.xbrlInput && this.defaultUnits && this.defaultUnits.length > 0) {
6211
+ this._applyDefaultUnitsToDatatypes();
6212
+ }
5112
6213
  if (changedProperties.has("xbrlInput") || changedProperties.has("schema") || changedProperties.has("language") || changedProperties.has("periodStartDate") || changedProperties.has("periodEndDate") || changedProperties.has("financialStatementsTypeAxis")) {
5113
6214
  this._initializeForm();
5114
6215
  }
5115
6216
  }
6217
+ /**
6218
+ * Apply developer-provided default units to datatypes by setting isDefault=true
6219
+ * This allows units to be auto-selected for derived types (e.g., nl-types:monetaryNoDecimals20ItemType)
6220
+ */
6221
+ _applyDefaultUnitsToDatatypes() {
6222
+ var _a;
6223
+ if (!((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) || !this.defaultUnits || this.defaultUnits.length === 0) {
6224
+ return;
6225
+ }
6226
+ console.log("🔧 [DynamicForm] Applying defaultUnits to datatypes:", this.defaultUnits);
6227
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts;
6228
+ if (!datatypesArray || datatypesArray.length === 0) {
6229
+ console.warn("⚠️ [DynamicForm] No datatypes found to apply defaults to");
6230
+ return;
6231
+ }
6232
+ this.defaultUnits.forEach((defaultUnitMap) => {
6233
+ Object.entries(defaultUnitMap).forEach(([datatypeId, unitId]) => {
6234
+ const datatype = datatypesArray.find((dt) => dt.type === datatypeId || dt.id === datatypeId);
6235
+ if (datatype && datatype.units && datatype.units.length > 0) {
6236
+ const targetUnit = datatype.units.find((u2) => u2.id === unitId);
6237
+ if (targetUnit) {
6238
+ datatype.units.forEach((u2) => u2.isDefault = false);
6239
+ targetUnit.isDefault = true;
6240
+ console.log(`✅ [DynamicForm] Set isDefault=true for unit "${unitId}" in datatype "${datatypeId}"`);
6241
+ } else {
6242
+ console.warn(`⚠️ [DynamicForm] Unit "${unitId}" not found in datatype "${datatypeId}"`);
6243
+ }
6244
+ } else {
6245
+ console.warn(`⚠️ [DynamicForm] Datatype "${datatypeId}" not found or has no units`);
6246
+ }
6247
+ });
6248
+ });
6249
+ }
5116
6250
  _initializeForm() {
5117
6251
  var _a;
5118
6252
  if (!this._draftStorageService) {
@@ -5155,8 +6289,8 @@ let JupiterDynamicForm = class extends LitElement {
5155
6289
  removable: false
5156
6290
  }
5157
6291
  ];
5158
- } catch (error) {
5159
- console.error("❌ Error building form from XBRL input:", error);
6292
+ } catch (error2) {
6293
+ console.error("❌ Error building form from XBRL input:", error2);
5160
6294
  this._currentSchema = this._getDefaultSchema();
5161
6295
  this._allSections = [];
5162
6296
  this._selectedRoleIds = [];
@@ -5230,11 +6364,26 @@ let JupiterDynamicForm = class extends LitElement {
5230
6364
  });
5231
6365
  this._periodPreferences = preferences;
5232
6366
  }
6367
+ /**
6368
+ * Helper method to extract roleIds from _selectedRoleIds
6369
+ * Handles both legacy string[] and enhanced object[] structure
6370
+ */
6371
+ _getRoleIdsArray() {
6372
+ if (!Array.isArray(this._selectedRoleIds) || this._selectedRoleIds.length === 0) {
6373
+ return [];
6374
+ }
6375
+ if (typeof this._selectedRoleIds[0] === "string") {
6376
+ return this._selectedRoleIds;
6377
+ } else {
6378
+ return this._selectedRoleIds.map((item) => item.roleId);
6379
+ }
6380
+ }
5233
6381
  _applyRoleFilter() {
5234
6382
  if (!this._currentSchema || !this._allSections.length)
5235
6383
  return;
5236
- console.log(`🔍 Applying role filter: ${this._selectedRoleIds.length} selected out of ${this._allSections.length} total`);
5237
- if (this._selectedRoleIds.length === 0) {
6384
+ const roleIds = this._getRoleIdsArray();
6385
+ console.log(`🔍 Applying role filter: ${roleIds.length} selected out of ${this._allSections.length} total`);
6386
+ if (roleIds.length === 0) {
5238
6387
  console.log(`📝 No roles selected - showing empty form`);
5239
6388
  this._currentSchema = {
5240
6389
  ...this._currentSchema,
@@ -5245,17 +6394,38 @@ let JupiterDynamicForm = class extends LitElement {
5245
6394
  }
5246
6395
  this._preserveDataForHiddenSections();
5247
6396
  const filteredSections = this._allSections.filter(
5248
- (section2) => this._selectedRoleIds.includes(section2.id)
6397
+ (section2) => roleIds.includes(section2.id)
5249
6398
  );
5250
- console.log(`📊 Filtered sections: ${filteredSections.length} (IDs: ${filteredSections.map((s2) => s2.id).join(", ")})`);
5251
- this._restoreDataForVisibleSections(filteredSections);
6399
+ const orderedSections = this._sortSectionsByCustomOrder(filteredSections);
6400
+ console.log(`📊 Filtered sections: ${orderedSections.length}`);
6401
+ console.log(`📋 Custom order applied:`, orderedSections.map((s2) => s2.title));
6402
+ this._restoreDataForVisibleSections(orderedSections);
5252
6403
  this._currentSchema = {
5253
6404
  ...this._currentSchema,
5254
- sections: filteredSections
6405
+ sections: orderedSections
5255
6406
  };
5256
- console.log(`✅ Schema updated. Current sections count: ${this._currentSchema.sections.length}`);
6407
+ console.log(`✅ Schema updated with custom order. Current sections count: ${this._currentSchema.sections.length}`);
5257
6408
  this.requestUpdate();
5258
6409
  }
6410
+ /**
6411
+ * Sort sections according to custom order from _selectedRoleIds
6412
+ * Handles both enhanced structure and legacy string array
6413
+ */
6414
+ _sortSectionsByCustomOrder(sections) {
6415
+ if (Array.isArray(this._selectedRoleIds) && this._selectedRoleIds.length > 0 && typeof this._selectedRoleIds[0] === "object") {
6416
+ const enhancedRoles = this._selectedRoleIds;
6417
+ const orderMap = /* @__PURE__ */ new Map();
6418
+ enhancedRoles.forEach((role) => {
6419
+ orderMap.set(role.roleId, role.order);
6420
+ });
6421
+ return [...sections].sort((a2, b2) => {
6422
+ const orderA = orderMap.get(a2.id) ?? 999;
6423
+ const orderB = orderMap.get(b2.id) ?? 999;
6424
+ return orderA - orderB;
6425
+ });
6426
+ }
6427
+ return sections;
6428
+ }
5259
6429
  /**
5260
6430
  * Filter roles based on financialStatementsTypeAxis property
5261
6431
  * Rules:
@@ -5326,8 +6496,9 @@ let JupiterDynamicForm = class extends LitElement {
5326
6496
  _preserveDataForHiddenSections() {
5327
6497
  var _a;
5328
6498
  const currentlyVisibleSectionIds = ((_a = this._currentSchema) == null ? void 0 : _a.sections.map((s2) => s2.id)) || [];
6499
+ const selectedRoleIds = this._getRoleIdsArray();
5329
6500
  const sectionsThatWillBeHidden = currentlyVisibleSectionIds.filter(
5330
- (sectionId) => !this._selectedRoleIds.includes(sectionId)
6501
+ (sectionId) => !selectedRoleIds.includes(sectionId)
5331
6502
  );
5332
6503
  sectionsThatWillBeHidden.forEach((sectionId) => {
5333
6504
  const section2 = this._allSections.find((s2) => s2.id === sectionId);
@@ -5351,9 +6522,9 @@ let JupiterDynamicForm = class extends LitElement {
5351
6522
  if (this._formData[concept.id]) {
5352
6523
  this._preservedFormData[concept.id] = { ...this._formData[concept.id] };
5353
6524
  }
5354
- concept.fields.forEach((field) => {
5355
- if (this._typedMemberData[field.columnId]) {
5356
- this._preservedTypedMemberData[field.columnId] = { ...this._typedMemberData[field.columnId] };
6525
+ concept.fields.forEach((field2) => {
6526
+ if (this._typedMemberData[field2.columnId]) {
6527
+ this._preservedTypedMemberData[field2.columnId] = { ...this._typedMemberData[field2.columnId] };
5357
6528
  }
5358
6529
  });
5359
6530
  if (concept.children) {
@@ -5371,9 +6542,9 @@ let JupiterDynamicForm = class extends LitElement {
5371
6542
  if (this._preservedFormData[concept.id]) {
5372
6543
  this._formData[concept.id] = { ...this._preservedFormData[concept.id] };
5373
6544
  }
5374
- concept.fields.forEach((field) => {
5375
- if (this._preservedTypedMemberData[field.columnId]) {
5376
- this._typedMemberData[field.columnId] = { ...this._preservedTypedMemberData[field.columnId] };
6545
+ concept.fields.forEach((field2) => {
6546
+ if (this._preservedTypedMemberData[field2.columnId]) {
6547
+ this._typedMemberData[field2.columnId] = { ...this._preservedTypedMemberData[field2.columnId] };
5377
6548
  }
5378
6549
  });
5379
6550
  if (concept.children) {
@@ -5390,7 +6561,8 @@ let JupiterDynamicForm = class extends LitElement {
5390
6561
  }
5391
6562
  _handleFilterDialogCancel() {
5392
6563
  this._showFilterDialog = false;
5393
- console.log(`🚫 Filter dialog cancelled. Current selection: ${this._selectedRoleIds.length}/${this._allSections.length}`);
6564
+ const roleCount = this._getRoleIdsArray().length;
6565
+ console.log(`🚫 Filter dialog cancelled. Current selection: ${roleCount}/${this._allSections.length}`);
5394
6566
  }
5395
6567
  _handleRoleFilterApply(event) {
5396
6568
  const { selectedRoleIds, periodPreferences } = event.detail;
@@ -5406,9 +6578,12 @@ let JupiterDynamicForm = class extends LitElement {
5406
6578
  this.periodEndDate,
5407
6579
  this.language,
5408
6580
  this._selectedRoleIds,
6581
+ // Enhanced structure with roleURI and order
5409
6582
  this._allSections,
5410
6583
  this._typedMemberData,
5411
- this._periodPreferences
6584
+ this._periodPreferences,
6585
+ this._periodData,
6586
+ this._unitData
5412
6587
  );
5413
6588
  this._draftStorageService.saveDraft(currentFormData, currentMetadata);
5414
6589
  console.log("✅ Current form data saved to draft storage");
@@ -5418,19 +6593,22 @@ let JupiterDynamicForm = class extends LitElement {
5418
6593
  console.log("📥 Restoring form data from draft after reinitialization...");
5419
6594
  this._loadDraftIfExists().then(() => {
5420
6595
  console.log("✅ Form data restored successfully after reinitialization");
5421
- }).catch((error) => {
5422
- console.error("❌ Error restoring form data after reinitialization:", error);
6596
+ }).catch((error2) => {
6597
+ console.error("❌ Error restoring form data after reinitialization:", error2);
5423
6598
  });
5424
6599
  } else {
5425
6600
  this._applyRoleFilter();
5426
6601
  }
5427
6602
  this._showFilterDialog = false;
5428
- console.log(`🎯 Applied role filter: ${selectedRoleIds.length}/${this._allSections.length} roles selected`);
6603
+ const roleCount = Array.isArray(this._selectedRoleIds) && this._selectedRoleIds.length > 0 ? typeof this._selectedRoleIds[0] === "string" ? this._selectedRoleIds.length : this._selectedRoleIds.length : 0;
6604
+ console.log(`🎯 Applied role filter: ${roleCount}/${this._allSections.length} roles selected`);
6605
+ console.log("📋 Enhanced selectedRoleIds structure:", this._selectedRoleIds);
5429
6606
  this.dispatchEvent(new CustomEvent("roles-filter-changed", {
5430
6607
  detail: {
5431
6608
  selectedRoleIds,
6609
+ // Enhanced structure with roleURI and order
5432
6610
  totalRoles: this._allSections.length,
5433
- visibleRoles: selectedRoleIds.length,
6611
+ visibleRoles: roleCount,
5434
6612
  periodPreferences
5435
6613
  },
5436
6614
  bubbles: true
@@ -5444,15 +6622,15 @@ let JupiterDynamicForm = class extends LitElement {
5444
6622
  return;
5445
6623
  for (const section2 of schema.sections) {
5446
6624
  for (const concept of section2.concepts) {
5447
- for (const field of concept.fields) {
5448
- const value = (_a = this._formData[concept.id]) == null ? void 0 : _a[field.columnId];
6625
+ for (const field2 of concept.fields) {
6626
+ const value = (_a = this._formData[concept.id]) == null ? void 0 : _a[field2.columnId];
5449
6627
  const fieldErrors = FormValidator.validateField(
5450
- field.id,
6628
+ field2.id,
5451
6629
  concept.id,
5452
- field.columnId,
6630
+ field2.columnId,
5453
6631
  value,
5454
- field.type,
5455
- field.validation || []
6632
+ field2.type,
6633
+ field2.validation || []
5456
6634
  );
5457
6635
  errors.push(...fieldErrors);
5458
6636
  }
@@ -5484,8 +6662,8 @@ let JupiterDynamicForm = class extends LitElement {
5484
6662
  _handlePeriodChange(event) {
5485
6663
  console.log(`🎯 [DynamicForm] _handlePeriodChange called with event:`, event);
5486
6664
  console.log(`🎯 [DynamicForm] Event detail:`, event.detail);
5487
- const { conceptId, columnId, periodType, periodStartDate, periodEndDate, periodInstantDate } = event.detail;
5488
- console.log(`📅 Period change received: conceptId=${conceptId}, columnId=${columnId}, periodType=${periodType}, startDate=${periodStartDate}, endDate=${periodEndDate}, instantDate=${periodInstantDate}`);
6665
+ const { conceptId, columnId, periodType, periodStartDate, periodEndDate, periodInstantDate, unit } = event.detail;
6666
+ console.log(`📅 Period change received: conceptId=${conceptId}, columnId=${columnId}, periodType=${periodType}, startDate=${periodStartDate}, endDate=${periodEndDate}, instantDate=${periodInstantDate}, unit=${unit}`);
5489
6667
  const updatedPeriodData = { ...this._periodData };
5490
6668
  if (!updatedPeriodData[conceptId]) {
5491
6669
  updatedPeriodData[conceptId] = {};
@@ -5501,9 +6679,37 @@ let JupiterDynamicForm = class extends LitElement {
5501
6679
  this._periodData = updatedPeriodData;
5502
6680
  console.log(`💾 Period data stored for [${conceptId}][${columnId}]:`, this._periodData[conceptId][columnId]);
5503
6681
  console.log(`📦 Full period data state:`, JSON.stringify(this._periodData, null, 2));
6682
+ if (unit) {
6683
+ this._storeUnit(conceptId, columnId, unit);
6684
+ }
6685
+ this._dirty = true;
6686
+ this.requestUpdate();
6687
+ }
6688
+ _handleUnitChange(event) {
6689
+ console.log(`🏷️ [DynamicForm] _handleUnitChange called with event:`, event);
6690
+ console.log(`🏷️ [DynamicForm] Event detail:`, event.detail);
6691
+ const { conceptId, columnId, unit } = event.detail;
6692
+ console.log(`🏷️ Unit change received: conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
6693
+ this._storeUnit(conceptId, columnId, unit);
5504
6694
  this._dirty = true;
5505
6695
  this.requestUpdate();
5506
6696
  }
6697
+ _storeUnit(conceptId, columnId, unit) {
6698
+ console.log(`🔧 [_storeUnit] Called with conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
6699
+ console.log(`🔧 [_storeUnit] Current _unitData before update:`, JSON.stringify(this._unitData, null, 2));
6700
+ const updatedUnitData = { ...this._unitData };
6701
+ if (!updatedUnitData[conceptId]) {
6702
+ console.log(`🔧 [_storeUnit] Creating new entry for conceptId: ${conceptId}`);
6703
+ updatedUnitData[conceptId] = {};
6704
+ }
6705
+ updatedUnitData[conceptId] = {
6706
+ ...updatedUnitData[conceptId],
6707
+ [columnId]: unit
6708
+ };
6709
+ this._unitData = updatedUnitData;
6710
+ console.log(`💾 [_storeUnit] Unit data stored for [${conceptId}][${columnId}]:`, this._unitData[conceptId][columnId]);
6711
+ console.log(`📦 [_storeUnit] Full unit data state after update:`, JSON.stringify(this._unitData, null, 2));
6712
+ }
5507
6713
  /**
5508
6714
  * Generate a unique concept key that includes section context
5509
6715
  */
@@ -5533,6 +6739,164 @@ let JupiterDynamicForm = class extends LitElement {
5533
6739
  bubbles: true
5534
6740
  }));
5535
6741
  }
6742
+ _handleFieldBlur(event) {
6743
+ var _a;
6744
+ console.log(`🟧 [DynamicForm] _handleFieldBlur received event:`, event);
6745
+ console.log(`🟧 [DynamicForm] Event detail:`, event.detail);
6746
+ const { fieldId, conceptId, columnId, xbrlValidationErrors } = event.detail;
6747
+ console.log(`🟧 [DynamicForm] Extracted - fieldId: ${fieldId}, conceptId: ${conceptId}, columnId: ${columnId}`);
6748
+ console.log(`🟧 [DynamicForm] xbrlValidationErrors:`, xbrlValidationErrors);
6749
+ let sectionId = "";
6750
+ const path = event.composedPath();
6751
+ console.log(`🟧 [DynamicForm] Event path length: ${path.length}`);
6752
+ for (const element of path) {
6753
+ const el = element;
6754
+ if (el.tagName === "JUPITER-FORM-SECTION") {
6755
+ sectionId = el.getAttribute("section-id") || "";
6756
+ console.log(`🟧 [DynamicForm] Found section element with id: ${sectionId}`);
6757
+ break;
6758
+ }
6759
+ }
6760
+ console.log(`🟧 [DynamicForm] Found sectionId: ${sectionId}`);
6761
+ console.log(`🟧 [DynamicForm] Processing errors - has errors: ${xbrlValidationErrors && xbrlValidationErrors.length > 0}`);
6762
+ if (xbrlValidationErrors && xbrlValidationErrors.length > 0) {
6763
+ console.log(`🟧 [DynamicForm] Adding/updating error for fieldId: ${fieldId}, sectionId: ${sectionId}`);
6764
+ const value = ((_a = this._formData[conceptId]) == null ? void 0 : _a[columnId]) || "";
6765
+ const existingIndex = this._xbrlFormErrors.findIndex(
6766
+ (e2) => e2.fieldId === fieldId && e2.sectionId === sectionId
6767
+ );
6768
+ const newError = {
6769
+ sectionId,
6770
+ fieldId,
6771
+ conceptId,
6772
+ columnId,
6773
+ value,
6774
+ errors: xbrlValidationErrors
6775
+ };
6776
+ console.log(`🟧 [DynamicForm] New error object:`, newError);
6777
+ console.log(`🟧 [DynamicForm] Existing index: ${existingIndex}`);
6778
+ if (existingIndex >= 0) {
6779
+ this._xbrlFormErrors = [
6780
+ ...this._xbrlFormErrors.slice(0, existingIndex),
6781
+ newError,
6782
+ ...this._xbrlFormErrors.slice(existingIndex + 1)
6783
+ ];
6784
+ console.log(`🟧 [DynamicForm] Updated existing error at index ${existingIndex}`);
6785
+ } else {
6786
+ this._xbrlFormErrors = [...this._xbrlFormErrors, newError];
6787
+ console.log(`🟧 [DynamicForm] Added new error`);
6788
+ }
6789
+ } else {
6790
+ console.log(`🟧 [DynamicForm] Removing error (if exists) for fieldId: ${fieldId}, sectionId: ${sectionId}`);
6791
+ const beforeLength = this._xbrlFormErrors.length;
6792
+ this._xbrlFormErrors = this._xbrlFormErrors.filter(
6793
+ (e2) => !(e2.fieldId === fieldId && e2.sectionId === sectionId)
6794
+ );
6795
+ console.log(`🟧 [DynamicForm] Removed ${beforeLength - this._xbrlFormErrors.length} errors`);
6796
+ }
6797
+ console.log(`🔍 [Validation] Total errors: ${this._xbrlFormErrors.length}`, this._xbrlFormErrors);
6798
+ }
6799
+ _getSectionTitle(sectionId) {
6800
+ console.log(`🔍 [_getSectionTitle] Looking for sectionId: "${sectionId}"`);
6801
+ console.log(`🔍 [_getSectionTitle] Available sections:`, this._allSections.map((s2) => ({ id: s2.id, title: s2.title })));
6802
+ const section2 = this._allSections.find((s2) => s2.id === sectionId);
6803
+ const result = (section2 == null ? void 0 : section2.title) || sectionId || "(Unknown Section)";
6804
+ console.log(`🔍 [_getSectionTitle] Result: "${result}"`);
6805
+ return result;
6806
+ }
6807
+ async _handleErrorFieldClick(conceptId, columnId, sectionId) {
6808
+ var _a, _b, _c, _d;
6809
+ console.log(`🎯 [Error Click] Attempting to focus field: ${conceptId}__${columnId} in section: ${sectionId}`);
6810
+ this._showErrorPopup = false;
6811
+ this.requestUpdate();
6812
+ await this.updateComplete;
6813
+ if (this.display === "sidePanel" && this._activeSidePanelRoleId !== sectionId) {
6814
+ console.log(`🔀 Switching to section: ${sectionId} (currently on: ${this._activeSidePanelRoleId})`);
6815
+ this._activeSidePanelRoleId = sectionId;
6816
+ this.requestUpdate();
6817
+ await this.updateComplete;
6818
+ await new Promise((resolve) => setTimeout(resolve, 500));
6819
+ }
6820
+ const sectionElements = (_a = this.shadowRoot) == null ? void 0 : _a.querySelectorAll("jupiter-form-section");
6821
+ let targetSection = null;
6822
+ sectionElements == null ? void 0 : sectionElements.forEach((sectionEl) => {
6823
+ var _a2;
6824
+ if (((_a2 = sectionEl.section) == null ? void 0 : _a2.id) === sectionId) {
6825
+ targetSection = sectionEl;
6826
+ }
6827
+ });
6828
+ if (!targetSection) {
6829
+ console.warn(`⚠️ Section not found: ${sectionId}`);
6830
+ return;
6831
+ }
6832
+ console.log(`✅ Found section element:`, targetSection);
6833
+ if ((_b = targetSection.section) == null ? void 0 : _b.collapsed) {
6834
+ console.log(`📂 Expanding collapsed section`);
6835
+ targetSection.section.collapsed = false;
6836
+ targetSection.requestUpdate();
6837
+ await targetSection.updateComplete;
6838
+ await new Promise((resolve) => setTimeout(resolve, 500));
6839
+ } else {
6840
+ await targetSection.updateComplete;
6841
+ await new Promise((resolve) => setTimeout(resolve, 100));
6842
+ }
6843
+ console.log(`🔍 Section shadow DOM exists: ${!!targetSection.shadowRoot}`);
6844
+ if (targetSection.shadowRoot) {
6845
+ console.log(`🔍 Shadow DOM innerHTML length: ${((_c = targetSection.shadowRoot.innerHTML) == null ? void 0 : _c.length) || 0}`);
6846
+ const allElements = targetSection.shadowRoot.querySelectorAll("*");
6847
+ console.log(`🔍 Total elements in shadow DOM: ${allElements.length}`);
6848
+ const customElements2 = Array.from(allElements).filter((el) => {
6849
+ const element = el;
6850
+ return !!(element.tagName && element.tagName.includes("-"));
6851
+ });
6852
+ console.log(`🔍 Custom elements found:`, customElements2.map((el) => el.tagName).join(", "));
6853
+ }
6854
+ const fieldId = `${conceptId}_${columnId}_field`;
6855
+ console.log(`🔍 Looking for input with fieldId: ${fieldId}`);
6856
+ console.log(`🔍 Looking for field with conceptId: ${conceptId} AND columnId: ${columnId}`);
6857
+ const conceptTrees = (_d = targetSection.shadowRoot) == null ? void 0 : _d.querySelectorAll("jupiter-concept-tree");
6858
+ let targetInput = null;
6859
+ console.log(`🔍 Found ${(conceptTrees == null ? void 0 : conceptTrees.length) || 0} concept-tree elements`);
6860
+ if (conceptTrees) {
6861
+ conceptTrees.forEach((conceptTree, treeIndex) => {
6862
+ var _a2;
6863
+ if (targetInput)
6864
+ return;
6865
+ const formFieldsInTree = (_a2 = conceptTree.shadowRoot) == null ? void 0 : _a2.querySelectorAll("jupiter-form-field");
6866
+ console.log(`🔍 Concept tree ${treeIndex}: Found ${(formFieldsInTree == null ? void 0 : formFieldsInTree.length) || 0} form-field elements`);
6867
+ formFieldsInTree == null ? void 0 : formFieldsInTree.forEach((fieldEl, fieldIndex) => {
6868
+ var _a3;
6869
+ if (targetInput)
6870
+ return;
6871
+ console.log(` Field ${fieldIndex}: conceptId=${fieldEl.conceptId}, columnId=${fieldEl.columnId}`);
6872
+ if (fieldEl.conceptId === conceptId && fieldEl.columnId === columnId) {
6873
+ const inputEl = (_a3 = fieldEl.shadowRoot) == null ? void 0 : _a3.querySelector("input, textarea");
6874
+ console.log(` -> Matched! Input element found: ${!!inputEl}`);
6875
+ if (inputEl) {
6876
+ targetInput = inputEl;
6877
+ console.log(`✅ Found input element in form-field`);
6878
+ }
6879
+ }
6880
+ });
6881
+ });
6882
+ }
6883
+ if (!targetInput) {
6884
+ console.warn(`⚠️ Input field not found for: ${fieldId}`);
6885
+ return;
6886
+ }
6887
+ const input = targetInput;
6888
+ targetSection.scrollIntoView({ behavior: "smooth", block: "start" });
6889
+ await new Promise((resolve) => setTimeout(resolve, 300));
6890
+ input.focus();
6891
+ if (input.tagName === "INPUT" || input.tagName === "TEXTAREA") {
6892
+ input.select();
6893
+ }
6894
+ input.style.boxShadow = "0 0 0 3px rgba(220, 38, 38, 0.5)";
6895
+ setTimeout(() => {
6896
+ input.style.boxShadow = "";
6897
+ }, 2e3);
6898
+ console.log(`✅ Successfully focused field: ${conceptId}__${columnId}`);
6899
+ }
5536
6900
  _handleSectionExpand(event) {
5537
6901
  this.dispatchEvent(new CustomEvent("section-expand", {
5538
6902
  detail: event.detail,
@@ -5798,7 +7162,7 @@ let JupiterDynamicForm = class extends LitElement {
5798
7162
  delete this._formData[concept.id][columnId];
5799
7163
  }
5800
7164
  if (concept.fields) {
5801
- concept.fields = concept.fields.filter((field) => field.columnId !== columnId);
7165
+ concept.fields = concept.fields.filter((field2) => field2.columnId !== columnId);
5802
7166
  }
5803
7167
  if (concept.children) {
5804
7168
  this._removeColumnDataFromConcepts(concept.children, columnId);
@@ -5809,7 +7173,8 @@ let JupiterDynamicForm = class extends LitElement {
5809
7173
  if (concept.abstract) {
5810
7174
  return false;
5811
7175
  }
5812
- if (concept.periodType) {
7176
+ const isDimensionColumn = request.selectedDimensions && request.selectedDimensions.length > 0;
7177
+ if (!isDimensionColumn && concept.periodType) {
5813
7178
  if (request.periodType === "instant" && concept.periodType !== "instant") {
5814
7179
  return false;
5815
7180
  }
@@ -5833,9 +7198,9 @@ let JupiterDynamicForm = class extends LitElement {
5833
7198
  var _a;
5834
7199
  if (this._shouldCreateFieldForConcept(concept, request)) {
5835
7200
  const existingField = (_a = concept.fields) == null ? void 0 : _a[0];
5836
- let field;
7201
+ let field2;
5837
7202
  if (existingField) {
5838
- field = {
7203
+ field2 = {
5839
7204
  id: `${concept.id}_${columnId}`,
5840
7205
  conceptId: concept.id,
5841
7206
  columnId,
@@ -5848,13 +7213,15 @@ let JupiterDynamicForm = class extends LitElement {
5848
7213
  defaultValue: existingField.defaultValue,
5849
7214
  periodType: concept.periodType,
5850
7215
  // Add periodType from concept
7216
+ conceptType: concept.type,
7217
+ // CRITICAL: Include conceptType for XBRL validation
5851
7218
  // Set period dates from the add column request
5852
7219
  periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
5853
7220
  periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate,
5854
7221
  periodInstantDate: concept.periodType === "instant" ? request.instantDate || request.startDate : void 0
5855
7222
  };
5856
7223
  } else {
5857
- field = {
7224
+ field2 = {
5858
7225
  id: `${concept.id}_${columnId}`,
5859
7226
  conceptId: concept.id,
5860
7227
  columnId,
@@ -5867,6 +7234,8 @@ let JupiterDynamicForm = class extends LitElement {
5867
7234
  defaultValue: "",
5868
7235
  periodType: concept.periodType,
5869
7236
  // Add periodType from concept
7237
+ conceptType: concept.type,
7238
+ // CRITICAL: Include conceptType for XBRL validation
5870
7239
  // Set period dates from the add column request
5871
7240
  periodStartDate: request.periodType === "instant" ? request.instantDate : request.startDate,
5872
7241
  periodEndDate: request.periodType === "instant" ? request.instantDate : request.endDate,
@@ -5876,7 +7245,7 @@ let JupiterDynamicForm = class extends LitElement {
5876
7245
  if (!concept.fields) {
5877
7246
  concept.fields = [];
5878
7247
  }
5879
- concept.fields.push(field);
7248
+ concept.fields.push(field2);
5880
7249
  }
5881
7250
  if (concept.children) {
5882
7251
  this._replicateFieldsForSection(concept.children, columnId, request, formBuilder);
@@ -5915,6 +7284,10 @@ let JupiterDynamicForm = class extends LitElement {
5915
7284
  this._validateForm();
5916
7285
  const submissionData = this._generateSubmissionData();
5917
7286
  console.log("📊 Form Submission Data:", JSON.stringify(submissionData, null, 2));
7287
+ console.log("📊 Submission Data Summary:");
7288
+ submissionData.forEach((entry, index) => {
7289
+ console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}, unit: ${entry.unit || "none"}`);
7290
+ });
5918
7291
  this.dispatchEvent(new CustomEvent("form-submit", {
5919
7292
  detail: {
5920
7293
  data: this._formData,
@@ -5927,24 +7300,39 @@ let JupiterDynamicForm = class extends LitElement {
5927
7300
  console.log("✅ Form submit event dispatched");
5928
7301
  }
5929
7302
  _handleSaveDraft() {
7303
+ console.log(`🔵 [Save Draft] Checking for errors...`);
7304
+ console.log(`🔵 [Save Draft] _xbrlFormErrors.length: ${this._xbrlFormErrors.length}`);
7305
+ console.log(`🔵 [Save Draft] _xbrlFormErrors:`, this._xbrlFormErrors);
7306
+ if (this._xbrlFormErrors.length > 0) {
7307
+ console.log("❌ [Save Draft] Cannot save - validation errors present:", this._xbrlFormErrors);
7308
+ this._showErrorPopup = true;
7309
+ this.requestUpdate();
7310
+ return;
7311
+ }
7312
+ console.log(`✅ [Save Draft] No validation errors, proceeding with save...`);
5930
7313
  console.log("💾 Raw form data before submission generation:", this._formData);
7314
+ console.log("🏷️ Unit data before submission generation:", this._unitData);
7315
+ console.log("📋 Enhanced selectedRoleIds with roleURI and order:", this._selectedRoleIds);
5931
7316
  const draftData = this._generateSubmissionData();
5932
7317
  console.log("📤 Generated submission data:", draftData);
5933
7318
  console.log("📊 Submission data breakdown:");
5934
7319
  draftData.forEach((entry, index) => {
5935
- console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}`);
7320
+ console.log(` [${index}] conceptId: ${entry.conceptId}, columnId: ${entry.columnId}, value: ${entry.value}, unit: ${entry.unit || "none"}`);
5936
7321
  });
5937
7322
  const metadata = this._draftStorageService.createMetadataSnapshot(
5938
7323
  this.periodStartDate,
5939
7324
  this.periodEndDate,
5940
7325
  this.language,
5941
7326
  this._selectedRoleIds,
7327
+ // Enhanced structure: Array<{ roleId, roleURI, order }> or string[]
5942
7328
  this._allSections,
5943
7329
  this._typedMemberData,
5944
7330
  this._periodPreferences,
5945
- this._periodData
7331
+ this._periodData,
7332
+ this._unitData
5946
7333
  );
5947
7334
  const saved = this._draftStorageService.saveDraft(draftData, metadata);
7335
+ console.log("💾 [Save Draft] Metadata saved with enhanced selectedRoleIds:", metadata.selectedRoleIds);
5948
7336
  this.dynaformsFacts = draftData;
5949
7337
  this.dynaformsMetadata = metadata;
5950
7338
  this.dispatchEvent(new CustomEvent("form-save-draft", {
@@ -5962,12 +7350,14 @@ let JupiterDynamicForm = class extends LitElement {
5962
7350
  bubbles: true,
5963
7351
  composed: true
5964
7352
  }));
7353
+ const roleCount = this._getRoleIdsArray().length;
5965
7354
  console.log("💾 Draft saved - localStorage + event emitted", {
5966
7355
  entries: draftData.length,
5967
7356
  saved,
5968
- roles: this._selectedRoleIds.length,
7357
+ roles: roleCount,
5969
7358
  customColumns: metadata.customColumns.length,
5970
- eventEmitted: true
7359
+ eventEmitted: true,
7360
+ enhancedRoleStructure: Array.isArray(this._selectedRoleIds) && this._selectedRoleIds.length > 0 && typeof this._selectedRoleIds[0] === "object"
5971
7361
  });
5972
7362
  }
5973
7363
  // ===========================================
@@ -6046,6 +7436,10 @@ let JupiterDynamicForm = class extends LitElement {
6046
7436
  this._periodData = metadata.periodData;
6047
7437
  console.log("🔄 Restored custom field-level period data:", Object.keys(this._periodData).length, "concepts");
6048
7438
  }
7439
+ if (metadata.unitData) {
7440
+ this._unitData = metadata.unitData;
7441
+ console.log("🔄 Restored custom field-level unit data:", Object.keys(this._unitData).length, "concepts");
7442
+ }
6049
7443
  if (metadata.periodPreferences) {
6050
7444
  this._periodPreferences = metadata.periodPreferences;
6051
7445
  console.log("🔄 Restored period preferences (including previous year settings):", this._periodPreferences);
@@ -6078,8 +7472,9 @@ let JupiterDynamicForm = class extends LitElement {
6078
7472
  }
6079
7473
  const restoredFormData = {};
6080
7474
  const restoredPeriodData = {};
7475
+ const restoredUnitData = {};
6081
7476
  formData.forEach((entry) => {
6082
- let { conceptId, value, columnId, period } = entry;
7477
+ let { conceptId, value, columnId, period, unit } = entry;
6083
7478
  if (!columnId && period) {
6084
7479
  columnId = this._inferColumnIdFromPeriod(period, conceptId);
6085
7480
  if (!columnId) {
@@ -6111,6 +7506,13 @@ let JupiterDynamicForm = class extends LitElement {
6111
7506
  console.log(`📅 [Restore Period] Extracted duration dates for ${conceptIdToUse}/${columnId}: ${period.startDate} - ${period.endDate}`);
6112
7507
  }
6113
7508
  }
7509
+ if (unit) {
7510
+ if (!restoredUnitData[conceptIdToUse]) {
7511
+ restoredUnitData[conceptIdToUse] = {};
7512
+ }
7513
+ restoredUnitData[conceptIdToUse][columnId] = unit;
7514
+ console.log(`🏷️ [Restore Unit] Extracted unit for ${conceptIdToUse}/${columnId}: ${unit}`);
7515
+ }
6114
7516
  });
6115
7517
  this._formData = { ...this._formData, ...restoredFormData };
6116
7518
  console.log(`🔄 Restored ${Object.keys(restoredFormData).length} concepts with data`);
@@ -6121,6 +7523,13 @@ let JupiterDynamicForm = class extends LitElement {
6121
7523
  };
6122
7524
  console.log(`📅 [Period Restore] Merged period data: ${Object.keys(this._periodData).length} concepts with custom periods`);
6123
7525
  console.log(`📅 [Period Restore] Full _periodData after merge:`, JSON.stringify(this._periodData, null, 2));
7526
+ this._unitData = {
7527
+ ...this._unitData,
7528
+ ...metadata.unitData || {},
7529
+ ...restoredUnitData
7530
+ };
7531
+ console.log(`🏷️ [Unit Restore] Merged unit data: ${Object.keys(this._unitData).length} concepts with custom units`);
7532
+ console.log(`🏷️ [Unit Restore] Full _unitData after merge:`, JSON.stringify(this._unitData, null, 2));
6124
7533
  if (this._selectedRoleIds.length > 0) {
6125
7534
  this._applyRoleFilter();
6126
7535
  }
@@ -6247,6 +7656,7 @@ let JupiterDynamicForm = class extends LitElement {
6247
7656
  columnsBySection.get(col.sectionId).push(col);
6248
7657
  });
6249
7658
  this._allSections.forEach((section2) => {
7659
+ var _a;
6250
7660
  const savedColumns = columnsBySection.get(section2.id);
6251
7661
  if (savedColumns) {
6252
7662
  section2.columns = savedColumns.map((col) => {
@@ -6258,11 +7668,22 @@ let JupiterDynamicForm = class extends LitElement {
6258
7668
  periodEndDate: col.endDate || col.date,
6259
7669
  dimensionData: col.dimensionData,
6260
7670
  order: 0,
6261
- removable: col.columnId !== "duration" && col.columnId !== "instant"
7671
+ removable: col.columnId !== "duration" && col.columnId !== "instant",
7672
+ periodType: col.periodType
7673
+ // CRITICAL: Preserve explicit period type
6262
7674
  };
6263
- console.log(`📅 [Draft Restore] Restoring column ${col.columnId}: startDate=${column2.periodStartDate}, endDate=${column2.periodEndDate}`);
7675
+ console.log(`📅 [Draft Restore] Restoring column ${col.columnId}: startDate=${column2.periodStartDate}, endDate=${column2.periodEndDate}, periodType=${column2.periodType}`);
6264
7676
  return column2;
6265
7677
  });
7678
+ if (((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) && !section2.datatypes) {
7679
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts || [];
7680
+ section2.datatypes = datatypesArray;
7681
+ console.log(`✅ [Draft Restore] Attached ${datatypesArray.length} datatypes to section ${section2.id}`);
7682
+ } else if (section2.datatypes) {
7683
+ console.log(`ℹ️ [Draft Restore] Section ${section2.id} already has ${section2.datatypes.length} datatypes`);
7684
+ } else {
7685
+ console.warn(`⚠️ [Draft Restore] No datatypes available for section ${section2.id}`);
7686
+ }
6266
7687
  this._regenerateFieldsForSection(section2);
6267
7688
  console.log(` └─ Restored ${savedColumns.length} columns for section ${section2.id}`);
6268
7689
  }
@@ -6291,11 +7712,21 @@ let JupiterDynamicForm = class extends LitElement {
6291
7712
  }
6292
7713
  });
6293
7714
  this._allSections.forEach((section2) => {
7715
+ var _a;
6294
7716
  const customColumnsForSection = columnsBySection.get(section2.id);
6295
7717
  if (customColumnsForSection && customColumnsForSection.length > 0) {
6296
7718
  if (!section2.columns) {
6297
7719
  section2.columns = [];
6298
7720
  }
7721
+ if (((_a = this.xbrlInput) == null ? void 0 : _a.datatypes) && !section2.datatypes) {
7722
+ const datatypesArray = Array.isArray(this.xbrlInput.datatypes) ? this.xbrlInput.datatypes : this.xbrlInput.datatypes.concepts || [];
7723
+ section2.datatypes = datatypesArray;
7724
+ console.log(`✅ [Merge Custom] Attached ${datatypesArray.length} datatypes to section ${section2.id}`);
7725
+ } else if (section2.datatypes) {
7726
+ console.log(`ℹ️ [Merge Custom] Section ${section2.id} already has ${section2.datatypes.length} datatypes`);
7727
+ } else {
7728
+ console.warn(`⚠️ [Merge Custom] No datatypes available for section ${section2.id}`);
7729
+ }
6299
7730
  customColumnsForSection.forEach((col) => {
6300
7731
  console.log(`📅 [Merge Custom Column] Column ${col.columnId}: col.startDate=${col.startDate}, col.endDate=${col.endDate}, col.date=${col.date}, col.periodType=${col.periodType}`);
6301
7732
  const existingColumn = section2.columns.find((c2) => c2.id === col.columnId);
@@ -6308,9 +7739,11 @@ let JupiterDynamicForm = class extends LitElement {
6308
7739
  periodEndDate: col.endDate || col.date,
6309
7740
  dimensionData: col.dimensionData,
6310
7741
  order: section2.columns.length,
6311
- removable: true
7742
+ removable: true,
7743
+ periodType: col.periodType
7744
+ // CRITICAL: Preserve explicit period type
6312
7745
  };
6313
- console.log(`📅 [New Column Created] Column ${newColumn.id}: periodStartDate=${newColumn.periodStartDate}, periodEndDate=${newColumn.periodEndDate}`);
7746
+ console.log(`📅 [New Column Created] Column ${newColumn.id}: periodStartDate=${newColumn.periodStartDate}, periodEndDate=${newColumn.periodEndDate}, periodType=${newColumn.periodType}`);
6314
7747
  section2.columns.push(newColumn);
6315
7748
  console.log(` └─ Added custom column ${col.columnId} to section ${section2.id}`);
6316
7749
  }
@@ -6340,20 +7773,20 @@ let JupiterDynamicForm = class extends LitElement {
6340
7773
  if (this._periodData[concept.id]) {
6341
7774
  const conceptPeriodData = this._periodData[concept.id];
6342
7775
  if (concept.fields) {
6343
- concept.fields.forEach((field) => {
6344
- const customPeriod = conceptPeriodData[field.columnId];
7776
+ concept.fields.forEach((field2) => {
7777
+ const customPeriod = conceptPeriodData[field2.columnId];
6345
7778
  if (customPeriod) {
6346
7779
  if (customPeriod.startDate) {
6347
- field.periodStartDate = customPeriod.startDate;
7780
+ field2.periodStartDate = customPeriod.startDate;
6348
7781
  }
6349
7782
  if (customPeriod.endDate) {
6350
- field.periodEndDate = customPeriod.endDate;
7783
+ field2.periodEndDate = customPeriod.endDate;
6351
7784
  }
6352
7785
  if (customPeriod.instantDate) {
6353
- field.periodInstantDate = customPeriod.instantDate;
7786
+ field2.periodInstantDate = customPeriod.instantDate;
6354
7787
  }
6355
7788
  appliedCount++;
6356
- console.log(`✅ [Apply Period] Updated field ${concept.id}/${field.columnId}: start=${field.periodStartDate}, end=${field.periodEndDate}, instant=${field.periodInstantDate}`);
7789
+ console.log(`✅ [Apply Period] Updated field ${concept.id}/${field2.columnId}: start=${field2.periodStartDate}, end=${field2.periodEndDate}, instant=${field2.periodInstantDate}`);
6357
7790
  }
6358
7791
  });
6359
7792
  }
@@ -6392,7 +7825,10 @@ let JupiterDynamicForm = class extends LitElement {
6392
7825
  const columnPeriodType = this._inferColumnPeriodType(column2);
6393
7826
  if (concept.abstract)
6394
7827
  return;
6395
- const shouldSkipPeriodCheck = !columnPeriodType || column2.id === "duration" || column2.id === "default";
7828
+ const isCustomColumn = column2.id.startsWith("col-");
7829
+ const isDimensionColumn = column2.id.startsWith("duration_") || column2.id.startsWith("instant_");
7830
+ const isMixedSection = section2.showPeriodControl === true;
7831
+ const shouldSkipPeriodCheck = !columnPeriodType || column2.id === "duration" || column2.id === "default" || isCustomColumn && isMixedSection || isDimensionColumn;
6396
7832
  if (!shouldSkipPeriodCheck && conceptPeriodType && columnPeriodType) {
6397
7833
  if (conceptPeriodType !== columnPeriodType) {
6398
7834
  console.log(`⏭️ [Field Regeneration] Skipping field for ${concept.id} in column ${column2.id}: conceptPeriodType=${conceptPeriodType}, columnPeriodType=${columnPeriodType}`);
@@ -6407,6 +7843,8 @@ let JupiterDynamicForm = class extends LitElement {
6407
7843
  label: concept.label,
6408
7844
  periodType: conceptPeriodType,
6409
7845
  // Add periodType from concept
7846
+ conceptType: concept.type,
7847
+ // CRITICAL: Include conceptType for XBRL validation
6410
7848
  periodStartDate: column2.periodStartDate,
6411
7849
  periodEndDate: column2.periodEndDate,
6412
7850
  periodInstantDate: conceptPeriodType === "instant" ? column2.periodEndDate || column2.periodStartDate : void 0
@@ -6456,6 +7894,9 @@ let JupiterDynamicForm = class extends LitElement {
6456
7894
  return true;
6457
7895
  }
6458
7896
  _inferColumnPeriodType(column2) {
7897
+ if (column2.periodType) {
7898
+ return column2.periodType;
7899
+ }
6459
7900
  if (column2.periodStartDate && column2.periodEndDate) {
6460
7901
  return column2.periodStartDate === column2.periodEndDate ? "instant" : "duration";
6461
7902
  }
@@ -6533,17 +7974,18 @@ let JupiterDynamicForm = class extends LitElement {
6533
7974
  return null;
6534
7975
  }
6535
7976
  _addConceptDataToSubmission(concept, columnId, value, submissionData, section2) {
6536
- var _a, _b;
6537
- const field = concept.fields.find((f2) => f2.columnId === columnId);
6538
- if (!field)
7977
+ var _a, _b, _c;
7978
+ const field2 = concept.fields.find((f2) => f2.columnId === columnId);
7979
+ if (!field2)
6539
7980
  return;
6540
7981
  const isInstant = concept.periodType === "instant";
6541
7982
  const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[columnId];
7983
+ const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[columnId];
6542
7984
  const column2 = this._findColumnByIdInAllSections(columnId);
6543
- console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}`);
6544
- const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field.periodStartDate || this.periodStartDate;
6545
- const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodEndDate || this.periodEndDate;
6546
- const periodInstantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || field.periodInstantDate || periodEndDate || periodStartDate;
7985
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Unit: ${fieldUnit || "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}`);
7986
+ const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate;
7987
+ const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate;
7988
+ const periodInstantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || field2.periodInstantDate || periodEndDate || periodStartDate;
6547
7989
  const entry = {
6548
7990
  conceptId: concept.originalConceptId || concept.id,
6549
7991
  columnId,
@@ -6556,9 +7998,14 @@ let JupiterDynamicForm = class extends LitElement {
6556
7998
  }
6557
7999
  }
6558
8000
  };
6559
- if ((_b = column2 == null ? void 0 : column2.dimensionData) == null ? void 0 : _b.memberLabel) {
8001
+ if (fieldUnit) {
8002
+ entry.unit = fieldUnit;
8003
+ console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${columnId}`);
8004
+ }
8005
+ if ((_c = column2 == null ? void 0 : column2.dimensionData) == null ? void 0 : _c.memberLabel) {
6560
8006
  entry.dimension = column2.dimensionData.memberLabel;
6561
8007
  }
8008
+ console.log(`📤 [Submission Entry] Created entry:`, JSON.stringify(entry, null, 2));
6562
8009
  submissionData.push(entry);
6563
8010
  }
6564
8011
  _findColumnByIdInAllSections(columnId) {
@@ -6681,27 +8128,27 @@ let JupiterDynamicForm = class extends LitElement {
6681
8128
  console.warn(`[DUPLICATE DEBUG] Processing concept ${concept.originalConceptId || concept.id} in target role`);
6682
8129
  if (concept.fields) {
6683
8130
  console.warn(`[DUPLICATE DEBUG] Concept has ${concept.fields.length} fields`);
6684
- concept.fields.forEach((field, index) => {
8131
+ concept.fields.forEach((field2, index) => {
6685
8132
  var _a;
6686
- console.warn(`[DUPLICATE DEBUG] Field ${index}: columnId=${field.columnId}, current value=${(_a = this._formData[concept.id]) == null ? void 0 : _a[field.columnId]}`);
8133
+ console.warn(`[DUPLICATE DEBUG] Field ${index}: columnId=${field2.columnId}, current value=${(_a = this._formData[concept.id]) == null ? void 0 : _a[field2.columnId]}`);
6687
8134
  });
6688
8135
  }
6689
8136
  }
6690
8137
  if (concept.fields && concept.fields.length > 1) {
6691
- concept.fields.forEach((field, index) => {
8138
+ concept.fields.forEach((field2, index) => {
6692
8139
  });
6693
8140
  }
6694
8141
  if (concept.fields && concept.fields.length > 0) {
6695
- concept.fields.forEach((field) => {
6696
- var _a, _b, _c;
8142
+ concept.fields.forEach((field2) => {
8143
+ var _a, _b, _c, _d;
6697
8144
  const conceptData = this._formData[concept.id];
6698
- const fieldValue = conceptData == null ? void 0 : conceptData[field.columnId];
8145
+ const fieldValue = conceptData == null ? void 0 : conceptData[field2.columnId];
6699
8146
  if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
6700
- const column2 = this._findColumnByIdInSection(field.columnId, section2);
6701
- const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field.columnId];
8147
+ const column2 = this._findColumnByIdInSection(field2.columnId, section2);
8148
+ const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field2.columnId];
6702
8149
  const submissionEntry = {
6703
8150
  conceptId: concept.id,
6704
- columnId: field.columnId,
8151
+ columnId: field2.columnId,
6705
8152
  // CRITICAL: Include columnId for draft restoration
6706
8153
  value: fieldValue,
6707
8154
  period: {
@@ -6709,27 +8156,34 @@ let JupiterDynamicForm = class extends LitElement {
6709
8156
  }
6710
8157
  };
6711
8158
  if (concept.periodType === "instant") {
6712
- const instantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodInstantDate || field.periodEndDate || field.periodStartDate || this.periodStartDate;
8159
+ const instantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodInstantDate || field2.periodEndDate || field2.periodStartDate || this.periodStartDate;
6713
8160
  submissionEntry.period.date = instantDate;
6714
8161
  } else {
6715
- const startDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field.periodStartDate || this.periodStartDate;
6716
- const endDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field.periodEndDate || this.periodEndDate;
8162
+ const startDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate;
8163
+ const endDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate;
6717
8164
  submissionEntry.period.startDate = startDate;
6718
8165
  submissionEntry.period.endDate = endDate;
6719
8166
  }
6720
- console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
6721
- if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_b = column2.dimensionData) == null ? void 0 : _b.dimensionIdKey)) {
8167
+ console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field2.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
8168
+ const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[field2.columnId];
8169
+ if (fieldUnit) {
8170
+ submissionEntry.unit = fieldUnit;
8171
+ console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${field2.columnId}`);
8172
+ } else {
8173
+ console.log(`⚠️ [Submission] No unit found in _unitData for ${concept.id}/${field2.columnId}. _unitData state:`, JSON.stringify(this._unitData, null, 2));
8174
+ }
8175
+ if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_c = column2.dimensionData) == null ? void 0 : _c.dimensionIdKey)) {
6722
8176
  submissionEntry.dimension = column2.dimensionData.dimensionIdKey;
6723
- console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field.columnId}):`, column2.dimensionData.dimensionIdKey);
8177
+ console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field2.columnId}):`, column2.dimensionData.dimensionIdKey);
6724
8178
  } else {
6725
- console.log(`🔍 [DynamicForm] No dimension data found for field column ${field.columnId}. Column type: ${column2 == null ? void 0 : column2.type}, has dimensionData: ${!!(column2 == null ? void 0 : column2.dimensionData)}`);
8179
+ console.log(`🔍 [DynamicForm] No dimension data found for field column ${field2.columnId}. Column type: ${column2 == null ? void 0 : column2.type}, has dimensionData: ${!!(column2 == null ? void 0 : column2.dimensionData)}`);
6726
8180
  }
6727
- if (this._typedMemberData[field.columnId]) {
8181
+ if (this._typedMemberData[field2.columnId]) {
6728
8182
  const applicableTypedDimensions = this._getApplicableTypedDimensions(concept, section2);
6729
8183
  console.log(`🔍 [DynamicForm] Concept ${concept.id} applicable typed dimensions:`, applicableTypedDimensions);
6730
8184
  if (applicableTypedDimensions.length > 0) {
6731
8185
  const filteredTypedMembers = {};
6732
- const allTypedMemberData = this._typedMemberData[field.columnId];
8186
+ const allTypedMemberData = this._typedMemberData[field2.columnId];
6733
8187
  applicableTypedDimensions.forEach((dimensionId) => {
6734
8188
  if (allTypedMemberData[dimensionId]) {
6735
8189
  const memberName = this._getTypedMemberNameForAxis(dimensionId, section2);
@@ -6749,12 +8203,12 @@ let JupiterDynamicForm = class extends LitElement {
6749
8203
  console.log(`🔍 [DynamicForm] Skipping typed members for concept ${concept.id} - not applicable to this hypercube`);
6750
8204
  }
6751
8205
  } else {
6752
- console.log(`🔍 [DynamicForm] No typed member data found for column ${field.columnId}. Available columns:`, Object.keys(this._typedMemberData));
8206
+ console.log(`🔍 [DynamicForm] No typed member data found for column ${field2.columnId}. Available columns:`, Object.keys(this._typedMemberData));
6753
8207
  if (column2) {
6754
8208
  console.log(`🔍 [DynamicForm] Column details:`, {
6755
8209
  id: column2.id,
6756
8210
  type: column2.type,
6757
- hasTypedMembers: (_c = column2.dimensionData) == null ? void 0 : _c.hasTypedMembers,
8211
+ hasTypedMembers: (_d = column2.dimensionData) == null ? void 0 : _d.hasTypedMembers,
6758
8212
  dimensionData: column2.dimensionData
6759
8213
  });
6760
8214
  }
@@ -6830,7 +8284,7 @@ let JupiterDynamicForm = class extends LitElement {
6830
8284
  });
6831
8285
  }
6832
8286
  _renderAdminModeContent(section2) {
6833
- var _a, _b, _c;
8287
+ var _a;
6834
8288
  if (!section2) {
6835
8289
  return html`
6836
8290
  <div class="admin-mode-container">
@@ -6838,10 +8292,7 @@ let JupiterDynamicForm = class extends LitElement {
6838
8292
  </div>
6839
8293
  `;
6840
8294
  }
6841
- const showPreviousYearChecked = ((_a = this._adminRoleConfigs[section2.id]) == null ? void 0 : _a.showPreviousYear) ?? section2.showPreviousYear ?? false;
6842
- const instantChecked = ((_b = this._adminRoleConfigs[section2.id]) == null ? void 0 : _b.instant) ?? section2.instant ?? false;
6843
- const durationChecked = ((_c = this._adminRoleConfigs[section2.id]) == null ? void 0 : _c.duration) ?? section2.duration ?? false;
6844
- const hasMixedPeriodTypes = section2.showPeriodControl === true;
8295
+ const showPreviousYearChecked = ((_a = this._periodPreferences[section2.id]) == null ? void 0 : _a.showPreviousYear) ?? section2.showPreviousYear ?? false;
6845
8296
  return html`
6846
8297
  <div class="admin-mode-container">
6847
8298
  <h2 class="admin-mode-title">Role Configuration: ${section2.title}</h2>
@@ -6857,45 +8308,33 @@ let JupiterDynamicForm = class extends LitElement {
6857
8308
  <label for="admin-prev-year-${section2.id}">Show Previous Year Column</label>
6858
8309
  </div>
6859
8310
  </div>
6860
-
6861
- ${hasMixedPeriodTypes ? html`
6862
- <div class="admin-role-item">
6863
- <div class="admin-role-checkbox">
6864
- <input
6865
- type="checkbox"
6866
- id="admin-instant-${section2.id}"
6867
- .checked="${instantChecked}"
6868
- @change="${(e2) => this._handleAdminCheckboxChange(section2.id, "instant", e2.target.checked)}"
6869
- />
6870
- <label for="admin-instant-${section2.id}">Show Instant Column</label>
6871
- </div>
6872
- </div>
6873
-
6874
- <div class="admin-role-item">
6875
- <div class="admin-role-checkbox">
6876
- <input
6877
- type="checkbox"
6878
- id="admin-duration-${section2.id}"
6879
- .checked="${durationChecked}"
6880
- @change="${(e2) => this._handleAdminCheckboxChange(section2.id, "duration", e2.target.checked)}"
6881
- />
6882
- <label for="admin-duration-${section2.id}">Show Duration Column</label>
6883
- </div>
6884
- </div>
6885
- ` : ""}
6886
8311
  </div>
6887
8312
  </div>
6888
8313
  `;
6889
8314
  }
6890
- _handleAdminCheckboxChange(roleId, field, checked) {
8315
+ _handleAdminCheckboxChange(roleId, field2, checked) {
6891
8316
  const currentConfig = this._adminRoleConfigs[roleId] || { showPreviousYear: false };
6892
8317
  this._adminRoleConfigs = {
6893
8318
  ...this._adminRoleConfigs,
6894
8319
  [roleId]: {
6895
8320
  ...currentConfig,
6896
- [field]: checked
8321
+ [field2]: checked
6897
8322
  }
6898
8323
  };
8324
+ const currentPeriodPref = this._periodPreferences[roleId] || {
8325
+ showDuration: true,
8326
+ showInstant: true,
8327
+ showPreviousYear: false
8328
+ };
8329
+ this._periodPreferences = {
8330
+ ...this._periodPreferences,
8331
+ [roleId]: {
8332
+ ...currentPeriodPref,
8333
+ [field2]: checked
8334
+ }
8335
+ };
8336
+ console.log(`✅ [Admin Mode] Updated ${field2} = ${checked} for role ${roleId}`);
8337
+ console.log(`📋 [Admin Mode] _periodPreferences now includes:`, this._periodPreferences[roleId]);
6899
8338
  }
6900
8339
  _handleAdminModeSubmit() {
6901
8340
  var _a, _b, _c, _d;
@@ -6916,12 +8355,6 @@ let JupiterDynamicForm = class extends LitElement {
6916
8355
  };
6917
8356
  if (config !== void 0 && isSelected) {
6918
8357
  updatedRole.showPreviousYear = config.showPreviousYear;
6919
- if (config.instant !== void 0) {
6920
- updatedRole.instant = config.instant;
6921
- }
6922
- if (config.duration !== void 0) {
6923
- updatedRole.duration = config.duration;
6924
- }
6925
8358
  }
6926
8359
  return updatedRole;
6927
8360
  });
@@ -6943,8 +8376,8 @@ let JupiterDynamicForm = class extends LitElement {
6943
8376
  <div class="validation-summary">
6944
8377
  <h4 class="validation-summary-title">${I18n.t("validation.summary")}</h4>
6945
8378
  <ul class="validation-summary-list">
6946
- ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
6947
- <li class="validation-summary-item">${error.message}</li>
8379
+ ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
8380
+ <li class="validation-summary-item">${error2.message}</li>
6948
8381
  `)}
6949
8382
  </ul>
6950
8383
  </div>
@@ -6961,12 +8394,19 @@ let JupiterDynamicForm = class extends LitElement {
6961
8394
  <p>${I18n.t("filter.selectRoles")}</p>
6962
8395
  <p>${I18n.t("filter.roles")}: ${this._allSections.length}</p>
6963
8396
  </div>
6964
- ` : schema.sections.map((section2, index) => html`
8397
+ ` : schema.sections.map((section2, index) => {
8398
+ var _a;
8399
+ return html`
6965
8400
  <jupiter-form-section
8401
+ section-id="${section2.id}"
6966
8402
  .section="${section2}"
6967
8403
  .columns="${section2.columns || this._columns}"
8404
+ .datatypes="${section2.datatypes || ((_a = this.xbrlInput) == null ? void 0 : _a.datatypes)}"
6968
8405
  .formData="${this._formData}"
8406
+ .periodData="${this._periodData}"
8407
+ .unitData="${this._unitData}"
6969
8408
  .typedMemberData="${this._typedMemberData}"
8409
+ .defaultUnits="${this.defaultUnits}"
6970
8410
  .disabled="${this.disabled || this.readonly}"
6971
8411
  .collapsible="${config.collapsibleSections !== false}"
6972
8412
  .locale="${config.locale || "en-US"}"
@@ -6980,11 +8420,13 @@ let JupiterDynamicForm = class extends LitElement {
6980
8420
  @column-remove="${this._handleColumnRemove}"
6981
8421
  @column-add-request="${this._handleColumnAddRequest}"
6982
8422
  ></jupiter-form-section>
6983
- `)}
8423
+ `;
8424
+ })}
6984
8425
  </div>
6985
8426
  `;
6986
8427
  }
6987
8428
  _renderSidePanelLayout(schema, config, showValidationSummary, errorCount) {
8429
+ var _a;
6988
8430
  const visibleSections = schema.sections;
6989
8431
  const filteredSections = this._filterSidePanelSections(visibleSections);
6990
8432
  if (!this._activeSidePanelRoleId || !filteredSections.find((s2) => s2.id === this._activeSidePanelRoleId)) {
@@ -7061,8 +8503,8 @@ let JupiterDynamicForm = class extends LitElement {
7061
8503
  <div class="validation-summary">
7062
8504
  <h4 class="validation-summary-title">Please fix the following errors:</h4>
7063
8505
  <ul class="validation-summary-list">
7064
- ${this._errors.filter((e2) => e2.severity === "error").map((error) => html`
7065
- <li class="validation-summary-item">${error.message}</li>
8506
+ ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
8507
+ <li class="validation-summary-item">${error2.message}</li>
7066
8508
  `)}
7067
8509
  </ul>
7068
8510
  </div>
@@ -7075,10 +8517,15 @@ let JupiterDynamicForm = class extends LitElement {
7075
8517
  </div>
7076
8518
  ` : activeSection ? html`
7077
8519
  <jupiter-form-section
8520
+ section-id="${activeSection.id}"
7078
8521
  .section="${activeSection}"
7079
8522
  .columns="${activeSection.columns || this._columns}"
8523
+ .datatypes="${activeSection.datatypes || ((_a = this.xbrlInput) == null ? void 0 : _a.datatypes)}"
7080
8524
  .formData="${this._formData}"
8525
+ .periodData="${this._periodData}"
8526
+ .unitData="${this._unitData}"
7081
8527
  .typedMemberData="${this._typedMemberData}"
8528
+ .defaultUnits="${this.defaultUnits}"
7082
8529
  .disabled="${this.disabled || this.readonly}"
7083
8530
  .collapsible="${false}"
7084
8531
  .hideHeader="${true}"
@@ -7179,11 +8626,7 @@ let JupiterDynamicForm = class extends LitElement {
7179
8626
  ${I18n.t("form.submit")}
7180
8627
  </button>
7181
8628
 
7182
- <div class="form-meta">
7183
- <span>${I18n.t("form.errors")}: ${errorCount}</span>
7184
- <span>${I18n.t("form.modified")}: ${this._dirty ? I18n.t("form.yes") : I18n.t("form.no")}</span>
7185
- <span>${I18n.t("form.valid")}: ${this._valid ? I18n.t("form.yes") : I18n.t("form.no")}</span>
7186
- </div>
8629
+
7187
8630
  </div>
7188
8631
 
7189
8632
  <!-- Filter Roles Dialog -->
@@ -7191,13 +8634,61 @@ let JupiterDynamicForm = class extends LitElement {
7191
8634
  <jupiter-filter-roles-dialog
7192
8635
  ?open="${this._showFilterDialog}"
7193
8636
  .availableRoles="${this._allSections}"
7194
- .selectedRoleIds="${this._selectedRoleIds}"
8637
+ .selectedRoleIds="${this._getRoleIdsArray()}"
7195
8638
  .periodPreferences="${this._periodPreferences}"
8639
+ .mode="${this.mode}"
7196
8640
  @dialog-cancel="${this._handleFilterDialogCancel}"
7197
8641
  @roles-filter-apply="${this._handleRoleFilterApply}"
7198
8642
  @click="${this._handleFilterDialogCancel}"
7199
8643
  ></jupiter-filter-roles-dialog>
7200
8644
  ` : ""}
8645
+
8646
+ <!-- Validation Error Popup -->
8647
+ ${this._showErrorPopup ? html`
8648
+ <div class="error-popup-overlay" @click="${() => {
8649
+ this._showErrorPopup = false;
8650
+ this.requestUpdate();
8651
+ }}">
8652
+ <div class="error-popup" @click="${(e2) => e2.stopPropagation()}">
8653
+ <div class="error-popup-header">
8654
+ <h3>⚠️ ${I18n.t("error.popup.title")}</h3>
8655
+ <button class="error-popup-close" @click="${() => {
8656
+ this._showErrorPopup = false;
8657
+ this.requestUpdate();
8658
+ }}">×</button>
8659
+ </div>
8660
+ <div class="error-popup-content">
8661
+ <p>${I18n.t("error.popup.message")}</p>
8662
+ <ul class="error-list">
8663
+ ${this._xbrlFormErrors.map((error2) => html`
8664
+ <li>
8665
+ <strong>${I18n.t("error.popup.field")}</strong>
8666
+ <a
8667
+ href="javascript:void(0)"
8668
+ class="error-field-link"
8669
+ @click="${() => this._handleErrorFieldClick(error2.conceptId, error2.columnId, error2.sectionId)}"
8670
+ title="${I18n.t("error.popup.clickToFocus")}"
8671
+ >
8672
+ ${error2.conceptId}__${error2.columnId}
8673
+ </a><br>
8674
+ <strong>${I18n.t("error.popup.value")}</strong> ${error2.value}<br>
8675
+ <strong>${I18n.t("error.popup.errors")}</strong>
8676
+ <ul>
8677
+ ${error2.errors.map((err) => html`<li>${err.message}</li>`)}
8678
+ </ul>
8679
+ </li>
8680
+ `)}
8681
+ </ul>
8682
+ </div>
8683
+ <div class="error-popup-footer">
8684
+ <button class="btn-primary" @click="${() => {
8685
+ this._showErrorPopup = false;
8686
+ this.requestUpdate();
8687
+ }}">${I18n.t("error.popup.ok")}</button>
8688
+ </div>
8689
+ </div>
8690
+ </div>
8691
+ ` : ""}
7201
8692
  </div>
7202
8693
  `;
7203
8694
  }
@@ -7631,6 +9122,128 @@ JupiterDynamicForm.styles = css`
7631
9122
  cursor: pointer;
7632
9123
  user-select: none;
7633
9124
  }
9125
+
9126
+ /* Error Popup Styles */
9127
+ .error-popup-overlay {
9128
+ position: fixed;
9129
+ top: 0;
9130
+ left: 0;
9131
+ right: 0;
9132
+ bottom: 0;
9133
+ background: rgba(0, 0, 0, 0.5);
9134
+ display: flex;
9135
+ align-items: center;
9136
+ justify-content: center;
9137
+ z-index: 10000;
9138
+ }
9139
+
9140
+ .error-popup {
9141
+ background: white;
9142
+ border-radius: 8px;
9143
+ max-width: 600px;
9144
+ width: 90%;
9145
+ max-height: 80vh;
9146
+ overflow: hidden;
9147
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
9148
+ display: flex;
9149
+ flex-direction: column;
9150
+ }
9151
+
9152
+ .error-popup-header {
9153
+ display: flex;
9154
+ justify-content: space-between;
9155
+ align-items: center;
9156
+ padding: 20px 24px;
9157
+ border-bottom: 1px solid var(--jupiter-border-color, #ddd);
9158
+ background: var(--jupiter-section-header-background, #f0f2f5);
9159
+ }
9160
+
9161
+ .error-popup-header h3 {
9162
+ margin: 0;
9163
+ font-size: 18px;
9164
+ font-weight: 600;
9165
+ color: var(--jupiter-error-color, #d32f2f);
9166
+ }
9167
+
9168
+ .error-popup-close {
9169
+ background: transparent;
9170
+ border: none;
9171
+ font-size: 28px;
9172
+ cursor: pointer;
9173
+ padding: 0;
9174
+ width: 32px;
9175
+ height: 32px;
9176
+ display: flex;
9177
+ align-items: center;
9178
+ justify-content: center;
9179
+ border-radius: 4px;
9180
+ color: var(--jupiter-text-color, #333);
9181
+ transition: background-color 0.2s;
9182
+ }
9183
+
9184
+ .error-popup-close:hover {
9185
+ background-color: rgba(0, 0, 0, 0.05);
9186
+ }
9187
+
9188
+ .error-popup-content {
9189
+ padding: 24px;
9190
+ overflow-y: auto;
9191
+ flex: 1;
9192
+ }
9193
+
9194
+ .error-popup-content p {
9195
+ margin: 0 0 16px 0;
9196
+ color: var(--jupiter-text-primary, #333);
9197
+ }
9198
+
9199
+ .error-list {
9200
+ list-style: none;
9201
+ padding: 0;
9202
+ margin: 0;
9203
+ }
9204
+
9205
+ .error-list > li {
9206
+ padding: 12px;
9207
+ background: #f8f9fa;
9208
+ border: 1px solid #dee2e6;
9209
+ border-radius: 4px;
9210
+ margin-bottom: 12px;
9211
+ }
9212
+
9213
+ .error-list > li strong {
9214
+ color: var(--jupiter-text-primary, #333);
9215
+ font-weight: 600;
9216
+ }
9217
+
9218
+ .error-list ul {
9219
+ margin: 8px 0 0 0;
9220
+ padding-left: 20px;
9221
+ }
9222
+
9223
+ .error-list ul li {
9224
+ color: var(--jupiter-error-color, #d32f2f);
9225
+ margin: 4px 0;
9226
+ }
9227
+
9228
+ .error-popup-footer {
9229
+ padding: 16px 24px;
9230
+ border-top: 1px solid var(--jupiter-border-color, #ddd);
9231
+ display: flex;
9232
+ justify-content: flex-end;
9233
+ gap: 12px;
9234
+ }
9235
+
9236
+ .error-field-link {
9237
+ color: #0066cc;
9238
+ text-decoration: underline;
9239
+ cursor: pointer;
9240
+ font-family: monospace;
9241
+ }
9242
+
9243
+ .error-field-link:hover {
9244
+ color: #0052a3;
9245
+ text-decoration: none;
9246
+ }
7634
9247
  `;
7635
9248
  __decorateClass([
7636
9249
  n2({ type: Object })
@@ -7668,6 +9281,9 @@ __decorateClass([
7668
9281
  __decorateClass([
7669
9282
  n2({ type: Array })
7670
9283
  ], JupiterDynamicForm.prototype, "financialStatementsTypeAxis", 2);
9284
+ __decorateClass([
9285
+ n2({ type: Array })
9286
+ ], JupiterDynamicForm.prototype, "defaultUnits", 2);
7671
9287
  __decorateClass([
7672
9288
  n2({ type: Object, attribute: "dynaforms-metadata" })
7673
9289
  ], JupiterDynamicForm.prototype, "dynaformsMetadata", 2);
@@ -7692,6 +9308,12 @@ __decorateClass([
7692
9308
  __decorateClass([
7693
9309
  r()
7694
9310
  ], JupiterDynamicForm.prototype, "_preservedPeriodData", 2);
9311
+ __decorateClass([
9312
+ r()
9313
+ ], JupiterDynamicForm.prototype, "_unitData", 2);
9314
+ __decorateClass([
9315
+ r()
9316
+ ], JupiterDynamicForm.prototype, "_preservedUnitData", 2);
7695
9317
  __decorateClass([
7696
9318
  r()
7697
9319
  ], JupiterDynamicForm.prototype, "_typedMemberData", 2);
@@ -7716,6 +9338,12 @@ __decorateClass([
7716
9338
  __decorateClass([
7717
9339
  r()
7718
9340
  ], JupiterDynamicForm.prototype, "_submitted", 2);
9341
+ __decorateClass([
9342
+ r()
9343
+ ], JupiterDynamicForm.prototype, "_xbrlFormErrors", 2);
9344
+ __decorateClass([
9345
+ r()
9346
+ ], JupiterDynamicForm.prototype, "_showErrorPopup", 2);
7719
9347
  __decorateClass([
7720
9348
  r()
7721
9349
  ], JupiterDynamicForm.prototype, "_currentSchema", 2);
@@ -7756,11 +9384,15 @@ export {
7756
9384
  JupiterFormField,
7757
9385
  JupiterFormSection,
7758
9386
  TYPE_INPUT_MAP,
9387
+ XBRLValidator,
9388
+ collectEnumerationsFromChain,
9389
+ determineInputTypeFromBaseChain,
7759
9390
  getInputTypeForConceptType,
7760
9391
  isCheckboxType,
7761
9392
  isNumericType,
7762
9393
  isSelectType,
7763
9394
  isTextareaType,
9395
+ resolveBaseTypeChain,
7764
9396
  version
7765
9397
  };
7766
9398
  //# sourceMappingURL=index.mjs.map