Files
orion/app/templates/admin/test-vendors-users-migration.html
Samir Boulahtit 8a367077e1 refactor: migrate vendor APIs to token-based context and consolidate architecture
## Vendor-in-Token Architecture (Complete Migration)
- Migrate all vendor API endpoints from require_vendor_context() to token_vendor_id
- Update permission dependencies to extract vendor from JWT token
- Add vendor exceptions: VendorAccessDeniedException, VendorOwnerOnlyException,
  InsufficientVendorPermissionsException
- Shop endpoints retain require_vendor_context() for URL-based detection
- Add AUTH-004 architecture rule enforcing vendor context patterns
- Fix marketplace router missing /marketplace prefix

## Exception Pattern Fixes (API-003/API-004)
- Services raise domain exceptions, endpoints let them bubble up
- Add code_quality and content_page exception modules
- Move business logic from endpoints to services (admin, auth, content_page)
- Fix exception handling in admin, shop, and vendor endpoints

## Tailwind CSS Consolidation
- Consolidate CSS to per-area files (admin, vendor, shop, platform)
- Remove shared/cdn-fallback.html and shared/css/tailwind.min.css
- Update all templates to use area-specific Tailwind output files
- Remove Node.js config (package.json, postcss.config.js, tailwind.config.js)

## Documentation & Cleanup
- Update vendor-in-token-architecture.md with completed migration status
- Update architecture-rules.md with new rules
- Move migration docs to docs/development/migration/
- Remove duplicate/obsolete documentation files
- Merge pytest.ini settings into pyproject.toml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 22:24:45 +01:00

216 lines
12 KiB
HTML

