1
0
mirror of https://github.com/community-scripts/ProxmoxVE.git synced 2025-04-19 13:58:06 +00:00

Move Scripts to Tools / Add-Ons

This commit is contained in:
CanbiZ 2025-04-09 09:57:56 +02:00
parent 3ab2ecc3ef
commit 3dbc7f80d2
77 changed files with 1262 additions and 1413 deletions

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE LXC IP-Tag",
"slug": "add-lxc-iptag",
"categories": [
1
],
"categories": [1],
"date_created": "2024-12-16",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/add-lxc-iptag.sh",
"script": "tools/pve/add-lxc-iptag.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "NetBird",
"slug": "add-netbird-lxc",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-19",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/add-netbird-lxc.sh",
"script": "tools/addon/add-netbird-lxc.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Tailscale",
"slug": "add-tailscale-lxc",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/add-tailscale-lxc.sh",
"script": "tools/addon/add-tailscale-lxc.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "All Templates",
"slug": "all-templates",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/all-templates.sh",
"script": "tools/addon/all-templates.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE LXC Cleaner",
"slug": "clean-lxcs",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/clean-lxcs.sh",
"script": "tools/pve/clean-lxcs.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox Clean Orphaned LVM",
"slug": "clean-orphaned-lvm",
"categories": [
1
],
"categories": [1],
"date_created": "2025-01-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/clean-orphaned-lvm.sh",
"script": "tools/pve/clean-orphaned-lvm.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,11 +1,7 @@
{
"name": "VS Code Server",
"slug": "code-server",
"categories": [
1,
20,
11
],
"categories": [1, 20, 11],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -18,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/code-server.sh",
"script": "tools/addon/code-server.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Cron LXC Updater",
"slug": "cron-update-lxcs",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/cron-update-lxcs.sh",
"script": "tools/pve/cron-update-lxcs.sh",
"resources": {
"cpu": null,
"ram": null,
@ -39,6 +37,5 @@
"text": "To exclude LXCs from updating, edit the crontab using `crontab -e` and add CTID as shown in the example below:\n\n\n\n`0 0 * * 0 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /bin/bash -c '$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/update-lxcs-cron.sh)' -s 103 111 >>/var/log/update-lxcs-cron.log 2>/dev/null`",
"type": "info"
}
]
}

View File

