mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-30 01:17:37 +03:00
refactor project menu
This commit is contained in:
parent
43a3a8b71e
commit
8e0b0a6bad
@ -4,7 +4,7 @@ use anyhow::Context;
|
||||
use tauri::{generate_context, Manager};
|
||||
|
||||
use gblib::{
|
||||
analytics, app, assets, commands, database, deltas, github, keys, logs, projects, sentry,
|
||||
analytics, app, assets, commands, database, deltas, github, keys, logs, menu, projects, sentry,
|
||||
sessions, storage, users, virtual_branches, watcher, zip,
|
||||
};
|
||||
|
||||
@ -27,13 +27,7 @@ fn main() {
|
||||
let tray_menu = tauri::SystemTrayMenu::new().add_item(hide).add_item(quit);
|
||||
let tray = tauri::SystemTray::new().with_menu(tray_menu);
|
||||
|
||||
let project_settings = tauri::CustomMenuItem::new("projectsettings".to_string(), "Project Settings");
|
||||
let project_submenu = tauri::Submenu::new("Project", tauri::Menu::new().add_item(project_settings.disabled()));
|
||||
let menu = tauri::Menu::os_default(&app_title)
|
||||
.add_submenu(project_submenu);
|
||||
|
||||
tauri::Builder::default()
|
||||
.menu(menu)
|
||||
.system_tray(tray)
|
||||
.on_system_tray_event(|app_handle, event| {
|
||||
if let tauri::SystemTrayEvent::MenuItemClick { id, .. } = event {
|
||||
@ -68,11 +62,6 @@ fn main() {
|
||||
api.prevent_close();
|
||||
}
|
||||
})
|
||||
.on_menu_event(move |event| {
|
||||
if event.menu_item_id() == "projectsettings" {
|
||||
_ = event.window().emit("menuAction", Some("projectSettings"));
|
||||
}
|
||||
})
|
||||
.setup(move |tauri_app| {
|
||||
let window =
|
||||
create_window(&tauri_app.handle()).expect("Failed to create window");
|
||||
@ -168,8 +157,6 @@ fn main() {
|
||||
users::commands::set_user,
|
||||
users::commands::delete_user,
|
||||
users::commands::get_user,
|
||||
users::commands::get_current_project,
|
||||
users::commands::set_current_project,
|
||||
projects::commands::add_project,
|
||||
projects::commands::get_project,
|
||||
projects::commands::update_project,
|
||||
@ -199,10 +186,13 @@ fn main() {
|
||||
virtual_branches::commands::amend_virtual_branch,
|
||||
virtual_branches::commands::list_remote_branches,
|
||||
virtual_branches::commands::squash_branch_commit,
|
||||
menu::menu_item_set_enabled,
|
||||
keys::commands::get_public_key,
|
||||
github::commands::init_device_oauth,
|
||||
github::commands::check_auth_status,
|
||||
])
|
||||
.menu(menu::build(tauri_context.package_info()))
|
||||
.on_menu_event(|event|menu::handle_event(&event))
|
||||
.build(tauri_context)
|
||||
.expect("Failed to build tauri app")
|
||||
.run(|app_handle, event| match event {
|
||||
|
@ -12,11 +12,13 @@ pub enum Code {
|
||||
ProjectGitRemote,
|
||||
ProjectConflict,
|
||||
ProjectHead,
|
||||
Menu,
|
||||
}
|
||||
|
||||
impl fmt::Display for Code {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Code::Menu => write!(f, "errors.menu"),
|
||||
Code::Unknown => write!(f, "errors.unknown"),
|
||||
Code::Validation => write!(f, "errors.validation"),
|
||||
Code::Projects => write!(f, "errors.projects"),
|
||||
|
@ -17,6 +17,7 @@ pub mod id;
|
||||
pub mod keys;
|
||||
pub mod lock;
|
||||
pub mod logs;
|
||||
pub mod menu;
|
||||
pub mod paths;
|
||||
pub mod project_repository;
|
||||
pub mod projects;
|
||||
|
58
packages/tauri/src/menu.rs
Normal file
58
packages/tauri/src/menu.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use serde_json::json;
|
||||
use tauri::{
|
||||
AppHandle, CustomMenuItem, Manager, Menu, MenuEntry, PackageInfo, Runtime, Submenu,
|
||||
WindowMenuEvent,
|
||||
};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::error::{Code, Error};
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[instrument(skip(handle))]
|
||||
pub async fn menu_item_set_enabled(
|
||||
handle: AppHandle,
|
||||
menu_item_id: &str,
|
||||
enabled: bool,
|
||||
) -> Result<(), Error> {
|
||||
let window = handle
|
||||
.get_window("main")
|
||||
.expect("main window always present");
|
||||
let menu_item = window
|
||||
.menu_handle()
|
||||
.try_get_item(menu_item_id)
|
||||
.ok_or_else(|| Error::UserError {
|
||||
message: format!("menu item not found: {}", menu_item_id),
|
||||
code: Code::Menu,
|
||||
})?;
|
||||
menu_item.set_enabled(enabled).map_err(|error| {
|
||||
tracing::error!(error = ?error, "failed to set menu item enabled state");
|
||||
Error::Unknown
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build(package_info: &PackageInfo) -> Menu {
|
||||
Menu::os_default(&package_info.name).add_submenu(Submenu::new(
|
||||
"Project",
|
||||
Menu::with_items([disabled_menu_item("project/settings", "Project Settings")]),
|
||||
))
|
||||
}
|
||||
|
||||
fn disabled_menu_item(id: &str, title: &str) -> MenuEntry {
|
||||
let mut item = CustomMenuItem::new(id, title);
|
||||
item.enabled = false;
|
||||
item.into()
|
||||
}
|
||||
|
||||
pub fn handle_event<R: Runtime>(event: &WindowMenuEvent<R>) {
|
||||
emit(
|
||||
event.window(),
|
||||
format!("menu://{}/clicked", event.menu_item_id()).as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
fn emit<R: Runtime>(window: &tauri::Window<R>, event: &str) {
|
||||
if let Err(err) = window.emit(event, json!({})) {
|
||||
tracing::error!(error = ?err, "failed to emit event");
|
||||
}
|
||||
}
|
@ -55,48 +55,6 @@ pub async fn set_user(handle: AppHandle, user: User) -> Result<User, Error> {
|
||||
Ok(proxy.proxy_user(user).await)
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[instrument(skip(handle))]
|
||||
pub async fn set_current_project(
|
||||
handle: tauri::AppHandle,
|
||||
project_id: Option<&str>,
|
||||
) -> Result<(), Error> {
|
||||
let app = handle.state::<Controller>();
|
||||
if let Some(user) = app.get_user()? {
|
||||
let mut user = user;
|
||||
match project_id {
|
||||
Some(project_id) => {
|
||||
user.current_project = Some(project_id.to_string());
|
||||
}
|
||||
None => {
|
||||
user.current_project = None;
|
||||
}
|
||||
}
|
||||
app.set_user(&user)?;
|
||||
if let Some(win) = handle.get_window("main") {
|
||||
let menu_handle = win.menu_handle();
|
||||
if let Some(project_settings) = menu_handle.try_get_item("projectsettings") {
|
||||
_ = project_settings.set_enabled(project_id.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: persist this not on the user object
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[instrument(skip(handle))]
|
||||
pub async fn get_current_project(handle: tauri::AppHandle) -> Result<Option<String>, Error> {
|
||||
let app = handle.state::<Controller>();
|
||||
match app.get_user()? {
|
||||
Some(user) => Ok(user.current_project),
|
||||
None => Err({
|
||||
tracing::error!("failed to get user");
|
||||
Error::Unknown
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
impl From<controller::DeleteError> for Error {
|
||||
fn from(value: controller::DeleteError) -> Self {
|
||||
match value {
|
||||
|
@ -17,8 +17,6 @@ pub struct User {
|
||||
pub github_access_token: Option<String>,
|
||||
#[serde(default)]
|
||||
pub github_username: Option<String>,
|
||||
#[serde(default)]
|
||||
pub current_project: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<User> for git::Signature<'_> {
|
||||
|
@ -2,8 +2,6 @@ import { handleErrorWithSentry, init } from '@sentry/sveltekit';
|
||||
import type { NavigationEvent } from '@sveltejs/kit';
|
||||
import { dev } from '$app/environment';
|
||||
import { PUBLIC_SENTRY_ENVIRONMENT } from '$env/static/public';
|
||||
import { goto } from '$app/navigation';
|
||||
import { getCurrentProject } from '$lib/backend/users';
|
||||
|
||||
init({
|
||||
enabled: !dev,
|
||||
@ -30,10 +28,3 @@ window.onunhandledrejection = (event: PromiseRejectionEvent) => {
|
||||
console.log('Unhandled exception', event.reason);
|
||||
originalUnhandledHandler?.bind(window)(event);
|
||||
};
|
||||
|
||||
// getCurrentProject().then((projectId) => {
|
||||
// // Start on the last used project
|
||||
// if (projectId) {
|
||||
// goto(`/${projectId}/base`);
|
||||
// }
|
||||
// });
|
||||
|
@ -9,13 +9,5 @@ export async function set(params: { user: User }) {
|
||||
return invoke<User>('set_user', params);
|
||||
}
|
||||
|
||||
export async function setCurrentProject(params: { projectId: string | undefined }) {
|
||||
return invoke<void>('set_current_project', params);
|
||||
}
|
||||
|
||||
export async function getCurrentProject() {
|
||||
return invoke<string | undefined>('get_current_project');
|
||||
}
|
||||
|
||||
const del = () => invoke<void>('delete_user');
|
||||
export { del as delete };
|
||||
|
19
packages/ui/src/lib/menu.ts
Normal file
19
packages/ui/src/lib/menu.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { emit } from '$lib/utils/events';
|
||||
import { invoke, listen as listenIpc } from '$lib/backend/ipc';
|
||||
|
||||
export function subscribe(projectId: string) {
|
||||
invoke('menu_item_set_enabled', {
|
||||
menuItemId: 'project/settings',
|
||||
enabled: true
|
||||
});
|
||||
const unsubscribeProjectSettings = listenIpc<string>('menu://project/settings/clicked', () => {
|
||||
emit('goto', `/${projectId}/settings/`);
|
||||
});
|
||||
return () => {
|
||||
unsubscribeProjectSettings();
|
||||
invoke('menu_item_set_enabled', {
|
||||
menuItemId: 'project/settings',
|
||||
enabled: false
|
||||
});
|
||||
};
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
import { SETTINGS_CONTEXT, loadUserSettings } from '$lib/settings/userSettings';
|
||||
import { initTheme } from './user/theme';
|
||||
import { navigating } from '$app/stores';
|
||||
import { setCurrentProject } from '$lib/backend/users';
|
||||
import { subscribe as menuSubscribe } from '$lib/menu';
|
||||
|
||||
export let data: LayoutData;
|
||||
const { projectService, cloud, user$ } = data;
|
||||
@ -31,10 +31,17 @@
|
||||
$: zoom = $userSettings.zoom || 1;
|
||||
$: document.documentElement.style.fontSize = zoom + 'rem';
|
||||
$: userSettings.update((s) => ({ ...s, zoom: zoom }));
|
||||
|
||||
// listen for current project events
|
||||
let unsubscribeMenu = () => {};
|
||||
$: if ($navigating) {
|
||||
// Keeps the backend aware of what is the current project
|
||||
let projectId = $navigating?.to?.params?.projectId;
|
||||
setCurrentProject({ projectId });
|
||||
const fromProject = $navigating?.from?.params?.projectId;
|
||||
const toProject = $navigating?.to?.params?.projectId;
|
||||
const projectHasChanged = fromProject !== toProject;
|
||||
if (projectHasChanged && toProject) {
|
||||
unsubscribeMenu?.();
|
||||
unsubscribeMenu = menuSubscribe(toProject);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() =>
|
||||
|
Loading…
Reference in New Issue
Block a user