Skip to main content

cx_sdk/client/
dashboards.rs

1// Copyright 2024 Coralogix Ltd.
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//     https://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
15use std::str::FromStr;
16
17use crate::{
18    auth::AuthContext,
19    error::{
20        Result,
21        SdkApiError,
22        SdkError,
23    },
24    metadata::CallProperties,
25    util::make_request_with_metadata,
26};
27
28pub use crate::com::coralogixapis::actions::v2::Action;
29
30pub use cx_api::proto::com::coralogixapis::dashboards::v1::ast::*;
31use cx_api::proto::com::coralogixapis::dashboards::v1::services::{
32    AssignDashboardFolderRequest,
33    AssignDashboardFolderResponse,
34    CreateDashboardRequest,
35    CreateDashboardResponse,
36    DeleteDashboardRequest,
37    DeleteDashboardResponse,
38    GetDashboardCatalogRequest,
39    GetDashboardCatalogResponse,
40    GetDashboardRequest,
41    GetDashboardResponse,
42    PinDashboardRequest,
43    PinDashboardResponse,
44    ReplaceDashboardRequest,
45    ReplaceDashboardResponse,
46    UnpinDashboardRequest,
47    UnpinDashboardResponse,
48    dashboard_catalog_service_client::DashboardCatalogServiceClient,
49    dashboards_service_client::DashboardsServiceClient,
50};
51use tokio::sync::Mutex;
52use tonic::{
53    Request,
54    metadata::MetadataMap,
55    transport::{
56        Channel,
57        ClientTlsConfig,
58        Endpoint,
59    },
60};
61
62const DASHBOARDS_FEATURE_GROUP_ID: &str = "dashboards";
63
64use crate::CoralogixRegion;
65
66/// The Dashboards API client.
67/// Read more at <https://coralogix.com/docs/custom-dashboards/>
68pub struct DashboardsClient {
69    teams_level_metadata_map: MetadataMap,
70    user_level_metadata_map: MetadataMap,
71    service_client: Mutex<DashboardsServiceClient<Channel>>,
72    catalog_client: Mutex<DashboardCatalogServiceClient<Channel>>,
73}
74
75impl DashboardsClient {
76    /// Creates a new client for the Dashboards API.
77    ///
78    /// # Arguments
79    /// * `auth_context` - The [`AuthContext`] to use for authentication.
80    /// * `region` - The [`CoralogixRegion`] to connect to.
81    pub fn new(auth_context: AuthContext, region: CoralogixRegion) -> Result<Self> {
82        let channel: Channel = Endpoint::from_str(region.grpc_endpoint().as_str())?
83            .tls_config(ClientTlsConfig::new().with_native_roots())?
84            .connect_lazy();
85        let teams_level_auth_data: CallProperties = (&auth_context.team_level_api_key).into();
86        let user_level_auth_data: CallProperties = (&auth_context.user_level_api_key).into();
87        Ok(Self {
88            teams_level_metadata_map: teams_level_auth_data.to_metadata_map(),
89            user_level_metadata_map: user_level_auth_data.to_metadata_map(),
90            service_client: Mutex::new(DashboardsServiceClient::new(channel.clone())),
91            catalog_client: Mutex::new(DashboardCatalogServiceClient::new(channel)),
92        })
93    }
94
95    /// Creates a new dashboard.
96    ///
97    /// # Arguments
98    /// * `dashboard` - The dashboard to create.
99    pub async fn create(
100        &self,
101        dashboard: Dashboard,
102        is_locked: bool,
103    ) -> Result<CreateDashboardResponse> {
104        self.create_with_access_policy(dashboard, is_locked, None)
105            .await
106    }
107
108    /// Creates a new dashboard with an optional access policy.
109    ///
110    /// # Arguments
111    /// * `dashboard` - The dashboard to create.
112    /// * `access_policy` - JSON string representing the dashboard access policy.
113    pub async fn create_with_access_policy(
114        &self,
115        dashboard: Dashboard,
116        is_locked: bool,
117        access_policy: Option<String>,
118    ) -> Result<CreateDashboardResponse> {
119        let request: Request<CreateDashboardRequest> = make_request_with_metadata(
120            CreateDashboardRequest {
121                request_id: None,
122                dashboard: Some(dashboard),
123                is_locked: Some(is_locked),
124                access_policy,
125            },
126            &self.teams_level_metadata_map,
127        );
128        {
129            let mut client = self.service_client.lock().await.clone();
130
131            client
132                .create_dashboard(request)
133                .await
134                .map(|r| r.into_inner())
135                .map_err(|status| {
136                    SdkError::ApiError(SdkApiError {
137                        status,
138                        endpoint:
139                            "/com.coralogixapis.dashboards.v1.DashboardsService/CreateDashboard"
140                                .into(),
141                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
142                    })
143                })
144        }
145    }
146
147    /// Replaces a dashboard.
148    ///
149    /// # Arguments
150    /// * `dashboard` - The [`Dashboard`] to replace.
151    pub async fn replace(
152        &self,
153        dashboard: Dashboard,
154        is_locked: bool,
155    ) -> Result<ReplaceDashboardResponse> {
156        self.replace_with_access_policy(dashboard, is_locked, None)
157            .await
158    }
159
160    /// Replaces a dashboard with an optional access policy.
161    ///
162    /// # Arguments
163    /// * `dashboard` - The [`Dashboard`] to replace.
164    /// * `access_policy` - JSON string representing the dashboard access policy.
165    pub async fn replace_with_access_policy(
166        &self,
167        dashboard: Dashboard,
168        is_locked: bool,
169        access_policy: Option<String>,
170    ) -> Result<ReplaceDashboardResponse> {
171        let request: Request<ReplaceDashboardRequest> = make_request_with_metadata(
172            ReplaceDashboardRequest {
173                request_id: None,
174                dashboard: Some(dashboard),
175                is_locked: Some(is_locked),
176                access_policy,
177            },
178            &self.teams_level_metadata_map,
179        );
180        {
181            let mut client = self.service_client.lock().await.clone();
182
183            client
184                .replace_dashboard(request)
185                .await
186                .map(|r| r.into_inner())
187                .map_err(|status| {
188                    SdkError::ApiError(SdkApiError {
189                        status,
190                        endpoint:
191                            "/com.coralogixapis.dashboards.v1.DashboardsService/ReplaceDashboard"
192                                .into(),
193                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
194                    })
195                })
196        }
197    }
198
199    /// Gets a dashboard by its ID.
200    ///
201    /// # Arguments
202    /// * `dashboard_id` - The ID of the dashboard to get.
203    pub async fn get(&self, dashboard_id: String) -> Result<GetDashboardResponse> {
204        let request: Request<GetDashboardRequest> = make_request_with_metadata(
205            GetDashboardRequest {
206                dashboard_id: Some(dashboard_id),
207            },
208            &self.teams_level_metadata_map,
209        );
210        {
211            let mut client = self.service_client.lock().await.clone();
212
213            client
214                .get_dashboard(request)
215                .await
216                .map(|r| r.into_inner())
217                .map_err(|status| {
218                    SdkError::ApiError(SdkApiError {
219                        status,
220                        endpoint: "/com.coralogixapis.dashboards.v1.DashboardsService/GetDashboard"
221                            .into(),
222                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
223                    })
224                })
225        }
226    }
227
228    /// Lists all dashboards.
229    pub async fn list(&self) -> Result<GetDashboardCatalogResponse> {
230        let mut client = self.catalog_client.lock().await.clone();
231
232        client
233            .get_dashboard_catalog(make_request_with_metadata(
234                GetDashboardCatalogRequest {},
235                &self.user_level_metadata_map,
236            ))
237            .await
238            .map(|r| r.into_inner())
239            .map_err(
240                |status| SdkError::ApiError(SdkApiError {
241                    status,
242                    endpoint: "/com.coralogixapis.dashboards.v1.DashboardCatalogService/GetDashboardCatalog".into(),
243                    feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
244                },
245            ))
246    }
247
248    /// Deletes a dashboard by its ID.
249    ///
250    /// # Arguments
251    /// * `dashboard_id` - The ID of the dashboard to delete.
252    pub async fn delete(&self, dashboard_id: String) -> Result<DeleteDashboardResponse> {
253        let request: Request<DeleteDashboardRequest> = make_request_with_metadata(
254            DeleteDashboardRequest {
255                request_id: None,
256                dashboard_id: Some(dashboard_id),
257            },
258            &self.teams_level_metadata_map,
259        );
260        {
261            let mut client = self.service_client.lock().await.clone();
262
263            client
264                .delete_dashboard(request)
265                .await
266                .map(|r| r.into_inner())
267                .map_err(|status| {
268                    SdkError::ApiError(SdkApiError {
269                        status,
270                        endpoint:
271                            "/com.coralogixapis.dashboards.v1.DashboardsService/DeleteDashboard"
272                                .into(),
273                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
274                    })
275                })
276        }
277    }
278
279    /// Pins a dashboard by its ID.
280    ///
281    /// # Arguments
282    /// * `dashboard_id` - The ID of the dashboard to pin.
283    pub async fn pin(&self, dashboard_id: String) -> Result<PinDashboardResponse> {
284        let request: Request<PinDashboardRequest> = make_request_with_metadata(
285            PinDashboardRequest {
286                request_id: None,
287                dashboard_id: Some(dashboard_id),
288            },
289            &self.user_level_metadata_map,
290        );
291        {
292            let mut client = self.service_client.lock().await.clone();
293
294            client
295                .pin_dashboard(request)
296                .await
297                .map(|r| r.into_inner())
298                .map_err(|status| {
299                    SdkError::ApiError(SdkApiError {
300                        status,
301                        endpoint: "/com.coralogixapis.dashboards.v1.DashboardsService/PinDashboard"
302                            .into(),
303                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
304                    })
305                })
306        }
307    }
308
309    /// Unpins a dashboard by its ID.
310    ///
311    /// # Arguments
312    /// * `dashboard_id` - The ID of the dashboard to unpin.
313    pub async fn unpin(&self, dashboard_id: String) -> Result<UnpinDashboardResponse> {
314        let request: Request<UnpinDashboardRequest> = make_request_with_metadata(
315            UnpinDashboardRequest {
316                request_id: None,
317                dashboard_id: Some(dashboard_id),
318            },
319            &self.user_level_metadata_map,
320        );
321        {
322            let mut client = self.service_client.lock().await.clone();
323
324            client
325                .unpin_dashboard(request)
326                .await
327                .map(|r| r.into_inner())
328                .map_err(|status| {
329                    SdkError::ApiError(SdkApiError {
330                        status,
331                        endpoint:
332                            "/com.coralogixapis.dashboards.v1.DashboardsService/UnpinDashboard"
333                                .into(),
334                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
335                    })
336                })
337        }
338    }
339
340    /// Assigns a dashboard to a folder.
341    ///
342    /// # Arguments
343    /// * `dashboard_id` - The ID of the dashboard to assign.
344    /// * `folder_id` - The ID of the folder to assign the dashboard to.
345    pub async fn assign_to_folder(
346        &self,
347        dashboard_id: String,
348        folder_id: String,
349    ) -> Result<AssignDashboardFolderResponse> {
350        let request: Request<AssignDashboardFolderRequest> = make_request_with_metadata(
351            AssignDashboardFolderRequest {
352                request_id: None,
353                dashboard_id: Some(dashboard_id),
354                folder_id: Some(folder_id),
355            },
356            &self.teams_level_metadata_map,
357        );
358        {
359            let mut client = self.service_client.lock().await.clone();
360
361            client
362                .assign_dashboard_folder(request)
363                .await
364                .map(|r| r.into_inner())
365                .map_err(
366                    |status| SdkError::ApiError(SdkApiError {
367                        status,
368                        endpoint: "/com.coralogixapis.dashboards.v1.DashboardsService/AssignDashboardFolder".into(),
369                        feature_group: DASHBOARDS_FEATURE_GROUP_ID.into(),
370                    },
371                ))
372        }
373    }
374}