feat: add configurable view-aware dashboards
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
|
||||
|
||||
WidgetId = Annotated[str, Field(min_length=1, max_length=160)]
|
||||
ConfigurationValue = str | int | float | bool | None
|
||||
|
||||
|
||||
class DashboardWidgetPlacementPayload(BaseModel):
|
||||
instance_id: str = Field(min_length=1, max_length=120)
|
||||
widget_id: WidgetId
|
||||
size: Literal["small", "medium", "wide", "full"] = "medium"
|
||||
configuration: dict[str, ConfigurationValue] = Field(
|
||||
default_factory=dict,
|
||||
max_length=40,
|
||||
)
|
||||
|
||||
@field_validator("configuration")
|
||||
@classmethod
|
||||
def validate_configuration(
|
||||
cls,
|
||||
value: dict[str, ConfigurationValue],
|
||||
) -> dict[str, ConfigurationValue]:
|
||||
approximate_size = 0
|
||||
for key, item in value.items():
|
||||
if not key or len(key) > 120:
|
||||
raise ValueError(
|
||||
"Widget configuration keys must contain 1 to 120 characters."
|
||||
)
|
||||
approximate_size += len(key)
|
||||
if isinstance(item, str):
|
||||
if len(item) > 4_000:
|
||||
raise ValueError(
|
||||
"Widget configuration text values may contain at most "
|
||||
"4,000 characters."
|
||||
)
|
||||
approximate_size += len(item)
|
||||
else:
|
||||
approximate_size += len(str(item))
|
||||
if isinstance(item, float) and not math.isfinite(item):
|
||||
raise ValueError(
|
||||
"Widget configuration numbers must be finite."
|
||||
)
|
||||
if approximate_size > 32_000:
|
||||
raise ValueError(
|
||||
"A widget configuration may contain at most 32,000 characters."
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
class DashboardLayoutUpdateRequest(BaseModel):
|
||||
expected_revision: int | None = Field(default=None, ge=0)
|
||||
layout_version: Literal[1] = 1
|
||||
placements: list[DashboardWidgetPlacementPayload] = Field(
|
||||
default_factory=list,
|
||||
max_length=100,
|
||||
)
|
||||
known_widget_ids: list[WidgetId] = Field(
|
||||
default_factory=list,
|
||||
max_length=500,
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_unique_ids(self) -> "DashboardLayoutUpdateRequest":
|
||||
instance_ids = [item.instance_id for item in self.placements]
|
||||
if len(instance_ids) != len(set(instance_ids)):
|
||||
raise ValueError("Dashboard widget instance ids must be unique.")
|
||||
return self
|
||||
|
||||
|
||||
class DashboardLayoutResponse(BaseModel):
|
||||
exists: bool
|
||||
view_id: str | None = None
|
||||
layout_version: int = 1
|
||||
revision: int = 0
|
||||
placements: list[DashboardWidgetPlacementPayload] = Field(
|
||||
default_factory=list
|
||||
)
|
||||
known_widget_ids: list[str] = Field(default_factory=list)
|
||||
updated_at: datetime | None = None
|
||||
|
||||
|
||||
__all__ = [
|
||||
"DashboardLayoutResponse",
|
||||
"DashboardLayoutUpdateRequest",
|
||||
"DashboardWidgetPlacementPayload",
|
||||
]
|
||||
Reference in New Issue
Block a user