v0.1.4-pre.006
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# file: crates/ksp-app-config-desk/Cargo.toml
|
||||
# version: 2
|
||||
# version: 3
|
||||
|
||||
[package]
|
||||
name = "ksp-app-config-desk"
|
||||
@@ -23,9 +23,13 @@ tauri-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
fs2.workspace = true
|
||||
ksp-config-lib = { path = "../ksp-config-lib" }
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
ksp-logging-lib = { path = "../ksp-logging-lib" }
|
||||
serde.workspace = true
|
||||
tauri.workspace = true
|
||||
tauri-plugin-tracing.workspace = true
|
||||
ts-rs.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-config-desk/README.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# `ksp-app-config-desk`
|
||||
|
||||
@@ -27,7 +27,8 @@ Le gabarit desktop actif fournit maintenant :
|
||||
- SimpleBar + `resize-observer-polyfill` pour le scrolling du shell ;
|
||||
- `tauri-plugin-tracing` côté Rust et `@fltsci/tauri-plugin-tracing` côté frontend ;
|
||||
- les ports dédiés `1430` pour Vite HTTP et `1431` pour le WebSocket de développement ;
|
||||
- la destination frontend externe commune à Tauri et Vite.
|
||||
- la destination frontend externe commune à Tauri et Vite;
|
||||
- le bootstrap Config/Logging réel, un `AppState` durable et le premier contrat Tauri/TS-RS `get_app_snapshot`.
|
||||
|
||||
Le bridge de logging frontend KSP à target explicite n'est pas encore introduit : il appartient à une tranche dédiée afin de passer par `ksp-logging-lib` et de ne pas figer le target vide du bridge JS générique comme contrat KSP.
|
||||
|
||||
@@ -51,13 +52,13 @@ frontend/
|
||||
└── splash.html
|
||||
```
|
||||
|
||||
Les futurs bindings TS-RS seront générés sous :
|
||||
Les premiers bindings TS-RS sont générés par les tests `ts-rs` sous :
|
||||
|
||||
```text
|
||||
frontend/ts/bindings/ksp_app_config_desk/...
|
||||
```
|
||||
|
||||
Le répertoire de bindings n'est pas créé artificiellement avant le premier DTO réel.
|
||||
Les DTO Rust applicatifs restent la source de vérité et les bindings générés ne sont pas versionnés.
|
||||
|
||||
## Artefacts frontend
|
||||
|
||||
@@ -85,3 +86,16 @@ Le port HTTP est strict. Les futures applications desk utilisent les couples sui
|
||||
Les bibliothèques consommées par le bundle applicatif sont déclarées sous `dependencies` : `@fltsci/tauri-plugin-tracing`, `@fortawesome/fontawesome-free`, `@tauri-apps/api`, `bootstrap`, `simplebar` et `resize-observer-polyfill`.
|
||||
|
||||
Les outils de compilation/développement et déclarations de types appartiennent à `devDependencies`, notamment `@tauri-apps/cli`, `@types/bootstrap`, `@types/node`, `sass-embedded`, `typescript` et `vite`. Les commandes npm directes sont réservées à l'installation ou à la mise à jour de ces dépendances ; le cycle normal de développement et de build est lancé depuis la racine du workspace par Tauri avec la configuration explicite de l'application.
|
||||
|
||||
|
||||
## Bootstrap Config et Logging
|
||||
|
||||
Au démarrage, l'application construit `ConfigBootstrapOptions`, `ConfigFileRegistry`, `ConfigDocumentEngine` et `ConfigManagement` à partir des arguments complets du processus. Elle tente ensuite de résoudre le profil Logging par défaut avec un snapshot `ConfigEnvironment` frais.
|
||||
|
||||
Si le document Logging, sa résolution environnementale ou l'initialisation du runtime configuré échoue avant installation du subscriber, Config Desk installe un fallback **transitoire** en mémoire : console stderr, niveau `Info`, aucun fichier, aucun span lifecycle. Ce fallback n'est jamais persisté et son diagnostic frontend est limité à `domain`, `code` et `message`.
|
||||
|
||||
Le `LoggingGuard` est conservé dans `AppState` pour préparer le hot reload ultérieur.
|
||||
|
||||
## Police du splash
|
||||
|
||||
Le splash bot3 de référence utilise `DOS_Amazigh.ttf` (`font-family: Dos Amazigh`). Le répertoire `frontend/fonts/` documente la provenance, la destination attendue et l'empreinte de l'asset de référence. Le style/lifecycle final du splash est traité dans la tranche dédiée `pre.008`.
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<!-- file: crates/ksp-app-config-desk/TODO.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# TODO `ksp-app-config-desk`
|
||||
|
||||
Le gabarit frontend de base est maintenant en place : Vite/TypeScript/SCSS, Bootstrap, Font Awesome, SimpleBar, resize observer, plugin tracing et ports dédiés.
|
||||
Le gabarit frontend, le bootstrap Config/Logging, `AppState`, le `LoggingGuard` durable et les premiers DTO TS-RS sont maintenant présents.
|
||||
|
||||
Les prochaines tranches doivent encore :
|
||||
|
||||
- introduire les DTO TS-RS au premier contrat Tauri réel, avec bindings générés sous `frontend/ts/bindings/` ;
|
||||
- introduire `AppState`, `ksp-config-lib`, `ksp-logging-lib` et l'ownership durable de `LoggingGuard` ;
|
||||
- reprendre/refondre `frontend_log.ts` depuis bot3 avec targets KSP whitelistés et émission via `ksp-logging-lib` ;
|
||||
- finaliser le lifecycle splash configurable sans temporisation environnementale codée en dur ;
|
||||
- appliquer la police `Dos Amazigh` du gabarit bot3 lorsque l'asset local `DOS_Amazigh.ttf` est présent sous `frontend/fonts/` ;
|
||||
- développer les panneaux Documents, Profils, Environnement/`.env`, Secrets et Logging ;
|
||||
- introduire DataTables au premier tableau qui exige tri, filtrage, sélection ou checkbox ;
|
||||
- démontrer le hot reload Logging et le panneau de test de routage.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- file: crates/ksp-app-config-desk/USAGE.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Utilisation de `ksp-app-config-desk`
|
||||
|
||||
## État actuel
|
||||
|
||||
Le gabarit Rust/Tauri et le frontend Vite/TypeScript/SCSS sont maintenant présents. Les panneaux métier Config restent volontairement absents à ce stade.
|
||||
Le gabarit Rust/Tauri et le frontend Vite/TypeScript/SCSS sont présents. Le backend initialise désormais Config, le runtime Logging et `AppState`; les panneaux métier Config restent volontairement absents à ce stade.
|
||||
|
||||
La fenêtre `splash` est la fenêtre visible au démarrage. La fenêtre `main` est déjà construite et bundlée, mais son lifecycle d'affichage est finalisé dans la tranche splash/shell dédiée afin de ne pas introduire une temporisation codée en dur.
|
||||
|
||||
@@ -86,3 +86,16 @@ frontend/ts/bindings/ksp_app_config_desk/...
|
||||
```
|
||||
|
||||
Les bindings sont générés au premier DTO Tauri réel ; aucune structure factice n'est ajoutée uniquement pour créer le répertoire.
|
||||
|
||||
|
||||
## Bootstrap backend
|
||||
|
||||
Les arguments `--cfgpath`, `--schemapath` et `--filemap=...` sont transmis tels quels à `ksp-config-lib`. Le profil Logging initial est le `default_profile` de `std.logging.json`.
|
||||
|
||||
Si cette configuration ne peut pas être utilisée, l'application doit rester démarrable pour permettre sa réparation : elle utilise alors un fallback Logging console/stderr en mémoire. Le fallback n'écrit aucun fichier de configuration et n'écrase aucune valeur utilisateur.
|
||||
|
||||
La commande Tauri `get_app_snapshot` expose un état sûr du bootstrap. Ses types TypeScript sont générés par `cargo test -p ksp-app-config-desk` sous `frontend/ts/bindings/`.
|
||||
|
||||
## Asset font du splash
|
||||
|
||||
La police bot3 de référence est `DOS_Amazigh.ttf`. Vérifier l'asset local contre l'empreinte documentée dans `frontend/fonts/README.md` avant la tranche de finition du splash.
|
||||
|
||||
BIN
crates/ksp-app-config-desk/frontend/fonts/DOS_Amazigh.ttf
Normal file
BIN
crates/ksp-app-config-desk/frontend/fonts/DOS_Amazigh.ttf
Normal file
Binary file not shown.
31
crates/ksp-app-config-desk/frontend/fonts/README.md
Normal file
31
crates/ksp-app-config-desk/frontend/fonts/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- file: crates/ksp-app-config-desk/frontend/fonts/README.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Fonts du splash
|
||||
|
||||
Le gabarit de splash repris de `khadhroony-bot3` utilise la police locale suivante :
|
||||
|
||||
```text
|
||||
DOS_Amazigh.ttf
|
||||
font-family: Dos Amazigh
|
||||
```
|
||||
|
||||
Source de référence auditée :
|
||||
|
||||
```text
|
||||
kb-app-demo-desktop/frontend/fonts/DOS_Amazigh.ttf
|
||||
```
|
||||
|
||||
Destination KSP attendue :
|
||||
|
||||
```text
|
||||
crates/ksp-app-config-desk/frontend/fonts/DOS_Amazigh.ttf
|
||||
```
|
||||
|
||||
Empreinte SHA-256 de l'asset bot3 audité :
|
||||
|
||||
```text
|
||||
a01ff4b5a0d699db7cefcf5336bf0e379ff6fbf0d096087571a13c8782f9aa02
|
||||
```
|
||||
|
||||
Le fichier est un asset tiers/historique du gabarit et doit être repris depuis la copie bot3 possédée par le projet. `splash.scss` basculera explicitement sur `Dos Amazigh` lorsque l'asset est présent dans le workspace ; le lifecycle visuel complet reste traité dans la tranche splash dédiée.
|
||||
78
crates/ksp-app-config-desk/src/app_state.rs
Normal file
78
crates/ksp-app-config-desk/src/app_state.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
// file: crates/ksp-app-config-desk/src/app_state.rs
|
||||
// version: 1
|
||||
|
||||
//! Shared backend state owned by the Tauri application.
|
||||
|
||||
struct LoggingRuntimeState {
|
||||
guard: ksp_logging_lib::LoggingGuard,
|
||||
active_profile_id: std::option::Option<String>,
|
||||
generation: u32,
|
||||
fallback_active: bool,
|
||||
startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
||||
}
|
||||
|
||||
/// Shared Config Desk application state managed by Tauri.
|
||||
pub(crate) struct AppState {
|
||||
config_management: ksp_config_lib::ConfigManagement,
|
||||
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
/// Initializes Config ownership, the Logging runtime and durable application state.
|
||||
pub(crate) fn initialize(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<Self> {
|
||||
let config_management = crate::config_management(arguments);
|
||||
let config_management = match config_management {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let logging_startup = crate::initialize_logging(&config_management);
|
||||
let logging_startup = match logging_startup {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return std::result::Result::Ok(Self {
|
||||
config_management,
|
||||
logging_runtime: std::sync::Mutex::new(LoggingRuntimeState {
|
||||
guard: logging_startup.guard,
|
||||
active_profile_id: logging_startup.active_profile_id,
|
||||
generation: 1,
|
||||
fallback_active: logging_startup.fallback_active,
|
||||
startup_diagnostic: logging_startup.startup_diagnostic,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/// Builds a safe initial frontend snapshot without exposing resolved secret values or arbitrary error context.
|
||||
pub(crate) fn snapshot(&self) -> ksp_core_lib::Result<crate::AppSnapshotDto> {
|
||||
let document_count = self.config_management.engine().registry().descriptors().count();
|
||||
let document_count = u32::try_from(document_count);
|
||||
let document_count = match document_count {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_APP_STATE_INVALID, "Config registry contains too many descriptors for the desktop DTO")
|
||||
.with_source(error),
|
||||
);
|
||||
},
|
||||
};
|
||||
let runtime = self.logging_runtime.lock();
|
||||
let runtime = match runtime {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_APP_STATE_LOCK_FAILED,
|
||||
"Config Desk Logging runtime state lock is poisoned",
|
||||
));
|
||||
},
|
||||
};
|
||||
let _keep_guard_alive = &runtime.guard;
|
||||
return std::result::Result::Ok(crate::AppSnapshotDto {
|
||||
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
config_document_count: document_count,
|
||||
active_logging_profile: runtime.active_profile_id.clone(),
|
||||
logging_generation: runtime.generation,
|
||||
fallback_logging_active: runtime.fallback_active,
|
||||
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
102
crates/ksp-app-config-desk/src/bootstrap.rs
Normal file
102
crates/ksp-app-config-desk/src/bootstrap.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
// file: crates/ksp-app-config-desk/src/bootstrap.rs
|
||||
// version: 1
|
||||
|
||||
//! Config and Logging bootstrap for the desktop application.
|
||||
|
||||
pub(crate) struct LoggingStartup {
|
||||
pub(crate) guard: ksp_logging_lib::LoggingGuard,
|
||||
pub(crate) active_profile_id: std::option::Option<String>,
|
||||
pub(crate) fallback_active: bool,
|
||||
pub(crate) startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
||||
}
|
||||
|
||||
pub(crate) fn config_management(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<ksp_config_lib::ConfigManagement> {
|
||||
let bootstrap = ksp_config_lib::ConfigBootstrapOptions::from_args(arguments);
|
||||
let bootstrap = match bootstrap {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let registry = ksp_config_lib::ConfigFileRegistry::from_args(arguments);
|
||||
let registry = match registry {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let engine = ksp_config_lib::ConfigDocumentEngine::new(bootstrap, registry);
|
||||
return std::result::Result::Ok(ksp_config_lib::ConfigManagement::new(engine));
|
||||
}
|
||||
|
||||
pub(crate) fn initialize_logging(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error),
|
||||
};
|
||||
let resolved = management.engine().load_resolved_logging_config(std::option::Option::None, &environment);
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error),
|
||||
};
|
||||
let active_profile_id = resolved.profile_id().to_owned();
|
||||
let settings = resolved.into_settings();
|
||||
let guard = ksp_logging_lib::initialize(&settings);
|
||||
return match guard {
|
||||
std::result::Result::Ok(guard) => {
|
||||
ksp_logging_lib::info!(
|
||||
target: crate::TRACING_TARGET,
|
||||
domain = crate::TRACING_DOMAIN_BOOTSTRAP,
|
||||
active_profile = active_profile_id.as_str(),
|
||||
"initialized Config Desk logging from managed configuration"
|
||||
);
|
||||
std::result::Result::Ok(LoggingStartup {
|
||||
guard,
|
||||
active_profile_id: std::option::Option::Some(active_profile_id),
|
||||
fallback_active: false,
|
||||
startup_diagnostic: std::option::Option::None,
|
||||
})
|
||||
},
|
||||
std::result::Result::Err(error) => initialize_fallback_logging(error),
|
||||
};
|
||||
}
|
||||
|
||||
fn initialize_fallback_logging(initial_error: ksp_core_lib::Error) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
let diagnostic = crate::CommandErrorDto::from_error(&initial_error);
|
||||
let settings = fallback_logging_settings();
|
||||
let guard = ksp_logging_lib::initialize(&settings);
|
||||
let guard = match guard {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(fallback_error) => {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED, "Cannot initialize Config Desk fallback Logging runtime")
|
||||
.with_context("initial_error_domain", initial_error.code().domain())
|
||||
.with_context("initial_error_code", initial_error.code().code())
|
||||
.with_source(fallback_error),
|
||||
);
|
||||
},
|
||||
};
|
||||
ksp_logging_lib::warn!(
|
||||
target: crate::TRACING_TARGET,
|
||||
domain = crate::TRACING_DOMAIN_BOOTSTRAP,
|
||||
error_domain = diagnostic.domain.as_str(),
|
||||
error_code = diagnostic.code.as_str(),
|
||||
"managed Logging configuration is unavailable; using transient in-memory fallback"
|
||||
);
|
||||
return std::result::Result::Ok(LoggingStartup {
|
||||
guard,
|
||||
active_profile_id: std::option::Option::None,
|
||||
fallback_active: true,
|
||||
startup_diagnostic: std::option::Option::Some(diagnostic),
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn fallback_logging_settings() -> ksp_logging_lib::LoggingSettings {
|
||||
return ksp_logging_lib::LoggingSettings::new(
|
||||
ksp_logging_lib::LogFilterLevel::Info,
|
||||
ksp_logging_lib::SpanEvents::Off,
|
||||
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
|
||||
std::vec::Vec::new(),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/bootstrap.rs"]
|
||||
mod tests;
|
||||
9
crates/ksp-app-config-desk/src/constants.rs
Normal file
9
crates/ksp-app-config-desk/src/constants.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
// file: crates/ksp-app-config-desk/src/constants.rs
|
||||
// version: 1
|
||||
|
||||
//! Application-owned tracing targets and domains.
|
||||
|
||||
/// Owning target for backend events emitted by Config Desk.
|
||||
pub(crate) const TRACING_TARGET: &str = "ksp-app-config-desk";
|
||||
/// Structured domain used while bootstrapping Config and Logging.
|
||||
pub(crate) const TRACING_DOMAIN_BOOTSTRAP: &str = "config.bootstrap";
|
||||
54
crates/ksp-app-config-desk/src/dto_common.rs
Normal file
54
crates/ksp-app-config-desk/src/dto_common.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
// file: crates/ksp-app-config-desk/src/dto_common.rs
|
||||
// version: 1
|
||||
|
||||
//! Common Tauri DTOs shared by Config Desk commands.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Safe command error projection that never serializes arbitrary KSP error context or source values.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/dto_common/CommandErrorDto.ts")]
|
||||
pub(crate) struct CommandErrorDto {
|
||||
/// Stable KSP error domain.
|
||||
pub(crate) domain: String,
|
||||
/// Stable KSP error code within the domain.
|
||||
pub(crate) code: String,
|
||||
/// Human-readable error message without arbitrary context fields.
|
||||
pub(crate) message: String,
|
||||
}
|
||||
|
||||
impl CommandErrorDto {
|
||||
/// Builds a bounded safe projection from a KSP error.
|
||||
#[must_use]
|
||||
pub(crate) fn from_error(error: &ksp_core_lib::Error) -> Self {
|
||||
return Self {
|
||||
domain: error.code().domain().to_owned(),
|
||||
code: error.code().code().to_owned(),
|
||||
message: error.message().to_owned(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Initial application/runtime snapshot exposed to the frontend.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/dto_common/AppSnapshotDto.ts")]
|
||||
pub(crate) struct AppSnapshotDto {
|
||||
/// Cargo application version.
|
||||
pub(crate) application_version: String,
|
||||
/// Number of files registered by the Config registry.
|
||||
pub(crate) config_document_count: u32,
|
||||
/// Active configured Logging profile, or `None` while the transient fallback runtime is active.
|
||||
pub(crate) active_logging_profile: std::option::Option<String>,
|
||||
/// Monotonic runtime generation, initialized to one after the first Logging runtime install.
|
||||
pub(crate) logging_generation: u32,
|
||||
/// Whether Config Desk had to install its transient in-memory Logging fallback.
|
||||
pub(crate) fallback_logging_active: bool,
|
||||
/// Safe startup diagnostic that caused fallback Logging, when applicable.
|
||||
pub(crate) startup_diagnostic: std::option::Option<CommandErrorDto>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/dto_common.rs"]
|
||||
mod tests;
|
||||
@@ -1,7 +1,13 @@
|
||||
// file: crates/ksp-app-config-desk/src/errors.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Application-local error codes for the configuration desktop shell.
|
||||
|
||||
/// Tauri runtime assembly or execution failed.
|
||||
pub(crate) const ERROR_CODE_TAURI_RUNTIME_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "tauri_runtime_failed");
|
||||
/// Config Desk could not install the managed Logging runtime or its safe fallback.
|
||||
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "logging_bootstrap_failed");
|
||||
/// Shared Config Desk application state is internally inconsistent.
|
||||
pub(crate) const ERROR_CODE_APP_STATE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "app_state_invalid");
|
||||
/// Shared Config Desk runtime state cannot be locked safely.
|
||||
pub(crate) const ERROR_CODE_APP_STATE_LOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "app_state_lock_failed");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/lib.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Tauri desktop application for managing and validating KSP configuration.
|
||||
|
||||
@@ -7,10 +7,24 @@
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod app_state;
|
||||
mod bootstrap;
|
||||
mod constants;
|
||||
mod dto_common;
|
||||
mod errors;
|
||||
mod tauri;
|
||||
|
||||
/// Runs the KSP configuration desktop application.
|
||||
pub use self::tauri::run;
|
||||
|
||||
pub(crate) use self::app_state::AppState;
|
||||
pub(crate) use self::bootstrap::config_management;
|
||||
pub(crate) use self::bootstrap::initialize_logging;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_BOOTSTRAP;
|
||||
pub(crate) use self::constants::TRACING_TARGET;
|
||||
pub(crate) use self::dto_common::AppSnapshotDto;
|
||||
pub(crate) use self::dto_common::CommandErrorDto;
|
||||
pub(crate) use self::errors::ERROR_CODE_APP_STATE_INVALID;
|
||||
pub(crate) use self::errors::ERROR_CODE_APP_STATE_LOCK_FAILED;
|
||||
pub(crate) use self::errors::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED;
|
||||
pub(crate) use self::errors::ERROR_CODE_TAURI_RUNTIME_FAILED;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/tauri.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Tauri runtime assembly for the KSP configuration desktop application.
|
||||
|
||||
@@ -7,9 +7,16 @@ use tauri::Manager; // rust-rules: trait-import
|
||||
|
||||
/// Runs the configuration desktop application.
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run(_arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<()> {
|
||||
pub fn run(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<()> {
|
||||
let app_state = crate::AppState::initialize(arguments);
|
||||
let app_state = match app_state {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let mut builder = tauri::Builder::default();
|
||||
builder = configure_state(builder, app_state);
|
||||
builder = configure_plugins(builder);
|
||||
builder = configure_commands(builder);
|
||||
builder = configure_setup(builder);
|
||||
let run_result = builder.run(tauri::generate_context!());
|
||||
return match run_result {
|
||||
@@ -21,11 +28,19 @@ pub fn run(_arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<()> {
|
||||
};
|
||||
}
|
||||
|
||||
fn configure_state(builder: tauri::Builder<tauri::Wry>, app_state: crate::AppState) -> tauri::Builder<tauri::Wry> {
|
||||
return builder.manage(app_state);
|
||||
}
|
||||
|
||||
fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||
let tracing_plugin = tauri_plugin_tracing::Builder::new().build::<tauri::Wry>();
|
||||
return builder.plugin(tracing_plugin);
|
||||
}
|
||||
|
||||
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||
return builder.invoke_handler(tauri::generate_handler![get_app_snapshot]);
|
||||
}
|
||||
|
||||
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||
return builder.setup(|app| {
|
||||
if app.get_webview_window("splash").is_none() {
|
||||
@@ -37,3 +52,12 @@ fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri:
|
||||
return std::result::Result::Ok(());
|
||||
});
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_app_snapshot(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::AppSnapshotDto, crate::CommandErrorDto> {
|
||||
let snapshot = state.snapshot();
|
||||
return match snapshot {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(crate::CommandErrorDto::from_error(&error)),
|
||||
};
|
||||
}
|
||||
|
||||
17
crates/ksp-app-config-desk/unit_tests/bootstrap.rs
Normal file
17
crates/ksp-app-config-desk/unit_tests/bootstrap.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// file: crates/ksp-app-config-desk/unit_tests/bootstrap.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn fallback_logging_is_console_only_and_bounded_to_info() {
|
||||
let settings = super::fallback_logging_settings();
|
||||
assert_eq!(settings.default_filter(), ksp_logging_lib::LogFilterLevel::Info);
|
||||
assert_eq!(settings.span_events(), ksp_logging_lib::SpanEvents::Off);
|
||||
assert!(settings.files().is_empty());
|
||||
let console = settings.console();
|
||||
assert!(console.is_some());
|
||||
if let std::option::Option::Some(console) = console {
|
||||
assert!(console.enabled());
|
||||
assert_eq!(console.output(), ksp_logging_lib::ConsoleOutput::Stderr);
|
||||
assert_eq!(console.format(), ksp_logging_lib::LogFormat::Human);
|
||||
}
|
||||
}
|
||||
11
crates/ksp-app-config-desk/unit_tests/dto_common.rs
Normal file
11
crates/ksp-app-config-desk/unit_tests/dto_common.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
// file: crates/ksp-app-config-desk/unit_tests/dto_common.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn command_error_projection_excludes_context_values() {
|
||||
let error = ksp_core_lib::Error::new(ksp_core_lib::ErrorCode::new("test", "failure"), "safe message").with_context("secret_canary", "must-not-be-exported");
|
||||
let dto = super::CommandErrorDto::from_error(&error);
|
||||
assert_eq!(dto.domain, "test");
|
||||
assert_eq!(dto.code, "failure");
|
||||
assert_eq!(dto.message, "safe message");
|
||||
}
|
||||
Reference in New Issue
Block a user