- {#if stateOptions}
-
- {
- selectPreferredSeed(item);
- closeFocused();
- }}
- slot="item"
- selected={item.hostname === preferredSeed.hostname}>
-
-
- {item.hostname}
-
-
-
+
+ {
+ submittingInput = true;
+ const customSeedBaseUrl = {
+ hostname: customSeed,
+ port: config.nodes.defaultHttpdPort,
+ scheme: config.nodes.defaultHttpdScheme,
+ };
+ valid = await validateInput(customSeedBaseUrl);
+ if (valid) {
+ addSeedsToConfiguredSeeds(
+ $configuredPreferredSeeds.length === 0
+ ? [customSeedBaseUrl, config.fallbackPreferredSeed]
+ : [customSeedBaseUrl],
+ );
+ selectPreferredSeed(customSeedBaseUrl);
+ customSeed = "";
+ closeFocused();
+ } else {
+ submittingInput = false;
+ }
+ }} />
+ {#if validationMessage}
+ {validationMessage}
{/if}
-
-
-
-
Add a different seed node
-
- Update preferred seeds in your Radicle config and restart httpd.
+
+
+ {#if stateOptions}
+
+ {
+ selectPreferredSeed(item);
+ closeFocused();
+ }}
+ slot="item"
+ selected={item.hostname === selectedSeed.hostname}>
+
+
+
+
+ {item.hostname}
+
+
+ {#if stateOptions && stateOptions.length > 1}
+
{
+ removeSeedFromConfiguredSeeds(item.hostname);
+ selectPreferredSeed(config.fallbackPreferredSeed);
+ }}>
+
+
+ {/if}
+
+
+ {
+ selectPreferredSeed(config.fallbackPreferredSeed);
+ closeFocused();
+ }}
+ slot="empty"
+ selected>
+
+
+
+
+ {config.fallbackPreferredSeed.hostname}
+
+
+
+
+
+ {/if}
-
+ {#if $httpdStore.state !== "stopped" && !initialPreferredSeeds.find(s => s.hostname === selectedSeed.hostname)}
+
+
+
Store in config
+
+ Add
+ {selectedSeed.hostname}
+
+ to your
+ preferredSeeds
+ in your Radicle config and restart httpd.
+
+
+
+ {/if}
diff --git a/src/views/home/router.ts b/src/views/home/router.ts
index 6776e6659..9319e94af 100644
--- a/src/views/home/router.ts
+++ b/src/views/home/router.ts
@@ -1,6 +1,10 @@
+import type { BaseUrl } from "@httpd-client";
import type { ErrorRoute } from "@app/lib/router/definitions";
import * as seeds from "@app/lib/seeds";
+import config from "virtual:config";
+import { api, httpdStore } from "@app/lib/httpd";
+import { get } from "svelte/store";
export interface HomeRoute {
resource: "home";
@@ -8,15 +12,34 @@ export interface HomeRoute {
export interface HomeLoadedRoute {
resource: "home";
- params: Record
;
+ params: { configPreferredSeeds: BaseUrl[] };
}
export async function loadHomeRoute(): Promise {
- seeds.initialize();
- await seeds.waitForLoad();
+ if (get(httpdStore).state !== "stopped") {
+ const profile = await api.profile.getProfile();
+ const newValue = profile.config.preferredSeeds.map(seed => {
+ const preferredSeedValue = seed?.split("@")[1];
+ const preferredSeedOrigin = preferredSeedValue?.split(":")[0];
+
+ return {
+ hostname: preferredSeedOrigin,
+ port: config.nodes.defaultHttpdPort,
+ scheme: config.nodes.defaultHttpdScheme,
+ };
+ });
+ if (get(seeds.configuredPreferredSeeds).length === 0) {
+ seeds.addSeedsToConfiguredSeeds(newValue);
+ }
+
+ return {
+ resource: "home",
+ params: { configPreferredSeeds: newValue },
+ };
+ }
return {
resource: "home",
- params: {},
+ params: { configPreferredSeeds: [] },
};
}
diff --git a/tests/e2e/landingPage.spec.ts b/tests/e2e/landingPage.spec.ts
index 56bebcd19..00d702a66 100644
--- a/tests/e2e/landingPage.spec.ts
+++ b/tests/e2e/landingPage.spec.ts
@@ -13,3 +13,127 @@ test("show pinned projects", async ({ page }) => {
page.getByText("Git repository for source browsing tests"),
).toBeVisible();
});
+
+test("no duplicate entry for preferred seeds", async ({ page }) => {
+ await page.goto("/");
+ await expect(page.getByText("seed.radicle.garden")).toBeVisible();
+
+ await page.getByTitle("Switch preferred seeds").getByRole("button").click();
+ await expect(
+ page.getByRole("button", { name: "seed.radicle.garden" }),
+ ).toBeVisible();
+
+ await page
+ .getByPlaceholder("Navigate to seed URL")
+ .fill("seed.radicle.garden");
+ await page.getByPlaceholder("Navigate to seed URL").press("Enter");
+ await expect(page.getByText("Seed node already added.")).toBeVisible();
+
+ await page.getByPlaceholder("Navigate to seed URL").fill("");
+ await expect(page.getByText("Seed node already added.")).toBeHidden();
+});
+
+test("adding and removing a new preferred seed", async ({ page }) => {
+ await page.route(
+ ({ hostname }) => hostname === "seed.rhizoma.dev",
+ route => route.fulfill({ json: nodeInfo }),
+ );
+
+ await page.goto("/");
+ await expect(page.getByText("seed.radicle.garden")).toBeVisible();
+
+ await page.getByTitle("Switch preferred seeds").getByRole("button").click();
+ await expect(
+ page.getByRole("button", { name: "seed.radicle.garden" }),
+ ).toBeVisible();
+
+ await page.getByPlaceholder("Navigate to seed URL").fill("seed.rhizoma.dev");
+ await page.getByPlaceholder("Navigate to seed URL").press("Enter");
+ await expect(page.getByText("seed.rhizoma.dev")).toBeVisible();
+
+ await page.getByTitle("Switch preferred seeds").getByRole("button").click();
+ await expect(
+ page.getByRole("button", { name: "seed.rhizoma.dev" }),
+ ).toBeVisible();
+
+ // Test that removing the selected seed doesn't end in an undefined state.
+ await page
+ .getByRole("button", { name: "seed.rhizoma.dev" })
+ .getByRole("button")
+ .click();
+ await expect(page.getByText("seed.radicle.garden")).toBeVisible();
+
+ await page.getByTitle("Switch preferred seeds").getByRole("button").click();
+ await expect(
+ page.getByRole("button", { name: "seed.rhizoma.dev" }),
+ ).toBeHidden();
+});
+
+test("stored custom preferred seeds in local storage", async ({ page }) => {
+ await page.addInitScript(() =>
+ localStorage.setItem(
+ "configuredPreferredSeeds",
+ '[{"hostname":"seed.radicle.xyz","port":443,"scheme":"https"},{"hostname":"seed.rhizoma.dev","port":443,"scheme":"https"}]',
+ ),
+ );
+ await page.goto("/");
+ await expect(page.getByText("seed.radicle.xyz")).toBeVisible();
+
+ await page.getByTitle("Switch preferred seeds").getByRole("button").click();
+ await expect(
+ page.getByRole("button", { name: "seed.radicle.xyz" }),
+ ).toBeVisible();
+ await expect(
+ page.getByRole("button", { name: "seed.rhizoma.dev" }),
+ ).toBeVisible();
+ // Check that the fallback node hasn't been added on load.
+ await expect(
+ page.getByRole("button", { name: "seed.radicle.garden" }),
+ ).toBeHidden();
+});
+
+const nodeInfo = {
+ id: "z6MkkGfMNQmjrp66Po2n4snzcSyTFRFw1m1fbYhCURxLxZpD",
+ version: "1.0.0-rc.9-d56d619f",
+ config: {
+ alias: "rhizoma",
+ listen: [],
+ peers: {
+ type: "dynamic",
+ target: 0,
+ },
+ connect: [],
+ externalAddresses: ["seed.rhizoma.dev:8776"],
+ db: {
+ journalMode: "wal",
+ },
+ network: "main",
+ log: "INFO",
+ relay: "auto",
+ limits: {
+ routingMaxSize: 1000,
+ routingMaxAge: 604800,
+ gossipMaxAge: 1209600,
+ fetchConcurrency: 1,
+ maxOpenFiles: 4096,
+ rate: {
+ inbound: {
+ fillRate: 2,
+ capacity: 128,
+ },
+ outbound: {
+ fillRate: 5,
+ capacity: 256,
+ },
+ },
+ connection: {
+ inbound: 128,
+ outbound: 16,
+ },
+ },
+ workers: 32,
+ policy: "block",
+ scope: "all",
+ },
+ state: "running",
+};