Skip to content
Merged
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
4 changes: 4 additions & 0 deletions docs/buzz-help.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ that agent in Buzz; they do not notify the external app through this connection.
before allowing a fresh participation invitation; failed checks keep the original.
If the original invitation was applied and the person was later removed, Retry
clears the old row without re-adding them. Use **Add** in People to invite them again.
- **Open links in your browser**: on desktop, ⌘-click (Ctrl-click on Windows
and Linux) an HTTP(S) link in a message to open it in your default browser
instead of a side panel. You can also right-click the link and choose
**Open in browser**.
- **Sidebar width**: drag the sidebar's right edge, or focus its resize handle
and use the Left/Right arrow keys. Double-click the handle to reset the width.
Messages and plugin pages share the saved width within the same community
Expand Down
71 changes: 71 additions & 0 deletions src/features/conversation/MessageLink.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { LinkThreadTabContext } from "./LinkLabelContext";
afterEach(() => {
cleanup();
vi.restoreAllMocks();
vi.unstubAllGlobals();
});

const entry: Contribution<LinkRenderer> = {
Expand Down Expand Up @@ -289,6 +290,76 @@ it("preserves ordinary pane interception and modified or middle-click fallback",
expect(onOpenLink).not.toHaveBeenCalled();
});

function desktopOpener() {
const invoke = vi.fn().mockResolvedValue(undefined);
vi.stubGlobal("isTauri", true);
vi.stubGlobal("__TAURI_INTERNALS__", { invoke });
return invoke;
}

it.each([
"https://github.com/block/buzz-app/pull/1?view=all#discussion_r1",
"http://example.com/path?query=yes#section",
])(
"opens desktop Command-click in the browser with the exact URL: %s",
(target) => {
const invoke = desktopOpener();
const { anchor, onOpenLink } = mount(target);
const event = new MouseEvent("click", {
bubbles: true,
cancelable: true,
metaKey: true,
});
fireEvent(anchor, event);
expect(event.defaultPrevented).toBe(true);
expect(invoke).toHaveBeenCalledExactlyOnceWith(
"plugin:opener|open_url",
{
url: target,
},
undefined,
);
expect(onOpenLink).not.toHaveBeenCalled();
},
);

it("keeps ordinary desktop clicks in the pane", () => {
const invoke = desktopOpener();
const { anchor, onOpenLink } = mount();
fireEvent.click(anchor);
expect(onOpenLink).toHaveBeenCalledExactlyOnceWith(url);
expect(invoke).not.toHaveBeenCalled();
});

it("reports a failed desktop browser open and clears the error on retry", async () => {
const invoke = desktopOpener();
invoke.mockRejectedValueOnce("Browser unavailable");
const { anchor, onOpenLink } = mount();
fireEvent.click(anchor, { metaKey: true });
expect(
await screen.findByText("Couldn’t open the link in your browser."),
).toBeInTheDocument();
fireEvent.click(anchor, { metaKey: true });
expect(
screen.queryByText("Couldn’t open the link in your browser."),
).not.toBeInTheDocument();
expect(invoke).toHaveBeenCalledTimes(2);
expect(onOpenLink).not.toHaveBeenCalled();
});

it("does not open a desktop browser from an inactive conversation", () => {
const invoke = desktopOpener();
const onOpenLink = vi.fn(() => true);
render(
<ConversationPresentation value={false}>
<MessageLink url={url} registry={undefined} onOpenLink={onOpenLink} />
</ConversationPresentation>,
);
fireEvent.click(screen.getByRole("link"), { metaKey: true });
expect(invoke).not.toHaveBeenCalled();
expect(onOpenLink).not.toHaveBeenCalled();
});

it("retires an external menu when its retained conversation becomes inactive", async () => {
const onOpenLink = vi.fn(() => true);
const tree = (active: boolean) => (
Expand Down
13 changes: 13 additions & 0 deletions src/features/conversation/MessageLink.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { invoke, isTauri } from "@tauri-apps/api/core";
import { useConversationPresentation } from "./ConversationPresentation";
import {
useContext,
Expand Down Expand Up @@ -226,6 +227,18 @@ export function MessageLink({
openInternal();
return;
}
// Tauri's automatic external-link opener skips Command-clicks.
if (external && event.metaKey && event.button === 0 && isTauri()) {
event.preventDefault();
setNotice(undefined);
void invoke("plugin:opener|open_url", { url }).catch(() => {
setNotice({
text: "Couldn’t open the link in your browser.",
error: true,
});
});
return;
}
if (
!event.metaKey &&
!event.ctrlKey &&
Expand Down
Loading