Version checks, drop native drag plugin, cloud menus and delete, about links
This commit is contained in:
+46
-1
@@ -675,6 +675,12 @@ fn lsp_running(state: State<'_, LspState>) -> bool {
|
||||
state.is_running()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_check_compatibility(server_url: String) -> sync::CompatibilityStatus {
|
||||
let server_url = server_url.trim_end_matches('/').to_string();
|
||||
sync::check_compatibility(&server_url)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_login(
|
||||
app: AppHandle,
|
||||
@@ -781,6 +787,30 @@ fn cloud_download_file(
|
||||
Ok(file.name)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_delete_file(app: AppHandle, store: State<'_, Store>, file_id: String) -> Result<(), String> {
|
||||
let (server_url, token) = cloud_credentials(&app, &store)?;
|
||||
sync::delete_account_file(&server_url, &token, &file_id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_delete_document(
|
||||
app: AppHandle,
|
||||
store: State<'_, Store>,
|
||||
document_id: String,
|
||||
) -> Result<(), String> {
|
||||
let (server_url, token) = cloud_credentials(&app, &store)?;
|
||||
sync::delete_document(&server_url, &token, &document_id)?;
|
||||
|
||||
if let Ok(links) = store.all_document_links() {
|
||||
if let Some((path, _, _)) = links.into_iter().find(|(_, id, _)| id == &document_id) {
|
||||
let _ = store.forget_document_link(&path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_list_shared(
|
||||
app: AppHandle,
|
||||
@@ -970,6 +1000,18 @@ fn cloud_create_project(app: AppHandle, store: State<'_, Store>, name: String) -
|
||||
sync::create_cloud_project(&server_url, &token, name.trim())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_new_document(app: AppHandle, store: State<'_, Store>, title: String) -> Result<sync::DocumentContent, String> {
|
||||
let title = title.trim();
|
||||
if title.is_empty() {
|
||||
return Err("Document name cannot be empty".to_string());
|
||||
}
|
||||
|
||||
let (server_url, token) = cloud_credentials(&app, &store)?;
|
||||
let content = format!("= {}\n\nStart writing here.\n", title);
|
||||
sync::create_document(&server_url, &token, title, &content)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn cloud_delete_project(app: AppHandle, store: State<'_, Store>, cloud_project_id: String) -> Result<(), String> {
|
||||
let (server_url, token) = cloud_credentials(&app, &store)?;
|
||||
@@ -1101,7 +1143,6 @@ pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_drag::init())
|
||||
.setup(|app| {
|
||||
let store = Store::open(&app.handle())?;
|
||||
app.manage(store);
|
||||
@@ -1149,6 +1190,7 @@ pub fn run() {
|
||||
lsp_send,
|
||||
lsp_stop,
|
||||
lsp_running,
|
||||
cloud_check_compatibility,
|
||||
cloud_login,
|
||||
cloud_logout,
|
||||
cloud_account,
|
||||
@@ -1158,7 +1200,9 @@ pub fn run() {
|
||||
cloud_list_shared,
|
||||
cloud_list_files,
|
||||
cloud_download_file,
|
||||
cloud_delete_file,
|
||||
cloud_download_document,
|
||||
cloud_delete_document,
|
||||
cloud_sync_document,
|
||||
cloud_resolve_document,
|
||||
cloud_document_link,
|
||||
@@ -1167,6 +1211,7 @@ pub fn run() {
|
||||
cloud_unlink_document,
|
||||
cloud_create_document,
|
||||
cloud_create_project,
|
||||
cloud_new_document,
|
||||
cloud_delete_project,
|
||||
cloud_clone_project,
|
||||
cloud_link_project,
|
||||
|
||||
@@ -34,6 +34,88 @@ fn describe(error: ureq::Error) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub const MIN_SERVER_VERSION: &str = "1.5.0";
|
||||
|
||||
fn parse_version(version: &str) -> (u32, u32, u32) {
|
||||
let mut parts = version.trim().split('.').map(|part| part.parse::<u32>().unwrap_or(0));
|
||||
(
|
||||
parts.next().unwrap_or(0),
|
||||
parts.next().unwrap_or(0),
|
||||
parts.next().unwrap_or(0),
|
||||
)
|
||||
}
|
||||
|
||||
fn version_at_least(actual: &str, required: &str) -> bool {
|
||||
parse_version(actual) >= parse_version(required)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ServerVersionInfo {
|
||||
server_version: String,
|
||||
min_desktop_version: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct CompatibilityStatus {
|
||||
pub compatible: bool,
|
||||
pub server_version: String,
|
||||
pub desktop_version: String,
|
||||
pub min_server_version: String,
|
||||
pub min_desktop_version: String,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
pub fn check_compatibility(server_url: &str) -> CompatibilityStatus {
|
||||
let desktop_version = env!("CARGO_PKG_VERSION").to_string();
|
||||
|
||||
let info = agent()
|
||||
.get(&endpoint(server_url, "/version"))
|
||||
.call()
|
||||
.map_err(describe)
|
||||
.and_then(|response| response.into_json::<ServerVersionInfo>().map_err(|e| e.to_string()));
|
||||
|
||||
match info {
|
||||
Ok(info) => {
|
||||
let server_too_old = !version_at_least(&info.server_version, MIN_SERVER_VERSION);
|
||||
let desktop_too_old = !version_at_least(&desktop_version, &info.min_desktop_version);
|
||||
|
||||
let message = if server_too_old {
|
||||
Some(format!(
|
||||
"This app requires a TypstDrive server v{} or newer (server is running v{}). Ask the administrator to update it.",
|
||||
MIN_SERVER_VERSION, info.server_version
|
||||
))
|
||||
} else if desktop_too_old {
|
||||
Some(format!(
|
||||
"This TypstDrive server requires typst-desktop v{} or newer (you have v{}). Please update the app.",
|
||||
info.min_desktop_version, desktop_version
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
CompatibilityStatus {
|
||||
compatible: !server_too_old && !desktop_too_old,
|
||||
server_version: info.server_version,
|
||||
desktop_version,
|
||||
min_server_version: MIN_SERVER_VERSION.to_string(),
|
||||
min_desktop_version: info.min_desktop_version,
|
||||
message,
|
||||
}
|
||||
}
|
||||
Err(_) => CompatibilityStatus {
|
||||
compatible: false,
|
||||
server_version: "unknown".to_string(),
|
||||
desktop_version,
|
||||
min_server_version: MIN_SERVER_VERSION.to_string(),
|
||||
min_desktop_version: "unknown".to_string(),
|
||||
message: Some(format!(
|
||||
"Could not determine the server's version. It may be unreachable, or older than v{} which doesn't support version checks. Please update the server.",
|
||||
MIN_SERVER_VERSION
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct Account {
|
||||
pub user_id: String,
|
||||
@@ -55,12 +137,20 @@ pub fn login(
|
||||
password: &str,
|
||||
device_name: &str,
|
||||
) -> Result<LoginResponse, String> {
|
||||
let status = check_compatibility(server_url);
|
||||
if !status.compatible {
|
||||
return Err(status
|
||||
.message
|
||||
.unwrap_or_else(|| "This server is not compatible with this app.".to_string()));
|
||||
}
|
||||
|
||||
agent()
|
||||
.post(&endpoint(server_url, "/auth/login"))
|
||||
.send_json(ureq::json!({
|
||||
"email": email,
|
||||
"password": password,
|
||||
"device_name": device_name,
|
||||
"client_version": env!("CARGO_PKG_VERSION"),
|
||||
}))
|
||||
.map_err(describe)?
|
||||
.into_json::<LoginResponse>()
|
||||
@@ -926,6 +1016,15 @@ pub fn push_document(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_document(server_url: &str, token: &str, document_id: &str) -> Result<(), String> {
|
||||
agent()
|
||||
.delete(&endpoint(server_url, &format!("/documents/{}", document_id)))
|
||||
.set("Authorization", &format!("Bearer {}", token))
|
||||
.call()
|
||||
.map_err(describe)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct CloudFile {
|
||||
pub id: String,
|
||||
@@ -974,3 +1073,12 @@ pub fn pull_account_file(
|
||||
.into_json::<CloudFileContent>()
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub fn delete_account_file(server_url: &str, token: &str, file_id: &str) -> Result<(), String> {
|
||||
agent()
|
||||
.delete(&endpoint(server_url, &format!("/files/{}", file_id)))
|
||||
.set("Authorization", &format!("Bearer {}", token))
|
||||
.call()
|
||||
.map_err(describe)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user