mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-03 08:26:36 +00:00
Compare commits
11 Commits
revert-276
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d83fa63af5 | ||
|
|
d5837ab718 | ||
|
|
b7ccb92236 | ||
|
|
23a151dd45 | ||
|
|
122079ddb2 | ||
|
|
1d0b0ae6ec | ||
|
|
0fc1aa9191 | ||
|
|
ddf417f4ca | ||
|
|
d08be59055 | ||
|
|
322c136d1f | ||
|
|
e06f2f47b1 |
@@ -624,6 +624,8 @@
|
|||||||
"targetErrorInvalidPortDescription": "Please enter a valid port number",
|
"targetErrorInvalidPortDescription": "Please enter a valid port number",
|
||||||
"targetErrorNoSite": "No site selected",
|
"targetErrorNoSite": "No site selected",
|
||||||
"targetErrorNoSiteDescription": "Please select a site for the target",
|
"targetErrorNoSiteDescription": "Please select a site for the target",
|
||||||
|
"targetTargetsCleared": "Targets cleared",
|
||||||
|
"targetTargetsClearedDescription": "All targets have been removed from this resource",
|
||||||
"targetCreated": "Target created",
|
"targetCreated": "Target created",
|
||||||
"targetCreatedDescription": "Target has been created successfully",
|
"targetCreatedDescription": "Target has been created successfully",
|
||||||
"targetErrorCreate": "Failed to create target",
|
"targetErrorCreate": "Failed to create target",
|
||||||
@@ -2607,6 +2609,9 @@
|
|||||||
"machineClients": "Machine Clients",
|
"machineClients": "Machine Clients",
|
||||||
"install": "Install",
|
"install": "Install",
|
||||||
"run": "Run",
|
"run": "Run",
|
||||||
|
"envFile": "Environment File",
|
||||||
|
"serviceFile": "Service File",
|
||||||
|
"enableAndStart": "Enable and Start",
|
||||||
"clientNameDescription": "The display name of the client that can be changed later.",
|
"clientNameDescription": "The display name of the client that can be changed later.",
|
||||||
"clientAddress": "Client Address (Advanced)",
|
"clientAddress": "Client Address (Advanced)",
|
||||||
"setupFailedToFetchSubnet": "Failed to fetch default subnet",
|
"setupFailedToFetchSubnet": "Failed to fetch default subnet",
|
||||||
|
|||||||
@@ -400,7 +400,11 @@ function ProxyResourceTargetsForm({
|
|||||||
pathMatchType: row.original.pathMatchType
|
pathMatchType: row.original.pathMatchType
|
||||||
}}
|
}}
|
||||||
onChange={(config) =>
|
onChange={(config) =>
|
||||||
updateTarget(row.original.targetId, config)
|
updateTarget(row.original.targetId,
|
||||||
|
config.path === null && config.pathMatchType === null
|
||||||
|
? { ...config, rewritePath: null, rewritePathType: null }
|
||||||
|
: config
|
||||||
|
)
|
||||||
}
|
}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
@@ -424,7 +428,11 @@ function ProxyResourceTargetsForm({
|
|||||||
pathMatchType: row.original.pathMatchType
|
pathMatchType: row.original.pathMatchType
|
||||||
}}
|
}}
|
||||||
onChange={(config) =>
|
onChange={(config) =>
|
||||||
updateTarget(row.original.targetId, config)
|
updateTarget(row.original.targetId,
|
||||||
|
config.path === null && config.pathMatchType === null
|
||||||
|
? { ...config, rewritePath: null, rewritePathType: null }
|
||||||
|
: config
|
||||||
|
)
|
||||||
}
|
}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
@@ -774,8 +782,12 @@ function ProxyResourceTargetsForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: t("settingsUpdated"),
|
title: targets.length === 0
|
||||||
description: t("settingsUpdatedDescription")
|
? t("targetTargetsCleared")
|
||||||
|
: t("settingsUpdated"),
|
||||||
|
description: targets.length === 0
|
||||||
|
? t("targetTargetsClearedDescription")
|
||||||
|
: t("settingsUpdatedDescription")
|
||||||
});
|
});
|
||||||
|
|
||||||
setTargetsToRemove([]);
|
setTargetsToRemove([]);
|
||||||
|
|||||||
@@ -776,7 +776,11 @@ export default function Page() {
|
|||||||
pathMatchType: row.original.pathMatchType
|
pathMatchType: row.original.pathMatchType
|
||||||
}}
|
}}
|
||||||
onChange={(config) =>
|
onChange={(config) =>
|
||||||
updateTarget(row.original.targetId, config)
|
updateTarget(row.original.targetId,
|
||||||
|
config.path === null && config.pathMatchType === null
|
||||||
|
? { ...config, rewritePath: null, rewritePathType: null }
|
||||||
|
: config
|
||||||
|
)
|
||||||
}
|
}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
@@ -800,7 +804,11 @@ export default function Page() {
|
|||||||
pathMatchType: row.original.pathMatchType
|
pathMatchType: row.original.pathMatchType
|
||||||
}}
|
}}
|
||||||
onChange={(config) =>
|
onChange={(config) =>
|
||||||
updateTarget(row.original.targetId, config)
|
updateTarget(row.original.targetId,
|
||||||
|
config.path === null && config.pathMatchType === null
|
||||||
|
? { ...config, rewritePath: null, rewritePathType: null }
|
||||||
|
: config
|
||||||
|
)
|
||||||
}
|
}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import {
|
|||||||
import { CheckboxWithLabel } from "./ui/checkbox";
|
import { CheckboxWithLabel } from "./ui/checkbox";
|
||||||
import { OptionSelect, type OptionSelectOption } from "./OptionSelect";
|
import { OptionSelect, type OptionSelectOption } from "./OptionSelect";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FaCubes, FaDocker, FaWindows } from "react-icons/fa";
|
import { FaApple, FaCubes, FaDocker, FaLinux, FaWindows } from "react-icons/fa";
|
||||||
import { Terminal } from "lucide-react";
|
|
||||||
import { SiKubernetes, SiNixos } from "react-icons/si";
|
import { SiKubernetes, SiNixos } from "react-icons/si";
|
||||||
|
|
||||||
export type CommandItem = string | { title: string; command: string };
|
export type CommandItem = string | { title: string; command: string };
|
||||||
|
|
||||||
const PLATFORMS = [
|
const PLATFORMS = [
|
||||||
"unix",
|
"linux",
|
||||||
|
"macos",
|
||||||
"docker",
|
"docker",
|
||||||
"kubernetes",
|
"kubernetes",
|
||||||
"podman",
|
"podman",
|
||||||
@@ -43,7 +43,7 @@ export function NewtSiteInstallCommands({
|
|||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
const [acceptClients, setAcceptClients] = useState(true);
|
const [acceptClients, setAcceptClients] = useState(true);
|
||||||
const [platform, setPlatform] = useState<Platform>("unix");
|
const [platform, setPlatform] = useState<Platform>("linux");
|
||||||
const [architecture, setArchitecture] = useState(
|
const [architecture, setArchitecture] = useState(
|
||||||
() => getArchitectures(platform)[0]
|
() => getArchitectures(platform)[0]
|
||||||
);
|
);
|
||||||
@@ -54,8 +54,68 @@ export function NewtSiteInstallCommands({
|
|||||||
: "";
|
: "";
|
||||||
|
|
||||||
const commandList: Record<Platform, Record<string, CommandItem[]>> = {
|
const commandList: Record<Platform, Record<string, CommandItem[]>> = {
|
||||||
unix: {
|
linux: {
|
||||||
All: [
|
Run: [
|
||||||
|
{
|
||||||
|
title: t("install"),
|
||||||
|
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("run"),
|
||||||
|
command: `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Systemd Service": [
|
||||||
|
{
|
||||||
|
title: t("install"),
|
||||||
|
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("envFile"),
|
||||||
|
command: `# Create the directory and environment file
|
||||||
|
sudo install -d -m 0755 /etc/newt
|
||||||
|
sudo tee /etc/newt/newt.env > /dev/null << 'EOF'
|
||||||
|
NEWT_ID=${id}
|
||||||
|
NEWT_SECRET=${secret}
|
||||||
|
PANGOLIN_ENDPOINT=${endpoint}${!acceptClients ? `
|
||||||
|
DISABLE_CLIENTS=true` : ""}
|
||||||
|
EOF
|
||||||
|
sudo chmod 600 /etc/newt/newt.env`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("serviceFile"),
|
||||||
|
command: `sudo tee /etc/systemd/system/newt.service > /dev/null << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Newt
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
EnvironmentFile=/etc/newt/newt.env
|
||||||
|
ExecStart=/usr/local/bin/newt
|
||||||
|
Restart=always
|
||||||
|
RestartSec=2
|
||||||
|
UMask=0077
|
||||||
|
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("enableAndStart"),
|
||||||
|
command: `sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now newt`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
macos: {
|
||||||
|
Run: [
|
||||||
{
|
{
|
||||||
title: t("install"),
|
title: t("install"),
|
||||||
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash`
|
command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash`
|
||||||
@@ -131,7 +191,7 @@ WantedBy=default.target`
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
nixos: {
|
nixos: {
|
||||||
All: [
|
Flake: [
|
||||||
`nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
`nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -172,9 +232,9 @@ WantedBy=default.target`
|
|||||||
|
|
||||||
<OptionSelect<string>
|
<OptionSelect<string>
|
||||||
label={
|
label={
|
||||||
["docker", "podman"].includes(platform)
|
platform === "windows"
|
||||||
? t("method")
|
? t("architecture")
|
||||||
: t("architecture")
|
: t("method")
|
||||||
}
|
}
|
||||||
options={getArchitectures(platform).map((arch) => ({
|
options={getArchitectures(platform).map((arch) => ({
|
||||||
value: arch,
|
value: arch,
|
||||||
@@ -261,8 +321,10 @@ function getPlatformIcon(platformName: Platform) {
|
|||||||
switch (platformName) {
|
switch (platformName) {
|
||||||
case "windows":
|
case "windows":
|
||||||
return <FaWindows className="h-4 w-4 mr-2" />;
|
return <FaWindows className="h-4 w-4 mr-2" />;
|
||||||
case "unix":
|
case "linux":
|
||||||
return <Terminal className="h-4 w-4 mr-2" />;
|
return <FaLinux className="h-4 w-4 mr-2" />;
|
||||||
|
case "macos":
|
||||||
|
return <FaApple className="h-4 w-4 mr-2" />;
|
||||||
case "docker":
|
case "docker":
|
||||||
return <FaDocker className="h-4 w-4 mr-2" />;
|
return <FaDocker className="h-4 w-4 mr-2" />;
|
||||||
case "kubernetes":
|
case "kubernetes":
|
||||||
@@ -272,7 +334,7 @@ function getPlatformIcon(platformName: Platform) {
|
|||||||
case "nixos":
|
case "nixos":
|
||||||
return <SiNixos className="h-4 w-4 mr-2" />;
|
return <SiNixos className="h-4 w-4 mr-2" />;
|
||||||
default:
|
default:
|
||||||
return <Terminal className="h-4 w-4 mr-2" />;
|
return <FaLinux className="h-4 w-4 mr-2" />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +342,10 @@ function getPlatformName(platformName: Platform) {
|
|||||||
switch (platformName) {
|
switch (platformName) {
|
||||||
case "windows":
|
case "windows":
|
||||||
return "Windows";
|
return "Windows";
|
||||||
case "unix":
|
case "linux":
|
||||||
return "Unix & macOS";
|
return "Linux";
|
||||||
|
case "macos":
|
||||||
|
return "macOS";
|
||||||
case "docker":
|
case "docker":
|
||||||
return "Docker";
|
return "Docker";
|
||||||
case "kubernetes":
|
case "kubernetes":
|
||||||
@@ -291,14 +355,16 @@ function getPlatformName(platformName: Platform) {
|
|||||||
case "nixos":
|
case "nixos":
|
||||||
return "NixOS";
|
return "NixOS";
|
||||||
default:
|
default:
|
||||||
return "Unix / macOS";
|
return "Linux";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getArchitectures(platform: Platform) {
|
function getArchitectures(platform: Platform) {
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
case "unix":
|
case "linux":
|
||||||
return ["All"];
|
return ["Run", "Systemd Service"];
|
||||||
|
case "macos":
|
||||||
|
return ["Run"];
|
||||||
case "windows":
|
case "windows":
|
||||||
return ["x64"];
|
return ["x64"];
|
||||||
case "docker":
|
case "docker":
|
||||||
@@ -308,8 +374,8 @@ function getArchitectures(platform: Platform) {
|
|||||||
case "podman":
|
case "podman":
|
||||||
return ["Podman Quadlet", "Podman Run"];
|
return ["Podman Quadlet", "Podman Run"];
|
||||||
case "nixos":
|
case "nixos":
|
||||||
return ["All"];
|
return ["Flake"];
|
||||||
default:
|
default:
|
||||||
return ["x64"];
|
return ["Run"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,21 @@ export async function getUserLocale(): Promise<Locale> {
|
|||||||
const res = await internal.get("/user", await authCookieHeader());
|
const res = await internal.get("/user", await authCookieHeader());
|
||||||
const userLocale = res.data?.data?.locale;
|
const userLocale = res.data?.data?.locale;
|
||||||
if (userLocale && locales.includes(userLocale as Locale)) {
|
if (userLocale && locales.includes(userLocale as Locale)) {
|
||||||
// Set the cookie so subsequent requests don't need the API call
|
// Try to cache in a cookie so subsequent requests skip the API
|
||||||
(await cookies()).set(COOKIE_NAME, userLocale, {
|
// call. cookies().set() is only permitted in Server Actions and
|
||||||
maxAge: COOKIE_MAX_AGE,
|
// Route Handlers — not during rendering — so we isolate it so
|
||||||
path: "/",
|
// that a write failure doesn't prevent the locale from being
|
||||||
sameSite: "lax"
|
// returned for the current request.
|
||||||
});
|
try {
|
||||||
|
(await cookies()).set(COOKIE_NAME, userLocale, {
|
||||||
|
maxAge: COOKIE_MAX_AGE,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "lax"
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Cannot set cookies in this context (e.g. during rendering);
|
||||||
|
// the correct locale is still returned below.
|
||||||
|
}
|
||||||
return userLocale as Locale;
|
return userLocale as Locale;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user