kimun_notes/settings/
workspace_config.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone)]
7pub enum WorkspaceConfigError {
8 DuplicateWorkspace {
9 name: String,
10 existing_path: PathBuf,
11 },
12}
13
14impl std::fmt::Display for WorkspaceConfigError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match self {
17 WorkspaceConfigError::DuplicateWorkspace { name, existing_path } => {
18 write!(f, "Workspace '{}' already exists at {:?}", name, existing_path)
19 }
20 }
21 }
22}
23
24impl std::error::Error for WorkspaceConfigError {}
25
26#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
27pub struct GlobalConfig {
28 pub current_workspace: String,
29 pub theme: String,
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
33pub struct WorkspaceEntry {
34 pub path: PathBuf,
35 pub last_paths: Vec<String>,
36 pub created: DateTime<Utc>,
37 #[serde(default)]
38 pub quick_note_path: Option<String>,
39}
40
41impl WorkspaceEntry {
42 pub fn effective_quick_note_path(&self) -> String {
43 self.quick_note_path.clone().unwrap_or_else(|| kimun_core::nfs::VaultPath::root().to_string())
44 }
45}
46
47#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
48pub struct WorkspaceConfig {
49 pub global: GlobalConfig,
50 pub workspaces: HashMap<String, WorkspaceEntry>,
51}
52
53impl WorkspaceConfig {
54 pub fn new_empty() -> Self {
55 Self {
56 global: GlobalConfig {
57 current_workspace: String::new(),
58 theme: "dark".to_string(),
59 },
60 workspaces: HashMap::new(),
61 }
62 }
63
64 pub fn add_workspace(&mut self, name: String, path: PathBuf) -> Result<(), WorkspaceConfigError> {
65 if self.workspaces.contains_key(&name) {
66 return Err(WorkspaceConfigError::DuplicateWorkspace {
67 name: name.clone(),
68 existing_path: self.workspaces[&name].path.clone(),
69 });
70 }
71
72 let entry = WorkspaceEntry {
73 path,
74 last_paths: Vec::new(),
75 created: Utc::now(),
76 quick_note_path: None,
77 };
78
79 self.workspaces.insert(name.clone(), entry);
80
81 if self.workspaces.len() == 1 {
83 self.global.current_workspace = name.clone();
84 }
85
86 Ok(())
87 }
88
89 pub fn get_current_workspace(&self) -> Option<&WorkspaceEntry> {
90 self.workspaces.get(&self.global.current_workspace)
91 }
92
93 pub fn get_workspace(&self, name: &str) -> Option<&WorkspaceEntry> {
94 self.workspaces.get(name)
95 }
96
97 pub fn from_phase1_migration(
98 workspace_dir: PathBuf,
99 theme: String,
100 last_paths: Vec<String>,
101 ) -> Self {
102 let mut config = Self::new_empty();
103 config.global.theme = theme;
104
105 let entry = WorkspaceEntry {
106 path: workspace_dir,
107 last_paths,
108 created: Utc::now(),
109 quick_note_path: None,
110 };
111
112 config.workspaces.insert("default".to_string(), entry);
113 config.global.current_workspace = "default".to_string();
114
115 config
116 }
117}