mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-06-10 08:32:50 +02:00
Remove analytics and add more update headers
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AnalyticsAction = "cancel" | "click" | "commit" | "create" | "delete" | "delete_many" | "duplicate" | "error" | "export" | "hide" | "import" | "launch" | "launch_first" | "launch_update" | "send" | "show" | "toggle" | "update" | "upsert";
|
||||
|
||||
export type AnalyticsResource = "app" | "appearance" | "button" | "checkbox" | "cookie_jar" | "dialog" | "environment" | "folder" | "grpc_connection" | "grpc_event" | "grpc_request" | "http_request" | "http_response" | "key_value" | "link" | "mutation" | "plugin" | "select" | "setting" | "sidebar" | "tab" | "theme" | "websocket_connection" | "websocket_event" | "websocket_request" | "workspace";
|
||||
@@ -1,247 +0,0 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use log::{debug, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use tauri::{Manager, Runtime, WebviewWindow};
|
||||
|
||||
use ts_rs::TS;
|
||||
use yaak_models::queries::{
|
||||
generate_id, get_key_value_int, get_key_value_string, get_or_create_settings,
|
||||
set_key_value_int, set_key_value_string, UpdateSource,
|
||||
};
|
||||
|
||||
use crate::is_dev;
|
||||
|
||||
const NAMESPACE: &str = "analytics";
|
||||
const NUM_LAUNCHES_KEY: &str = "num_launches";
|
||||
|
||||
// serializable
|
||||
#[derive(Serialize, Deserialize, Debug, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export, export_to = "analytics.ts")]
|
||||
pub enum AnalyticsResource {
|
||||
App,
|
||||
Appearance,
|
||||
Button,
|
||||
Checkbox,
|
||||
CookieJar,
|
||||
Dialog,
|
||||
Environment,
|
||||
Folder,
|
||||
GrpcConnection,
|
||||
GrpcEvent,
|
||||
GrpcRequest,
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
KeyValue,
|
||||
Link,
|
||||
Mutation,
|
||||
Plugin,
|
||||
Select,
|
||||
Setting,
|
||||
Sidebar,
|
||||
Tab,
|
||||
Theme,
|
||||
WebsocketConnection,
|
||||
WebsocketEvent,
|
||||
WebsocketRequest,
|
||||
Workspace,
|
||||
}
|
||||
|
||||
impl AnalyticsResource {
|
||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsResource> {
|
||||
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AnalyticsResource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", serde_json::to_string(self).unwrap().replace("\"", ""))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export, export_to = "analytics.ts")]
|
||||
pub enum AnalyticsAction {
|
||||
Cancel,
|
||||
Click,
|
||||
Commit,
|
||||
Create,
|
||||
Delete,
|
||||
DeleteMany,
|
||||
Duplicate,
|
||||
Error,
|
||||
Export,
|
||||
Hide,
|
||||
Import,
|
||||
Launch,
|
||||
LaunchFirst,
|
||||
LaunchUpdate,
|
||||
Send,
|
||||
Show,
|
||||
Toggle,
|
||||
Update,
|
||||
Upsert,
|
||||
}
|
||||
|
||||
impl AnalyticsAction {
|
||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsAction> {
|
||||
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AnalyticsAction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", serde_json::to_string(self).unwrap().replace("\"", ""))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LaunchEventInfo {
|
||||
pub current_version: String,
|
||||
pub previous_version: String,
|
||||
pub launched_after_update: bool,
|
||||
pub num_launches: i32,
|
||||
}
|
||||
|
||||
pub async fn track_launch_event<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEventInfo {
|
||||
let last_tracked_version_key = "last_tracked_version";
|
||||
|
||||
let mut info = LaunchEventInfo::default();
|
||||
|
||||
info.num_launches = get_num_launches(w).await + 1;
|
||||
info.previous_version = get_key_value_string(w, NAMESPACE, last_tracked_version_key, "").await;
|
||||
info.current_version = w.package_info().version.to_string();
|
||||
|
||||
if info.previous_version.is_empty() {
|
||||
track_event(w, AnalyticsResource::App, AnalyticsAction::LaunchFirst, None).await;
|
||||
} else {
|
||||
info.launched_after_update = info.current_version != info.previous_version;
|
||||
if info.launched_after_update {
|
||||
track_event(
|
||||
w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::LaunchUpdate,
|
||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
};
|
||||
|
||||
// Track a launch event in all cases
|
||||
track_event(
|
||||
w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Launch,
|
||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Update key values
|
||||
|
||||
set_key_value_string(
|
||||
w,
|
||||
NAMESPACE,
|
||||
last_tracked_version_key,
|
||||
info.current_version.as_str(),
|
||||
&UpdateSource::Background,
|
||||
)
|
||||
.await;
|
||||
set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches, &UpdateSource::Background)
|
||||
.await;
|
||||
|
||||
info
|
||||
}
|
||||
|
||||
pub async fn track_event<R: Runtime>(
|
||||
w: &WebviewWindow<R>,
|
||||
resource: AnalyticsResource,
|
||||
action: AnalyticsAction,
|
||||
attributes: Option<Value>,
|
||||
) {
|
||||
let id = get_id(w).await;
|
||||
let event = format!("{}.{}", resource, action);
|
||||
let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string();
|
||||
let info = w.app_handle().package_info();
|
||||
let tz = datetime::sys_timezone().unwrap_or("unknown".to_string());
|
||||
let site = match is_dev() {
|
||||
true => "site_TkHWjoXwZPq3HfhERb",
|
||||
false => "site_zOK0d7jeBy2TLxFCnZ",
|
||||
};
|
||||
let base_url = match is_dev() {
|
||||
true => "http://localhost:7194",
|
||||
false => "https://t.yaak.app",
|
||||
};
|
||||
let params = vec![
|
||||
("u", id),
|
||||
("e", event.clone()),
|
||||
("a", attributes_json.clone()),
|
||||
("id", site.to_string()),
|
||||
("v", info.version.clone().to_string()),
|
||||
("os", get_os().to_string()),
|
||||
("tz", tz),
|
||||
("xy", get_window_size(w)),
|
||||
];
|
||||
let req =
|
||||
reqwest::Client::builder().build().unwrap().get(format!("{base_url}/t/e")).query(¶ms);
|
||||
|
||||
let settings = get_or_create_settings(w).await;
|
||||
if !settings.telemetry {
|
||||
info!("Track event (disabled): {}", event);
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable analytics actual sending in dev
|
||||
if is_dev() {
|
||||
debug!("Track event: {} {}", event, attributes_json);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(e) = req.send().await {
|
||||
info!("Error sending analytics event: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_os() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"windows"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"macos"
|
||||
} else if cfg!(target_os = "linux") {
|
||||
"linux"
|
||||
} else {
|
||||
"unknown"
|
||||
}
|
||||
}
|
||||
|
||||
fn get_window_size<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||
let current_monitor = match w.current_monitor() {
|
||||
Ok(Some(m)) => m,
|
||||
_ => return "unknown".to_string(),
|
||||
};
|
||||
|
||||
let scale_factor = current_monitor.scale_factor();
|
||||
let size = current_monitor.size();
|
||||
let width: f64 = size.width as f64 / scale_factor;
|
||||
let height: f64 = size.height as f64 / scale_factor;
|
||||
|
||||
format!("{}x{}", (width / 100.0).round() * 100.0, (height / 100.0).round() * 100.0)
|
||||
}
|
||||
|
||||
async fn get_id<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||
let id = get_key_value_string(w, "analytics", "id", "").await;
|
||||
if id.is_empty() {
|
||||
let new_id = generate_id();
|
||||
set_key_value_string(w, "analytics", "id", new_id.as_str(), &UpdateSource::Background)
|
||||
.await;
|
||||
new_id
|
||||
} else {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_num_launches<R: Runtime>(w: &WebviewWindow<R>) -> i32 {
|
||||
get_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
use tauri::{Manager, Runtime, WebviewWindow};
|
||||
|
||||
use yaak_models::queries::{
|
||||
get_key_value_int, get_key_value_string,
|
||||
set_key_value_int, set_key_value_string, UpdateSource,
|
||||
};
|
||||
|
||||
const NAMESPACE: &str = "analytics";
|
||||
const NUM_LAUNCHES_KEY: &str = "num_launches";
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LaunchEventInfo {
|
||||
pub current_version: String,
|
||||
pub previous_version: String,
|
||||
pub launched_after_update: bool,
|
||||
pub num_launches: i32,
|
||||
}
|
||||
|
||||
pub async fn store_launch_history<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEventInfo {
|
||||
let last_tracked_version_key = "last_tracked_version";
|
||||
|
||||
let mut info = LaunchEventInfo::default();
|
||||
|
||||
info.num_launches = get_num_launches(w).await + 1;
|
||||
info.previous_version = get_key_value_string(w, NAMESPACE, last_tracked_version_key, "").await;
|
||||
info.current_version = w.package_info().version.to_string();
|
||||
|
||||
if info.previous_version.is_empty() {
|
||||
} else {
|
||||
info.launched_after_update = info.current_version != info.previous_version;
|
||||
};
|
||||
|
||||
// Update key values
|
||||
|
||||
set_key_value_string(
|
||||
w,
|
||||
NAMESPACE,
|
||||
last_tracked_version_key,
|
||||
info.current_version.as_str(),
|
||||
&UpdateSource::Background,
|
||||
)
|
||||
.await;
|
||||
|
||||
set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches, &UpdateSource::Background)
|
||||
.await;
|
||||
|
||||
info
|
||||
}
|
||||
|
||||
pub fn get_os() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"windows"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"macos"
|
||||
} else if cfg!(target_os = "linux") {
|
||||
"linux"
|
||||
} else {
|
||||
"unknown"
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_num_launches<R: Runtime>(w: &WebviewWindow<R>) -> i32 {
|
||||
get_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||
}
|
||||
+37
-52
@@ -1,13 +1,12 @@
|
||||
extern crate core;
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate objc;
|
||||
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||
use crate::encoding::read_response_body;
|
||||
use crate::grpc::metadata_to_map;
|
||||
use crate::http_request::send_http_request;
|
||||
use crate::notifications::YaakNotifier;
|
||||
use crate::render::{render_grpc_request, render_template};
|
||||
use crate::updates::{UpdateMode, YaakUpdater};
|
||||
use crate::updates::{UpdateMode, UpdateTrigger, YaakUpdater};
|
||||
use eventsource_client::{EventParser, SSE};
|
||||
use log::{debug, error, warn};
|
||||
use rand::random;
|
||||
@@ -30,8 +29,30 @@ use tokio::sync::Mutex;
|
||||
use tokio::task::block_in_place;
|
||||
use yaak_grpc::manager::{DynamicMessage, GrpcHandle};
|
||||
use yaak_grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||
use yaak_models::models::{CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection, GrpcConnectionState, GrpcEvent, GrpcEventType, GrpcRequest, HttpRequest, HttpResponse, HttpResponseState, KeyValue, ModelType, Plugin, Settings, WebsocketRequest, Workspace, WorkspaceMeta};
|
||||
use yaak_models::queries::{batch_upsert, cancel_pending_grpc_connections, cancel_pending_responses, create_default_http_response, delete_all_grpc_connections, delete_all_grpc_connections_for_workspace, delete_all_http_responses_for_request, delete_all_http_responses_for_workspace, delete_all_websocket_connections_for_workspace, delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request, delete_http_response, delete_plugin, delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request, ensure_base_environment, generate_model_id, get_base_environment, get_cookie_jar, get_environment, get_folder, get_grpc_connection, get_grpc_request, get_http_request, get_http_response, get_key_value_raw, get_or_create_settings, get_or_create_workspace_meta, get_plugin, get_workspace, get_workspace_export_resources, list_cookie_jars, list_environments, list_folders, list_grpc_connections_for_workspace, list_grpc_events, list_grpc_requests, list_http_requests, list_http_responses_for_workspace, list_key_values_raw, list_plugins, list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_plugin, upsert_workspace, upsert_workspace_meta, BatchUpsertResult, UpdateSource};
|
||||
use yaak_models::models::{
|
||||
CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection, GrpcConnectionState,
|
||||
GrpcEvent, GrpcEventType, GrpcRequest, HttpRequest, HttpResponse, HttpResponseState, KeyValue,
|
||||
ModelType, Plugin, Settings, WebsocketRequest, Workspace, WorkspaceMeta,
|
||||
};
|
||||
use yaak_models::queries::{
|
||||
batch_upsert, cancel_pending_grpc_connections, cancel_pending_responses,
|
||||
create_default_http_response, delete_all_grpc_connections,
|
||||
delete_all_grpc_connections_for_workspace, delete_all_http_responses_for_request,
|
||||
delete_all_http_responses_for_workspace, delete_all_websocket_connections_for_workspace,
|
||||
delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection,
|
||||
delete_grpc_request, delete_http_request, delete_http_response, delete_plugin,
|
||||
delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request,
|
||||
ensure_base_environment, generate_model_id, get_base_environment, get_cookie_jar,
|
||||
get_environment, get_folder, get_grpc_connection, get_grpc_request, get_http_request,
|
||||
get_http_response, get_key_value_raw, get_or_create_settings, get_or_create_workspace_meta,
|
||||
get_plugin, get_workspace, get_workspace_export_resources, list_cookie_jars, list_environments,
|
||||
list_folders, list_grpc_connections_for_workspace, list_grpc_events, list_grpc_requests,
|
||||
list_http_requests, list_http_responses_for_workspace, list_key_values_raw, list_plugins,
|
||||
list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar,
|
||||
upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_event,
|
||||
upsert_grpc_request, upsert_http_request, upsert_plugin, upsert_workspace,
|
||||
upsert_workspace_meta, BatchUpsertResult, UpdateSource,
|
||||
};
|
||||
use yaak_plugins::events::{
|
||||
BootResponse, CallHttpAuthenticationRequest, CallHttpRequestActionRequest, FilterResponse,
|
||||
GetHttpAuthenticationConfigResponse, GetHttpAuthenticationSummaryResponse,
|
||||
@@ -44,9 +65,9 @@ use yaak_sse::sse::ServerSentEvent;
|
||||
use yaak_templates::format::format_json;
|
||||
use yaak_templates::{Parser, Tokens};
|
||||
|
||||
mod analytics;
|
||||
mod encoding;
|
||||
mod grpc;
|
||||
mod history;
|
||||
mod http_request;
|
||||
mod notifications;
|
||||
mod plugin_events;
|
||||
@@ -807,7 +828,7 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.await
|
||||
.unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
||||
let file_contents = file.as_str();
|
||||
let (import_result, plugin_name) =
|
||||
let import_result =
|
||||
plugin_manager.import_data(&window, file_contents).await.map_err(|e| e.to_string())?;
|
||||
|
||||
let mut id_map: BTreeMap<String, String> = BTreeMap::new();
|
||||
@@ -923,14 +944,6 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
analytics::track_event(
|
||||
&window,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin_name })),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(upserted)
|
||||
}
|
||||
|
||||
@@ -1007,17 +1020,9 @@ async fn cmd_curl_to_request<R: Runtime>(
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
workspace_id: &str,
|
||||
) -> Result<HttpRequest, String> {
|
||||
let (import_result, plugin_name) =
|
||||
let import_result =
|
||||
{ plugin_manager.import_data(&window, command).await.map_err(|e| e.to_string())? };
|
||||
|
||||
analytics::track_event(
|
||||
&window,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin_name })),
|
||||
)
|
||||
.await;
|
||||
|
||||
import_result.resources.http_requests.get(0).ok_or("No curl command found".to_string()).map(
|
||||
|r| {
|
||||
let mut request = r.clone();
|
||||
@@ -1051,8 +1056,6 @@ async fn cmd_export_data(
|
||||
|
||||
f.sync_all().expect("Failed to sync");
|
||||
|
||||
analytics::track_event(&window, AnalyticsResource::App, AnalyticsAction::Export, None).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1131,28 +1134,6 @@ async fn response_err<R: Runtime>(
|
||||
response
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_track_event(
|
||||
window: WebviewWindow,
|
||||
resource: &str,
|
||||
action: &str,
|
||||
attributes: Option<Value>,
|
||||
) -> Result<(), String> {
|
||||
match (AnalyticsResource::from_str(resource), AnalyticsAction::from_str(action)) {
|
||||
(Ok(resource), Ok(action)) => {
|
||||
analytics::track_event(&window, resource, action, attributes).await;
|
||||
}
|
||||
(r, a) => {
|
||||
error!(
|
||||
"Invalid action/resource for track_event: {resource}.{action} = {:?}.{:?}",
|
||||
r, a
|
||||
);
|
||||
return Err("Invalid analytics event".to_string());
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_set_update_mode(update_mode: &str, w: WebviewWindow) -> Result<KeyValue, String> {
|
||||
cmd_set_key_value("app", "update_mode", update_mode, w).await.map_err(|e| e.to_string())
|
||||
@@ -1739,7 +1720,12 @@ async fn cmd_check_for_updates(
|
||||
yaak_updater: State<'_, Mutex<YaakUpdater>>,
|
||||
) -> Result<bool, String> {
|
||||
let update_mode = get_update_mode(&app_handle).await;
|
||||
yaak_updater.lock().await.force_check(&app_handle, update_mode).await.map_err(|e| e.to_string())
|
||||
yaak_updater
|
||||
.lock()
|
||||
.await
|
||||
.check_now(&app_handle, update_mode, UpdateTrigger::User)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
@@ -1918,7 +1904,6 @@ pub fn run() {
|
||||
cmd_set_update_mode,
|
||||
cmd_template_functions,
|
||||
cmd_template_tokens_to_string,
|
||||
cmd_track_event,
|
||||
cmd_uninstall_plugin,
|
||||
cmd_update_cookie_jar,
|
||||
cmd_update_environment,
|
||||
@@ -1941,7 +1926,7 @@ pub fn run() {
|
||||
RunEvent::Ready => {
|
||||
let w = create_main_window(app_handle, "/");
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let info = analytics::track_launch_event(&w).await;
|
||||
let info = history::store_launch_history(&w).await;
|
||||
debug!("Launched Yaak {:?}", info);
|
||||
});
|
||||
|
||||
@@ -1961,7 +1946,7 @@ pub fn run() {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let val: State<'_, Mutex<YaakUpdater>> = h.state();
|
||||
let update_mode = get_update_mode(&h).await;
|
||||
if let Err(e) = val.lock().await.check(&h, update_mode).await {
|
||||
if let Err(e) = val.lock().await.maybe_check(&h, update_mode).await {
|
||||
warn!("Failed to check for updates {e:?}");
|
||||
};
|
||||
});
|
||||
@@ -2070,7 +2055,7 @@ fn monitor_plugin_events<R: Runtime>(app_handle: &AppHandle<R>) {
|
||||
// We might have recursive back-and-forth calls between app and plugin, so we don't
|
||||
// want to block here
|
||||
tauri::async_runtime::spawn(async move {
|
||||
crate::plugin_events::handle_plugin_event(&app_handle, &event, &plugin).await;
|
||||
plugin_events::handle_plugin_event(&app_handle, &event, &plugin).await;
|
||||
});
|
||||
}
|
||||
plugin_manager.unsubscribe(rx_id.as_str()).await;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::analytics::{get_num_launches, get_os};
|
||||
use crate::history::{get_num_launches, get_os};
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use log::debug;
|
||||
use reqwest::Method;
|
||||
|
||||
@@ -6,6 +6,7 @@ use tauri::{AppHandle, Manager};
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons};
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
use tokio::task::block_in_place;
|
||||
use yaak_models::queries::get_or_create_settings;
|
||||
use yaak_plugins::manager::PluginManager;
|
||||
|
||||
use crate::is_dev;
|
||||
@@ -46,6 +47,11 @@ impl UpdateMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum UpdateTrigger {
|
||||
Background,
|
||||
User,
|
||||
}
|
||||
|
||||
impl YaakUpdater {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@@ -53,11 +59,14 @@ impl YaakUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn force_check(
|
||||
pub async fn check_now(
|
||||
&mut self,
|
||||
app_handle: &AppHandle,
|
||||
mode: UpdateMode,
|
||||
update_trigger: UpdateTrigger,
|
||||
) -> Result<bool, tauri_plugin_updater::Error> {
|
||||
let settings = get_or_create_settings(app_handle).await;
|
||||
let update_key = format!("{:x}", md5::compute(settings.id));
|
||||
self.last_update_check = SystemTime::now();
|
||||
|
||||
info!("Checking for updates mode={}", mode);
|
||||
@@ -79,6 +88,14 @@ impl YaakUpdater {
|
||||
});
|
||||
})
|
||||
.header("X-Update-Mode", mode.to_string())?
|
||||
.header("X-Update-Key", update_key)?
|
||||
.header(
|
||||
"X-Update-Trigger",
|
||||
match update_trigger {
|
||||
UpdateTrigger::Background => "background",
|
||||
UpdateTrigger::User => "user",
|
||||
},
|
||||
)?
|
||||
.build()?
|
||||
.check()
|
||||
.await;
|
||||
@@ -129,7 +146,7 @@ impl YaakUpdater {
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub async fn check(
|
||||
pub async fn maybe_check(
|
||||
&mut self,
|
||||
app_handle: &AppHandle,
|
||||
mode: UpdateMode,
|
||||
@@ -150,6 +167,6 @@ impl YaakUpdater {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.force_check(app_handle, mode).await
|
||||
self.check_now(app_handle, mode, UpdateTrigger::Background).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SyncModel } from "./gen_models";
|
||||
import type { SyncModel } from "./gen_models.js";
|
||||
|
||||
export type GitAuthor = { name: string | null, email: string | null, };
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export type ProxySetting = { "type": "enabled", http: string, https: string, aut
|
||||
|
||||
export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, telemetry: boolean, theme: string, themeDark: string, themeLight: string, updateChannel: string, editorKeymap: EditorKeymap, };
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, theme: string, themeDark: string, themeLight: string, updateChannel: string, editorKeymap: EditorKeymap, };
|
||||
|
||||
export type SyncHistory = { model: "sync_history", id: string, workspaceId: string, createdAt: string, states: Array<SyncState>, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ pub struct Settings {
|
||||
pub interface_scale: f32,
|
||||
pub open_workspace_new_window: Option<bool>,
|
||||
pub proxy: Option<ProxySetting>,
|
||||
pub telemetry: bool,
|
||||
pub theme: String,
|
||||
pub theme_dark: String,
|
||||
pub theme_light: String,
|
||||
@@ -112,7 +111,6 @@ pub enum SettingsIden {
|
||||
InterfaceScale,
|
||||
OpenWorkspaceNewWindow,
|
||||
Proxy,
|
||||
Telemetry,
|
||||
Theme,
|
||||
ThemeDark,
|
||||
ThemeLight,
|
||||
@@ -138,7 +136,6 @@ impl<'s> TryFrom<&Row<'s>> for Settings {
|
||||
interface_scale: r.get("interface_scale")?,
|
||||
open_workspace_new_window: r.get("open_workspace_new_window")?,
|
||||
proxy: proxy.map(|p| -> ProxySetting { serde_json::from_str(p.as_str()).unwrap() }),
|
||||
telemetry: r.get("telemetry")?,
|
||||
theme: r.get("theme")?,
|
||||
theme_dark: r.get("theme_dark")?,
|
||||
theme_light: r.get("theme_light")?,
|
||||
|
||||
@@ -1478,7 +1478,6 @@ pub async fn update_settings<R: Runtime>(
|
||||
(SettingsIden::EditorFontSize, settings.editor_font_size.into()),
|
||||
(SettingsIden::EditorKeymap, settings.editor_keymap.to_string().into()),
|
||||
(SettingsIden::EditorSoftWrap, settings.editor_soft_wrap.into()),
|
||||
(SettingsIden::Telemetry, settings.telemetry.into()),
|
||||
(SettingsIden::OpenWorkspaceNewWindow, settings.open_workspace_new_window.into()),
|
||||
(
|
||||
SettingsIden::Proxy,
|
||||
|
||||
@@ -559,7 +559,7 @@ impl PluginManager {
|
||||
Some(JsonPrimitive::Boolean(v)) => v.clone(),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
||||
// Auth is disabled, so don't do anything
|
||||
if disabled {
|
||||
info!("Not applying disabled auth {:?}", auth_name);
|
||||
@@ -623,7 +623,7 @@ impl PluginManager {
|
||||
&self,
|
||||
window: &WebviewWindow<R>,
|
||||
content: &str,
|
||||
) -> Result<(ImportResponse, String)> {
|
||||
) -> Result<ImportResponse> {
|
||||
let reply_events = self
|
||||
.send_and_wait(
|
||||
&WindowContext::from_window(window),
|
||||
@@ -635,19 +635,13 @@ impl PluginManager {
|
||||
|
||||
// TODO: Don't just return the first valid response
|
||||
let result = reply_events.into_iter().find_map(|e| match e.payload {
|
||||
InternalEventPayload::ImportResponse(resp) => Some((resp, e.plugin_ref_id)),
|
||||
InternalEventPayload::ImportResponse(resp) => Some(resp),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
match result {
|
||||
None => Err(PluginErr("No importers found for file contents".to_string())),
|
||||
Some((resp, ref_id)) => {
|
||||
let plugin = self
|
||||
.get_plugin_by_ref_id(ref_id.as_str())
|
||||
.await
|
||||
.ok_or(PluginNotFoundErr(ref_id))?;
|
||||
Ok((resp, plugin.info().await.name))
|
||||
}
|
||||
Some(resp) => Ok(resp),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import { InlineCode } from '../components/core/InlineCode';
|
||||
import { VStack } from '../components/core/Stacks';
|
||||
import { getActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirm } from '../lib/confirm';
|
||||
import { resolvedModelNameWithFolders } from '../lib/resolvedModelName';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
@@ -42,7 +41,6 @@ export const createFolder = createFastMutation<
|
||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||
return invokeCmd<Folder>('cmd_update_folder', { folder: { workspaceId, ...patch } });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'create'),
|
||||
});
|
||||
|
||||
export const syncWorkspace = createFastMutation<
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { WebsocketConnection } from '@yaakapp-internal/models';
|
||||
import { deleteWebsocketConnection as cmdDeleteWebsocketConnection } from '@yaakapp-internal/ws';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export const deleteWebsocketConnection = createFastMutation({
|
||||
mutationKey: ['delete_websocket_connection'],
|
||||
mutationFn: async function (connection: WebsocketConnection) {
|
||||
return cmdDeleteWebsocketConnection(connection.id);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
trackEvent('websocket_connection', 'delete');
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { deleteWebsocketConnections as cmdDeleteWebsocketConnections } from '@yaakapp-internal/ws';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export const deleteWebsocketConnections = createFastMutation({
|
||||
mutationKey: ['delete_websocket_connections'],
|
||||
mutationFn: async function (request: WebsocketRequest) {
|
||||
return cmdDeleteWebsocketConnections(request.id);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
trackEvent('websocket_connection', 'delete_many');
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { deleteWebsocketRequest as cmdDeleteWebsocketRequest } from '@yaakapp-internal/ws';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
|
||||
@@ -24,7 +23,4 @@ export const deleteWebsocketRequest = createFastMutation({
|
||||
|
||||
return cmdDeleteWebsocketRequest(request.id);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
trackEvent('websocket_request', 'delete');
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { duplicateWebsocketRequest as cmdDuplicateWebsocketRequest } from '@yaakapp-internal/ws';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
|
||||
export const duplicateWebsocketRequest = createFastMutation({
|
||||
@@ -10,7 +9,6 @@ export const duplicateWebsocketRequest = createFastMutation({
|
||||
return cmdDuplicateWebsocketRequest(request.id);
|
||||
},
|
||||
onSuccess: async (request) => {
|
||||
trackEvent('websocket_request', 'duplicate');
|
||||
await router.navigate({
|
||||
to: '/workspaces/$workspaceId',
|
||||
params: { workspaceId: request.workspaceId },
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { SettingsTab } from '../components/Settings/SettingsTab';
|
||||
import { getActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
@@ -11,7 +10,6 @@ export const openSettings = createFastMutation<void, string, SettingsTab | null>
|
||||
const workspaceId = getActiveWorkspaceId();
|
||||
if (workspaceId == null) return;
|
||||
|
||||
trackEvent('dialog', 'show', { id: 'settings', tab: `${tab}` });
|
||||
const location = router.buildLocation({
|
||||
to: '/workspaces/$workspaceId/settings',
|
||||
params: { workspaceId },
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { upsertWebsocketRequest as cmdUpsertWebsocketRequest } from '@yaakapp-internal/ws';
|
||||
import { differenceInMilliseconds } from 'date-fns';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
|
||||
export const upsertWebsocketRequest = createFastMutation<
|
||||
@@ -16,12 +15,11 @@ export const upsertWebsocketRequest = createFastMutation<
|
||||
const isNew = differenceInMilliseconds(new Date(), request.createdAt + 'Z') < 100;
|
||||
|
||||
if (isNew) {
|
||||
trackEvent('websocket_request', 'create');
|
||||
await router.navigate({
|
||||
to: '/workspaces/$workspaceId',
|
||||
params: { workspaceId: request.workspaceId },
|
||||
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||
});
|
||||
} else trackEvent('websocket_request', 'update');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { Workspace } from '@yaakapp-internal/models';
|
||||
import { differenceInMilliseconds } from 'date-fns';
|
||||
import { createFastMutation } from '../hooks/useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export const upsertWorkspace = createFastMutation<
|
||||
@@ -11,10 +9,4 @@ export const upsertWorkspace = createFastMutation<
|
||||
>({
|
||||
mutationKey: ['upsert_workspace'],
|
||||
mutationFn: (workspace) => invokeCmd<Workspace>('cmd_update_workspace', { workspace }),
|
||||
onSuccess: async (workspace) => {
|
||||
const isNew = differenceInMilliseconds(new Date(), workspace.createdAt + 'Z') < 100;
|
||||
|
||||
if (isNew) trackEvent('workspace', 'create');
|
||||
else trackEvent('workspace', 'update');
|
||||
},
|
||||
});
|
||||
|
||||
@@ -60,6 +60,7 @@ export function LicenseBadge() {
|
||||
size="2xs"
|
||||
variant="border"
|
||||
className="!rounded-full mx-1"
|
||||
color={detail.color}
|
||||
onClick={async () => {
|
||||
if (check.data.type === 'trialing') {
|
||||
await setLicenseDetails((v) => ({
|
||||
@@ -69,8 +70,6 @@ export function LicenseBadge() {
|
||||
}
|
||||
openSettings.mutate(SettingsTab.License);
|
||||
}}
|
||||
color={detail.color}
|
||||
event={{ id: 'license-badge', status: check.data.type }}
|
||||
>
|
||||
{detail.label}
|
||||
</Button>
|
||||
|
||||
@@ -66,18 +66,8 @@ export function MarkdownEditor({
|
||||
onChange={setViewMode}
|
||||
value={viewMode}
|
||||
options={[
|
||||
{
|
||||
event: { id: 'md_mode', mode: 'preview' },
|
||||
icon: 'eye',
|
||||
label: 'Preview mode',
|
||||
value: 'preview',
|
||||
},
|
||||
{
|
||||
event: { id: 'md_mode', mode: 'edit' },
|
||||
icon: 'pencil',
|
||||
label: 'Edit mode',
|
||||
value: 'edit',
|
||||
},
|
||||
{ icon: 'eye', label: 'Preview mode', value: 'preview' },
|
||||
{ icon: 'pencil', label: 'Edit mode', value: 'edit' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +96,6 @@ export function SettingsAppearance() {
|
||||
value={`${settings.interfaceFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) => updateSettings.mutate({ interfaceFontSize: parseInt(v) })}
|
||||
event="ui-font-size"
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
@@ -106,7 +105,6 @@ export function SettingsAppearance() {
|
||||
value={`${settings.editorFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) => updateSettings.mutate({ editorFontSize: clamp(parseInt(v) || 14, 8, 30) })}
|
||||
event="editor-font-size"
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
@@ -116,13 +114,11 @@ export function SettingsAppearance() {
|
||||
value={`${settings.editorKeymap}`}
|
||||
options={keymaps}
|
||||
onChange={(v) => updateSettings.mutate({ editorKeymap: v })}
|
||||
event="editor-keymap"
|
||||
/>
|
||||
<Checkbox
|
||||
checked={settings.editorSoftWrap}
|
||||
title="Wrap Editor Lines"
|
||||
onChange={(editorSoftWrap) => updateSettings.mutate({ editorSoftWrap })}
|
||||
event="editor-wrap-lines"
|
||||
/>
|
||||
|
||||
<Separator className="my-4" />
|
||||
@@ -134,7 +130,6 @@ export function SettingsAppearance() {
|
||||
size="sm"
|
||||
value={settings.appearance}
|
||||
onChange={(appearance) => updateSettings.mutate({ appearance })}
|
||||
event="appearance"
|
||||
options={[
|
||||
{ label: 'Automatic', value: 'system' },
|
||||
{ label: 'Light', value: 'light' },
|
||||
@@ -152,7 +147,6 @@ export function SettingsAppearance() {
|
||||
className="flex-1"
|
||||
value={activeTheme.light.id}
|
||||
options={lightThemes}
|
||||
event="theme.light"
|
||||
onChange={(themeLight) => updateSettings.mutate({ ...settings, themeLight })}
|
||||
/>
|
||||
)}
|
||||
@@ -166,7 +160,6 @@ export function SettingsAppearance() {
|
||||
size="sm"
|
||||
value={activeTheme.dark.id}
|
||||
options={darkThemes}
|
||||
event="theme.dark"
|
||||
onChange={(themeDark) => updateSettings.mutate({ ...settings, themeDark })}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -38,7 +38,6 @@ export function SettingsGeneral() {
|
||||
size="sm"
|
||||
value={settings.updateChannel}
|
||||
onChange={(updateChannel) => updateSettings.mutate({ updateChannel })}
|
||||
event="update-channel"
|
||||
options={[
|
||||
{ label: 'Stable (less frequent)', value: 'stable' },
|
||||
{ label: 'Beta (more frequent)', value: 'beta' },
|
||||
@@ -59,7 +58,6 @@ export function SettingsGeneral() {
|
||||
labelPosition="left"
|
||||
labelClassName="w-[14rem]"
|
||||
size="sm"
|
||||
event="workspace-switch-behavior"
|
||||
value={
|
||||
settings.openWorkspaceNewWindow === true
|
||||
? 'new'
|
||||
@@ -81,9 +79,9 @@ export function SettingsGeneral() {
|
||||
|
||||
<Checkbox
|
||||
className="mt-3"
|
||||
checked={settings.telemetry}
|
||||
title="Send Usage Statistics"
|
||||
event="usage-statistics"
|
||||
checked={false}
|
||||
title="Send Usage Statistics (all tracking was removed in 2025.1.2)"
|
||||
disabled
|
||||
onChange={(telemetry) => updateSettings.mutate({ telemetry })}
|
||||
/>
|
||||
|
||||
@@ -115,7 +113,6 @@ export function SettingsGeneral() {
|
||||
<Checkbox
|
||||
checked={workspace.settingValidateCertificates}
|
||||
title="Validate TLS Certificates"
|
||||
event="validate-certs"
|
||||
onChange={(settingValidateCertificates) =>
|
||||
upsertWorkspace.mutate({ ...workspace, settingValidateCertificates })
|
||||
}
|
||||
@@ -124,7 +121,6 @@ export function SettingsGeneral() {
|
||||
<Checkbox
|
||||
checked={workspace.settingFollowRedirects}
|
||||
title="Follow Redirects"
|
||||
event="follow-redirects"
|
||||
onChange={(settingFollowRedirects) =>
|
||||
upsertWorkspace.mutate({
|
||||
...workspace,
|
||||
|
||||
@@ -81,7 +81,6 @@ export function SettingsLicense() {
|
||||
color="secondary"
|
||||
size="sm"
|
||||
onClick={toggleActivateFormVisible}
|
||||
event="license.another"
|
||||
>
|
||||
Activate Another License
|
||||
</Button>
|
||||
@@ -90,7 +89,6 @@ export function SettingsLicense() {
|
||||
size="sm"
|
||||
onClick={() => openUrl('https://yaak.app/dashboard')}
|
||||
rightSlot={<Icon icon="external_link" />}
|
||||
event="license.support"
|
||||
>
|
||||
Direct Support
|
||||
</Button>
|
||||
@@ -101,7 +99,6 @@ export function SettingsLicense() {
|
||||
color="primary"
|
||||
size="sm"
|
||||
onClick={toggleActivateFormVisible}
|
||||
event="license.activate"
|
||||
>
|
||||
Activate
|
||||
</Button>
|
||||
@@ -110,7 +107,6 @@ export function SettingsLicense() {
|
||||
size="sm"
|
||||
onClick={() => openUrl('https://yaak.app/pricing?ref=app.yaak.desktop')}
|
||||
rightSlot={<Icon icon="external_link" />}
|
||||
event="license.purchase"
|
||||
>
|
||||
Purchase
|
||||
</Button>
|
||||
@@ -140,7 +136,6 @@ export function SettingsLicense() {
|
||||
color="primary"
|
||||
size="sm"
|
||||
isLoading={activate.isPending}
|
||||
event="license.submit"
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
|
||||
@@ -66,7 +66,6 @@ export function SettingsPlugins() {
|
||||
type="submit"
|
||||
color="primary"
|
||||
className="ml-auto"
|
||||
event="plugin.add"
|
||||
>
|
||||
Add Plugin
|
||||
</Button>
|
||||
@@ -76,14 +75,12 @@ export function SettingsPlugins() {
|
||||
icon="refresh"
|
||||
title="Reload plugins"
|
||||
spin={refreshPlugins.isPending}
|
||||
event="plugin.reload"
|
||||
onClick={() => refreshPlugins.mutate()}
|
||||
/>
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon="help"
|
||||
title="View documentation"
|
||||
event="plugin.docs"
|
||||
onClick={() => openUrl('https://feedback.yaak.app/help/articles/6911763-quick-start')}
|
||||
/>
|
||||
</HStack>
|
||||
@@ -107,7 +104,6 @@ function PluginInfo({ plugin }: { plugin: Plugin }) {
|
||||
size="sm"
|
||||
icon="trash"
|
||||
title="Uninstall plugin"
|
||||
event="plugin.delete"
|
||||
onClick={() => deletePlugin.mutate()}
|
||||
/>
|
||||
</td>
|
||||
|
||||
@@ -19,7 +19,6 @@ export function SettingsProxy() {
|
||||
hideLabel
|
||||
size="sm"
|
||||
value={settings.proxy?.type ?? 'automatic'}
|
||||
event="proxy"
|
||||
onChange={(v) => {
|
||||
if (v === 'automatic') {
|
||||
updateSettings.mutate({ proxy: undefined });
|
||||
|
||||
@@ -18,7 +18,6 @@ import { requestsAtom } from '../hooks/useRequests';
|
||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||
import { useLatestWebsocketConnection } from '../hooks/useWebsocketConnections';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { deepEqualAtom } from '../lib/atoms';
|
||||
import { languageFromContentType } from '../lib/contentType';
|
||||
import { generateId } from '../lib/generateId';
|
||||
@@ -190,7 +189,6 @@ export function WebsocketRequestPane({ style, fullHeight, className, activeReque
|
||||
environmentId: getActiveEnvironment()?.id ?? null,
|
||||
cookieJarId: getActiveCookieJar()?.id ?? null,
|
||||
});
|
||||
trackEvent('websocket_request', 'send');
|
||||
}, [activeRequest.id]);
|
||||
|
||||
const handleSend = useCallback(async () => {
|
||||
@@ -199,13 +197,11 @@ export function WebsocketRequestPane({ style, fullHeight, className, activeReque
|
||||
connectionId: connection?.id,
|
||||
environmentId: getActiveEnvironment()?.id ?? null,
|
||||
});
|
||||
trackEvent('websocket_connection', 'send');
|
||||
}, [connection]);
|
||||
|
||||
const handleCancel = useCallback(async () => {
|
||||
if (connection == null) return;
|
||||
await closeWebsocket({ connectionId: connection?.id });
|
||||
trackEvent('websocket_connection', 'cancel');
|
||||
}, [connection]);
|
||||
|
||||
const handleUrlChange = useCallback(
|
||||
|
||||
@@ -46,7 +46,6 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
|
||||
icon="search"
|
||||
title="Search or execute a command"
|
||||
size="sm"
|
||||
event="search"
|
||||
iconColor="secondary"
|
||||
onClick={togglePalette}
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { HTMLAttributes, ReactNode } from 'react';
|
||||
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||
import type { HotkeyAction } from '../../hooks/useHotKey';
|
||||
import { useFormattedHotkey, useHotKey } from '../../hooks/useHotKey';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import { Icon } from './Icon';
|
||||
import { LoadingIcon } from './LoadingIcon';
|
||||
|
||||
@@ -22,7 +21,6 @@ export type ButtonProps = Omit<HTMLAttributes<HTMLButtonElement>, 'color' | 'onC
|
||||
leftSlot?: ReactNode;
|
||||
rightSlot?: ReactNode;
|
||||
hotkeyAction?: HotkeyAction;
|
||||
event?: string | { id: string; [attr: string]: number | string };
|
||||
};
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
||||
@@ -43,7 +41,6 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||
hotkeyAction,
|
||||
title,
|
||||
onClick,
|
||||
event,
|
||||
...props
|
||||
}: ButtonProps,
|
||||
ref,
|
||||
@@ -107,12 +104,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||
type={type}
|
||||
className={classes}
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
onClick?.(e);
|
||||
if (event != null) {
|
||||
trackEvent('button', 'click', typeof event === 'string' ? { id: event } : event);
|
||||
}
|
||||
}}
|
||||
onClick={onClick}
|
||||
onDoubleClick={(e) => {
|
||||
// Kind of a hack? This prevents double-clicks from going through buttons. For example, when
|
||||
// double-clicking the workspace header to toggle window maximization
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import { type ReactNode } from 'react';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import { Icon } from './Icon';
|
||||
import { HStack } from './Stacks';
|
||||
|
||||
@@ -13,7 +12,6 @@ export interface CheckboxProps {
|
||||
inputWrapperClassName?: string;
|
||||
hideLabel?: boolean;
|
||||
fullWidth?: boolean;
|
||||
event?: string;
|
||||
}
|
||||
|
||||
export function Checkbox({
|
||||
@@ -25,7 +23,6 @@ export function Checkbox({
|
||||
title,
|
||||
hideLabel,
|
||||
fullWidth,
|
||||
event,
|
||||
}: CheckboxProps) {
|
||||
return (
|
||||
<HStack as="label" space={2} className={classNames(className, 'text-text mr-auto')}>
|
||||
@@ -42,9 +39,6 @@ export function Checkbox({
|
||||
disabled={disabled}
|
||||
onChange={() => {
|
||||
onChange(checked === 'indeterminate' ? true : !checked);
|
||||
if (event != null) {
|
||||
trackEvent('button', 'click', { id: event, checked: checked ? 'on' : 'off' });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { Link as RouterLink } from '@tanstack/react-router';
|
||||
import classNames from 'classnames';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
import { Link as RouterLink } from '@tanstack/react-router';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLAnchorElement> {
|
||||
href: string;
|
||||
event?: string;
|
||||
}
|
||||
|
||||
export function Link({ href, children, className, event, ...other }: Props) {
|
||||
export function Link({ href, children, className, ...other }: Props) {
|
||||
const isExternal = href.match(/^https?:\/\//);
|
||||
|
||||
className = classNames(className, 'relative underline hover:text-violet-600');
|
||||
@@ -23,9 +21,6 @@ export function Link({ href, children, className, event, ...other }: Props) {
|
||||
className={classNames(className, 'pr-4 inline-flex items-center')}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
if (event != null) {
|
||||
trackEvent('link', 'click', { id: event });
|
||||
}
|
||||
}}
|
||||
{...other}
|
||||
>
|
||||
|
||||
@@ -261,7 +261,6 @@ export const PairEditor = forwardRef<PairEditorRef, PairEditorProps>(function Pa
|
||||
variant="border"
|
||||
className="m-2"
|
||||
size="xs"
|
||||
event="pairs.reveal-more"
|
||||
>
|
||||
Show {pairs.length - MAX_INITIAL_PAIRS} More
|
||||
</Button>
|
||||
|
||||
@@ -2,18 +2,17 @@ import classNames from 'classnames';
|
||||
import { useRef } from 'react';
|
||||
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
|
||||
import type { IconProps } from './Icon';
|
||||
import type { IconButtonProps } from './IconButton';
|
||||
import { IconButton } from './IconButton';
|
||||
import { HStack } from './Stacks';
|
||||
|
||||
interface Props<T extends string> {
|
||||
options: { value: T; label: string; icon: IconProps['icon']; event?: IconButtonProps['event'] }[];
|
||||
options: { value: T; label: string; icon: IconProps['icon'] }[];
|
||||
onChange: (value: T) => void;
|
||||
value: T;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export function SegmentedControl<T extends string>({ value, onChange, options, name }: Props<T>) {
|
||||
export function SegmentedControl<T extends string>({ value, onChange, options }: Props<T>) {
|
||||
const [selectedValue, setSelectedValue] = useStateWithDeps<T>(value, [value]);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
@@ -45,14 +44,13 @@ export function SegmentedControl<T extends string>({ value, onChange, options, n
|
||||
<IconButton
|
||||
size="xs"
|
||||
variant="solid"
|
||||
color={isActive ? "secondary" : undefined}
|
||||
color={isActive ? 'secondary' : undefined}
|
||||
role="radio"
|
||||
event={{ id: name, value: String(o.value) }}
|
||||
tabIndex={isSelected ? 0 : -1}
|
||||
className={classNames(
|
||||
isActive && '!text-text',
|
||||
'!px-1.5 !w-auto',
|
||||
'focus:ring-border-focus',
|
||||
isActive && '!text-text',
|
||||
'!px-1.5 !w-auto',
|
||||
'focus:ring-border-focus',
|
||||
)}
|
||||
key={i}
|
||||
title={o.label}
|
||||
|
||||
@@ -2,7 +2,6 @@ import classNames from 'classnames';
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useOsInfo } from '../../hooks/useOsInfo';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import type { ButtonProps } from './Button';
|
||||
import { Button } from './Button';
|
||||
import { Label } from './Label';
|
||||
@@ -22,7 +21,6 @@ export interface SelectProps<T extends string> {
|
||||
onChange: (value: T) => void;
|
||||
size?: ButtonProps['size'];
|
||||
className?: string;
|
||||
event?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
@@ -38,7 +36,6 @@ export function Select<T extends string>({
|
||||
leftSlot,
|
||||
onChange,
|
||||
className,
|
||||
event,
|
||||
size = 'md',
|
||||
}: SelectProps<T>) {
|
||||
const osInfo = useOsInfo();
|
||||
@@ -48,9 +45,6 @@ export function Select<T extends string>({
|
||||
|
||||
const handleChange = (value: T) => {
|
||||
onChange?.(value);
|
||||
if (event != null) {
|
||||
trackEvent('select', 'click', { id: event, value });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
import { memo, useEffect, useRef } from 'react';
|
||||
import { trackEvent } from '../../../lib/analytics';
|
||||
import { Icon } from '../Icon';
|
||||
import type { RadioDropdownProps } from '../RadioDropdown';
|
||||
import { RadioDropdown } from '../RadioDropdown';
|
||||
@@ -104,14 +103,7 @@ export function Tabs({
|
||||
onChange={t.options.onChange}
|
||||
>
|
||||
<button
|
||||
onClick={
|
||||
isActive
|
||||
? undefined
|
||||
: () => {
|
||||
trackEvent('tab', 'click', { label, tab: t.value });
|
||||
onChangeValue(t.value);
|
||||
}
|
||||
}
|
||||
onClick={isActive ? undefined : () => onChangeValue(t.value)}
|
||||
className={btnClassName}
|
||||
>
|
||||
{option && 'shortLabel' in option && option.shortLabel
|
||||
@@ -133,14 +125,7 @@ export function Tabs({
|
||||
return (
|
||||
<button
|
||||
key={t.value}
|
||||
onClick={
|
||||
isActive
|
||||
? undefined
|
||||
: () => {
|
||||
trackEvent('tab', 'click', { label, tab: t.value });
|
||||
onChangeValue(t.value);
|
||||
}
|
||||
}
|
||||
onClick={isActive ? undefined : () => onChangeValue(t.value)}
|
||||
className={btnClassName}
|
||||
>
|
||||
{t.label}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useMemo } from 'react';
|
||||
import { useFloatingSidebarHidden } from '../../hooks/useFloatingSidebarHidden';
|
||||
import { useShouldFloatSidebar } from '../../hooks/useShouldFloatSidebar';
|
||||
import { useSidebarHidden } from '../../hooks/useSidebarHidden';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import { IconButton } from '../core/IconButton';
|
||||
import { HStack } from '../core/Stacks';
|
||||
import { CreateDropdown } from '../CreateDropdown';
|
||||
@@ -22,8 +21,6 @@ export function SidebarActions() {
|
||||
<HStack className="h-full">
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
trackEvent('sidebar', 'toggle');
|
||||
|
||||
// NOTE: We're not using the (h) => !h pattern here because the data
|
||||
// might be different if another window changed it (out of sync)
|
||||
await setHidden(!hidden);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { event } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export function useCancelHttpResponse(id: string | null) {
|
||||
return useFastMutation<void>({
|
||||
mutationKey: ['cancel_http_response', id],
|
||||
mutationFn: () => event.emit(`cancel_http_response_${id}`),
|
||||
onSettled: () => trackEvent('http_response', 'cancel'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { CookieJar } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showPrompt } from '../lib/prompt';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||
@@ -25,6 +24,5 @@ export function useCreateCookieJar() {
|
||||
|
||||
return invokeCmd('cmd_create_cookie_jar', { workspaceId, name });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'create'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Environment } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showPrompt } from '../lib/prompt';
|
||||
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -33,7 +32,6 @@ export function useCreateEnvironment() {
|
||||
environmentId: baseEnvironment.id,
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('environment', 'create'),
|
||||
onSuccess: async (environment) => {
|
||||
if (environment == null) return;
|
||||
setWorkspaceSearchParams({ environment_id: environment.id });
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveRequest } from './useActiveRequest';
|
||||
@@ -36,7 +35,6 @@ export function useCreateGrpcRequest() {
|
||||
...patch,
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
await router.navigate({
|
||||
to: '/workspaces/$workspaceId',
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveRequest } from './useActiveRequest';
|
||||
@@ -30,7 +29,6 @@ export function useCreateHttpRequest() {
|
||||
request: { workspaceId, ...patch },
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
await router.navigate({
|
||||
to: '/workspaces/$workspaceId',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Workspace } from '@yaakapp-internal/models';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { router } from '../lib/router';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -24,7 +23,6 @@ export function useDeleteActiveWorkspace() {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_workspace', { workspaceId: workspace?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('workspace', 'delete'),
|
||||
onSuccess: async (workspace) => {
|
||||
if (workspace === null) return;
|
||||
await router.navigate({ to: '/workspaces' });
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -24,6 +23,5 @@ export function useDeleteAnyGrpcRequest() {
|
||||
}
|
||||
return invokeCmd('cmd_delete_grpc_request', { requestId: request.id });
|
||||
},
|
||||
onSuccess: () => trackEvent('grpc_request', 'delete'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { resolvedModelName } from '../lib/resolvedModelName';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -24,6 +23,5 @@ export function useDeleteAnyHttpRequest() {
|
||||
}
|
||||
return invokeCmd<HttpRequest>('cmd_delete_http_request', { requestId: request.id });
|
||||
},
|
||||
onSuccess: () => trackEvent('http_request', 'delete'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { CookieJar } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { cookieJarsAtom } from './useCookieJars';
|
||||
@@ -26,7 +25,6 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'delete'),
|
||||
onSuccess: (cookieJar) => {
|
||||
if (cookieJar == null) return;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Environment } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { environmentsAtom } from './useEnvironments';
|
||||
@@ -26,7 +25,6 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('environment', 'delete'),
|
||||
onSuccess: (environment) => {
|
||||
if (environment == null) return;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Folder } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
@@ -27,7 +26,6 @@ export function useDeleteFolder(id: string | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_folder', { folderId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'delete'),
|
||||
onSuccess: (folder) => {
|
||||
if (folder == null) return;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { GrpcConnection } from '@yaakapp-internal/models';
|
||||
import {useSetAtom} from "jotai";
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import {grpcConnectionsAtom} from "./useGrpcConnections";
|
||||
import {removeModelById} from "./useSyncModelStores";
|
||||
@@ -13,7 +12,6 @@ export function useDeleteGrpcConnection(id: string | null) {
|
||||
mutationFn: async () => {
|
||||
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_connection', 'delete'),
|
||||
onSuccess: (connection) => {
|
||||
if (connection == null) return;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcConnectionsAtom } from './useGrpcConnections';
|
||||
|
||||
@@ -12,7 +11,6 @@ export function useDeleteGrpcConnections(requestId?: string) {
|
||||
if (requestId === undefined) return;
|
||||
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
|
||||
onSuccess: () => {
|
||||
setGrpcConnections((all) => all.filter((r) => r.requestId !== requestId));
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import {useSetAtom} from "jotai";
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import {httpResponsesAtom} from "./useHttpResponses";
|
||||
import {removeModelById} from "./useSyncModelStores";
|
||||
@@ -13,7 +12,6 @@ export function useDeleteHttpResponse(id: string | null) {
|
||||
mutationFn: async () => {
|
||||
return await invokeCmd('cmd_delete_http_response', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_response', 'delete'),
|
||||
onSuccess: (response) => {
|
||||
setHttpResponses(removeModelById(response));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpResponsesAtom } from './useHttpResponses';
|
||||
|
||||
@@ -15,6 +14,5 @@ export function useDeleteHttpResponses(requestId?: string) {
|
||||
onSuccess: () => {
|
||||
setHttpResponses((all) => all.filter((r) => r.requestId !== requestId));
|
||||
},
|
||||
onSettled: () => trackEvent('http_response', 'delete_many'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useDuplicateFolder(id: string) {
|
||||
return useFastMutation<void, string>({
|
||||
mutationKey: ['duplicate_folder', id],
|
||||
mutationFn: () => invokeCmd('cmd_duplicate_folder', { id }),
|
||||
onSettled: () => trackEvent('folder', 'duplicate'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
@@ -18,7 +17,6 @@ export function useDuplicateGrpcRequest({
|
||||
if (id === null) throw new Error("Can't duplicate a null grpc request");
|
||||
return invokeCmd('cmd_duplicate_grpc_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
if (id == null) return;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { router } from '../lib/router';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
@@ -17,7 +16,6 @@ export function useDuplicateHttpRequest({
|
||||
if (id === null) throw new Error("Can't duplicate a null request");
|
||||
return invokeCmd('cmd_duplicate_http_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
if (navigateAfter) {
|
||||
await router.navigate({
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { MutationKey } from '@tanstack/react-query';
|
||||
import { useMemo } from 'react';
|
||||
import { showToast } from '../lib/toast';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
interface MutationOptions<TData, TError, TVariables> {
|
||||
mutationKey: MutationKey;
|
||||
@@ -36,7 +35,6 @@ export function createFastMutation<TData = unknown, TError = unknown, TVariables
|
||||
const stringKey = mutationKey.join('.');
|
||||
const e = err as TError;
|
||||
console.log('mutation error', stringKey, e);
|
||||
trackEvent('mutation', 'error', { key: stringKey });
|
||||
if (!disableToastError) {
|
||||
showToast({
|
||||
id: stringKey,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import type { GrpcConnection, GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
@@ -24,26 +23,22 @@ export function useGrpc(
|
||||
mutationKey: ['grpc_go', conn?.id],
|
||||
mutationFn: () =>
|
||||
invokeCmd<void>('cmd_grpc_go', { requestId, environmentId: environment?.id, protoFiles }),
|
||||
onSettled: () => trackEvent('grpc_request', 'send'),
|
||||
});
|
||||
|
||||
const send = useMutation({
|
||||
mutationKey: ['grpc_send', conn?.id],
|
||||
mutationFn: ({ message }: { message: string }) =>
|
||||
emit(`grpc_client_msg_${conn?.id ?? 'none'}`, { Message: message }),
|
||||
onSettled: () => trackEvent('grpc_connection', 'send'),
|
||||
});
|
||||
|
||||
const cancel = useMutation({
|
||||
mutationKey: ['grpc_cancel', conn?.id ?? 'n/a'],
|
||||
mutationFn: () => emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Cancel'),
|
||||
onSettled: () => trackEvent('grpc_connection', 'cancel'),
|
||||
});
|
||||
|
||||
const commit = useMutation({
|
||||
mutationKey: ['grpc_commit', conn?.id ?? 'n/a'],
|
||||
mutationFn: () => emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Commit'),
|
||||
onSettled: () => trackEvent('grpc_connection', 'commit'),
|
||||
});
|
||||
|
||||
const debouncedUrl = useDebouncedValue<string>(req?.url ?? '', 1000);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useInstallPlugin() {
|
||||
@@ -8,6 +7,5 @@ export function useInstallPlugin() {
|
||||
mutationFn: async (directory: string) => {
|
||||
await invokeCmd('cmd_install_plugin', { directory });
|
||||
},
|
||||
onSettled: () => trackEvent('plugin', 'create'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { getActiveCookieJar } from './useActiveCookieJar';
|
||||
import { getActiveEnvironment } from './useActiveEnvironment';
|
||||
@@ -21,6 +20,5 @@ export function useSendAnyHttpRequest() {
|
||||
cookieJarId: getActiveCookieJar()?.id,
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'send'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { Plugin } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useUninstallPlugin(pluginId: string) {
|
||||
@@ -9,6 +8,5 @@ export function useUninstallPlugin(pluginId: string) {
|
||||
mutationFn: async () => {
|
||||
return invokeCmd('cmd_uninstall_plugin', { pluginId });
|
||||
},
|
||||
onSettled: () => trackEvent('plugin', 'delete'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { AnalyticsAction, AnalyticsResource } from '../../src-tauri/bindings/analytics';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export function trackEvent(
|
||||
resource: AnalyticsResource,
|
||||
action: AnalyticsAction,
|
||||
attributes: Record<string, string | number> = {},
|
||||
) {
|
||||
invokeCmd('cmd_track_event', {
|
||||
resource: resource,
|
||||
action,
|
||||
attributes,
|
||||
}).catch(console.error);
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import { atom } from 'jotai/index';
|
||||
import type { DialogInstance } from '../components/Dialogs';
|
||||
import { trackEvent } from './analytics';
|
||||
import { jotaiStore } from './jotai';
|
||||
|
||||
export const dialogsAtom = atom<DialogInstance[]>([]);
|
||||
|
||||
export function showDialog({ id, ...props }: DialogInstance) {
|
||||
trackEvent('dialog', 'show', { id });
|
||||
jotaiStore.set(dialogsAtom, (a) => [...a.filter((d) => d.id !== id), { id, ...props }]);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ type TauriCmd =
|
||||
| 'cmd_set_update_mode'
|
||||
| 'cmd_template_functions'
|
||||
| 'cmd_template_tokens_to_string'
|
||||
| 'cmd_track_event'
|
||||
| 'cmd_uninstall_plugin'
|
||||
| 'cmd_update_cookie_jar'
|
||||
| 'cmd_update_environment'
|
||||
|
||||
Reference in New Issue
Block a user