mirror of
https://github.com/henrygd/beszel.git
synced 2026-08-19 08:47:46 +02:00
Compare commits
4 Commits
v0.12.0
...
3ac0b185d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ac0b185d1 | ||
|
|
1e675cabb5 | ||
|
|
5f44965c2c | ||
|
|
f080929296 |
@@ -173,7 +173,6 @@ brews:
|
|||||||
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
||||||
keep_alive true
|
keep_alive true
|
||||||
restart_delay 5
|
restart_delay 5
|
||||||
name beszel-agent
|
|
||||||
process_type :background
|
process_type :background
|
||||||
|
|
||||||
winget:
|
winget:
|
||||||
@@ -204,7 +203,7 @@ winget:
|
|||||||
name: beszel-winget
|
name: beszel-winget
|
||||||
branch: henrygd.beszel-agent-{{ .Version }}
|
branch: henrygd.beszel-agent-{{ .Version }}
|
||||||
pull_request:
|
pull_request:
|
||||||
enabled: false
|
enabled: true
|
||||||
draft: false
|
draft: false
|
||||||
base:
|
base:
|
||||||
owner: microsoft
|
owner: microsoft
|
||||||
|
|||||||
@@ -9,35 +9,30 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// getDataDir returns the path to the data directory for the agent and an error
|
// getDataDir returns the path to the data directory for the agent and an error
|
||||||
// if the directory is not valid. Pass an empty string to attempt to find the
|
// if the directory is not valid. Attempts to find the optimal data directory if
|
||||||
// optimal data directory.
|
// no data directories are provided.
|
||||||
func getDataDir(dataDir string) (string, error) {
|
func getDataDir(dataDirs ...string) (string, error) {
|
||||||
if dataDir == "" {
|
if len(dataDirs) > 0 {
|
||||||
dataDir, _ = GetEnv("DATA_DIR")
|
return testDataDirs(dataDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dataDir, _ := GetEnv("DATA_DIR")
|
||||||
if dataDir != "" {
|
if dataDir != "" {
|
||||||
return testDataDirs([]string{dataDir})
|
dataDirs = append(dataDirs, dataDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirsToTry []string
|
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
dirsToTry = []string{
|
dataDirs = append(dataDirs,
|
||||||
filepath.Join(os.Getenv("APPDATA"), "beszel-agent"),
|
filepath.Join(os.Getenv("APPDATA"), "beszel-agent"),
|
||||||
filepath.Join(os.Getenv("LOCALAPPDATA"), "beszel-agent"),
|
filepath.Join(os.Getenv("LOCALAPPDATA"), "beszel-agent"),
|
||||||
}
|
)
|
||||||
} else {
|
} else {
|
||||||
homeDir, err := os.UserHomeDir()
|
dataDirs = append(dataDirs, "/var/lib/beszel-agent")
|
||||||
if err != nil {
|
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||||
return "", err
|
dataDirs = append(dataDirs, filepath.Join(homeDir, ".config", "beszel"))
|
||||||
}
|
|
||||||
dirsToTry = []string{
|
|
||||||
"/var/lib/beszel-agent",
|
|
||||||
filepath.Join(homeDir, ".config", "beszel"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return testDataDirs(dirsToTry)
|
return testDataDirs(dataDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDataDirs(paths []string) (string, error) {
|
func testDataDirs(paths []string) (string, error) {
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ func TestGetDataDir(t *testing.T) {
|
|||||||
oldValue := os.Getenv("DATA_DIR")
|
oldValue := os.Getenv("DATA_DIR")
|
||||||
defer func() {
|
defer func() {
|
||||||
if oldValue == "" {
|
if oldValue == "" {
|
||||||
os.Unsetenv("DATA_DIR")
|
os.Unsetenv("BESZEL_AGENT_DATA_DIR")
|
||||||
} else {
|
} else {
|
||||||
os.Setenv("DATA_DIR", oldValue)
|
os.Setenv("BESZEL_AGENT_DATA_DIR", oldValue)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
os.Setenv("DATA_DIR", tempDir)
|
os.Setenv("BESZEL_AGENT_DATA_DIR", tempDir)
|
||||||
|
|
||||||
result, err := getDataDir("")
|
result, err := getDataDir()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tempDir, result)
|
assert.Equal(t, tempDir, result)
|
||||||
})
|
})
|
||||||
@@ -79,7 +79,7 @@ func TestGetDataDir(t *testing.T) {
|
|||||||
|
|
||||||
// This will try platform-specific defaults, which may or may not work
|
// This will try platform-specific defaults, which may or may not work
|
||||||
// We're mainly testing that it doesn't panic and returns some result
|
// We're mainly testing that it doesn't panic and returns some result
|
||||||
result, err := getDataDir("")
|
result, err := getDataDir()
|
||||||
// We don't assert success/failure here since it depends on system permissions
|
// We don't assert success/failure here since it depends on system permissions
|
||||||
// Just verify we get a string result if no error
|
// Just verify we get a string result if no error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { t } from "@lingui/core/macro";
|
import { t } from "@lingui/core/macro"
|
||||||
import { Trans } from "@lingui/react/macro";
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { buttonVariants } from "@/components/ui/button"
|
import { buttonVariants } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
@@ -43,6 +43,14 @@ const showLoginFaliedToast = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getAuthProviderIcon = (provider: AuthProviderInfo) => {
|
||||||
|
let { name } = provider
|
||||||
|
if (name.startsWith("oidc")) {
|
||||||
|
name = "oidc"
|
||||||
|
}
|
||||||
|
return prependBasePath(`/_/images/oauth2/${name}.svg`)
|
||||||
|
}
|
||||||
|
|
||||||
export function UserAuthForm({
|
export function UserAuthForm({
|
||||||
className,
|
className,
|
||||||
isFirstRun,
|
isFirstRun,
|
||||||
@@ -165,8 +173,8 @@ export function UserAuthForm({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("grid gap-6", className)} {...props}>
|
<div className={cn("grid gap-6", className)} {...props}>
|
||||||
{passwordEnabled && (
|
{passwordEnabled && (
|
||||||
<>
|
<>
|
||||||
<form onSubmit={handleSubmit} onChange={() => setErrors({})}>
|
<form onSubmit={handleSubmit} onChange={() => setErrors({})}>
|
||||||
<div className="grid gap-2.5">
|
<div className="grid gap-2.5">
|
||||||
@@ -242,20 +250,20 @@ export function UserAuthForm({
|
|||||||
</form>
|
</form>
|
||||||
{(isFirstRun || oauthEnabled) && (
|
{(isFirstRun || oauthEnabled) && (
|
||||||
// only show 'continue with' during onboarding or if we have auth providers
|
// only show 'continue with' during onboarding or if we have auth providers
|
||||||
(<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute inset-0 flex items-center">
|
<div className="absolute inset-0 flex items-center">
|
||||||
<span className="w-full border-t" />
|
<span className="w-full border-t" />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex justify-center text-xs uppercase">
|
<div className="relative flex justify-center text-xs uppercase">
|
||||||
<span className="bg-background px-2 text-muted-foreground">
|
<span className="bg-background px-2 text-muted-foreground">
|
||||||
<Trans>Or continue with</Trans>
|
<Trans>Or continue with</Trans>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{oauthEnabled && (
|
{oauthEnabled && (
|
||||||
<div className="grid gap-2 -mt-1">
|
<div className="grid gap-2 -mt-1">
|
||||||
{authMethods.oauth2.providers.map((provider) => (
|
{authMethods.oauth2.providers.map((provider) => (
|
||||||
<button
|
<button
|
||||||
@@ -273,7 +281,7 @@ export function UserAuthForm({
|
|||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
className="me-2 h-4 w-4 dark:brightness-0 dark:invert"
|
className="me-2 h-4 w-4 dark:brightness-0 dark:invert"
|
||||||
src={prependBasePath(`/_/images/oauth2/${provider.name}.svg`)}
|
src={getAuthProviderIcon(provider)}
|
||||||
alt=""
|
alt=""
|
||||||
// onError={(e) => {
|
// onError={(e) => {
|
||||||
// e.currentTarget.src = "/static/lock.svg"
|
// e.currentTarget.src = "/static/lock.svg"
|
||||||
@@ -285,16 +293,16 @@ export function UserAuthForm({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!oauthEnabled && isFirstRun && (
|
{!oauthEnabled && isFirstRun && (
|
||||||
// only show GitHub button / dialog during onboarding
|
// only show GitHub button / dialog during onboarding
|
||||||
(<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<button type="button" className={cn(buttonVariants({ variant: "outline" }))}>
|
<button type="button" className={cn(buttonVariants({ variant: "outline" }))}>
|
||||||
<img className="me-2 h-4 w-4 dark:invert" src={prependBasePath("/_/images/oauth2/github.svg")} alt="" />
|
<img className="me-2 h-4 w-4 dark:invert" src={prependBasePath("/_/images/oauth2/github.svg")} alt="" />
|
||||||
<span className="translate-y-[1px]">GitHub</span>
|
<span className="translate-y-[1px]">GitHub</span>
|
||||||
</button>
|
</button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent style={{ maxWidth: 440, width: "90%" }}>
|
<DialogContent style={{ maxWidth: 440, width: "90%" }}>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<Trans>OAuth 2 / OIDC support</Trans>
|
<Trans>OAuth 2 / OIDC support</Trans>
|
||||||
@@ -318,9 +326,9 @@ export function UserAuthForm({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>)
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
{passwordEnabled && !isFirstRun && (
|
{passwordEnabled && !isFirstRun && (
|
||||||
<Link
|
<Link
|
||||||
href={getPagePath($router, "forgot_password")}
|
href={getPagePath($router, "forgot_password")}
|
||||||
className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity"
|
className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity"
|
||||||
@@ -328,6 +336,6 @@ export function UserAuthForm({
|
|||||||
<Trans>Forgot password?</Trans>
|
<Trans>Forgot password?</Trans>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ import { Dialog } from "../ui/dialog"
|
|||||||
type ViewMode = "table" | "grid"
|
type ViewMode = "table" | "grid"
|
||||||
|
|
||||||
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||||
const val = (info.getValue() as number) || 0
|
const val = Number(info.getValue()) || 0
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2 items-center tabular-nums tracking-tight">
|
<div className="flex gap-2 items-center tabular-nums tracking-tight">
|
||||||
<span className="min-w-8">{decimalString(val, 1)}%</span>
|
<span className="min-w-8">{decimalString(val, val >= 10 ? 1 : 2)}%</span>
|
||||||
<span className="grow min-w-8 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
|
<span className="grow min-w-8 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -189,7 +189,7 @@ export default function SystemsTable() {
|
|||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: ({ info }) => decimalString(info.cpu, info.cpu >= 10 ? 1 : 2),
|
accessorFn: ({ info }) => info.cpu,
|
||||||
id: "cpu",
|
id: "cpu",
|
||||||
name: () => t`CPU`,
|
name: () => t`CPU`,
|
||||||
cell: CellFormatter,
|
cell: CellFormatter,
|
||||||
@@ -198,7 +198,7 @@ export default function SystemsTable() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// accessorKey: "info.mp",
|
// accessorKey: "info.mp",
|
||||||
accessorFn: (originalRow) => originalRow.info.mp,
|
accessorFn: ({ info }) => info.mp,
|
||||||
id: "memory",
|
id: "memory",
|
||||||
name: () => t`Memory`,
|
name: () => t`Memory`,
|
||||||
cell: CellFormatter,
|
cell: CellFormatter,
|
||||||
@@ -206,7 +206,7 @@ export default function SystemsTable() {
|
|||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.dp,
|
accessorFn: ({ info }) => info.dp,
|
||||||
id: "disk",
|
id: "disk",
|
||||||
name: () => t`Disk`,
|
name: () => t`Disk`,
|
||||||
cell: CellFormatter,
|
cell: CellFormatter,
|
||||||
@@ -214,7 +214,7 @@ export default function SystemsTable() {
|
|||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.g,
|
accessorFn: ({ info }) => info.g,
|
||||||
id: "gpu",
|
id: "gpu",
|
||||||
name: () => "GPU",
|
name: () => "GPU",
|
||||||
cell: CellFormatter,
|
cell: CellFormatter,
|
||||||
@@ -281,7 +281,7 @@ export default function SystemsTable() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.dt,
|
accessorFn: ({ info }) => info.dt,
|
||||||
id: "temp",
|
id: "temp",
|
||||||
name: () => t({ message: "Temp", comment: "Temperature label in systems table" }),
|
name: () => t({ message: "Temp", comment: "Temperature label in systems table" }),
|
||||||
size: 50,
|
size: 50,
|
||||||
@@ -303,7 +303,7 @@ export default function SystemsTable() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.v,
|
accessorFn: ({ info }) => info.v,
|
||||||
id: "agent",
|
id: "agent",
|
||||||
name: () => t`Agent`,
|
name: () => t`Agent`,
|
||||||
// invertSorting: true,
|
// invertSorting: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user