diff --git a/.github/workflows/sync-changelog.yml b/.github/workflows/sync-changelog.yml new file mode 100644 index 000000000..afe773d62 --- /dev/null +++ b/.github/workflows/sync-changelog.yml @@ -0,0 +1,57 @@ +name: Sync Changelog + +on: + schedule: + - cron: '0 9 * * *' # Run daily at 9 AM UTC + workflow_dispatch: # Allow manual trigger + +concurrency: + group: changelog-sync + cancel-in-progress: false + +permissions: + contents: write + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Sync changelog + env: + GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }} + run: node scripts/sync-changelog.mjs --latest + + - name: Check for changes + id: git-check + run: | + if [ -z "$(git status --porcelain)" ]; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi + + - name: Commit and push changes + if: steps.git-check.outputs.changed == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add apps/ascent/app/changelog/content/ + git commit -m "chore: sync changelog [skip ci]" + git push diff --git a/apps/ascent/app/changelog/content/v0.0.10.mdx b/apps/ascent/app/changelog/content/v0.0.10.mdx new file mode 100644 index 000000000..be9be0757 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.10.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.10' +date: '2025-08-13' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.11.mdx b/apps/ascent/app/changelog/content/v0.0.11.mdx new file mode 100644 index 000000000..a19bf8cb8 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.11.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.11' +date: '2025-08-18' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.12.mdx b/apps/ascent/app/changelog/content/v0.0.12.mdx new file mode 100644 index 000000000..b32a114b2 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.12.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.12' +date: '2025-08-18' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.13.mdx b/apps/ascent/app/changelog/content/v0.0.13.mdx new file mode 100644 index 000000000..f70768841 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.13.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.13' +date: '2025-08-20' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.16.mdx b/apps/ascent/app/changelog/content/v0.0.16.mdx new file mode 100644 index 000000000..688221da8 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.16.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.16' +date: '2025-09-17' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.17.mdx b/apps/ascent/app/changelog/content/v0.0.17.mdx new file mode 100644 index 000000000..7fae5b976 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.17.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.17' +date: '2025-09-22' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.18.mdx b/apps/ascent/app/changelog/content/v0.0.18.mdx new file mode 100644 index 000000000..e621d6d31 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.18.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.18' +date: '2025-09-29' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.19.mdx b/apps/ascent/app/changelog/content/v0.0.19.mdx new file mode 100644 index 000000000..954d4b957 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.19.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.19' +date: '2025-10-06' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.20.mdx b/apps/ascent/app/changelog/content/v0.0.20.mdx new file mode 100644 index 000000000..14b49df30 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.20.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.20' +date: '2025-10-15' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.21.mdx b/apps/ascent/app/changelog/content/v0.0.21.mdx new file mode 100644 index 000000000..7046f43e0 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.21.mdx @@ -0,0 +1,166 @@ +--- +version: 'v0.0.21' +date: '2025-10-25' +status: 'stable' +--- + + + + **Remove** - duplicate props from button + + + + + + **Bug** - fix/chart ticks + + + + + + **Feat/code** - block + + + + + + **Update** - table and sidebar component + + + + + + **Fixed** - minor naming issue in menu documentation + + + + + + **Adjust** - padding and remove minWidth from Snackbar + + + + + + **481** - data ids for tag tabs + + + + + + **Added** - data ids for input fields + + + **Add** - isFirstRow prop to TableCell and update styling for first row + + + + + + **Simplify** - VirtualList and Select components + + + + + + **Fix/workflows** + + + **Token** - revamp + + diff --git a/apps/ascent/app/changelog/content/v0.0.22.mdx b/apps/ascent/app/changelog/content/v0.0.22.mdx new file mode 100644 index 000000000..ae069c8cb --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.22.mdx @@ -0,0 +1,130 @@ +--- +version: 'v0.0.22' +date: '2025-10-31' +status: 'stable' +--- + + + + **Added** - the height and minHeight prop to the card component + + + **Add** - Data-ids calendar table sidebar and update component(card, + table, calendar) + + + + + + **Enhance** - DataTable to handle empty values with hyphen display + + + + + + **Added** - the wrapping funcationality in key value pair component + + + + + + ***sidebar**:** - prevent tokens prop forwarding to DOM to remove React + unknown prop warnings + + + + + + **Added** - stepper component with theme provider + + + + + + **Add** - Upload component and integrate with context and demo + + + + + + **Added** - the initial version of workflow canvas component + + + + + + **Firebase** - credential rotation + + diff --git a/apps/ascent/app/changelog/content/v0.0.23.mdx b/apps/ascent/app/changelog/content/v0.0.23.mdx new file mode 100644 index 000000000..654affa86 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.23.mdx @@ -0,0 +1,77 @@ +--- +version: 'v0.0.23' +date: '2025-11-04' +status: 'stable' +--- + + + + **Update** - SidebarDemo to use chatInput component + + + **Add** - ChatInput component with utility functions and demo + integration + + + **Fixed** - chat-input component + + + + + + **Matched** - the height of sidebar header with the topbar + + + + + + **Added** - gap control for directory + + + **Remove** - unnecessary type assertions + + diff --git a/apps/ascent/app/changelog/content/v0.0.24.mdx b/apps/ascent/app/changelog/content/v0.0.24.mdx new file mode 100644 index 000000000..dee665cec --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.24.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.24' +date: '2025-11-10' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.25.mdx b/apps/ascent/app/changelog/content/v0.0.25.mdx new file mode 100644 index 000000000..6cae8f97b --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.25.mdx @@ -0,0 +1,130 @@ +--- +version: 'v0.0.25' +date: '2025-11-18' +status: 'stable' +--- + + + + **Add** - ripple effect to Button and Tag component + + + + + + **Resolve** - hover state issues and improve bar chart interactions + + + + + + **569** - Create mweb for sidebar and enhance data table + + + + + + **Fix/bugs(snackbar,** - avatar, chat component) + + + + + + **Update** - component documentation + + + **Dark** - theme setup + + + **Add** - CodeEditor component with syntax highlighting + + + **Add** - SkeletonTag component + + + + + + **Update** - contributing and getting started guides + + + + + + **Feat/animate** + + diff --git a/apps/ascent/app/changelog/content/v0.0.26.mdx b/apps/ascent/app/changelog/content/v0.0.26.mdx new file mode 100644 index 000000000..5e0961c4e --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.26.mdx @@ -0,0 +1,104 @@ +--- +version: 'v0.0.26' +date: '2025-11-20' +status: 'stable' +--- + + + + **Fix** - code editor and multi value input issues + + + + + + **Integrate** - drag-and-drop column reordering in DataTable + + + + + + **Fix** - multiselct and checkbox and add skeletons + + + + + + **Implement** - tenant panel only mode in Sidebar + + + + + + **Added** - variant support in split tag + + + + + + **Add** - Tabs animation and skeleton + + + + + + **Add** - Directory component and tokens + + diff --git a/apps/ascent/app/changelog/content/v0.0.27.mdx b/apps/ascent/app/changelog/content/v0.0.27.mdx new file mode 100644 index 000000000..f7cb6f0b8 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.27.mdx @@ -0,0 +1,20 @@ +--- +version: 'v0.0.27' +date: '2025-11-21' +status: 'stable' +--- + + + + **Update** - tabs addition functionality and fix code editor + + diff --git a/apps/ascent/app/changelog/content/v0.0.28.mdx b/apps/ascent/app/changelog/content/v0.0.28.mdx new file mode 100644 index 000000000..217c3e593 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.28.mdx @@ -0,0 +1,80 @@ +--- +version: 'v0.0.28' +date: '2025-11-26' +status: 'stable' +--- + + + + **Add** - skeleton for card, statcard and fix dropdown, switch, modal + + + + + + **Add** - Sankey chart support to Charts + + + + + + **Tabs** - code and update dynamic tabs management + + + **Fix** - tabs with underscore data + + + **Fix** - tabs with underscore data + + + + + + **Enhance** - custom issue template and add Monaco editor styles + + diff --git a/apps/ascent/app/changelog/content/v0.0.29.mdx b/apps/ascent/app/changelog/content/v0.0.29.mdx new file mode 100644 index 000000000..48842b654 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.29.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.29' +date: '2025-12-08' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.30.mdx b/apps/ascent/app/changelog/content/v0.0.30.mdx new file mode 100644 index 000000000..19fdd24ec --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.30.mdx @@ -0,0 +1,426 @@ +--- +version: 'v0.0.30' +date: '2025-12-16' +status: 'stable' +--- + + + + **Improve** - accessibility to meet wcag standards for avatar avatar + group breadcrumb menu and alert + + + + + + **Data** - ids for Breadcrumb, Accordion, Single Select, Multi Select + + + + + + **Added** - button type = button in primitive button + + + **Add** - accessibility dashboard with button component + + + **Add** - data attributes for button + + + + + + **734** - accessibility for cards statcards charts sidebar + + + + + + **Fixed** - charts ticks issue + + + + + + **Add** - data attribute for table and calendar + + + **Fix** - table dropdowns overlap issue + + + + + + **Improve** - accessibility for table calendar, progressbar and upload + + + + + + **Fix** - z index to resolve dropdown in drawer and fix accordion + chevron + + + + + + **Separate** - disable options for dropdownInput + + + **Updated** - the dropdown tokens with designs + + + + + + **735** - improve accessibility for key value pair snackbar tabs and + accordion + + + + + + **Added** - maxWidth, maxHeight, minWidth, minHeight, isCustom prop to + modal + + + + + + **725** - accessibility for modal popover tag tooltip + + + + + + **AvoidCollision** - in multiselect and spacing fixes in keyValuePair/… + + + + + + **Bug-fix/sidebar-numberInput-otp** + + + + + + **Improve** - accessibility to meet wcag aaa standards for Single & + Multi selects + + + + + + **Tab** - component's dropdown issues for large number of tab lists + + + **Fix/tab** - issues v1 + + + + + + **Password** - prop added to text input + + + + + + **Add** - data-id attributes to textInput, avatar, and tags + + + + + + **Added** - newLine functionality to tooltip + + + **Fix/tooltip** - data ids + + + + + + **File** - Upload, Snackbar, SearchInput, OTPInput, Alert, Modal, Tabs… + + + + + + **Enhance** - accessibility + + + + + + **Changed** - the tokens of selectors + + + **Update** - react version + + + **708** - accessibilty input component + + + **Add** - skeletons for differents components and fix minor bugs + + + **Bug** - fix/issues list + + + **Improve** - accessibility to meet wcag aaa standards + + diff --git a/apps/ascent/app/changelog/content/v0.0.31.mdx b/apps/ascent/app/changelog/content/v0.0.31.mdx new file mode 100644 index 000000000..57293f569 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.31.mdx @@ -0,0 +1,408 @@ +--- +version: 'v0.0.31' +date: '2025-12-22' +status: 'stable' +--- + + + + **Enhance** - ButtonGroup with different stacking + + + + + + **Update** - Card component padding handling for CUSTOM variant + + + + + + **Add** - maxHeight to charts legend dropdown + + + **Chart** - legend data handling by removing capitalisation + + + + + + **Improve** - Checkbox component checked state handling + + + + + + **Enhance** - CodeEditor with customizable header slots and icon + visibility + + + **Add** - autoFocus prop to CodeEditor + + + + + + **Add** - description tooltip support to DataTable component + + + **Fix** - table height and update rows sync with api for pagination + + + + + + **Add** - timezone support to DateRangePicker + + + + + + **Removed** - overflow from drawerbase + + + + + + **Api** - call example for dropdown + + + + + + **Add** - scroll lock for dropdowns inside modals + + + + + + **Fix/multiselect** - placeholder color + + + + + + **Added** - a prop in numberInput to prevent entry of neg value + + + **Enhance** - NumberInput with input sanitization + + + + + + **Bug** - fix/otp input + + + + + + **Added** - conditional virtual list to single select + + + + + + **Enhance** - SingleSelect and multiselect with Tooltip integration + + + **Corrected** - the height for single/multi-select + + + + + + **Update** - Snackbar component layout and structure + + + + + + **Fix** - stat card mismatch between delta colorsign and graph color + + + + + + **Created** - separate div for switch and sublable + + + + + + **Update** - Tag component styles for better alignment and sizing + + + + + + **Update** - error message display in ErrorState of upload + + + + + + **Upload** - file error state file name added and Data Table hide column + manager on no Data + + + + + + **Wrap** - state update calls in requestAnimationFrame + + + **Input** - field disabled lable fixed + + + + + + **Migrate** - from blend-v1 to @juspay/blend-design-system + + + **Bug** - fix/issues + + + **Enhance** - TableHeader component layout and tooltip handling + + diff --git a/apps/ascent/app/changelog/content/v0.0.32.mdx b/apps/ascent/app/changelog/content/v0.0.32.mdx new file mode 100644 index 000000000..3222e5c6c --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.32.mdx @@ -0,0 +1,384 @@ +--- +version: 'v0.0.32' +date: '2026-01-20' +status: 'stable' +--- + + + + **Accordion** - overflow hiiden visibility fix + + + + + + **Button** - icon disable color added + + + **Update** - ButtonBase sizing logic + + + + + + **Remove** - overflow from card + + + + + + **Custom** - legend for chart + + + **Legends** - total type + + + **Linechart** - overlap issue fixed + + + **Text** - spilling over tooltip box in Charts resolved + + + **Feat/mulit** - colored line chart + + + **Feat/area** - chart + + + **Feat/charts** - custom dot + + + + + + **Fix/chatinput** - mweb(refactored) + + + + + + **Optimize** - ColumnManager and MultiSelectMenu + + + + + + **Implement** - delta sorting feature in DataTable + + + **Data** - table: space in search box and initialColumns renderCell + change sync + + + **Change** - DataTable overflow property from 'visible' to 'auto' + + + **920** - datatable pagination control is not responsive goes out of + container + + + + + + **Add** - full screen support for drawer + + + + + + **Enhance** - TableCell with truncation logic and improve Menu + + + + + + **Add** - prop to show clear button in multiselect + + + + + + **Enhance** - MultiSelect, SingleSelect with disabled state + + + **Enhance** - MultiSelect, SingleSelect border styling + + + + + + **Enhance** - NumberInput with interactive min/max and validation + + + + + + **Add** - sidebar icon only state + + + + + + **Enhance** - SingleSelect with width adjustments and demo updates + + + **No** - padding between 'No items available' in single select fixed + + + + + + **Fixed** - the border issue in statCard help icon + + + + + + **Remove** - tooltip exit animations for instant disappearance + + + + + + **Update** - input components background colors + + + **Improve** - SelectItem performance + + + + + + **De-couple** - delta sign with graph color (resolved) + + diff --git a/apps/ascent/app/changelog/content/v0.0.33.mdx b/apps/ascent/app/changelog/content/v0.0.33.mdx new file mode 100644 index 000000000..44f996f02 --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.33.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.33' +date: '2026-01-20' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/app/changelog/content/v0.0.34.mdx b/apps/ascent/app/changelog/content/v0.0.34.mdx new file mode 100644 index 000000000..f49a09bfa --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.34.mdx @@ -0,0 +1,602 @@ +--- +version: 'v0.0.34' +date: '2026-02-03' +status: 'stable' +--- + + + + **Add** - export in component index for tokens and accodion visibility + fix + + + + + + **Removed** - maxWidth from alert + + + **Feat/alert** - v2 + + + + + + **Introduce** - ButtonV2 + + + **Fix/button** - token change + + + + + + **Fix/card** - data ids + + + + + + **Charts** - outage not getting grey issue fixed + + + **Color** - should be map by keys instead of index in legend more + + + **Fix/chart** - legend menu + + + **Fix/bar** - chart aux not visible + + + **Fix/chart** - dot issue + + + **Fix/chart** - legend more color + + + **Fix/color** - mismatch legend chart + + + + + + **Checkboc** - span data-id added + + + + + + **Improve** - column state management in DataTable + + + **Added** - virtual list to data table filter + + + **Focus** - id added for data table + + + + + + **Data** - table column msnager selection removed on close + + + + + + **Fix/offsets** - support in the web drawer + + + + + + **Search** - added to dropdowninput + + + + + + **Feat/multi** - select group + + + **Multiselect** - new token added for disabled, removed border left from + x button + + + + + + **Added** - prevent default hook to multiselect and singleselect + + + + + + **Enhance** - MultiValueInput with left and right slot support + + + + + + **Fix/sidebar** - intermediate state removed + + + + + + **Single** - select diselect function removed + + + **Feat/single** - select group + + + + + + **Add** - SnackbarV2 and demo + + + + + + **Add** - showBorder prop to StatCard component for customizable border + display + + + **Option** - to hide delta value in Stat Card + + + + + + **Add** - stickyHeader prop to Tabs + + + **Ui** - render issue fixed for tabs UNDERLINE varient + + + **Tabs** - render issue on api call resolved + + + **Auto** - change tab issue resolved & right slot applied + + + **Tabs** - underline issue fixed + + + **Tabs** - new flow added for add button + + + **Fix/tabs** - render issue + + + + + + **Feat/tagv2** + + + + + + **Added** - error msg to error tag in multi file upload + + + **Ui** - overflow issue reolved in fileupload + + + + + + **Data** - id added for upload, tag, tooltip + + + + + + **Implement** - virtual scrolling for submenus to enhance performance + + + **Add** - centralized accessibility utilities and add rfc for + refactoration + + + + + + **Table** - Checkbox issue fixed + + + **Added** - divider line between up and down arrow + + + **Undefined** - restricted + + + **Mapped** - with key instead of index + + + **Fixed** - autofill overlapping issue in inputs + + + + + + **Fix/observer** - loop + + + **Added** - demo for multiple labels + + + **Fix** - table filter popover opening + + diff --git a/apps/ascent/app/changelog/content/v0.0.35.mdx b/apps/ascent/app/changelog/content/v0.0.35.mdx new file mode 100644 index 000000000..2c7ae8e8a --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.35.mdx @@ -0,0 +1,92 @@ +--- +version: 'v0.0.35' +date: '2026-02-24' +status: 'stable' +--- + + + + **1058** - avatar components code refactor + + + + + + **Fix/button** - border changed 1.5px from 1px + + + + + + **Update** - table column to handle react element width and no data + available state + + + + + + **Enhance** - dropdown interaction lock with selective pointer event + disabling + + + + + + **Add** - portal in menu + + + + + + **Enhance** - changelog generation with dynamic repository URL retrieval + + diff --git a/apps/ascent/app/changelog/content/v0.0.7.mdx b/apps/ascent/app/changelog/content/v0.0.7.mdx new file mode 100644 index 000000000..43b69a57f --- /dev/null +++ b/apps/ascent/app/changelog/content/v0.0.7.mdx @@ -0,0 +1,11 @@ +--- +version: 'v0.0.7' +date: '2025-08-05' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + diff --git a/apps/ascent/components/changelog/ChangelogCard.tsx b/apps/ascent/components/changelog/ChangelogCard.tsx index 8761a4d42..fbd44bdde 100644 --- a/apps/ascent/components/changelog/ChangelogCard.tsx +++ b/apps/ascent/components/changelog/ChangelogCard.tsx @@ -34,7 +34,7 @@ export const ChangelogCard = ({ isExpanded && 'border-b' )} > -
+
0 && (
- {commitHashes.map((hash, i) => { - const url = - commitUrls[i] || - `https://github.com/juspay/blend-design-system/commit/${hash}` - return ( - e.stopPropagation()} - > - Commit - - - ) - })} + {commitHashes.length === 1 ? ( + e.stopPropagation()} + > + Commit + + + ) : ( +
e.stopPropagation()} + > + {commitHashes.length} commits +
+ )}
)}
diff --git a/deploy.sh b/deploy.sh index 4247a8f16..e020bae00 100755 --- a/deploy.sh +++ b/deploy.sh @@ -25,7 +25,13 @@ fi ENVIRONMENT=$1 ROOT_DIR=$(pwd) -# Load appropriate environment file +# Load base .env first (contains shared secrets like GROQ_API_KEY, FIGMA_ACCESS_TOKEN) +if [ -f ".env" ]; then + echo "πŸ“‹ Loading base environment from .env" + export $(cat ".env" | grep -v '^#' | xargs) +fi + +# Load appropriate environment file (overrides base values if needed) if [ "$ENVIRONMENT" = "dev" ]; then load_env ".env.dev" elif [ "$ENVIRONMENT" = "prod" ]; then @@ -54,6 +60,71 @@ if [ ! -d "node_modules" ]; then pnpm install fi +# Sync changelog before building +echo "πŸ“ Syncing changelog..." +pnpm sync-changelog --latest || echo "⚠️ Changelog sync failed, continuing with existing files" + +# Format newly generated changelog files +echo "✨ Formatting changelog files..." +pnpm prettier --write "apps/ascent/app/changelog/content/*.mdx" 2>/dev/null || true + +# Commit any newly generated changelog files via PR +echo "πŸ“ Committing new changelog files..." +git add apps/ascent/app/changelog/content/ +if ! git diff --staged --quiet; then + git config user.name "$(git config --global user.name)" + git config user.email "$(git config --global user.email)" + + # Check if GitHub CLI is installed, if not install it + if ! command -v gh &> /dev/null; then + echo "βš™οΈ GitHub CLI not found, installing..." + if [[ "$OSTYPE" == "darwin"* ]]; then + brew install gh + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null + sudo apt update && sudo apt install gh -y + else + echo "❌ Unsupported OS, please install GitHub CLI manually: https://cli.github.com" + exit 1 + fi + echo "βœ… GitHub CLI installed!" + else + echo "βœ… GitHub CLI found: $(gh --version | head -1)" + fi + + # Check if authenticated, if not trigger login + if ! gh auth status &> /dev/null; then + echo "πŸ” GitHub CLI is not authenticated. Launching login..." + gh auth login + # Verify auth succeeded + if ! gh auth status &> /dev/null; then + echo "❌ GitHub authentication failed. Aborting PR creation." + exit 1 + fi + echo "βœ… GitHub CLI authenticated!" + else + echo "βœ… GitHub CLI already authenticated" + fi + + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + PR_BRANCH="chore/sync-changelog-$(date +'%Y%m%d-%H%M%S')" + + git checkout -b $PR_BRANCH + git commit -m "chore: sync changelog" + git push origin $PR_BRANCH + + gh pr create \ + --title "chore: sync changelog" \ + --body "Automated changelog sync from deploy script" \ + --base $CURRENT_BRANCH \ + --head $PR_BRANCH \ + || echo "⚠️ PR creation failed, check manually" + + git checkout $CURRENT_BRANCH + git branch -D $PR_BRANCH +fi + # Build Ascent app echo "πŸ“š Building Ascent documentation..." pnpm --filter ascent run build diff --git a/package.json b/package.json index c16b6c00a..465d6ddd7 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,10 @@ "test:a11y:watch": "cd packages/blend && pnpm test:a11y:watch", "test:a11y:file": "cd packages/blend && pnpm test:file", "chromatic": "cd apps/storybook && pnpm chromatic", - "chromatic:ci": "cd apps/storybook && pnpm chromatic:ci" + "chromatic:ci": "cd apps/storybook && pnpm chromatic:ci", + "sync-changelog": "node --env-file=.env scripts/sync-changelog.mjs", + "sync-changelog:latest": "node --env-file=.env scripts/sync-changelog.mjs --latest", + "sync-changelog:force": "node --env-file=.env scripts/sync-changelog.mjs --force" }, "devDependencies": { "@changesets/cli": "^2.27.1", diff --git a/scripts/sync-changelog.mjs b/scripts/sync-changelog.mjs new file mode 100644 index 000000000..fdecc13c9 --- /dev/null +++ b/scripts/sync-changelog.mjs @@ -0,0 +1,683 @@ +#!/usr/bin/env node +/** + * Changelog Sync Script + * Fetches releases from juspay/blend-design-system and generates MDX files. + */ + +// ============ CONFIGURATION ============ +const CONFIG = { + owner: 'juspay', + repo: 'blend-design-system', + outputDir: 'apps/ascent/app/changelog/content', + groqModel: 'llama-3.3-70b-versatile', + groqApiUrl: 'https://api.groq.com/openai/v1/chat/completions', +} + +// Emoji to type mapping +const EMOJI_TYPE_MAP = { + 'πŸš€': { type: 'feat', summary: 'Features' }, + 'πŸ›': { type: 'fix', summary: 'Bug Fixes' }, + '♻️': { type: 'refactor', summary: 'Refactoring' }, + 'πŸ”§': { type: 'chore', summary: 'Chores' }, + 'πŸ“š': { type: 'docs', summary: 'Documentation' }, + 'πŸ’₯': { type: 'breaking', summary: 'Breaking Changes' }, + '⚑': { type: 'perf', summary: 'Performance' }, +} + +// Noise patterns to skip +const NOISE_PATTERNS = [ + /^dev to staging/i, + /^release:/i, + /^\*\*release\*\*:/i, + /^chore\(release\)/i, + /\[BETA/i, + /^Update blend landing/i, + /^launch video/i, + /^added firebase/i, + /^build fixes which came while deployment/i, + /^updated the docs for new landing/i, + /^Feat\/workflow/i, + /^chore\/workflow/i, + /^workflow/i, +] + +// ============ UTILITIES ============ + +/** + * Log with emoji prefixes + */ +function log(level, message) { + const prefixes = { + info: 'πŸ“‘', + success: 'βœ“', + error: '❌', + warning: '⚠️', + skip: '⏭', + processing: 'πŸ”„', + robot: 'πŸ€–', + done: 'βœ…', + dash: ' ', + } + console.log(`${prefixes[level] || ''} ${message}`) +} + +/** + * Check if text matches any noise pattern + */ +function isNoise(text) { + return NOISE_PATTERNS.some((pattern) => pattern.test(text)) +} + +/** + * Clean up commit message text + */ +function cleanMessage(text) { + return text + .replace(/\s*\(#\d+\)\s*$/, '') // Remove PR reference at end + .replace(/^[-*β€’]\s*/, '') // Remove list marker + .trim() +} + +/** + * Capitalize first letter + */ +function capitalize(text) { + return text.charAt(0).toUpperCase() + text.slice(1) +} + +// ============ PARSING ============ + +/** + * Parse CHANGELOG.md content into structured entries + */ +function parseChangelog(content) { + const lines = content.split('\n') + const entries = [] + let currentSection = null + + for (const line of lines) { + const trimmed = line.trim() + + // Check for section headers (## πŸš€ Features, etc.) + const sectionMatch = trimmed.match(/^##\s+(\S+)\s+(.+)$/) + if (sectionMatch) { + const emoji = sectionMatch[1] + const sectionName = sectionMatch[2] + const mapping = EMOJI_TYPE_MAP[emoji] + if (mapping) { + currentSection = { + type: mapping.type, + summary: mapping.summary, + } + } + continue + } + + // Parse list items + if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) { + // Extract commit link + const linkMatch = trimmed.match(/\[([a-f0-9]{7})\]\(([^)]+)\)/) + const commitHash = linkMatch ? linkMatch[1] : null + let commitUrl = linkMatch ? linkMatch[2] : null + + // Normalize relative URLs to absolute + if (commitUrl && !commitUrl.startsWith('http')) { + commitUrl = `https://github.com/juspay/blend-design-system/commit/${commitHash}` + } + + // Extract PR ID before removing it + const prMatch = trimmed.match(/\(#(\d+)\)/) + const prId = prMatch ? prMatch[1] : null + + // Remove commit link [abc1234](url) + let message = trimmed + .replace(/\s*\[([a-f0-9]{7})\]\([^)]+\)\s*/g, '') // Remove ALL commit links + .replace(/^[-*]\s*/, '') // Remove list marker + .replace(/\s*\(#\d+\)\s*/g, '') // Remove ALL PR references (#123) + .replace(/\(\s*\)/g, '') // Remove empty parentheses () + .trim() + + // Skip noise + if (isNoise(message)) { + continue + } + + if (message && currentSection) { + entries.push({ + type: currentSection.type, + summary: currentSection.summary, + message: capitalize(cleanMessage(message)), + commitHash, + commitUrl, + }) + } + } + } + + return entries +} + +// ============ GROQ API ============ + +/** + * Extract component names using Groq API (batched) + */ +async function extractComponentNames(entries, apiKey) { + if (!apiKey) { + throw new Error('GROQ_API_KEY environment variable is required') + } + + // Prepare batch request + const messages = entries + .map((entry, idx) => `${idx + 1}. ${entry.message}`) + .join('\n') + + // STRICT prompt - emphasize exact format requirement + const prompt = `You must respond with ONLY a numbered list, nothing else. No explanations, no notes, no extra text before or after the list. + +For each commit message below, extract the component name being changed. Write the component name (e.g., DataTable, Sidebar, Charts, Button) or write "null" if no specific component is mentioned. + +Example response format: +1. DataTable +2. null +3. Sidebar +4. Button + +Commit messages: +${messages}` + + try { + const response = await fetch(CONFIG.groqApiUrl, { + method: 'POST', + headers: { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: CONFIG.groqModel, + messages: [ + { + role: 'system', + content: + 'You are a precise extraction tool for a React design system called Blend. Return ONLY numbered lists with no extra text, explanations, or formatting.The design system has these exact components (use these exact PascalCase names): Button, ButtonGroup, Breadcrumb, Alert, Accordion, Tabs, DataTable, Avatar,AvatarGroup, Badge, SplitTag, Tag, Card, Charts, ChatInput, Checkbox, CodeBlock,DateRangePicker, Drawer, DropdownInput, KeyValuePair, Menu, Modal, MultiSelect,MultiValueInput, NumberInput, OTPInput, Popover, ProgressBar, Radio, SearchInput,Sidebar, SingleSelect, Slider, Snackbar, StatCard, Stepper, Switch, Textarea,TextInput, Tooltip, UnitInput, Upload, ColumnManager, Timeline Rules:- Always match to the closest component from the list above- Strip version suffixes: "Popover v2" β†’ "Popover", "Radio-V2" β†’ "Radio", "checkbox v2" β†’ "Checkbox"- Handle branch-name format: "Refactor/popover-v2" β†’ "Popover", "Refactor/key-value-pair" β†’ "KeyValuePair"- Convert informal names: "key value pair" β†’ "KeyValuePair", "chat input" β†’ "ChatInput", "data table" β†’ "DataTable"- Handle multi-component entries: "MultiSelect and SingleSelect" β†’ "MultiSelect, SingleSelect"- If genuinely no component is mentioned return null', + }, + { role: 'user', content: prompt }, + ], + temperature: 0.0, + max_tokens: 500, + }), + }) + + if (!response.ok) { + throw new Error( + `Groq API error: ${response.status} ${await response.text()}` + ) + } + + const data = await response.json() + const content = data.choices?.[0]?.message?.content || '' + + // Parse numbered list response + const results = [] + const lines = content.split('\n').filter((l) => l.trim()) + + for (const line of lines) { + // Match numbered response: "1. DataTable" or "1. null" + // Skip lines that don't start with a number (extra text LLM might add) + const match = line.match(/^\d+[.\)]\s*(.+)$/i) + if (match) { + const component = match[1].trim() + results.push( + component.toLowerCase() === 'null' ? null : component + ) + } + } + + // VALIDATION: Check if we got the right number of results + if (results.length !== entries.length) { + log( + 'warning', + `Groq returned ${results.length} results for ${entries.length} entries β€” using type-based grouping instead` + ) + return entries.map((entry) => ({ ...entry, component: null })) + } + + // Merge results back into entries + return entries.map((entry, idx) => ({ + ...entry, + component: results[idx], + })) + } catch (error) { + log( + 'warning', + `Groq API failed: ${error.message}. Proceeding without component extraction.` + ) + return entries.map((entry) => ({ ...entry, component: null })) + } +} + +// ============ MDX GENERATION ============ + +/** + * Group entries by component (with fallback to type) + */ +function groupEntries(entries) { + const groups = new Map() + + // First, group by component + const componentGroups = new Map() + const typeGroups = new Map() + + for (const entry of entries) { + if (entry.component) { + const existing = componentGroups.get(entry.component) || [] + componentGroups.set(entry.component, [...existing, entry]) + } else { + const key = entry.summary // Features, Bug Fixes, etc. + const existing = typeGroups.get(key) || [] + typeGroups.set(key, [...existing, entry]) + } + } + + // Add component groups first (sorted alphabetically) + const sortedComponents = Array.from(componentGroups.entries()).sort( + ([a], [b]) => a.localeCompare(b) + ) + for (const [component, items] of sortedComponents) { + groups.set(component, { type: 'component', items }) + } + + // Then add type groups in priority order + const typeOrder = [ + 'Features', + 'Bug Fixes', + 'Breaking Changes', + 'Refactoring', + 'Performance', + 'Documentation', + 'Chores', + ] + for (const typeName of typeOrder) { + if (typeGroups.has(typeName)) { + groups.set(typeName, { + type: 'category', + items: typeGroups.get(typeName), + }) + } + } + + return groups +} + +/** + * Generate MDX content + */ +function generateMDXContent(version, date, entries) { + const groups = groupEntries(entries) + + let mdx = `--- +version: '${version}' +date: '${date}' +status: 'stable' +--- + +` + + let isFirstCard = true + for (const [groupName, groupData] of groups) { + const { items, type } = groupData + + // Collect all commit hashes and URLs for the card + const commitHashes = items.map((e) => e.commitHash).filter(Boolean) + + // Build ChangelogCard props + let cardProps = `summary="${groupName}"` + if (isFirstCard) { + cardProps += ` defaultExpanded={true}` + isFirstCard = false + } + if (commitHashes.length === 1) { + cardProps += ` commitHash="${commitHashes[0]}"` + if (items[0].commitUrl) + cardProps += ` commitUrl="${items[0].commitUrl}"` + } else if (commitHashes.length > 1) { + cardProps += ` commitHash={[${commitHashes.map((h) => `"${h}"`).join(', ')}]}` + const urls = items.map((e) => e.commitUrl).filter(Boolean) + if (urls.length > 0) + cardProps += ` commitUrl={[${urls.map((u) => `"${u}"`).join(', ')}]}` + } + + mdx += ` +` + + for (const entry of items) { + // Build ChangelogEntry props + let entryProps = `type="${entry.type}"` + if (entry.commitHash) + entryProps += ` commitHash="${entry.commitHash}"` + if (entry.commitUrl) entryProps += ` commitUrl="${entry.commitUrl}"` + + // Format message with bold title + const title = entry.message.split(' ')[0] + const rest = entry.message.slice(title.length).trim() + const formattedMessage = rest + ? `**${title}** - ${rest}` + : `**${entry.message}**` + + mdx += ` + ${formattedMessage} + +` + } + + mdx += ` + +` + } + + return mdx.trim() + '\n' +} + +// ============ FILE OPERATIONS ============ + +import { + writeFileSync, + existsSync, + mkdirSync, + readdirSync, + readFileSync, +} from 'fs' +import { join } from 'path' + +/** + * Ensure output directory exists + */ +function ensureOutputDir() { + const dir = join(process.cwd(), CONFIG.outputDir) + if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }) + } + return dir +} + +/** + * Check if MDX file already exists + */ +function fileExists(version) { + const filepath = join(process.cwd(), CONFIG.outputDir, `${version}.mdx`) + return existsSync(filepath) +} + +/** + * Write MDX file + */ +function writeMDXFile(version, content) { + const filepath = join(process.cwd(), CONFIG.outputDir, `${version}.mdx`) + writeFileSync(filepath, content, 'utf-8') + return filepath +} + +// ============ FETCHERS ============ + +/** + * Fetch releases from GitHub API + */ +async function fetchReleases() { + const url = `https://api.github.com/repos/${CONFIG.owner}/${CONFIG.repo}/releases?per_page=100` + const response = await fetch(url) + + if (!response.ok) { + throw new Error( + `GitHub API error: ${response.status} ${await response.text()}` + ) + } + + return response.json() +} + +/** + * Fetch archived changelog for a specific version + */ +async function fetchArchivedChangelog(version) { + const url = `https://raw.githubusercontent.com/${CONFIG.owner}/${CONFIG.repo}/main/docs/changelogs/${version}.md` + + try { + const response = await fetch(url) + if (response.ok) { + return { content: await response.text(), source: 'archive' } + } + } catch (e) { + // Ignore fetch errors + } + + return null +} + +/** + * Fetch CHANGELOG.md from main and verify version matches + */ +async function fetchChangelogFromMain(version) { + const url = `https://raw.githubusercontent.com/juspay/blend-design-system/main/docs/CHANGELOG.md` + try { + const response = await fetch(url) + if (!response.ok) return null + const content = await response.text() + if (content.trimStart().startsWith(`# Changelog for ${version}`)) { + return { content, source: 'main' } + } + return null + } catch (e) { + return null + } +} + +/** + * Fetch changelog from GitHub release body (for older releases) + */ +async function fetchChangelogFromReleaseBody(release) { + const body = release.body || '' + + // Old releases had real content in body + // New releases have boilerplate - detect and skip those + if ( + !body || + body.includes('See the CHANGELOG') || + body.includes('This stable release is now published') || + body.length < 300 + ) { + return null + } + + return { content: body, source: 'release-body' } +} + +/** + * Fetch CHANGELOG.md from the specific git tag (last resort) + */ +async function fetchChangelogFromTag(version) { + const url = `https://raw.githubusercontent.com/juspay/blend-design-system/${version}/docs/CHANGELOG.md` + try { + const response = await fetch(url) + if (!response.ok) return null + const content = await response.text() + return { content, source: 'tag' } + } catch (e) { + return null + } +} + +// ============ MAIN ============ + +async function main() { + const args = process.argv.slice(2) + const isLatest = args.includes('--latest') + const isForce = args.includes('--force') + + // Check for API key first + const apiKey = process.env.GROQ_API_KEY + if (!apiKey) { + log('error', 'GROQ_API_KEY is not set. Add it to your .env file.') + process.exit(1) + } + + log('info', 'Fetching releases from GitHub...') + + const releases = await fetchReleases() + + // Filter stable releases only + const stableReleases = releases.filter( + (r) => + !r.prerelease && !r.draft && !/beta|alpha|rc|pre/i.test(r.tag_name) + ) + + log( + 'info', + `Found ${releases.length} total releases, ${stableReleases.length} stable.` + ) + + if (stableReleases.length === 0) { + log('warning', 'No stable releases found.') + process.exit(0) + } + + // Determine which releases to process + let releasesToProcess = stableReleases + if (isLatest) { + releasesToProcess = [stableReleases[0]] // Most recent + } + + const outputDir = ensureOutputDir() + let generatedCount = 0 + let skippedCount = 0 + + for (const release of releasesToProcess) { + const version = release.tag_name + const date = release.published_at.split('T')[0] + + log('processing', `Processing ${version} (${date})...`) + + // Check if file exists (unless force mode) + if (!isForce && fileExists(version)) { + log( + 'skip', + `Skipping ${version} β€” already exists (use --force to regenerate)` + ) + skippedCount++ + continue + } + + // Try to fetch changelog content + // 1. Check for archived changelog (docs/changelogs/vX.X.X.md) + let changelogData = await fetchArchivedChangelog(version) + + // 2. Fallback to CHANGELOG.md on main (only if version matches) + if (!changelogData) { + changelogData = await fetchChangelogFromMain(version) + } + + // 3. Fallback to release body (for older releases with content in body) + if (!changelogData) { + changelogData = await fetchChangelogFromReleaseBody(release) + } + + // 4. Last resort: Fetch from git tag + if (!changelogData) { + changelogData = await fetchChangelogFromTag(version) + } + + if (!changelogData) { + log('warning', `Could not find changelog for ${version}, skipping`) + skippedCount++ + continue + } + + log('success', `Found changelog (${changelogData.source})`) + + // Parse entries + const entries = parseChangelog(changelogData.content) + + if (entries.length === 0) { + log( + 'warning', + `No entries found for ${version} β€” generating minimal release card` + ) + const minimalContent = `--- +version: '${version}' +date: '${date}' +status: 'stable' +--- + + + + Stable release. No detailed changelog available for this version. + + +` + writeMDXFile(version, minimalContent) + generatedCount++ + continue + } + + // Count by type + const typeCounts = {} + let noiseSkipped = 0 + for (const entry of entries) { + typeCounts[entry.type] = (typeCounts[entry.type] || 0) + 1 + } + + const typeSummary = Object.entries(typeCounts) + .map(([t, c]) => `${c} ${t}`) + .join(', ') + + log('success', `Parsed ${entries.length} entries (${typeSummary})`) + + // Extract component names via Groq + log('robot', 'Extracting component names via Groq...') + const entriesWithComponents = await extractComponentNames( + entries, + apiKey + ) + + // Count component extractions + const componentCounts = new Map() + let noComponentCount = 0 + for (const entry of entriesWithComponents) { + if (entry.component) { + componentCounts.set( + entry.component, + (componentCounts.get(entry.component) || 0) + 1 + ) + } else { + noComponentCount++ + } + } + + for (const [comp, count] of componentCounts) { + log('dash', `${comp} (${count} entries)`) + } + if (noComponentCount > 0) { + log( + 'dash', + `No component (${noComponentCount} entries β†’ grouped by type)` + ) + } + + // Generate MDX + const mdxContent = generateMDXContent( + version, + date, + entriesWithComponents + ) + const filepath = writeMDXFile(version, mdxContent) + + log('success', `Generated ${filepath.replace(process.cwd() + '/', '')}`) + generatedCount++ + } + + log('done', `Done. ${generatedCount} generated, ${skippedCount} skipped.`) +} + +main().catch((err) => { + log('error', err.message) + process.exit(1) +})