Files
markbase/markbase-tauri/src-tauri/src/commands/share_management.rs
Warren 103bb66924 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
2026-06-24 05:16:24 +08:00

152 lines
3.6 KiB
Rust

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)),
})
}
}
}