feat: add dashboard API with quick links and widgets
Build and Push / build (release) Successful in 1m28s
Build and Push / build (release) Successful in 1m28s
- Dashboard domain with Quick Links CRUD + reorder endpoints - Dashboard widgets management endpoints - Database migrations for quick_links and dashboard_widgets tables - Static file controller for Organizr widgets - Default local user when OIDC is disabled - Domain-based architecture refactor (src/domains/, src/shared/) - Test suite updated for new structure (285 tests passing) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
e85c9a123d
commit
381d43b60b
+4
-3
@@ -13,11 +13,12 @@ from sqlalchemy.ext.asyncio import async_engine_from_config
|
||||
from alembic import context
|
||||
|
||||
# Import our models and config
|
||||
from src.config import get_settings
|
||||
from src.db.database import Base
|
||||
from src.shared.config import get_settings
|
||||
from src.shared.database import Base
|
||||
|
||||
# Import all models to ensure they're registered with Base.metadata
|
||||
from src.db.models import User, Role, UserRole, UserPreferences, ApiKey # noqa: F401
|
||||
from src.domains.auth.models import User, Role, UserRole, UserPreferences, ApiKey # noqa: F401
|
||||
from src.domains.dashboard.models import QuickLink, DashboardWidget # noqa: F401
|
||||
|
||||
# Alembic Config object
|
||||
config = context.config
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Create dashboard tables
|
||||
|
||||
Revision ID: 003
|
||||
Revises: 002
|
||||
Create Date: 2026-01-03
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '003'
|
||||
down_revision: Union[str, None] = '002'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Create quick_links and dashboard_widgets tables."""
|
||||
# Create quick_links table
|
||||
op.create_table(
|
||||
'quick_links',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('title', sa.String(length=100), nullable=False),
|
||||
sa.Column('url', sa.String(length=500), nullable=False),
|
||||
sa.Column('icon', sa.String(length=100), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('category', sa.String(length=50), nullable=True),
|
||||
sa.Column('user_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('position', sa.Integer(), nullable=True, default=0),
|
||||
sa.Column('is_visible', sa.Boolean(), nullable=True, default=True),
|
||||
sa.Column('color', sa.String(length=20), nullable=True),
|
||||
sa.Column('background_color', sa.String(length=20), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_quick_links_id'), 'quick_links', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_quick_links_user_id'), 'quick_links', ['user_id'], unique=False)
|
||||
|
||||
# Create dashboard_widgets table
|
||||
op.create_table(
|
||||
'dashboard_widgets',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('widget_type', sa.String(length=50), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('position_x', sa.Integer(), nullable=True, default=0),
|
||||
sa.Column('position_y', sa.Integer(), nullable=True, default=0),
|
||||
sa.Column('width', sa.Integer(), nullable=True, default=1),
|
||||
sa.Column('height', sa.Integer(), nullable=True, default=1),
|
||||
sa.Column('config', sa.Text(), nullable=True),
|
||||
sa.Column('is_visible', sa.Boolean(), nullable=True, default=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_dashboard_widgets_id'), 'dashboard_widgets', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_dashboard_widgets_user_id'), 'dashboard_widgets', ['user_id'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Drop dashboard tables."""
|
||||
op.drop_index(op.f('ix_dashboard_widgets_user_id'), table_name='dashboard_widgets')
|
||||
op.drop_index(op.f('ix_dashboard_widgets_id'), table_name='dashboard_widgets')
|
||||
op.drop_table('dashboard_widgets')
|
||||
|
||||
op.drop_index(op.f('ix_quick_links_user_id'), table_name='quick_links')
|
||||
op.drop_index(op.f('ix_quick_links_id'), table_name='quick_links')
|
||||
op.drop_table('quick_links')
|
||||
Reference in New Issue
Block a user