Phase 2: Tags UI, Custom Fields UI, Notifications Bell
- Tags UI: TagsPage (CRUD, color picker), TagBadge, TagSelector (multi-select, inline creation) - Custom Fields Backend: model, schema, service, routes, migration 0041 - Custom Fields Frontend: CustomFieldsPage (definitions CRUD), CustomFieldRenderer (dynamic field rendering) - Custom Fields: _collect_custom_field_definitions() extended to merge DB definitions with plugin definitions - Notifications Bell: NotificationBell (30s polling, unread badge), NotificationDropdown, NotificationItem - NotificationBell integrated into TopBar - Routes: /tags, /settings/custom-fields registered - Settings nav: Custom Fields entry added - Menu items: Tags added to automation plugin manifest
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""Pydantic schemas for CustomFieldDefinition CRUD."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class CustomFieldDefinitionCreate(BaseModel):
|
||||
"""Schema for creating a new custom field definition."""
|
||||
|
||||
entity: str = Field(..., description="Entity type (e.g. 'contact', 'company')")
|
||||
name: str = Field(..., min_length=1, max_length=100, description="Unique field name (snake_case)")
|
||||
label: str = Field(..., min_length=1, max_length=200, description="Human-readable label")
|
||||
field_type: str = Field(
|
||||
...,
|
||||
pattern=r"^(text|number|date|select|multiselect|boolean)$",
|
||||
description="Field type",
|
||||
)
|
||||
options: list[str] | None = Field(default=None, description="Options for select/multiselect types")
|
||||
default_value: Any = Field(default=None, description="Default value")
|
||||
required: bool = Field(default=False, description="Whether the field is required")
|
||||
is_active: bool = Field(default=True, description="Whether the field is active")
|
||||
sort_order: int = Field(default=0, description="Sort order")
|
||||
|
||||
|
||||
class CustomFieldDefinitionUpdate(BaseModel):
|
||||
"""Schema for updating an existing custom field definition."""
|
||||
|
||||
label: str | None = Field(default=None, max_length=200)
|
||||
field_type: str | None = Field(
|
||||
default=None,
|
||||
pattern=r"^(text|number|date|select|multiselect|boolean)$",
|
||||
)
|
||||
options: list[str] | None = Field(default=None)
|
||||
default_value: Any = Field(default=None)
|
||||
required: bool | None = Field(default=None)
|
||||
is_active: bool | None = Field(default=None)
|
||||
sort_order: int | None = Field(default=None)
|
||||
|
||||
|
||||
class CustomFieldDefinitionResponse(BaseModel):
|
||||
"""Schema for returning a custom field definition."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: uuid.UUID
|
||||
tenant_id: uuid.UUID
|
||||
entity: str
|
||||
name: str
|
||||
label: str
|
||||
field_type: str
|
||||
options: list[str] | None = None
|
||||
default_value: Any = None
|
||||
required: bool = False
|
||||
is_active: bool = True
|
||||
sort_order: int = 0
|
||||
created_by: uuid.UUID | None = None
|
||||
updated_by: uuid.UUID | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
Reference in New Issue
Block a user