Skip to main content

drasi_reaction_dashboard/
lib.rs

1// Copyright 2026 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(unexpected_cfgs)]
16
17//! Dashboard reaction plugin for Drasi.
18
19pub mod api;
20pub mod config;
21pub mod dashboard;
22pub mod descriptor;
23pub mod storage;
24pub mod websocket;
25
26pub use config::DashboardReactionConfig;
27pub use dashboard::DashboardReaction;
28pub use storage::{DashboardConfig, DashboardWidget, GridOptions, WidgetGrid};
29
30/// Builder for dashboard reactions.
31pub struct DashboardReactionBuilder {
32    id: String,
33    queries: Vec<String>,
34    host: String,
35    port: u16,
36    heartbeat_interval_ms: u64,
37    priority_queue_capacity: Option<usize>,
38    auto_start: bool,
39    predefined_dashboards: Vec<DashboardConfig>,
40}
41
42impl DashboardReactionBuilder {
43    /// Create a new dashboard builder with defaults.
44    pub fn new(id: impl Into<String>) -> Self {
45        let config = DashboardReactionConfig::default();
46        Self {
47            id: id.into(),
48            queries: Vec::new(),
49            host: config.host,
50            port: config.port,
51            heartbeat_interval_ms: config.heartbeat_interval_ms,
52            priority_queue_capacity: None,
53            auto_start: true,
54            predefined_dashboards: Vec::new(),
55        }
56    }
57
58    /// Replace subscribed query IDs.
59    pub fn with_queries(mut self, queries: Vec<String>) -> Self {
60        self.queries = queries;
61        self
62    }
63
64    /// Add one subscribed query ID.
65    pub fn with_query(mut self, query_id: impl Into<String>) -> Self {
66        self.queries.push(query_id.into());
67        self
68    }
69
70    /// Set bind host.
71    pub fn with_host(mut self, host: impl Into<String>) -> Self {
72        self.host = host.into();
73        self
74    }
75
76    /// Set bind port.
77    pub fn with_port(mut self, port: u16) -> Self {
78        self.port = port;
79        self
80    }
81
82    /// Set websocket heartbeat interval.
83    pub fn with_heartbeat_interval_ms(mut self, heartbeat_interval_ms: u64) -> Self {
84        self.heartbeat_interval_ms = heartbeat_interval_ms;
85        self
86    }
87
88    /// Set priority queue capacity.
89    pub fn with_priority_queue_capacity(mut self, capacity: usize) -> Self {
90        self.priority_queue_capacity = Some(capacity);
91        self
92    }
93
94    /// Configure auto-start behavior.
95    pub fn with_auto_start(mut self, auto_start: bool) -> Self {
96        self.auto_start = auto_start;
97        self
98    }
99
100    /// Add a predefined dashboard that will be seeded on startup.
101    /// Predefined dashboards are only seeded if they don't already exist in the state store,
102    /// so user edits made via the UI are preserved across restarts.
103    pub fn with_dashboard(mut self, dashboard: DashboardConfig) -> Self {
104        self.predefined_dashboards.push(dashboard);
105        self
106    }
107
108    /// Set full config.
109    pub fn with_config(mut self, config: DashboardReactionConfig) -> Self {
110        self.host = config.host;
111        self.port = config.port;
112        self.heartbeat_interval_ms = config.heartbeat_interval_ms;
113        self
114    }
115
116    /// Build the dashboard reaction.
117    pub fn build(self) -> anyhow::Result<DashboardReaction> {
118        let config = DashboardReactionConfig {
119            host: self.host,
120            port: self.port,
121            heartbeat_interval_ms: self.heartbeat_interval_ms,
122        };
123
124        Ok(DashboardReaction::from_builder(
125            self.id,
126            self.queries,
127            config,
128            self.priority_queue_capacity,
129            self.auto_start,
130            self.predefined_dashboards,
131        ))
132    }
133}
134
135#[cfg(test)]
136mod tests;
137
138/// Dynamic plugin entry point.
139#[cfg(feature = "dynamic-plugin")]
140drasi_plugin_sdk::export_plugin!(
141    plugin_id = "dashboard-reaction",
142    core_version = env!("CARGO_PKG_VERSION"),
143    lib_version = env!("CARGO_PKG_VERSION"),
144    plugin_version = env!("CARGO_PKG_VERSION"),
145    source_descriptors = [],
146    reaction_descriptors = [descriptor::DashboardReactionDescriptor],
147    bootstrap_descriptors = [],
148);