Skip to content

Commit 46896bd

Browse files
CopilotByron
andcommitted
Implement Clone Window feature for File menu
Co-authored-by: Byron <[email protected]>
1 parent 1b3fb11 commit 46896bd

File tree

6 files changed

+42
-0
lines changed

6 files changed

+42
-0
lines changed

apps/desktop/src/components/FileMenuAction.svelte

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
}),
2323
shortcutService.on('clone-repo', async () => {
2424
goto(clonePath());
25+
}),
26+
shortcutService.on('clone-window', async () => {
27+
const currentProjectId = await projectsService.getCurrentProjectId();
28+
if (currentProjectId) {
29+
await projectsService.openProjectInNewWindow(currentProjectId);
30+
}
31+
// If no project is available, the menu item will be ignored (as per requirements)
2532
})
2633
)
2734
);

apps/desktop/src/lib/project/projectsService.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ export class ProjectsService {
7373
await this.api.endpoints.openProjectInWindow.mutate({ id: projectId });
7474
}
7575

76+
async getCurrentProjectId(): Promise<string | undefined> {
77+
const result = await this.api.endpoints.getCurrentProjectId.query();
78+
return result || undefined;
79+
}
80+
7681
async relocateProject(projectId: string): Promise<void> {
7782
const path = await this.getValidPath();
7883
if (!path) return;
@@ -177,6 +182,10 @@ function injectEndpoints(api: ClientState['backendApi']) {
177182
openProjectInWindow: build.mutation<void, { id: string }>({
178183
extraOptions: { command: 'open_project_in_window' },
179184
query: (args) => args
185+
}),
186+
getCurrentProjectId: build.query<string | null, void>({
187+
extraOptions: { command: 'get_current_project_id' },
188+
query: () => undefined
180189
})
181190
})
182191
});

crates/gitbutler-tauri/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ fn main() {
230230
projects::list_projects,
231231
projects::set_project_active,
232232
projects::open_project_in_window,
233+
projects::get_current_project_id,
233234
repo::git_get_local_config,
234235
repo::git_set_local_config,
235236
repo::check_signing_settings,

crates/gitbutler-tauri/src/menu.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ pub fn build<R: Runtime>(
7979
.accelerator("CmdOrCtrl+Shift+O")
8080
.build(handle)?,
8181
&PredefinedMenuItem::separator(handle)?,
82+
&MenuItemBuilder::with_id("file/clone-window", "Clone Window")
83+
.accelerator("CmdOrCtrl+Shift+N")
84+
.build(handle)?,
85+
&PredefinedMenuItem::separator(handle)?,
8286
])
8387
.build()?;
8488

@@ -265,6 +269,11 @@ pub fn handle_event<R: Runtime>(
265269
return;
266270
}
267271

272+
if event.id() == "file/clone-window" {
273+
emit(webview, SHORTCUT_EVENT, "clone-window");
274+
return;
275+
}
276+
268277
#[cfg(any(debug_assertions, feature = "devtools"))]
269278
{
270279
if event.id() == "view/devtools" {

crates/gitbutler-tauri/src/projects.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ pub fn open_project_in_window(handle: tauri::AppHandle, id: ProjectId) -> Result
114114
Ok(())
115115
}
116116

117+
/// Get the current project ID for a window, if any.
118+
#[tauri::command]
119+
#[instrument(skip(window_state, window), err(Debug))]
120+
pub fn get_current_project_id(
121+
window_state: State<'_, WindowState>,
122+
window: Window,
123+
) -> Result<Option<ProjectId>, Error> {
124+
Ok(window_state.get_project_for_window(window.label()))
125+
}
126+
117127
#[derive(serde::Deserialize, serde::Serialize)]
118128
pub struct ProjectForFrontend {
119129
#[serde(flatten)]

crates/gitbutler-tauri/src/window.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ pub(crate) mod state {
276276
.map(|state| state.project_id)
277277
.collect()
278278
}
279+
280+
/// Get the current project ID for a specific window, if any.
281+
pub fn get_project_for_window(&self, window: &WindowLabelRef) -> Option<ProjectId> {
282+
let state_by_label = self.state.lock();
283+
state_by_label.get(window).map(|state| state.project_id)
284+
}
279285
}
280286
}
281287

0 commit comments

Comments
 (0)