Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions apps/desktop/src-tauri/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ pub struct AuthStore {
pub user_id: Option<String>,
pub plan: Option<Plan>,
pub intercom_hash: Option<String>,
#[serde(default)]
pub organizations: Vec<Organization>,
}

#[derive(Serialize, Deserialize, Type, Debug, Clone)]
pub struct Organization {
pub id: String,
pub name: String,
#[serde(rename = "ownerId")]
pub owner_id: String,
}

#[derive(Serialize, Deserialize, Type, Debug)]
Expand Down Expand Up @@ -97,6 +107,31 @@ impl AuthStore {
});
auth.intercom_hash = Some(plan_response.intercom_hash.unwrap_or_default());

// Fetch organizations
println!("Fetching organizations for user");
match app
.authed_api_request("/api/desktop/organizations", |client, url| client.get(url))
.await
{
Ok(response) if response.status().is_success() => {
match response.json::<Vec<Organization>>().await {
Ok(orgs) => {
println!("Fetched {} organizations", orgs.len());
auth.organizations = orgs;
}
Err(e) => {
println!("Failed to parse organizations: {e}");
}
}
}
Err(e) => {
println!("Failed to fetch organizations: {e}");
}
Ok(response) => {
println!("Failed to fetch organizations: status {}", response.status());
}
}

Self::set(app, Some(auth))?;

Ok(())
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/deeplink_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ impl DeepLinkAction {
capture_target,
capture_system_audio,
mode,
organization_id: None,
};

crate::recording::start_recording(app.clone(), state, inputs)
Expand Down
43 changes: 40 additions & 3 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ use tauri_specta::Event;
#[cfg(target_os = "macos")]
use tokio::sync::Mutex;
use tokio::sync::{RwLock, oneshot};
use tracing::{error, trace, warn};
use tracing::{error, info, trace, warn};
use upload::{create_or_get_video, upload_image, upload_video};
use web_api::AuthedApiError;
use web_api::ManagerExt as WebManagerExt;
Expand Down Expand Up @@ -1063,6 +1063,7 @@ async fn upload_exported_video(
path: PathBuf,
mode: UploadMode,
channel: Channel<UploadProgress>,
organization_id: Option<String>,
) -> Result<UploadResult, String> {
let Ok(Some(auth)) = AuthStore::get(&app) else {
AuthStore::set(&app, None).map_err(|e| e.to_string())?;
Expand Down Expand Up @@ -1109,6 +1110,7 @@ async fn upload_exported_video(
video_id,
Some(meta.pretty_name.clone()),
Some(metadata.clone()),
organization_id,
)
.await
}
Expand Down Expand Up @@ -1631,6 +1633,7 @@ async fn check_upgraded_and_update(app: AppHandle) -> Result<bool, String> {
manual: auth.plan.map(|p| p.manual).unwrap_or(false),
last_checked: chrono::Utc::now().timestamp() as i32,
}),
organizations: auth.organizations,
};
println!("Updating auth store with new pro status");
AuthStore::set(&app, Some(updated_auth)).map_err(|e| e.to_string())?;
Expand Down Expand Up @@ -1886,6 +1889,13 @@ async fn update_auth_plan(app: AppHandle) {
AuthStore::update_auth_plan(&app).await.ok();
}

#[tauri::command]
#[specta::specta]
async fn refresh_organizations(app: AppHandle) -> Result<(), String> {
info!("Manually refreshing organizations");
AuthStore::update_auth_plan(&app).await
}

pub type FilteredRegistry = tracing_subscriber::layer::Layered<
tracing_subscriber::filter::FilterFn<fn(m: &tracing::Metadata) -> bool>,
tracing_subscriber::Registry,
Expand Down Expand Up @@ -1962,12 +1972,14 @@ pub async fn run(recording_logging_handle: LoggingHandle) {
windows::position_traffic_lights,
windows::set_theme,
global_message_dialog,
log_message,
show_window,
write_clipboard_string,
platform::perform_haptic_feedback,
list_fails,
set_fail,
update_auth_plan,
refresh_organizations,
set_window_transparent,
get_editor_meta,
set_pretty_name,
Expand Down Expand Up @@ -2062,8 +2074,8 @@ pub async fn run(recording_logging_handle: LoggingHandle) {
tauri::async_runtime::set(tokio::runtime::Handle::current());

#[allow(unused_mut)]
let mut builder =
tauri::Builder::default().plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
let mut builder = tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
trace!("Single instance invoked with args {args:?}");

// This is also handled as a deeplink on some platforms (eg macOS), see deeplink_actions
Expand Down Expand Up @@ -2172,6 +2184,19 @@ pub async fn run(recording_logging_handle: LoggingHandle) {
..Default::default()
}));
});

