statezero 0.1.0b61__py3-none-any.whl → 0.1.0b63__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- statezero/core/classes.py +218 -5
- {statezero-0.1.0b61.dist-info → statezero-0.1.0b63.dist-info}/METADATA +1 -1
- {statezero-0.1.0b61.dist-info → statezero-0.1.0b63.dist-info}/RECORD +5 -5
- {statezero-0.1.0b61.dist-info → statezero-0.1.0b63.dist-info}/WHEEL +0 -0
- {statezero-0.1.0b61.dist-info → statezero-0.1.0b63.dist-info}/top_level.txt +0 -0
statezero/core/classes.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from dataclasses import
|
|
1
|
+
from dataclasses import field
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import Any, Dict, List, Optional, Set, Type, Union
|
|
3
|
+
from typing import Any, Dict, List, Literal, Optional, Set, Type, Union, Annotated
|
|
4
4
|
|
|
5
5
|
import jsonschema
|
|
6
6
|
from fastapi.encoders import jsonable_encoder
|
|
7
|
-
from pydantic import BaseModel, Field
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
8
|
+
from pydantic.dataclasses import dataclass
|
|
8
9
|
|
|
9
10
|
from statezero.core.types import ORMField
|
|
10
11
|
|
|
@@ -82,7 +83,7 @@ class FieldFormat(str, Enum):
|
|
|
82
83
|
MONEY = "money"
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
@dataclass
|
|
86
|
+
@dataclass(config=ConfigDict(arbitrary_types_allowed=True))
|
|
86
87
|
class AdditionalField:
|
|
87
88
|
"""
|
|
88
89
|
Represents configuration for an additional computed field in the schema.
|
|
@@ -94,7 +95,7 @@ class AdditionalField:
|
|
|
94
95
|
"""
|
|
95
96
|
|
|
96
97
|
name: str # The property/method name to pull from
|
|
97
|
-
field:
|
|
98
|
+
field: ORMField # The instantiated serializer field (e.g. CharField(max_length=255)) #type:ignore
|
|
98
99
|
title: Optional[str] # Optional display name override
|
|
99
100
|
|
|
100
101
|
class SchemaFieldMetadata(BaseModel):
|
|
@@ -205,6 +206,213 @@ class FieldGroup:
|
|
|
205
206
|
field_names: Optional[List[str]] = None
|
|
206
207
|
|
|
207
208
|
|
|
209
|
+
# =============================================================================
|
|
210
|
+
# Layout Elements - JSON Forms inspired layout system
|
|
211
|
+
# =============================================================================
|
|
212
|
+
|
|
213
|
+
class LayoutType(str, Enum):
|
|
214
|
+
"""Types of layout elements"""
|
|
215
|
+
VERTICAL = "VerticalLayout"
|
|
216
|
+
HORIZONTAL = "HorizontalLayout"
|
|
217
|
+
GROUP = "Group"
|
|
218
|
+
CONTROL = "Control"
|
|
219
|
+
DISPLAY = "Display"
|
|
220
|
+
ALERT = "Alert"
|
|
221
|
+
LABEL = "Label"
|
|
222
|
+
DIVIDER = "Divider"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@dataclass
|
|
226
|
+
class Control:
|
|
227
|
+
"""
|
|
228
|
+
A form control bound to a serializer field.
|
|
229
|
+
Uses same attribute names as FieldDisplayConfig for consistency.
|
|
230
|
+
|
|
231
|
+
Attributes:
|
|
232
|
+
field_name: The serializer field this control is bound to
|
|
233
|
+
display_component: Custom UI component name
|
|
234
|
+
filter_queryset: Filter options for FK/M2M fields
|
|
235
|
+
display_help_text: Additional help text
|
|
236
|
+
extra: Additional custom metadata passed to the component
|
|
237
|
+
label: Override the field's title
|
|
238
|
+
full_width: Whether this control should span full width
|
|
239
|
+
"""
|
|
240
|
+
field_name: str
|
|
241
|
+
display_component: Optional[str] = None
|
|
242
|
+
filter_queryset: Optional[Dict[str, Any]] = None
|
|
243
|
+
display_help_text: Optional[str] = None
|
|
244
|
+
extra: Optional[Dict[str, Any]] = None
|
|
245
|
+
label: Optional[str] = None
|
|
246
|
+
full_width: bool = False
|
|
247
|
+
type: Literal["Control"] = field(default="Control", init=False)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@dataclass
|
|
251
|
+
class Display:
|
|
252
|
+
"""
|
|
253
|
+
A display-only element that renders data from context.
|
|
254
|
+
Does not collect input - purely for showing information.
|
|
255
|
+
|
|
256
|
+
Attributes:
|
|
257
|
+
context_path: Dot-notation path to value in workflow context (e.g., "unit.access_code")
|
|
258
|
+
display_component: UI component to render with (e.g., "code-display", "copy-url")
|
|
259
|
+
label: Label to show above the display
|
|
260
|
+
extra: Additional custom metadata passed to the component
|
|
261
|
+
"""
|
|
262
|
+
context_path: Optional[str] = None
|
|
263
|
+
display_component: str = "text"
|
|
264
|
+
label: Optional[str] = None
|
|
265
|
+
extra: Optional[Dict[str, Any]] = None
|
|
266
|
+
type: Literal["Display"] = field(default="Display", init=False)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@dataclass
|
|
270
|
+
class Alert:
|
|
271
|
+
"""
|
|
272
|
+
An alert/info banner element.
|
|
273
|
+
|
|
274
|
+
Attributes:
|
|
275
|
+
severity: Alert type - "info", "warning", "error", "success"
|
|
276
|
+
text: Static text to display
|
|
277
|
+
context_path: Or pull text from context
|
|
278
|
+
"""
|
|
279
|
+
severity: Literal["info", "warning", "error", "success"] = "info"
|
|
280
|
+
text: Optional[str] = None
|
|
281
|
+
context_path: Optional[str] = None
|
|
282
|
+
type: Literal["Alert"] = field(default="Alert", init=False)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@dataclass
|
|
286
|
+
class Label:
|
|
287
|
+
"""
|
|
288
|
+
A static text label element.
|
|
289
|
+
|
|
290
|
+
Attributes:
|
|
291
|
+
text: The text to display
|
|
292
|
+
variant: Text style - "heading", "subheading", "body", "caption"
|
|
293
|
+
"""
|
|
294
|
+
text: str
|
|
295
|
+
variant: Literal["heading", "subheading", "body", "caption"] = "body"
|
|
296
|
+
type: Literal["Label"] = field(default="Label", init=False)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@dataclass
|
|
300
|
+
class Divider:
|
|
301
|
+
"""A visual separator/divider element."""
|
|
302
|
+
type: Literal["Divider"] = field(default="Divider", init=False)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class Conditional:
|
|
307
|
+
"""
|
|
308
|
+
Conditionally render a layout based on form data or context.
|
|
309
|
+
|
|
310
|
+
The `when` expression is evaluated as JavaScript with access to:
|
|
311
|
+
- formData: Current form field values
|
|
312
|
+
- context: Workflow context data
|
|
313
|
+
|
|
314
|
+
Examples:
|
|
315
|
+
when="formData.payment_method === 'card'"
|
|
316
|
+
when="context.has_wifi === true"
|
|
317
|
+
when="formData.amount > 100"
|
|
318
|
+
|
|
319
|
+
Attributes:
|
|
320
|
+
when: JavaScript expression that returns a boolean
|
|
321
|
+
layout: Layout to render when condition is true
|
|
322
|
+
"""
|
|
323
|
+
when: str
|
|
324
|
+
layout: "LayoutElement"
|
|
325
|
+
type: Literal["Conditional"] = field(default="Conditional", init=False)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@dataclass
|
|
329
|
+
class Tab:
|
|
330
|
+
"""
|
|
331
|
+
A single tab within a Tabs container.
|
|
332
|
+
|
|
333
|
+
Attributes:
|
|
334
|
+
label: Tab button label
|
|
335
|
+
layout: Content to render when tab is active
|
|
336
|
+
"""
|
|
337
|
+
label: str
|
|
338
|
+
layout: "LayoutElement"
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@dataclass
|
|
342
|
+
class Tabs:
|
|
343
|
+
"""
|
|
344
|
+
A tabbed container for organizing content into switchable panels.
|
|
345
|
+
|
|
346
|
+
Attributes:
|
|
347
|
+
tabs: List of Tab elements
|
|
348
|
+
default_tab: Index of initially active tab (0-based)
|
|
349
|
+
"""
|
|
350
|
+
tabs: List[Tab] = field(default_factory=list)
|
|
351
|
+
default_tab: int = 0
|
|
352
|
+
type: Literal["Tabs"] = field(default="Tabs", init=False)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# Layout element union type for type hints
|
|
356
|
+
LayoutElement = Union[
|
|
357
|
+
Control, Display, Alert, Label, Divider, Conditional, Tabs,
|
|
358
|
+
"VerticalLayout", "HorizontalLayout", "Group"
|
|
359
|
+
]
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@dataclass
|
|
363
|
+
class VerticalLayout:
|
|
364
|
+
"""
|
|
365
|
+
Stack elements vertically.
|
|
366
|
+
|
|
367
|
+
Attributes:
|
|
368
|
+
elements: Child layout elements
|
|
369
|
+
gap: Spacing between elements - "sm", "md", "lg"
|
|
370
|
+
"""
|
|
371
|
+
elements: List["LayoutElement"] = field(default_factory=list)
|
|
372
|
+
gap: Literal["sm", "md", "lg"] = "md"
|
|
373
|
+
type: Literal["VerticalLayout"] = field(default="VerticalLayout", init=False)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@dataclass
|
|
377
|
+
class HorizontalLayout:
|
|
378
|
+
"""
|
|
379
|
+
Stack elements horizontally.
|
|
380
|
+
|
|
381
|
+
Attributes:
|
|
382
|
+
elements: Child layout elements
|
|
383
|
+
gap: Spacing between elements - "sm", "md", "lg"
|
|
384
|
+
align: Vertical alignment - "start", "center", "end", "stretch"
|
|
385
|
+
"""
|
|
386
|
+
elements: List["LayoutElement"] = field(default_factory=list)
|
|
387
|
+
gap: Literal["sm", "md", "lg"] = "md"
|
|
388
|
+
align: Literal["start", "center", "end", "stretch"] = "start"
|
|
389
|
+
type: Literal["HorizontalLayout"] = field(default="HorizontalLayout", init=False)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
@dataclass
|
|
393
|
+
class Group:
|
|
394
|
+
"""
|
|
395
|
+
A labeled container/section with nested layout.
|
|
396
|
+
|
|
397
|
+
Attributes:
|
|
398
|
+
label: Section heading
|
|
399
|
+
description: Section description
|
|
400
|
+
layout: Nested layout (defaults to VerticalLayout)
|
|
401
|
+
collapsible: Whether the group can be collapsed
|
|
402
|
+
collapsed: Initial collapsed state
|
|
403
|
+
"""
|
|
404
|
+
label: str
|
|
405
|
+
description: Optional[str] = None
|
|
406
|
+
layout: Optional["LayoutElement"] = None
|
|
407
|
+
collapsible: bool = False
|
|
408
|
+
collapsed: bool = False
|
|
409
|
+
type: Literal["Group"] = field(default="Group", init=False)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
# Convenience type for the root layout
|
|
413
|
+
Layout = Union[VerticalLayout, HorizontalLayout]
|
|
414
|
+
|
|
415
|
+
|
|
208
416
|
@dataclass
|
|
209
417
|
class DisplayMetadata:
|
|
210
418
|
"""
|
|
@@ -214,11 +422,16 @@ class DisplayMetadata:
|
|
|
214
422
|
display_title: Main heading/title override
|
|
215
423
|
display_description: Explanatory text about the model/action
|
|
216
424
|
field_groups: Logical grouping of fields (e.g., "Contact Info", "Address Details")
|
|
425
|
+
- Legacy: use `layout` for more control
|
|
217
426
|
field_display_configs: Per-field customization (custom components, filters, help text)
|
|
427
|
+
- Legacy: use Control elements in `layout` for more control
|
|
428
|
+
layout: Rich layout tree for complex form/display rendering. Takes precedence over
|
|
429
|
+
field_groups when present. Supports nesting, display-only elements, conditionals, etc.
|
|
218
430
|
extra: Additional custom metadata for framework-specific or UI-specific extensions
|
|
219
431
|
"""
|
|
220
432
|
display_title: Optional[str] = None
|
|
221
433
|
display_description: Optional[str] = None
|
|
222
434
|
field_groups: Optional[List[FieldGroup]] = None
|
|
223
435
|
field_display_configs: Optional[List[FieldDisplayConfig]] = None
|
|
436
|
+
layout: Optional[Layout] = None
|
|
224
437
|
extra: Optional[Dict[str, Any]] = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: statezero
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0b63
|
|
4
4
|
Summary: Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity.
|
|
5
5
|
Author-email: Robert <robert.herring@statezero.dev>
|
|
6
6
|
Project-URL: homepage, https://www.statezero.dev
|
|
@@ -39,7 +39,7 @@ statezero/core/__init__.py,sha256=IaNGa9WGZ-2OopG8UTqmijDZcwpC8tIGrfkl_cvCjBk,10
|
|
|
39
39
|
statezero/core/actions.py,sha256=MO1NN5Vtc-nu1e43x32hHrEdPRXWTYRvbC5sKPZczXQ,5385
|
|
40
40
|
statezero/core/ast_parser.py,sha256=oKDchCrv2FDN2UsnC3mfI-6D3HiqXtlID5JLock6Aow,45382
|
|
41
41
|
statezero/core/ast_validator.py,sha256=130IMTemJnIWd3PQHTLZYLfMFBLMmkTm37ckwHpt-QY,12214
|
|
42
|
-
statezero/core/classes.py,sha256=
|
|
42
|
+
statezero/core/classes.py,sha256=UZugF4ZAqewyOtr_WMu0N9pa0U6bwTfEwYEML8Fq6qs,13272
|
|
43
43
|
statezero/core/config.py,sha256=LdFlGutkJF-rsIViJwbRHVOFKWzt-33Q0Inhcba8PnY,14875
|
|
44
44
|
statezero/core/context_storage.py,sha256=nyQX8dGavLeaFosApupLqsMmy1269Ederwz8PjRRjvE,846
|
|
45
45
|
statezero/core/event_bus.py,sha256=jqmzTTHJCqBoQ0OnDYWt5fbpNt_z1hgZu_2TdWZ2CP4,8303
|
|
@@ -51,7 +51,7 @@ statezero/core/process_request.py,sha256=s1yys2ms856KJxV-cIfnVIdMkrOW9nLfzyLor64
|
|
|
51
51
|
statezero/core/query_cache.py,sha256=zLRbvWw4H30Wn0JSPlPyNc1FVqhzFeu4n3dhCWILj4U,9155
|
|
52
52
|
statezero/core/telemetry.py,sha256=EV2yLV6WAS-MTYCQSRQadiMgOD_ViJ_qUspgvbD0GqA,7757
|
|
53
53
|
statezero/core/types.py,sha256=An57YP1sdd7u6eppXeKMoSudEn_6-Pb6UoC3IdR5E8w,916
|
|
54
|
-
statezero-0.1.
|
|
55
|
-
statezero-0.1.
|
|
56
|
-
statezero-0.1.
|
|
57
|
-
statezero-0.1.
|
|
54
|
+
statezero-0.1.0b63.dist-info/METADATA,sha256=HTBbii2bSOhFCMbb1ViV90PqzIK_tf12U0U8eB5096E,9872
|
|
55
|
+
statezero-0.1.0b63.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
56
|
+
statezero-0.1.0b63.dist-info/top_level.txt,sha256=UAuZYPKczradU1kcMQxsGjUzEW0qdgsqzhXyscrcLpw,10
|
|
57
|
+
statezero-0.1.0b63.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|