diff --git a/httpd-client/index.ts b/httpd-client/index.ts index 804cf5c4b..77ce6811c 100644 --- a/httpd-client/index.ts +++ b/httpd-client/index.ts @@ -115,6 +115,28 @@ export class HttpdClient { this.session = new session.Client(this.#fetcher); } + public changePort(port: number): void { + this.#baseUrl.port = port; + } + + public get url(): string { + return `${this.#baseUrl.scheme}://${this.#baseUrl.hostname}:${ + this.#baseUrl.port + }`; + } + + public get hostnamePort(): string { + return `${this.#baseUrl.hostname}:${this.#baseUrl.port}`; + } + + public get hostname(): string { + return this.#baseUrl.hostname; + } + + public get port(): string { + return this.#baseUrl.port.toString(); + } + public async getNodeInfo(options?: RequestOptions): Promise { return this.#fetcher.fetchOk( { diff --git a/src/App/Header/Connect.svelte b/src/App/Header/Connect.svelte index a0af0aa41..5c52415f7 100644 --- a/src/App/Header/Connect.svelte +++ b/src/App/Header/Connect.svelte @@ -1,8 +1,9 @@ + + + +
+ Port +
+ httpd.changeHttpdPort(Number(port))} /> +
+
diff --git a/src/App/Header/Search.svelte b/src/App/Header/Search.svelte index fbb065abf..d96d4180f 100644 --- a/src/App/Header/Search.svelte +++ b/src/App/Header/Search.svelte @@ -123,13 +123,9 @@ {loading} disabled={loading} bind:value={input} - on:focus={() => { - expanded = true; - }} + on:focus={() => (expanded = true)} on:blur={() => { - if (input === "") { - expanded = false; - } + if (input === "") expanded = false; }} on:submit={search} placeholder={searchPlaceholder}> diff --git a/src/components/TextInput.svelte b/src/components/TextInput.svelte index f6d525872..ab16dabc8 100644 --- a/src/components/TextInput.svelte +++ b/src/components/TextInput.svelte @@ -1,14 +1,17 @@ -
+
{#if $$slots.left} @@ -145,6 +178,8 @@ -
+
{#if $$slots.right} {/if} @@ -173,8 +212,12 @@ {/if} - {#if valid && !loading} -
⏎
+ {#if valid && !loading && isFocused} + {#if success} + + {:else} +
⏎
+ {/if} {/if}
diff --git a/src/lib/httpd.ts b/src/lib/httpd.ts index 5699b596a..9cd4453d9 100644 --- a/src/lib/httpd.ts +++ b/src/lib/httpd.ts @@ -17,11 +17,12 @@ export type HttpdState = }; const HTTPD_STATE_STORAGE_KEY = "httpdState"; +const HTTPD_CUSTOM_PORT_KEY = "httpdCustomPort"; const store = writable({ state: "stopped" }); export const httpdStore = derived(store, s => s); -const api = new HttpdClient({ +export const api = new HttpdClient({ hostname: "127.0.0.1", port: 8080, scheme: "http", @@ -29,6 +30,11 @@ const api = new HttpdClient({ let pollHttpdStateHandle: number | undefined = undefined; +export function changeHttpdPort(port: number) { + window.localStorage.setItem(HTTPD_CUSTOM_PORT_KEY, String(port)); + void checkState(); +} + function update(state: HttpdState) { window.localStorage.setItem(HTTPD_STATE_STORAGE_KEY, JSON.stringify(state)); store.set(state); @@ -89,6 +95,10 @@ export async function disconnect() { async function checkState() { let httpdState: HttpdState | null = null; const rawHttpdState = window.localStorage.getItem(HTTPD_STATE_STORAGE_KEY); + const customHttpdPort = window.localStorage.getItem(HTTPD_CUSTOM_PORT_KEY); + if (customHttpdPort) { + api.changePort(Number(customHttpdPort)); + } if (rawHttpdState) { try { httpdState = JSON.parse(rawHttpdState); @@ -140,8 +150,9 @@ export function initialize() { // Sync session state changes with other open tabs and windows. addEventListener("storage", event => { if ( - event.key === HTTPD_STATE_STORAGE_KEY && - event.oldValue !== event.newValue + (event.key === HTTPD_STATE_STORAGE_KEY && + event.oldValue !== event.newValue) || + (event.key === HTTPD_CUSTOM_PORT_KEY && event.oldValue !== event.newValue) ) { void checkState(); } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index f4566a928..ce1cfd72f 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -255,10 +255,11 @@ export function extractBaseUrl(hostnamePort: string): BaseUrl { ) { return { hostname: "127.0.0.1", port: 8080, scheme: "http" }; } else if (hostnamePort.includes(":")) { + const [hostname, port] = hostnamePort.split(":"); return { - hostname: hostnamePort.split(":")[0], - port: Number(hostnamePort.split(":")[1]), - scheme: config.seeds.defaultHttpdScheme, + hostname, + port: Number(port), + scheme: isLocal(hostname) ? "http" : config.seeds.defaultHttpdScheme, }; } else { return { diff --git a/src/views/projects/View.svelte b/src/views/projects/View.svelte index 95a7706bd..caee4fbd5 100644 --- a/src/views/projects/View.svelte +++ b/src/views/projects/View.svelte @@ -4,6 +4,7 @@ import type { Project } from "@httpd-client"; import type { ProjectLoadedView } from "@app/views/projects/router"; + import * as httpd from "@app/lib/httpd"; import * as router from "@app/lib/router"; import * as utils from "@app/lib/utils"; import { HttpdClient } from "@httpd-client"; @@ -49,8 +50,8 @@ void router.push({ resource: "projects", params: { - id: id, - hostnamePort: baseUrl.hostname, + id, + hostnamePort: httpd.api.hostnamePort, view: { resource: "issue", params: { issue: issueId }, diff --git a/src/views/session/Index.svelte b/src/views/session/Index.svelte index 841b5efff..94f873d71 100644 --- a/src/views/session/Index.svelte +++ b/src/views/session/Index.svelte @@ -20,7 +20,7 @@ modal.show({ component: AuthenticatedModal, props: {} }); void router.push({ resource: "seeds", - params: { hostnamePort: "radicle.local", projectPageIndex: 0 }, + params: { hostnamePort: httpd.api.hostnamePort, projectPageIndex: 0 }, }); } else { modal.show({ diff --git a/tests/e2e/hotkeys.spec.ts b/tests/e2e/hotkeys.spec.ts index 68024ba9b..9a3aa7d40 100644 --- a/tests/e2e/hotkeys.spec.ts +++ b/tests/e2e/hotkeys.spec.ts @@ -29,7 +29,7 @@ test("global hotkeys", async ({ page }) => { await expect(page.getByPlaceholder(searchPlaceholder)).toHaveValue( "searchquery?", ); - await expect(page.getByText("⏎")).toBeVisible(); + await expect(page.getByText("⏎")).toBeHidden(); await expect(page.getByPlaceholder(searchPlaceholder)).not.toBeFocused(); } }); diff --git a/tests/e2e/httpd.spec.ts b/tests/e2e/httpd.spec.ts new file mode 100644 index 000000000..ae3c066cb --- /dev/null +++ b/tests/e2e/httpd.spec.ts @@ -0,0 +1,29 @@ +import { test, expect } from "@tests/support/fixtures.js"; + +test("change httpd port", async ({ page, peerManager }) => { + const peer = await peerManager.startPeer({ name: "httpd" }); + + await peer.startHttpd(8070); + await peer.startNode(); + + await page.goto("/"); + await page.getByRole("button", { name: "radicle.local" }).click(); + + await page.locator('input[name="port"]').fill("8070"); + await page.locator('input[name="port"]').press("Enter"); + + const { stdout } = await peer.rad([ + "web", + "--frontend", + "http://localhost:3000", + "--backend", + "http://127.0.0.1:8070", + ]); + const match = stdout.trim().match(/(http:\/\/localhost:3000\/.*)$/); + if (!match) { + throw Error("Not able to parse auth url"); + } + await page.goto(match[0]); + await expect(page.getByText("Authenticated")).toBeVisible(); + await expect(page).toHaveURL("/seeds/127.0.0.1:8070"); +});