mirror of
https://github.com/moghtech/komodo.git
synced 2026-04-28 11:49:39 -05:00
improve cards, add tags and accordion
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@monitor/client": "link:../client/ts",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@ui/accordion";
|
||||
import { Badge } from "@ui/badge";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
@@ -28,12 +35,39 @@ export const ResourceCard = ({
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
</div>
|
||||
{statusIcon}
|
||||
<div className="flex items-center gap-2">
|
||||
{statusIcon && (
|
||||
<>
|
||||
{statusIcon}
|
||||
<div className="border h-6 w-0" />
|
||||
</>
|
||||
)}
|
||||
{icon}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="flex items-center gap-4">
|
||||
{icon}
|
||||
<div className="border h-6" />
|
||||
<CardContent className="flex flex-col gap-6">
|
||||
{/* {icon}
|
||||
<div className="border h-6" /> */}
|
||||
{children}
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
<AccordionItem value="tags">
|
||||
<AccordionTrigger>Show Tags</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<Badge>crawler</Badge>
|
||||
<Badge>prod</Badge>
|
||||
<Badge>cex</Badge>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import { useRead } from "@hooks";
|
||||
import { ServerStatusIcon } from "@resources/server/util";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from "@ui/card";
|
||||
import { version_to_string } from "@util/helpers";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BuildInfo } from "./util";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useRead } from "@hooks";
|
||||
import { CardDescription } from "@ui/card";
|
||||
import { version_to_string } from "@util/helpers";
|
||||
import { Factory, History } from "lucide-react";
|
||||
|
||||
@@ -18,7 +17,7 @@ export const BuildVersion = ({ id }: { id: string }) => {
|
||||
export const BuildBuilder = ({ id }: { id: string }) => {
|
||||
const builds = useRead("ListBuilds", {}).data;
|
||||
const build = builds?.find((b) => b.id === id);
|
||||
return <>{build?.id.slice(0, 10) + "..." ?? "..."}</>;
|
||||
return <>{build?.id ?? "..."}</>;
|
||||
};
|
||||
|
||||
export const BuildLastBuilt = ({ id }: { id: string }) => {
|
||||
@@ -30,7 +29,7 @@ export const BuildLastBuilt = ({ id }: { id: string }) => {
|
||||
|
||||
export const BuildInfo = ({ id }: { id: string }) => {
|
||||
return (
|
||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
||||
<div className="flex flex-col text-muted-foreground text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<Factory className="w-4 h-4" />
|
||||
<BuildBuilder id={id} />
|
||||
|
||||
@@ -19,5 +19,13 @@ export const DeploymentCard = ({ id }: { id: string }) => {
|
||||
<DeploymentInfo deploymentId={id} />
|
||||
</ResourceCard>
|
||||
</Link>
|
||||
// <ResourceCard
|
||||
// title={deployment.name}
|
||||
// description={deployment.status ?? "not deployed"}
|
||||
// statusIcon={<DeploymentStatusIcon deploymentId={id} />}
|
||||
// icon={<Rocket className="w-4 h-4" />}
|
||||
// >
|
||||
// <DeploymentInfo deploymentId={id} />
|
||||
// </ResourceCard>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ export const DeploymentInfo = ({ deploymentId }: { deploymentId: string }) => {
|
||||
const deployment = deployments?.find((d) => d.id === deploymentId);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
||||
<div className="flex flex-col text-muted-foreground text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<Server className="w-4 h-4" />
|
||||
server name
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useRead } from "@hooks";
|
||||
import { ServerStatus } from "@monitor/client/dist/types";
|
||||
import { CardDescription } from "@ui/card";
|
||||
import { cn } from "@util/helpers";
|
||||
import { Circle, Cpu, Database, MemoryStick } from "lucide-react";
|
||||
import { Circle, Cpu, Database, MapPin, MemoryStick } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const ServerName = ({ serverId }: { serverId: string | undefined }) => {
|
||||
@@ -37,18 +37,24 @@ export const ServerStats = ({ server_id }: { server_id: string }) => {
|
||||
}, [refetch]);
|
||||
|
||||
return (
|
||||
<div className="flex gap-4 text-sm text-muted-foreground">
|
||||
<div className="flex gap-2 items-center ">
|
||||
<Cpu className="w-4 h-4" />
|
||||
{data?.cpu_perc.toFixed(2)}%
|
||||
<div className="flex flex-col text-sm text-muted-foreground">
|
||||
<div className="flex gap-4">
|
||||
<div className="flex gap-2 items-center">
|
||||
<Cpu className="w-4 h-4" />
|
||||
{data?.cpu_perc.toFixed(2)}%
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<MemoryStick className="w-4 h-4" />
|
||||
{data?.mem_total_gb.toFixed(2)} GB
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Database className="w-4 h-4" />
|
||||
{data?.disk_total_gb.toFixed(2)} GB
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<MemoryStick className="w-4 h-4" />
|
||||
{data?.mem_total_gb.toFixed(2)} GB
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Database className="w-4 h-4" />
|
||||
{data?.disk_total_gb.toFixed(2)} GB
|
||||
<MapPin className="w-4 h-4" />
|
||||
server.region
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
55
frontend/src/ui/accordion.tsx
Normal file
55
frontend/src/ui/accordion.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
||||
// import { ChevronDownIcon } from "@radix-ui/react-icons";
|
||||
|
||||
import { cn } from "@util/helpers";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
|
||||
const Accordion = AccordionPrimitive.Root;
|
||||
|
||||
const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||
>(({ ...props }, ref) => <AccordionPrimitive.Item ref={ref} {...props} />);
|
||||
AccordionItem.displayName = "AccordionItem";
|
||||
|
||||
const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Header className="flex">
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-1 items-center justify-between py-2 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
));
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
||||
|
||||
const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</AccordionPrimitive.Content>
|
||||
));
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
35
frontend/src/ui/badge.tsx
Normal file
35
frontend/src/ui/badge.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@util/helpers";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants };
|
||||
@@ -485,6 +485,22 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-accordion@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz#738441f7343e5142273cdef94d12054c3287966f"
|
||||
integrity sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.1"
|
||||
"@radix-ui/react-collapsible" "1.0.3"
|
||||
"@radix-ui/react-collection" "1.0.3"
|
||||
"@radix-ui/react-compose-refs" "1.0.1"
|
||||
"@radix-ui/react-context" "1.0.1"
|
||||
"@radix-ui/react-direction" "1.0.1"
|
||||
"@radix-ui/react-id" "1.0.1"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||
|
||||
"@radix-ui/react-arrow@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d"
|
||||
@@ -493,6 +509,21 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
"@radix-ui/react-collapsible@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz#df0e22e7a025439f13f62d4e4a9e92c4a0df5b81"
|
||||
integrity sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.1"
|
||||
"@radix-ui/react-compose-refs" "1.0.1"
|
||||
"@radix-ui/react-context" "1.0.1"
|
||||
"@radix-ui/react-id" "1.0.1"
|
||||
"@radix-ui/react-presence" "1.0.1"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||
|
||||
"@radix-ui/react-collection@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.2.tgz#d50da00bfa2ac14585319efdbbb081d4c5a29a97"
|
||||
|
||||
Reference in New Issue
Block a user