Merge branch 'dev' into improbableone-hub-dev

This commit is contained in:
Owen 2025-06-01 23:31:11 -04:00
commit ea0ab0e63c
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
20 changed files with 3232 additions and 2974 deletions

46
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,46 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
dev-major-updates:
dependency-type: "development"
update-types:
- "major"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
prod-major-updates:
dependency-type: "production"
update-types:
- "major"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
groups:
patch-updates:
update-types:
- "patch"
minor-updates:
update-types:
- "minor"
major-updates:
update-types:
- "major"

View file

@ -1,4 +1,4 @@
FROM node:20-alpine AS builder
FROM node:24-alpine AS builder
WORKDIR /app
@ -12,7 +12,7 @@ RUN npx drizzle-kit generate --dialect sqlite --schema ./server/db/schemas/ --ou
RUN npm run build
FROM node:20-alpine AS runner
FROM node:24-alpine AS runner
WORKDIR /app

View file

@ -9,7 +9,7 @@
</div>
<h3 align="center">Tunneled Mesh Reverse Proxy Server with Access Control</h3>
<h3 align="center">Tunneled Reverse Proxy Server with Access Control</h3>
<div align="center">
_Your own self-hosted zero trust tunnel._
@ -83,7 +83,7 @@ _Resources page of Pangolin dashboard (dark mode) showing multiple resources ava
### Modular Design
- Extend functionality with existing [Traefik](https://github.com/traefik/traefik) plugins, such as [CrowdSec](https://plugins.traefik.io/plugins/6335346ca4caa9ddeffda116/crowdsec-bouncer-traefik-plugin) and [Geoblock](github.com/PascalMinder/geoblock).
- Extend functionality with existing [Traefik](https://github.com/traefik/traefik) plugins, such as [CrowdSec](https://plugins.traefik.io/plugins/6335346ca4caa9ddeffda116/crowdsec-bouncer-traefik-plugin) and [Geoblock](https://github.com/PascalMinder/geoblock).
- **Automatically install and configure Crowdsec via Pangolin's installer script.**
- Attach as many sites to the central server as you wish.

View file

@ -9,6 +9,7 @@ import (
"io/fs"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"
@ -17,6 +18,7 @@ import (
"time"
"unicode"
"math/rand"
"strconv"
"golang.org/x/term"
)
@ -57,9 +59,18 @@ type Config struct {
func main() {
reader := bufio.NewReader(os.Stdin)
// check if the user is root
if os.Geteuid() != 0 {
fmt.Println("This script must be run as root")
// check if docker is not installed and the user is root
if !isDockerInstalled() {
if os.Geteuid() != 0 {
fmt.Println("Docker is not installed. Please install Docker manually or run this installer as root.")
os.Exit(1)
}
}
// check if the user is in the docker group (linux only)
if !isUserInDockerGroup() {
fmt.Println("You are not in the docker group.")
fmt.Println("The installer will not be able to run docker commands without running it as root.")
os.Exit(1)
}
@ -83,6 +94,27 @@ func main() {
if !isDockerInstalled() && runtime.GOOS == "linux" {
if readBool(reader, "Docker is not installed. Would you like to install it?", true) {
installDocker()
// try to start docker service but ignore errors
if err := startDockerService(); err != nil {
fmt.Println("Error starting Docker service:", err)
} else {
fmt.Println("Docker service started successfully!")
}
// wait 10 seconds for docker to start checking if docker is running every 2 seconds
fmt.Println("Waiting for Docker to start...")
for i := 0; i < 5; i++ {
if isDockerRunning() {
fmt.Println("Docker is running!")
break
}
fmt.Println("Docker is not running yet, waiting...")
time.Sleep(2 * time.Second)
}
if !isDockerRunning() {
fmt.Println("Docker is still not running after 10 seconds. Please check the installation.")
os.Exit(1)
}
fmt.Println("Docker installed successfully!")
}
}
@ -397,7 +429,7 @@ func installDocker() error {
return fmt.Errorf("failed to detect Linux distribution: %v", err)
}
osRelease := string(output)
// Detect system architecture
archCmd := exec.Command("uname", "-m")
archOutput, err := archCmd.Output()
@ -405,7 +437,7 @@ func installDocker() error {
return fmt.Errorf("failed to detect system architecture: %v", err)
}
arch := strings.TrimSpace(string(archOutput))
// Map architecture to Docker's architecture naming
var dockerArch string
switch arch {
@ -438,11 +470,31 @@ func installDocker() error {
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
`, dockerArch))
case strings.Contains(osRelease, "ID=fedora"):
installCmd = exec.Command("bash", "-c", `
// Detect Fedora version to handle DNF 5 changes
versionCmd := exec.Command("bash", "-c", "grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '\"'")
versionOutput, err := versionCmd.Output()
var fedoraVersion int
if err == nil {
if v, parseErr := strconv.Atoi(strings.TrimSpace(string(versionOutput))); parseErr == nil {
fedoraVersion = v
}
}
// Use appropriate DNF syntax based on version
var repoCmd string
if fedoraVersion >= 41 {
// DNF 5 syntax for Fedora 41+
repoCmd = "dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo"
} else {
// DNF 4 syntax for Fedora < 41
repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo"
}
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
dnf -y install dnf-plugins-core &&
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo &&
%s &&
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
`)
`, repoCmd))
case strings.Contains(osRelease, "ID=opensuse") || strings.Contains(osRelease, "ID=\"opensuse-"):
installCmd = exec.Command("bash", "-c", `
zypper install -y docker docker-compose &&
@ -466,11 +518,26 @@ func installDocker() error {
default:
return fmt.Errorf("unsupported Linux distribution")
}
installCmd.Stdout = os.Stdout
installCmd.Stderr = os.Stderr
return installCmd.Run()
}
func startDockerService() error {
if runtime.GOOS == "linux" {
cmd := exec.Command("systemctl", "enable", "--now", "docker")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
} else if runtime.GOOS == "darwin" {
// On macOS, Docker is usually started via the Docker Desktop application
fmt.Println("Please start Docker Desktop manually on macOS.")
return nil
}
return fmt.Errorf("unsupported operating system for starting Docker service")
}
func isDockerInstalled() bool {
cmd := exec.Command("docker", "--version")
if err := cmd.Run(); err != nil {
@ -479,6 +546,43 @@ func isDockerInstalled() bool {
return true
}
func isUserInDockerGroup() bool {
if runtime.GOOS == "darwin" {
// Docker group is not applicable on macOS
// So we assume that the user can run Docker commands
return true
}
if os.Geteuid() == 0 {
return true // Root user can run Docker commands anyway
}
// Check if the current user is in the docker group
if dockerGroup, err := user.LookupGroup("docker"); err == nil {
if currentUser, err := user.Current(); err == nil {
if currentUserGroupIds, err := currentUser.GroupIds(); err == nil {
for _, groupId := range currentUserGroupIds {
if groupId == dockerGroup.Gid {
return true
}
}
}
}
}
// Eventually, if any of the checks fail, we assume the user cannot run Docker commands
return false
}
// isDockerRunning checks if the Docker daemon is running by using the `docker info` command.
func isDockerRunning() bool {
cmd := exec.Command("docker", "info")
if err := cmd.Run(); err != nil {
return false
}
return true
}
// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied
func executeDockerComposeCommandWithArgs(args ...string) error {
var cmd *exec.Cmd
@ -619,4 +723,4 @@ func generateRandomSecretKey() string {
b[i] = charset[seededRand.Intn(len(charset))]
}
return string(b)
}
}

5764
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -20,93 +20,93 @@
"email": "email dev --dir server/emails/templates --port 3005"
},
"dependencies": {
"@asteasolutions/zod-to-openapi": "^7.3.0",
"@asteasolutions/zod-to-openapi": "^7.3.2",
"@hookform/resolvers": "3.9.1",
"@node-rs/argon2": "2.0.2",
"@node-rs/argon2": "^2.0.2",
"@oslojs/crypto": "1.0.1",
"@oslojs/encoding": "1.1.0",
"@radix-ui/react-avatar": "1.1.2",
"@radix-ui/react-checkbox": "1.1.3",
"@radix-ui/react-collapsible": "1.1.2",
"@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "2.1.4",
"@radix-ui/react-avatar": "1.1.10",
"@radix-ui/react-checkbox": "1.3.2",
"@radix-ui/react-collapsible": "1.1.11",
"@radix-ui/react-dialog": "1.1.14",
"@radix-ui/react-dropdown-menu": "2.1.15",
"@radix-ui/react-icons": "1.3.2",
"@radix-ui/react-label": "2.1.1",
"@radix-ui/react-popover": "1.1.4",
"@radix-ui/react-progress": "^1.1.4",
"@radix-ui/react-radio-group": "1.2.2",
"@radix-ui/react-label": "2.1.7",
"@radix-ui/react-popover": "1.1.14",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-radio-group": "1.3.7",
"@radix-ui/react-scroll-area": "^1.2.9",
"@radix-ui/react-select": "2.1.4",
"@radix-ui/react-separator": "1.1.1",
"@radix-ui/react-slot": "1.1.1",
"@radix-ui/react-switch": "1.1.2",
"@radix-ui/react-tabs": "1.1.2",
"@radix-ui/react-toast": "1.2.4",
"@react-email/components": "0.0.36",
"@react-email/render": "^1.0.6",
"@react-email/tailwind": "1.0.4",
"@radix-ui/react-select": "2.2.5",
"@radix-ui/react-separator": "1.1.7",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-switch": "1.2.5",
"@radix-ui/react-tabs": "1.1.12",
"@radix-ui/react-toast": "1.2.14",
"@react-email/components": "0.0.41",
"@react-email/render": "^1.1.2",
"@react-email/tailwind": "1.0.5",
"@tailwindcss/forms": "^0.5.10",
"@tanstack/react-table": "8.20.6",
"arctic": "^3.6.0",
"axios": "1.8.4",
"@tanstack/react-table": "8.21.3",
"arctic": "^3.7.0",
"axios": "1.9.0",
"better-sqlite3": "11.7.0",
"canvas-confetti": "1.9.3",
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"cmdk": "1.0.4",
"cmdk": "1.1.1",
"cookie": "^1.0.2",
"cookie-parser": "1.4.7",
"cookies": "^0.9.1",
"cors": "2.8.5",
"crypto-js": "^4.2.0",
"drizzle-orm": "0.38.3",
"eslint": "9.17.0",
"eslint-config-next": "15.1.3",
"drizzle-orm": "0.44.1",
"eslint": "9.28.0",
"eslint-config-next": "15.3.3",
"express": "4.21.2",
"express-rate-limit": "7.5.0",
"glob": "11.0.0",
"helmet": "8.0.0",
"glob": "11.0.2",
"helmet": "8.1.0",
"http-errors": "2.0.0",
"i": "^0.3.7",
"input-otp": "1.4.1",
"input-otp": "1.4.2",
"jmespath": "^0.16.0",
"js-yaml": "4.1.0",
"jsonwebtoken": "^9.0.2",
"lucide-react": "0.469.0",
"lucide-react": "0.511.0",
"moment": "2.30.1",
"next": "15.2.4",
"next-themes": "0.4.4",
"next": "15.3.3",
"next-themes": "0.4.6",
"node-cache": "5.1.2",
"node-fetch": "3.3.2",
"nodemailer": "6.9.16",
"npm": "^11.2.0",
"npm": "^11.4.1",
"oslo": "1.2.1",
"qrcode.react": "4.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-easy-sort": "^1.6.0",
"react-hook-form": "7.54.2",
"react-hook-form": "7.56.4",
"react-icons": "^5.5.0",
"rebuild": "0.1.2",
"semver": "7.6.3",
"semver": "7.7.2",
"swagger-ui-express": "^5.0.1",
"tailwind-merge": "2.6.0",
"tw-animate-css": "^1.2.5",
"tw-animate-css": "^1.3.3",
"uuid": "^11.1.0",
"vaul": "1.1.2",
"winston": "3.17.0",
"winston-daily-rotate-file": "5.0.0",
"ws": "8.18.0",
"zod": "3.24.1",
"zod-validation-error": "3.4.0"
"ws": "8.18.2",
"zod": "3.25.46",
"zod-validation-error": "3.4.1"
},
"devDependencies": {
"@dotenvx/dotenvx": "1.32.0",
"@dotenvx/dotenvx": "1.44.1",
"@esbuild-plugins/tsconfig-paths": "0.1.2",
"@tailwindcss/postcss": "^4.1.3",
"@tailwindcss/postcss": "^4.1.8",
"@types/better-sqlite3": "7.6.12",
"@types/cookie-parser": "1.4.8",
"@types/cors": "2.8.17",
"@types/cors": "2.8.18",
"@types/crypto-js": "^4.2.2",
"@types/express": "5.0.0",
"@types/jmespath": "^0.15.2",
@ -114,22 +114,22 @@
"@types/jsonwebtoken": "^9.0.9",
"@types/node": "^22",
"@types/nodemailer": "6.4.17",
"@types/react": "19.1.1",
"@types/react-dom": "19.1.2",
"@types/semver": "7.5.8",
"@types/react": "19.1.6",
"@types/react-dom": "19.1.5",
"@types/semver": "7.7.0",
"@types/swagger-ui-express": "^4.1.8",
"@types/ws": "8.5.13",
"@types/ws": "8.18.1",
"@types/yargs": "17.0.33",
"drizzle-kit": "0.30.6",
"esbuild": "0.25.2",
"drizzle-kit": "0.31.1",
"esbuild": "0.25.5",
"esbuild-node-externals": "1.18.0",
"postcss": "^8",
"react-email": "4.0.6",
"react-email": "4.0.15",
"tailwindcss": "^4.1.4",
"tsc-alias": "1.8.10",
"tsx": "4.19.3",
"tsc-alias": "1.8.16",
"tsx": "4.19.4",
"typescript": "^5",
"yargs": "17.7.2"
"yargs": "18.0.0"
},
"overrides": {
"emblor": {

View file

@ -1,22 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="900.82861"
height="955.20648"
viewBox="0 0 238.34422 252.7317"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 399.99999 400.00002"
enable-background="new 0 0 419.528 419.528"
xml:space="preserve"
id="svg52"
sodipodi:docname="noun-pangolin-1798092.svg"
width="400"
height="400"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
id="svg420"
inkscape:export-filename="logo.svg"
inkscape:export-xdpi="221.14999"
inkscape:export-ydpi="221.14999"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs56" /><sodipodi:namedview
id="namedview54"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview422"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -24,15 +23,18 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.9583914"
inkscape:cx="209.86611"
inkscape:cy="262.20499"
inkscape:window-width="3840"
inkscape:window-height="2136"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg52" /><path
d="m 62.232921,184.91974 c 0,2.431 -1.97,4.402 -4.399,4.402 -2.429,0 -4.399,-1.972 -4.399,-4.402 0,-2.429 1.97,-4.399 4.399,-4.399 2.429,-10e-4 4.399,1.97 4.399,4.399 z m 58.993999,-4.821 c -25.943999,-2.826 -38.978999,7.453 -71.181999,31.357 -27.572,20.467 -32.767,4.381 -31.748,-2.614 1.499,-10.282 25.222,-58.573 48.079,-88.461 28.273,7.34 49.869999,30.727 54.850999,59.718 z m -55.915999,4.821 c 0,-4.131 -3.349,-7.478 -7.478,-7.478 -4.129,0 -7.478,3.347 -7.478,7.478 0,4.131 3.349,7.481 7.478,7.481 4.13,0 7.478,-3.35 7.478,-7.481 z m -15.032,48.424 -0.234,14.041 20.413,22.687 -9.818,7.353 33.306,27.492 -11.759,8.124 42.631999,19.939 -10.825,9.747 48.291,8.078 -7.526,10.307 48.758,-4.531 -3.997,11.725 53.916,-18.153 -2.76,13.357 48.077,-34.345 1.479,13.562 34.087,-48.576 7.478,14.206 15.187,-58.89 10.391,8.533 -2.14,-57.884 13.814,5.13 -21.082,-51.204 13.404,0.048 -33.696,-42.131 15.312,-1.366 -47.026,-32.831002 14.255,-8.399 -54.817,-14.682 9.257,-11.695 -49.625,0.352 0.6,-13.337 -38.537,14.084 -1.597,-12.689 -29.984,21.429 -6.446,-10.852 -22.59,26.504 -7.021,-9.572 -18.923,30.294 -9.595999,-8.744 -16.754,30.138002 c 31.509999,10.197 54.979999,37.951 59.126999,71.547 0.404,0.087 -22.37,31.257 10.955,57.85 -0.576,-2.985 -6.113,-53.902 47.496,-57.61 26.668,-1.844 48.4,21.666 48.4,48.399 0,8.184 -2.05,15.883 -5.636,22.64 -15.927,29.611 -64.858,30.755 -80.429,30.596 -45.154,-0.459 -104.051999,-51.521 -104.051999,-51.521 z"
id="path46" /></svg>
inkscape:document-units="mm"
showgrid="false" />
<defs
id="defs417" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-13.119542,-5.9258171)">
<path
d="m 213.66176,90.072122 c 4.95655,0 8.97383,4.018046 8.97383,8.973827 0,4.956581 -4.01728,8.974621 -8.97383,8.974621 -4.95657,0 -8.97462,-4.01804 -8.97462,-8.974621 0,-4.955781 4.01805,-8.973827 8.97462,-8.973827 z m 35.2316,37.450998 c -0.90048,29.80928 -23.66033,69.21262 -54.51292,79.34466 -36.04206,11.836 -63.40991,-5.92226 -72.08409,-26.74061 -6.75754,-16.21966 -1.65117,-35.62363 10.96266,-43.83669 10.6506,-6.93533 30.48543,-8.76736 47.15454,2.19144 -5.85627,-15.34246 -21.62491,-25.4256 -35.59101,-28.49424 -13.96613,-3.06867 -28.38324,0.43858 -38.74504,5.69946 13.29071,-14.68572 44.40801,-28.946049 78.24077,-10.95958 22.67676,12.05491 32.43775,28.93208 42.0489,51.72763 C 251.59637,117.87858 234.026,71.411066 203.39074,43.794029 172.15544,15.636686 129.95516,4.340214 97.668803,6.103155 108.32483,12.678273 120.84625,22.06586 132.41209,33.053363 81.298533,26.697169 39.174705,38.314245 13.119542,73.749217 27.67508,70.878527 46.868833,69.073666 65.974711,70.016861 28.737658,96.252107 7.1124298,140.38147 18.105298,186.43137 c 6.718497,-11.74129 16.767711,-25.84558 28.726275,-38.62863 -3.677175,34.36994 1.42836,80.83745 45.62293,110.85478 -2.25587,-9.42394 -4.08014,-20.88443 -4.91466,-33.0154 20.673197,16.1282 50.685067,29.42205 87.917917,20.24096 65.77679,-16.21975 83.34719,-79.78335 73.4356,-118.35996"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0776283"
id="path32" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -1,39 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="900.82861"
height="955.20648"
viewBox="0 0 238.34422 252.7317"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 399.99999 400.00002"
enable-background="new 0 0 419.528 419.528"
xml:space="preserve"
id="svg52"
sodipodi:docname="pangolin_orange.svg"
width="400"
height="400"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
id="svg420"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs56" /><sodipodi:namedview
id="namedview54"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.9583914"
inkscape:cx="127.40048"
inkscape:cy="262.71561"
inkscape:window-width="1436"
inkscape:window-height="1236"
inkscape:window-x="2208"
inkscape:window-y="511"
inkscape:window-maximized="0"
inkscape:current-layer="svg52" /><path
d="m 62.232921,184.91974 c 0,2.431 -1.97,4.402 -4.399,4.402 -2.429,0 -4.399,-1.972 -4.399,-4.402 0,-2.429 1.97,-4.399 4.399,-4.399 2.429,-10e-4 4.399,1.97 4.399,4.399 z m 58.993999,-4.821 c -25.943999,-2.826 -38.978999,7.453 -71.181999,31.357 -27.572,20.467 -32.767,4.381 -31.748,-2.614 1.499,-10.282 25.222,-58.573 48.079,-88.461 28.273,7.34 49.869999,30.727 54.850999,59.718 z m -55.915999,4.821 c 0,-4.131 -3.349,-7.478 -7.478,-7.478 -4.129,0 -7.478,3.347 -7.478,7.478 0,4.131 3.349,7.481 7.478,7.481 4.13,0 7.478,-3.35 7.478,-7.481 z m -15.032,48.424 -0.234,14.041 20.413,22.687 -9.818,7.353 33.306,27.492 -11.759,8.124 42.631999,19.939 -10.825,9.747 48.291,8.078 -7.526,10.307 48.758,-4.531 -3.997,11.725 53.916,-18.153 -2.76,13.357 48.077,-34.345 1.479,13.562 34.087,-48.576 7.478,14.206 15.187,-58.89 10.391,8.533 -2.14,-57.884 13.814,5.13 -21.082,-51.204 13.404,0.048 -33.696,-42.131 15.312,-1.366 -47.026,-32.831002 14.255,-8.399 -54.817,-14.682 9.257,-11.695 -49.625,0.352 0.6,-13.337 -38.537,14.084 -1.597,-12.689 -29.984,21.429 -6.446,-10.852 -22.59,26.504 -7.021,-9.572 -18.923,30.294 -9.595999,-8.744 -16.754,30.138002 c 31.509999,10.197 54.979999,37.951 59.126999,71.547 0.404,0.087 -22.37,31.257 10.955,57.85 -0.576,-2.985 -6.113,-53.902 47.496,-57.61 26.668,-1.844 48.4,21.666 48.4,48.399 0,8.184 -2.05,15.883 -5.636,22.64 -15.927,29.611 -64.858,30.755 -80.429,30.596 -45.154,-0.459 -104.051999,-51.521 -104.051999,-51.521 z"
id="path46"
style="fill:#f97315;fill-opacity:1" /></svg>
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs417" />
<g
id="layer1"
transform="translate(-13.119542,-5.9258171)">
<path
d="m 213.66176,90.072122 c 4.95655,0 8.97383,4.018046 8.97383,8.973827 0,4.956581 -4.01728,8.974621 -8.97383,8.974621 -4.95657,0 -8.97462,-4.01804 -8.97462,-8.974621 0,-4.955781 4.01805,-8.973827 8.97462,-8.973827 z m 35.2316,37.450998 c -0.90048,29.80928 -23.66033,69.21262 -54.51292,79.34466 -36.04206,11.836 -63.40991,-5.92226 -72.08409,-26.74061 -6.75754,-16.21966 -1.65117,-35.62363 10.96266,-43.83669 10.6506,-6.93533 30.48543,-8.76736 47.15454,2.19144 -5.85627,-15.34246 -21.62491,-25.4256 -35.59101,-28.49424 -13.96613,-3.06867 -28.38324,0.43858 -38.74504,5.69946 13.29071,-14.68572 44.40801,-28.946049 78.24077,-10.95958 22.67676,12.05491 32.43775,28.93208 42.0489,51.72763 C 251.59637,117.87858 234.026,71.411066 203.39074,43.794029 172.15544,15.636686 129.95516,4.340214 97.668803,6.103155 108.32483,12.678273 120.84625,22.06586 132.41209,33.053363 81.298533,26.697169 39.174705,38.314245 13.119542,73.749217 27.67508,70.878527 46.868833,69.073666 65.974711,70.016861 28.737658,96.252107 7.1124298,140.38147 18.105298,186.43137 c 6.718497,-11.74129 16.767711,-25.84558 28.726275,-38.62863 -3.677175,34.36994 1.42836,80.83745 45.62293,110.85478 -2.25587,-9.42394 -4.08014,-20.88443 -4.91466,-33.0154 20.673197,16.1282 50.685067,29.42205 87.917917,20.24096 65.77679,-16.21975 83.34719,-79.78335 73.4356,-118.35996"
style="fill:#f36118;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0776283"
id="path32" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -268,7 +268,7 @@ PersistentKeepalive = 5`
- NEWT_ID=${siteDefaults?.newtId}
- NEWT_SECRET=${siteDefaults?.newtSecret}`;
const newtConfigDockerRun = `docker run -it fosrl/newt --id ${siteDefaults?.newtId} --secret ${siteDefaults?.newtSecret} --endpoint ${env.app.dashboardUrl}`;
const newtConfigDockerRun = `docker run -dit fosrl/newt --id ${siteDefaults?.newtId} --secret ${siteDefaults?.newtSecret} --endpoint ${env.app.dashboardUrl}`;
return loadingPage ? (
<LoaderPlaceholder height="300px" />

View file

@ -257,7 +257,7 @@ PersistentKeepalive = 5`;
- NEWT_SECRET=${secret}`
],
"Docker Run": [
`docker run -it fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}`
`docker run -dit fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}`
]
},
podman: {
@ -280,7 +280,7 @@ Restart=always
WantedBy=default.target`
],
"Podman Run": [
`podman run -it docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}`
`podman run -dit docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}`
]
}
};

View file

@ -45,8 +45,8 @@ export default function DashboardLoginForm({
<Image
src={`/logo/pangolin_orange.svg`}
alt="Pangolin Logo"
width="100"
height="100"
width={100}
height={100}
/>
</div>
<div className="text-center space-y-1">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
"use client";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { SidebarNav } from "@app/components/SidebarNav";
import { OrgSelector } from "@app/components/OrgSelector";
import { cn } from "@app/lib/cn";
@ -23,6 +23,7 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { useUserContext } from "@app/hooks/useUserContext";
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
import { useTheme } from "next-themes";
interface LayoutProps {
children: React.ReactNode;
@ -61,6 +62,30 @@ export function Layout({
const { user } = useUserContext();
const { isUnlocked } = useLicenseStatusContext();
const { theme } = useTheme();
const [path, setPath] = useState<string>(""); // Default logo path
useEffect(() => {
function getPath() {
let lightOrDark = theme;
if (theme === "system" || !theme) {
lightOrDark = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
}
if (lightOrDark === "light") {
return "/logo/word_mark_black.png";
}
return "/logo/word_mark_white.png";
}
setPath(getPath());
}, [theme, env]);
return (
<div className="flex flex-col h-screen overflow-hidden">
{/* Full width header */}
@ -139,12 +164,14 @@ export function Layout({
href="/"
className="flex items-center hidden md:block"
>
<Image
src="/logo/pangolin_orange.svg"
alt="Pangolin Logo"
width={35}
height={35}
/>
{path && (
<Image
src={path}
alt="Pangolin Logo"
width={110}
height={25}
/>
)}
</Link>
{showBreadcrumbs && (
<div className="hidden md:block overflow-x-auto scrollbar-hide">