mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-25 10:18:31 +02:00
Rust analytics and a few tweaks
This commit is contained in:
75
src-tauri/src/analytics.rs
Normal file
75
src-tauri/src/analytics.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use sqlx::types::JsonValue;
|
||||||
|
|
||||||
|
use crate::is_dev;
|
||||||
|
|
||||||
|
pub enum AnalyticsResource {
|
||||||
|
App,
|
||||||
|
// Workspace,
|
||||||
|
// Environment,
|
||||||
|
// Folder,
|
||||||
|
// HttpRequest,
|
||||||
|
// HttpResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AnalyticsAction {
|
||||||
|
Launch,
|
||||||
|
// Create,
|
||||||
|
// Update,
|
||||||
|
// Upsert,
|
||||||
|
// Delete,
|
||||||
|
// Send,
|
||||||
|
// Duplicate,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resource_name(resource: AnalyticsResource) -> &'static str {
|
||||||
|
match resource {
|
||||||
|
AnalyticsResource::App => "app",
|
||||||
|
// AnalyticsResource::Workspace => "workspace",
|
||||||
|
// AnalyticsResource::Environment => "environment",
|
||||||
|
// AnalyticsResource::Folder => "folder",
|
||||||
|
// AnalyticsResource::HttpRequest => "http_request",
|
||||||
|
// AnalyticsResource::HttpResponse => "http_response",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action_name(action: AnalyticsAction) -> &'static str {
|
||||||
|
match action {
|
||||||
|
AnalyticsAction::Launch => "launch",
|
||||||
|
// AnalyticsAction::Create => "create",
|
||||||
|
// AnalyticsAction::Update => "update",
|
||||||
|
// AnalyticsAction::Upsert => "upsert",
|
||||||
|
// AnalyticsAction::Delete => "delete",
|
||||||
|
// AnalyticsAction::Send => "send",
|
||||||
|
// AnalyticsAction::Duplicate => "duplicate",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn track_event(
|
||||||
|
resource: AnalyticsResource,
|
||||||
|
action: AnalyticsAction,
|
||||||
|
attributes: Option<JsonValue>,
|
||||||
|
) {
|
||||||
|
let event = format!("{}.{}", resource_name(resource), action_name(action));
|
||||||
|
let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string();
|
||||||
|
let params = vec![
|
||||||
|
("e", event.clone()),
|
||||||
|
("a", attributes_json.clone()),
|
||||||
|
("id", "site_zOK0d7jeBy2TLxFCnZ".to_string()),
|
||||||
|
];
|
||||||
|
let url = format!("https://t.yaak.app/t/e");
|
||||||
|
let req = reqwest::Client::builder()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.get(&url)
|
||||||
|
.query(¶ms);
|
||||||
|
|
||||||
|
if is_dev() {
|
||||||
|
println!("Ignore dev analytics event: {}", event);
|
||||||
|
} else {
|
||||||
|
if let Err(e) = req.send().await {
|
||||||
|
println!("Error sending analytics event: {}", e);
|
||||||
|
} else {
|
||||||
|
println!("Sent analytics event: {}", event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,9 @@ use tokio::sync::Mutex;
|
|||||||
|
|
||||||
use window_ext::TrafficLightWindowExt;
|
use window_ext::TrafficLightWindowExt;
|
||||||
|
|
||||||
|
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||||
|
|
||||||
|
mod analytics;
|
||||||
mod models;
|
mod models;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod render;
|
mod render;
|
||||||
@@ -92,7 +95,7 @@ async fn actually_send_request(
|
|||||||
let environment_ref = environment.as_ref();
|
let environment_ref = environment.as_ref();
|
||||||
let workspace = models::get_workspace(&request.workspace_id, pool)
|
let workspace = models::get_workspace(&request.workspace_id, pool)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get workspace");
|
.expect("Failed to get Workspace");
|
||||||
|
|
||||||
let mut url_string = render::render(&request.url, &workspace, environment.as_ref());
|
let mut url_string = render::render(&request.url, &workspace, environment.as_ref());
|
||||||
|
|
||||||
@@ -363,7 +366,7 @@ async fn create_workspace(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create workspace");
|
.expect("Failed to create Workspace");
|
||||||
|
|
||||||
emit_and_return(&window, "created_model", created_workspace)
|
emit_and_return(&window, "created_model", created_workspace)
|
||||||
}
|
}
|
||||||
@@ -684,7 +687,7 @@ async fn list_workspaces(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create workspace");
|
.expect("Failed to create Workspace");
|
||||||
Ok(vec![workspace])
|
Ok(vec![workspace])
|
||||||
} else {
|
} else {
|
||||||
Ok(workspaces)
|
Ok(workspaces)
|
||||||
@@ -706,7 +709,7 @@ async fn delete_workspace(
|
|||||||
let pool = &*db_instance.lock().await;
|
let pool = &*db_instance.lock().await;
|
||||||
let workspace = models::delete_workspace(workspace_id, pool)
|
let workspace = models::delete_workspace(workspace_id, pool)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to delete workspace");
|
.expect("Failed to delete Workspace");
|
||||||
emit_and_return(&window, "deleted_model", workspace)
|
emit_and_return(&window, "deleted_model", workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,6 +816,11 @@ fn main() {
|
|||||||
let w = create_window(app_handle, None);
|
let w = create_window(app_handle, None);
|
||||||
w.restore_state(StateFlags::all())
|
w.restore_state(StateFlags::all())
|
||||||
.expect("Failed to restore window state");
|
.expect("Failed to restore window state");
|
||||||
|
|
||||||
|
tauri::async_runtime::block_on(async move {
|
||||||
|
analytics::track_event(AnalyticsResource::App, AnalyticsAction::Launch, None)
|
||||||
|
.await;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitRequested { api, .. } => {
|
// ExitRequested { api, .. } => {
|
||||||
|
|||||||
@@ -659,7 +659,7 @@ pub async fn upsert_workspace(
|
|||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
get_workspace(&workspace.id, pool).await
|
get_workspace(&id, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_response(
|
pub async fn update_response(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useFolders } from '../hooks/useFolders';
|
|||||||
import { useKeyValue } from '../hooks/useKeyValue';
|
import { useKeyValue } from '../hooks/useKeyValue';
|
||||||
import { useLatestResponse } from '../hooks/useLatestResponse';
|
import { useLatestResponse } from '../hooks/useLatestResponse';
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
|
import { usePrompt } from '../hooks/usePrompt';
|
||||||
import { useRequests } from '../hooks/useRequests';
|
import { useRequests } from '../hooks/useRequests';
|
||||||
import { useSendAnyRequest } from '../hooks/useSendAnyRequest';
|
import { useSendAnyRequest } from '../hooks/useSendAnyRequest';
|
||||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||||
@@ -28,6 +29,7 @@ import { isResponseLoading } from '../lib/models';
|
|||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
import { StatusTag } from './core/StatusTag';
|
import { StatusTag } from './core/StatusTag';
|
||||||
import { DropMarker } from './DropMarker';
|
import { DropMarker } from './DropMarker';
|
||||||
@@ -493,6 +495,8 @@ const SidebarItem = forwardRef(function SidebarItem(
|
|||||||
const deleteRequest = useDeleteFolder(itemId);
|
const deleteRequest = useDeleteFolder(itemId);
|
||||||
const latestResponse = useLatestResponse(itemId);
|
const latestResponse = useLatestResponse(itemId);
|
||||||
const updateRequest = useUpdateRequest(itemId);
|
const updateRequest = useUpdateRequest(itemId);
|
||||||
|
const updateAnyFolder = useUpdateAnyFolder();
|
||||||
|
const prompt = usePrompt();
|
||||||
const [editing, setEditing] = useState<boolean>(false);
|
const [editing, setEditing] = useState<boolean>(false);
|
||||||
const activeRequestId = useActiveRequestId();
|
const activeRequestId = useActiveRequestId();
|
||||||
const isActive = activeRequestId === itemId;
|
const isActive = activeRequestId === itemId;
|
||||||
@@ -562,6 +566,25 @@ const SidebarItem = forwardRef(function SidebarItem(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ type: 'separator', label: itemName },
|
{ type: 'separator', label: itemName },
|
||||||
|
{
|
||||||
|
key: 'rename',
|
||||||
|
label: 'Rename',
|
||||||
|
leftSlot: <Icon icon="pencil" />,
|
||||||
|
onSelect: async () => {
|
||||||
|
const name = await prompt({
|
||||||
|
title: 'Rename Folder',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
Enter a new name for <InlineCode>{itemName}</InlineCode>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
name: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
defaultValue: itemName,
|
||||||
|
});
|
||||||
|
updateAnyFolder.mutate({ id: itemId, update: (f) => ({ ...f, name }) });
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'deleteFolder',
|
key: 'deleteFolder',
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ import {
|
|||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { graphql, graphqlLanguageSupport } from 'cm6-graphql';
|
import { graphql, graphqlLanguageSupport } from 'cm6-graphql';
|
||||||
|
import type { Environment, Workspace } from '../../../lib/models';
|
||||||
import type { EditorProps } from './index';
|
import type { EditorProps } from './index';
|
||||||
import { text } from './text/extension';
|
import { text } from './text/extension';
|
||||||
import { twig } from './twig/extension';
|
import { twig } from './twig/extension';
|
||||||
import { url } from './url/extension';
|
import { url } from './url/extension';
|
||||||
import type { Environment, Workspace } from '../../../lib/models';
|
|
||||||
|
|
||||||
export const myHighlightStyle = HighlightStyle.define([
|
export const myHighlightStyle = HighlightStyle.define([
|
||||||
{
|
{
|
||||||
@@ -125,7 +125,6 @@ export const baseExtensions = [
|
|||||||
// autocompletion({ closeOnBlur: true, interactionDelay: 200, activateOnTyping: false }),
|
// autocompletion({ closeOnBlur: true, interactionDelay: 200, activateOnTyping: false }),
|
||||||
autocompletion({
|
autocompletion({
|
||||||
// closeOnBlur: false,
|
// closeOnBlur: false,
|
||||||
interactionDelay: 200,
|
|
||||||
compareCompletions: (a, b) => {
|
compareCompletions: (a, b) => {
|
||||||
// Don't sort completions at all, only on boost
|
// Don't sort completions at all, only on boost
|
||||||
return (a.boost ?? 0) - (b.boost ?? 0);
|
return (a.boost ?? 0) - (b.boost ?? 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user