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:
2025-12-22 22:39:34 +01:00
parent 1274135091
commit 6f8434f200
27 changed files with 1966 additions and 303 deletions

View File

@@ -145,6 +145,143 @@ javascript_rules:
exceptions:
- "utils.js"
- id: "JS-010"
name: "Use PlatformSettings for pagination rows per page"
severity: "error"
description: |
All pages with tables MUST use window.PlatformSettings.getRowsPerPage()
to load the platform-configured rows per page setting. This ensures
consistent pagination behavior across the entire admin and vendor interface.
The setting is configured at /admin/settings under the Display tab.
Settings are cached client-side for 5 minutes to minimize API calls.
Required pattern in init() method:
async init() {
// Guard against multiple initialization
if (window._pageNameInitialized) return;
window._pageNameInitialized = true;
// REQUIRED: Load platform settings for pagination
if (window.PlatformSettings) {
this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
}
await this.loadData();
}
WRONG (hardcoded pagination):
pagination: {
page: 1,
per_page: 50, // Hardcoded!
total: 0
}
RIGHT (platform settings):
pagination: {
page: 1,
per_page: 20, // Default, overridden by PlatformSettings
total: 0
}
async init() {
if (window.PlatformSettings) {
this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
}
}
Documentation: docs/frontend/shared/platform-settings.md
pattern:
file_pattern: "static/admin/js/**/*.js"
required_in_pages_with_pagination:
- "PlatformSettings\\.getRowsPerPage"
- "window\\.PlatformSettings"
exceptions:
- "init-alpine.js"
- "init-api-client.js"
- "settings.js"
- id: "JS-011"
name: "Use standard pagination object structure"
severity: "error"
description: |
All pages with tables MUST use the standard nested pagination object
structure. This ensures compatibility with the pagination macro and
consistent behavior across all pages.
REQUIRED structure:
pagination: {
page: 1,
per_page: 20,
total: 0,
pages: 0
}
WRONG (flat structure):
page: 1,
limit: 20,
total: 0,
skip: 0
WRONG (different property names):
pagination: {
currentPage: 1,
itemsPerPage: 20
}
Required computed properties:
- totalPages
- startIndex
- endIndex
- pageNumbers
Required methods:
- previousPage()
- nextPage()
- goToPage(pageNum)
Documentation: docs/frontend/shared/pagination.md
pattern:
file_pattern: "static/**/js/**/*.js"
required_in_pages_with_pagination:
- "pagination:"
- "pagination\\.page"
- "pagination\\.per_page"
anti_patterns_in_pagination_pages:
- "^\\s*page:\\s*\\d"
- "^\\s*limit:\\s*\\d"
- "^\\s*skip:\\s*"
exceptions:
- "init-alpine.js"
- id: "JS-012"
name: "Do not include /api/v1 prefix in API endpoints"
severity: "error"
description: |
When using apiClient.get(), apiClient.post(), etc., do NOT include
the /api/v1 prefix in the endpoint path. The apiClient automatically
prepends this prefix.
CORRECT:
apiClient.get('/admin/vendors')
apiClient.post('/admin/products')
const apiEndpoint = '/admin/vendors'
WRONG (causes double prefix /api/v1/api/v1/...):
apiClient.get('/api/v1/admin/vendors')
const apiEndpoint = '/api/v1/admin/vendors'
Exception: Direct fetch() calls without apiClient should use full path.
Documentation: docs/frontend/shared/api-client.md
pattern:
file_pattern: "static/**/js/**/*.js"
anti_patterns:
- "apiClient\\.(get|post|put|delete|patch)\\s*\\(\\s*['\"`]/api/v1"
- "apiEndpoint.*=.*['\"`]/api/v1"
exceptions:
- "init-api-client.js"
# ============================================================================
# TEMPLATE RULES (Jinja2)
# ============================================================================