Trilium als Archiv: verwaltete Instanz pro Projekt, MD-Archiv und Dokument-Tab entfernt
- domain/trilium.rs: Runtime-Download (gepinnt 0.104.0), Instanz pro Projekt auf 127.0.0.1 mit FNV-Port, ETAPI (archive_note, search_notes), Token im Keyring - Setup bis aufs Passwort automatisiert: trilium_connect macht new-document (skipDemoDb), set-password und ETAPI-Login; Modul-Flag erst nach Token-Erfolg - write_panel legt direkt eine Trilium-Notiz an (text|path, folder/description/tags); noteopen-Kanal, das Terminal-Fenster öffnet die Notiz (ersetzt archive_panel) - MD-Altbestand raus: archive*/wiki*, archiveHome samt Permissions, panel_set/panel_load/ wiki_open, panel_archive*/archive_docs/*_archive_home, reveal_path, spellcheck - Dokument-Tab raus: Panel = ToDo/Befehle/Suche + Archiv-Knopf (trilium_open); panel-view/archive-form gelöscht, Markup/CSS/Messages bereinigt - Lösch-Stufe Archiv: Instanz stoppen, Trilium-Datadir und Keyring-Token löschen
This commit is contained in:
+104
-72
@@ -3,9 +3,6 @@
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::domain::archive::{
|
||||
archive_panel_content, project_archive_home, require_archive_home, ArchiveMeta,
|
||||
};
|
||||
use crate::domain::credentials::keychain_service;
|
||||
use crate::domain::paths::Paths;
|
||||
use crate::domain::pool::{
|
||||
@@ -350,11 +347,6 @@ pub(crate) fn set_terminal_font_size(size: u32) -> Result<(), String> {
|
||||
settings::set_terminal_font_size_in(&Paths::real(), size)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn spellcheck_lang() -> String {
|
||||
settings::spellcheck_lang(&Paths::real())
|
||||
}
|
||||
|
||||
// ---------- Verbrauch ----------
|
||||
|
||||
#[tauri::command]
|
||||
@@ -362,15 +354,6 @@ pub(crate) fn usage_stats(days: u32) -> Result<Vec<UsageRow>, String> {
|
||||
usage_stats_in(&Paths::real(), days)
|
||||
}
|
||||
|
||||
// ---------- Panel-Archiv ----------
|
||||
|
||||
/// Konfiguriertes Archiv-Home des Projekts (für den Panel-Button: entscheidet,
|
||||
/// ob der Ordner-Dialog nötig ist).
|
||||
#[tauri::command]
|
||||
pub(crate) fn panel_archive_dir_cmd(project: String) -> Option<String> {
|
||||
project_archive_home(&project).map(|p| p.display().to_string())
|
||||
}
|
||||
|
||||
/// Modul-Registry für den Settings-Dialog (Checkbox-Gruppe „Module").
|
||||
#[tauri::command]
|
||||
pub(crate) fn module_registry(project: String) -> Result<Vec<crate::domain::modules::ModuleInfo>, String> {
|
||||
@@ -383,78 +366,127 @@ pub(crate) fn set_module(project: String, module: String, enabled: bool) -> Resu
|
||||
crate::domain::modules::set_module_in(&Paths::real(), &project, &module, enabled)
|
||||
}
|
||||
|
||||
/// Aktive Module fürs Frontend: Registry-Enablement der Projekt-Config plus
|
||||
/// `requires_archive` — ohne konfiguriertes Archiv-Home fallen Archiv-Module
|
||||
/// weg, ihre Tabs erscheinen nicht.
|
||||
/// Aktive Module fürs Frontend (Registry-Enablement der Projekt-Config).
|
||||
#[tauri::command]
|
||||
pub(crate) fn enabled_modules(project: String) -> Result<Vec<String>, String> {
|
||||
let paths = Paths::real();
|
||||
let has_archive = read_project_config_in(&paths, &project)?.archive_home.is_some();
|
||||
Ok(
|
||||
crate::domain::modules::active_in(&paths, &project)?
|
||||
crate::domain::modules::active_in(&Paths::real(), &project)?
|
||||
.iter()
|
||||
.filter(|m| !m.requires_archive || has_archive)
|
||||
.map(|m| m.id.to_string())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Setzt das Archiv-Home eines Projekts (Einstellungsdialog) — inklusive
|
||||
/// Permissions-Eintrag in der Projekt-settings.json.
|
||||
#[tauri::command]
|
||||
pub(crate) fn set_archive_home_cmd(project: String, dir: String) -> Result<(), String> {
|
||||
crate::domain::archive::set_project_archive_home(&project, &dir)
|
||||
// ---------- Trilium ----------
|
||||
|
||||
/// Wizard-Status: Runtime da, Instanz erreichbar, Token gültig. Reine
|
||||
/// Checks, keine Schreiber.
|
||||
#[derive(serde::Serialize)]
|
||||
pub(crate) struct TriliumStatus {
|
||||
version: &'static str,
|
||||
port: u16,
|
||||
data_dir: String,
|
||||
runtime_ready: bool,
|
||||
instance_running: bool,
|
||||
token_ok: bool,
|
||||
}
|
||||
|
||||
fn trilium_status_for(project: &str) -> TriliumStatus {
|
||||
let paths = Paths::real();
|
||||
let instance_running = crate::domain::trilium::instance_running(project);
|
||||
TriliumStatus {
|
||||
version: crate::domain::trilium::VERSION,
|
||||
port: crate::domain::trilium::port_for(project),
|
||||
data_dir: crate::domain::paths::contract_home(
|
||||
&paths,
|
||||
&crate::domain::trilium::data_dir(&paths, project),
|
||||
),
|
||||
runtime_ready: crate::domain::trilium::runtime_ready(&paths),
|
||||
instance_running,
|
||||
token_ok: instance_running && crate::domain::trilium::token_ok(project),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wechselt das Archiv-Home (Einstellungsdialog, wenn schon eins gesetzt
|
||||
/// ist): optional ziehen die Dokumente mit um; die Rechte des alten Ordners
|
||||
/// werden zurückgenommen.
|
||||
#[tauri::command]
|
||||
pub(crate) fn change_archive_home_cmd(
|
||||
pub(crate) async fn trilium_status(project: String) -> TriliumStatus {
|
||||
trilium_status_for(&project)
|
||||
}
|
||||
|
||||
/// Richtet die Projekt-Instanz ein: Runtime laden (gepinnt, Checksum),
|
||||
/// Instanz starten. Schreibt KEINE Config — das Modul-Flag setzt erst
|
||||
/// trilium_connect nach erfolgreichem Token-Login.
|
||||
#[tauri::command]
|
||||
pub(crate) async fn trilium_setup(project: String) -> Result<TriliumStatus, String> {
|
||||
crate::domain::trilium::ensure_instance(&Paths::real(), &project)?;
|
||||
Ok(trilium_status_for(&project))
|
||||
}
|
||||
|
||||
/// Richtet die Instanz mit dem Passwort aus dem Wizard vollständig ein:
|
||||
/// Erstlauf legt das Dokument an und setzt das Passwort, dann ETAPI-Token
|
||||
/// holen, im Keyring ablegen und ERST DANN das Modul in der Projekt-Config
|
||||
/// freischalten. Das Passwort wird nicht gespeichert.
|
||||
#[tauri::command]
|
||||
pub(crate) async fn trilium_connect(
|
||||
project: String,
|
||||
dir: String,
|
||||
migrate: bool,
|
||||
password: String,
|
||||
) -> Result<TriliumStatus, String> {
|
||||
let paths = Paths::real();
|
||||
crate::domain::trilium::ensure_instance(&paths, &project)?;
|
||||
if !crate::domain::trilium::initialized(&project)? {
|
||||
crate::domain::trilium::setup_new_document(&project)?;
|
||||
crate::domain::trilium::set_password(&project, &password)?;
|
||||
}
|
||||
let token = crate::domain::trilium::login(&project, &password)?;
|
||||
crate::domain::trilium::store_token(&project, &token)?;
|
||||
if !crate::domain::trilium::token_ok(&project) {
|
||||
crate::domain::trilium::delete_token(&project);
|
||||
return Err("Token angenommen, aber ETAPI-Zugriff scheitert".into());
|
||||
}
|
||||
crate::domain::modules::set_module_in(&paths, &project, "trilium", true)?;
|
||||
Ok(trilium_status_for(&project))
|
||||
}
|
||||
|
||||
/// Öffnet das Trilium-Fenster des Projekts (startet die Instanz bei Bedarf);
|
||||
/// `note_id` springt zur Notiz. Async wie open_panel_window (Fenster-Erzeugung
|
||||
/// aus synchronen Commands klemmt auf dem GTK-Mainloop).
|
||||
#[tauri::command]
|
||||
pub(crate) async fn trilium_open(
|
||||
app: tauri::AppHandle,
|
||||
project: String,
|
||||
note_id: Option<String>,
|
||||
) -> Result<(), String> {
|
||||
crate::domain::archive::change_project_archive_home(&project, &dir, migrate)
|
||||
use tauri::Manager;
|
||||
crate::domain::trilium::ensure_instance(&Paths::real(), &project)?;
|
||||
let mut url = crate::domain::trilium::base_url(&project);
|
||||
if let Some(id) = ¬e_id {
|
||||
url.push_str(&format!("/#root/{id}"));
|
||||
}
|
||||
let label = format!("trilium-{project}");
|
||||
if let Some(win) = app.get_webview_window(&label) {
|
||||
if note_id.is_some() {
|
||||
win
|
||||
.eval(&format!("window.location.href = {}", serde_json::json!(url)))
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
win.set_focus().map_err(|e| e.to_string())?;
|
||||
return Ok(());
|
||||
}
|
||||
let parsed: tauri::Url = url.parse().map_err(|e| format!("{url}: {e}"))?;
|
||||
tauri::WebviewWindowBuilder::new(&app, &label, tauri::WebviewUrl::External(parsed))
|
||||
.title(format!("Trilium — {}", crate::domain::project::display_name_in(&Paths::real(), &project)?))
|
||||
.inner_size(1100.0, 780.0)
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wählt das Archiv ab (Einstellungsdialog): Config-Eintrag und Permissions
|
||||
/// weg, der Ordner bleibt liegen.
|
||||
/// Wählt das Modul ab und stoppt die Projekt-Instanz. Daten und Token
|
||||
/// bleiben — erneutes Aktivieren verbindet sich wieder.
|
||||
#[tauri::command]
|
||||
pub(crate) fn clear_archive_home_cmd(project: String) -> Result<(), String> {
|
||||
crate::domain::archive::clear_project_archive_home(&project)
|
||||
pub(crate) async fn trilium_disable(project: String) -> Result<(), String> {
|
||||
crate::domain::modules::set_module_in(&Paths::real(), &project, "trilium", false)?;
|
||||
crate::domain::trilium::stop_instance(&project);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Archiviert den aktuellen Panel-Entwurf. `dir` (aus dem Ordner-Dialog) setzt
|
||||
/// das Archiv-Home zugleich; ohne `dir` muss es konfiguriert sein. Ordner,
|
||||
/// Beschreibung und Schlagwörter kommen aus dem Archiv-Formular im Panel.
|
||||
#[tauri::command]
|
||||
pub(crate) fn panel_archive_cmd(
|
||||
project: String,
|
||||
dir: Option<String>,
|
||||
folder: Option<String>,
|
||||
description: Option<String>,
|
||||
tags: Option<Vec<String>>,
|
||||
) -> Result<String, String> {
|
||||
let meta = ArchiveMeta {
|
||||
folder: folder.filter(|f| !f.trim().is_empty()),
|
||||
description: description.filter(|d| !d.trim().is_empty()),
|
||||
tags: tags.unwrap_or_default(),
|
||||
};
|
||||
archive_panel_content(&project, dir.as_deref(), &meta).map(|p| p.display().to_string())
|
||||
}
|
||||
|
||||
/// Dokumentliste des Archiv-Index (frisch gescannt) fürs Panel.
|
||||
#[tauri::command]
|
||||
pub(crate) fn archive_docs_cmd(
|
||||
project: String,
|
||||
) -> Result<Vec<crate::domain::archive_index::Doc>, String> {
|
||||
let home = require_archive_home(&project)?;
|
||||
crate::domain::archive_index::scan_archive(&home)
|
||||
}
|
||||
|
||||
/// Zeigt einen Pfad im Dateimanager (nach dem Archivieren „im Finder zeigen").
|
||||
#[tauri::command]
|
||||
pub(crate) fn reveal_path_cmd(path: String) {
|
||||
crate::platform::reveal_path(std::path::Path::new(&path));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user