feat: add logging, marketplace, and admin enhancements

Database & Migrations:
- Add application_logs table migration for hybrid cloud logging
- Add companies table migration and restructure vendor relationships

Logging System:
- Implement hybrid logging system (database + file)
- Add log_service for centralized log management
- Create admin logs page with filtering and viewing capabilities
- Add init_log_settings.py script for log configuration
- Enhance core logging with database integration

Marketplace Integration:
- Add marketplace admin page with product management
- Create marketplace vendor page with product listings
- Implement marketplace.js for both admin and vendor interfaces
- Add marketplace integration documentation

Admin Enhancements:
- Add imports management page and functionality
- Create settings page for admin configuration
- Add vendor themes management page
- Enhance vendor detail and edit pages
- Improve code quality dashboard and violation details
- Add logs viewing and management
- Update icons guide and shared icon system

Architecture & Documentation:
- Document frontend structure and component architecture
- Document models structure and relationships
- Add vendor-in-token architecture documentation
- Add vendor RBAC (role-based access control) documentation
- Document marketplace integration patterns
- Update architecture patterns documentation

Infrastructure:
- Add platform static files structure (css, img, js)
- Move architecture_scan.py to proper models location
- Update model imports and registrations
- Enhance exception handling
- Update dependency injection patterns

UI/UX:
- Improve vendor edit interface
- Update admin user interface
- Enhance page templates documentation
- Add vendor marketplace interface
This commit is contained in:
2025-12-01 21:51:07 +01:00
parent 915734e9b4
commit cc74970223
56 changed files with 8440 additions and 202 deletions

View File

@@ -220,7 +220,7 @@ app/
class="flex items-center justify-center p-2 text-red-600 rounded-lg hover:bg-red-50 dark:text-gray-400 dark:hover:bg-gray-700"
title="Delete"
>
<span x-html="$icon('trash', 'w-5 h-5')"></span>
<span x-html="$icon('delete', 'w-5 h-5')"></span>
</button>
</div>
</td>
@@ -994,3 +994,200 @@ The base template loads scripts in this specific order:
---
This template provides a complete, production-ready pattern for building vendor admin pages with consistent structure, error handling, and user experience.
---
## 🎯 Real-World Example: Marketplace Import Page
The marketplace import page is a comprehensive real-world implementation demonstrating all best practices.
### Implementation Files
**Template**: `app/templates/vendor/marketplace.html`
**JavaScript**: `static/vendor/js/marketplace.js`
**Route**: `app/routes/vendor_pages.py` - `vendor_marketplace_page()`
### Key Features Demonstrated
#### 1. Complete Form Handling
```javascript
// Import form with validation
importForm: {
csv_url: '',
marketplace: 'Letzshop',
language: 'fr',
batch_size: 1000
},
async startImport() {
if (!this.importForm.csv_url) {
this.error = 'Please enter a CSV URL';
return;
}
this.importing = true;
try {
const response = await apiClient.post('/vendor/marketplace/import', {
source_url: this.importForm.csv_url,
marketplace: this.importForm.marketplace,
batch_size: this.importForm.batch_size
});
this.successMessage = `Import job #${response.job_id} started!`;
await this.loadJobs(); // Refresh list
} catch (error) {
this.error = error.message;
} finally {
this.importing = false;
}
}
```
#### 2. Auto-Refresh for Active Jobs
```javascript
startAutoRefresh() {
this.autoRefreshInterval = setInterval(async () => {
const hasActiveJobs = this.jobs.some(job =>
job.status === 'pending' || job.status === 'processing'
);
if (hasActiveJobs) {
await this.loadJobs();
}
}, 10000); // Every 10 seconds
}
```
#### 3. Quick Fill from Settings
```javascript
// Load vendor settings
async loadVendorSettings() {
const response = await apiClient.get('/vendor/settings');
this.vendorSettings = {
letzshop_csv_url_fr: response.letzshop_csv_url_fr || '',
letzshop_csv_url_en: response.letzshop_csv_url_en || '',
letzshop_csv_url_de: response.letzshop_csv_url_de || ''
};
}
// Quick fill function
quickFill(language) {
const urlMap = {
'fr': this.vendorSettings.letzshop_csv_url_fr,
'en': this.vendorSettings.letzshop_csv_url_en,
'de': this.vendorSettings.letzshop_csv_url_de
};
if (urlMap[language]) {
this.importForm.csv_url = urlMap[language];
this.importForm.language = language;
}
}
```
#### 4. Job Details Modal
```javascript
async viewJobDetails(jobId) {
try {
const response = await apiClient.get(`/vendor/marketplace/imports/${jobId}`);
this.selectedJob = response;
this.showJobModal = true;
} catch (error) {
this.error = error.message;
}
}
```
#### 5. Pagination
```javascript
async nextPage() {
if (this.page * this.limit < this.totalJobs) {
this.page++;
await this.loadJobs();
}
}
```
#### 6. Utility Functions
```javascript
formatDate(dateString) {
if (!dateString) return 'N/A';
const date = new Date(dateString);
return date.toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
calculateDuration(job) {
if (!job.started_at) return 'Not started';
const start = new Date(job.started_at);
const end = job.completed_at ? new Date(job.completed_at) : new Date();
const durationMs = end - start;
const seconds = Math.floor(durationMs / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}h ${minutes % 60}m`;
} else if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
}
return `${seconds}s`;
}
```
### Template Features
#### Dynamic Status Badges
```html
<span class="px-2 py-1 font-semibold leading-tight rounded-full text-xs"
:class="{
'text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100': job.status === 'completed',
'text-blue-700 bg-blue-100 dark:bg-blue-700 dark:text-blue-100': job.status === 'processing',
'text-yellow-700 bg-yellow-100 dark:bg-yellow-700 dark:text-yellow-100': job.status === 'pending',
'text-red-700 bg-red-100 dark:bg-red-700 dark:text-red-100': job.status === 'failed'
}"
x-text="job.status.toUpperCase()">
</span>
```
#### Conditional Display
```html
<!-- Quick fill buttons -->
<button
type="button"
@click="quickFill('fr')"
x-show="vendorSettings.letzshop_csv_url_fr"
class="...">
<span x-html="$icon('lightning-bolt', 'w-3 h-3 mr-1')"></span>
French CSV
</button>
```
#### Progress Metrics
```html
<div class="space-y-1">
<div class="text-xs text-gray-600 dark:text-gray-400">
<span class="text-green-600" x-text="job.imported_count"></span> imported,
<span class="text-blue-600" x-text="job.updated_count"></span> updated
</div>
<div x-show="job.error_count > 0" class="text-xs text-red-600">
<span x-text="job.error_count"></span> errors
</div>
</div>
```
---
## 📚 Related Documentation
- [Marketplace Integration Guide](../../guides/marketplace-integration.md) - Complete marketplace system documentation
- [Admin Page Templates](../admin/page-templates.md) - Admin page patterns
- [Icons Guide](../../development/icons-guide.md) - Available icons