Skip to content

Commit f3ace06

Browse files
committed
app: Open link for connected organizations in Zulip desktop
Fixes: #1219 Two new IPC messages are introduced to implement this feature: 1. `"update-org-urls": (urls: string[]) => void` in `MainMessage` stores the list of urls for connected organizations. 2. `"navigate-to-org-url": (url: string) => void` in `RenderMessage` that opens the corresponding tab if the url points to a connected organization. If not, this is a no-op. Uses the list of urls from above to determine whether a url belongs to a connected organization.
1 parent 7da12ba commit f3ace06

File tree

5 files changed

+50
-0
lines changed

5 files changed

+50
-0
lines changed

app/common/typed-ipc.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type MainMessage = {
2323
"update-badge": (messageCount: number) => void;
2424
"update-menu": (properties: MenuProperties) => void;
2525
"update-taskbar-icon": (data: string, text: string) => void;
26+
"update-org-urls": (urls: string[]) => void;
2627
};
2728

2829
export type MainCall = {
@@ -78,6 +79,7 @@ export type RendererMessage = {
7879
"update-realm-icon": (serverURL: string, iconURL: string) => void;
7980
"update-realm-name": (serverURL: string, realmName: string) => void;
8081
"webview-reload": () => void;
82+
"navigate-to-org-url": (url: string) => void;
8183
zoomActualSize: () => void;
8284
zoomIn: () => void;
8385
zoomOut: () => void;

app/main/handle-external-link.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as ConfigUtil from "../common/config-util.ts";
1313
import * as LinkUtil from "../common/link-util.ts";
1414
import * as t from "../common/translation-util.ts";
1515

16+
import {isConfiguredOrgUrl} from "./org-url-cache.ts";
1617
import {send} from "./typed-ipc-main.ts";
1718

1819
function isUploadsUrl(server: string, url: URL): boolean {
@@ -159,6 +160,9 @@ export default function handleExternalLink(
159160
}
160161
},
161162
});
163+
} else if (isConfiguredOrgUrl(url)) {
164+
// URL belongs to a configured organization - navigate there in-app
165+
send(mainContents, "navigate-to-org-url", url.href);
162166
} else {
163167
(async () => LinkUtil.openBrowser(url))();
164168
}

app/main/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {appUpdater, shouldQuitForUpdate} from "./autoupdater.ts";
2727
import * as BadgeSettings from "./badge-settings.ts";
2828
import handleExternalLink from "./handle-external-link.ts";
2929
import * as AppMenu from "./menu.ts";
30+
import {updateOrgUrls} from "./org-url-cache.ts";
3031
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request.ts";
3132
import {sentryInit} from "./sentry.ts";
3233
import {setAutoLaunch} from "./startup.ts";
@@ -456,6 +457,10 @@ function createMainWindow(): BrowserWindow {
456457
ConfigUtil.setConfigItem("lastActiveTab", index);
457458
});
458459

460+
ipcMain.on("update-org-urls", (_event, urls: string[]) => {
461+
updateOrgUrls(urls);
462+
});
463+
459464
ipcMain.on("focus-this-webview", (event) => {
460465
send(page, "focus-webview-with-id", event.sender.id);
461466
mainWindow.show();

app/main/org-url-cache.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Cache of configured organization origins for cross-org link handling
2+
// This is updated by the renderer process when orgs change
3+
4+
let cachedOrgOrigins: string[] = [];
5+
6+
export function updateOrgUrls(urls: string[]): void {
7+
cachedOrgOrigins = urls.map((url) => new URL(url).origin);
8+
}
9+
10+
export function isConfiguredOrgUrl(url: URL): boolean {
11+
return cachedOrgOrigins.includes(url.origin);
12+
}

app/renderer/js/main.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ export class ServerManagerView {
328328

329329
async initTabs(): Promise<void> {
330330
const servers = DomainUtil.getDomains();
331+
// Sync org URLs to main process for cross-org link handling
332+
this.syncOrgUrlsToMain();
331333
if (servers.length > 0) {
332334
for (const [i, server] of servers.entries()) {
333335
const tab = this.initServer(server, i);
@@ -489,6 +491,12 @@ export class ServerManagerView {
489491
return currentIndex;
490492
}
491493

494+
// Sync configured org URLs to main process for cross-org link handling
495+
syncOrgUrlsToMain(): void {
496+
const urls = DomainUtil.getDomains().map((server) => server.url);
497+
ipcRenderer.send("update-org-urls", urls);
498+
}
499+
492500
async getCurrentActiveServer(): Promise<string> {
493501
const tab = this.tabs[this.activeTabIndex];
494502
return tab instanceof ServerTab ? (await tab.webview).properties.url : "";
@@ -1009,6 +1017,25 @@ export class ServerManagerView {
10091017
await this.activateLastTab(index);
10101018
});
10111019

1020+
ipcRenderer.on("navigate-to-org-url", async (event, urlString: string) => {
1021+
// Handle cross-organization link navigation, no-op if the url doesn't
1022+
// point to a connected organization.
1023+
const url = new URL(urlString);
1024+
const servers = DomainUtil.getDomains();
1025+
const orgIndex = servers.findIndex(
1026+
(s) => new URL(s.url).origin === url.origin,
1027+
);
1028+
1029+
if (orgIndex !== -1) {
1030+
await this.activateTab(orgIndex);
1031+
const tab = this.tabs[orgIndex];
1032+
if (tab instanceof ServerTab) {
1033+
const webview = await tab.webview;
1034+
await webview.getWebContents().loadURL(urlString);
1035+
}
1036+
}
1037+
});
1038+
10121039
ipcRenderer.on("open-org-tab", async () => {
10131040
await this.openSettings("AddServer");
10141041
});

0 commit comments

Comments
 (0)