feat: add import error tracking and translation tabs
Import Error Tracking:
- Add MarketplaceImportError model to store detailed error information
- Store row number, identifier, error type, message, and row data for each error
- Add API endpoint GET /admin/marketplace-import-jobs/{job_id}/errors
- Add UI to view and browse import errors in job details modal
- Support pagination and error type filtering
Translation Tabs:
- Replace flat translation list with tabbed interface on product detail page
- Add language tabs with full language names
- Add copy-to-clipboard functionality for translation content
- Improved UX with better visual separation of translations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
"""add marketplace import errors table
|
||||
|
||||
Revision ID: 91d02647efae
|
||||
Revises: 987b4ecfa503
|
||||
Create Date: 2025-12-13 13:13:46.969503
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '91d02647efae'
|
||||
down_revision: Union[str, None] = '987b4ecfa503'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Create marketplace_import_errors table to store detailed import error information
|
||||
op.create_table('marketplace_import_errors',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('import_job_id', sa.Integer(), nullable=False),
|
||||
sa.Column('row_number', sa.Integer(), nullable=False),
|
||||
sa.Column('identifier', sa.String(), nullable=True),
|
||||
sa.Column('error_type', sa.String(length=50), nullable=False),
|
||||
sa.Column('error_message', sa.Text(), nullable=False),
|
||||
sa.Column('row_data', sa.JSON(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['import_job_id'], ['marketplace_import_jobs.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index('idx_import_error_job_id', 'marketplace_import_errors', ['import_job_id'], unique=False)
|
||||
op.create_index('idx_import_error_type', 'marketplace_import_errors', ['error_type'], unique=False)
|
||||
op.create_index(op.f('ix_marketplace_import_errors_id'), 'marketplace_import_errors', ['id'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(op.f('ix_marketplace_import_errors_id'), table_name='marketplace_import_errors')
|
||||
op.drop_index('idx_import_error_type', table_name='marketplace_import_errors')
|
||||
op.drop_index('idx_import_error_job_id', table_name='marketplace_import_errors')
|
||||
op.drop_table('marketplace_import_errors')
|
||||
Reference in New Issue
Block a user