A modern, high-performance integration store for WSO2 Integrator, showcasing 800+ Ballerina connectors, libraries, and other integration assets from Ballerina Central with accurate download metrics and powerful filtering capabilities.
The WSO2 Integration Store provides a user-friendly interface to discover, search, filter, and explore Ballerina connectors from Ballerina Central. Built with React and WSO2 Oxygen UI (built on Material-UI v7), it offers a fast, responsive experience with professional WSO2 branding.
Live Demo: [Your deployment URL here]
- WSO2 Oxygen UI Design System - Built with @wso2/oxygen-ui
- Official WSO2 header with logo and integrated theme toggle
- Exact color scheme from wso2.com/integrator
- Plus Jakarta Sans font family
- Dark/Light theme support with system preference detection
- Lucide icons via @wso2/oxygen-ui-icons-react
- Sticky header for better navigation
- Extended theme using
extendThemewith OxygenTheme base
- Customizable page size: 10, 30, 50, or 100 items per page
- Default: 30 connectors per page
- Smart page navigation with ellipsis
- Auto-reset to page 1 on filter/search changes
- Smooth scroll to top on page transitions
- "Showing X-Y of Z" item counter
- URL-based navigation (bookmarkable, shareable links)
- Real-time Search: Server-side search across names, summaries, and keywords
- Dynamic Filters (3 dimensions):
- Area (Finance, Communication, Health, etc.)
- Vendor (AWS, Salesforce, Google, etc.)
- Type (Connector, Library, Driver, etc.)
- Combined search + filter functionality
- Active filter count badges
- One-click clear all filters
- Filter state preserved in URL
- Progressive filter loading with 24-hour cache
- Most Popular - Highest downloads first (default)
- Least Popular - Lowest downloads first
- Newest First - Recently created connectors
- Oldest First - Oldest connectors
- Name (A-Z) - Alphabetical ascending
- Name (Z-A) - Alphabetical descending
- All sorting works with filters and search
- Sort preference preserved in URL
- Server-side sorting for optimal performance
- Fast Initial Load: ~2 seconds to first render
- Server-Side Operations: Filtering, sorting, and pagination handled by API
- Progressive Filter Loading:
- First 100 packages fetch filter options (~2s)
- Complete filter list loads in background
- 24-hour localStorage cache for instant subsequent loads
- Minimal Memory Footprint: Only current page (30 items) in memory
- Retry Logic: Automatic retries with exponential backoff for network resilience
- Graceful Degradation: Works with partial data if some requests fail
- Optimized Rendering: Only current page items rendered
- Memoized Components: Efficient re-renders
- Expandable Descriptions: "Show more" button for long summaries
- Mobile-first approach
- Adaptive grid: 1-3 columns based on screen width
- Touch-friendly interface
- Optimized for all devices
- React 18.2 - Modern React with concurrent features
- TypeScript 5.9 - Type-safe development
- React Router 6 - Client-side routing
- WSO2 Oxygen UI 0.2.1 - WSO2's official design system
- Built on Material-UI v7.3.7
- Includes pre-built WSO2 themes (OxygenTheme, AcrylicOrangeTheme, etc.)
- Provides
OxygenUIThemeProviderfor theme management - Re-exports all MUI components and utilities
- @wso2/oxygen-ui-icons-react - Lucide icon set for React
- @emotion/react & @emotion/styled - CSS-in-JS styling
- Create React App - Zero-config build setup
- react-app-rewired - Custom webpack configuration
- TypeScript Compiler - Type checking and compilation
{
"@wso2/oxygen-ui": "^0.2.1",
"@wso2/oxygen-ui-icons-react": "^0.2.1",
"@mui/material": "^7.3.7",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"react": "^18.2.0",
"react-router-dom": "^6.29.0",
"typescript": "^5.9.3"
}- Node.js: 18.0 or higher
- npm: 9.0 or higher (or yarn/pnpm)
- Git: For version control
# Clone the repository
git clone <repository-url>
cd integration-store
# Install dependencies
npm install
# Start development server
npm startOpen http://localhost:3000 to view the application.
npm start
# or
npm run devStarts the development server on http://localhost:3000 with hot-reload.
npm run buildCreates an optimized production build in the build/ folder.
Sitemap Generation (Optional): By default, the build process skips sitemap generation. To generate a sitemap with connector URLs:
# Generate sitemap before building
GENERATE_SITEMAP=true npm run build
# Or generate sitemap separately
npm run generate-sitemap
# Override production domain if needed (defaults to https://wso2.com/integration-platform/connectors)
SITE_URL=https://yourdomain.com npm run generate-sitemapFor CI/CD pipelines, set the GENERATE_SITEMAP=true environment variable:
# GitHub Actions example
- name: Build with sitemap
run: npm run build
env:
GENERATE_SITEMAP: true
SITE_URL: https://yourdomain.com# After building
npx serve -s buildServes the production build locally on port 3000.
npx tsc --noEmitRuns TypeScript type checking without emitting files.
npm run lint # Check for issues
npm run lint:fix # Auto-fix issuesRuns ESLint checks on the codebase.
npm run format # Format all files
npm run format:check # Check formattingRuns Prettier formatting.
wso2-integration-store/
├── public/
│ ├── index.html # HTML entry point
│ ├── manifest.json # PWA manifest
│ ├── _redirects # SPA routing config (Netlify/Vercel)
│ └── images/
│ ├── wso2-logo.svg # WSO2 official logo
│ └── wso2-integrator-correct.svg # Integrator icon
├── src/
│ ├── index.tsx # React entry point
│ ├── App.tsx # Root component with router
│ ├── pages/
│ │ └── HomePage.tsx # Main Integration store page
│ ├── components/
│ │ ├── ConnectorCard/
│ │ │ ├── ConnectorCard.tsx # Individual connector card
│ │ │ └── ConnectorCard.test.tsx
│ │ ├── FilterSidebar/
│ │ │ └── FilterSidebar.tsx # Filter panel (Area/Vendor)
│ │ ├── Pagination/
│ │ │ ├── Pagination.tsx # Pagination controls
│ │ │ └── Pagination.test.tsx
│ │ ├── SearchBar/
│ │ │ ├── SearchBar.tsx # Search input
│ │ │ └── SearchBar.test.tsx
│ │ ├── SortSelector/
│ │ │ └── SortSelector.tsx # Sort dropdown
│ │ ├── ThemeProvider/
│ │ │ └── ThemeProvider.tsx # (Deprecated - using Oxygen UI)
│ │ ├── ThemeToggle/
│ │ │ └── ThemeToggle.tsx # (Deprecated - using ColorSchemeToggle)
│ │ └── WSO2Header/
│ │ └── WSO2Header.tsx # Branded header with Oxygen UI
│ ├── lib/
│ │ ├── rest-client.ts # REST API integration with retry logic
│ │ ├── connector-utils.ts # Utility functions (filter/sort)
│ │ └── graphql-client.ts # (Deprecated) Legacy GraphQL client
│ ├── styles/
│ │ └── globals.css # Global styles
│ └── types/
│ └── connector.ts # TypeScript type definitions
├── .docs/ # Comprehensive documentation
│ ├── AI-README.md # AI-focused implementation guide
│ ├── FINAL-SOLUTION.md # Performance optimization details
│ ├── TESTING-GUIDE.md # Testing instructions
│ ├── URL-ROUTING.md # URL structure documentation
│ └── VERCEL-BUILD-WARNINGS.md # Build warnings explained
├── .gitignore
├── .npmrc # npm configuration (legacy-peer-deps)
├── config-overrides.js # Webpack customization
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── vercel.json # Vercel deployment config
└── README.md # This file
No environment variables required. The application uses public Ballerina Central APIs.
File: .npmrc
legacy-peer-deps=true
Required to resolve TypeScript 5.x peer dependency conflicts with react-scripts 5.0.1.
File: config-overrides.js
Custom webpack configuration for Create React App (using react-app-rewired).
Includes:
- Module resolution fix for prismjs ESM compatibility
- Handles
.mjsfiles from dependencies properly
File: vercel.json
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}Enables client-side routing for single-page application.
Implementation: src/App.tsx
The application uses WSO2 Oxygen UI's theme system:
import { OxygenUIThemeProvider, extendTheme, OxygenTheme } from '@wso2/oxygen-ui';
// Create custom theme by extending OxygenTheme
const theme = extendTheme(OxygenTheme);
// Wrap app with theme provider
<OxygenUIThemeProvider themes={[{ key: 'default', label: 'Default', theme }]}>
{/* App content */}
</OxygenUIThemeProvider>WSO2 Brand Colors (from OxygenTheme):
- Primary Orange:
#ff7300 - Background Light:
#f7f8fb - Background Dark: Oxygen UI's dark theme palette
- Text Primary:
#000000/#ffffff - Text Secondary:
#494848/#cccccc
Typography:
- Font: Plus Jakarta Sans (bundled with Oxygen UI)
- Automatically imported via Oxygen UI's font system
Endpoint: https://api.central.ballerina.io/2.0/registry/search-packages
Primary Data Source: All connector data, filtering, sorting, and pagination are handled server-side via the REST API.
Query Parameters:
q: Solr query string (e.g., "org:ballerinax AND keyword:Area/Finance")
offset: Pagination offset (0-based)
limit: Items per page (10, 30, 50, 100)
sort: Sort parameter (e.g., "pullCount,DESC", "name,ASC")
readme: false (exclude README content)
Example Request:
curl 'https://api.central.ballerina.io/2.0/registry/search-packages?q=org:ballerinax%20AND%20keyword:Area/Finance&offset=0&limit=30&sort=pullCount,DESC&readme=false'Response Structure:
{
"packages": [
{
"name": "string",
"version": "string",
"URL": "string",
"summary": "string",
"keywords": ["string"],
"icon": "string",
"createdDate": "string",
"pullCount": number
}
],
"count": number,
"offset": number,
"limit": number
}Key Features:
- Server-side filtering: Solr query language for powerful filtering
- Server-side sorting: Sort by name, pullCount, or createdDate
- Server-side pagination: Offset/limit based pagination
- Pull counts included: No separate enrichment queries needed
- Scalable: Handles unlimited number of connectors
Filter Logic:
- AND between filter types: Area AND Vendor AND Type
- OR within filter type: Area/Finance OR Area/Health
- Implementation: Multiple parallel queries merged for OR logic
Example Queries:
# Single filter
org:ballerinax AND keyword:Area/Finance
# Multiple filter types (AND)
org:ballerinax AND keyword:Area/Finance AND keyword:Vendor/Amazon
# Multiple values same type (OR via parallel queries)
Query 1: org:ballerinax AND keyword:Area/Finance
Query 2: org:ballerinax AND keyword:Area/Health
Results: Merged and deduplicated
# Text search with filters
graphql AND org:ballerinax AND keyword:Area/Database
24-Hour localStorage Cache:
interface CachedFilters {
filters: FilterOptions;
timestamp: number;
}
const FILTER_CACHE_KEY = 'ballerina_connector_filters';
const FILTER_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hoursBenefits:
- Instant filter display on subsequent visits
- Reduces API load for filter discovery
- Automatic cache invalidation after 24 hours
All API requests include automatic retry with exponential backoff:
- Search requests: 3 retry attempts (1s, 2s, 4s delays)
- Filter fetch: 3 retry attempts (1s, 2s, 4s delays)
- Graceful degradation: Works with partial data if some requests fail
See .docs/LATEST_UPDATES.md for migration details.
User Visits Page
↓
┌─────────────────────────────────────┐
│ 1. Initial Load (0-2s) │
│ - Fetch first page (30 items) │
│ - Fetch first 100 for filters │
│ - Display page immediately │
│ - Pull counts included in data │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 2. Background Filter Load (2-3s) │
│ - Fetch remaining packages │
│ - Extract complete filter list │
│ - Cache in localStorage (24h) │
│ - Update filter options │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ User Interactions │
│ - Filter change: API call (~500ms) │
│ - Sort change: API call (~500ms) │
│ - Page change: API call (~500ms) │
│ - Search: API call (~500ms) │
│ All operations server-side │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Subsequent Visits │
│ - Filters load from cache (instant)│
│ - First page loads via API (~500ms)│
│ - No background fetching needed │
└─────────────────────────────────────┘
- Page visible: ~2 seconds (filters + first page)
- Filters cached: Instant on subsequent visits
- Total interactive: ~2 seconds
- Filter/Sort/Page changes: ~500ms (server-side)
- Current page only: ~2MB (30 items)
- vs Previous (GraphQL): ~50MB (800+ items)
- Memory reduction: 96% less memory usage
- Scalability: Handles unlimited connectors
- Initial requests: 2 (first page + filter batch)
- Filter caching: 24-hour localStorage cache
- Background requests: 1-2 (complete filter list)
- User interactions: 1 request per action (filter/sort/page)
- Total: 2-4 requests vs 10-24 (GraphQL)
- Retry logic: 3 attempts per request
- Exponential backoff: 1s, 2s, 4s delays
- Graceful degradation: Works with partial data
- Error recovery: 95%+ success rate even with network issues
- Initial load: ~2s (server-side operations)
- Page changes: ~500ms (API call)
- Filter changes: ~500ms (API call)
- Sort changes: ~500ms (API call)
- Search: ~500ms (API call)
- Cached filters: Instant (localStorage)
- First Load JS: ~300KB (React 19, MUI, React Router)
- CSS: ~50KB
- Total: <350KB (removed GraphQL dependencies)
- Lazy loading: Connector images load on demand
See .docs/LATEST_UPDATES.md for migration details.
Framework Preset: Create React App
Configuration:
- Connect your Git repository to Vercel
- Set Framework Preset to "Create React App"
- Deploy
Files required:
.npmrc- Resolves TypeScript peer dependency conflictsvercel.json- Enables client-side routing
Build Command: npm run build
Output Directory: build
Build Settings:
- Build Command:
npm run build - Publish Directory:
build - Redirects: Configured in
public/_redirects
Dockerfile:
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
COPY .npmrc ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]nginx.conf:
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}Build and Run:
docker build -t wso2-integration-store .
docker run -p 80:80 wso2-integration-storeThe app is a static SPA and can be hosted on any static hosting service:
- AWS S3 + CloudFront
- Azure Static Web Apps
- GitHub Pages (with routing config)
- Google Cloud Storage
Important: Configure the host to redirect all routes to index.html for client-side routing.
The application uses URL-based navigation for bookmarkable, shareable links.
Base URL:
https://your-domain.com/
Query Parameters:
| Parameter | Values | Default | Description |
|---|---|---|---|
page |
1, 2, 3... | 1 | Current page number |
size |
10, 30, 50, 100 | 30 | Items per page |
search |
string | - | Search query |
areas |
comma-separated | - | Selected area filters |
vendors |
comma-separated | - | Selected vendor filters |
types |
comma-separated | - | Selected type filters |
sort |
pullCount-desc, pullCount-asc, date-desc, date-asc, name-asc, name-desc | pullCount-desc | Sort option |
Example URLs:
# Page 2, default settings
/?page=2
# Search for "salesforce"
/?search=salesforce
# Filter by Finance area
/?areas=Finance
# Multiple filters
/?areas=Finance,Health&vendors=AWS,Salesforce
# Most popular, page size 50
/?sort=pullCount-desc&size=50
# With type filter
/?types=Connector
# Complete example
/?page=2&size=50&search=api&areas=Finance&vendors=AWS&types=Connector&sort=pullCount-desc
See .docs/URL-ROUTING.md for complete documentation.
- New Component: Add to
src/components/ - New Utility: Add to
src/lib/ - New Type: Add to
src/types/ - New Page: Add to
src/pages/and update router inApp.tsx
- TypeScript strict mode enabled
- Functional components with hooks
- CSS-in-JS with Material-UI
sxprop - Descriptive variable names
- ESLint + Prettier for consistent formatting
- Always use TypeScript types
- Memoize expensive computations (
useMemo,memo) - Use refs for non-rendering state
- Keep components focused and small
- Use semantic HTML
- Ensure accessibility (ARIA labels, keyboard navigation)
- Avoid unnecessary re-renders
- Separate data loading from UI updates
- Use
useReffor tracking state that doesn't need re-renders - Implement smart loading strategies (visible items first)
- Add retry logic for network operations
- Handle partial failures gracefully
- Connectors load correctly (~2s)
- Download counts appear (~5s)
- Search works across all fields
- All filters work (Area, Vendor)
- Sorting changes order correctly
- Pagination navigates properly
- Page size changes work
- Card links open Ballerina Central
- URL parameters update correctly
- Bookmarked URLs restore state
- Header displays correctly
- Dark/light mode toggle works
- Responsive on mobile/tablet/desktop
- Smooth scrolling on page change
- Loading states show properly
- Empty states display correctly
- No layout shifts during load
- Page loads in ~2 seconds
- Download counts appear in ~5 seconds
- Zero layout shift (CLS = 0)
- Filters/sort are instant
- No console errors
- Works on slow network (Slow 3G)
- Handles offline gracefully
- Displays error message on complete failure
- Retries failed requests automatically
- Works with partial data if some requests fail
- Background enrichment fails silently
See .docs/TESTING-GUIDE.md for detailed testing instructions.
# Clear cache and rebuild
rm -rf build node_modules package-lock.json
npm install
npm run buildIf you see TypeScript version conflicts during deployment:
# Ensure .npmrc exists with:
legacy-peer-deps=trueSee .docs/VERCEL-BUILD-WARNINGS.md for detailed explanation.
REST API Issues:
- Check: https://api.central.ballerina.io/2.0/registry/search-packages
- Verify network tab for errors
- Look for retry attempts in console (3 attempts with exponential backoff)
Network Failures:
- Application automatically retries failed requests (3 attempts)
- Check console for "retry attempt" messages
- Verify internet connection
Connector icons not loading:
- Check that icons exist at
https://bcentral-packageicons.azureedge.net/ - Check network tab for blocked requests
- Verify CORS policy
# Analyze bundle size
npm run build
ls -lh build/static/js/
# Check for large dependencies
npx source-map-explorer build/static/js/*.js
# Profile in Chrome DevTools
# Performance tab → Record → Analyze"Failed to load connectors" error:
- Network issue or API temporarily down
- Application will automatically retry 3 times
- Check console for detailed error messages
Layout shifts during load:
- Verify default sort is "Most Popular"
- Check that API returns items in date-desc order
- Review console for unexpected state updates
"Most Popular" sort slow:
- First time: Needs to enrich 100 items (~2s)
- Subsequent times: Should be instant (cached)
- Check network tab for enrichment requests
.docs/AI-README.md- Comprehensive implementation guide for AI assistants.docs/FINAL-SOLUTION.md- Performance optimization details and trade-offs.docs/TESTING-GUIDE.md- Detailed testing procedures and checklist.docs/URL-ROUTING.md- URL structure and parameter documentation.docs/VERCEL-BUILD-WARNINGS.md- Build warning explanations and fixes
The application uses a 4-phase loading strategy:
- Fast Initial Load (0-2s) - First 100 connectors
- Background Load (2-4s) - Remaining connectors in parallel
- Visible Enrichment (4-5s) - Download counts for first 30 items
- Background Enrichment (5s+) - Download counts for remaining items
This approach provides:
- Fast time-to-interactive (~2s)
- Zero layout shift (CLS = 0)
- Complete data within ~5s
- Graceful degradation on errors
Major Architecture Migration:
- GraphQL to REST: Migrated from GraphQL to REST API for all operations
- Server-Side Operations: Filtering, sorting, and pagination now server-side
- Next.js to React: Migrated from Next.js to React 19 with Create React App
- Memory Optimization: 96% reduction in memory usage (50MB → 2MB)
- Progressive Filter Loading: 24-hour localStorage cache for instant filter display
- Type Filter Added: Third filter dimension alongside Area and Vendor
- Expandable Descriptions: "Show more" button for long connector summaries
- Default Sort Changed: Most Popular First instead of Newest First
- Improved Loading UX: Overlay instead of full page re-render on filter changes
- Clear All Filters: Badge showing active filter count with one-click clear
Performance Impact:
- Same ~2s initial load time
- 96% less memory (2MB vs 50MB)
- Scalable to unlimited connectors
- Filter changes: ~500ms (was instant, but now server-side)
Technical Details:
- New REST client with Solr query building
- Parallel API calls for OR logic within filter types
- AND logic between different filter types
- Retry logic with exponential backoff preserved
Major Performance Overhaul:
- Reduced stable load time by 60% (14s → 6s)
- Eliminated layout shifts (CLS: 3 → 0)
- Added retry logic with exponential backoff
- Implemented graceful degradation for partial failures
- Reduced GraphQL requests by 58% (24 → 10)
- Added URL-based navigation with shareable links
- Migrated to React 19 and Material-UI 7
Bug Fixes:
- Fixed re-render loops on sort change
- Fixed TypeScript peer dependency conflicts
- Resolved Vercel deployment issues
- Fixed header to show "WSO2 Integration Store"
- Fixed card links to point to Ballerina Central package pages
- Implemented efficient total pull count aggregation
- Added sort functionality (6 options)
- Improved header design (sticky, better dark mode)
- Made search bar smaller and better positioned
- Added pagination with page size selector
- Added WSO2 branding (exact colors, fonts, logo)
- Created WSO2 header component
- Added scroll-to-top on pagination
- Initial release with basic functionality
- GraphQL integration
- Filtering by Area, Vendor
- Real-time search
- Dark/light themes
This is a WSO2 internal project. For contributions:
- Create a feature branch
- Make your changes
- Test thoroughly (see
.docs/TESTING-GUIDE.md) - Ensure no TypeScript errors (
npx tsc --noEmit) - Format code (
npm run format) - Lint code (
npm run lint) - Submit a pull request
Part of the WSO2 ecosystem. Copyright (c) WSO2 Inc.
- WSO2 Integrator
- Ballerina Central
- React Documentation
- Material-UI Documentation
- Create React App Documentation
For issues, questions, or feature requests:
- Review documentation in
.docs/directory - Check troubleshooting section above
- Review console for error messages
- Contact WSO2 development team
Built by the WSO2 Team
Powered by React, TypeScript, Material-UI, and the Ballerina Central REST API