@salesforce/plugin-omnistudio-migration-tool 2.0.0-rc.6 → 2.0.0-rc.61

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.
Files changed (252) hide show
  1. package/README.md +165 -73
  2. package/lib/commands/omnistudio/migration/assess.d.ts +23 -15
  3. package/lib/commands/omnistudio/migration/assess.js +250 -89
  4. package/lib/commands/omnistudio/migration/assess.js.map +1 -1
  5. package/lib/commands/omnistudio/migration/clean.d.ts +13 -0
  6. package/lib/commands/omnistudio/migration/clean.js +162 -0
  7. package/lib/commands/omnistudio/migration/clean.js.map +1 -0
  8. package/lib/commands/omnistudio/migration/info.d.ts +10 -16
  9. package/lib/commands/omnistudio/migration/info.js +53 -35
  10. package/lib/commands/omnistudio/migration/info.js.map +1 -1
  11. package/lib/commands/omnistudio/migration/migrate.d.ts +78 -18
  12. package/lib/commands/omnistudio/migration/migrate.js +461 -175
  13. package/lib/commands/omnistudio/migration/migrate.js.map +1 -1
  14. package/lib/error/deploymentErrors.d.ts +15 -0
  15. package/lib/error/deploymentErrors.js +35 -0
  16. package/lib/error/deploymentErrors.js.map +1 -0
  17. package/lib/error/errorInterfaces.d.ts +5 -0
  18. package/lib/error/errorInterfaces.js +9 -1
  19. package/lib/error/errorInterfaces.js.map +1 -1
  20. package/lib/javascripts/reportGeneratorUtility.js +585 -22
  21. package/lib/migration/ApexNamespaceRegistry.d.ts +49 -0
  22. package/lib/migration/ApexNamespaceRegistry.js +130 -0
  23. package/lib/migration/ApexNamespaceRegistry.js.map +1 -0
  24. package/lib/migration/CustomCssRegistry.d.ts +117 -0
  25. package/lib/migration/CustomCssRegistry.js +234 -0
  26. package/lib/migration/CustomCssRegistry.js.map +1 -0
  27. package/lib/migration/NameMappingRegistry.d.ts +134 -0
  28. package/lib/migration/NameMappingRegistry.js +411 -0
  29. package/lib/migration/NameMappingRegistry.js.map +1 -0
  30. package/lib/migration/base.d.ts +8 -6
  31. package/lib/migration/base.js +25 -8
  32. package/lib/migration/base.js.map +1 -1
  33. package/lib/migration/customLabels.d.ts +70 -0
  34. package/lib/migration/customLabels.js +177 -0
  35. package/lib/migration/customLabels.js.map +1 -0
  36. package/lib/migration/dataraptor.d.ts +13 -0
  37. package/lib/migration/dataraptor.js +205 -80
  38. package/lib/migration/dataraptor.js.map +1 -1
  39. package/lib/migration/deployer.d.ts +14 -0
  40. package/lib/migration/deployer.js +105 -0
  41. package/lib/migration/deployer.js.map +1 -0
  42. package/lib/migration/flexcard.d.ts +256 -6
  43. package/lib/migration/flexcard.js +1808 -268
  44. package/lib/migration/flexcard.js.map +1 -1
  45. package/lib/migration/globalautonumber.d.ts +8 -8
  46. package/lib/migration/globalautonumber.js +49 -24
  47. package/lib/migration/globalautonumber.js.map +1 -1
  48. package/lib/migration/interfaces.d.ts +14 -0
  49. package/lib/migration/interfaces.js.map +1 -1
  50. package/lib/migration/metadataobjnamecheck.js.map +1 -1
  51. package/lib/migration/omniscript.d.ts +218 -4
  52. package/lib/migration/omniscript.js +1709 -247
  53. package/lib/migration/omniscript.js.map +1 -1
  54. package/lib/migration/omniscriptInstance.d.ts +90 -0
  55. package/lib/migration/omniscriptInstance.js +755 -0
  56. package/lib/migration/omniscriptInstance.js.map +1 -0
  57. package/lib/migration/postMigrate.d.ts +20 -4
  58. package/lib/migration/postMigrate.js +199 -12
  59. package/lib/migration/postMigrate.js.map +1 -1
  60. package/lib/migration/premigrate.d.ts +51 -0
  61. package/lib/migration/premigrate.js +325 -0
  62. package/lib/migration/premigrate.js.map +1 -0
  63. package/lib/migration/related/ApexMigration.d.ts +3 -0
  64. package/lib/migration/related/ApexMigration.js +222 -56
  65. package/lib/migration/related/ApexMigration.js.map +1 -1
  66. package/lib/migration/related/ExperienceSiteMigration.d.ts +30 -5
  67. package/lib/migration/related/ExperienceSiteMigration.js +263 -73
  68. package/lib/migration/related/ExperienceSiteMigration.js.map +1 -1
  69. package/lib/migration/related/FlexipageMigration.d.ts +5 -5
  70. package/lib/migration/related/FlexipageMigration.js +60 -38
  71. package/lib/migration/related/FlexipageMigration.js.map +1 -1
  72. package/lib/migration/related/LwcMigration.js +45 -26
  73. package/lib/migration/related/LwcMigration.js.map +1 -1
  74. package/lib/migration/related/OmnistudioRelatedObjectMigrationFacade.js +48 -32
  75. package/lib/migration/related/OmnistudioRelatedObjectMigrationFacade.js.map +1 -1
  76. package/lib/styles/reportGenerator.css +241 -16
  77. package/lib/templates/assessmentReport.template +78 -8
  78. package/lib/templates/dashboard.template +86 -57
  79. package/lib/templates/migrationReport.template +151 -0
  80. package/lib/utils/OmnistudioSettingsPrefManager.d.ts +14 -0
  81. package/lib/utils/OmnistudioSettingsPrefManager.js +112 -0
  82. package/lib/utils/OmnistudioSettingsPrefManager.js.map +1 -0
  83. package/lib/utils/XMLUtil.js +2 -1
  84. package/lib/utils/XMLUtil.js.map +1 -1
  85. package/lib/utils/apex/executor/AnonymousApexRunner.d.ts +1 -1
  86. package/lib/utils/apex/parser/apexparser.d.ts +8 -1
  87. package/lib/utils/apex/parser/apexparser.js +79 -13
  88. package/lib/utils/apex/parser/apexparser.js.map +1 -1
  89. package/lib/utils/config/ExistingRecordCleanupService.d.ts +30 -0
  90. package/lib/utils/config/ExistingRecordCleanupService.js +266 -0
  91. package/lib/utils/config/ExistingRecordCleanupService.js.map +1 -0
  92. package/lib/utils/config/OmniStudioMetadataCleanupService.d.ts +36 -0
  93. package/lib/utils/config/OmniStudioMetadataCleanupService.js +123 -0
  94. package/lib/utils/config/OmniStudioMetadataCleanupService.js.map +1 -0
  95. package/lib/utils/config/SpecialCharacterRecordCleanupService.d.ts +17 -0
  96. package/lib/utils/config/SpecialCharacterRecordCleanupService.js +186 -0
  97. package/lib/utils/config/SpecialCharacterRecordCleanupService.js.map +1 -0
  98. package/lib/utils/constants/documentRegistry.d.ts +9 -17
  99. package/lib/utils/constants/documentRegistry.js +9 -17
  100. package/lib/utils/constants/documentRegistry.js.map +1 -1
  101. package/lib/utils/constants/stringContants.d.ts +78 -0
  102. package/lib/utils/constants/stringContants.js +91 -4
  103. package/lib/utils/constants/stringContants.js.map +1 -1
  104. package/lib/utils/customLabels.d.ts +35 -0
  105. package/lib/utils/customLabels.js +100 -0
  106. package/lib/utils/customLabels.js.map +1 -0
  107. package/lib/utils/dataModelService.d.ts +18 -0
  108. package/lib/utils/dataModelService.js +72 -0
  109. package/lib/utils/dataModelService.js.map +1 -0
  110. package/lib/utils/file/fileUtil.d.ts +3 -1
  111. package/lib/utils/file/fileUtil.js +30 -13
  112. package/lib/utils/file/fileUtil.js.map +1 -1
  113. package/lib/utils/flexipage/flexiPageTransformer.js +119 -23
  114. package/lib/utils/flexipage/flexiPageTransformer.js.map +1 -1
  115. package/lib/utils/formula/FormulaUtil.d.ts +1 -1
  116. package/lib/utils/formula/FormulaUtil.js +17 -9
  117. package/lib/utils/formula/FormulaUtil.js.map +1 -1
  118. package/lib/utils/formula/Stack.js.map +1 -1
  119. package/lib/utils/generatePackageXml.d.ts +6 -2
  120. package/lib/utils/generatePackageXml.js +73 -33
  121. package/lib/utils/generatePackageXml.js.map +1 -1
  122. package/lib/utils/index.d.ts +1 -0
  123. package/lib/utils/index.js +1 -0
  124. package/lib/utils/index.js.map +1 -1
  125. package/lib/utils/interfaces.d.ts +69 -8
  126. package/lib/utils/json/jsonutil.js.map +1 -1
  127. package/lib/utils/logger/fileLogger.js +17 -7
  128. package/lib/utils/logger/fileLogger.js.map +1 -1
  129. package/lib/utils/logger.d.ts +3 -3
  130. package/lib/utils/logger.js +10 -6
  131. package/lib/utils/logger.js.map +1 -1
  132. package/lib/utils/logging/debugtimer.js.map +1 -1
  133. package/lib/utils/lwcparser/fileutils/FileDiffUtil.js +30 -22
  134. package/lib/utils/lwcparser/fileutils/FileDiffUtil.js.map +1 -1
  135. package/lib/utils/lwcparser/fileutils/FileProcessorFactory.js.map +1 -1
  136. package/lib/utils/lwcparser/fileutils/HtmlFileProcessor.js.map +1 -1
  137. package/lib/utils/lwcparser/fileutils/JavascriptFileProcessor.js.map +1 -1
  138. package/lib/utils/lwcparser/fileutils/XmlFileProcessor.js.map +1 -1
  139. package/lib/utils/lwcparser/htmlParser/HTMLParser.js +29 -10
  140. package/lib/utils/lwcparser/htmlParser/HTMLParser.js.map +1 -1
  141. package/lib/utils/lwcparser/jsParser/JavaScriptParser.js +29 -11
  142. package/lib/utils/lwcparser/jsParser/JavaScriptParser.js.map +1 -1
  143. package/lib/utils/lwcparser/xmlParser/XmlParser.js +19 -8
  144. package/lib/utils/lwcparser/xmlParser/XmlParser.js.map +1 -1
  145. package/lib/utils/net/index.d.ts +5 -0
  146. package/lib/utils/net/index.js +40 -2
  147. package/lib/utils/net/index.js.map +1 -1
  148. package/lib/utils/omniscriptPackageManager.d.ts +31 -0
  149. package/lib/utils/omniscriptPackageManager.js +215 -0
  150. package/lib/utils/omniscriptPackageManager.js.map +1 -0
  151. package/lib/utils/orgPreferences.d.ts +25 -0
  152. package/lib/utils/orgPreferences.js +124 -8
  153. package/lib/utils/orgPreferences.js.map +1 -1
  154. package/lib/utils/orgUtils/index.d.ts +12 -5
  155. package/lib/utils/orgUtils/index.js +52 -22
  156. package/lib/utils/orgUtils/index.js.map +1 -1
  157. package/lib/utils/projectPathUtil.d.ts +1 -1
  158. package/lib/utils/projectPathUtil.js +27 -10
  159. package/lib/utils/projectPathUtil.js.map +1 -1
  160. package/lib/utils/promptUtil.d.ts +11 -1
  161. package/lib/utils/promptUtil.js +92 -0
  162. package/lib/utils/promptUtil.js.map +1 -1
  163. package/lib/utils/query/index.d.ts +1 -0
  164. package/lib/utils/query/index.js +18 -1
  165. package/lib/utils/query/index.js.map +1 -1
  166. package/lib/utils/recordPrioritization.d.ts +44 -0
  167. package/lib/utils/recordPrioritization.js +69 -0
  168. package/lib/utils/recordPrioritization.js.map +1 -0
  169. package/lib/utils/reportGenerator/reportInterfaces.d.ts +12 -0
  170. package/lib/utils/reportGenerator/reportUtil.d.ts +6 -1
  171. package/lib/utils/reportGenerator/reportUtil.js +22 -7
  172. package/lib/utils/reportGenerator/reportUtil.js.map +1 -1
  173. package/lib/utils/resultsbuilder/ApexAssessmentReporter.d.ts +1 -0
  174. package/lib/utils/resultsbuilder/ApexAssessmentReporter.js +40 -17
  175. package/lib/utils/resultsbuilder/ApexAssessmentReporter.js.map +1 -1
  176. package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.d.ts +13 -0
  177. package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.js +179 -0
  178. package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.js.map +1 -0
  179. package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.d.ts +27 -0
  180. package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.js +262 -0
  181. package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.js.map +1 -0
  182. package/lib/utils/resultsbuilder/DRAssessmentReporter.js +38 -70
  183. package/lib/utils/resultsbuilder/DRAssessmentReporter.js.map +1 -1
  184. package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.d.ts +14 -0
  185. package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.js +143 -0
  186. package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.js.map +1 -0
  187. package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js +46 -85
  188. package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js.map +1 -1
  189. package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.d.ts +1 -0
  190. package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.js +37 -19
  191. package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.js.map +1 -1
  192. package/lib/utils/resultsbuilder/GlobalAutoNumberAssessmentReporter.js +22 -14
  193. package/lib/utils/resultsbuilder/GlobalAutoNumberAssessmentReporter.js.map +1 -1
  194. package/lib/utils/resultsbuilder/IPAssessmentReporter.js +38 -71
  195. package/lib/utils/resultsbuilder/IPAssessmentReporter.js.map +1 -1
  196. package/lib/utils/resultsbuilder/LWCAssessmentReporter.d.ts +14 -0
  197. package/lib/utils/resultsbuilder/LWCAssessmentReporter.js +143 -139
  198. package/lib/utils/resultsbuilder/LWCAssessmentReporter.js.map +1 -1
  199. package/lib/utils/resultsbuilder/OSAssessmentReporter.js +41 -88
  200. package/lib/utils/resultsbuilder/OSAssessmentReporter.js.map +1 -1
  201. package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.d.ts +12 -0
  202. package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js +109 -0
  203. package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js.map +1 -0
  204. package/lib/utils/resultsbuilder/assessmentReporter.d.ts +16 -6
  205. package/lib/utils/resultsbuilder/assessmentReporter.js +96 -152
  206. package/lib/utils/resultsbuilder/assessmentReporter.js.map +1 -1
  207. package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.d.ts +104 -0
  208. package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js +380 -0
  209. package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js.map +1 -0
  210. package/lib/utils/resultsbuilder/index.d.ts +37 -1
  211. package/lib/utils/resultsbuilder/index.js +582 -151
  212. package/lib/utils/resultsbuilder/index.js.map +1 -1
  213. package/lib/utils/resultsbuilder/reportingHelper.d.ts +2 -7
  214. package/lib/utils/resultsbuilder/reportingHelper.js +0 -43
  215. package/lib/utils/resultsbuilder/reportingHelper.js.map +1 -1
  216. package/lib/utils/sfcli/project/sfProject.d.ts +29 -0
  217. package/lib/utils/sfcli/project/sfProject.js +220 -2
  218. package/lib/utils/sfcli/project/sfProject.js.map +1 -1
  219. package/lib/utils/shell/cli.js +20 -14
  220. package/lib/utils/shell/cli.js.map +1 -1
  221. package/lib/utils/storageUtil.d.ts +14 -1
  222. package/lib/utils/storageUtil.js +31 -1
  223. package/lib/utils/storageUtil.js.map +1 -1
  224. package/lib/utils/stringUtils.d.ts +24 -0
  225. package/lib/utils/stringUtils.js +76 -9
  226. package/lib/utils/stringUtils.js.map +1 -1
  227. package/lib/utils/templateParser/__tests__/test.js +1 -2
  228. package/lib/utils/templateParser/__tests__/test.js.map +1 -1
  229. package/lib/utils/templateParser/generate.d.ts +1 -1
  230. package/lib/utils/templateParser/generate.js.map +1 -1
  231. package/lib/utils/templateParser/model/elementNode.d.ts +2 -2
  232. package/lib/utils/templateParser/model/elementNode.js +11 -2
  233. package/lib/utils/templateParser/model/elementNode.js.map +1 -1
  234. package/lib/utils/templateParser/model/nodeTypes.js +1 -1
  235. package/lib/utils/templateParser/model/nodeTypes.js.map +1 -1
  236. package/lib/utils/templateParser/util.d.ts +2 -2
  237. package/lib/utils/templateParser/util.js.map +1 -1
  238. package/lib/utils/validatorService.d.ts +14 -0
  239. package/lib/utils/validatorService.js +136 -0
  240. package/lib/utils/validatorService.js.map +1 -0
  241. package/messages/assess.json +220 -103
  242. package/messages/clean.json +40 -0
  243. package/messages/info.json +2 -1
  244. package/messages/migrate.json +314 -102
  245. package/oclif.manifest.json +1 -1
  246. package/package.json +49 -13
  247. package/lib/commands/basecommand.d.ts +0 -8
  248. package/lib/commands/basecommand.js +0 -13
  249. package/lib/commands/basecommand.js.map +0 -1
  250. package/lib/utils/OmniGlobalAutoNumberPrefManager.d.ts +0 -40
  251. package/lib/utils/OmniGlobalAutoNumberPrefManager.js +0 -65
  252. package/lib/utils/OmniGlobalAutoNumberPrefManager.js.map +0 -1