{# app/templates/admin/test-vendors-users-migration.html #}
{% extends 'admin/base.html' %}
{% block title %}Vendors & Users Migration Testing{% endblock %}
{% block content %}
<div x-data="migrationTest()" x-init="init()">
{# Page Header #}
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-8">
<div>
<h2 class="text-2xl font-semibold text-gray-700 dark:text-gray-200">
Vendors & Users Migration Testing
</h2>
<p class="text-gray-600 dark:text-gray-400 mt-1">
Comprehensive test suite for verifying the Jinja2 migration
</p>
</div>
</div>
{# Status Cards #}
<div class="grid gap-6 mb-8 md:grid-cols-2 xl:grid-cols-4">
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
<div class="p-3 mr-4 text-purple-500 bg-purple-100 rounded-full dark:text-purple-100 dark:bg-purple-500">
<span x-html="$icon('badge-check', 'w-5 h-5')"></span>
</div>
<div>
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Dashboard</p>
<p class="text-lg font-semibold text-green-600 dark:text-green-400">Complete</p>
</div>
</div>
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
<div class="p-3 mr-4 text-orange-500 bg-orange-100 rounded-full dark:text-orange-100 dark:bg-orange-500">
<span x-html="$icon('building-storefront', 'w-5 h-5')"></span>
</div>
<div>
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Vendors List</p>
<p class="text-lg font-semibold" :class="vendorsStatus === 'Complete' ? 'text-green-600 dark:text-green-400' : 'text-yellow-600 dark:text-yellow-400'" x-text="vendorsStatus">Testing</p>
</div>
</div>
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
<div class="p-3 mr-4 text-blue-500 bg-blue-100 rounded-full dark:text-blue-100 dark:bg-blue-500">
<span x-html="$icon('pencil-square', 'w-5 h-5')"></span>
</div>
<div>
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Vendor Edit</p>
<p class="text-lg font-semibold" :class="editStatus === 'Complete' ? 'text-green-600 dark:text-green-400' : 'text-yellow-600 dark:text-yellow-400'" x-text="editStatus">Testing</p>
</div>
</div>
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
<div class="p-3 mr-4 text-green-500 bg-green-100 rounded-full dark:text-green-100 dark:bg-green-500">
<span x-html="$icon('user-group', 'w-5 h-5')"></span>
</div>
<div>
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Users Page</p>
<p class="text-lg font-semibold" :class="usersStatus === 'Complete' ? 'text-green-600 dark:text-green-400' : 'text-yellow-600 dark:text-yellow-400'" x-text="usersStatus">Testing</p>
</div>
</div>
</div>
{# Quick Actions #}
<div class="px-4 py-3 mb-8 bg-white rounded-lg shadow-md dark:bg-gray-800">
<h4 class="mb-4 text-lg font-semibold text-gray-600 dark:text-gray-300">Quick Actions</h4>
<div class="flex flex-wrap gap-3">
<a href="{{ url_for('admin:vendors_list') }}" class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-orange-600 border border-transparent rounded-lg hover:bg-orange-700 focus:outline-none">
<span x-html="$icon('building-storefront', 'w-4 h-4 mr-2')"></span>
Go to Vendors List
</a>
<a href="{{ url_for('admin:users_list') }}" class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-green-600 border border-transparent rounded-lg hover:bg-green-700 focus:outline-none">
<span x-html="$icon('user-group', 'w-4 h-4 mr-2')"></span>
Go to Users Page
</a>
<a href="{{ url_for('admin:dashboard') }}" class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none">
<span x-html="$icon('home', 'w-4 h-4 mr-2')"></span>
Go to Dashboard
</a>
</div>
{# Progress Bar #}
<div class="mt-4">
<div class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
<div class="bg-green-600 h-2.5 rounded-full transition-all duration-300" :style="'width: ' + progress + '%'"></div>
</div>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400" x-text="progress + '% Complete - ' + checkedCount + '/' + totalChecks + ' checks passed'"></p>
</div>
</div>
{# Test Section: Vendors List #}
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-orange-500">
<h4 class="mb-4 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 1: Vendors List Page
<span class="ml-2 px-2 py-1 text-xs font-semibold text-red-700 bg-red-100 rounded-full dark:bg-red-700 dark:text-red-100">High Priority</span>
</h4>
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400">Tests the vendor LIST functionality using adminVendors() function.</p>
<div class="space-y-2 mb-4">
<template x-for="(item, index) in vendorChecks" :key="index">
<label class="flex items-center p-2 rounded hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer">
<input type="checkbox" x-model="item.checked" @change="updateProgress()" class="w-4 h-4 text-purple-600 form-checkbox focus:ring-purple-500">
<span class="ml-3 text-sm text-gray-700 dark:text-gray-300" :class="{ 'line-through text-gray-400': item.checked }" x-text="item.label"></span>
</label>
</template>
</div>
<div class="p-3 bg-green-50 dark:bg-green-900/20 rounded-lg border-l-3 border-green-500">
<p class="text-sm font-medium text-green-700 dark:text-green-400">Expected: adminVendors() works with ApiClient, Logger, Utils</p>
</div>
</div>
{# Test Section: Users Page #}
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-green-500">
<h4 class="mb-4 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 2: Users Page
<span class="ml-2 px-2 py-1 text-xs font-semibold text-yellow-700 bg-yellow-100 rounded-full dark:bg-yellow-700 dark:text-yellow-100">Medium Priority</span>
</h4>
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400">Tests the users page created with adminUsers() function.</p>
<div class="space-y-2 mb-4">
<template x-for="(item, index) in userChecks" :key="index">
<label class="flex items-center p-2 rounded hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer">
<input type="checkbox" x-model="item.checked" @change="updateProgress()" class="w-4 h-4 text-purple-600 form-checkbox focus:ring-purple-500">
<span class="ml-3 text-sm text-gray-700 dark:text-gray-300" :class="{ 'line-through text-gray-400': item.checked }" x-text="item.label"></span>
</label>
</template>
</div>
<div class="p-3 bg-green-50 dark:bg-green-900/20 rounded-lg border-l-3 border-green-500">
<p class="text-sm font-medium text-green-700 dark:text-green-400">Expected: adminUsers() follows same pattern as vendors list</p>
</div>
</div>
{# Console Panel #}
<div class="px-4 py-3 bg-gray-800 rounded-lg shadow-md">
<div class="flex items-center justify-between mb-3">
<h4 class="text-lg font-semibold text-gray-200">Test Console</h4>
<button @click="logs = []" class="px-3 py-1 text-xs text-gray-400 border border-gray-600 rounded hover:bg-gray-700">Clear</button>
</div>
<div class="h-48 overflow-y-auto font-mono text-sm">
<template x-for="(log, index) in logs" :key="index">
<div class="py-1 border-b border-gray-700">
<span class="text-gray-500" x-text="log.time"></span>
<span :class="log.level === 'success' ? 'text-green-400' : log.level === 'error' ? 'text-red-400' : 'text-blue-400'" x-text="log.message"></span>
</div>
</template>
<div x-show="logs.length === 0" class="text-gray-500">No logs yet. Start testing!</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function migrationTest() {
return {
...data(),
currentPage: 'testing',
vendorsStatus: 'Testing',
editStatus: 'Testing',
usersStatus: 'Testing',
progress: 0,
checkedCount: 0,
totalChecks: 0,
logs: [],
vendorChecks: [
{ label: 'Navigate to /admin/vendors - Page loads without errors', checked: false },
{ label: 'Check console - No JavaScript errors', checked: false },
{ label: 'Verify Alpine.js function - adminVendors() is called', checked: false },
{ label: '4 stat cards display in a grid', checked: false },
{ label: 'Table displays with correct headers', checked: false },
{ label: 'Status badges show correctly (Verified/Pending)', checked: false },
{ label: 'Action buttons (View, Edit, Delete) work', checked: false },
],
userChecks: [
{ label: 'Navigate to /admin/users - Page loads without errors', checked: false },
{ label: 'Alpine.js adminUsers() function works', checked: false },
{ label: '4 stat cards display (Total, Active, Admins, Vendors)', checked: false },
{ label: 'Users table displays correctly', checked: false },
{ label: 'Role badges display (admin/vendor/customer)', checked: false },
{ label: 'Status badges show (Active/Inactive)', checked: false },
{ label: 'Action buttons work (View, Edit, Toggle Status)', checked: false },
],
init() {
this.totalChecks = this.vendorChecks.length + this.userChecks.length;
this.log('Migration Test Suite Ready', 'success');
this.log('Follow the test sections to verify migration', 'info');
},
updateProgress() {
const vendorChecked = this.vendorChecks.filter(c => c.checked).length;
const userChecked = this.userChecks.filter(c => c.checked).length;
this.checkedCount = vendorChecked + userChecked;
this.progress = Math.round((this.checkedCount / this.totalChecks) * 100);
// Update section status
if (vendorChecked === this.vendorChecks.length) {
this.vendorsStatus = 'Complete';
this.log('Vendors list tests completed!', 'success');
}
if (userChecked === this.userChecks.length) {
this.usersStatus = 'Complete';
this.log('Users page tests completed!', 'success');
}
},
log(message, level = 'info') {
const time = new Date().toLocaleTimeString();
this.logs.push({ time: `[${time}]`, message, level });
}
};
}
</script>
{% endblock %}