@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.
- package/README.md +165 -73
- package/lib/commands/omnistudio/migration/assess.d.ts +23 -15
- package/lib/commands/omnistudio/migration/assess.js +250 -89
- package/lib/commands/omnistudio/migration/assess.js.map +1 -1
- package/lib/commands/omnistudio/migration/clean.d.ts +13 -0
- package/lib/commands/omnistudio/migration/clean.js +162 -0
- package/lib/commands/omnistudio/migration/clean.js.map +1 -0
- package/lib/commands/omnistudio/migration/info.d.ts +10 -16
- package/lib/commands/omnistudio/migration/info.js +53 -35
- package/lib/commands/omnistudio/migration/info.js.map +1 -1
- package/lib/commands/omnistudio/migration/migrate.d.ts +78 -18
- package/lib/commands/omnistudio/migration/migrate.js +461 -175
- package/lib/commands/omnistudio/migration/migrate.js.map +1 -1
- package/lib/error/deploymentErrors.d.ts +15 -0
- package/lib/error/deploymentErrors.js +35 -0
- package/lib/error/deploymentErrors.js.map +1 -0
- package/lib/error/errorInterfaces.d.ts +5 -0
- package/lib/error/errorInterfaces.js +9 -1
- package/lib/error/errorInterfaces.js.map +1 -1
- package/lib/javascripts/reportGeneratorUtility.js +585 -22
- package/lib/migration/ApexNamespaceRegistry.d.ts +49 -0
- package/lib/migration/ApexNamespaceRegistry.js +130 -0
- package/lib/migration/ApexNamespaceRegistry.js.map +1 -0
- package/lib/migration/CustomCssRegistry.d.ts +117 -0
- package/lib/migration/CustomCssRegistry.js +234 -0
- package/lib/migration/CustomCssRegistry.js.map +1 -0
- package/lib/migration/NameMappingRegistry.d.ts +134 -0
- package/lib/migration/NameMappingRegistry.js +411 -0
- package/lib/migration/NameMappingRegistry.js.map +1 -0
- package/lib/migration/base.d.ts +8 -6
- package/lib/migration/base.js +25 -8
- package/lib/migration/base.js.map +1 -1
- package/lib/migration/customLabels.d.ts +70 -0
- package/lib/migration/customLabels.js +177 -0
- package/lib/migration/customLabels.js.map +1 -0
- package/lib/migration/dataraptor.d.ts +13 -0
- package/lib/migration/dataraptor.js +205 -80
- package/lib/migration/dataraptor.js.map +1 -1
- package/lib/migration/deployer.d.ts +14 -0
- package/lib/migration/deployer.js +105 -0
- package/lib/migration/deployer.js.map +1 -0
- package/lib/migration/flexcard.d.ts +256 -6
- package/lib/migration/flexcard.js +1808 -268
- package/lib/migration/flexcard.js.map +1 -1
- package/lib/migration/globalautonumber.d.ts +8 -8
- package/lib/migration/globalautonumber.js +49 -24
- package/lib/migration/globalautonumber.js.map +1 -1
- package/lib/migration/interfaces.d.ts +14 -0
- package/lib/migration/interfaces.js.map +1 -1
- package/lib/migration/metadataobjnamecheck.js.map +1 -1
- package/lib/migration/omniscript.d.ts +218 -4
- package/lib/migration/omniscript.js +1709 -247
- package/lib/migration/omniscript.js.map +1 -1
- package/lib/migration/omniscriptInstance.d.ts +90 -0
- package/lib/migration/omniscriptInstance.js +755 -0
- package/lib/migration/omniscriptInstance.js.map +1 -0
- package/lib/migration/postMigrate.d.ts +20 -4
- package/lib/migration/postMigrate.js +199 -12
- package/lib/migration/postMigrate.js.map +1 -1
- package/lib/migration/premigrate.d.ts +51 -0
- package/lib/migration/premigrate.js +325 -0
- package/lib/migration/premigrate.js.map +1 -0
- package/lib/migration/related/ApexMigration.d.ts +3 -0
- package/lib/migration/related/ApexMigration.js +222 -56
- package/lib/migration/related/ApexMigration.js.map +1 -1
- package/lib/migration/related/ExperienceSiteMigration.d.ts +30 -5
- package/lib/migration/related/ExperienceSiteMigration.js +263 -73
- package/lib/migration/related/ExperienceSiteMigration.js.map +1 -1
- package/lib/migration/related/FlexipageMigration.d.ts +5 -5
- package/lib/migration/related/FlexipageMigration.js +60 -38
- package/lib/migration/related/FlexipageMigration.js.map +1 -1
- package/lib/migration/related/LwcMigration.js +45 -26
- package/lib/migration/related/LwcMigration.js.map +1 -1
- package/lib/migration/related/OmnistudioRelatedObjectMigrationFacade.js +48 -32
- package/lib/migration/related/OmnistudioRelatedObjectMigrationFacade.js.map +1 -1
- package/lib/styles/reportGenerator.css +241 -16
- package/lib/templates/assessmentReport.template +78 -8
- package/lib/templates/dashboard.template +86 -57
- package/lib/templates/migrationReport.template +151 -0
- package/lib/utils/OmnistudioSettingsPrefManager.d.ts +14 -0
- package/lib/utils/OmnistudioSettingsPrefManager.js +112 -0
- package/lib/utils/OmnistudioSettingsPrefManager.js.map +1 -0
- package/lib/utils/XMLUtil.js +2 -1
- package/lib/utils/XMLUtil.js.map +1 -1
- package/lib/utils/apex/executor/AnonymousApexRunner.d.ts +1 -1
- package/lib/utils/apex/parser/apexparser.d.ts +8 -1
- package/lib/utils/apex/parser/apexparser.js +79 -13
- package/lib/utils/apex/parser/apexparser.js.map +1 -1
- package/lib/utils/config/ExistingRecordCleanupService.d.ts +30 -0
- package/lib/utils/config/ExistingRecordCleanupService.js +266 -0
- package/lib/utils/config/ExistingRecordCleanupService.js.map +1 -0
- package/lib/utils/config/OmniStudioMetadataCleanupService.d.ts +36 -0
- package/lib/utils/config/OmniStudioMetadataCleanupService.js +123 -0
- package/lib/utils/config/OmniStudioMetadataCleanupService.js.map +1 -0
- package/lib/utils/config/SpecialCharacterRecordCleanupService.d.ts +17 -0
- package/lib/utils/config/SpecialCharacterRecordCleanupService.js +186 -0
- package/lib/utils/config/SpecialCharacterRecordCleanupService.js.map +1 -0
- package/lib/utils/constants/documentRegistry.d.ts +9 -17
- package/lib/utils/constants/documentRegistry.js +9 -17
- package/lib/utils/constants/documentRegistry.js.map +1 -1
- package/lib/utils/constants/stringContants.d.ts +78 -0
- package/lib/utils/constants/stringContants.js +91 -4
- package/lib/utils/constants/stringContants.js.map +1 -1
- package/lib/utils/customLabels.d.ts +35 -0
- package/lib/utils/customLabels.js +100 -0
- package/lib/utils/customLabels.js.map +1 -0
- package/lib/utils/dataModelService.d.ts +18 -0
- package/lib/utils/dataModelService.js +72 -0
- package/lib/utils/dataModelService.js.map +1 -0
- package/lib/utils/file/fileUtil.d.ts +3 -1
- package/lib/utils/file/fileUtil.js +30 -13
- package/lib/utils/file/fileUtil.js.map +1 -1
- package/lib/utils/flexipage/flexiPageTransformer.js +119 -23
- package/lib/utils/flexipage/flexiPageTransformer.js.map +1 -1
- package/lib/utils/formula/FormulaUtil.d.ts +1 -1
- package/lib/utils/formula/FormulaUtil.js +17 -9
- package/lib/utils/formula/FormulaUtil.js.map +1 -1
- package/lib/utils/formula/Stack.js.map +1 -1
- package/lib/utils/generatePackageXml.d.ts +6 -2
- package/lib/utils/generatePackageXml.js +73 -33
- package/lib/utils/generatePackageXml.js.map +1 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/interfaces.d.ts +69 -8
- package/lib/utils/json/jsonutil.js.map +1 -1
- package/lib/utils/logger/fileLogger.js +17 -7
- package/lib/utils/logger/fileLogger.js.map +1 -1
- package/lib/utils/logger.d.ts +3 -3
- package/lib/utils/logger.js +10 -6
- package/lib/utils/logger.js.map +1 -1
- package/lib/utils/logging/debugtimer.js.map +1 -1
- package/lib/utils/lwcparser/fileutils/FileDiffUtil.js +30 -22
- package/lib/utils/lwcparser/fileutils/FileDiffUtil.js.map +1 -1
- package/lib/utils/lwcparser/fileutils/FileProcessorFactory.js.map +1 -1
- package/lib/utils/lwcparser/fileutils/HtmlFileProcessor.js.map +1 -1
- package/lib/utils/lwcparser/fileutils/JavascriptFileProcessor.js.map +1 -1
- package/lib/utils/lwcparser/fileutils/XmlFileProcessor.js.map +1 -1
- package/lib/utils/lwcparser/htmlParser/HTMLParser.js +29 -10
- package/lib/utils/lwcparser/htmlParser/HTMLParser.js.map +1 -1
- package/lib/utils/lwcparser/jsParser/JavaScriptParser.js +29 -11
- package/lib/utils/lwcparser/jsParser/JavaScriptParser.js.map +1 -1
- package/lib/utils/lwcparser/xmlParser/XmlParser.js +19 -8
- package/lib/utils/lwcparser/xmlParser/XmlParser.js.map +1 -1
- package/lib/utils/net/index.d.ts +5 -0
- package/lib/utils/net/index.js +40 -2
- package/lib/utils/net/index.js.map +1 -1
- package/lib/utils/omniscriptPackageManager.d.ts +31 -0
- package/lib/utils/omniscriptPackageManager.js +215 -0
- package/lib/utils/omniscriptPackageManager.js.map +1 -0
- package/lib/utils/orgPreferences.d.ts +25 -0
- package/lib/utils/orgPreferences.js +124 -8
- package/lib/utils/orgPreferences.js.map +1 -1
- package/lib/utils/orgUtils/index.d.ts +12 -5
- package/lib/utils/orgUtils/index.js +52 -22
- package/lib/utils/orgUtils/index.js.map +1 -1
- package/lib/utils/projectPathUtil.d.ts +1 -1
- package/lib/utils/projectPathUtil.js +27 -10
- package/lib/utils/projectPathUtil.js.map +1 -1
- package/lib/utils/promptUtil.d.ts +11 -1
- package/lib/utils/promptUtil.js +92 -0
- package/lib/utils/promptUtil.js.map +1 -1
- package/lib/utils/query/index.d.ts +1 -0
- package/lib/utils/query/index.js +18 -1
- package/lib/utils/query/index.js.map +1 -1
- package/lib/utils/recordPrioritization.d.ts +44 -0
- package/lib/utils/recordPrioritization.js +69 -0
- package/lib/utils/recordPrioritization.js.map +1 -0
- package/lib/utils/reportGenerator/reportInterfaces.d.ts +12 -0
- package/lib/utils/reportGenerator/reportUtil.d.ts +6 -1
- package/lib/utils/reportGenerator/reportUtil.js +22 -7
- package/lib/utils/reportGenerator/reportUtil.js.map +1 -1
- package/lib/utils/resultsbuilder/ApexAssessmentReporter.d.ts +1 -0
- package/lib/utils/resultsbuilder/ApexAssessmentReporter.js +40 -17
- package/lib/utils/resultsbuilder/ApexAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.d.ts +13 -0
- package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.js +179 -0
- package/lib/utils/resultsbuilder/CustomLabelAssessmentReporter.js.map +1 -0
- package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.d.ts +27 -0
- package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.js +262 -0
- package/lib/utils/resultsbuilder/CustomLabelMigrationReporter.js.map +1 -0
- package/lib/utils/resultsbuilder/DRAssessmentReporter.js +38 -70
- package/lib/utils/resultsbuilder/DRAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.d.ts +14 -0
- package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.js +143 -0
- package/lib/utils/resultsbuilder/ExperienceSiteAssessmentReporter.js.map +1 -0
- package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js +46 -85
- package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.d.ts +1 -0
- package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.js +37 -19
- package/lib/utils/resultsbuilder/FlexipageAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/GlobalAutoNumberAssessmentReporter.js +22 -14
- package/lib/utils/resultsbuilder/GlobalAutoNumberAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/IPAssessmentReporter.js +38 -71
- package/lib/utils/resultsbuilder/IPAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/LWCAssessmentReporter.d.ts +14 -0
- package/lib/utils/resultsbuilder/LWCAssessmentReporter.js +143 -139
- package/lib/utils/resultsbuilder/LWCAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/OSAssessmentReporter.js +41 -88
- package/lib/utils/resultsbuilder/OSAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.d.ts +12 -0
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js +109 -0
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js.map +1 -0
- package/lib/utils/resultsbuilder/assessmentReporter.d.ts +16 -6
- package/lib/utils/resultsbuilder/assessmentReporter.js +96 -152
- package/lib/utils/resultsbuilder/assessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.d.ts +104 -0
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js +380 -0
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js.map +1 -0
- package/lib/utils/resultsbuilder/index.d.ts +37 -1
- package/lib/utils/resultsbuilder/index.js +582 -151
- package/lib/utils/resultsbuilder/index.js.map +1 -1
- package/lib/utils/resultsbuilder/reportingHelper.d.ts +2 -7
- package/lib/utils/resultsbuilder/reportingHelper.js +0 -43
- package/lib/utils/resultsbuilder/reportingHelper.js.map +1 -1
- package/lib/utils/sfcli/project/sfProject.d.ts +29 -0
- package/lib/utils/sfcli/project/sfProject.js +220 -2
- package/lib/utils/sfcli/project/sfProject.js.map +1 -1
- package/lib/utils/shell/cli.js +20 -14
- package/lib/utils/shell/cli.js.map +1 -1
- package/lib/utils/storageUtil.d.ts +14 -1
- package/lib/utils/storageUtil.js +31 -1
- package/lib/utils/storageUtil.js.map +1 -1
- package/lib/utils/stringUtils.d.ts +24 -0
- package/lib/utils/stringUtils.js +76 -9
- package/lib/utils/stringUtils.js.map +1 -1
- package/lib/utils/templateParser/__tests__/test.js +1 -2
- package/lib/utils/templateParser/__tests__/test.js.map +1 -1
- package/lib/utils/templateParser/generate.d.ts +1 -1
- package/lib/utils/templateParser/generate.js.map +1 -1
- package/lib/utils/templateParser/model/elementNode.d.ts +2 -2
- package/lib/utils/templateParser/model/elementNode.js +11 -2
- package/lib/utils/templateParser/model/elementNode.js.map +1 -1
- package/lib/utils/templateParser/model/nodeTypes.js +1 -1
- package/lib/utils/templateParser/model/nodeTypes.js.map +1 -1
- package/lib/utils/templateParser/util.d.ts +2 -2
- package/lib/utils/templateParser/util.js.map +1 -1
- package/lib/utils/validatorService.d.ts +14 -0
- package/lib/utils/validatorService.js +136 -0
- package/lib/utils/validatorService.js.map +1 -0
- package/messages/assess.json +220 -103
- package/messages/clean.json +40 -0
- package/messages/info.json +2 -1
- package/messages/migrate.json +314 -102
- package/oclif.manifest.json +1 -1
- package/package.json +49 -13
- package/lib/commands/basecommand.d.ts +0 -8
- package/lib/commands/basecommand.js +0 -13
- package/lib/commands/basecommand.js.map +0 -1
- package/lib/utils/OmniGlobalAutoNumberPrefManager.d.ts +0 -40
- package/lib/utils/OmniGlobalAutoNumberPrefManager.js +0 -65
- 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
|
|
15
|
-
const
|
|
16
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
180
|
-
|
|
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
|
-
|
|
184
|
-
document.
|
|
185
|
-
if (
|
|
186
|
-
|
|
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;
|