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 TypeHandler Action
mtCardSavedOpenDashboardLayoutAsync(FirstDashboardNumber)
mtDashboardSavedStartAsync(UserID) - full reload
mtDashboardDeletedDeleteDashboardAsync(payload.DashboardNumber)
mtErrorOccurredError handling

TCard Subscriptions

Message TypeHandler Action
mtModeChangedUpdate TrafficLight, Paused state
mtFormMessageUpdate SubtitleLabel
mtChartButtonClickForward to embedded form
mtMapButtonClickForward to embedded form
mtCardDeleteHandle card deletion
mtCardSetupShow setup panel
mtCardShowInfoShow info panel
mtCardResumeAllResume card updates
mtCardPausedPause card updates
mtCardRefreshMapRefresh map display
mtCardRefreshChartRefresh chart display
mtCardDroppedHandle card drop
mtCardChangedHandle card change
mtCardLoadingStartShow loading indicator
mtAttachObjectAttach external object

Header Button Actions by Dashboard Mode

Display Mode (mdDisplay)

ButtonMessage SentEffect
Chart/MapmtChartButtonClick / mtMapButtonClickRefresh data visualization
GridmtCardShowGridShow data grid, maximize card
InfomtCardShowInfoShow info panel
SetupmtCardSetupShow settings panel
Date RangemtCardSetDateRangeOpen date picker, pause card
MaximizemtCanvasMaximizeExpand card to full canvas
AdjustmtAdjustLayoutSwitch to sizing header

Layout Mode (mdLayout)

ButtonMessage SentEffect
→ (Expand Right)mtCanvasExpandRightIncrease span across
↓ (Expand Down)mtCanvasExpandDownIncrease span down
↗ (Expand Both)mtCanvasExpandBothIncrease both spans
← (Shrink Left)mtCanvasShrinkLeftDecrease span across
↑ (Shrink Up)mtCanvasShrinkUpDecrease span down
↙ (Shrink Both)mtCanvasShrinkBothDecrease both spans
DeletemtCardDeleteRemove 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

StateCSS ClassMeaning
tlGreen.loadingCard is actively loading/updating data
tlOrange.pausedCard is paused (user interaction or waiting)
tlRed.stoppedCard is stopped/error state