mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-09-23 00:30:43 -07:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fab9d7a83 |
No files matched your search
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Linux tab of the setup modal — distro selector spec.
|
||||
*
|
||||
* The manual-install accordion offers per-distro instructions via a
|
||||
* SelectDropdown (data-testid="linux-distro-select"). This validates that
|
||||
* switching distros swaps the repository and install commands, that
|
||||
* CLI-only distros render no desktop-app line, and that the copy button
|
||||
* emits commands without comment lines. Runs against /install, which
|
||||
* renders the setup modal without authentication.
|
||||
*/
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
async function openLinuxManualInstall(page: import("@playwright/test").Page) {
|
||||
await page.goto("/install");
|
||||
await page.getByTestId("setup-netbird-modal").waitFor();
|
||||
await page.getByRole("tab", { name: /linux/i }).click();
|
||||
await page.getByText("Install manually with a package manager").click();
|
||||
await page.getByTestId("linux-distro-select").waitFor();
|
||||
}
|
||||
|
||||
async function selectDistro(
|
||||
page: import("@playwright/test").Page,
|
||||
name: string,
|
||||
) {
|
||||
await page.getByTestId("linux-distro-select").click();
|
||||
await page.getByRole("option", { name }).click();
|
||||
}
|
||||
|
||||
test.describe("Setup modal Linux distro instructions", () => {
|
||||
test("defaults to APT with repository, install and run steps", async ({
|
||||
page,
|
||||
}) => {
|
||||
await openLinuxManualInstall(page);
|
||||
|
||||
const modal = page.getByTestId("setup-netbird-modal");
|
||||
await expect(modal.getByTestId("linux-distro-select")).toContainText(
|
||||
"Debian / Ubuntu (APT)",
|
||||
);
|
||||
await expect(modal).toContainText(
|
||||
"https://pkgs.netbird.io/debian stable main",
|
||||
);
|
||||
await expect(modal).toContainText("sudo apt-get install netbird");
|
||||
await expect(modal).toContainText(
|
||||
"sudo apt-get install netbird-ui libgtk-4-1 libwebkitgtk-6.0-4 xdg-utils",
|
||||
);
|
||||
// The run step stays present alongside the distro-specific steps
|
||||
await expect(modal.getByText("netbird up")).toHaveCount(2);
|
||||
});
|
||||
|
||||
test("switches repository and install commands per distro", async ({
|
||||
page,
|
||||
}) => {
|
||||
await openLinuxManualInstall(page);
|
||||
const modal = page.getByTestId("setup-netbird-modal");
|
||||
|
||||
await selectDistro(page, "Fedora (DNF)");
|
||||
await expect(modal).toContainText("/etc/yum.repos.d/netbird.repo");
|
||||
await expect(modal).toContainText("sudo dnf install netbird");
|
||||
await expect(modal).toContainText(
|
||||
"sudo dnf install netbird-ui gtk4 webkitgtk6.0 xdg-utils",
|
||||
);
|
||||
await expect(modal).not.toContainText("apt-get");
|
||||
await expect(modal).not.toContainText("epel-release");
|
||||
|
||||
await selectDistro(page, "RHEL / AlmaLinux / Rocky (DNF)");
|
||||
await expect(modal).toContainText("sudo dnf install epel-release -y");
|
||||
await expect(modal).toContainText(
|
||||
"sudo dnf install netbird-ui gtk4 webkitgtk6.0 xdg-utils",
|
||||
);
|
||||
});
|
||||
|
||||
test("offers CLI only on Amazon Linux", async ({ page }) => {
|
||||
await openLinuxManualInstall(page);
|
||||
const modal = page.getByTestId("setup-netbird-modal");
|
||||
|
||||
await selectDistro(page, "Amazon Linux (YUM)");
|
||||
await expect(modal).toContainText("sudo yum install netbird");
|
||||
await expect(modal).not.toContainText("netbird-ui");
|
||||
await expect(modal).not.toContainText("for CLI only");
|
||||
await expect(modal).toContainText("only the CLI is available");
|
||||
});
|
||||
|
||||
test("copies install commands without comment lines", async ({
|
||||
page,
|
||||
context,
|
||||
}) => {
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await openLinuxManualInstall(page);
|
||||
const modal = page.getByTestId("setup-netbird-modal");
|
||||
|
||||
// Copy buttons in DOM order: install script, run command, repository,
|
||||
// install step, run command (accordion).
|
||||
await modal.getByTestId("copy-to-clipboard").nth(3).click();
|
||||
const copied = await page.evaluate(() => navigator.clipboard.readText());
|
||||
expect(copied, "clipboard should hold runnable commands only").toBe(
|
||||
[
|
||||
"sudo apt-get update",
|
||||
"sudo apt-get install netbird",
|
||||
"sudo apt-get install netbird-ui libgtk-4-1 libwebkitgtk-6.0-4 xdg-utils",
|
||||
].join("\n"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -4,13 +4,14 @@ import {
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@components/Accordion";
|
||||
import { Callout } from "@components/Callout";
|
||||
import Code from "@components/Code";
|
||||
import { SelectDropdown } from "@components/select/SelectDropdown";
|
||||
import Separator from "@components/Separator";
|
||||
import Steps from "@components/Steps";
|
||||
import TabsContentPadding, { TabsContent } from "@components/Tabs";
|
||||
import { IconBrandUbuntu } from "@tabler/icons-react";
|
||||
import { TerminalSquareIcon } from "lucide-react";
|
||||
import React from "react";
|
||||
import { PackageIcon, TerminalSquareIcon } from "lucide-react";
|
||||
import React, { useState } from "react";
|
||||
import { OperatingSystem } from "@/interfaces/OperatingSystem";
|
||||
import {
|
||||
NetBirdUpCommand,
|
||||
@@ -25,6 +26,84 @@ type Props = {
|
||||
hostname?: string;
|
||||
};
|
||||
|
||||
type Distro = {
|
||||
label: string;
|
||||
value: string;
|
||||
/** Commands that register the NetBird package repository. */
|
||||
repository: string[];
|
||||
/** Commands that run before the install lines, after the repository is added. */
|
||||
beforeInstall?: string[];
|
||||
cli: string;
|
||||
/**
|
||||
* Desktop app install lines. Omitted when the distribution cannot run it,
|
||||
* in which case only the CLI is offered.
|
||||
*/
|
||||
desktopApp?: string[];
|
||||
note: string;
|
||||
};
|
||||
|
||||
const YUM_REPOSITORY = [
|
||||
"sudo tee /etc/yum.repos.d/netbird.repo <<EOF",
|
||||
"[netbird]",
|
||||
"name=netbird",
|
||||
"baseurl=https://pkgs.netbird.io/yum/",
|
||||
"enabled=1",
|
||||
"gpgcheck=1",
|
||||
"gpgkey=https://pkgs.netbird.io/yum/repodata/repomd.xml.key",
|
||||
"repo_gpgcheck=1",
|
||||
"EOF",
|
||||
];
|
||||
|
||||
// The desktop app links GTK 4.10+ and WebKitGTK 6.0, and the released
|
||||
// packages do not declare those as dependencies, so each install line names
|
||||
// them explicitly. Distributions below that floor get the CLI only.
|
||||
const DISTROS: Distro[] = [
|
||||
{
|
||||
label: "Debian / Ubuntu (APT)",
|
||||
value: "apt",
|
||||
repository: [
|
||||
"sudo apt-get update",
|
||||
"sudo apt-get install ca-certificates curl gnupg -y",
|
||||
"curl -sSL https://pkgs.netbird.io/debian/public.key | sudo gpg --dearmor --output /usr/share/keyrings/netbird-archive-keyring.gpg",
|
||||
`echo 'deb [signed-by=/usr/share/keyrings/netbird-archive-keyring.gpg] https://pkgs.netbird.io/debian stable main' | sudo tee /etc/apt/sources.list.d/netbird.list`,
|
||||
],
|
||||
beforeInstall: ["sudo apt-get update"],
|
||||
cli: "sudo apt-get install netbird",
|
||||
desktopApp: [
|
||||
"sudo apt-get install netbird-ui libgtk-4-1 libwebkitgtk-6.0-4 xdg-utils",
|
||||
],
|
||||
note: "The desktop app needs Ubuntu 24.04 or Debian 13 and newer. On earlier releases install the CLI only.",
|
||||
},
|
||||
{
|
||||
label: "Fedora (DNF)",
|
||||
value: "fedora",
|
||||
repository: YUM_REPOSITORY,
|
||||
cli: "sudo dnf install netbird",
|
||||
desktopApp: ["sudo dnf install netbird-ui gtk4 webkitgtk6.0 xdg-utils"],
|
||||
note: "The desktop app needs Fedora 43 and newer. On earlier releases install the CLI only.",
|
||||
},
|
||||
{
|
||||
label: "RHEL / AlmaLinux / Rocky (DNF)",
|
||||
value: "rhel",
|
||||
repository: YUM_REPOSITORY,
|
||||
cli: "sudo dnf install netbird",
|
||||
// WebKitGTK 6.0 ships in EPEL rather than the base repositories, so the
|
||||
// desktop app path enables it first. CLI-only users do not need it.
|
||||
desktopApp: [
|
||||
"sudo dnf install epel-release -y",
|
||||
"sudo dnf install netbird-ui gtk4 webkitgtk6.0 xdg-utils",
|
||||
],
|
||||
note: "The desktop app needs version 10 or newer with EPEL enabled, which provides WebKitGTK 6.0. On version 9 install the CLI only.",
|
||||
},
|
||||
{
|
||||
label: "Amazon Linux (YUM)",
|
||||
value: "amazon",
|
||||
repository: YUM_REPOSITORY,
|
||||
cli: "sudo yum install netbird",
|
||||
note: "Amazon Linux does not ship GTK 4 or WebKitGTK 6.0, so only the CLI is available.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function LinuxTab({
|
||||
setupKey,
|
||||
setupKeyContent,
|
||||
@@ -32,8 +111,20 @@ export default function LinuxTab({
|
||||
showSetupKeyInfo = false,
|
||||
hostname,
|
||||
}: Readonly<Props>) {
|
||||
const [distroValue, setDistroValue] = useState(DISTROS[0].value);
|
||||
const distro =
|
||||
DISTROS.find((option) => option.value === distroValue) ?? DISTROS[0];
|
||||
|
||||
const runStep = setupKeyContent ? 3 : 2;
|
||||
const usingSetupKey = !!setupKey || !!setupKeyPlaceholder;
|
||||
|
||||
const hasDesktopApp = !!distro.desktopApp?.length;
|
||||
const installLines = [
|
||||
...(distro.beforeInstall ?? []),
|
||||
distro.cli,
|
||||
...(distro.desktopApp ?? []),
|
||||
];
|
||||
|
||||
return (
|
||||
<TabsContent value={String(OperatingSystem.LINUX)}>
|
||||
<TabsContentPadding>
|
||||
@@ -66,43 +157,56 @@ export default function LinuxTab({
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>
|
||||
<IconBrandUbuntu size={16} />
|
||||
Install manually on Ubuntu
|
||||
<PackageIcon size={16} />
|
||||
Install manually with a package manager
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className={"mt-1"}>
|
||||
<SelectDropdown
|
||||
value={distroValue}
|
||||
className={"w-[280px]"}
|
||||
onChange={setDistroValue}
|
||||
placeholder={"Select distribution"}
|
||||
options={DISTROS.map(({ label, value }) => ({
|
||||
label,
|
||||
value,
|
||||
}))}
|
||||
data-testid={"linux-distro-select"}
|
||||
/>
|
||||
</div>
|
||||
<Steps>
|
||||
<Steps.Step step={1}>
|
||||
<p>Add our repository</p>
|
||||
<Code>
|
||||
<Code.Line>sudo apt-get update</Code.Line>
|
||||
<Code.Line>
|
||||
sudo apt install ca-certificates curl gnupg -y
|
||||
</Code.Line>
|
||||
<Code.Line>
|
||||
curl -sSL https://pkgs.netbird.io/debian/public.key | sudo
|
||||
gpg --dearmor --output
|
||||
/usr/share/keyrings/netbird-archive-keyring.gpg
|
||||
</Code.Line>
|
||||
<Code.Line>
|
||||
{`echo 'deb [signed-by=/usr/share/keyrings/netbird-archive-keyring.gpg] https://pkgs.netbird.io/debian stable main' | sudo tee /etc/apt/sources.list.d/netbird.list`}
|
||||
</Code.Line>
|
||||
<Code codeToCopy={distro.repository.join("\n")}>
|
||||
{distro.repository.map((line) => (
|
||||
<Code.Line key={line}>{line}</Code.Line>
|
||||
))}
|
||||
</Code>
|
||||
</Steps.Step>
|
||||
<Steps.Step step={2}>
|
||||
<p>Install NetBird</p>
|
||||
<Code
|
||||
codeToCopy={[
|
||||
`sudo apt-get update`,
|
||||
`sudo apt-get install netbird`,
|
||||
`sudo apt-get install netbird-ui`,
|
||||
].join("\n")}
|
||||
>
|
||||
<Code.Line>sudo apt-get update</Code.Line>
|
||||
<Code.Comment># for CLI only</Code.Comment>
|
||||
<Code.Line>sudo apt-get install netbird</Code.Line>
|
||||
<Code.Comment># for GUI package</Code.Comment>
|
||||
<Code.Line>sudo apt-get install netbird-ui</Code.Line>
|
||||
<Code codeToCopy={installLines.join("\n")}>
|
||||
{distro.beforeInstall?.map((line) => (
|
||||
<Code.Line key={line}>{line}</Code.Line>
|
||||
))}
|
||||
{hasDesktopApp && (
|
||||
<Code.Comment># for CLI only</Code.Comment>
|
||||
)}
|
||||
<Code.Line>{distro.cli}</Code.Line>
|
||||
{hasDesktopApp && (
|
||||
<>
|
||||
<Code.Comment># for the desktop app</Code.Comment>
|
||||
{distro.desktopApp?.map((line) => (
|
||||
<Code.Line key={line}>{line}</Code.Line>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Code>
|
||||
<Callout variant={"info"} className={"mt-1"}>
|
||||
{distro.note}
|
||||
{hasDesktopApp &&
|
||||
" Desktop app packages are available for x86_64 only."}
|
||||
</Callout>
|
||||
</Steps.Step>
|
||||
<Steps.Step step={3} line={false}>
|
||||
<p>
|
||||
|
||||
Reference in new issue
Block a user