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
152 lines
3.6 KiB
Rust
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)),
|
|
})
|
|
}
|
|
}
|
|
} |