@ -1,9 +1,7 @@
{
"name": "CrowdSec",
"slug": "crowdsec",
"categories": [
6
],
"categories": [6],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/crowdsec.sh",
"script": "tools/addon/crowdsec.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "File Browser",
"slug": "filebrowser",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/filebrowser.sh",
"script": "tools/addon/filebrowser.sh",
"resources": {
"cpu": null,
"ram": null,
@ -27,7 +25,7 @@
},
{
"type": "alpine",
"script": "misc/filebrowser.sh",
"script": "tools/addon/filebrowser.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE LXC Filesystem Trim",
"slug": "fstrim",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/fstrim.sh",
"script": "tools/pve/fstrim.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Glances",
"slug": "glances",
"categories": [
9
],
"categories": [9],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/glances.sh",
"script": "tools/addon/glances.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Host Backup",
"slug": "host-backup",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/host-backup.sh",
"script": "tools/pve/host-backup.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Kernel Clean",
"slug": "kernel-clean",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/kernel-clean.sh",
"script": "tools/pve/kernel-clean.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Kernel Pin",
"slug": "kernel-pin",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-08",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/kernel-pin.sh",
"script": "tools/pve/kernel-pin.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Container LXC Deletion",
"slug": "lxc-delete",
"categories": [
1
],
"categories": [1],
"date_created": "2025-01-21",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/lxc-delete.sh",
"script": "tools/pve/lxc-delete.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Processor Microcode",
"slug": "microcode",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/microcode.sh",
"script": "tools/pve/microcode.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Monitor-All",
"slug": "monitor-all",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/monitor-all.sh",
"script": "tools/pve/monitor-all.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Netdata",
"slug": "netdata",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/netdata.sh",
"script": "tools/addon/netdata.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "OliveTin",
"slug": "olivetin",
"categories": [
10
],
"categories": [10],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/olivetin.sh",
"script": "tools/addon/olivetin.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox Backup Server Processor Microcode",
"slug": "pbs-microcode",
"categories": [
1
],
"categories": [1],
"date_created": "2025-02-07",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/pbs_microcode.sh",
"script": "tools/pve/pbs_microcode.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox Backup Server Post Install",
"slug": "post-pbs-install",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/post-pbs-install.sh",
"script": "tools/pve/post-pbs-install.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox Mail Gateway Post Install",
"slug": "post-pmg-install",
"categories": [
1
],
"categories": [1],
"date_created": "2025-01-20",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/post-pmg-install.sh",
"script": "tools/pve/post-pmg-install.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE Post Install",
"slug": "post-pve-install",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-28",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/post-pve-install.sh",
"script": "tools/pve/post-pve-install.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE CPU Scaling Governor",
"slug": "scaling-governor",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/scaling-governor.sh",
"script": "tools/pve/scaling-governor.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox VE LXC Updater",
"slug": "update-lxcs",
"categories": [
1
],
"categories": [1],
"date_created": "2024-04-29",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/update-lxcs.sh",
"script": "tools/pve/update-lxcs.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Proxmox Update Repositories",
"slug": "update-repo",
"categories": [
1
],
"categories": [1],
"date_created": "2024-11-04",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/update-repo.sh",
"script": "tools/pve/update-repo.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,9 +1,7 @@
{
"name": "Webmin System Administration",
"slug": "webmin",
"categories": [
1
],
"categories": [1],
"date_created": "2024-05-02",
"type": "misc",
"updateable": false,
@ -16,7 +14,7 @@
"install_methods": [
{
"type": "default",
"script": "misc/webmin.sh",
"script": "tools/addon/webmin.sh",
"resources": {
"cpu": null,
"ram": null,

View File

@ -1,12 +1,12 @@
"use client";
import React, { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Category } from "@/lib/types";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
const defaultLogo = "/default-logo.png"; // Fallback logo path
const MAX_DESCRIPTION_LENGTH = 100; // Set max length for description
@ -17,11 +17,11 @@ const formattedBadge = (type: string) => {
case "vm":
return <Badge className="text-blue-500/75 border-blue-500/75 badge">VM</Badge>;
case "ct":
return (
<Badge className="text-yellow-500/75 border-yellow-500/75 badge">LXC</Badge>
);
case "misc":
return <Badge className="text-green-500/75 border-green-500/75 badge">MISC</Badge>;
return <Badge className="text-yellow-500/75 border-yellow-500/75 badge">LXC</Badge>;
case "pve":
return <Badge className="text-orange-500/75 border-orange-500/75 badge">PVE</Badge>;
case "addon":
return <Badge className="text-green-500/75 border-green-500/75 badge">ADDON</Badge>;
}
return null;
};
@ -100,9 +100,7 @@ const CategoryView = () => {
};
const truncateDescription = (text: string) => {
return text.length > MAX_DESCRIPTION_LENGTH
? `${text.slice(0, MAX_DESCRIPTION_LENGTH)}...`
: text;
return text.length > MAX_DESCRIPTION_LENGTH ? `${text.slice(0, MAX_DESCRIPTION_LENGTH)}...` : text;
};
const renderResources = (script: any) => {
@ -111,9 +109,24 @@ const CategoryView = () => {
const hdd = script.install_methods[0]?.resources.hdd;
const resourceParts = [];
if (cpu) resourceParts.push(<span key="cpu"><b>CPU:</b> {cpu}vCPU</span>);
if (ram) resourceParts.push(<span key="ram"><b>RAM:</b> {ram}MB</span>);
if (hdd) resourceParts.push(<span key="hdd"><b>HDD:</b> {hdd}GB</span>);
if (cpu)
resourceParts.push(
<span key="cpu">
<b>CPU:</b> {cpu}vCPU
</span>,
);
if (ram)
resourceParts.push(
<span key="ram">
<b>RAM:</b> {ram}MB
</span>,
);
if (hdd)
resourceParts.push(
<span key="hdd">
<b>HDD:</b> {hdd}GB
</span>,
);
return resourceParts.length > 0 ? (
<div className="text-sm text-gray-400">

View File

@ -24,8 +24,8 @@ export const ScriptSchema = z.object({
slug: z.string().min(1, "Slug is required"),
categories: z.array(z.number()),
date_created: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").min(1, "Date is required"),
type: z.enum(["vm", "ct", "misc", "turnkey"], {
errorMap: () => ({ message: "Type must be either 'vm', 'ct', 'misc' or 'turnkey'" })
type: z.enum(["vm", "ct", "pve", "addon", "turnkey"], {
errorMap: () => ({ message: "Type must be either 'vm', 'ct', 'pve', 'addon' or 'turnkey'" })
}),
updateable: z.boolean(),
privileged: z.boolean(),

View File

@ -5,18 +5,8 @@ import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { fetchCategories } from "@/lib/data";
@ -66,8 +56,7 @@ export default function JSONGenerator() {
.catch((error) => console.error("Error fetching categories:", error));
}, []);
const updateScript = useCallback(
(key: keyof Script, value: Script[keyof Script]) => {
const updateScript = useCallback((key: keyof Script, value: Script[keyof Script]) => {
setScript((prev) => {
const updated = { ...prev, [key]: value };
@ -86,9 +75,7 @@ export default function JSONGenerator() {
setZodErrors(result.success ? null : result.error);
return updated;
});
},
[],
);
}, []);
const handleCopy = useCallback(() => {
navigator.clipboard.writeText(JSON.stringify(script, null, 2));
@ -120,16 +107,13 @@ export default function JSONGenerator() {
);
const formattedDate = useMemo(
() =>
script.date_created ? format(script.date_created, "PPP") : undefined,
() => (script.date_created ? format(script.date_created, "PPP") : undefined),
[script.date_created],
);
const validationAlert = useMemo(
() => (
<Alert
className={cn("text-black", isValid ? "bg-green-100" : "bg-red-100")}
>
<Alert className={cn("text-black", isValid ? "bg-green-100" : "bg-red-100")}>
<AlertTitle>{isValid ? "Valid JSON" : "Invalid JSON"}</AlertTitle>
<AlertDescription>
{isValid
@ -160,21 +144,13 @@ export default function JSONGenerator() {
<Label>
Name <span className="text-red-500">*</span>
</Label>
<Input
placeholder="Example"
value={script.name}
onChange={(e) => updateScript("name", e.target.value)}
/>
<Input placeholder="Example" value={script.name} onChange={(e) => updateScript("name", e.target.value)} />
</div>
<div>
<Label>
Slug <span className="text-red-500">*</span>
</Label>
<Input
placeholder="example"
value={script.slug}
onChange={(e) => updateScript("slug", e.target.value)}
/>
<Input placeholder="example" value={script.slug} onChange={(e) => updateScript("slug", e.target.value)} />
</div>
</div>
<div>
@ -197,11 +173,7 @@ export default function JSONGenerator() {
onChange={(e) => updateScript("description", e.target.value)}
/>
</div>
<Categories
script={script}
setScript={setScript}
categories={categories}
/>
<Categories script={script} setScript={setScript} categories={categories} />
<div className="flex gap-2">
<div className="flex flex-col gap-2 w-full">
<Label>Date Created</Label>
@ -209,10 +181,7 @@ export default function JSONGenerator() {
<PopoverTrigger asChild className="flex-1">
<Button
variant={"outline"}
className={cn(
"pl-3 text-left font-normal w-full",
!script.date_created && "text-muted-foreground",
)}
className={cn("pl-3 text-left font-normal w-full", !script.date_created && "text-muted-foreground")}
>
{formattedDate || <span>Pick a date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
@ -230,38 +199,26 @@ export default function JSONGenerator() {
</div>
<div className="flex flex-col gap-2 w-full">
<Label>Type</Label>
<Select
value={script.type}
onValueChange={(value) => updateScript("type", value)}
>
<Select value={script.type} onValueChange={(value) => updateScript("type", value)}>
<SelectTrigger className="flex-1">
<SelectValue placeholder="Type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="ct">LXC Container</SelectItem>
<SelectItem value="vm">Virtual Machine</SelectItem>
<SelectItem value="misc">Miscellaneous</SelectItem>
<SelectItem value="pve">PVE-Tool</SelectItem>
<SelectItem value="addon">Add-On</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="w-full flex gap-5">
<div className="flex items-center space-x-2">
<Switch
checked={script.updateable}
onCheckedChange={(checked) =>
updateScript("updateable", checked)
}
/>
<Switch checked={script.updateable} onCheckedChange={(checked) => updateScript("updateable", checked)} />
<label>Updateable</label>
</div>
<div className="flex items-center space-x-2">
<Switch
checked={script.privileged}
onCheckedChange={(checked) =>
updateScript("privileged", checked)
}
/>
<Switch checked={script.privileged} onCheckedChange={(checked) => updateScript("privileged", checked)} />
<label>Privileged</label>
</div>
</div>
@ -269,12 +226,7 @@ export default function JSONGenerator() {
placeholder="Interface Port"
type="number"
value={script.interface_port || ""}
onChange={(e) =>
updateScript(
"interface_port",
e.target.value ? Number(e.target.value) : null,
)
}
onChange={(e) => updateScript("interface_port", e.target.value ? Number(e.target.value) : null)}
/>
<div className="flex gap-2">
<Input
@ -285,17 +237,10 @@ export default function JSONGenerator() {
<Input
placeholder="Documentation URL"
value={script.documentation || ""}
onChange={(e) =>
updateScript("documentation", e.target.value || null)
}
onChange={(e) => updateScript("documentation", e.target.value || null)}
/>
</div>
<InstallMethod
script={script}
setScript={setScript}
setIsValid={setIsValid}
setZodErrors={setZodErrors}
/>
<InstallMethod script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} />
<h3 className="text-xl font-semibold">Default Credentials</h3>
<Input
placeholder="Username"
@ -317,30 +262,17 @@ export default function JSONGenerator() {
})
}
/>
<Note
script={script}
setScript={setScript}
setIsValid={setIsValid}
setZodErrors={setZodErrors}
/>
<Note script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} />
</form>
</div>
<div className="w-1/2 p-4 bg-background overflow-y-auto">
{validationAlert}
<div className="relative">
<div className="absolute right-2 top-2 flex gap-1">
<Button
size="icon"
variant="outline"
onClick={handleCopy}
>
<Button size="icon" variant="outline" onClick={handleCopy}>
{isCopied ? <Check className="h-4 w-4" /> : <Clipboard className="h-4 w-4" />}
</Button>
<Button
size="icon"
variant="outline"
onClick={handleDownload}
>
<Button size="icon" variant="outline" onClick={handleDownload}>
<Download className="h-4 w-4" />
</Button>
</div>

View File

@ -1,12 +1,5 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { basePath, mostPopularScripts } from "@/config/siteConfig";
import { extractDate } from "@/lib/time";
import { Category, Script } from "@/lib/types";
@ -23,7 +16,8 @@ export const getDisplayValueFromType = (type: string) => {
return "LXC";
case "vm":
return "VM";
case "misc":
case "pve":
case "addon":
return "";
default:
return "";
@ -47,8 +41,7 @@ export function LatestScripts({ items }: { items: Category[] }) {
});
return Array.from(uniqueScriptsMap.values()).sort(
(a, b) =>
new Date(b.date_created).getTime() - new Date(a.date_created).getTime(),
(a, b) => new Date(b.date_created).getTime() - new Date(a.date_created).getTime(),
);
}, [items]);
@ -74,18 +67,12 @@ export function LatestScripts({ items }: { items: Category[] }) {
<h2 className="text-lg font-semibold">Newest Scripts</h2>
<div className="flex items-center justify-end gap-1">
{page > 1 && (
<div
className="cursor-pointer select-none p-2 text-sm font-semibold"
onClick={goToPreviousPage}
>
<div className="cursor-pointer select-none p-2 text-sm font-semibold" onClick={goToPreviousPage}>
Previous
</div>
)}
{endIndex < latestScripts.length && (
<div
onClick={goToNextPage}
className="cursor-pointer select-none p-2 text-sm font-semibold"
>
<div onClick={goToNextPage} className="cursor-pointer select-none p-2 text-sm font-semibold">
{page === 1 ? "More.." : "Next"}
</div>
)}
@ -94,10 +81,7 @@ export function LatestScripts({ items }: { items: Category[] }) {
)}
<div className="min-w flex w-full flex-row flex-wrap gap-4">
{latestScripts.slice(startIndex, endIndex).map((script) => (
<Card
key={script.slug}
className="min-w-[250px] flex-1 flex-grow bg-accent/30"
>
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader>
<CardTitle className="flex items-center gap-3">
<div className="flex h-16 w-16 min-w-16 items-center justify-center rounded-lg bg-accent p-1">
@ -107,10 +91,7 @@ export function LatestScripts({ items }: { items: Category[] }) {
height={64}
width={64}
alt=""
onError={(e) =>
((e.currentTarget as HTMLImageElement).src =
`/${basePath}/logo.png`)
}
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain"
/>
</div>
@ -126,9 +107,7 @@ export function LatestScripts({ items }: { items: Category[] }) {
</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="line-clamp-3 text-card-foreground">
{script.description}
</CardDescription>
<CardDescription className="line-clamp-3 text-card-foreground">{script.description}</CardDescription>
</CardContent>
<CardFooter className="">
<Button asChild variant="outline">
@ -151,9 +130,7 @@ export function LatestScripts({ items }: { items: Category[] }) {
export function MostViewedScripts({ items }: { items: Category[] }) {
const mostViewedScripts = items.reduce((acc: Script[], category) => {
const foundScripts = category.scripts.filter((script) =>
mostPopularScripts.includes(script.slug),
);
const foundScripts = category.scripts.filter((script) => mostPopularScripts.includes(script.slug));
return acc.concat(foundScripts);
}, []);
@ -166,10 +143,7 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
)}
<div className="min-w flex w-full flex-row flex-wrap gap-4">
{mostViewedScripts.map((script) => (
<Card
key={script.slug}
className="min-w-[250px] flex-1 flex-grow bg-accent/30"
>
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader>
<CardTitle className="flex items-center gap-3">
<div className="flex size-16 min-w-16 items-center justify-center rounded-lg bg-accent p-1">
@ -179,10 +153,7 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
height={64}
width={64}
alt=""
onError={(e) =>
((e.currentTarget as HTMLImageElement).src =
`/${basePath}/logo.png`)
}
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain"
/>
</div>

View File

@ -14,12 +14,12 @@ import { Suspense } from "react";
import { ResourceDisplay } from "./ResourceDisplay";
import { getDisplayValueFromType } from "./ScriptInfoBlocks";
import Alerts from "./ScriptItems/Alerts";
import Buttons from "./ScriptItems/Buttons";
import DefaultPassword from "./ScriptItems/DefaultPassword";
import Description from "./ScriptItems/Description";
import InstallCommand from "./ScriptItems/InstallCommand";
import Tooltips from "./ScriptItems/Tooltips";
import InterFaces from "./ScriptItems/InterFaces";
import Buttons from "./ScriptItems/Buttons";
import Tooltips from "./ScriptItems/Tooltips";
interface ScriptItemProps {
item: Script;
@ -142,7 +142,9 @@ export function ScriptItem({ item, setSelectedScript }: ScriptItemProps) {
<div className="mt-4 rounded-lg border shadow-sm">
<div className="flex gap-3 px-4 py-2 bg-accent/25">
<h2 className="text-lg font-semibold">How to {item.type === "misc" ? "use" : "install"}</h2>
<h2 className="text-lg font-semibold">
How to {item.type === "pve" ? "use" : item.type === "addon" ? "apply" : "install"}
</h2>
<Tooltips item={item} />
</div>
<Separator />

View File

@ -16,7 +16,17 @@ const generateInstallSourceUrl = (slug: string) => {
const generateSourceUrl = (slug: string, type: string) => {
const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`;
return type === "vm" ? `${baseUrl}/vm/${slug}.sh` : `${baseUrl}/misc/${slug}.sh`;
switch (type) {
case "vm":
return `${baseUrl}/vm/${slug}.sh`;
case "pve":
return `${baseUrl}/tools/pve/${slug}.sh`;
case "addon":
return `${baseUrl}/tools/addon/${slug}.sh`;
default:
return `${baseUrl}/ct/${slug}.sh`; // fallback for "ct"
}
};
const generateUpdateUrl = (slug: string) => {

View File

@ -6,50 +6,44 @@ import { getDisplayValueFromType } from "../ScriptInfoBlocks";
const getInstallCommand = (scriptPath = "", isAlpine = false) => {
const url = `https://raw.githubusercontent.com/community-scripts/${basePath}/main/${scriptPath}`;
return isAlpine
? `bash -c "$(curl -fsSL ${url})"`
: `bash -c "$(curl -fsSL ${url})"`;
return isAlpine ? `bash -c "$(curl -fsSL ${url})"` : `bash -c "$(curl -fsSL ${url})"`;
};
export default function InstallCommand({ item }: { item: Script }) {
const alpineScript = item.install_methods.find(
(method) => method.type === "alpine",
);
const alpineScript = item.install_methods.find((method) => method.type === "alpine");
const defaultScript = item.install_methods.find(
(method) => method.type === "default",
);
const defaultScript = item.install_methods.find((method) => method.type === "default");
const renderInstructions = (isAlpine = false) => (
<>
<p className="text-sm mt-2">
{isAlpine ? (
<>
As an alternative option, you can use Alpine Linux and the{" "}
{item.name} package to create a {item.name}{" "}
{getDisplayValueFromType(item.type)} container with faster creation
time and minimal system resource usage. You are also obliged to
adhere to updates provided by the package maintainer.
As an alternative option, you can use Alpine Linux and the {item.name} package to create a {item.name}{" "}
{getDisplayValueFromType(item.type)} container with faster creation time and minimal system resource usage.
You are also obliged to adhere to updates provided by the package maintainer.
</>
) : item.type == "misc" ? (
) : item.type === "pve" ? (
<>
To use the {item.name} script, run the command below in the shell.
To use the {item.name} script, run the command below **only** in the Proxmox VE Shell. This script is
intended for managing or enhancing the host system directly.
</>
) : item.type === "addon" ? (
<>
This script enhances an existing setup. You can use it inside a running LXC container or directly on the
Proxmox VE host to extend functionality with {item.name}.
</>
) : (
<>
{" "}
To create a new Proxmox VE {item.name}{" "}
{getDisplayValueFromType(item.type)}, run the command below in the
To create a new Proxmox VE {item.name} {getDisplayValueFromType(item.type)}, run the command below in the
Proxmox VE Shell.
</>
)}
</p>
{isAlpine && (
<p className="mt-2 text-sm">
To create a new Proxmox VE Alpine-{item.name}{" "}
{getDisplayValueFromType(item.type)}, run the command below in the
Proxmox VE Shell
To create a new Proxmox VE Alpine-{item.name} {getDisplayValueFromType(item.type)}, run the command below in
the Proxmox VE Shell.
</p>
)}
</>
@ -65,23 +59,17 @@ export default function InstallCommand({ item }: { item: Script }) {
</TabsList>
<TabsContent value="default">
{renderInstructions()}
<CodeCopyButton>
{getInstallCommand(defaultScript?.script)}
</CodeCopyButton>
<CodeCopyButton>{getInstallCommand(defaultScript?.script)}</CodeCopyButton>
</TabsContent>
<TabsContent value="alpine">
{renderInstructions(true)}
<CodeCopyButton>
{getInstallCommand(alpineScript.script, true)}
</CodeCopyButton>
<CodeCopyButton>{getInstallCommand(alpineScript.script, true)}</CodeCopyButton>
</TabsContent>
</Tabs>
) : defaultScript?.script ? (
<>
{renderInstructions()}
<CodeCopyButton>
{getInstallCommand(defaultScript.script)}
</CodeCopyButton>
<CodeCopyButton>{getInstallCommand(defaultScript.script)}</CodeCopyButton>
</>
) : null}
</div>

View File

@ -6,6 +6,7 @@ import {
CommandItem,
CommandList,
} from "@/components/ui/command";
import { basePath } from "@/config/siteConfig";
import { fetchCategories } from "@/lib/data";
import { Category } from "@/lib/types";
import { cn } from "@/lib/utils";
@ -15,18 +16,17 @@ import React from "react";
import { Badge } from "./ui/badge";
import { Button } from "./ui/button";
import { DialogTitle } from "./ui/dialog";
import { basePath } from "@/config/siteConfig";
export const formattedBadge = (type: string) => {
switch (type) {
case "vm":
return <Badge className="text-blue-500/75 border-blue-500/75">VM</Badge>;
case "ct":
return (
<Badge className="text-yellow-500/75 border-yellow-500/75">LXC</Badge>
);
case "misc":
return <Badge className="text-green-500/75 border-green-500/75">MISC</Badge>;
return <Badge className="text-yellow-500/75 border-yellow-500/75">LXC</Badge>;
case "pve":
return <Badge className="text-orange-500/75 border-orange-500/75">PVE</Badge>;
case "addon":
return <Badge className="text-green-500/75 border-green-500/75">ADDON</Badge>;
}
return null;
};
@ -84,14 +84,9 @@ export default function CommandMenu() {
<DialogTitle className="sr-only">Search scripts</DialogTitle>
<CommandInput placeholder="Search for a script..." />
<CommandList>
<CommandEmpty>
{isLoading ? "Loading..." : "No scripts found."}
</CommandEmpty>
<CommandEmpty>{isLoading ? "Loading..." : "No scripts found."}</CommandEmpty>
{links.map((category) => (
<CommandGroup
key={`category:${category.name}`}
heading={category.name}
>
<CommandGroup key={`category:${category.name}`} heading={category.name}>
{category.scripts.map((script) => (
<CommandItem
key={`script:${script.slug}`}
@ -104,10 +99,7 @@ export default function CommandMenu() {
<div className="flex gap-2" onClick={() => setOpen(false)}>
<Image
src={script.logo || `/${basePath}/logo.png`}
onError={(e) =>
((e.currentTarget as HTMLImageElement).src =
`/${basePath}/logo.png`)
}
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
unoptimized
width={16}
height={16}

View File

@ -5,7 +5,7 @@ export type Script = {
slug: string;
categories: number[];
date_created: string;
type: "vm" | "ct" | "misc";
type: "vm" | "ct" | "pve" | "addon";
updateable: boolean;
privileged: boolean;
interface_port: number | null;

View File

@ -18,7 +18,7 @@ $STD apt-get install -y g++-multilib
msg_ok "Installed Dependencies"
msg_info "Installing Daemon Sync Server"
curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/daemonsync_2.2.0.0059_amd64.deb" -o "daemonsync_2.2.0.0059_amd64.deb"
curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/daemonsync_2.2.0.0059_amd64.deb" -o "daemonsync_2.2.0.0059_amd64.deb"
$STD dpkg -i daemonsync_2.2.0.0059_amd64.deb
msg_ok "Installed Daemon Sync Server"

Binary file not shown.