refactor: app logging - script-src access in release

This commit is contained in:
Louis 2025-04-07 02:03:51 +07:00
parent 7392b2f92b
commit 38c7355e43
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
11 changed files with 62 additions and 67 deletions

View File

@ -21,7 +21,6 @@
"dev:electron": "yarn copy:assets && yarn workspace jan dev", "dev:electron": "yarn copy:assets && yarn workspace jan dev",
"dev:web:standalone": "concurrently \"yarn workspace @janhq/web dev\" \"wait-on http://localhost:3000 && rsync -av --prune-empty-dirs --include '*/' --include 'dist/***' --include 'package.json' --include 'tsconfig.json' --exclude '*' ./extensions/ web/.next/static/extensions/\"", "dev:web:standalone": "concurrently \"yarn workspace @janhq/web dev\" \"wait-on http://localhost:3000 && rsync -av --prune-empty-dirs --include '*/' --include 'dist/***' --include 'package.json' --include 'tsconfig.json' --exclude '*' ./extensions/ web/.next/static/extensions/\"",
"dev:web": "yarn workspace @janhq/web dev", "dev:web": "yarn workspace @janhq/web dev",
"dev:web:tauri": "IS_TAURI=true yarn workspace @janhq/web dev",
"dev:server": "yarn workspace @janhq/server dev", "dev:server": "yarn workspace @janhq/server dev",
"dev": "concurrently -n \"NEXT,ELECTRON\" -c \"yellow,blue\" --kill-others \"yarn dev:web\" \"yarn dev:electron\"", "dev": "concurrently -n \"NEXT,ELECTRON\" -c \"yellow,blue\" --kill-others \"yarn dev:web\" \"yarn dev:electron\"",
"install:cortex:linux:darwin": "cd src-tauri/binaries && ./download.sh", "install:cortex:linux:darwin": "cd src-tauri/binaries && ./download.sh",

View File

