Update the database by creating separate tables for alerts and default login details. Add a tab for default login details, and implement badges for updatable scripts and scripts requiring privileged access.

This commit is contained in:
Bram Suurd
2024-08-09 02:32:06 +02:00
parent 8a2d92a4bb
commit bbefd7cb42
7 changed files with 156 additions and 48 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -25,6 +25,7 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@vercel/analytics": "^1.2.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",

View File

@@ -5,7 +5,7 @@ import { Category } from "@/lib/types";
export async function GET(req: NextRequest) {
try {
const response = await pb.collection("categories").getFullList({
expand: "items.alpine_script",
expand: "items.alerts,items.alpine_script,items.default_login",
sort: "order",
});

View File

@@ -18,9 +18,17 @@ import { Category, Script } from "@/lib/types";
import { useSearchParams } from "next/navigation";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { MostViewedScripts, LatestScripts } from "./ScriptInfoBlocks";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import CodeCopyButton from "@/components/ui/code-copy-button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
function ScriptItem({
items,
@@ -129,6 +137,7 @@ function ScriptItem({
};
const hasAlpineScript = item?.expand?.alpine_script !== undefined;
const hasDefaultLogin = item?.expand?.default_login !== undefined;
return (
<>
@@ -277,40 +286,66 @@ function ScriptItem({
<Separator className="mt-4" />
<div>
<div className="mt-4">
<div className="p-2">
<h2 className="mb-2 max-w-prose text-lg font-semibold">
Description
</h2>
<p className="text-sm">
{descriptionCodeBlock(item.description)}
</p>
</div>
{item.alert1 && (
<div className="mt-4 flex flex-col gap-2">
<p className="inline-flex items-center gap-2 rounded-lg border border-red-500/25 bg-destructive/25 p-2 pl-4 text-sm">
<Info className="h-4 min-h-4 w-4 min-w-4" />
{descriptionCodeBlock(item.alert1)}
<div className="flex p-2">
<div>
<h2 className="mb-2 max-w-prose text-lg font-semibold">
Description
</h2>
<p className="text-sm text-muted-foreground">
{descriptionCodeBlock(item.description)}
</p>
{item.alert2 && (
<p className="inline-flex items-center gap-2 rounded-lg border border-red-500/25 bg-destructive/25 p-2 pl-4 text-sm">
<Info className="min-w-42 h-4 min-h-4 w-4" />
{descriptionCodeBlock(item.alert2)}
</p>
)}
{item.alert3 && (
</div>
</div>
{item.expand?.alerts?.length > 0 &&
item.expand.alerts.map((alert: any, index: number) => (
<div key={index} className="mt-4 flex flex-col gap-2">
<p className="inline-flex items-center gap-2 rounded-lg border border-red-500/25 bg-destructive/25 p-2 pl-4 text-sm">
<Info className="h-4 min-h-4 w-4 min-w-4" />
{descriptionCodeBlock(item.alert3)}
{descriptionCodeBlock(alert.content)}
</p>
)}
</div>
)}
</div>
))}
</div>
<div className="mt-4 rounded-lg border bg-accent/50">
<h2 className="px-4 py-2 text-lg font-semibold">
How to {item.item_type ? "install" : "use"}
</h2>
<div className="flex gap-3 px-4 py-2">
<h2 className=" text-lg font-semibold">
How to {item.item_type ? "install" : "use"}
</h2>
<div className="flex items-center gap-2">
{item.privileged && (
<TooltipProvider>
<Tooltip delayDuration={100}>
<TooltipTrigger>
<Badge variant={"success"}>
Privileged
</Badge>
</TooltipTrigger>
<TooltipContent side="bottom">
<p className="text-sm">
This script will be run in a privileged LXC
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{item.isUpdateable && (
<TooltipProvider>
<Tooltip delayDuration={100}>
<TooltipTrigger>
<Badge variant={"success"}>Updateable</Badge>
</TooltipTrigger>
<TooltipContent side="bottom">
<p className="text-sm">
To Update {item.title}, run the command below
(or type update) in the LXC Console.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
</div>
<Separator className="w-full"></Separator>
<div className="p-4">
{hasAlpineScript ? (
@@ -332,12 +367,6 @@ function ScriptItem({
{item.item_type}, run the command below in the
Proxmox VE Shell.
</p>
{item.isUpdateable && (
<p className="text-sm">
To Update {item.title}, run the command
below (or type update) in the LXC Console.
</p>
)}
</>
)}
<CodeCopyButton>{installCommand}</CodeCopyButton>
@@ -374,12 +403,6 @@ function ScriptItem({
{item.item_type}, run the command below in the
Proxmox VE Shell.
</p>
{item.isUpdateable && (
<p className="text-sm">
To Update {item.title}, run the command below
(or type update) in the LXC Console.
</p>
)}
</>
)}
{installCommand && (
@@ -390,6 +413,55 @@ function ScriptItem({
</div>
</div>
</div>
<div>
{hasDefaultLogin && (
<div className="mt-4 rounded-lg border bg-accent/50">
<div className="flex gap-3 px-4 py-2">
<h2 className=" text-lg font-semibold">
Default Login Credentials
</h2>
</div>
<Separator className="w-full"></Separator>
<div className="flex flex-col gap-2 p-4">
<p className="mb-2 text-sm">
You can use the following credentials to login to the{" "}
{""}
{item.title} {item.item_type}.
</p>
<div className="text-sm">
Username:{" "}
<Button
variant={"secondary"}
size={"null"}
onClick={() =>
handleCopy(
"username",
item.expand.default_login.username,
)
}
>
{item.expand.default_login.username}
</Button>
</div>
<div className="text-sm">
Password:{" "}
<Button
variant={"secondary"}
size={"null"}
onClick={() =>
handleCopy(
"password",
item.expand.default_login.password,
)
}
>
{item.expand.default_login.password}
</Button>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>

View File

@@ -15,6 +15,7 @@ const badgeVariants = cva(
destructive:
"border-transparent text-destructive-foreground border-destructive-foreground",
outline: "text-foreground",
success: "text-green-500 border-green-500"
},
},
defaultVariants: {

View File

@@ -0,0 +1,30 @@
"use client"
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import { cn } from "@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

View File

@@ -18,6 +18,8 @@ export type Script = {
id: string;
expand: {
alpine_script: alpine_script;
alerts: alerts[];
default_login: default_login;
}
isUpdateable: boolean;
item_type: string;
@@ -30,6 +32,7 @@ export type Script = {
isMostViewed: boolean;
mostViewedPosition: number;
interface: string;
privileged: boolean;
};
type alpine_script = {
@@ -39,6 +42,15 @@ type alpine_script = {
default_ram: string;
};
type alerts = {
content: string;
}
type default_login = {
username: string;
password: string;
}
export interface Category {
catagoryName: string;
collectionId: string;
@@ -49,11 +61,3 @@ export interface Category {
items: Script[];
};
}
export type Scripts = {
page: number;
perPage: number;
totalItems: number;
totalPages: number;
items: Category[];
};