Skip to content

Commit 6e71047

Browse files
authored
Refactor Buttons component to use a ButtonLink for cleaner code, simplifying the source URL generation and layout (#371)
* Refactor Buttons component to use a ButtonLink for cleaner code, simplifying the source URL generation and layout * Refactor DefaultPassword component to simplify credential handling and enhance code readability with map function * Refactor DefaultSettings component to improve resource display logic and enhance readability using a new ResourceDisplay subcomponent
1 parent 9f80cec commit 6e71047

File tree

3 files changed

+104
-118
lines changed

3 files changed

+104
-118
lines changed

frontend/src/app/scripts/_components/ScriptItems/Buttons.tsx

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,53 @@ import { BookOpenText, Code, Globe } from "lucide-react";
55
import Link from "next/link";
66

77
const generateSourceUrl = (slug: string, type: string) => {
8-
if (type === "ct") {
9-
return `https://raw.githubusercontent.com/community-scripts/${basePath}/main/install/${slug}-install.sh`;
10-
} else {
11-
return `https://raw.githubusercontent.com/community-scripts/${basePath}/main/${type}/${slug}.sh`;
12-
}
8+
const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`;
9+
return type === "ct"
10+
? `${baseUrl}/install/${slug}-install.sh`
11+
: `${baseUrl}/${type}/${slug}.sh`;
1312
};
1413

14+
interface ButtonLinkProps {
15+
href: string;
16+
icon: React.ReactNode;
17+
text: string;
18+
}
19+
20+
const ButtonLink = ({ href, icon, text }: ButtonLinkProps) => (
21+
<Button variant="secondary" asChild>
22+
<Link target="_blank" href={href}>
23+
<span className="flex items-center gap-2">
24+
{icon}
25+
{text}
26+
</span>
27+
</Link>
28+
</Button>
29+
);
30+
1531
export default function Buttons({ item }: { item: Script }) {
32+
const buttons = [
33+
item.website && {
34+
href: item.website,
35+
icon: <Globe className="h-4 w-4" />,
36+
text: "Website",
37+
},
38+
item.documentation && {
39+
href: item.documentation,
40+
icon: <BookOpenText className="h-4 w-4" />,
41+
text: "Documentation",
42+
},
43+
{
44+
href: generateSourceUrl(item.slug, item.type),
45+
icon: <Code className="h-4 w-4" />,
46+
text: "Source Code",
47+
},
48+
].filter(Boolean) as ButtonLinkProps[];
49+
1650
return (
1751
<div className="flex flex-wrap justify-end gap-2">
18-
{item.website && (
19-
<Button variant="secondary" asChild>
20-
<Link target="_blank" href={item.website}>
21-
<span className="flex items-center gap-2">
22-
<Globe className="h-4 w-4" /> Website
23-
</span>
24-
</Link>
25-
</Button>
26-
)}
27-
{item.documentation && (
28-
<Button variant="secondary" asChild>
29-
<Link target="_blank" href={item.documentation}>
30-
<span className="flex items-center gap-2">
31-
<BookOpenText className="h-4 w-4" />
32-
Documentation
33-
</span>
34-
</Link>
35-
</Button>
36-
)}
37-
{
38-
<Button variant="secondary" asChild>
39-
<Link target="_blank" href={generateSourceUrl(item.slug, item.type)}>
40-
<span className="flex items-center gap-2">
41-
<Code className="h-4 w-4" />
42-
Source Code
43-
</span>
44-
</Link>
45-
</Button>
46-
}
52+
{buttons.map((props, index) => (
53+
<ButtonLink key={index} {...props} />
54+
))}
4755
</div>
4856
);
4957
}

frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,39 @@ import { Separator } from "@/components/ui/separator";
44
import { Script } from "@/lib/types";
55

66
export default function DefaultPassword({ item }: { item: Script }) {
7-
const hasDefaultLogin =
8-
item.default_credentials.username && item.default_credentials.password;
7+
const { username, password } = item.default_credentials;
8+
const hasDefaultLogin = username && password;
9+
10+
if (!hasDefaultLogin) return null;
11+
12+
const copyCredential = (type: "username" | "password") => {
13+
handleCopy(type, item.default_credentials[type] ?? "");
14+
};
915

1016
return (
11-
<div>
12-
{hasDefaultLogin && (
13-
<div className="mt-4 rounded-lg border bg-accent/50">
14-
<div className="flex gap-3 px-4 py-2">
15-
<h2 className="text-lg font-semibold">Default Login Credentials</h2>
16-
</div>
17-
<Separator className="w-full"></Separator>
18-
<div className="flex flex-col gap-2 p-4">
19-
<p className="mb-2 text-sm">
20-
You can use the following credentials to login to the {""}
21-
{item.name} {item.type}.
22-
</p>
23-
<div className="text-sm">
24-
Username:{" "}
25-
<Button
26-
variant={"secondary"}
27-
size={"null"}
28-
onClick={() =>
29-
handleCopy(
30-
"username",
31-
item.default_credentials.username ?? "",
32-
)
33-
}
34-
>
35-
{item.default_credentials.username}
36-
</Button>
37-
</div>
38-
<div className="text-sm">
39-
Password:{" "}
40-
<Button
41-
variant={"secondary"}
42-
size={"null"}
43-
onClick={() =>
44-
handleCopy(
45-
"password",
46-
item.default_credentials.password ?? "",
47-
)
48-
}
49-
>
50-
{item.default_credentials.password}
51-
</Button>
52-
</div>
17+
<div className="mt-4 rounded-lg border bg-accent/50">
18+
<div className="flex gap-3 px-4 py-2">
19+
<h2 className="text-lg font-semibold">Default Login Credentials</h2>
20+
</div>
21+
<Separator className="w-full" />
22+
<div className="flex flex-col gap-2 p-4">
23+
<p className="mb-2 text-sm">
24+
You can use the following credentials to login to the {item.name}{" "}
25+
{item.type}.
26+
</p>
27+
{["username", "password"].map((type) => (
28+
<div key={type} className="text-sm">
29+
{type.charAt(0).toUpperCase() + type.slice(1)}:{" "}
30+
<Button
31+
variant="secondary"
32+
size="null"
33+
onClick={() => copyCredential(type as "username" | "password")}
34+
>
35+
{item.default_credentials[type as "username" | "password"]}
36+
</Button>
5337
</div>
54-
</div>
55-
)}
38+
))}
39+
</div>
5640
</div>
5741
);
5842
}

frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,50 @@
11
import { Script } from "@/lib/types";
22

33
export default function DefaultSettings({ item }: { item: Script }) {
4+
const getDisplayValueFromRAM = (ram: number) =>
5+
ram >= 1024 ? `${Math.floor(ram / 1024)}GB` : `${ram}MB`;
6+
7+
const ResourceDisplay = ({
8+
settings,
9+
title,
10+
}: {
11+
settings: (typeof item.install_methods)[0];
12+
title: string;
13+
}) => {
14+
const { cpu, ram, hdd } = settings.resources;
15+
return (
16+
<div>
17+
<h2 className="text-md font-semibold">{title}</h2>
18+
<p className="text-sm text-muted-foreground">CPU: {cpu}vCPU</p>
19+
<p className="text-sm text-muted-foreground">
20+
RAM: {getDisplayValueFromRAM(ram ?? 0)}
21+
</p>
22+
<p className="text-sm text-muted-foreground">HDD: {hdd}GB</p>
23+
</div>
24+
);
25+
};
26+
427
const defaultSettings = item.install_methods.find(
528
(method) => method.type === "default",
629
);
7-
8-
const defaultSettingsAvailable =
9-
defaultSettings?.resources.cpu ||
10-
defaultSettings?.resources.ram ||
11-
defaultSettings?.resources.hdd;
12-
1330
const defaultAlpineSettings = item.install_methods.find(
1431
(method) => method.type === "alpine",
1532
);
1633

17-
const getDisplayValueFromRAM = (ram: number) => {
18-
if (ram >= 1024) {
19-
return (ram / 1024).toFixed(0) + "GB";
20-
}
21-
return ram + "MB";
22-
};
34+
const hasDefaultSettings =
35+
defaultSettings?.resources &&
36+
Object.values(defaultSettings.resources).some(Boolean);
2337

2438
return (
2539
<>
26-
{defaultSettingsAvailable && (
27-
<div>
28-
<h2 className="text-md font-semibold">Default settings</h2>
29-
<p className="text-sm text-muted-foreground">
30-
CPU: {defaultSettings?.resources.cpu}vCPU
31-
</p>
32-
<p className="text-sm text-muted-foreground">
33-
RAM: {getDisplayValueFromRAM(defaultSettings?.resources.ram ?? 0)}
34-
</p>
35-
<p className="text-sm text-muted-foreground">
36-
HDD: {defaultSettings?.resources.hdd}GB
37-
</p>
38-
</div>
40+
{hasDefaultSettings && (
41+
<ResourceDisplay settings={defaultSettings} title="Default settings" />
3942
)}
4043
{defaultAlpineSettings && (
41-
<div>
42-
<h2 className="text-md font-semibold">Default Alpine settings</h2>
43-
<p className="text-sm text-muted-foreground">
44-
CPU: {defaultAlpineSettings?.resources.cpu}vCPU
45-
</p>
46-
<p className="text-sm text-muted-foreground">
47-
RAM:{" "}
48-
{getDisplayValueFromRAM(defaultAlpineSettings?.resources.ram ?? 0)}
49-
</p>
50-
<p className="text-sm text-muted-foreground">
51-
HDD: {defaultAlpineSettings?.resources.hdd}GB
52-
</p>
53-
</div>
44+
<ResourceDisplay
45+
settings={defaultAlpineSettings}
46+
title="Default Alpine settings"
47+
/>
5448
)}
5549
</>
5650
);

0 commit comments

Comments
 (0)