Explicit header, text and bullet blocks rather than one HTML block in ui spec

This commit is contained in:
Julian Stirling 2026-03-10 15:25:04 +00:00
parent 85ebfef44a
commit c4d0c0e9da
5 changed files with 82 additions and 41 deletions

View file

@ -42,7 +42,8 @@ from openflexure_microscope_server.things.stage import BaseStage
from openflexure_microscope_server.ui import (
UI_ELEMENT_RESPONSE,
Accordion,
HTMLBlock,
HeaderBlock,
TextBlock,
UIElementList,
action_button_for,
property_control_for,
@ -642,7 +643,8 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
return UIElementList(
[
HTMLBlock(html=f"<h4>{self.display_name}</h4><p>{self.ui_blurb}<p>"),
HeaderBlock(text=self.display_name, level=4),
TextBlock(text=self.ui_blurb),
Accordion(title="Background Detect", children=background_ui),
Accordion(
title="Scan Settings",
@ -750,7 +752,8 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
)
return UIElementList(
[
HTMLBlock(html=f"<h4>{self.display_name}</h4><p>{self.ui_blurb}<p>"),
HeaderBlock(text=self.display_name, level=4),
TextBlock(text=self.ui_blurb),
Accordion(
title="Scan Settings",
children=scan_settings,

View file

@ -5,24 +5,12 @@ from html.parser import HTMLParser
from typing import Annotated, Any, Literal, Optional
from urllib.parse import urlparse
from pydantic import BaseModel, BeforeValidator, RootModel
from pydantic import BaseModel, BeforeValidator, Field, RootModel
import labthings_fastapi as lt
ALLOWED_TAGS = {
"p",
"i",
"b",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"ul",
"li",
"a",
}
# Only allowed tags are italic, bold, and link. Also allows self closing br tags.
ALLOWED_TAGS = {"i", "b", "a"}
ALLOWED_SCHEMES = {"http", "https"}
@ -116,8 +104,7 @@ class SafeHTMLParser(HTMLParser):
def sanitise_html(html: str) -> str:
"""Santitise HTML to only have a small list of allowed tags.
Tags allowed without attrs: ``<p>, <i>, <b>, <h1>, <h2>, <h3>, <h4>, <h5>, <h6>,``
``<ul>, <li>``
Tags allowed without attrs: ``<i>, <b>,``
Tags allowed with attrs: ``<a>`` is allowed with ``href`` only. This automatically
appends ``target="_blank" rel="noopener noreferrer"`` so the link opens externally.
@ -137,14 +124,31 @@ def sanitise_html(html: str) -> str:
HtmlFragment = Annotated[str, BeforeValidator(sanitise_html)]
class HTMLBlock(BaseModel):
"""The data required for creating a block of HTML for the UI.
class HeaderBlock(BaseModel):
"""The data required for header."""
The HTML is limited to a small number of tags.
"""
element_type: Literal["header_block"] = "header_block"
text: HtmlFragment
"""The header text (can include basic HTML tags)."""
element_type: Literal["html_block"] = "html_block"
html: HtmlFragment
level: int = Field(default=2, ge=1, le=6)
"""The header level. A number from 1-6."""
class TextBlock(BaseModel):
"""The data required for creating a block text."""
element_type: Literal["text_block"] = "text_block"
text: HtmlFragment
"""The text (can include basic HTML tags)."""
class BulletBlock(BaseModel):
"""The data required for creating a block text."""
element_type: Literal["bullet_block"] = "bullet_block"
bullets: list[HtmlFragment]
"""A list of text elements (can include basic HTML tags)."""
class ActionButton(BaseModel):
@ -304,7 +308,15 @@ class Container(BaseModel):
children: "UIElementList"
UIElementModels = HTMLBlock | PropertyControl | ActionButton | Accordion | Container
UIElementModels = (
HeaderBlock
| TextBlock
| BulletBlock
| PropertyControl
| ActionButton
| Accordion
| Container
)
class UIElementList(RootModel[list[UIElementModels]]):