mirror of
https://github.com/sassanix/Warracker.git
synced 2026-02-16 11:41:38 -06:00
## [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
105 lines
3.5 KiB
Python
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() |