From f3ef6535d1e77e96eaae425cacf5207c6d714a32 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Mon, 27 May 2024 22:37:32 +0200 Subject: [PATCH] Navigate seed nodes from explore section --- src/components/Popover.svelte | 6 +- src/lib/seeds.ts | 84 ++----- src/views/home/Index.svelte | 56 ++--- .../home/components/HomepageSection.svelte | 9 +- .../components/PreferredSeedDropdown.svelte | 208 +++++++++++++----- src/views/home/router.ts | 31 ++- tests/e2e/landingPage.spec.ts | 80 ++++++- tests/support/fixtures.ts | 45 ++++ 8 files changed, 355 insertions(+), 164 deletions(-) diff --git a/src/components/Popover.svelte b/src/components/Popover.svelte index 984e95633b..b306ddeb1c 100644 --- a/src/components/Popover.svelte +++ b/src/components/Popover.svelte @@ -8,6 +8,7 @@ - + title="Switch preferred seeds" + let:toggle> +
{selectedSeed.hostname}
+ + + + -
- {#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}> + + + { + selectPreferredSeed(config.fallbackPreferredSeed); + closeFocused(); + }} + slot="empty" + selected> + + + + {/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 6776e6659c..9319e94af6 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 56bebcd19e..1b9210dcfb 100644 --- a/tests/e2e/landingPage.spec.ts +++ b/tests/e2e/landingPage.spec.ts @@ -1,4 +1,4 @@ -import { expect, test } from "@tests/support/fixtures.js"; +import { expect, nodeInfo, test } from "@tests/support/fixtures.js"; test("show pinned projects", async ({ page }) => { await page.addInitScript(() => localStorage.setItem("experimental", "true")); @@ -13,3 +13,81 @@ 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(); +}); diff --git a/tests/support/fixtures.ts b/tests/support/fixtures.ts index 8a3d6fb6c6..85dd499233 100644 --- a/tests/support/fixtures.ts +++ b/tests/support/fixtures.ts @@ -633,3 +633,48 @@ export const gitOptions = { GIT_COMMITTER_DATE: "1671627600", }, }; +export 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", +};