mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
feat: Add quick action to open repository in browser
Add "Open Repository in Browser" to the Quick Actions menu (Cmd+K) for git repositories. Supports GitHub, GitLab, Bitbucket, and other common hosts by parsing SSH and HTTPS remote URLs. Claude ID: ac8e7811-8742-4991-b9ce-9c03629b8288 Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
This commit is contained in:
@@ -220,6 +220,14 @@ export function QuickActionsModal(props: QuickActionsModalProps) {
|
||||
setQuickActionOpen(false);
|
||||
} }] : []),
|
||||
...(activeSession?.isGitRepo ? [{ id: 'gitLog', label: 'View Git Log', shortcut: shortcuts.viewGitLog, action: () => { setGitLogOpen(true); setQuickActionOpen(false); } }] : []),
|
||||
...(activeSession?.isGitRepo ? [{ id: 'openRepo', label: 'Open Repository in Browser', action: async () => {
|
||||
const cwd = activeSession.inputMode === 'terminal' ? (activeSession.shellCwd || activeSession.cwd) : activeSession.cwd;
|
||||
const browserUrl = await gitService.getRemoteBrowserUrl(cwd);
|
||||
if (browserUrl) {
|
||||
window.maestro.shell.openExternal(browserUrl);
|
||||
}
|
||||
setQuickActionOpen(false);
|
||||
} }] : []),
|
||||
{ id: 'devtools', label: 'Toggle JavaScript Console', action: () => { window.maestro.devtools.toggle(); setQuickActionOpen(false); } },
|
||||
{ id: 'about', label: 'About Maestro', action: () => { setAboutModalOpen(true); setQuickActionOpen(false); } },
|
||||
{ id: 'goToFiles', label: 'Go to Files Tab', action: () => { setRightPanelOpen(true); setActiveRightTab('files'); setQuickActionOpen(false); } },
|
||||
|
||||
@@ -22,6 +22,43 @@ export interface GitNumstat {
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a git remote URL to a browser-friendly URL
|
||||
* Supports GitHub, GitLab, Bitbucket, and other common hosts
|
||||
*/
|
||||
function remoteUrlToBrowserUrl(remoteUrl: string): string | null {
|
||||
if (!remoteUrl) return null;
|
||||
|
||||
let url = remoteUrl.trim();
|
||||
|
||||
// Handle SSH format: git@github.com:user/repo.git
|
||||
if (url.startsWith('git@')) {
|
||||
// git@github.com:user/repo.git -> https://github.com/user/repo
|
||||
url = url
|
||||
.replace(/^git@/, 'https://')
|
||||
.replace(/:([^/])/, '/$1') // Replace first : with / (but not :// from https)
|
||||
.replace(/\.git$/, '');
|
||||
return url;
|
||||
}
|
||||
|
||||
// Handle HTTPS format: https://github.com/user/repo.git
|
||||
if (url.startsWith('https://') || url.startsWith('http://')) {
|
||||
url = url.replace(/\.git$/, '');
|
||||
return url;
|
||||
}
|
||||
|
||||
// Handle SSH format without git@: ssh://git@github.com/user/repo.git
|
||||
if (url.startsWith('ssh://')) {
|
||||
url = url
|
||||
.replace(/^ssh:\/\/git@/, 'https://')
|
||||
.replace(/^ssh:\/\//, 'https://')
|
||||
.replace(/\.git$/, '');
|
||||
return url;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const gitService = {
|
||||
/**
|
||||
* Check if a directory is a git repository
|
||||
@@ -115,5 +152,22 @@ export const gitService = {
|
||||
console.error('Git numstat error:', error);
|
||||
return { files: [] };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the browser-friendly URL for the remote repository
|
||||
* Returns null if no remote or URL cannot be parsed
|
||||
*/
|
||||
async getRemoteBrowserUrl(cwd: string): Promise<string | null> {
|
||||
try {
|
||||
const result = await window.maestro.git.remote(cwd);
|
||||
if (result.stdout) {
|
||||
return remoteUrlToBrowserUrl(result.stdout);
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Git remote error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user