157 lines
4.2 KiB
Rust
157 lines
4.2 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
pub use anyhow::Result;
|
|
use async_trait::async_trait;
|
|
use collab::core::origin::CollabOrigin;
|
|
use collab::entity::EncodedCollab;
|
|
|
|
use collab::preclude::Collab;
|
|
use collab_entity::CollabType;
|
|
use collab_folder::{
|
|
timestamp, Folder, FolderData, RepeatedViewIdentifier, ViewIdentifier, ViewLayout, Workspace,
|
|
};
|
|
|
|
use crate::hierarchy_builder::{FlattedViews, WorkspaceViewBuilder};
|
|
|
|
pub mod database;
|
|
pub mod document;
|
|
|
|
mod hierarchy_builder;
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
#[async_trait]
|
|
pub trait WorkspaceTemplate {
|
|
fn layout(&self) -> ViewLayout;
|
|
|
|
async fn create(&self, object_id: String) -> Result<Vec<TemplateData>>;
|
|
|
|
async fn create_workspace_view(
|
|
&self,
|
|
uid: i64,
|
|
workspace_view_builder: &mut WorkspaceViewBuilder,
|
|
) -> Result<Vec<TemplateData>>;
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum TemplateObjectId {
|
|
Folder(String),
|
|
Document(String),
|
|
DatabaseRow(String),
|
|
Database {
|
|
object_id: String,
|
|
// It's used to reference the database id from the object_id
|
|
database_id: String,
|
|
},
|
|
}
|
|
|
|
pub struct TemplateData {
|
|
pub template_id: TemplateObjectId,
|
|
pub collab_type: CollabType,
|
|
pub encoded_collab: EncodedCollab,
|
|
}
|
|
|
|
pub type WorkspaceTemplateHandlers = HashMap<ViewLayout, Arc<dyn WorkspaceTemplate + Send + Sync>>;
|
|
|
|
/// A builder for creating a workspace template.
|
|
/// workspace template is a set of views that are created when a workspace is created.
|
|
pub struct WorkspaceTemplateBuilder {
|
|
pub uid: i64,
|
|
pub workspace_id: String,
|
|
pub handlers: WorkspaceTemplateHandlers,
|
|
}
|
|
|
|
impl WorkspaceTemplateBuilder {
|
|
pub fn new(uid: i64, workspace_id: &str) -> Self {
|
|
let handlers = WorkspaceTemplateHandlers::default();
|
|
Self {
|
|
uid,
|
|
workspace_id: workspace_id.to_string(),
|
|
handlers,
|
|
}
|
|
}
|
|
|
|
pub fn with_template<T>(mut self, template: T) -> Self
|
|
where
|
|
T: WorkspaceTemplate + Send + Sync + 'static,
|
|
{
|
|
self.handlers.insert(template.layout(), Arc::new(template));
|
|
self
|
|
}
|
|
|
|
pub fn with_templates<T>(mut self, templates: Vec<T>) -> Self
|
|
where
|
|
T: WorkspaceTemplate + Send + Sync + 'static,
|
|
{
|
|
for template in templates {
|
|
self.handlers.insert(template.layout(), Arc::new(template));
|
|
}
|
|
self
|
|
}
|
|
|
|
pub async fn build(&self) -> Result<Vec<TemplateData>> {
|
|
let mut workspace_view_builder = WorkspaceViewBuilder::new(self.workspace_id.clone(), self.uid);
|
|
let mut templates: Vec<TemplateData> = vec![];
|
|
for handler in self.handlers.values() {
|
|
if let Ok(template) = handler
|
|
.create_workspace_view(self.uid, &mut workspace_view_builder)
|
|
.await
|
|
{
|
|
templates.extend(template);
|
|
}
|
|
}
|
|
|
|
let views = workspace_view_builder.build();
|
|
// Safe to unwrap because we have at least one view.
|
|
let first_view = views.first().unwrap().parent_view.clone();
|
|
let first_level_views = views
|
|
.iter()
|
|
.map(|value| ViewIdentifier {
|
|
id: value.parent_view.id.clone(),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let workspace = Workspace {
|
|
id: self.workspace_id.clone(),
|
|
name: "Workspace".to_string(),
|
|
child_views: RepeatedViewIdentifier::new(first_level_views),
|
|
created_at: timestamp(),
|
|
created_by: Some(self.uid),
|
|
last_edited_time: timestamp(),
|
|
last_edited_by: Some(self.uid),
|
|
};
|
|
|
|
let uid = self.uid;
|
|
let workspace_id = self.workspace_id.clone();
|
|
let folder_template = tokio::task::spawn_blocking(move || {
|
|
let folder_data = FolderData {
|
|
workspace,
|
|
current_view: first_view.id,
|
|
views: FlattedViews::flatten_views(views),
|
|
favorites: Default::default(),
|
|
recent: Default::default(),
|
|
trash: Default::default(),
|
|
private: Default::default(),
|
|
};
|
|
|
|
let collab = Collab::new_with_origin(CollabOrigin::Empty, &workspace_id, vec![], false);
|
|
let folder = Folder::create(uid, collab, None, folder_data);
|
|
let data = folder.encode_collab()?;
|
|
Ok::<_, anyhow::Error>(TemplateData {
|
|
template_id: TemplateObjectId::Folder(workspace_id),
|
|
collab_type: CollabType::Folder,
|
|
encoded_collab: data,
|
|
})
|
|
})
|
|
.await??;
|
|
|
|
templates.push(folder_template);
|
|
Ok(templates)
|
|
}
|
|
}
|
|
|
|
pub fn gen_view_id() -> String {
|
|
uuid::Uuid::new_v4().to_string()
|
|
}
|