// Fetch organizations if missing (for existing users)
if auth.organizations.is_empty() {
info!("User is logged in but organizations not cached, fetching...");
let app_clone = app.clone();
tokio::spawn(async move {
if let Err(e) = AuthStore::update_auth_plan(&app_clone).await {
error!("Failed to fetch organizations on startup: {}", e);
} else {
info!("Organizations fetched successfully on startup");
}
});
}
}

tokio::spawn({
Expand Down Expand Up @@ -2274,6 +2299,7 @@ pub async fn run(recording_logging_handle: LoggingHandle) {
}),
capture_system_audio: settings.system_audio,
mode: event.mode,
organization_id: settings.organization_id,
},
)
.await;
Expand Down Expand Up @@ -2651,6 +2677,17 @@ fn global_message_dialog(app: AppHandle, message: String) {
app.dialog().message(message).show(|_| {});
}

#[tauri::command]
#[specta::specta]
fn log_message(level: String, message: String) {
match level.as_str() {
"info" => info!("{}", message),
"warn" => warn!("{}", message),
"error" => error!("{}", message),
_ => trace!("{}", message),
}
}

#[tauri::command]
#[specta::specta]
async fn write_clipboard_string(
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ pub struct StartRecordingInputs {
#[serde(default)]
pub capture_system_audio: bool,
pub mode: RecordingMode,
#[serde(default)]
pub organization_id: Option<String>,
}

#[derive(tauri_specta::Event, specta::Type, Clone, Debug, serde::Serialize)]
Expand Down Expand Up @@ -313,6 +315,7 @@ pub async fn start_recording(
chrono::Local::now().format("%Y-%m-%d %H:%M:%S")
)),
None,
inputs.organization_id.clone(),
)
.await
{
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/recording_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct RecordingSettingsStore {
pub camera_id: Option<DeviceOrModelID>,
pub mode: Option<RecordingMode>,
pub system_audio: bool,
pub organization_id: Option<String>,
}

impl RecordingSettingsStore {
Expand Down
7 changes: 6 additions & 1 deletion apps/desktop/src-tauri/src/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ pub async fn upload_image(
.ok_or("Invalid file path")?
.to_string();

let s3_config = create_or_get_video(app, true, None, None, None).await?;
let s3_config = create_or_get_video(app, true, None, None, None, None).await?;

let (stream, total_size) = file_reader_stream(file_path).await?;
singlepart_uploader(
Expand Down Expand Up @@ -223,6 +223,7 @@ pub async fn create_or_get_video(
video_id: Option<String>,
name: Option<String>,
meta: Option<S3VideoMeta>,
organization_id: Option<String>,
) -> Result<S3UploadMeta, AuthedApiError> {
let mut s3_config_url = if let Some(id) = video_id {
format!("/api/desktop/video/create?recordingMode=desktopMP4&videoId={id}")
Expand All @@ -245,6 +246,10 @@ pub async fn create_or_get_video(
}
}

if let Some(org_id) = organization_id {
s3_config_url.push_str(&format!("&orgId={}", org_id));
}

let response = app
.authed_api_request(s3_config_url, |client, url| client.get(url))
.await?;
Expand Down
9 changes: 7 additions & 2 deletions apps/desktop/src-tauri/src/upload_legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub async fn upload_video(
let client = reqwest::Client::new();
let s3_config = match existing_config {
Some(config) => config,
None => create_or_get_video(app, false, Some(video_id.clone()), None, meta).await?,
None => create_or_get_video(app, false, Some(video_id.clone()), None, meta, None).await?,
};

let presigned_put = presigned_s3_put(
Expand Down Expand Up @@ -331,7 +331,7 @@ pub async fn upload_image(app: &AppHandle, file_path: PathBuf) -> Result<Uploade
.to_string();

let client = reqwest::Client::new();
let s3_config = create_or_get_video(app, true, None, None, None).await?;
let s3_config = create_or_get_video(app, true, None, None, None, None).await?;

let presigned_put = presigned_s3_put(
app,
Expand Down Expand Up @@ -385,6 +385,7 @@ pub async fn create_or_get_video(
video_id: Option<String>,
name: Option<String>,
meta: Option<S3VideoMeta>,
organization_id: Option<String>,
) -> Result<S3UploadMeta, String> {
let mut s3_config_url = if let Some(id) = video_id {
format!("/api/desktop/video/create?recordingMode=desktopMP4&videoId={id}")
Expand All @@ -407,6 +408,10 @@ pub async fn create_or_get_video(
}
}

if let Some(org_id) = organization_id {
s3_config_url.push_str(&format!("&orgId={}", org_id));
}

let response = app
.authed_api_request(s3_config_url, |client, url| client.get(url))
.await
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ function Page() {
currentWindow.setSize(new LogicalSize(size.width, size.height));
});

// Refresh organizations when main window loads
try {
await commands.refreshOrganizations();
} catch {}

onCleanup(async () => {
(await unlistenFocus)?.();
(await unlistenResize)?.();
Expand Down
Loading
Loading