Dashboard Message Flow Architecture
Comprehensive message flow between DashboardManager, DashboardCanvas, Card, HeaderButtons, and embedded forms.
TMS Web CoreMessage BusObserver Pattern
Component Hierarchy
%%{init: {'theme': 'dark'}}%%
classDiagram
direction TB
class TDashboardManager {
-FDashboards: TObjectDictionary
-FActiveDashboard: TDashboard
-FDashboardCanvas: TDashboardCanvas
-FTransmitter: TTransmitter
-FMessageReceiver: TReceiver
+StartAsync()
+SelectDashboard()
+DeleteDashboardAsync()
+NewDashboard()
+HandleMessageReceived()
}
class TDashboardCanvas {
-FActiveDashboard: TDashboard
-FTransmitter: TTransmitter
-FSaveCardDataSet: TAPIDataSet
+LoadCards()
+RenderDashboard()
+SaveCard()
+MaximizeCard()
+MinimizeCard()
+ExpandRight/Down/Both()
+ShrinkUp/Left/Both()
}
class TCard {
-FContainer: TWebFormContainer
-FHeaderButtons: TWebButtonContainer
-FTransmitter: TTransmitter
-FMessageReceiver: TReceiver
+DrawCard()
+EmbedForm()
+NotifyFormContainer()
+HandleDragDrop()
+CardMessageReceived()
}
class TWebButtonContainer {
-FButtons: TList
+SwitchToButtonType()
+ChangeToDetailsHeader()
+ChangeToSizingHeader()
+OnHeaderButtonClick()
}
class TWebFormContainer {
-FEmbeddedForm: TRoot
-FTransmitter: TTransmitter
+Run()
+RemoveEmbeddedForm()
}
class TTransmitter {
-FRegistrations: TObjectList
+Send()
+SendTo()
+Subscribe()
+Unsubscribe()
}
class TReceiver {
-FMessageBus: TTransmitter
-FAccepted: TMessageTypes
+Subscribe()
+OnMessage()
}
TDashboardManager --> TDashboardCanvas
TDashboardManager --> TTransmitter
TDashboardManager --> TReceiver
TDashboardCanvas --> TCard
TDashboardCanvas --> TTransmitter
TCard --> TWebButtonContainer
TCard --> TWebFormContainer
TCard --> TReceiver
TWebFormContainer --> TTransmitter
Message Types Reference
Card Interaction Messages
mtCardSelected
mtCardPaused
mtCardStopped
mtCardResumeAll
mtCardSetup
mtCardShowInfo
mtCardShowGrid
mtCardDelete
mtCardDropped
mtCardChanged
mtCardSaved
mtCardSetDateRange
mtCardLoadingStart
Canvas Sizing Messages
mtCanvasMaximize
mtCanvasMinimize
mtCanvasExpandRight
mtCanvasExpandDown
mtCanvasExpandBoth
mtCanvasShrinkUp
mtCanvasShrinkLeft
mtCanvasShrinkBoth
mtAdjustLayout
Data Refresh Messages
mtMapButtonClick
mtChartButtonClick
mtCardRefreshMap
mtCardRefreshChart
mtPeriodChanged
mtModeChanged
Dashboard Messages
mtDashboardSelected
mtDashboardCreate
mtDashboardCreated
mtDashboardDeleted
mtDashboardChanged
mtDashboardSaved
mtLayoutLoaded
System Messages
mtDOMIsReady
mtErrorOccurred
mtFormMessage
mtFormCompleted
mtAttachObject
mtContainerResized
mtLoadingShow
mtLoadingHide
User Action: Click Card Header Button
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant HB as HeaderButtons
participant C as TCard
participant T as Transmitter
participant FC as FormContainer
participant EF as EmbeddedForm
U->>HB: Click button (e.g. Chart)
HB->>HB: DoOnHeaderButtonsButtonClick()
HB->>C: OnHeaderButtonClick(mtChartButtonClick)
C->>C: CreateCardPayload()
C->>C: NotifyFormContainer()
C->>T: Send(mtChartButtonClick, payload)
T->>EF: Dispatch to subscribed form
EF->>EF: HandleMessage()
EF-->>U: Update chart display
User Action: Drag Card to New Position
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant SC as SourceCard
participant TC as TargetCard
participant CV as DashboardCanvas
participant API as SaveCardDataSet
participant DB as Database
U->>SC: Start drag (MouseDown on header)
SC->>SC: BeginDrag()
SC->>SC: DoOnStartDrag() → TCardDragObject
U->>TC: Drop on target card
TC->>TC: HandleDragOver() → Accept=true
TC->>TC: HandleDragDrop()
TC->>TC: Copy properties from source
TC->>TC: EmbedForm()
TC->>TC: ChangeToDetailsHeader()
TC->>CV: OnHandleDrop()
CV->>CV: InternalDoOnHandleDrop()
CV->>CV: SaveCard(TargetCard)
CV->>API: Set params & Connect
API->>DB: UPDATE card position
DB-->>API: Success
API->>CV: DoOnCardSaved()
CV->>CV: OnCardSaved event
User Action: Expand Card Right
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant HB as HeaderButtons
participant C as TCard
participant CV as DashboardCanvas
participant OC as OtherCards
U->>HB: Click ExpandRight arrow
HB->>C: DoOnHeaderButtonsButtonClick(mtCanvasExpandRight)
C->>C: CardInDesignMode = true
C->>C: Paused = true
C->>CV: OnExpandRight()
CV->>CV: ExpandRight()
CV->>CV: PushCardOutOfWay(card, newSpan)
loop Each overlapping card
CV->>OC: Move to next free position
CV->>CV: IsPositionOccupied() check
end
CV->>CV: SaveCard(each moved card)
CV->>CV: RenderDashboard()
CV-->>U: Updated grid layout
User Action: Delete Card Content
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant HB as HeaderButtons
participant C as TCard
participant FC as FormContainer
participant CV as DashboardCanvas
participant API as SaveCardDataSet
U->>HB: Click Delete button
HB->>C: DoOnHeaderButtonsButtonClick(mtCardDelete)
C->>C: CardInDesignMode = false
C->>C: HandleDeleteCardClick()
C->>FC: RemoveEmbeddedForm()
FC->>FC: Free embedded form
C->>C: CardVisible = vInvisible
C->>CV: OnDeleteCard()
CV->>CV: DoOnCardDelete()
CV->>CV: Card.TileId = 0
CV->>CV: SaveCard(card)
CV->>API: CardVisible = false, TileId = 0
API-->>CV: Saved
User Action: Select Dashboard from Sidebar
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant SB as SideBar
participant DM as DashboardManager
participant CV as DashboardCanvas
participant API as LayoutDataSet
participant DB as Database
U->>SB: Click dashboard name
SB->>DM: SelectDashboard(number)
DM->>DM: OpenDashboardLayoutAsync()
DM->>API: Set DashboardNumber param
DM->>API: Connected = true
API->>DB: SELECT layout for dashboard
DB-->>API: Card layout records
API->>DM: DoOnLayoutDatasetLoaded()
DM->>DM: LoadDashboardInCanvas()
DM->>CV: Set LayoutDataSet, ActiveDashboard
DM->>CV: LoadCards()
DM->>DM: RenderDashboard()
CV->>CV: ClearCanvas()
CV->>CV: CreateCardsFromLayoutDataSet()
loop Each card record
CV->>CV: Create TCard
CV->>CV: Set position, span, properties
CV->>CV: AddCard to ActiveDashboard
end
CV->>CV: RenderDashboard()
CV->>CV: EmbedForms()
DM->>DM: OnDashboardOpened event
User Action: Create New Dashboard
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant U as User
participant DM as DashboardManager
participant API as SaveDashboardDataSet
participant DB as Database
participant SB as SideBar
U->>DM: NewDashboard(name, period, periodType)
DM->>DM: FNewDashboard = true
DM->>DM: SaveDashboardAsync()
DM->>API: Set all params
DM->>API: Connected = true
API->>DB: INSERT new dashboard
DB-->>API: Return DashboardId
API->>DM: DoOnSavedDashboard()
DM->>SB: AddCard(name, id)
SB->>SB: Create sidebar card
SB->>SB: SelectCard(id)
DM->>DM: Create TDashboard object
DM->>DM: Add to Dashboards dictionary
DM->>DM: SelectDashboard(id)
DM->>DM: OnNewDashboard event
Message Receiver Subscriptions by Component
TDashboardManager Subscriptions
| Message Type | Handler Action |
|---|---|
mtCardSaved | OpenDashboardLayoutAsync(FirstDashboardNumber) |
mtDashboardSaved | StartAsync(UserID) - full reload |
mtDashboardDeleted | DeleteDashboardAsync(payload.DashboardNumber) |
mtErrorOccurred | Error handling |
TCard Subscriptions
| Message Type | Handler Action |
|---|---|
mtModeChanged | Update TrafficLight, Paused state |
mtFormMessage | Update SubtitleLabel |
mtChartButtonClick | Forward to embedded form |
mtMapButtonClick | Forward to embedded form |
mtCardDelete | Handle card deletion |
mtCardSetup | Show setup panel |
mtCardShowInfo | Show info panel |
mtCardResumeAll | Resume card updates |
mtCardPaused | Pause card updates |
mtCardRefreshMap | Refresh map display |
mtCardRefreshChart | Refresh chart display |
mtCardDropped | Handle card drop |
mtCardChanged | Handle card change |
mtCardLoadingStart | Show loading indicator |
mtAttachObject | Attach external object |
Header Button Actions by Dashboard Mode
Display Mode (mdDisplay)
| Button | Message Sent | Effect |
|---|---|---|
| Chart/Map | mtChartButtonClick / mtMapButtonClick | Refresh data visualization |
| Grid | mtCardShowGrid | Show data grid, maximize card |
| Info | mtCardShowInfo | Show info panel |
| Setup | mtCardSetup | Show settings panel |
| Date Range | mtCardSetDateRange | Open date picker, pause card |
| Maximize | mtCanvasMaximize | Expand card to full canvas |
| Adjust | mtAdjustLayout | Switch to sizing header |
Layout Mode (mdLayout)
| Button | Message Sent | Effect |
|---|---|---|
| → (Expand Right) | mtCanvasExpandRight | Increase span across |
| ↓ (Expand Down) | mtCanvasExpandDown | Increase span down |
| ↗ (Expand Both) | mtCanvasExpandBoth | Increase both spans |
| ← (Shrink Left) | mtCanvasShrinkLeft | Decrease span across |
| ↑ (Shrink Up) | mtCanvasShrinkUp | Decrease span down |
| ↙ (Shrink Both) | mtCanvasShrinkBoth | Decrease both spans |
| Delete | mtCardDelete | Remove card content |
TPayload Structure
All messages carry a TPayload or TCardPayload object containing context:
TPayload
├── Key: string
├── IntValue: integer (CardNumber)
├── Target: TObject (EmbeddedForm)
├── TargetName: string (Form pagename)
├── Action: TMessageType
├── Paused: boolean
├── TrafficLight: TTrafficLight
├── XClickedPosition, YClickedPosition: integer
└── TileId: integer
TCardPayload (extends TPayload)
├── CardNumber: integer
├── DashboardNumber: integer
├── DashboardName: string
├── Period: integer
├── PeriodUnit: TPeriodUnit
├── DataDisplayType: TDataDisplayType
├── Position: TCardPosition (Col, Row)
├── Span: TCardSpan (Across, Down)
└── Radius: double
Traffic Light States
| State | CSS Class | Meaning |
|---|---|---|
tlGreen | .loading | Card is actively loading/updating data |
tlOrange | .paused | Card is paused (user interaction or waiting) |
tlRed | .stopped | Card is stopped/error state |