diff --git a/docs/changelog/assets/css/app.css b/docs/changelog/assets/css/app.css index 31de425f3..f90987681 100644 --- a/docs/changelog/assets/css/app.css +++ b/docs/changelog/assets/css/app.css @@ -63,23 +63,28 @@ body { top: 0; background-color: var(--color-webex-blue); color: white; - padding: 1.25rem; /* 20px */ + padding: 1.25rem; + /* 20px */ margin: 0; - text-align: left; /* Align the title text to the left */ + text-align: left; + /* Align the title text to the left */ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); font-size: 1.5rem; - z-index: 1000; /* Ensure the header is above other content */ + z-index: 1000; + /* Ensure the header is above other content */ } #body { flex: 1; - padding: 1.25rem; /* 20px */ + padding: 1.25rem; + /* 20px */ } #footer { background-color: var(--color-background); text-align: center; - padding: 0.625rem; /* 10px */ + padding: 0.625rem; + /* 10px */ box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2); } @@ -96,12 +101,14 @@ body { /* Rest of the CSS for form and results remains the same */ form#search-form { - padding: 0.625rem; /* 10px */ + padding: 0.625rem; + /* 10px */ } label { display: block; - margin-bottom: 0.5rem; /* 8px */ + margin-bottom: 0.5rem; + /* 8px */ color: #333; } @@ -118,11 +125,14 @@ select { button { background-color: var(--color-webex-blue); color: white; - padding: 0.625rem 1.25rem; /* 10px 20px */ + padding: 0.625rem 1.25rem; + /* 10px 20px */ border: none; - border-radius: 0.25rem; /* 4px */ + border-radius: 0.25rem; + /* 4px */ cursor: pointer; - font-size: 1rem; /* 16px */ + font-size: 1rem; + /* 16px */ transition: background-color 0.3s; } @@ -143,7 +153,8 @@ td { th, td { - padding: 0.625rem; /* 10px */ + padding: 0.625rem; + /* 10px */ text-align: left; } @@ -153,79 +164,103 @@ th { .search-container { background: white; - border-radius: 0.5rem; /* 8px */ + border-radius: 0.5rem; + /* 8px */ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); margin: auto; width: 100%; - padding: 1.25rem; /* 20px */ - box-sizing: border-box; /* Include padding in the width calculation */ + padding: 1.25rem; + /* 20px */ + box-sizing: border-box; + /* Include padding in the width calculation */ } .form-row { display: flex; flex-wrap: wrap; - margin-bottom: 1.25rem; /* 20px */ + margin-bottom: 1.25rem; + /* 20px */ } .form-group { - flex: 1 1 25%; /* Each form group will take up half the width of the form-row */ - padding: 0 0.625rem; /* 10px */ + flex: 1 1 25%; + /* Each form group will take up half the width of the form-row */ + padding: 0 0.625rem; + /* 10px */ box-sizing: border-box; } .full-width { - margin: 0 0.625rem; /* 10px */ + margin: 0 0.625rem; + /* 10px */ } .results-container { width: 100%; background: white; - padding: 1.25rem; /* 20px */ - border-radius: 0.5rem; /* 8px */ + padding: 1.25rem; + /* 20px */ + border-radius: 0.5rem; + /* 8px */ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); margin: auto; - margin-top: 1.25rem; /* 20px */ + margin-top: 1.25rem; + /* 20px */ } /* Responsive styles */ @media (max-width: 48rem) { + /* 768px */ .form-group { - flex: 1 1 100%; /* Each form group will take up the full width on smaller screens */ - padding: 0 0.625rem; /* 10px */ + flex: 1 1 100%; + /* Each form group will take up the full width on smaller screens */ + padding: 0 0.625rem; + /* 10px */ } } .changelog-item { - padding-bottom: 1.25rem; /* 20px */ - margin-bottom: 1.25rem; /* 20px */ - border-bottom: 0.1875rem solid #e4e5e6; /* 3px */ + padding-bottom: 1.25rem; + /* 20px */ + margin-bottom: 1.25rem; + /* 20px */ + border-bottom: 0.1875rem solid #e4e5e6; + /* 3px */ } .changelog-item h2, .changelog-item h3 { color: #333; - margin-bottom: 0.625rem; /* 10px */ + margin-bottom: 0.625rem; + /* 10px */ } .changelog-item .commits { - margin-top: 1.25rem; /* 20px */ - margin-bottom: 1.25rem; /* 20px */ + margin-top: 1.25rem; + /* 20px */ + margin-bottom: 1.25rem; + /* 20px */ } .changelog-item .commits ul { - margin-top: 0.625rem; /* 10px */ + margin-top: 0.625rem; + /* 10px */ list-style-type: none; padding: 0; - max-height: 12.5rem; /* 200px */ + max-height: 12.5rem; + /* 200px */ overflow: scroll; } .changelog-item .commits ul li { background-color: #eee; - margin-bottom: 0.3125rem; /* 5px */ - padding: 0.625rem; /* 10px */ - border-radius: 0.1875rem; /* 3px */ + margin-bottom: 0.3125rem; + /* 5px */ + padding: 0.625rem; + /* 10px */ + border-radius: 0.1875rem; + /* 3px */ word-wrap: break-word; } @@ -261,7 +296,8 @@ th { .changelog-item th, .changelog-item td { - padding: 0.625rem; /* 10px */ + padding: 0.625rem; + /* 10px */ text-align: left; } @@ -280,19 +316,23 @@ th { .copy-button { display: inline; position: absolute; - margin-left: 0.3125rem; /* 5px */ + margin-left: 0.3125rem; + /* 5px */ cursor: pointer; right: 0; } .copy-button img { - width: 1.25rem; /* 20px */ + width: 1.25rem; + /* 20px */ height: auto; - margin-right: 0.3125rem; /* 5px */ + margin-right: 0.3125rem; + /* 5px */ } footer { - margin: 1.25rem 0; /* 20px 0px */ + margin: 1.25rem 0; + /* 20px 0px */ } footer .copyright { @@ -302,10 +342,13 @@ footer .copyright { .alert-info { background-color: #f0f9ff; - border-left: 0.375rem solid var(--color-webex-blue); /* 6px */ + border-left: 0.375rem solid var(--color-webex-blue); + /* 6px */ color: #333; - padding: 0.625rem; /* 10px */ - margin-bottom: 1.25rem; /* 20px */ + padding: 0.625rem; + /* 10px */ + margin-bottom: 1.25rem; + /* 20px */ } .alert-info p.note { @@ -326,8 +369,10 @@ footer .copyright { /* Mode Toggle Buttons */ .mode-toggle { display: flex; - gap: 0.625rem; /* 10px */ - margin-bottom: 1.25rem; /* 20px */ + gap: 0.625rem; + /* 10px */ + margin-bottom: 1.25rem; + /* 20px */ } .mode-toggle button { @@ -338,7 +383,8 @@ footer .copyright { color: var(--color-webex-blue); cursor: pointer; transition: all 0.3s; - border-radius: 0.25rem; /* 4px */ + border-radius: 0.25rem; + /* 4px */ font-weight: 500; } @@ -356,9 +402,97 @@ footer .copyright { display: none !important; } +/* Version Comparison: make form box full width (equal to Note box above) and expand height */ +#changelog-form-row.comparison-view-active #comparison-form-column { + width: 100% !important; + max-width: 100% !important; + flex: 0 0 100%; +} + +#changelog-form-row.comparison-view-active #comparison-helper-column { + display: none; +} + +#changelog-form-row.comparison-view-active #comparison-form-column .search-container { + min-height: 20rem; + padding: 1.75rem 1.5rem; + overflow: visible; +} + +#changelog-form-row.comparison-view-active #comparison-form-column { + overflow: visible; +} + +/* Let the package dropdown list show all options (avoid clipping) */ +#comparison-form #comparison-package-row { + overflow: visible; +} + +#comparison-form select#comparison-package-select { + max-height: none; +} + +#comparison-form-column select { + position: relative; + z-index: 10; +} + +#comparison-form-column select:focus { + z-index: 11; +} + +/* Comparison form: package first, version row with clear buttons */ +#comparison-form .comparison-package-full-width { + flex: 1 1 100%; +} + +#comparison-form .required-asterisk { + color: var(--color-danger); +} + +#comparison-form .select-with-clear { + display: flex; + align-items: center; + gap: 0.5rem; +} + +#comparison-form .select-with-clear select.full-width { + flex: 1; + margin: 0; +} + +.btn-clear-circle { + flex-shrink: 0; + width: 2.25rem; + height: 2.25rem; + padding: 0; + border-radius: 50%; + border: 1px solid #ccc; + background-color: #f5f5f5; + color: var(--color-danger); + font-size: 1.5rem; + line-height: 1; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s, color 0.2s; +} + +.btn-clear-circle:hover:not(:disabled) { + background-color: #ffe0e0; + color: var(--color-danger-hover); +} + +.btn-clear-circle:disabled { + opacity: 0.5; + cursor: not-allowed; +} + /* Comparison Form */ #comparison-form { - margin-top: 1.25rem; /* 20px */ + margin-top: 1.25rem; + /* 20px */ } /* Comparison Results Table */ @@ -376,7 +510,8 @@ footer .copyright { width: 100%; border-collapse: collapse; margin-top: 0; - font-size: 0.875rem; /* 14px */ + font-size: 0.875rem; + /* 14px */ } .comparison-table th, @@ -405,36 +540,48 @@ footer .copyright { /* Color Coding for Changes */ .comparison-table tr.version-changed { - background-color: #fff3cd; /* Yellow - version changed */ - border-left: 0.25rem solid #ffc107; /* 4px */ + background-color: #fff3cd; + /* Yellow - version changed */ + border-left: 0.25rem solid #ffc107; + /* 4px */ } .comparison-table tr.only-in-a { - background-color: #f8d7da; /* Red - removed in B */ - border-left: 0.25rem solid #dc3545; /* 4px */ + background-color: #f8d7da; + /* Red - removed in B */ + border-left: 0.25rem solid #dc3545; + /* 4px */ } .comparison-table tr.only-in-b { - background-color: #d4edda; /* Green - added in B */ - border-left: 0.25rem solid #28a745; /* 4px */ + background-color: #d4edda; + /* Green - added in B */ + border-left: 0.25rem solid #28a745; + /* 4px */ } .comparison-table tr.unchanged { - background-color: #ffffff; /* White - no change */ + background-color: #ffffff; + /* White - no change */ } /* Comparison Summary */ .comparison-summary { background: linear-gradient(135deg, #e7f3ff 0%, #f0f9ff 100%); - padding: 1.5625rem; /* 25px */ - border-radius: 0.5rem; /* 8px */ - margin-bottom: 1.25rem; /* 20px */ - border-left: 0.3125rem solid var(--color-webex-blue); /* 5px */ + padding: 1.5625rem; + /* 25px */ + border-radius: 0.5rem; + /* 8px */ + margin-bottom: 1.25rem; + /* 20px */ + border-left: 0.3125rem solid var(--color-webex-blue); + /* 5px */ } .comparison-summary h3 { margin-top: 0; - margin-bottom: 0.9375rem; /* 15px */ + margin-bottom: 0.9375rem; + /* 15px */ color: var(--color-webex-blue); font-size: 1.5em; } @@ -442,8 +589,10 @@ footer .copyright { .summary-stats { display: flex; flex-wrap: wrap; - gap: 0.9375rem; /* 15px */ - margin-top: 0.9375rem; /* 15px */ + gap: 0.9375rem; + /* 15px */ + margin-top: 0.9375rem; + /* 15px */ } .stat-item { @@ -455,22 +604,26 @@ footer .copyright { } .stat-item.changed { - border-left: 0.25rem solid #ffc107; /* 4px */ + border-left: 0.25rem solid #ffc107; + /* 4px */ } .stat-item.unchanged { - border-left: 0.25rem solid #6c757d; /* 4px */ + border-left: 0.25rem solid #6c757d; + /* 4px */ } .stat-item.added { - border-left: 0.25rem solid #28a745; /* 4px */ + border-left: 0.25rem solid #28a745; + /* 4px */ } .stat-item.removed { - border-left: 0.25rem solid #dc3545; /* 4px */ + border-left: 0.25rem solid #dc3545; + /* 4px */ } .stat-item strong { font-size: 1.2em; color: #333; -} +} \ No newline at end of file diff --git a/docs/changelog/assets/js/app.js b/docs/changelog/assets/js/app.js index 6368c66d1..98bcc8286 100644 --- a/docs/changelog/assets/js/app.js +++ b/docs/changelog/assets/js/app.js @@ -50,6 +50,9 @@ const compareButton = document.getElementById('compare-button'); const clearComparisonButton = document.getElementById('clear-comparison-button'); const copyComparisonLinkBtn = document.getElementById('copy-comparison-link'); const comparisonHelper = document.getElementById('comparison-helper'); +const clearVersionABtn = document.getElementById('clear-version-a-btn'); +const clearVersionBBtn = document.getElementById('clear-version-b-btn'); +const changelogFormRow = document.getElementById('changelog-form-row'); // DOM elements - Shared const helperSection = document.getElementById('helper-section'); @@ -71,8 +74,8 @@ const uiVisibilityStates = { hidden: ['comparisonForm', 'comparisonResults', 'comparisonHelper'], }, comparison: { - visible: ['comparisonForm', 'comparisonHelper'], - hidden: ['searchForm', 'searchResults', 'helperSection', 'comparisonResults'], + visible: ['comparisonForm'], + hidden: ['searchForm', 'searchResults', 'helperSection', 'comparisonResults', 'comparisonHelper'], }, }; @@ -95,6 +98,10 @@ function updateUIVisibility(viewState) { const el = uiViewElements[key]; if (el) el.classList.remove('hide'); }); + if (changelogFormRow) { + if (viewState === 'comparison') changelogFormRow.classList.add('comparison-view-active'); + else changelogFormRow.classList.remove('comparison-view-active'); + } } // Initialize UI to search view on load (single source of truth for visibility) @@ -192,6 +199,43 @@ const populateFormFieldsFromURL = async () => { } }; +/** + * Return the latest version key from versionPaths (by semver). + */ +const getLatestVersionKey = () => { + const keys = Object.keys(versionPaths); + if (keys.length === 0) return null; + keys.sort((a, b) => { + const pa = a.split('.').map(Number); + const pb = b.split('.').map(Number); + for (let i = 0; i < Math.max(pa.length, pb.length); i++) { + const na = pa[i] || 0; + const nb = pb[i] || 0; + if (na !== nb) return nb - na; // descending: latest first + } + return 0; + }); + return keys[0]; +}; + +/** + * Fetch all version changelogs and return merged package list (union) so dropdown shows every package. + */ +const fetchMergedChangelogPackages = async () => { + const paths = Object.values(versionPaths); + if (paths.length === 0) return {}; + const results = await Promise.all(paths.map((p) => fetch(p).then((r) => r.json()).catch(() => ({})))); + const merged = {}; + results.forEach((changelog) => { + if (changelog && typeof changelog === 'object') { + Object.keys(changelog).forEach((pkg) => { + if (!merged[pkg]) merged[pkg] = changelog[pkg]; + }); + } + }); + return merged; +}; + const populateVersions = async () => { try { const response = await fetch('logs/main.json'); @@ -779,10 +823,6 @@ const displayComparison = (versionA, versionB, comparisonData) => { } else { console.warn('Copy link button not found in DOM'); } - if (comparisonHelper) { - comparisonHelper.classList.remove('hide'); - } - // Scroll to results smoothly setTimeout(() => { comparisonResults.scrollIntoView({behavior: 'smooth', block: 'start'}); @@ -859,11 +899,9 @@ const handleComparisonURLParams = async () => { * @param {string} versionA - Base version (optional) * @param {string} versionB - Target version (optional) */ -const switchToComparisonMode = (versionA = null, versionB = null) => { - // Update mode +const switchToComparisonMode = async (versionA = null, versionB = null) => { comparisonMode = true; - // Update button states if (comparisonViewBtn && singleViewBtn) { comparisonViewBtn.classList.add('active', 'btn-primary'); comparisonViewBtn.classList.remove('btn-default'); @@ -871,21 +909,35 @@ const switchToComparisonMode = (versionA = null, versionB = null) => { singleViewBtn.classList.add('btn-default'); } - // Update form visibility (centralized view state) updateUIVisibility('comparison'); - // Hide package-level comparison section in version comparison mode if (packageLevelSection) packageLevelSection.classList.add('hide'); - // Populate version dropdowns if (versionSelectDropdown && versionSelectDropdown.innerHTML) { const options = versionSelectDropdown.innerHTML; if (versionASelect) versionASelect.innerHTML = options; if (versionBSelect) versionBSelect.innerHTML = options; } - // Set selected versions if provided + try { + const changelog = await fetchMergedChangelogPackages(); + populateComparisonPackagesFromChangelog(changelog); + } catch (e) { + console.error('Error loading packages for comparison:', e); + populateComparisonPackagesFromChangelog({}); + } + if (versionA && versionASelect) versionASelect.value = versionA; if (versionB && versionBSelect) versionBSelect.value = versionB; + + if (!versionA && !versionB) { + resetComparisonSelections(); + if (compareButton) compareButton.disabled = true; + } else { + versionASelect.disabled = false; + versionBSelect.disabled = false; + if (clearVersionABtn) clearVersionABtn.disabled = false; + if (clearVersionBBtn) clearVersionBBtn.disabled = false; + } }; /* ============================================ @@ -961,9 +1013,7 @@ const compareAndRenderPackageVersions = (packageName, versionASpecific, versionB comparisonData.versionB ); - // Show copy link button and helper if (copyComparisonLinkBtn) copyComparisonLinkBtn.classList.remove('hide'); - if (comparisonHelper) comparisonHelper.classList.remove('hide'); // Scroll to results setTimeout(() => { @@ -980,6 +1030,28 @@ const compareAndRenderPackageVersions = (packageName, versionASpecific, versionB } } }; +/** + * Populate comparison package dropdown from a changelog. + * Always includes @webex/widgets and @webex/cc-widgets first, then separator, then rest from changelog alphabetically. + */ +const populateComparisonPackagesFromChangelog = (changelog) => { + if (!comparisonPackageSelect) return; + const specialPackagesAlways = ['@webex/widgets', '@webex/cc-widgets']; + const allPackages = Object.keys(changelog || {}); + const otherPackages = allPackages.filter((pkg) => !specialPackagesAlways.includes(pkg)).sort(); + const sortedPackages = ['separator', ...specialPackagesAlways, 'separator', ...otherPackages]; + + let optionsHtml = ''; + sortedPackages.forEach((packageName) => { + if (packageName === 'separator') { + optionsHtml += ``; + return; + } + optionsHtml += ``; + }); + comparisonPackageSelect.innerHTML = optionsHtml; +}; + /** * Populate the package dropdown with union of packages from both versions * @param {Object} changelogA - Changelog for base version @@ -996,7 +1068,7 @@ const populateUnionPackages = (changelogA, changelogB) => { return; } - let optionsHtml = ''; + let optionsHtml = ''; allPackages.forEach((pkg) => { optionsHtml += ``; }); @@ -1024,11 +1096,13 @@ const populatePrereleaseVersions = (packageName, changelog, selectId, stableVers return; } - // Check if package exists in this changelog (it might not for union packages) + // If package not in this changelog, show the selected stable version as the only option (so user can still compare) if (!changelog[packageName]) { - if (versionSelect) { - versionSelect.innerHTML = ''; - versionSelect.disabled = true; + if (versionSelect && stableVersion) { + let optionsHtml = ''; + optionsHtml += ``; + versionSelect.innerHTML = optionsHtml; + versionSelect.disabled = false; } return; } @@ -1130,13 +1204,22 @@ const populateComparisonVersions = () => { }; /** - * Reset comparison form selections + * Reset comparison form selections and disable version/clear controls until package is selected */ const resetComparisonSelections = () => { if (comparisonPackageSelect) comparisonPackageSelect.value = ''; if (versionAPrereleaseSelect) versionAPrereleaseSelect.value = ''; if (versionBPrereleaseSelect) versionBPrereleaseSelect.value = ''; - if (comparisonPackageRow) comparisonPackageRow.style.display = 'none'; + if (versionASelect) { + versionASelect.value = ''; + versionASelect.disabled = true; + } + if (versionBSelect) { + versionBSelect.value = ''; + versionBSelect.disabled = true; + } + if (clearVersionABtn) clearVersionABtn.disabled = true; + if (clearVersionBBtn) clearVersionBBtn.disabled = true; if (prereleaseRow) prereleaseRow.style.display = 'none'; }; @@ -1144,8 +1227,14 @@ const resetComparisonSelections = () => { * Clear all comparison form inputs and state */ const clearComparisonForm = () => { - if (versionASelect) versionASelect.value = ''; - if (versionBSelect) versionBSelect.value = ''; + if (versionASelect) { + versionASelect.value = ''; + versionASelect.disabled = true; + } + if (versionBSelect) { + versionBSelect.value = ''; + versionBSelect.disabled = true; + } resetComparisonSelections(); if (comparisonResults) comparisonResults.classList.add('hide'); @@ -1153,7 +1242,7 @@ const clearComparisonForm = () => { if (copyComparisonLinkBtn) copyComparisonLinkBtn.classList.add('hide'); if (comparisonHelper) comparisonHelper.classList.add('hide'); - if (compareButton) compareButton.disabled = false; + if (compareButton) compareButton.disabled = true; }; /** @@ -1177,27 +1266,26 @@ const clearComparisonURLParams = () => { }; /** - * Check and update comparison button state based on form selections + * Check and update comparison button state based on form selections. + * Compare enables only when: package + base version + target version + both pre-release selections. */ const updateCompareButtonState = () => { if (!compareButton) return; const selectedPackage = comparisonPackageSelect ? comparisonPackageSelect.value : null; + const baseVersion = versionASelect ? versionASelect.value : null; + const targetVersion = versionBSelect ? versionBSelect.value : null; const versionASpecific = versionAPrereleaseSelect ? versionAPrereleaseSelect.value : null; const versionBSpecific = versionBPrereleaseSelect ? versionBPrereleaseSelect.value : null; const prereleaseRowVisible = prereleaseRow && prereleaseRow.style.display !== 'none'; - if (selectedPackage) { - // Package selected - require at least one pre-release version - if (!prereleaseRowVisible || (!versionASpecific && !versionBSpecific)) { - compareButton.disabled = true; - } else { - compareButton.disabled = false; - } - } else { - // No package selected - enable for full version comparison - compareButton.disabled = false; - } + const hasAll = + selectedPackage && + baseVersion && + targetVersion && + (!prereleaseRowVisible || (versionASpecific && versionBSpecific)); + + compareButton.disabled = !hasAll; }; /** @@ -1213,65 +1301,112 @@ const updatePrereleaseLabels = () => { }; /** - * Handle stable version changes - fetch changelogs and populate packages + * Handle stable version (base/target) change - fetch changelogs and populate pre-release dropdowns when package selected */ const handleStableVersionChange = async () => { - console.log('🟢 handleStableVersionChange FIRED'); const stableA = versionASelect.value; const stableB = versionBSelect.value; + const selectedPackage = comparisonPackageSelect ? comparisonPackageSelect.value : ''; - resetComparisonSelections(); - updateCompareButtonState(); + if (versionAPrereleaseSelect) { + versionAPrereleaseSelect.value = ''; + versionAPrereleaseSelect.disabled = true; + } + if (versionBPrereleaseSelect) { + versionBPrereleaseSelect.value = ''; + versionBPrereleaseSelect.disabled = true; + } - if (stableA && stableB) { - try { - const [changelogA, changelogB] = await Promise.all([ - fetch(versionPaths[stableA]).then((res) => res.json()), - fetch(versionPaths[stableB]).then((res) => res.json()), - ]); - - comparisonState.update(changelogA, changelogB, stableA, stableB); - populateUnionPackages(changelogA, changelogB); - updateCompareButtonState(); - } catch (error) { - console.error('Error loading changelogs:', error); - alert('Error loading version data. Please try again.'); + try { + if (stableA) { + const changelogA = await fetch(versionPaths[stableA]).then((r) => r.json()); + comparisonState.cachedChangelogA = changelogA; + comparisonState.currentStableA = stableA; + if (selectedPackage) { + populatePrereleaseVersions( + selectedPackage, + changelogA, + 'version-a-prerelease-select', + stableA + ); + } else if (versionAPrereleaseSelect) { + versionAPrereleaseSelect.innerHTML = ''; + } + } else if (versionAPrereleaseSelect) { + versionAPrereleaseSelect.innerHTML = ''; + } + if (stableB) { + const changelogB = await fetch(versionPaths[stableB]).then((r) => r.json()); + comparisonState.cachedChangelogB = changelogB; + comparisonState.currentStableB = stableB; + if (selectedPackage) { + populatePrereleaseVersions( + selectedPackage, + changelogB, + 'version-b-prerelease-select', + stableB + ); + } else if (versionBPrereleaseSelect) { + versionBPrereleaseSelect.innerHTML = ''; + } + } else if (versionBPrereleaseSelect) { + versionBPrereleaseSelect.innerHTML = ''; } + if (prereleaseRow) updatePrereleaseLabels(); + + // After both base and target are selected, disable version dropdowns so user picks pre-release only + if (stableA && stableB && selectedPackage) { + versionASelect.disabled = true; + versionBSelect.disabled = true; + } + } catch (error) { + console.error('Error loading changelogs:', error); + alert('Error loading version data. Please try again.'); } + updateCompareButtonState(); }; /** - * Handle package selection - populate pre-release versions + * Handle package selection - enable version dropdowns and clear buttons, show pre-release row */ const handlePackageChange = () => { - console.log('🟢 handlePackageChange FIRED'); - const selectedPackage = comparisonPackageSelect.value; + const selectedPackage = comparisonPackageSelect ? comparisonPackageSelect.value : ''; - if (versionAPrereleaseSelect) versionAPrereleaseSelect.value = ''; - if (versionBPrereleaseSelect) versionBPrereleaseSelect.value = ''; + if (!selectedPackage) { + resetComparisonSelections(); + if (compareButton) compareButton.disabled = true; + return; + } + + versionASelect.disabled = false; + versionBSelect.disabled = false; + if (clearVersionABtn) clearVersionABtn.disabled = false; + if (clearVersionBBtn) clearVersionBBtn.disabled = false; + if (prereleaseRow) prereleaseRow.style.display = 'flex'; - if (selectedPackage && comparisonState.cachedChangelogA && comparisonState.cachedChangelogB) { + if (versionASelect.value && comparisonState.cachedChangelogA) { populatePrereleaseVersions( selectedPackage, comparisonState.cachedChangelogA, 'version-a-prerelease-select', comparisonState.currentStableA ); + } else if (versionAPrereleaseSelect) { + versionAPrereleaseSelect.innerHTML = ''; + versionAPrereleaseSelect.disabled = true; + } + if (versionBSelect.value && comparisonState.cachedChangelogB) { populatePrereleaseVersions( selectedPackage, comparisonState.cachedChangelogB, 'version-b-prerelease-select', comparisonState.currentStableB ); - - if (prereleaseRow) { - prereleaseRow.style.display = 'flex'; - updatePrereleaseLabels(); - } - } else { - if (prereleaseRow) prereleaseRow.style.display = 'none'; + } else if (versionBPrereleaseSelect) { + versionBPrereleaseSelect.innerHTML = ''; + versionBPrereleaseSelect.disabled = true; } - + if (prereleaseRow) updatePrereleaseLabels(); updateCompareButtonState(); }; @@ -1297,41 +1432,49 @@ const switchToSingleViewMode = () => { /** * Switch to comparison view mode */ -const switchToComparisonViewMode = () => { - console.log('🔵 Switching to COMPARISON VIEW mode'); +const switchToComparisonViewMode = async () => { comparisonMode = true; - // Update button styles comparisonViewBtn.classList.add('active', 'btn-primary'); comparisonViewBtn.classList.remove('btn-default'); singleViewBtn.classList.remove('active', 'btn-primary'); singleViewBtn.classList.add('btn-default'); - // Toggle visibility (centralized view state) updateUIVisibility('comparison'); populateComparisonVersions(); + try { + const changelog = await fetchMergedChangelogPackages(); + populateComparisonPackagesFromChangelog(changelog); + } catch (e) { + console.error('Error loading packages for comparison:', e); + populateComparisonPackagesFromChangelog({}); + } + resetComparisonSelections(); + if (compareButton) compareButton.disabled = true; }; /** - * Validate comparison form inputs + * Validate comparison form inputs (package and both versions required) */ const validateComparisonInputs = (stableA, stableB, selectedPackage, versionASpecific, versionBSpecific) => { + if (!selectedPackage) { + alert('Please select a package'); + return false; + } if (!stableA || !stableB) { - alert('Please select both stable versions'); + alert('Please select both base and target stable versions'); return false; } - - if (selectedPackage && !versionASpecific && !versionBSpecific) { - alert('Please select at least one pre-release version, or leave package empty for full version comparison'); + if (!versionASpecific || !versionBSpecific) { + alert('Please select pre-release (or stable) for both base and target'); return false; } - return true; }; /** - * Handle comparison form submission + * Handle comparison form submission (package-level only) */ const handleComparisonSubmit = (event) => { event.preventDefault(); @@ -1346,25 +1489,16 @@ const handleComparisonSubmit = (event) => { return; } - if (selectedPackage && (versionASpecific || versionBSpecific)) { - // Package-level comparison - const finalVersionA = versionASpecific || stableA; - const finalVersionB = versionBSpecific || stableB; - console.log('Comparing:', finalVersionA, 'vs', finalVersionB); - - compareAndRenderPackageVersions( - selectedPackage, - finalVersionA, - finalVersionB, - comparisonState.cachedChangelogA, - comparisonState.cachedChangelogB - ); - } else { - // Full version comparison - performVersionComparison(stableA, stableB); - } + const finalVersionA = versionASpecific || stableA; + const finalVersionB = versionBSpecific || stableB; - if (compareButton) compareButton.disabled = false; + compareAndRenderPackageVersions( + selectedPackage, + finalVersionA, + finalVersionB, + comparisonState.cachedChangelogA, + comparisonState.cachedChangelogB + ); }; /** @@ -1405,6 +1539,34 @@ const setupComparisonEventListeners = () => { if (comparisonForm) comparisonForm.addEventListener('submit', handleComparisonSubmit); if (clearComparisonButton) clearComparisonButton.addEventListener('click', handleClearClick); if (copyComparisonLinkBtn) copyComparisonLinkBtn.addEventListener('click', copyComparisonLink); + if (clearVersionABtn) { + clearVersionABtn.addEventListener('click', () => { + if (versionASelect) { + versionASelect.value = ''; + versionASelect.disabled = false; + if (versionAPrereleaseSelect) { + versionAPrereleaseSelect.innerHTML = ''; + versionAPrereleaseSelect.value = ''; + versionAPrereleaseSelect.disabled = true; + } + updateCompareButtonState(); + } + }); + } + if (clearVersionBBtn) { + clearVersionBBtn.addEventListener('click', () => { + if (versionBSelect) { + versionBSelect.value = ''; + versionBSelect.disabled = false; + if (versionBPrereleaseSelect) { + versionBPrereleaseSelect.innerHTML = ''; + versionBPrereleaseSelect.value = ''; + versionBPrereleaseSelect.disabled = true; + } + updateCompareButtonState(); + } + }); + } comparisonListenersInitialized = true; console.log('comparison listeners are initialized sucessfully......'); @@ -1414,7 +1576,7 @@ const setupComparisonEventListeners = () => { * Handle enhanced comparison URL parameters on page load */ const loadEnhancedComparisonFromURL = async (enhancedParams) => { - switchToComparisonMode(); + await switchToComparisonMode(); await new Promise((resolve) => setTimeout(resolve, 300)); @@ -1445,7 +1607,7 @@ const loadEnhancedComparisonFromURL = async (enhancedParams) => { * Handle standard comparison URL parameters on page load */ const loadStandardComparisonFromURL = async (urlParams) => { - switchToComparisonMode(urlParams.versionA, urlParams.versionB); + await switchToComparisonMode(urlParams.versionA, urlParams.versionB); await new Promise((resolve) => setTimeout(resolve, 300)); diff --git a/docs/changelog/assets/js/comparison-view.js b/docs/changelog/assets/js/comparison-view.js index 7352606aa..52bb4e4de 100644 --- a/docs/changelog/assets/js/comparison-view.js +++ b/docs/changelog/assets/js/comparison-view.js @@ -24,13 +24,11 @@ const extractPackagesFromVersion = (changelog, specificVersions = null) => { for (const packageName of Object.keys(changelog)) { const packageVersions = changelog[packageName]; - console.log('packageVersions', packageVersions); // Safety check: ensure packageVersions is an object if (!packageVersions || typeof packageVersions !== 'object') continue; const versionKeys = Object.keys(packageVersions); - console.log('versionKeys', versionKeys); if (versionKeys.length === 0) continue; @@ -370,6 +368,22 @@ const generatePackageComparisonData = (packageName, versionASpecific, versionBSp ...stats, }; }; + +/** + * Get sorted widget-related package names from a changelog (for comparison package dropdown). + * Puts @webex/widgets and @webex/cc-widgets first, then remaining packages alphabetically. + * @param {Object} changelog - Changelog data (package name -> versions) + * @returns {string[]} Sorted array of package names + */ +const getWidgetPackagesFromChangelog = (changelog) => { + if (!changelog || typeof changelog !== 'object') return []; + const specialPackages = ['@webex/widgets', '@webex/cc-widgets']; + const allPackages = Object.keys(changelog); + const existingSpecial = specialPackages.filter((p) => allPackages.includes(p)); + const other = allPackages.filter((p) => !specialPackages.includes(p)).sort(); + return [...existingSpecial, ...other]; +}; + //Export All the functions export { comparisonState, @@ -384,4 +398,5 @@ export { comparePackages, fetchAndCompareVersions, generatePackageComparisonData, + getWidgetPackagesFromChangelog, }; diff --git a/docs/changelog/index.html b/docs/changelog/index.html index 18a7eb548..c924475e7 100644 --- a/docs/changelog/index.html +++ b/docs/changelog/index.html @@ -1,100 +1,88 @@ - - - - - Webex Widgets - + + + + - - - + Webex Widgets + - - + + + - - +
+
+
+
-
-
- -
- - -
+
+
+
+ +
+ +
-
-
+
+
+
+
- +
@@ -137,27 +125,35 @@ -
-
- - -
-
- - +
- -
+
Search Examples:
+
+
- -
-
- -
- - -
- -
-
+
+
+ +
+ + +
+ + +
-
^
-
-