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:
@@ -24,6 +24,13 @@ function adminVendorThemes() {
|
||||
vendors: [],
|
||||
selectedVendorCode: '',
|
||||
|
||||
// Selected vendor for filter (Tom Select)
|
||||
selectedVendor: null,
|
||||
vendorSelector: null,
|
||||
|
||||
// Search/filter
|
||||
searchQuery: '',
|
||||
|
||||
async init() {
|
||||
// Guard against multiple initialization
|
||||
if (window._adminVendorThemesInitialized) {
|
||||
@@ -31,13 +38,86 @@ function adminVendorThemes() {
|
||||
}
|
||||
window._adminVendorThemesInitialized = true;
|
||||
|
||||
// Call parent init first
|
||||
const parentInit = data().init;
|
||||
if (parentInit) {
|
||||
await parentInit.call(this);
|
||||
vendorThemesLog.info('Vendor Themes init() called');
|
||||
|
||||
// Initialize vendor selector (Tom Select)
|
||||
this.$nextTick(() => {
|
||||
this.initVendorSelector();
|
||||
});
|
||||
|
||||
// Check localStorage for saved vendor
|
||||
const savedVendorId = localStorage.getItem('vendor_themes_selected_vendor_id');
|
||||
if (savedVendorId) {
|
||||
vendorThemesLog.info('Restoring saved vendor:', savedVendorId);
|
||||
await this.loadVendors();
|
||||
// Restore vendor after vendors are loaded
|
||||
setTimeout(async () => {
|
||||
await this.restoreSavedVendor(parseInt(savedVendorId));
|
||||
}, 200);
|
||||
} else {
|
||||
await this.loadVendors();
|
||||
}
|
||||
|
||||
await this.loadVendors();
|
||||
vendorThemesLog.info('Vendor Themes initialization complete');
|
||||
},
|
||||
|
||||
/**
|
||||
* Restore saved vendor from localStorage
|
||||
*/
|
||||
async restoreSavedVendor(vendorId) {
|
||||
try {
|
||||
const vendor = await apiClient.get(`/admin/vendors/${vendorId}`);
|
||||
if (this.vendorSelector && vendor) {
|
||||
// Use the vendor selector's setValue method
|
||||
this.vendorSelector.setValue(vendor.id, vendor);
|
||||
|
||||
// Set the filter state
|
||||
this.selectedVendor = vendor;
|
||||
|
||||
vendorThemesLog.info('Restored vendor:', vendor.name);
|
||||
}
|
||||
} catch (error) {
|
||||
vendorThemesLog.warn('Failed to restore saved vendor, clearing localStorage:', error);
|
||||
localStorage.removeItem('vendor_themes_selected_vendor_id');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize vendor selector with Tom Select
|
||||
*/
|
||||
initVendorSelector() {
|
||||
if (!this.$refs.vendorSelect) {
|
||||
vendorThemesLog.warn('Vendor select element not found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.vendorSelector = initVendorSelector(this.$refs.vendorSelect, {
|
||||
placeholder: 'Search vendor...',
|
||||
onSelect: (vendor) => {
|
||||
vendorThemesLog.info('Vendor selected:', vendor);
|
||||
this.selectedVendor = vendor;
|
||||
// Save to localStorage
|
||||
localStorage.setItem('vendor_themes_selected_vendor_id', vendor.id.toString());
|
||||
},
|
||||
onClear: () => {
|
||||
vendorThemesLog.info('Vendor filter cleared');
|
||||
this.selectedVendor = null;
|
||||
// Clear from localStorage
|
||||
localStorage.removeItem('vendor_themes_selected_vendor_id');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear vendor filter
|
||||
*/
|
||||
clearVendorFilter() {
|
||||
if (this.vendorSelector) {
|
||||
this.vendorSelector.clear();
|
||||
}
|
||||
this.selectedVendor = null;
|
||||
// Clear from localStorage
|
||||
localStorage.removeItem('vendor_themes_selected_vendor_id');
|
||||
},
|
||||
|
||||
async loadVendors() {
|
||||
@@ -56,6 +136,28 @@ function adminVendorThemes() {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Computed: Filtered vendors based on search and selected vendor
|
||||
*/
|
||||
get filteredVendors() {
|
||||
let filtered = this.vendors;
|
||||
|
||||
// If a vendor is selected via Tom Select, show only that vendor
|
||||
if (this.selectedVendor) {
|
||||
filtered = this.vendors.filter(v => v.id === this.selectedVendor.id);
|
||||
}
|
||||
// Otherwise filter by search query
|
||||
else if (this.searchQuery) {
|
||||
const query = this.searchQuery.toLowerCase();
|
||||
filtered = this.vendors.filter(v =>
|
||||
v.name.toLowerCase().includes(query) ||
|
||||
(v.vendor_code && v.vendor_code.toLowerCase().includes(query))
|
||||
);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
},
|
||||
|
||||
navigateToTheme() {
|
||||
if (!this.selectedVendorCode) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user