c5fbb6722b
- Create styles/tokens.css with CSS custom properties and dark theme - Create styles/global.css with resets, shell layout, and navigation - Create styles/utilities.css with generic utilities and primitives - Create styles/syntax-highlight.css with Prism.js theme - Update main.tsx to import the 4 new style files - Keep styles.css intact for backward compatibility Quality gates: build (pass), lint (pass) Refs: repo-restructure Task 2.1
132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
"""Config profile request/response schemas."""
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
MAX_MOUNT_PATH_LENGTH = 1024
|
|
|
|
|
|
class ConfigProfileCreate(BaseModel):
|
|
name: str = Field(description="Profile name (unique per user)")
|
|
description: str | None = Field(default=None, description="Optional description")
|
|
|
|
@field_validator("name")
|
|
@classmethod
|
|
def validate_name(cls, v: str) -> str:
|
|
v = v.strip()
|
|
if not v:
|
|
raise ValueError("Profile name cannot be empty")
|
|
if len(v) > 255:
|
|
raise ValueError("Profile name must be 255 characters or less")
|
|
return v
|
|
|
|
|
|
class ConfigProfileUpdate(BaseModel):
|
|
name: str | None = Field(default=None, description="Profile name")
|
|
description: str | None = Field(default=None, description="Optional description")
|
|
|
|
@field_validator("name")
|
|
@classmethod
|
|
def validate_name(cls, v: str | None) -> str | None:
|
|
if v is None:
|
|
return v
|
|
v = v.strip()
|
|
if not v:
|
|
raise ValueError("Profile name cannot be empty")
|
|
if len(v) > 255:
|
|
raise ValueError("Profile name must be 255 characters or less")
|
|
return v
|
|
|
|
|
|
class ConfigProfileResponse(BaseModel):
|
|
id: str
|
|
user_id: str
|
|
name: str
|
|
description: str | None
|
|
created_at: str
|
|
updated_at: str
|
|
|
|
|
|
class ConfigProfileDetailResponse(ConfigProfileResponse):
|
|
includes: list[dict[str, Any]]
|
|
mounts: list[dict[str, Any]]
|
|
|
|
|
|
class ConfigIncludeCreate(BaseModel):
|
|
included_profile_id: str = Field(description="UUID of the profile to include")
|
|
order_index: int = Field(default=0, description="Order index for include resolution")
|
|
|
|
|
|
class ConfigIncludeUpdate(BaseModel):
|
|
order_index: int = Field(description="Order index for include resolution")
|
|
|
|
|
|
class ConfigIncludeResponse(BaseModel):
|
|
id: str
|
|
profile_id: str
|
|
included_profile_id: str
|
|
included_profile_name: str | None
|
|
order_index: int
|
|
created_at: str
|
|
updated_at: str
|
|
|
|
|
|
class ConfigMountCreate(BaseModel):
|
|
target_path: str = Field(description="Absolute target path in container")
|
|
mode: str = Field(default="rw", description="Mount mode (rw or ro)")
|
|
files: dict[str, str] | None = Field(
|
|
default=None, description="Files as {path: content}"
|
|
)
|
|
order_index: int = Field(default=0, description="Order index for mount resolution")
|
|
|
|
@field_validator("target_path")
|
|
@classmethod
|
|
def validate_target_path(cls, v: str) -> str:
|
|
if not v.startswith("/"):
|
|
raise ValueError("Target path must be absolute (start with /)")
|
|
if ".." in v:
|
|
raise ValueError("Target path cannot contain parent directory references (..)")
|
|
if len(v) > MAX_MOUNT_PATH_LENGTH:
|
|
raise ValueError(f"Target path must be {MAX_MOUNT_PATH_LENGTH} characters or less")
|
|
return v
|
|
|
|
|
|
class ConfigMountUpdate(BaseModel):
|
|
target_path: str | None = Field(default=None, description="Absolute target path in container")
|
|
mode: str | None = Field(default=None, description="Mount mode (rw or ro)")
|
|
files: dict[str, str] | None = Field(
|
|
default=None, description="Files as {path: content}"
|
|
)
|
|
order_index: int | None = Field(default=None, description="Order index for mount resolution")
|
|
|
|
@field_validator("target_path")
|
|
@classmethod
|
|
def validate_target_path(cls, v: str | None) -> str | None:
|
|
if v is None:
|
|
return v
|
|
if not v.startswith("/"):
|
|
raise ValueError("Target path must be absolute (start with /)")
|
|
if ".." in v:
|
|
raise ValueError("Target path cannot contain parent directory references (..)")
|
|
if len(v) > MAX_MOUNT_PATH_LENGTH:
|
|
raise ValueError(f"Target path must be {MAX_MOUNT_PATH_LENGTH} characters or less")
|
|
return v
|
|
|
|
|
|
class ConfigMountResponse(BaseModel):
|
|
id: str
|
|
profile_id: str
|
|
target_path: str
|
|
mode: str
|
|
files: dict[str, str] | None
|
|
order_index: int
|
|
created_at: str
|
|
updated_at: str
|
|
|
|
|
|
class DefaultProfilesUpdate(BaseModel):
|
|
default_profiles: dict[str, str] = Field(
|
|
description="Mapping of tool_type_id to profile_id"
|
|
)
|