@ -21,9 +21,7 @@ tauri-build = { version = "2.0.2", features = [] }
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
log = "0.4" log = "0.4"
tauri = { version = "2.1.0", features = [ tauri = { version = "2.1.0", features = [ "protocol-asset", "macos-private-api",
"protocol-asset",
'macos-private-api',
"test", "test",
] } ] }
tauri-plugin-log = "2.0.0-rc" tauri-plugin-log = "2.0.0-rc"
@ -36,7 +34,6 @@ tauri-plugin-store = "2"
hyper = { version = "0.14", features = ["server"] } hyper = { version = "0.14", features = ["server"] }
reqwest = { version = "0.11", features = ["json"] } reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tracing = "0.1.41"
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main", features = [ rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main", features = [
"client", "client",
"transport-sse", "transport-sse",

View File

@ -2,18 +2,15 @@
"$schema": "../gen/schemas/desktop-schema.json", "$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default", "identifier": "default",
"description": "enables the default permissions", "description": "enables the default permissions",
"windows": [ "windows": ["main"],
"main"
],
"remote": { "remote": {
"urls": [ "urls": ["http://*"]
"http://*"
]
}, },
"permissions": [ "permissions": [
"core:default", "core:default",
"shell:allow-spawn", "shell:allow-spawn",
"shell:allow-open", "shell:allow-open",
"log:default",
{ {
"identifier": "http:default", "identifier": "http:default",
"allow": [ "allow": [

View File

@ -35,7 +35,7 @@ pub fn get_app_configurations<R: Runtime>(app_handle: tauri::AppHandle<R>) -> Ap
let default_data_folder = default_data_folder_path(app_handle.clone()); let default_data_folder = default_data_folder_path(app_handle.clone());
if !configuration_file.exists() { if !configuration_file.exists() {
println!( log::info!(
"App config not found, creating default config at {:?}", "App config not found, creating default config at {:?}",
configuration_file configuration_file
); );
@ -46,7 +46,7 @@ pub fn get_app_configurations<R: Runtime>(app_handle: tauri::AppHandle<R>) -> Ap
&configuration_file, &configuration_file,
serde_json::to_string(&app_default_configuration).unwrap(), serde_json::to_string(&app_default_configuration).unwrap(),
) { ) {
eprintln!("Failed to create default config: {}", err); log::error!("Failed to create default config: {}", err);
} }
return app_default_configuration; return app_default_configuration;
@ -56,7 +56,7 @@ pub fn get_app_configurations<R: Runtime>(app_handle: tauri::AppHandle<R>) -> Ap
Ok(content) => match serde_json::from_str::<AppConfiguration>(&content) { Ok(content) => match serde_json::from_str::<AppConfiguration>(&content) {
Ok(app_configurations) => app_configurations, Ok(app_configurations) => app_configurations,
Err(err) => { Err(err) => {
eprintln!( log::error!(
"Failed to parse app config, returning default config instead. Error: {}", "Failed to parse app config, returning default config instead. Error: {}",
err err
); );
@ -64,7 +64,7 @@ pub fn get_app_configurations<R: Runtime>(app_handle: tauri::AppHandle<R>) -> Ap
} }
}, },
Err(err) => { Err(err) => {
eprintln!( log::error!(
"Failed to read app config, returning default config instead. Error: {}", "Failed to read app config, returning default config instead. Error: {}",
err err
); );
@ -79,7 +79,7 @@ pub fn update_app_configuration(
configuration: AppConfiguration, configuration: AppConfiguration,
) -> Result<(), String> { ) -> Result<(), String> {
let configuration_file = get_configuration_file_path(app_handle); let configuration_file = get_configuration_file_path(app_handle);
println!( log::info!(
"update_app_configuration, configuration_file: {:?}", "update_app_configuration, configuration_file: {:?}",
configuration_file configuration_file
); );
@ -136,7 +136,7 @@ pub fn read_theme(app_handle: tauri::AppHandle, theme_name: String) -> Result<St
#[tauri::command] #[tauri::command]
pub fn get_configuration_file_path<R: Runtime>(app_handle: tauri::AppHandle<R>) -> PathBuf { pub fn get_configuration_file_path<R: Runtime>(app_handle: tauri::AppHandle<R>) -> PathBuf {
let app_path = app_handle.path().app_data_dir().unwrap_or_else(|err| { let app_path = app_handle.path().app_data_dir().unwrap_or_else(|err| {
eprintln!( log::error!(
"Failed to get app data directory: {}. Using home directory instead.", "Failed to get app data directory: {}. Using home directory instead.",
err err
); );
@ -215,7 +215,7 @@ pub fn open_file_explorer(path: String) {
#[tauri::command] #[tauri::command]
pub fn install_extensions(app: AppHandle) { pub fn install_extensions(app: AppHandle) {
if let Err(err) = setup::install_extensions(app, true) { if let Err(err) = setup::install_extensions(app, true) {
eprintln!("Failed to install extensions: {}", err); log::error!("Failed to install extensions: {}", err);
} }
} }
@ -223,7 +223,7 @@ pub fn install_extensions(app: AppHandle) {
pub fn get_active_extensions(app: AppHandle) -> Vec<serde_json::Value> { pub fn get_active_extensions(app: AppHandle) -> Vec<serde_json::Value> {
let mut path = get_jan_extensions_path(app); let mut path = get_jan_extensions_path(app);
path.push("extensions.json"); path.push("extensions.json");
println!("get jan extensions, path: {:?}", path); log::info!("get jan extensions, path: {:?}", path);
let contents = fs::read_to_string(path); let contents = fs::read_to_string(path);
let contents: Vec<serde_json::Value> = match contents { let contents: Vec<serde_json::Value> = match contents {

View File

@ -73,7 +73,7 @@ pub fn readdir_sync<R: Runtime>(
} }
let path = resolve_path(app_handle, &args[0]); let path = resolve_path(app_handle, &args[0]);
println!("Reading directory: {:?}", path); log::error!("Reading directory: {:?}", path);
let entries = fs::read_dir(&path).map_err(|e| e.to_string())?; let entries = fs::read_dir(&path).map_err(|e| e.to_string())?;
let paths: Vec<String> = entries let paths: Vec<String> = entries
.filter_map(|entry| entry.ok()) .filter_map(|entry| entry.ok())

View File

@ -17,7 +17,7 @@ pub async fn run_mcp_commands(
app_path: String, app_path: String,
servers_state: Arc<Mutex<HashMap<String, RunningService<RoleClient, ()>>>>, servers_state: Arc<Mutex<HashMap<String, RunningService<RoleClient, ()>>>>,
) -> Result<(), String> { ) -> Result<(), String> {
println!( log::info!(
"Load MCP configs from {}", "Load MCP configs from {}",
app_path.clone() + "/mcp_config.json" app_path.clone() + "/mcp_config.json"
); );
@ -29,7 +29,7 @@ pub async fn run_mcp_commands(
.map_err(|e| format!("Failed to parse config: {}", e))?; .map_err(|e| format!("Failed to parse config: {}", e))?;
if let Some(server_map) = mcp_servers.get("mcpServers").and_then(Value::as_object) { if let Some(server_map) = mcp_servers.get("mcpServers").and_then(Value::as_object) {
println!("MCP Servers: {server_map:#?}"); log::info!("MCP Servers: {server_map:#?}");
for (name, config) in server_map { for (name, config) in server_map {
if let Some((command, args)) = extract_command_args(config) { if let Some((command, args)) = extract_command_args(config) {
@ -53,7 +53,7 @@ pub async fn run_mcp_commands(
for (_, service) in servers_map.iter() { for (_, service) in servers_map.iter() {
// Initialize // Initialize
let _server_info = service.peer_info(); let _server_info = service.peer_info();
println!("Connected to server: {_server_info:#?}"); log::info!("Connected to server: {_server_info:#?}");
} }
Ok(()) Ok(())
} }

View File

@ -6,7 +6,6 @@ use std::net::SocketAddr;
use std::sync::LazyLock; use std::sync::LazyLock;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tracing::{debug, error, info};
/// Server handle type for managing the proxy server lifecycle /// Server handle type for managing the proxy server lifecycle
type ServerHandle = JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>>; type ServerHandle = JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>>;
@ -24,7 +23,7 @@ struct ProxyConfig {
/// Removes a prefix from a path, ensuring proper formatting /// Removes a prefix from a path, ensuring proper formatting
fn remove_prefix(path: &str, prefix: &str) -> String { fn remove_prefix(path: &str, prefix: &str) -> String {
debug!("Processing path: {}, removing prefix: {}", path, prefix); log::debug!("Processing path: {}, removing prefix: {}", path, prefix);
if !prefix.is_empty() && path.starts_with(prefix) { if !prefix.is_empty() && path.starts_with(prefix) {
let result = path[prefix.len()..].to_string(); let result = path[prefix.len()..].to_string();
@ -42,7 +41,6 @@ fn remove_prefix(path: &str, prefix: &str) -> String {
fn get_destination_path(original_path: &str, prefix: &str) -> String { fn get_destination_path(original_path: &str, prefix: &str) -> String {
let removed_prefix_path = remove_prefix(original_path, prefix); let removed_prefix_path = remove_prefix(original_path, prefix);
println!("Removed prefix path: {}", removed_prefix_path);
// Special paths don't need the /v1 prefix // Special paths don't need the /v1 prefix
if !original_path.contains(prefix) if !original_path.contains(prefix)
|| removed_prefix_path.contains("/healthz") || removed_prefix_path.contains("/healthz")
@ -81,7 +79,7 @@ async fn proxy_request(
// Build the outbound request // Build the outbound request
let upstream_url = build_upstream_url(&config.upstream, &path); let upstream_url = build_upstream_url(&config.upstream, &path);
debug!("Proxying request to: {}", upstream_url); log::debug!("Proxying request to: {}", upstream_url);
let mut outbound_req = client.request(req.method().clone(), &upstream_url); let mut outbound_req = client.request(req.method().clone(), &upstream_url);
@ -100,7 +98,7 @@ async fn proxy_request(
match outbound_req.body(req.into_body()).send().await { match outbound_req.body(req.into_body()).send().await {
Ok(response) => { Ok(response) => {
let status = response.status(); let status = response.status();
debug!("Received response with status: {}", status); log::debug!("Received response with status: {}", status);
let mut builder = Response::builder().status(status); let mut builder = Response::builder().status(status);
@ -113,7 +111,7 @@ async fn proxy_request(
match response.bytes().await { match response.bytes().await {
Ok(bytes) => Ok(builder.body(Body::from(bytes)).unwrap()), Ok(bytes) => Ok(builder.body(Body::from(bytes)).unwrap()),
Err(e) => { Err(e) => {
error!("Failed to read response body: {}", e); log::error!("Failed to read response body: {}", e);
Ok(Response::builder() Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR) .status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from("Error reading upstream response")) .body(Body::from("Error reading upstream response"))
@ -122,7 +120,7 @@ async fn proxy_request(
} }
} }
Err(e) => { Err(e) => {
error!("Proxy request failed: {}", e); log::error!("Proxy request failed: {}", e);
Ok(Response::builder() Ok(Response::builder()
.status(StatusCode::BAD_GATEWAY) .status(StatusCode::BAD_GATEWAY)
.body(Body::from(format!("Upstream error: {}", e))) .body(Body::from(format!("Upstream error: {}", e)))
@ -175,12 +173,12 @@ pub async fn start_server(
// Create and start the server // Create and start the server
let server = Server::bind(&addr).serve(make_svc); let server = Server::bind(&addr).serve(make_svc);
info!("Proxy server started on http://{}", addr); log::info!("Proxy server started on http://{}", addr);
// Spawn server task // Spawn server task
let server_handle = tokio::spawn(async move { let server_handle = tokio::spawn(async move {
if let Err(e) = server.await { if let Err(e) = server.await {
error!("Server error: {}", e); log::error!("Server error: {}", e);
return Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>); return Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>);
} }
Ok(()) Ok(())
@ -196,9 +194,9 @@ pub async fn stop_server() -> Result<(), Box<dyn std::error::Error + Send + Sync
if let Some(handle) = handle_guard.take() { if let Some(handle) = handle_guard.take() {
handle.abort(); handle.abort();
info!("Proxy server stopped"); log::info!("Proxy server stopped");
} else { } else {
debug!("No server was running"); log::debug!("No server was running");
} }
Ok(()) Ok(())

View File

@ -11,6 +11,7 @@ use tauri_plugin_shell::process::CommandEvent;
use tauri_plugin_shell::ShellExt; use tauri_plugin_shell::ShellExt;
use tauri_plugin_store::StoreExt; use tauri_plugin_store::StoreExt;
// MCP
use super::{ use super::{
cmd::{get_jan_data_folder_path, get_jan_extensions_path}, cmd::{get_jan_data_folder_path, get_jan_extensions_path},
mcp::run_mcp_commands, mcp::run_mcp_commands,
@ -39,7 +40,7 @@ pub fn install_extensions(app: tauri::AppHandle, force: bool) -> Result<(), Stri
// Attempt to remove extensions folder // Attempt to remove extensions folder
if extensions_path.exists() { if extensions_path.exists() {
fs::remove_dir_all(&extensions_path).unwrap_or_else(|_| { fs::remove_dir_all(&extensions_path).unwrap_or_else(|_| {
println!("Failed to remove existing extensions folder, it may not exist."); log::info!("Failed to remove existing extensions folder, it may not exist.");
}); });
} }
@ -66,7 +67,7 @@ pub fn install_extensions(app: tauri::AppHandle, force: bool) -> Result<(), Stri
let path = entry.path(); let path = entry.path();
if path.extension().map_or(false, |ext| ext == "tgz") { if path.extension().map_or(false, |ext| ext == "tgz") {
println!("Installing extension from {:?}", path); log::info!("Installing extension from {:?}", path);
let tar_gz = File::open(&path).map_err(|e| e.to_string())?; let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
let gz_decoder = GzDecoder::new(tar_gz); let gz_decoder = GzDecoder::new(tar_gz);
let mut archive = Archive::new(gz_decoder); let mut archive = Archive::new(gz_decoder);
@ -132,7 +133,7 @@ pub fn install_extensions(app: tauri::AppHandle, force: bool) -> Result<(), Stri
extensions_list.push(new_extension); extensions_list.push(new_extension);
println!("Installed extension to {:?}", extension_dir); log::info!("Installed extension to {:?}", extension_dir);
} }
} }
fs::write( fs::write(
@ -186,7 +187,7 @@ pub fn setup_mcp(app: &App) {
let servers = state.mcp_servers.clone(); let servers = state.mcp_servers.clone();
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
if let Err(e) = run_mcp_commands(app_path_str, servers).await { if let Err(e) = run_mcp_commands(app_path_str, servers).await {
eprintln!("Failed to run mcp commands: {}", e); log::error!("Failed to run mcp commands: {}", e);
} }
}); });
} }
@ -252,7 +253,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
if let CommandEvent::Stdout(line_bytes) = event { if let CommandEvent::Stdout(line_bytes) = event {
let line = String::from_utf8_lossy(&line_bytes); let line = String::from_utf8_lossy(&line_bytes);
println!("Outputs: {:?}", line) log::info!("Outputs: {:?}", line)
} }
} }
}); });
@ -268,7 +269,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
fn copy_dir_all(src: PathBuf, dst: PathBuf) -> Result<(), String> { fn copy_dir_all(src: PathBuf, dst: PathBuf) -> Result<(), String> {
fs::create_dir_all(&dst).map_err(|e| e.to_string())?; fs::create_dir_all(&dst).map_err(|e| e.to_string())?;
println!("Copying from {:?} to {:?}", src, dst); log::info!("Copying from {:?} to {:?}", src, dst);
for entry in fs::read_dir(src).map_err(|e| e.to_string())? { for entry in fs::read_dir(src).map_err(|e| e.to_string())? {
let entry = entry.map_err(|e| e.to_string())?; let entry = entry.map_err(|e| e.to_string())?;
let ty = entry.file_type().map_err(|e| e.to_string())?; let ty = entry.file_type().map_err(|e| e.to_string())?;
@ -293,10 +294,10 @@ pub fn setup_engine_binaries(app: &App) -> Result<(), String> {
.join("resources"); .join("resources");
if let Err(e) = copy_dir_all(binaries_dir, app_data_dir.clone()) { if let Err(e) = copy_dir_all(binaries_dir, app_data_dir.clone()) {
eprintln!("Failed to copy binaries: {}", e); log::error!("Failed to copy binaries: {}", e);
} }
if let Err(e) = copy_dir_all(themes_dir, app_data_dir.clone()) { if let Err(e) = copy_dir_all(themes_dir, app_data_dir.clone()) {
eprintln!("Failed to copy themes: {}", e); log::error!("Failed to copy themes: {}", e);
} }
Ok(()) Ok(())
} }

View File

@ -1,5 +1,6 @@
mod core; mod core;
use core::{ use core::{
cmd::get_jan_data_folder_path,
setup::{self, setup_engine_binaries, setup_mcp, setup_sidecar}, setup::{self, setup_engine_binaries, setup_mcp, setup_sidecar},
state::{generate_app_token, AppState}, state::{generate_app_token, AppState},
}; };
@ -11,8 +12,8 @@ use tokio::sync::Mutex;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
// FS commands - Deperecate soon // FS commands - Deperecate soon
@ -47,25 +48,26 @@ pub fn run() {
mcp_servers: Arc::new(Mutex::new(HashMap::new())), mcp_servers: Arc::new(Mutex::new(HashMap::new())),
}) })
.setup(|app| { .setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin( app.handle().plugin(
tauri_plugin_log::Builder::default() tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info) .targets([
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Folder {
path: get_jan_data_folder_path(app.handle().clone()).join("logs"),
file_name: Some("app".to_string()),
}),
if cfg!(debug_assertions) {
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout)
},
])
.build(), .build(),
)?; )?;
}
// Install extensions // Install extensions
if let Err(e) = setup::install_extensions(app.handle().clone(), false) { if let Err(e) = setup::install_extensions(app.handle().clone(), false) {
eprintln!("Failed to install extensions: {}", e); log::error!("Failed to install extensions: {}", e);
} }
setup_mcp(app); setup_mcp(app);
setup_sidecar(app).expect("Failed to setup sidecar"); setup_sidecar(app).expect("Failed to setup sidecar");
setup_engine_binaries(app).expect("Failed to setup engine binaries"); setup_engine_binaries(app).expect("Failed to setup engine binaries");
Ok(()) Ok(())
}) })
.on_window_event(|window, event| match event { .on_window_event(|window, event| match event {

View File

@ -1,13 +1,13 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "https://schema.tauri.app/config/2",
"productName": "Jan", "productName": "Jan",
"version": "0.1.0", "version": "0.1.0",
"identifier": "jan.ai", "identifier": "jan.ai",
"build": { "build": {
"frontendDist": "../web/out", "frontendDist": "../web/out",
"devUrl": "http://localhost:3000", "devUrl": "http://localhost:3000",
"beforeDevCommand": "yarn dev:web:tauri", "beforeDevCommand": "IS_TAURI=true yarn dev:web",
"beforeBuildCommand": "yarn build:web" "beforeBuildCommand": "IS_TAURI=true yarn build:web"
}, },
"app": { "app": {
"macOSPrivateApi": true, "macOSPrivateApi": true,
@ -27,9 +27,10 @@
"csp": { "csp": {
"default-src": "'self' customprotocol: asset: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*", "default-src": "'self' customprotocol: asset: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*",
"connect-src": "ipc: http://ipc.localhost", "connect-src": "ipc: http://ipc.localhost",
"font-src": ["https://fonts.gstatic.com"], "font-src": ["https://fonts.gstatic.com blob: data:"],
"img-src": "'self' asset: http://asset.localhost blob: data:", "img-src": "'self' asset: http://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com" "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com",
"script-src": "'self' asset: $APPDATA/**.*"
}, },
"assetProtocol": { "assetProtocol": {
"enable": true, "enable": true,

View File

@ -22,7 +22,8 @@ export const useLoadTheme = () => {
const setNativeTheme = useCallback( const setNativeTheme = useCallback(
(nativeTheme: NativeThemeProps) => { (nativeTheme: NativeThemeProps) => {
if (!('setNativeThemeDark' in window.core.api)) return if (!window.electronAPI) return
if (nativeTheme === 'dark') { if (nativeTheme === 'dark') {
window?.core?.api?.setNativeThemeDark() window?.core?.api?.setNativeThemeDark()
setTheme('dark') setTheme('dark')
@ -58,21 +59,20 @@ export const useLoadTheme = () => {
setThemeOptions(themesOptions) setThemeOptions(themesOptions)
if (!selectedIdTheme.length) return setSelectedIdTheme('joi-light') if (!selectedIdTheme.length) return setSelectedIdTheme('joi-light')
const theme: Theme = JSON.parse( const theme: Theme = JSON.parse(
await window.core.api.readTheme({ await window.core.api.readTheme({
theme: selectedIdTheme, themeName: selectedIdTheme,
}) })
) )
setThemeData(theme) setThemeData(theme)
setNativeTheme(theme.nativeTheme) setNativeTheme(theme.nativeTheme)
applyTheme(theme) applyTheme(theme)
}, []) }, [selectedIdTheme])
const configureTheme = useCallback(async () => { const configureTheme = useCallback(async () => {
if (!themeData || !themeOptions) { if (!themeData || !themeOptions) {
await getThemes() getThemes()
} else { } else {
applyTheme(themeData) applyTheme(themeData)
} }