feat(import): merge re-imports from a linked source instead of duplicating (#618)

This commit is contained in:
Gregory Schier
2026-09-01 11:12:07 -07:00
committed by GitHub
parent d461c982ec
commit d2d4b80a09
28 changed files with 2504 additions and 275 deletions
+28 -6
View File
@@ -6,13 +6,16 @@ use std::io::ErrorKind;
use tauri::{Manager, Runtime, WebviewWindow};
use yaak::import::{self, PlanImportDataParams};
use yaak_api::{ApiClientKind, yaak_api_client};
use yaak_models::util::{BatchUpsertResult, ImportDestination, ImportPlan};
use yaak_models::util::{BatchUpsertResult, ImportDestination, ImportOrigin, ImportPlan};
pub(crate) async fn import_data<R: Runtime>(
window: &WebviewWindow<R>,
file_path: &str,
origin: Option<ImportOrigin>,
) -> Result<BatchUpsertResult> {
let plan = plan_import_data(window, file_path, ImportDestination::NewWorkspace).await?;
let contents = read_import_file(file_path)?;
let plan =
plan_import_contents(window, &contents, ImportDestination::NewWorkspace, origin).await?;
commit_import(window, plan)
}
@@ -22,7 +25,7 @@ pub(crate) async fn plan_import_data<R: Runtime>(
destination: ImportDestination,
) -> Result<ImportPlan> {
let contents = read_import_file(file_path)?;
plan_import_contents(window, &contents, destination).await
plan_import_contents(window, &contents, destination, Some(file_origin(file_path))).await
}
pub(crate) async fn plan_import_url<R: Runtime>(
@@ -30,14 +33,16 @@ pub(crate) async fn plan_import_url<R: Runtime>(
url: &str,
destination: ImportDestination,
) -> Result<ImportPlan> {
let contents = fetch_import_url(window, url).await?;
plan_import_contents(window, &contents, destination).await
let url = normalize_import_url(url)?;
let contents = fetch_import_url(window, &url).await?;
plan_import_contents(window, &contents, destination, Some(url_origin(&url))).await
}
async fn plan_import_contents<R: Runtime>(
window: &WebviewWindow<R>,
contents: &str,
destination: ImportDestination,
origin: Option<ImportOrigin>,
) -> Result<ImportPlan> {
let plugin_manager = crate::plugins_ext::plugin_manager(window).await?;
let query_manager = window.db_manager();
@@ -49,10 +54,27 @@ async fn plan_import_contents<R: Runtime>(
plugin_context: &plugin_context,
destination,
contents,
origin,
})
.await?)
}
/// Canonicalize so re-importing the same file through a different spelling of its path still
/// matches the linked source.
pub(crate) fn file_origin(file_path: &str) -> ImportOrigin {
let path = std::path::Path::new(file_path);
let canonical = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
let label = canonical
.file_name()
.map(|name| name.to_string_lossy().to_string())
.unwrap_or_else(|| file_path.to_string());
ImportOrigin { origin: canonical.to_string_lossy().to_string(), label }
}
pub(crate) fn url_origin(url: &str) -> ImportOrigin {
ImportOrigin { origin: url.to_string(), label: url.to_string() }
}
pub(crate) fn commit_import<R: Runtime>(
window: &WebviewWindow<R>,
plan: ImportPlan,
@@ -88,7 +110,7 @@ async fn fetch_import_url<R: Runtime>(window: &WebviewWindow<R>, url: &str) -> R
.map_err(|err| Error::GenericError(format!("Failed to read response from {url}: {err}")))
}
fn normalize_import_url(url: &str) -> Result<String> {
pub(crate) fn normalize_import_url(url: &str) -> Result<String> {
let url = url.trim();
if url.is_empty() {
return Err(Error::GenericError("Import URL must not be empty".to_string()));