feat: add PlatformSettings for pagination and vendor filter improvements
Platform Settings: - Add PlatformSettings utility in init-alpine.js with 5-min cache - Add Display tab in /admin/settings for rows_per_page config - Integrate PlatformSettings.getRowsPerPage() in all paginated pages - Standardize default per_page to 20 across all admin pages - Add documentation at docs/frontend/shared/platform-settings.md Architecture Rules: - Add JS-010: enforce PlatformSettings usage for pagination - Add JS-011: enforce standard pagination structure - Add JS-012: detect double /api/v1 prefix in apiClient calls - Implement all rules in validate_architecture.py Vendor Filter (Tom Select): - Add vendor filter to marketplace-products, vendor-products, customers, inventory, and vendor-themes pages - Add selectedVendor display panel with clear button - Add localStorage persistence for vendor selection - Fix double /api/v1 prefix in vendor-selector.js Bug Fixes: - Remove duplicate PlatformSettings from utils.js - Fix customers.js pagination structure (page_size → per_page) - Fix code-quality-violations.js pagination structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
363
docs/frontend/shared/platform-settings.md
Normal file
363
docs/frontend/shared/platform-settings.md
Normal file
@@ -0,0 +1,363 @@
|
||||
# Platform Settings Integration
|
||||
|
||||
> **Version:** 1.0
|
||||
> **Last Updated:** December 2024
|
||||
> **Audience:** Frontend Developers
|
||||
|
||||
## Overview
|
||||
|
||||
Platform Settings provides a centralized configuration system for admin and vendor frontend applications. Settings are stored in the database and cached client-side for performance. This ensures consistent behavior across all pages while allowing administrators to customize the platform.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Centralized Configuration**: All display settings in one place (`/admin/settings`)
|
||||
- **Client-Side Caching**: 5-minute cache to minimize API calls
|
||||
- **Automatic Integration**: Easy integration with existing page patterns
|
||||
- **Admin Configurable**: Settings can be changed without code deployment
|
||||
|
||||
## Available Settings
|
||||
|
||||
| Setting | Description | Default | Options |
|
||||
|---------|-------------|---------|---------|
|
||||
| `rows_per_page` | Number of items per page in tables | 20 | 10, 20, 50, 100 |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Platform Settings in Your Page
|
||||
|
||||
```javascript
|
||||
async init() {
|
||||
// Guard against multiple initialization
|
||||
if (window._myPageInitialized) return;
|
||||
window._myPageInitialized = true;
|
||||
|
||||
// Load platform settings for rows per page
|
||||
if (window.PlatformSettings) {
|
||||
this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
|
||||
}
|
||||
|
||||
// Continue with page initialization...
|
||||
await this.loadData();
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### PlatformSettings Object
|
||||
|
||||
The `PlatformSettings` utility is available globally via `window.PlatformSettings`.
|
||||
|
||||
#### Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `get()` | `Promise<Object>` | Get all cached settings or fetch from API |
|
||||
| `getRowsPerPage()` | `Promise<number>` | Get the rows per page setting |
|
||||
| `clearCache()` | `void` | Clear the cached settings |
|
||||
|
||||
#### Example Usage
|
||||
|
||||
```javascript
|
||||
// Get rows per page
|
||||
const rowsPerPage = await window.PlatformSettings.getRowsPerPage();
|
||||
|
||||
// Get all settings
|
||||
const settings = await window.PlatformSettings.get();
|
||||
console.log(settings.rows_per_page);
|
||||
|
||||
// Clear cache (call after saving settings)
|
||||
window.PlatformSettings.clearCache();
|
||||
```
|
||||
|
||||
## Implementation Pattern
|
||||
|
||||
### Standard Pagination State Structure
|
||||
|
||||
All pages with tables should use this standard pagination structure:
|
||||
|
||||
```javascript
|
||||
function adminMyPage() {
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'my-page',
|
||||
|
||||
// Standard pagination structure
|
||||
pagination: {
|
||||
page: 1,
|
||||
per_page: 20, // Will be overridden by platform settings
|
||||
total: 0,
|
||||
pages: 0
|
||||
},
|
||||
|
||||
async init() {
|
||||
if (window._adminMyPageInitialized) return;
|
||||
window._adminMyPageInitialized = true;
|
||||
|
||||
// REQUIRED: Load platform settings for pagination
|
||||
if (window.PlatformSettings) {
|
||||
this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
|
||||
}
|
||||
|
||||
await this.loadData();
|
||||
},
|
||||
|
||||
async loadData() {
|
||||
const params = new URLSearchParams({
|
||||
skip: ((this.pagination.page - 1) * this.pagination.per_page).toString(),
|
||||
limit: this.pagination.per_page.toString()
|
||||
});
|
||||
|
||||
const response = await apiClient.get(`/admin/my-endpoint?${params}`);
|
||||
this.items = response.items;
|
||||
this.pagination.total = response.total;
|
||||
this.pagination.pages = Math.ceil(this.pagination.total / this.pagination.per_page);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Computed Properties for Pagination
|
||||
|
||||
Include these computed properties for the pagination macro:
|
||||
|
||||
```javascript
|
||||
// Computed: Total pages
|
||||
get totalPages() {
|
||||
return this.pagination.pages;
|
||||
},
|
||||
|
||||
// Computed: Start index for pagination display
|
||||
get startIndex() {
|
||||
if (this.pagination.total === 0) return 0;
|
||||
return (this.pagination.page - 1) * this.pagination.per_page + 1;
|
||||
},
|
||||
|
||||
// Computed: End index for pagination display
|
||||
get endIndex() {
|
||||
const end = this.pagination.page * this.pagination.per_page;
|
||||
return end > this.pagination.total ? this.pagination.total : end;
|
||||
},
|
||||
|
||||
// Computed: Page numbers for pagination
|
||||
get pageNumbers() {
|
||||
const pages = [];
|
||||
const totalPages = this.totalPages;
|
||||
const current = this.pagination.page;
|
||||
|
||||
if (totalPages <= 7) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
pages.push(1);
|
||||
if (current > 3) pages.push('...');
|
||||
const start = Math.max(2, current - 1);
|
||||
const end = Math.min(totalPages - 1, current + 1);
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
if (current < totalPages - 2) pages.push('...');
|
||||
pages.push(totalPages);
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation Methods
|
||||
|
||||
```javascript
|
||||
previousPage() {
|
||||
if (this.pagination.page > 1) {
|
||||
this.pagination.page--;
|
||||
this.loadData();
|
||||
}
|
||||
},
|
||||
|
||||
nextPage() {
|
||||
if (this.pagination.page < this.totalPages) {
|
||||
this.pagination.page++;
|
||||
this.loadData();
|
||||
}
|
||||
},
|
||||
|
||||
goToPage(pageNum) {
|
||||
if (typeof pageNum === 'number' && pageNum !== this.pagination.page) {
|
||||
this.pagination.page = pageNum;
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Correct vs Incorrect Patterns
|
||||
|
||||
### Loading Platform Settings
|
||||
|
||||
```javascript
|
||||
// CORRECT: Load platform settings in init()
|
||||
async init() {
|
||||
if (window.PlatformSettings) {
|
||||
this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
|
||||
}
|
||||
await this.loadData();
|
||||
}
|
||||
|
||||
// INCORRECT: Hardcoding pagination values
|
||||
async init() {
|
||||
this.pagination.per_page = 50; // Don't hardcode!
|
||||
await this.loadData();
|
||||
}
|
||||
```
|
||||
|
||||
### Pagination Structure
|
||||
|
||||
```javascript
|
||||
// CORRECT: Standard nested pagination object
|
||||
pagination: {
|
||||
page: 1,
|
||||
per_page: 20,
|
||||
total: 0,
|
||||
pages: 0
|
||||
}
|
||||
|
||||
// INCORRECT: Flat pagination variables
|
||||
page: 1,
|
||||
limit: 20,
|
||||
total: 0,
|
||||
skip: 0
|
||||
```
|
||||
|
||||
### API Calls with Pagination
|
||||
|
||||
```javascript
|
||||
// CORRECT: Use pagination object properties
|
||||
const params = new URLSearchParams({
|
||||
skip: ((this.pagination.page - 1) * this.pagination.per_page).toString(),
|
||||
limit: this.pagination.per_page.toString()
|
||||
});
|
||||
|
||||
// INCORRECT: Hardcoded values
|
||||
const params = new URLSearchParams({
|
||||
skip: '0',
|
||||
limit: '50' // Don't hardcode!
|
||||
});
|
||||
```
|
||||
|
||||
## Admin Settings Page
|
||||
|
||||
The rows per page setting can be configured at `/admin/settings` under the **Display** tab.
|
||||
|
||||
### Available Options
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| 10 | Compact view, good for slow connections |
|
||||
| 20 | Default, balanced view |
|
||||
| 50 | Extended view, fewer page loads |
|
||||
| 100 | Maximum view, best for power users |
|
||||
|
||||
## Caching Behavior
|
||||
|
||||
### How Caching Works
|
||||
|
||||
1. **First Access**: API call to `/admin/settings/display/public`
|
||||
2. **Subsequent Access**: Returns cached value (within 5-minute TTL)
|
||||
3. **Cache Expiry**: After 5 minutes, next access fetches fresh data
|
||||
4. **Manual Clear**: Call `PlatformSettings.clearCache()` after saving settings
|
||||
|
||||
### Cache Storage
|
||||
|
||||
Settings are cached in `localStorage` under the key `platform_settings_cache`:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"rows_per_page": 20
|
||||
},
|
||||
"timestamp": 1703123456789
|
||||
}
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Get Display Settings (Public)
|
||||
|
||||
```
|
||||
GET /api/v1/admin/settings/display/public
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"rows_per_page": 20
|
||||
}
|
||||
```
|
||||
|
||||
### Get Rows Per Page (Authenticated)
|
||||
|
||||
```
|
||||
GET /api/v1/admin/settings/display/rows-per-page
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"rows_per_page": 20
|
||||
}
|
||||
```
|
||||
|
||||
### Update Rows Per Page
|
||||
|
||||
```
|
||||
PUT /api/v1/admin/settings/display/rows-per-page?rows=50
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"rows_per_page": 50,
|
||||
"message": "Rows per page setting updated"
|
||||
}
|
||||
```
|
||||
|
||||
## Pages Using Platform Settings
|
||||
|
||||
The following pages currently integrate with platform settings:
|
||||
|
||||
### Admin Pages
|
||||
- `/admin/orders` - Orders management
|
||||
- `/admin/marketplace-products` - Marketplace product catalog
|
||||
- `/admin/vendor-products` - Vendor product catalog
|
||||
- `/admin/customers` - Customer management
|
||||
- `/admin/inventory` - Inventory management
|
||||
|
||||
### Vendor Pages
|
||||
- (Future) All vendor table pages should follow the same pattern
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Settings Not Loading
|
||||
|
||||
1. Check browser console for errors
|
||||
2. Verify `window.PlatformSettings` is available
|
||||
3. Check network tab for API call to `/settings/display/public`
|
||||
|
||||
### Cache Not Clearing
|
||||
|
||||
```javascript
|
||||
// Force clear cache manually
|
||||
localStorage.removeItem('platform_settings_cache');
|
||||
```
|
||||
|
||||
### Wrong Default Value
|
||||
|
||||
If `PlatformSettings` fails to load, pages fall back to their hardcoded default (typically 20). Check:
|
||||
|
||||
1. API endpoint is accessible
|
||||
2. User has authentication (if required)
|
||||
3. No CORS issues
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Pagination Components](pagination.md) - Pagination macro usage
|
||||
- [Admin Architecture](../admin/architecture.md) - Admin frontend patterns
|
||||
- [Logging System](logging.md) - Frontend logging configuration
|
||||
Reference in New Issue
Block a user