Implement Share Management UI (Phase 11 P0 #2)
Share Management Features:
- Shares.vue: Complete share CRUD interface
- Tauri commands: 5 share endpoints
- In-memory share storage (lazy_static)
UI Components:
- Share list table (name, path, protocol, users, permissions)
- Create share dialog (name, path, protocol, users, permissions)
- Edit share dialog (path, protocol, users, permissions)
- Delete share confirmation
- Test connection button
Tauri Commands:
- list_shares: List all shares
- create_share: Create share + create directory if needed
- update_share: Update share config
- delete_share: Remove share from list
- test_share_connection: Test share path exists
Supported Protocols:
- SMB/CIFS (default)
- SFTP
- WebDAV
- S3
Router:
- Added /shares route
Home.vue:
- Added Share Management card
Build: ✅ Tauri + markbase-core
Tests: 495 markbase-core + 201 smb-server
This commit is contained in:
@@ -7,6 +7,7 @@ pub mod health;
|
||||
pub mod monitor;
|
||||
pub mod backup;
|
||||
pub mod user_management;
|
||||
pub mod share_management;
|
||||
|
||||
pub use file_ops::*;
|
||||
pub use install::*;
|
||||
@@ -16,4 +17,5 @@ pub use management::*;
|
||||
pub use health::*;
|
||||
pub use monitor::*;
|
||||
pub use backup::*;
|
||||
pub use user_management::*;
|
||||
pub use user_management::*;
|
||||
pub use share_management::*;
|
||||
152
markbase-tauri/src-tauri/src/commands/share_management.rs
Normal file
152
markbase-tauri/src-tauri/src/commands/share_management.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ShareInfo {
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
pub protocol: String,
|
||||
pub users: Vec<String>,
|
||||
pub permissions: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ConnectionTestResult {
|
||||
pub success: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref SHARES: std::sync::Arc<std::sync::Mutex<Vec<ShareInfo>>> =
|
||||
std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_shares() -> Result<Vec<ShareInfo>, String> {
|
||||
let shares = SHARES.lock().unwrap();
|
||||
Ok(shares.clone())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_share(
|
||||
name: String,
|
||||
path: String,
|
||||
protocol: String,
|
||||
users: Vec<String>,
|
||||
permissions: String,
|
||||
) -> Result<(), String> {
|
||||
let mut shares = SHARES.lock().unwrap();
|
||||
|
||||
if shares.iter().any(|s| s.name == name) {
|
||||
return Err(format!("Share '{}' already exists", name));
|
||||
}
|
||||
|
||||
let path_buf = PathBuf::from(&path);
|
||||
if !path_buf.exists() {
|
||||
std::fs::create_dir_all(&path_buf)
|
||||
.map_err(|e| format!("Failed to create directory: {}", e))?;
|
||||
}
|
||||
|
||||
shares.push(ShareInfo {
|
||||
name,
|
||||
path,
|
||||
protocol,
|
||||
users,
|
||||
permissions,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_share(
|
||||
name: String,
|
||||
path: String,
|
||||
protocol: String,
|
||||
users: Vec<String>,
|
||||
permissions: String,
|
||||
) -> Result<(), String> {
|
||||
let mut shares = SHARES.lock().unwrap();
|
||||
|
||||
let share = shares.iter_mut().find(|s| s.name == name);
|
||||
if share.is_none() {
|
||||
return Err(format!("Share '{}' not found", name));
|
||||
}
|
||||
|
||||
let share = share.unwrap();
|
||||
share.path = path;
|
||||
share.protocol = protocol;
|
||||
share.users = users;
|
||||
share.permissions = permissions;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_share(name: String) -> Result<(), String> {
|
||||
let mut shares = SHARES.lock().unwrap();
|
||||
|
||||
let index = shares.iter().position(|s| s.name == name);
|
||||
if index.is_none() {
|
||||
return Err(format!("Share '{}' not found", name));
|
||||
}
|
||||
|
||||
shares.remove(index.unwrap());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn test_share_connection(
|
||||
name: String,
|
||||
protocol: String,
|
||||
) -> Result<ConnectionTestResult, String> {
|
||||
let shares = SHARES.lock().unwrap();
|
||||
|
||||
let share = shares.iter().find(|s| s.name == name);
|
||||
if share.is_none() {
|
||||
return Err(format!("Share '{}' not found", name));
|
||||
}
|
||||
|
||||
let share = share.unwrap();
|
||||
let path = PathBuf::from(&share.path);
|
||||
|
||||
if !path.exists() {
|
||||
return Ok(ConnectionTestResult {
|
||||
success: false,
|
||||
error: Some(format!("Path '{}' does not exist", share.path)),
|
||||
});
|
||||
}
|
||||
|
||||
match protocol.as_str() {
|
||||
"smb" => {
|
||||
Ok(ConnectionTestResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
},
|
||||
"sftp" => {
|
||||
Ok(ConnectionTestResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
},
|
||||
"webdav" => {
|
||||
Ok(ConnectionTestResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
},
|
||||
"s3" => {
|
||||
Ok(ConnectionTestResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
Ok(ConnectionTestResult {
|
||||
success: false,
|
||||
error: Some(format!("Unknown protocol: {}", protocol)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user