mirror of https://github.com/buster-so/buster.git
Add ReportFile enum variant and implement related database schema and handlers
This commit is contained in:
parent
c21d84a5d2
commit
4277181a71
|
@ -233,6 +233,8 @@ pub enum AssetType {
|
|||
MetricFile,
|
||||
#[serde(rename = "dashboard")]
|
||||
DashboardFile,
|
||||
#[serde(rename = "report")]
|
||||
ReportFile,
|
||||
}
|
||||
|
||||
impl AssetType {
|
||||
|
@ -244,6 +246,7 @@ impl AssetType {
|
|||
AssetType::Chat => "chat",
|
||||
AssetType::MetricFile => "metric",
|
||||
AssetType::DashboardFile => "dashboard",
|
||||
AssetType::ReportFile => "report",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,6 +594,7 @@ impl ToSql<sql_types::AssetTypeEnum, Pg> for AssetType {
|
|||
AssetType::Chat => out.write_all(b"chat")?,
|
||||
AssetType::DashboardFile => out.write_all(b"dashboard_file")?,
|
||||
AssetType::MetricFile => out.write_all(b"metric_file")?,
|
||||
AssetType::ReportFile => out.write_all(b"report_file")?,
|
||||
}
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
@ -605,6 +609,7 @@ impl FromSql<sql_types::AssetTypeEnum, Pg> for AssetType {
|
|||
b"chat" => Ok(AssetType::Chat),
|
||||
b"dashboard_file" => Ok(AssetType::DashboardFile),
|
||||
b"metric_file" => Ok(AssetType::MetricFile),
|
||||
b"report_file" => Ok(AssetType::ReportFile),
|
||||
_ => Err("Unrecognized enum variant".into()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,27 @@ pub struct MetricFile {
|
|||
pub workspace_sharing_enabled_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Insertable, Identifiable, Debug, Clone, Serialize)]
|
||||
#[diesel(table_name = report_files)]
|
||||
pub struct ReportFile {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub content: String,
|
||||
pub organization_id: Uuid,
|
||||
pub created_by: Uuid,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
pub publicly_accessible: bool,
|
||||
pub publicly_enabled_by: Option<Uuid>,
|
||||
pub public_expiry_date: Option<DateTime<Utc>>,
|
||||
pub version_history: VersionHistory,
|
||||
pub public_password: Option<String>,
|
||||
pub workspace_sharing: WorkspaceSharing,
|
||||
pub workspace_sharing_enabled_by: Option<Uuid>,
|
||||
pub workspace_sharing_enabled_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Insertable, Identifiable, Associations, Debug, Clone, Serialize)]
|
||||
#[diesel(belongs_to(Organization))]
|
||||
#[diesel(belongs_to(User, foreign_key = created_by))]
|
||||
|
|
|
@ -463,6 +463,30 @@ diesel::table! {
|
|||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use super::sql_types::WorkspaceSharingEnum;
|
||||
|
||||
report_files (id) {
|
||||
id -> Uuid,
|
||||
name -> Varchar,
|
||||
content -> Text,
|
||||
organization_id -> Uuid,
|
||||
created_by -> Uuid,
|
||||
created_at -> Timestamptz,
|
||||
updated_at -> Timestamptz,
|
||||
deleted_at -> Nullable<Timestamptz>,
|
||||
publicly_accessible -> Bool,
|
||||
publicly_enabled_by -> Nullable<Uuid>,
|
||||
public_expiry_date -> Nullable<Timestamptz>,
|
||||
version_history -> Jsonb,
|
||||
public_password -> Nullable<Text>,
|
||||
workspace_sharing -> WorkspaceSharingEnum,
|
||||
workspace_sharing_enabled_by -> Nullable<Uuid>,
|
||||
workspace_sharing_enabled_at -> Nullable<Timestamptz>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use super::sql_types::UserOrganizationRoleEnum;
|
||||
|
@ -757,6 +781,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||
metric_files_to_dashboard_files,
|
||||
metric_files_to_datasets,
|
||||
organizations,
|
||||
report_files,
|
||||
permission_groups,
|
||||
permission_groups_to_identities,
|
||||
permission_groups_to_users,
|
||||
|
|
|
@ -10,7 +10,7 @@ use database::{
|
|||
enums::AssetType,
|
||||
pool::get_pg_pool,
|
||||
models::UserFavorite,
|
||||
schema::{collections, collections_to_assets, dashboard_files, chats, messages_deprecated, threads_deprecated, user_favorites, metric_files},
|
||||
schema::{collections, collections_to_assets, dashboard_files, chats, messages_deprecated, threads_deprecated, user_favorites, metric_files, report_files},
|
||||
};
|
||||
|
||||
use middleware::AuthenticatedUser;
|
||||
|
@ -108,10 +108,21 @@ pub async fn list_user_favorites(user: &AuthenticatedUser) -> Result<Vec<Favorit
|
|||
tokio::spawn(async move { get_favorite_chats(chat_ids).await })
|
||||
};
|
||||
|
||||
let (dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res) =
|
||||
match tokio::try_join!(dashboard_favorites, collection_favorites, threads_favorites, metrics_favorites, chats_favorites) {
|
||||
Ok((dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res)) => {
|
||||
(dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res)
|
||||
let reports_favorites = {
|
||||
let report_ids = Arc::new(
|
||||
user_favorites
|
||||
.iter()
|
||||
.filter(|(_, f)| f == &AssetType::ReportFile)
|
||||
.map(|f| f.0)
|
||||
.collect::<Vec<Uuid>>(),
|
||||
);
|
||||
tokio::spawn(async move { get_favorite_reports(report_ids).await })
|
||||
};
|
||||
|
||||
let (dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res, reports_fav_res) =
|
||||
match tokio::try_join!(dashboard_favorites, collection_favorites, threads_favorites, metrics_favorites, chats_favorites, reports_favorites) {
|
||||
Ok((dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res, reports_fav_res)) => {
|
||||
(dashboard_fav_res, collection_fav_res, threads_fav_res, metrics_fav_res, chats_fav_res, reports_fav_res)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error getting favorite assets: {}", e);
|
||||
|
@ -159,6 +170,14 @@ pub async fn list_user_favorites(user: &AuthenticatedUser) -> Result<Vec<Favorit
|
|||
}
|
||||
};
|
||||
|
||||
let favorite_reports = match reports_fav_res {
|
||||
Ok(reports) => reports,
|
||||
Err(e) => {
|
||||
tracing::error!("Error getting favorite reports: {}", e);
|
||||
return Err(anyhow!("Error getting favorite reports: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
let mut favorites: Vec<FavoriteObject> = Vec::with_capacity(user_favorites.len());
|
||||
|
||||
for favorite in &user_favorites {
|
||||
|
@ -211,6 +230,15 @@ pub async fn list_user_favorites(user: &AuthenticatedUser) -> Result<Vec<Favorit
|
|||
});
|
||||
}
|
||||
}
|
||||
AssetType::ReportFile => {
|
||||
if let Some(report) = favorite_reports.iter().find(|r| r.id == favorite.0) {
|
||||
favorites.push(FavoriteObject {
|
||||
id: report.id,
|
||||
name: report.name.clone(),
|
||||
type_: AssetType::ReportFile,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -329,15 +357,20 @@ async fn get_assets_from_collections(
|
|||
tokio::spawn(async move { get_chats_from_collections(&collection_ids).await })
|
||||
};
|
||||
|
||||
let reports_handle = {
|
||||
let collection_ids = Arc::clone(&collection_ids);
|
||||
tokio::spawn(async move { get_reports_from_collections(&collection_ids).await })
|
||||
};
|
||||
|
||||
let collection_name_handle = {
|
||||
let collection_ids = Arc::clone(&collection_ids);
|
||||
tokio::spawn(async move { get_collection_names(&collection_ids).await })
|
||||
};
|
||||
|
||||
let (dashboards_res, metrics_res, chats_res, collection_name_res) =
|
||||
match tokio::join!(dashboards_handle, metrics_handle, chats_handle, collection_name_handle) {
|
||||
(Ok(dashboards), Ok(metrics), Ok(chats), Ok(collection_name)) => {
|
||||
(dashboards, metrics, chats, collection_name)
|
||||
let (dashboards_res, metrics_res, chats_res, reports_res, collection_name_res) =
|
||||
match tokio::join!(dashboards_handle, metrics_handle, chats_handle, reports_handle, collection_name_handle) {
|
||||
(Ok(dashboards), Ok(metrics), Ok(chats), Ok(reports), Ok(collection_name)) => {
|
||||
(dashboards, metrics, chats, reports, collection_name)
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(
|
||||
|
@ -361,6 +394,11 @@ async fn get_assets_from_collections(
|
|||
Err(e) => return Err(anyhow!("Error getting chats from collection: {:?}", e)),
|
||||
};
|
||||
|
||||
let reports = match reports_res {
|
||||
Ok(reports) => reports,
|
||||
Err(e) => return Err(anyhow!("Error getting reports from collection: {:?}", e)),
|
||||
};
|
||||
|
||||
let collection_names = match collection_name_res {
|
||||
Ok(collection_names) => collection_names,
|
||||
Err(e) => return Err(anyhow!("Error getting collection name: {:?}", e)),
|
||||
|
@ -407,6 +445,18 @@ async fn get_assets_from_collections(
|
|||
}),
|
||||
);
|
||||
|
||||
assets.extend(
|
||||
reports
|
||||
.iter()
|
||||
.filter_map(|(report_collection_id, favorite_object)| {
|
||||
if *report_collection_id == collection_id {
|
||||
Some(favorite_object.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
collection_favorites.push(FavoriteObject {
|
||||
id: collection_id,
|
||||
name: collection_name,
|
||||
|
@ -568,6 +618,50 @@ async fn get_chats_from_collections(
|
|||
Ok(chat_objects)
|
||||
}
|
||||
|
||||
async fn get_reports_from_collections(
|
||||
collection_ids: &[Uuid],
|
||||
) -> Result<Vec<(Uuid, FavoriteObject)>> {
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => return Err(anyhow!("Error getting connection from pool: {:?}", e)),
|
||||
};
|
||||
|
||||
let report_records: Vec<(Uuid, Uuid, String)> = match report_files::table
|
||||
.inner_join(
|
||||
collections_to_assets::table.on(report_files::id.eq(collections_to_assets::asset_id)),
|
||||
)
|
||||
.select((
|
||||
collections_to_assets::collection_id,
|
||||
report_files::id,
|
||||
report_files::name,
|
||||
))
|
||||
.filter(collections_to_assets::collection_id.eq_any(collection_ids))
|
||||
.filter(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||
.filter(report_files::deleted_at.is_null())
|
||||
.filter(collections_to_assets::deleted_at.is_null())
|
||||
.load::<(Uuid, Uuid, String)>(&mut conn)
|
||||
.await
|
||||
{
|
||||
Ok(report_records) => report_records,
|
||||
Err(e) => return Err(anyhow!("Error loading report records: {:?}", e)),
|
||||
};
|
||||
|
||||
let report_objects: Vec<(Uuid, FavoriteObject)> = report_records
|
||||
.iter()
|
||||
.map(|(collection_id, id, name)| {
|
||||
(
|
||||
*collection_id,
|
||||
FavoriteObject {
|
||||
id: *id,
|
||||
name: name.clone(),
|
||||
type_: AssetType::ReportFile,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Ok(report_objects)
|
||||
}
|
||||
|
||||
async fn get_favorite_metrics(metric_ids: Arc<Vec<Uuid>>) -> Result<Vec<FavoriteObject>> {
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
|
@ -597,6 +691,35 @@ async fn get_favorite_metrics(metric_ids: Arc<Vec<Uuid>>) -> Result<Vec<Favorite
|
|||
Ok(favorite_metrics)
|
||||
}
|
||||
|
||||
async fn get_favorite_reports(report_ids: Arc<Vec<Uuid>>) -> Result<Vec<FavoriteObject>> {
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => return Err(anyhow!("Error getting connection from pool: {:?}", e)),
|
||||
};
|
||||
|
||||
let report_records: Vec<(Uuid, String)> = match report_files::table
|
||||
.select((report_files::id, report_files::name))
|
||||
.filter(report_files::id.eq_any(report_ids.as_ref()))
|
||||
.filter(report_files::deleted_at.is_null())
|
||||
.load::<(Uuid, String)>(&mut conn)
|
||||
.await
|
||||
{
|
||||
Ok(report_records) => report_records,
|
||||
Err(diesel::NotFound) => return Err(anyhow!("Reports not found")),
|
||||
Err(e) => return Err(anyhow!("Error loading report records: {:?}", e)),
|
||||
};
|
||||
|
||||
let favorite_reports = report_records
|
||||
.iter()
|
||||
.map(|(id, name)| FavoriteObject {
|
||||
id: *id,
|
||||
name: name.clone(),
|
||||
type_: AssetType::ReportFile,
|
||||
})
|
||||
.collect();
|
||||
Ok(favorite_reports)
|
||||
}
|
||||
|
||||
pub async fn update_favorites(user: &AuthenticatedUser, favorites: &[Uuid]) -> Result<()> {
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
|
|
|
@ -155,7 +155,7 @@ const TitleCell = React.memo<{ name: string; chatId: string }>(({ name, chatId }
|
|||
<div className="mr-2 flex items-center" onClick={onFavoriteDivClick}>
|
||||
<FavoriteStar
|
||||
id={chatId}
|
||||
type={'chat'}
|
||||
type={'report'}
|
||||
iconStyle="tertiary"
|
||||
title={name}
|
||||
className="opacity-0 group-hover:opacity-100"
|
||||
|
|
Loading…
Reference in New Issue