From 0668542d0043163f64049e6aad89a35ebac214af Mon Sep 17 00:00:00 2001 From: Will Gordon Date: Thu, 30 Apr 2026 13:21:16 -0400 Subject: [PATCH] fix(jira): restores domain dropdown for self-hosted Jira support Reverts the removal of the domain selector dropdown from f1b26bc. Users can now choose between atlassian.net (default) and a custom domain for self-hosted Jira instances. isSafeJiraSiteUrl relaxed to allow any HTTPS domain with a valid hostname. --- src/app/components/settings/SettingsPage.tsx | 58 +++++++++++++++----- src/app/lib/url.ts | 4 +- tests/lib/url.test.ts | 16 ++++-- 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/app/components/settings/SettingsPage.tsx b/src/app/components/settings/SettingsPage.tsx index 32a3e8fb..bc3087a2 100644 --- a/src/app/components/settings/SettingsPage.tsx +++ b/src/app/components/settings/SettingsPage.tsx @@ -221,13 +221,16 @@ export default function SettingsPage() { const [jiraApiEmail, setJiraApiEmail] = createSignal(""); const [jiraApiToken, setJiraApiToken] = createSignal(""); const [jiraApiSubdomain, setJiraApiSubdomain] = createSignal(""); + const [jiraApiDomain, setJiraApiDomain] = createSignal("atlassian.net"); + const [jiraApiCustomUrl, setJiraApiCustomUrl] = createSignal(""); const [jiraApiConnecting, setJiraApiConnecting] = createSignal(false); const [jiraApiError, setJiraApiError] = createSignal(null); const [jiraApiMode, setJiraApiMode] = createSignal(false); const jiraApiSiteUrl = () => { + if (jiraApiDomain() === "custom") return jiraApiCustomUrl().trim().replace(/\/$/, ""); const sub = jiraApiSubdomain().trim(); - return sub ? `https://${sub}.atlassian.net` : ""; + return sub ? `https://${sub}.${jiraApiDomain()}` : ""; }; function handleJiraOAuthConnect() { @@ -244,7 +247,9 @@ export default function SettingsPage() { const token = jiraApiToken().trim(); const siteUrl = jiraApiSiteUrl(); if (!email || !token || !siteUrl) { - setJiraApiError("Email, API token, and site name are all required."); + setJiraApiError(jiraApiDomain() === "custom" + ? "Email, API token, and site URL are all required." + : "Email, API token, and site name are all required."); return; } setJiraApiConnecting(true); @@ -299,6 +304,8 @@ export default function SettingsPage() { setJiraApiEmail(""); setJiraApiToken(""); setJiraApiSubdomain(""); + setJiraApiDomain("atlassian.net"); + setJiraApiCustomUrl(""); setJiraApiMode(false); } catch (err) { const msg = err instanceof Error ? err.message : "Unknown error"; @@ -917,16 +924,41 @@ export default function SettingsPage() { aria-label="Atlassian API token" />
- https:// - setJiraApiSubdomain(e.currentTarget.value)} - class="input input-sm w-32" - aria-label="Jira site name" - /> - .atlassian.net + + https:// + + setJiraApiCustomUrl(e.currentTarget.value)} + class="input input-sm flex-1" + aria-label="Jira site URL" + /> + } + > + setJiraApiSubdomain(e.currentTarget.value)} + class="input input-sm w-32" + aria-label="Jira site name" + /> + . + +

{jiraApiError()}

@@ -942,7 +974,7 @@ export default function SettingsPage() {