diff --git a/backend/apps/dashboards/models.py b/backend/apps/dashboards/models.py index 22ede85c..3f514033 100644 --- a/backend/apps/dashboards/models.py +++ b/backend/apps/dashboards/models.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from typing import Optional from datetime import datetime from uuid import uuid4 @@ -53,9 +53,17 @@ class NotePosition(BaseModel): class DashboardLayout(BaseModel): + # Accept whatever the FE serialises (workflow_cards, configure_panels, + # workflows_hub etc). Pydantic was silently stripping these because + # they weren't declared, which made the dashboard re-render WITHOUT + # the workflow card the user just placed. + model_config = ConfigDict(extra="allow") cards: dict[str, CardPosition] = Field(default_factory=dict) view_cards: dict[str, ViewCardPosition] = Field(default_factory=dict) browser_cards: dict[str, BrowserCardPosition] = Field(default_factory=dict) + workflow_cards: dict = Field(default_factory=dict) + configure_panels: dict = Field(default_factory=dict) + workflows_hub: Optional[dict] = None notes: dict[str, NotePosition] = Field(default_factory=dict) expanded_session_ids: list[str] = Field(default_factory=list) diff --git a/frontend/src/shared/state/store.ts b/frontend/src/shared/state/store.ts index 89155cb4..6e248635 100644 --- a/frontend/src/shared/state/store.ts +++ b/frontend/src/shared/state/store.ts @@ -59,3 +59,10 @@ export const store = configureStore({ export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch; + +// Expose the store on window in dev so playwright + the user's devtools +// can drive UI flows without hunting for selectors. The expose is +// guarded by NODE_ENV so production bundles don't ship it. +if (typeof window !== 'undefined' && process.env.NODE_ENV !== 'production') { + (window as unknown as { __OPENSWARM_STORE__?: typeof store }).__OPENSWARM_STORE__ = store; +}