@@ -1,3 +1,6 @@
1
+ let props = {};
2
+ let classToHide = 'no-display';
3
+
1
4
  function toggleFilterDropdown(tableId) {
2
5
  const reportTable = document.getElementById(tableId);
3
6
  const dropdown = reportTable.querySelector('#filter-dropdown');
@@ -11,9 +14,35 @@ function toggleFilterDropdown(tableId) {
11
14
  }
12
15
  }
13
16
 
14
- function toggleDiffModal(name) {
15
- const modal = document.getElementById(`myModal_${name}`);
16
- modal.style.display = modal.style.display === 'none' ? 'flex' : 'none';
17
+ function closeFilterDropdown(tableId) {
18
+ const reportTable = document.getElementById(tableId);
19
+ if (!reportTable) return;
20
+
21
+ const dropdown = reportTable.querySelector('#filter-dropdown');
22
+ const chevronUp = reportTable.querySelector('#chevron-up');
23
+ const chevronDown = reportTable.querySelector('#chevron-down');
24
+
25
+ if (dropdown && dropdown.classList.contains('show')) {
26
+ dropdown.classList.remove('show');
27
+ if (chevronUp) chevronUp.classList.add('hidden');
28
+ if (chevronDown) chevronDown.classList.remove('hidden');
29
+ }
30
+ }
31
+
32
+ function closeAllFilterDropdowns() {
33
+ const openDropdowns = document.querySelectorAll('.filter-dropdown.show');
34
+
35
+ openDropdowns.forEach((dropdown) => {
36
+ dropdown.classList.remove('show');
37
+ // Find and update chevron icons
38
+ const container = dropdown.closest('.filter-dropdown-container') || dropdown.parentElement;
39
+ if (container) {
40
+ const chevronUp = container.querySelector('#chevron-up');
41
+ const chevronDown = container.querySelector('#chevron-down');
42
+ if (chevronUp) chevronUp.classList.add('hidden');
43
+ if (chevronDown) chevronDown.classList.remove('hidden');
44
+ }
45
+ });
17
46
  }
18
47
 
19
48
  function toggleDiffModal(name) {
@@ -61,6 +90,8 @@ function filterAndSearchTable(tableId) {
61
90
 
62
91
  // Otherwise, apply filters and search
63
92
  let processedClasses = new Set();
93
+
94
+ let classRowMap = new Map();
64
95
  rows.forEach((row) => {
65
96
  if (row.id === 'no-rows-message') return;
66
97
 
@@ -86,10 +117,18 @@ function filterAndSearchTable(tableId) {
86
117
  }
87
118
  }
88
119
 
89
- // row.style.display = show ? '' : 'none';
90
- if (!processedClasses.has(row.classList[0])) {
91
- hideOrShowData(reportTable, row.classList[0], show);
92
- processedClasses.add(row.classList[0]);
120
+ if (props?.rowBased) {
121
+ if (show && !classRowMap.has(row.classList[0])) {
122
+ classRowMap.set(row.classList[0], { row, cnt: 1 });
123
+ } else if (show) {
124
+ classRowMap.get(row.classList[0]).cnt++;
125
+ }
126
+ row.style.display = show ? '' : 'none';
127
+ } else {
128
+ if (!processedClasses.has(row.classList[0])) {
129
+ hideOrShowData(reportTable, row.classList[0], show);
130
+ processedClasses.add(row.classList[0]);
131
+ }
93
132
  }
94
133
  if (show) visibleRowCount++;
95
134
  });
@@ -102,9 +141,25 @@ function filterAndSearchTable(tableId) {
102
141
  const visibleRows = Array.from(table.rows).filter(
103
142
  (row) => row.style.display !== 'none' && row.id !== 'no-rows-message'
104
143
  );
105
- reportTable.querySelector('#row-count').textContent = `Showing ${visibleRows.length} record${
106
- visibleRows.length !== 1 ? 's' : ''
107
- }`;
144
+
145
+ if (props?.rowBased) {
146
+ rows.forEach((row) => {
147
+ row.cells[0].classList.add(classToHide);
148
+ });
149
+
150
+ classRowMap.forEach((value) => {
151
+ value.row.cells[0].classList.remove(classToHide);
152
+ value.row.cells[0].rowSpan = value.cnt;
153
+ });
154
+ }
155
+
156
+ // filter only distinct classes from visibleRows
157
+ let recordLabel = props?.recordName || 'records';
158
+ let cnt = visibleRows.length;
159
+ if (!props?.rowCount) {
160
+ cnt = [...new Set(visibleRows.map((row) => row.classList[0]))].length;
161
+ }
162
+ reportTable.querySelector('#row-count').textContent = `Total ${recordLabel}: ${cnt}`;
108
163
  }
109
164
 
110
165
  function toggleCtaSummaryPanel() {
@@ -131,6 +186,7 @@ function hideOrShowData(reportTable, rowClass, show) {
131
186
  }
132
187
 
133
188
  document.addEventListener('DOMContentLoaded', () => {
189
+ loadProps();
134
190
  document.querySelectorAll('.collapsible-content').forEach((collapsibleContent) => {
135
191
  collapsibleContent.style.display = 'none';
136
192
  });
@@ -153,6 +209,55 @@ document.addEventListener('DOMContentLoaded', () => {
153
209
  document.querySelectorAll('.rpt-table-container').forEach((tableContainer) => {
154
210
  filterAndSearchTable(tableContainer.id);
155
211
  });
212
+
213
+ document.querySelectorAll('tr').forEach((row) => {
214
+ row.addEventListener('mouseover', (event) => {
215
+ const className = event.currentTarget.classList[0];
216
+ document.querySelectorAll(`.${className}`).forEach((r) => {
217
+ r.classList.add('highlight');
218
+ });
219
+ });
220
+ row.addEventListener('mouseout', (event) => {
221
+ const className = event.currentTarget.classList[0];
222
+ document.querySelectorAll(`.${className}`).forEach((r) => {
223
+ r.classList.remove('highlight');
224
+ });
225
+ });
226
+ });
227
+
228
+ // Attach filter dropdown event listeners after DOM is loaded
229
+ // Close panel and filter dropdown on escape key
230
+ document.addEventListener('keydown', function (event) {
231
+ if (event.key === 'Escape' || event.keyCode === 27) {
232
+ event.preventDefault();
233
+
234
+ try {
235
+ closeCtaPanel();
236
+ } catch (error) {
237
+ // Silently handle error if CTA panel elements don't exist
238
+ }
239
+
240
+ try {
241
+ closeAllFilterDropdowns();
242
+ } catch (error) {
243
+ // Silently handle error if filter dropdown elements don't exist
244
+ }
245
+ }
246
+ });
247
+
248
+ // Close filter dropdown when clicking outside
249
+ document.addEventListener('click', function (event) {
250
+ // Find all open filter dropdowns
251
+ document.querySelectorAll('.filter-dropdown.show').forEach((dropdown) => {
252
+ const reportTable = dropdown.closest('.rpt-table-container');
253
+ const filterButton = reportTable?.querySelector('.filter-toggle-button');
254
+
255
+ // Check if click was outside the dropdown and not on the filter button
256
+ if (reportTable && !dropdown.contains(event.target) && !filterButton?.contains(event.target)) {
257
+ closeFilterDropdown(reportTable.id);
258
+ }
259
+ });
260
+ });
156
261
  });
157
262
 
158
263
  function openReport(ele) {
@@ -164,11 +269,14 @@ function toggleCtaPanel() {
164
269
  const panel = document.getElementById('ctaPanel');
165
270
  const overlay = document.getElementById('overlay');
166
271
 
167
- if (panel.classList.contains('open')) {
168
- closeCtaPanel();
169
- } else {
170
- panel.classList.add('open');
171
- overlay.classList.add('open');
272
+ // Only try to toggle if elements exist
273
+ if (panel && overlay) {
274
+ if (panel.classList.contains('open')) {
275
+ closeCtaPanel();
276
+ } else {
277
+ panel.classList.add('open');
278
+ overlay.classList.add('open');
279
+ }
172
280
  }
173
281
  }
174
282
 
@@ -176,18 +284,473 @@ function closeCtaPanel() {
176
284
  const panel = document.getElementById('ctaPanel');
177
285
  const overlay = document.getElementById('overlay');
178
286
 
179
- panel.classList.remove('open');
180
- overlay.classList.remove('open');
287
+ // Only try to close if elements exist
288
+ if (panel) {
289
+ panel.classList.remove('open');
290
+ }
291
+ if (overlay) {
292
+ overlay.classList.remove('open');
293
+ }
181
294
  }
182
295
 
183
- // Close panel on escape key
184
- document.addEventListener('keydown', function (event) {
185
- if (event.key === 'Escape') {
186
- closeCtaPanel();
296
+ function loadProps() {
297
+ const propElement = document.querySelector('#props');
298
+ if (!propElement) {
299
+ return;
187
300
  }
188
- });
301
+
302
+ try {
303
+ props = JSON.parse(propElement.textContent);
304
+ } catch (error) {
305
+ console.error('error parsing props', error);
306
+ return;
307
+ }
308
+ console.log('parsed props', props);
309
+ }
310
+
311
+ /**
312
+ * Helper function to apply sticky styling to a single column
313
+ * Used for reports where only the first column should be frozen:
314
+ * - Custom Labels (rowspan=2, colspan=1) - 180px width
315
+ * - Apex, LWC, Experience Sites, FlexiPage (single-level header) - 250px width
316
+ */
317
+ function applySingleColumnFreeze(table, headerCell, columnWidth = 180) {
318
+ // Default to 180px for Custom Labels, but can be overridden for other reports
319
+
320
+ // Apply styles to first header cell
321
+ applyStickyStyles(headerCell, columnWidth, 0, 50, '#f3f3f3', true);
322
+
323
+ // Ensure all other header cells in both rows are NOT sticky
324
+ const thead = table.querySelector('thead');
325
+ if (thead) {
326
+ const allHeaderCells = thead.querySelectorAll('th');
327
+ allHeaderCells.forEach((th, index) => {
328
+ if (index > 0) {
329
+ removeStickyStyles(th);
330
+ }
331
+ });
332
+ }
333
+
334
+ // Apply styles to body cells in first column
335
+ const tbody = table.querySelector('tbody');
336
+ if (tbody) {
337
+ const rows = tbody.querySelectorAll('tr');
338
+ rows.forEach((row) => {
339
+ // Use key="name" selector to handle rowspan correctly
340
+ const firstCell = row.querySelector('td[key="name"]');
341
+ if (firstCell) {
342
+ applyStickyStyles(firstCell, columnWidth, 0, 30, '#fff', true);
343
+ }
344
+ });
345
+
346
+ // Ensure all other columns are NOT sticky
347
+ rows.forEach((row) => {
348
+ const cells = Array.from(row.querySelectorAll('td'));
349
+ cells.forEach((cell) => {
350
+ // Remove sticky from any cell that's NOT the name column
351
+ if (cell.getAttribute('key') !== 'name') {
352
+ removeStickyStyles(cell);
353
+ }
354
+ });
355
+ });
356
+
357
+ // Add hover effect for first column
358
+ rows.forEach((row) => {
359
+ row.addEventListener('mouseenter', () => {
360
+ const firstCell = row.querySelector('td[key="name"]');
361
+ if (firstCell) {
362
+ firstCell.style.setProperty('background-color', '#f3f3f3', 'important');
363
+ }
364
+ });
365
+
366
+ row.addEventListener('mouseleave', () => {
367
+ const firstCell = row.querySelector('td[key="name"]');
368
+ if (firstCell) {
369
+ firstCell.style.setProperty('background-color', '#fff', 'important');
370
+ }
371
+ });
372
+ });
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Helper function to apply sticky styles to a cell
378
+ */
379
+ function applyStickyStyles(element, width, left, zIndex, bgColor, addBorder = false) {
380
+ element.style.setProperty('width', `${width}px`, 'important');
381
+ element.style.setProperty('min-width', `${width}px`, 'important');
382
+ element.style.setProperty('max-width', `${width}px`, 'important');
383
+ element.style.setProperty('position', 'sticky', 'important');
384
+ element.style.setProperty('left', `${left}px`, 'important');
385
+ element.style.setProperty('z-index', `${zIndex}`, 'important');
386
+ element.style.setProperty('background-color', bgColor, 'important');
387
+ if (addBorder) {
388
+ element.style.setProperty('border-right', '1px solid #e5e5e5', 'important');
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Helper function to remove sticky styles from a cell
394
+ */
395
+ function removeStickyStyles(element) {
396
+ element.style.setProperty('position', 'static', 'important');
397
+ element.style.setProperty('left', 'auto', 'important');
398
+ element.style.setProperty('width', 'auto', 'important');
399
+ element.style.setProperty('min-width', 'auto', 'important');
400
+ element.style.setProperty('max-width', 'none', 'important');
401
+ }
402
+
403
+ /**
404
+ * Apply sticky styles to header cells for multi-column freeze
405
+ */
406
+ function applyMultiColumnHeaderFreeze(firstHeaderCell, secondRow, colspan, baseColumnWidth, firstColumnWidth) {
407
+ // Calculate total width for the first header
408
+ const totalHeaderWidth = firstColumnWidth + (colspan - 1) * baseColumnWidth;
409
+
410
+ // Apply styles to first row first header
411
+ applyStickyStyles(firstHeaderCell, totalHeaderWidth, 0, 20, '#f3f3f3', true);
412
+
413
+ // Apply styles to second row headers (sub-headers under the first header)
414
+ const secondRowHeaders = Array.from(secondRow.querySelectorAll('th'));
415
+ let cumulativeLeft = 0;
416
+
417
+ for (let i = 0; i < secondRowHeaders.length; i++) {
418
+ const header = secondRowHeaders[i];
419
+
420
+ if (i < colspan) {
421
+ // Freeze this column
422
+ const columnWidth = i === 0 ? firstColumnWidth : baseColumnWidth;
423
+ const isLastFrozen = i === colspan - 1;
424
+ applyStickyStyles(header, columnWidth, cumulativeLeft, 50, '#f3f3f3', isLastFrozen);
425
+ cumulativeLeft += columnWidth;
426
+ } else {
427
+ // Ensure non-frozen columns are NOT sticky
428
+ removeStickyStyles(header);
429
+ }
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Remove sticky styles from non-frozen first-row headers
435
+ */
436
+ function removeNonFrozenHeaderStyles(firstRow) {
437
+ const firstRowHeaders = Array.from(firstRow.querySelectorAll('th'));
438
+ for (let i = 1; i < firstRowHeaders.length; i++) {
439
+ removeStickyStyles(firstRowHeaders[i]);
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Apply sticky styles to body cells for multi-column freeze
445
+ */
446
+ function applyMultiColumnBodyFreeze(tbody, colspan, baseColumnWidth, firstColumnWidth) {
447
+ const rows = tbody.querySelectorAll('tr');
448
+
449
+ rows.forEach((row) => {
450
+ const cells = Array.from(row.querySelectorAll('td'));
451
+ let cumulativeLeft = 0;
452
+
453
+ for (let i = 0; i < cells.length; i++) {
454
+ const cell = cells[i];
455
+
456
+ if (i < colspan) {
457
+ // Freeze this column
458
+ const columnWidth = i === 0 ? firstColumnWidth : baseColumnWidth;
459
+ const isLastFrozen = i === colspan - 1;
460
+ applyStickyStyles(cell, columnWidth, cumulativeLeft, 30, '#fff', isLastFrozen);
461
+ cumulativeLeft += columnWidth;
462
+ } else {
463
+ // Ensure non-frozen columns are NOT sticky
464
+ removeStickyStyles(cell);
465
+ }
466
+ }
467
+ });
468
+ }
469
+
470
+ /**
471
+ * Add hover effects to frozen cells
472
+ */
473
+ function addHoverEffects(tbody, colspan) {
474
+ const rows = tbody.querySelectorAll('tr');
475
+
476
+ rows.forEach((row) => {
477
+ row.addEventListener('mouseenter', () => {
478
+ const cells = Array.from(row.querySelectorAll('td'));
479
+ for (let i = 0; i < colspan && i < cells.length; i++) {
480
+ cells[i].style.setProperty('background-color', '#f3f3f3', 'important');
481
+ }
482
+ });
483
+
484
+ row.addEventListener('mouseleave', () => {
485
+ const cells = Array.from(row.querySelectorAll('td'));
486
+ for (let i = 0; i < colspan && i < cells.length; i++) {
487
+ cells[i].style.setProperty('background-color', '#fff', 'important');
488
+ }
489
+ });
490
+ });
491
+ }
492
+
493
+ /**
494
+ * Handle multi-column freeze (for reports with colspan > 1)
495
+ */
496
+ function handleMultiColumnFreeze(table, firstHeaderCell, firstRow, secondRow, colspan) {
497
+ const baseColumnWidth = 200;
498
+ const firstColumnWidth = 250;
499
+
500
+ // Apply header styles
501
+ applyMultiColumnHeaderFreeze(firstHeaderCell, secondRow, colspan, baseColumnWidth, firstColumnWidth);
502
+
503
+ // Remove sticky from other first-row headers
504
+ removeNonFrozenHeaderStyles(firstRow);
505
+
506
+ // Apply body cell styles
507
+ const tbody = table.querySelector('tbody');
508
+ if (tbody) {
509
+ applyMultiColumnBodyFreeze(tbody, colspan, baseColumnWidth, firstColumnWidth);
510
+ addHoverEffects(tbody, colspan);
511
+ }
512
+ }
513
+
514
+ /**
515
+ * Process a single table for sticky column application
516
+ */
517
+ function processTable(table) {
518
+ const thead = table.querySelector('thead');
519
+ if (!thead) return;
520
+
521
+ const firstRow = thead.querySelector('tr:first-child');
522
+ const secondRow = thead.querySelector('tr:nth-child(2)');
523
+
524
+ if (!firstRow) return;
525
+
526
+ // Get the first header cell and its colspan/rowspan
527
+ const firstHeaderCell = firstRow.querySelector('th:first-child');
528
+ if (!firstHeaderCell) return;
529
+
530
+ const colspan = parseInt(firstHeaderCell.getAttribute('colspan') || '1', 10);
531
+ const rowspan = parseInt(firstHeaderCell.getAttribute('rowspan') || '1', 10);
532
+
533
+ // Handle single column with rowspan=2 (e.g., Custom Labels)
534
+ if (rowspan === 2 && colspan === 1) {
535
+ applySingleColumnFreeze(table, firstHeaderCell, 180);
536
+ return;
537
+ }
538
+
539
+ // Handle single-level header (e.g., Apex, LWC, Experience Sites, FlexiPage)
540
+ if (rowspan === 1 && colspan === 1 && !secondRow) {
541
+ applySingleColumnFreeze(table, firstHeaderCell, 250);
542
+ return;
543
+ }
544
+
545
+ // Handle multi-column freeze with colspan
546
+ if (secondRow && colspan > 1) {
547
+ handleMultiColumnFreeze(table, firstHeaderCell, firstRow, secondRow, colspan);
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Main function: Dynamically applies sticky column styling to all tables
553
+ * Reads the table structure to determine how many columns should be frozen
554
+ */
555
+ function applyDynamicStickyColumns() {
556
+ const tableContainers = document.querySelectorAll('.table-container');
557
+
558
+ tableContainers.forEach((container) => {
559
+ const table = container.querySelector('table.slds-table');
560
+ if (table) {
561
+ processTable(table);
562
+ }
563
+ });
564
+ }
565
+
566
+ // Run on page load
567
+ document.addEventListener('DOMContentLoaded', applyDynamicStickyColumns);
568
+
569
+ /**
570
+ * Export visible table data to CSV file
571
+ * Only exports rows that are currently visible (respects active filters and search)
572
+ * Shows visual feedback on the export button to confirm success or indicate failure
573
+ */
574
+ function exportTableToCSV(tableId) {
575
+ const exportButton = document.querySelector('.export-csv-button');
576
+
577
+ try {
578
+ const reportTable = document.getElementById(tableId);
579
+ if (!reportTable) return;
580
+
581
+ // Show "Exporting..." state on button
582
+ if (exportButton) {
583
+ exportButton.textContent = 'Exporting...';
584
+ exportButton.disabled = true;
585
+ }
586
+
587
+ // Check if props has a pre-generated CSV file to download (e.g., Custom Labels with all records)
588
+ if (props && props.csvFile) {
589
+ // Download the pre-generated CSV file
590
+ const link = document.createElement('a');
591
+ link.setAttribute('href', props.csvFile);
592
+ link.setAttribute('download', props.csvFile);
593
+ link.style.display = 'none';
594
+ document.body.appendChild(link);
595
+ link.click();
596
+ document.body.removeChild(link);
597
+ showExportSuccess(exportButton);
598
+ return;
599
+ }
600
+
601
+ const table = reportTable.querySelector('table.slds-table');
602
+ if (!table) {
603
+ showExportError(exportButton, 'No table data found');
604
+ return;
605
+ }
606
+
607
+ const csvRows = [];
608
+
609
+ // Extract headers - flatten multi-row headers into a single row
610
+ const thead = table.querySelector('thead');
611
+ if (thead) {
612
+ const headerRows = thead.querySelectorAll('tr');
613
+ const headers = [];
614
+
615
+ if (headerRows.length === 1) {
616
+ // Single-row header
617
+ headerRows[0].querySelectorAll('th').forEach((th) => {
618
+ headers.push(escapeCSVValue(th.textContent.trim()));
619
+ });
620
+ } else if (headerRows.length >= 2) {
621
+ // Multi-row header (e.g., Custom Labels with "Package > Id, Value" and "Core > Id, Value")
622
+ const firstRow = headerRows[0];
623
+ const secondRow = headerRows[1];
624
+ const secondRowHeaders = Array.from(secondRow.querySelectorAll('th'));
625
+ let subHeaderIndex = 0;
626
+
627
+ firstRow.querySelectorAll('th').forEach((th) => {
628
+ const colspan = parseInt(th.getAttribute('colspan') || '1', 10);
629
+ const rowspan = parseInt(th.getAttribute('rowspan') || '1', 10);
630
+ const headerName = th.textContent.trim();
631
+
632
+ if (rowspan >= 2 || colspan === 1) {
633
+ // This header spans all rows - use it directly
634
+ headers.push(escapeCSVValue(headerName));
635
+ if (rowspan < 2) subHeaderIndex++;
636
+ } else {
637
+ // This header has sub-headers in the second row
638
+ for (let i = 0; i < colspan && subHeaderIndex < secondRowHeaders.length; i++) {
639
+ const subHeader = secondRowHeaders[subHeaderIndex]?.textContent.trim() || '';
640
+ headers.push(escapeCSVValue(`${headerName} - ${subHeader}`));
641
+ subHeaderIndex++;
642
+ }
643
+ }
644
+ });
645
+ }
646
+
647
+ csvRows.push(headers.join(','));
648
+ }
649
+
650
+ // Extract visible body rows
651
+ const tbody = table.querySelector('tbody');
652
+ if (tbody) {
653
+ const rows = tbody.querySelectorAll('tr');
654
+ rows.forEach((row) => {
655
+ // Skip hidden rows (filtered out) and the "no rows" message
656
+ if (row.style.display === 'none' || row.id === 'no-rows-message') return;
657
+
658
+ const cells = [];
659
+ row.querySelectorAll('td').forEach((td) => {
660
+ // Get the text content, handling lists and links
661
+ let value = '';
662
+ const list = td.querySelector('ul');
663
+ if (list) {
664
+ value = Array.from(list.querySelectorAll('li'))
665
+ .map((li) => li.textContent.trim())
666
+ .join('; ');
667
+ } else {
668
+ value = td.textContent.trim();
669
+ }
670
+ cells.push(escapeCSVValue(value));
671
+ });
672
+ csvRows.push(cells.join(','));
673
+ });
674
+ }
675
+
676
+ // Generate and download CSV
677
+ const csvContent = csvRows.join('\n');
678
+ const blob = new Blob(['' + csvContent], { type: 'text/csv;charset=utf-8;' });
679
+ const url = URL.createObjectURL(blob);
680
+ const link = document.createElement('a');
681
+
682
+ // Use the report title for the filename
683
+ const title = document.querySelector('.slds-text-heading_large span')?.textContent.trim() || 'report';
684
+ const filename = `${title.replace(/[^a-zA-Z0-9]/g, '_')}_export.csv`;
685
+
686
+ link.setAttribute('href', url);
687
+ link.setAttribute('download', filename);
688
+ link.style.display = 'none';
689
+ document.body.appendChild(link);
690
+ link.click();
691
+ document.body.removeChild(link);
692
+ URL.revokeObjectURL(url);
693
+ showExportSuccess(exportButton);
694
+ } catch (error) {
695
+ console.error('CSV export failed:', error);
696
+ showExportError(exportButton, 'Export failed');
697
+ }
698
+ }
699
+
700
+ /**
701
+ * Show success state on the export button briefly, then reset
702
+ */
703
+ function showExportSuccess(button) {
704
+ if (!button) return;
705
+ button.textContent = '✓ Exported';
706
+ button.style.backgroundColor = '#2e844a';
707
+ button.disabled = false;
708
+ setTimeout(() => {
709
+ button.innerHTML =
710
+ '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">' +
711
+ '<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>' +
712
+ '<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"/>' +
713
+ '</svg> Export CSV';
714
+ button.style.backgroundColor = '';
715
+ }, 2000);
716
+ }
717
+
718
+ /**
719
+ * Show error state on the export button briefly, then reset
720
+ */
721
+ function showExportError(button, message) {
722
+ if (!button) return;
723
+ button.textContent = message || 'Export failed';
724
+ button.style.backgroundColor = '#c23934';
725
+ button.disabled = false;
726
+ setTimeout(() => {
727
+ button.innerHTML =
728
+ '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">' +
729
+ '<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>' +
730
+ '<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"/>' +
731
+ '</svg> Export CSV';
732
+ button.style.backgroundColor = '';
733
+ }, 3000);
734
+ }
735
+
736
+ /**
737
+ * Escape a value for CSV format
738
+ * Wraps in quotes if it contains commas, quotes, or newlines
739
+ */
740
+ function escapeCSVValue(value) {
741
+ if (value == null) return '""';
742
+ const str = String(value);
743
+ if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {
744
+ return `"${str.replace(/"/g, '""')}"`;
745
+ }
746
+ return str;
747
+ }
189
748
 
190
749
  // Expose globally so HTML inline event handlers can access them
191
750
  window.toggleFilterDropdown = toggleFilterDropdown;
751
+ window.closeFilterDropdown = closeFilterDropdown;
752
+ window.closeAllFilterDropdowns = closeAllFilterDropdowns;
192
753
  window.filterAndSearchTable = filterAndSearchTable;
193
754
  window.toggleCtaSummaryPanel = toggleCtaSummaryPanel;
755
+ window.applyDynamicStickyColumns = applyDynamicStickyColumns;
756
+ window.exportTableToCSV = exportTableToCSV;