feat: add workspace system and sidebar layout (UI design system Phase A+B)
Backend: Workspace model, migration (036), schemas, CRUD API endpoints. Adds workspace_id to trees and categories, seeds 4 default workspaces per account, auto-assigns existing trees by tree_type. Frontend: Complete AppLayout rewrite from top-nav to CSS Grid shell with persistent sidebar + topbar. New components: WorkspaceSwitcher, NavItem, CategoryList, TagCloud, TopBar, Sidebar. Dashboard components: QuickStats, FiltersBar, SectionGroup, TreeListItem, SessionsPanel. WorkspaceStore with localStorage persistence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
||||
from app.models.team import Team
|
||||
from app.models.account import Account
|
||||
from app.models.user import User
|
||||
from app.models.workspace import Workspace
|
||||
|
||||
|
||||
class TreeCategory(Base):
|
||||
@@ -47,6 +48,17 @@ class TreeCategory(Base):
|
||||
)
|
||||
display_order: Mapped[int] = mapped_column(Integer, nullable=False, default=0, index=True)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
color: Mapped[Optional[str]] = mapped_column(
|
||||
String(7), nullable=True, default='#3b82f6',
|
||||
comment="Hex color for category dot indicator"
|
||||
)
|
||||
workspace_id: Mapped[Optional[uuid.UUID]] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("workspaces.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
comment="Workspace this category belongs to"
|
||||
)
|
||||
created_by: Mapped[Optional[uuid.UUID]] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("users.id", ondelete="SET NULL"),
|
||||
@@ -67,6 +79,7 @@ class TreeCategory(Base):
|
||||
account: Mapped[Optional["Account"]] = relationship("Account", foreign_keys=[account_id], back_populates="categories")
|
||||
creator: Mapped[Optional["User"]] = relationship("User", foreign_keys=[created_by])
|
||||
trees: Mapped[list["Tree"]] = relationship("Tree", back_populates="category_rel")
|
||||
workspace: Mapped[Optional["Workspace"]] = relationship("Workspace", back_populates="categories")
|
||||
|
||||
@property
|
||||
def is_global(self) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user