mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-06 18:56:39 +00:00
♻️ move olm install command to its own component
This commit is contained in:
@@ -32,6 +32,7 @@ import CopyToClipboard from "@app/components/CopyToClipboard";
|
|||||||
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
|
||||||
import { InfoIcon } from "lucide-react";
|
import { InfoIcon } from "lucide-react";
|
||||||
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
||||||
|
import { OlmInstallCommands } from "@app/components/olm-install-commands";
|
||||||
|
|
||||||
export default function CredentialsPage() {
|
export default function CredentialsPage() {
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
@@ -204,6 +205,12 @@ export default function CredentialsPage() {
|
|||||||
</SettingsSectionFooter>
|
</SettingsSectionFooter>
|
||||||
)}
|
)}
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
|
<OlmInstallCommands
|
||||||
|
id={displayOlmId ?? "********"}
|
||||||
|
endpoint={env.app.dashboardUrl}
|
||||||
|
secret={displaySecret ?? "********"}
|
||||||
|
/>
|
||||||
</SettingsContainer>
|
</SettingsContainer>
|
||||||
|
|
||||||
<ConfirmDeleteDialog
|
<ConfirmDeleteDialog
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import CopyToClipboard from "@app/components/CopyToClipboard";
|
||||||
|
import {
|
||||||
|
InfoSection,
|
||||||
|
InfoSectionContent,
|
||||||
|
InfoSections,
|
||||||
|
InfoSectionTitle
|
||||||
|
} from "@app/components/InfoSection";
|
||||||
import {
|
import {
|
||||||
SettingsContainer,
|
SettingsContainer,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
SettingsSectionForm,
|
|
||||||
SettingsSectionHeader,
|
SettingsSectionHeader,
|
||||||
SettingsSectionTitle
|
SettingsSectionTitle
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { StrategySelect } from "@app/components/StrategySelect";
|
import HeaderTitle from "@app/components/SettingsSectionTitle";
|
||||||
|
import { Button } from "@app/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -19,44 +26,24 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage
|
FormMessage
|
||||||
} from "@app/components/ui/form";
|
} from "@app/components/ui/form";
|
||||||
import HeaderTitle from "@app/components/SettingsSectionTitle";
|
|
||||||
import { z } from "zod";
|
|
||||||
import { createElement, useEffect, useState } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { Input } from "@app/components/ui/input";
|
import { Input } from "@app/components/ui/input";
|
||||||
import { ChevronDown, ChevronUp, InfoIcon, Terminal } from "lucide-react";
|
|
||||||
import { Button } from "@app/components/ui/button";
|
|
||||||
import CopyTextBox from "@app/components/CopyTextBox";
|
|
||||||
import CopyToClipboard from "@app/components/CopyToClipboard";
|
|
||||||
import {
|
|
||||||
InfoSection,
|
|
||||||
InfoSectionContent,
|
|
||||||
InfoSections,
|
|
||||||
InfoSectionTitle
|
|
||||||
} from "@app/components/InfoSection";
|
|
||||||
import {
|
|
||||||
FaApple,
|
|
||||||
FaCubes,
|
|
||||||
FaDocker,
|
|
||||||
FaFreebsd,
|
|
||||||
FaWindows
|
|
||||||
} from "react-icons/fa";
|
|
||||||
import { SiNixos, SiKubernetes } from "react-icons/si";
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
|
|
||||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
|
import { toast } from "@app/hooks/useToast";
|
||||||
|
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import {
|
import {
|
||||||
CreateClientBody,
|
CreateClientBody,
|
||||||
CreateClientResponse,
|
CreateClientResponse,
|
||||||
PickClientDefaultsResponse
|
PickClientDefaultsResponse
|
||||||
} from "@server/routers/client";
|
} from "@server/routers/client";
|
||||||
import { ListSitesResponse } from "@server/routers/site";
|
|
||||||
import { toast } from "@app/hooks/useToast";
|
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
|
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { Tag, TagInput } from "@app/components/tags/tag-input";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { OlmInstallCommands } from "@app/components/olm-install-commands";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
type ClientType = "olm";
|
type ClientType = "olm";
|
||||||
@@ -68,18 +55,6 @@ interface TunnelTypeOption {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandItem = string | { title: string; command: string };
|
|
||||||
|
|
||||||
type Commands = {
|
|
||||||
unix: Record<string, CommandItem[]>;
|
|
||||||
windows: Record<string, CommandItem[]>;
|
|
||||||
docker: Record<string, CommandItem[]>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const platforms = ["unix", "docker", "windows"] as const;
|
|
||||||
|
|
||||||
type Platform = (typeof platforms)[number];
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
const api = createApiClient({ env });
|
const api = createApiClient({ env });
|
||||||
@@ -113,13 +88,9 @@ export default function Page() {
|
|||||||
|
|
||||||
const [loadingPage, setLoadingPage] = useState(true);
|
const [loadingPage, setLoadingPage] = useState(true);
|
||||||
|
|
||||||
const [platform, setPlatform] = useState<Platform>("unix");
|
|
||||||
const [architecture, setArchitecture] = useState("All");
|
|
||||||
const [commands, setCommands] = useState<Commands | null>(null);
|
|
||||||
|
|
||||||
const [olmId, setOlmId] = useState("");
|
const [olmId, setOlmId] = useState("");
|
||||||
const [olmSecret, setOlmSecret] = useState("");
|
const [olmSecret, setOlmSecret] = useState("");
|
||||||
const [olmCommand, setOlmCommand] = useState("");
|
const [olmVersion, setOlmVersion] = useState("latest");
|
||||||
|
|
||||||
const [createLoading, setCreateLoading] = useState(false);
|
const [createLoading, setCreateLoading] = useState(false);
|
||||||
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
||||||
@@ -127,136 +98,6 @@ export default function Page() {
|
|||||||
const [clientDefaults, setClientDefaults] =
|
const [clientDefaults, setClientDefaults] =
|
||||||
useState<PickClientDefaultsResponse | null>(null);
|
useState<PickClientDefaultsResponse | null>(null);
|
||||||
|
|
||||||
const hydrateCommands = (
|
|
||||||
id: string,
|
|
||||||
secret: string,
|
|
||||||
endpoint: string,
|
|
||||||
version: string
|
|
||||||
) => {
|
|
||||||
const commands = {
|
|
||||||
unix: {
|
|
||||||
All: [
|
|
||||||
{
|
|
||||||
title: t("install"),
|
|
||||||
command: `curl -fsSL https://static.pangolin.net/get-olm.sh | bash`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("run"),
|
|
||||||
command: `sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
windows: {
|
|
||||||
x64: [
|
|
||||||
{
|
|
||||||
title: t("install"),
|
|
||||||
command: `curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/olm_windows_installer.exe"`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("run"),
|
|
||||||
command: `olm.exe --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
docker: {
|
|
||||||
"Docker Compose": [
|
|
||||||
`services:
|
|
||||||
olm:
|
|
||||||
image: fosrl/olm
|
|
||||||
container_name: olm
|
|
||||||
restart: unless-stopped
|
|
||||||
network_mode: host
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
devices:
|
|
||||||
- /dev/net/tun:/dev/net/tun
|
|
||||||
environment:
|
|
||||||
- PANGOLIN_ENDPOINT=${endpoint}
|
|
||||||
- OLM_ID=${id}
|
|
||||||
- OLM_SECRET=${secret}`
|
|
||||||
],
|
|
||||||
"Docker Run": [
|
|
||||||
`docker run -dit --network host --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun fosrl/olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setCommands(commands);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getArchitectures = () => {
|
|
||||||
switch (platform) {
|
|
||||||
case "unix":
|
|
||||||
return ["All"];
|
|
||||||
case "windows":
|
|
||||||
return ["x64"];
|
|
||||||
case "docker":
|
|
||||||
return ["Docker Compose", "Docker Run"];
|
|
||||||
default:
|
|
||||||
return ["x64"];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPlatformName = (platformName: string) => {
|
|
||||||
switch (platformName) {
|
|
||||||
case "windows":
|
|
||||||
return "Windows";
|
|
||||||
case "unix":
|
|
||||||
return "Unix & macOS";
|
|
||||||
case "docker":
|
|
||||||
return "Docker";
|
|
||||||
default:
|
|
||||||
return "Unix & macOS";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCommand = (): CommandItem[] => {
|
|
||||||
const placeholder: CommandItem[] = [t("unknownCommand")];
|
|
||||||
if (!commands) {
|
|
||||||
return placeholder;
|
|
||||||
}
|
|
||||||
let platformCommands = commands[platform as keyof Commands];
|
|
||||||
|
|
||||||
if (!platformCommands) {
|
|
||||||
// get first key
|
|
||||||
const firstPlatform = Object.keys(commands)[0] as Platform;
|
|
||||||
platformCommands = commands[firstPlatform as keyof Commands];
|
|
||||||
|
|
||||||
setPlatform(firstPlatform);
|
|
||||||
}
|
|
||||||
|
|
||||||
let architectureCommands = platformCommands[architecture];
|
|
||||||
if (!architectureCommands) {
|
|
||||||
// get first key
|
|
||||||
const firstArchitecture = Object.keys(platformCommands)[0];
|
|
||||||
architectureCommands = platformCommands[firstArchitecture];
|
|
||||||
|
|
||||||
setArchitecture(firstArchitecture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return architectureCommands || placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPlatformIcon = (platformName: string) => {
|
|
||||||
switch (platformName) {
|
|
||||||
case "windows":
|
|
||||||
return <FaWindows className="h-4 w-4 mr-2" />;
|
|
||||||
case "unix":
|
|
||||||
return <Terminal className="h-4 w-4 mr-2" />;
|
|
||||||
case "docker":
|
|
||||||
return <FaDocker className="h-4 w-4 mr-2" />;
|
|
||||||
case "kubernetes":
|
|
||||||
return <SiKubernetes className="h-4 w-4 mr-2" />;
|
|
||||||
case "podman":
|
|
||||||
return <FaCubes className="h-4 w-4 mr-2" />;
|
|
||||||
case "freebsd":
|
|
||||||
return <FaFreebsd className="h-4 w-4 mr-2" />;
|
|
||||||
case "nixos":
|
|
||||||
return <SiNixos className="h-4 w-4 mr-2" />;
|
|
||||||
default:
|
|
||||||
return <Terminal className="h-4 w-4 mr-2" />;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const form = useForm<CreateClientFormValues>({
|
const form = useForm<CreateClientFormValues>({
|
||||||
resolver: zodResolver(createClientFormSchema),
|
resolver: zodResolver(createClientFormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -311,23 +152,6 @@ export default function Page() {
|
|||||||
const load = async () => {
|
const load = async () => {
|
||||||
setLoadingPage(true);
|
setLoadingPage(true);
|
||||||
|
|
||||||
// Fetch available sites
|
|
||||||
|
|
||||||
// const res = await api.get<AxiosResponse<ListSitesResponse>>(
|
|
||||||
// `/org/${orgId}/sites/`
|
|
||||||
// );
|
|
||||||
// const sites = res.data.data.sites.filter(
|
|
||||||
// (s) => s.type === "newt" && s.subnet
|
|
||||||
// );
|
|
||||||
// setSites(
|
|
||||||
// sites.map((site) => ({
|
|
||||||
// id: site.siteId.toString(),
|
|
||||||
// text: site.name
|
|
||||||
// }))
|
|
||||||
// );
|
|
||||||
|
|
||||||
let olmVersion = "latest";
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
||||||
@@ -348,7 +172,7 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const latestVersion = data.tag_name;
|
const latestVersion = data.tag_name;
|
||||||
olmVersion = latestVersion;
|
setOlmVersion(latestVersion);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error && error.name === "AbortError") {
|
if (error instanceof Error && error.name === "AbortError") {
|
||||||
console.error(t("olmErrorFetchTimeout"));
|
console.error(t("olmErrorFetchTimeout"));
|
||||||
@@ -377,18 +201,9 @@ export default function Page() {
|
|||||||
|
|
||||||
const olmId = data.olmId;
|
const olmId = data.olmId;
|
||||||
const olmSecret = data.olmSecret;
|
const olmSecret = data.olmSecret;
|
||||||
const olmCommand = `olm --id ${olmId} --secret ${olmSecret} --endpoint ${env.app.dashboardUrl}`;
|
|
||||||
|
|
||||||
setOlmId(olmId);
|
setOlmId(olmId);
|
||||||
setOlmSecret(olmSecret);
|
setOlmSecret(olmSecret);
|
||||||
setOlmCommand(olmCommand);
|
|
||||||
|
|
||||||
hydrateCommands(
|
|
||||||
olmId,
|
|
||||||
olmSecret,
|
|
||||||
env.app.dashboardUrl,
|
|
||||||
olmVersion
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data.subnet) {
|
if (data.subnet) {
|
||||||
form.setValue("subnet", data.subnet);
|
form.setValue("subnet", data.subnet);
|
||||||
@@ -571,118 +386,12 @@ export default function Page() {
|
|||||||
</InfoSections>
|
</InfoSections>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
<SettingsSection>
|
<OlmInstallCommands
|
||||||
<SettingsSectionHeader>
|
id={olmId}
|
||||||
<SettingsSectionTitle>
|
endpoint={env.app.dashboardUrl}
|
||||||
{t("clientInstallOlm")}
|
secret={olmSecret}
|
||||||
</SettingsSectionTitle>
|
version={olmVersion}
|
||||||
<SettingsSectionDescription>
|
/>
|
||||||
{t("clientInstallOlmDescription")}
|
|
||||||
</SettingsSectionDescription>
|
|
||||||
</SettingsSectionHeader>
|
|
||||||
<SettingsSectionBody>
|
|
||||||
<div>
|
|
||||||
<p className="font-bold mb-3">
|
|
||||||
{t("operatingSystem")}
|
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
|
|
||||||
{platforms.map((os) => (
|
|
||||||
<Button
|
|
||||||
key={os}
|
|
||||||
variant={
|
|
||||||
platform === os
|
|
||||||
? "squareOutlinePrimary"
|
|
||||||
: "squareOutline"
|
|
||||||
}
|
|
||||||
className={`flex-1 min-w-[120px] ${platform === os ? "bg-primary/10" : ""} shadow-none`}
|
|
||||||
onClick={() => {
|
|
||||||
setPlatform(os);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{getPlatformIcon(os)}
|
|
||||||
{getPlatformName(os)}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p className="font-bold mb-3">
|
|
||||||
{["docker", "podman"].includes(
|
|
||||||
platform
|
|
||||||
)
|
|
||||||
? t("method")
|
|
||||||
: t("architecture")}
|
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
|
|
||||||
{getArchitectures().map(
|
|
||||||
(arch) => (
|
|
||||||
<Button
|
|
||||||
key={arch}
|
|
||||||
variant={
|
|
||||||
architecture ===
|
|
||||||
arch
|
|
||||||
? "squareOutlinePrimary"
|
|
||||||
: "squareOutline"
|
|
||||||
}
|
|
||||||
className={`flex-1 min-w-[120px] ${architecture === arch ? "bg-primary/10" : ""} shadow-none`}
|
|
||||||
onClick={() =>
|
|
||||||
setArchitecture(
|
|
||||||
arch
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{arch}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="pt-4">
|
|
||||||
<p className="font-bold mb-3">
|
|
||||||
{t("commands")}
|
|
||||||
</p>
|
|
||||||
<div className="mt-2 space-y-3">
|
|
||||||
{getCommand().map(
|
|
||||||
(item, index) => {
|
|
||||||
const commandText =
|
|
||||||
typeof item ===
|
|
||||||
"string"
|
|
||||||
? item
|
|
||||||
: item.command;
|
|
||||||
const title =
|
|
||||||
typeof item ===
|
|
||||||
"string"
|
|
||||||
? undefined
|
|
||||||
: item.title;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
>
|
|
||||||
{title && (
|
|
||||||
<p className="text-sm font-medium mb-1.5">
|
|
||||||
{
|
|
||||||
title
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<CopyTextBox
|
|
||||||
text={
|
|
||||||
commandText
|
|
||||||
}
|
|
||||||
outline={
|
|
||||||
true
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SettingsSectionBody>
|
|
||||||
</SettingsSection>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</SettingsContainer>
|
</SettingsContainer>
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ export default function CredentialsPage() {
|
|||||||
id={displayNewtId ?? "**********"}
|
id={displayNewtId ?? "**********"}
|
||||||
secret={displaySecret ?? "**************"}
|
secret={displaySecret ?? "**************"}
|
||||||
endpoint={env.app.dashboardUrl}
|
endpoint={env.app.dashboardUrl}
|
||||||
version={"latest"}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -31,19 +31,22 @@ export type NewtSiteInstallCommandsProps = {
|
|||||||
id: string;
|
id: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
version: string;
|
version?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function NewtSiteInstallCommands({
|
export function NewtSiteInstallCommands({
|
||||||
id,
|
id,
|
||||||
secret,
|
secret,
|
||||||
endpoint,
|
endpoint,
|
||||||
version
|
version = "latest"
|
||||||
}: NewtSiteInstallCommandsProps) {
|
}: NewtSiteInstallCommandsProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
const [platform, setPlatform] = useState<Platform>("unix");
|
|
||||||
const [acceptClients, setAcceptClients] = useState(true);
|
const [acceptClients, setAcceptClients] = useState(true);
|
||||||
|
const [platform, setPlatform] = useState<Platform>("unix");
|
||||||
|
const [architecture, setArchitecture] = useState(
|
||||||
|
() => getArchitectures(platform)[0]
|
||||||
|
);
|
||||||
|
|
||||||
const acceptClientsFlag = !acceptClients ? " --disable-clients" : "";
|
const acceptClientsFlag = !acceptClients ? " --disable-clients" : "";
|
||||||
const acceptClientsEnv = !acceptClients
|
const acceptClientsEnv = !acceptClients
|
||||||
@@ -133,10 +136,6 @@ WantedBy=default.target`
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [architecture, setArchitecture] = useState(
|
|
||||||
() => getArchitectures(platform)[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
const commands = commandList[platform][architecture];
|
const commands = commandList[platform][architecture];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
220
src/components/olm-install-commands.tsx
Normal file
220
src/components/olm-install-commands.tsx
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
import { Terminal } from "lucide-react";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { FaDocker, FaWindows } from "react-icons/fa";
|
||||||
|
import CopyTextBox from "./CopyTextBox";
|
||||||
|
import {
|
||||||
|
SettingsSection,
|
||||||
|
SettingsSectionBody,
|
||||||
|
SettingsSectionDescription,
|
||||||
|
SettingsSectionHeader,
|
||||||
|
SettingsSectionTitle
|
||||||
|
} from "./Settings";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
|
||||||
|
export type CommandItem = string | { title: string; command: string };
|
||||||
|
|
||||||
|
const PLATFORMS = ["unix", "windows", "docker"] as const;
|
||||||
|
|
||||||
|
type Platform = (typeof PLATFORMS)[number];
|
||||||
|
|
||||||
|
export type OlmInstallCommandsProps = {
|
||||||
|
id: string;
|
||||||
|
secret: string;
|
||||||
|
endpoint: string;
|
||||||
|
version?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function OlmInstallCommands({
|
||||||
|
id,
|
||||||
|
secret,
|
||||||
|
endpoint,
|
||||||
|
version = "latest"
|
||||||
|
}: OlmInstallCommandsProps) {
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
|
const [platform, setPlatform] = useState<Platform>("unix");
|
||||||
|
const [architecture, setArchitecture] = useState(
|
||||||
|
() => getArchitectures(platform)[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
const commandList: Record<Platform, Record<string, CommandItem[]>> = {
|
||||||
|
unix: {
|
||||||
|
All: [
|
||||||
|
{
|
||||||
|
title: t("install"),
|
||||||
|
command: `curl -fsSL https://static.pangolin.net/get-olm.sh | bash`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("run"),
|
||||||
|
command: `sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
windows: {
|
||||||
|
x64: [
|
||||||
|
{
|
||||||
|
title: t("install"),
|
||||||
|
command: `curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/olm_windows_installer.exe"`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("run"),
|
||||||
|
command: `olm.exe --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
docker: {
|
||||||
|
"Docker Compose": [
|
||||||
|
`services:
|
||||||
|
olm:
|
||||||
|
image: fosrl/olm
|
||||||
|
container_name: olm
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun
|
||||||
|
environment:
|
||||||
|
- PANGOLIN_ENDPOINT=${endpoint}
|
||||||
|
- OLM_ID=${id}
|
||||||
|
- OLM_SECRET=${secret}`
|
||||||
|
],
|
||||||
|
"Docker Run": [
|
||||||
|
`docker run -dit --network host --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun fosrl/olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const commands = commandList[platform][architecture];
|
||||||
|
return (
|
||||||
|
<SettingsSection>
|
||||||
|
<SettingsSectionHeader>
|
||||||
|
<SettingsSectionTitle>
|
||||||
|
{t("clientInstallOlm")}
|
||||||
|
</SettingsSectionTitle>
|
||||||
|
<SettingsSectionDescription>
|
||||||
|
{t("clientInstallOlmDescription")}
|
||||||
|
</SettingsSectionDescription>
|
||||||
|
</SettingsSectionHeader>
|
||||||
|
<SettingsSectionBody>
|
||||||
|
<div>
|
||||||
|
<p className="font-bold mb-3">{t("operatingSystem")}</p>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
|
||||||
|
{PLATFORMS.map((os) => (
|
||||||
|
<Button
|
||||||
|
key={os}
|
||||||
|
variant={
|
||||||
|
platform === os
|
||||||
|
? "squareOutlinePrimary"
|
||||||
|
: "squareOutline"
|
||||||
|
}
|
||||||
|
className={`flex-1 min-w-30 ${platform === os ? "bg-primary/10" : ""} shadow-none`}
|
||||||
|
onClick={() => {
|
||||||
|
setPlatform(os);
|
||||||
|
const architectures = getArchitectures(os);
|
||||||
|
setArchitecture(architectures[0]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getPlatformIcon(os)}
|
||||||
|
{getPlatformName(os)}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="font-bold mb-3">
|
||||||
|
{["docker", "podman"].includes(platform)
|
||||||
|
? t("method")
|
||||||
|
: t("architecture")}
|
||||||
|
</p>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
|
||||||
|
{getArchitectures(platform).map((arch) => (
|
||||||
|
<Button
|
||||||
|
key={arch}
|
||||||
|
variant={
|
||||||
|
architecture === arch
|
||||||
|
? "squareOutlinePrimary"
|
||||||
|
: "squareOutline"
|
||||||
|
}
|
||||||
|
className={`flex-1 min-w-30 ${architecture === arch ? "bg-primary/10" : ""} shadow-none`}
|
||||||
|
onClick={() => setArchitecture(arch)}
|
||||||
|
>
|
||||||
|
{arch}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="pt-4">
|
||||||
|
<p className="font-bold mb-3">{t("commands")}</p>
|
||||||
|
<div className="mt-2 space-y-3">
|
||||||
|
{commands.map((item, index) => {
|
||||||
|
const commandText =
|
||||||
|
typeof item === "string"
|
||||||
|
? item
|
||||||
|
: item.command;
|
||||||
|
const title =
|
||||||
|
typeof item === "string"
|
||||||
|
? undefined
|
||||||
|
: item.title;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
{title && (
|
||||||
|
<p className="text-sm font-medium mb-1.5">
|
||||||
|
{title}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<CopyTextBox
|
||||||
|
text={commandText}
|
||||||
|
outline={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingsSectionBody>
|
||||||
|
</SettingsSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArchitectures(platform: Platform) {
|
||||||
|
switch (platform) {
|
||||||
|
case "unix":
|
||||||
|
return ["All"];
|
||||||
|
case "windows":
|
||||||
|
return ["x64"];
|
||||||
|
case "docker":
|
||||||
|
return ["Docker Compose", "Docker Run"];
|
||||||
|
default:
|
||||||
|
return ["x64"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlatformName(platformName: Platform) {
|
||||||
|
switch (platformName) {
|
||||||
|
case "windows":
|
||||||
|
return "Windows";
|
||||||
|
case "unix":
|
||||||
|
return "Unix & macOS";
|
||||||
|
case "docker":
|
||||||
|
return "Docker";
|
||||||
|
default:
|
||||||
|
return "Unix & macOS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlatformIcon(platformName: Platform) {
|
||||||
|
switch (platformName) {
|
||||||
|
case "windows":
|
||||||
|
return <FaWindows className="h-4 w-4 mr-2" />;
|
||||||
|
case "unix":
|
||||||
|
return <Terminal className="h-4 w-4 mr-2" />;
|
||||||
|
case "docker":
|
||||||
|
return <FaDocker className="h-4 w-4 mr-2" />;
|
||||||
|
default:
|
||||||
|
return <Terminal className="h-4 w-4 mr-2" />;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user