Files
Warracker/backend/run_migrations.py
sassanix b4855af43f Grid view, manuals, prices, table view, export option, filters
## [0.5.0] - 2025-03-07

### Added
- Enhanced filtering and sorting capabilities
  - Status filter (All, Active, Expiring Soon, Expired)
  - Multiple sorting options (Expiration Date, Purchase Date, Name)
  - Export filtered warranties as CSV
  - Improved filter controls layout
  - Mobile-responsive filter design
- Multiple view options for warranty display
  - Grid view with card layout (default)
  - List view for compact horizontal display
  - Table view for structured data presentation
  - View preference saved between sessions
  - Responsive design for all view types
- Optional purchase price tracking
  - Users can now add purchase prices to warranties
  - Price information displayed in warranty cards
  - Currency formatting with dollar sign
  - Included in warranty summary and exports

### Changed
- Completely redesigned user interface
  - Modern card-based layout for warranties
  - Enhanced filter controls with improved styling
  - Better visual hierarchy with labeled filter groups
  - Custom dropdown styling with intuitive icons
  - Improved spacing and alignment throughout
  - Consistent color scheme and visual feedback
  - Responsive grid layout for warranty cards

### Fixed
- Status indicator borders now correctly displayed for all warranty states
  - Green border for active warranties
  - Orange border for warranties expiring soon
  - Red border for expired warranties
- Consistent status styling across all warranty cards
- Form now resets to first tab after successful warranty submission
- Manual filename now properly cleared when form is reset

## [0.4.0] - 2025-03-07

### Added
- Improved warranty creation process
  - Multi-step form with intuitive navigation
  - Progress indicator showing completion status
  - Enhanced validation with clear error messages
  - Summary review step before submission
  - Expiration date preview in summary
  - Responsive design for all device sizes

### Fixed
- Progress indicator alignment issue in multi-step form
  - Contained indicator within form boundaries
  - Prevented overflow with improved CSS approach
  - Ensured consistent tab widths for better alignment
- Improved tab navigation visual feedback

## [0.3.0] - 2025-03-07

### Added
- Product manual upload support
  - Users can now upload a second document for product manuals
  - Manual documents are displayed alongside invoices in the warranty details
  - Both add and edit forms support manual uploads
- Product URL support
  - Users can now add website URLs for products
  - Links to product websites displayed in warranty cards
  - Easy access to product support and information pages

### Changed
- Improved document link styling for consistency
  - Enhanced visual appearance of document links
  - Consistent styling between invoice and manual links
  - Better hover effects for document links
  - Fixed styling inconsistencies between document links
- Improved warranty card layout
  - Document links now displayed side by side for better space utilization
  - Responsive design adapts to different screen sizes
  - More compact and organized appearance

### Fixed
- Styling inconsistency between View Invoice and View Manual buttons
- Removed unused CSS file to prevent styling conflicts
2025-03-07 16:12:15 -04:00

105 lines
3.5 KiB
Python

#!/usr/bin/env python3
import os
import sys
import psycopg2
import logging
from psycopg2 import pool
import time
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# PostgreSQL connection details
DB_HOST = os.environ.get('DB_HOST', 'warrackerdb')
DB_NAME = os.environ.get('DB_NAME', 'warranty_db')
DB_USER = os.environ.get('DB_USER', 'warranty_user')
DB_PASSWORD = os.environ.get('DB_PASSWORD', 'warranty_password')
def create_db_connection(max_retries=5, retry_delay=5):
"""Create a database connection with retry logic"""
attempt = 0
last_exception = None
while attempt < max_retries:
try:
logger.info(f"Attempting to connect to database (attempt {attempt+1}/{max_retries})")
conn = psycopg2.connect(
host=DB_HOST,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD
)
logger.info("Database connection successful")
return conn
except Exception as e:
last_exception = e
logger.error(f"Database connection error: {e}")
logger.info(f"Retrying in {retry_delay} seconds...")
time.sleep(retry_delay)
attempt += 1
# If we got here, all connection attempts failed
logger.error(f"Failed to connect to database after {max_retries} attempts")
raise last_exception
def run_migrations():
"""Run all migration scripts in order"""
conn = None
try:
conn = create_db_connection()
conn.autocommit = False
cursor = conn.cursor()
# Get list of migration files
migration_dir = os.path.join(os.path.dirname(__file__), 'migrations')
migration_files = sorted([f for f in os.listdir(migration_dir) if f.endswith('.sql')])
# Create migrations table if it doesn't exist
cursor.execute('''
CREATE TABLE IF NOT EXISTS migrations (
id SERIAL PRIMARY KEY,
filename VARCHAR(255) NOT NULL UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# Get already applied migrations
cursor.execute('SELECT filename FROM migrations')
applied_migrations = {row[0] for row in cursor.fetchall()}
# Apply new migrations
for migration_file in migration_files:
if migration_file in applied_migrations:
logger.info(f"Migration {migration_file} already applied, skipping")
continue
logger.info(f"Applying migration: {migration_file}")
migration_path = os.path.join(migration_dir, migration_file)
with open(migration_path, 'r') as f:
migration_sql = f.read()
try:
cursor.execute(migration_sql)
cursor.execute('INSERT INTO migrations (filename) VALUES (%s)', (migration_file,))
logger.info(f"Migration {migration_file} applied successfully")
except Exception as e:
conn.rollback()
logger.error(f"Error applying migration {migration_file}: {e}")
raise
conn.commit()
logger.info("All migrations applied successfully")
except Exception as e:
logger.error(f"Migration error: {e}")
if conn:
conn.rollback()
sys.exit(1)
finally:
if conn:
conn.close()
if __name__ == "__main__":
run_migrations()