From 70ff93050f44de1f92b4c71ceeb40862e9b26061 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Sat, 11 May 2024 16:06:36 -0700 Subject: [PATCH] choose between config / log for deployment --- frontend/package.json | 2 + frontend/src/components/config/index.tsx | 63 ++++---- frontend/src/components/layouts.tsx | 14 +- .../resources/deployment/config/index.tsx | 5 +- .../components/resources/deployment/index.tsx | 66 ++++++++- .../components/resources/deployment/log.tsx | 139 ++++++++---------- frontend/src/globals.css | 4 +- frontend/src/ui/toggle-group.tsx | 59 ++++++++ frontend/src/ui/toggle.tsx | 43 ++++++ frontend/yarn.lock | 24 +++ 10 files changed, 305 insertions(+), 114 deletions(-) create mode 100644 frontend/src/ui/toggle-group.tsx create mode 100644 frontend/src/ui/toggle.tsx diff --git a/frontend/package.json b/frontend/package.json index a87ddddb4..29833ae33 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,8 @@ "@radix-ui/react-switch": "1.0.3", "@radix-ui/react-tabs": "1.0.4", "@radix-ui/react-toast": "1.1.5", + "@radix-ui/react-toggle": "^1.0.3", + "@radix-ui/react-toggle-group": "^1.0.4", "@tanstack/react-query": "5.35.1", "@tanstack/react-table": "8.16.0", "ansi-to-html": "0.7.2", diff --git a/frontend/src/components/config/index.tsx b/frontend/src/components/config/index.tsx index 72da67e4d..329daed45 100644 --- a/frontend/src/components/config/index.tsx +++ b/frontend/src/components/config/index.tsx @@ -30,6 +30,7 @@ export const ConfigLayout = < onConfirm, onReset, selector, + titleOther, }: { config: Partial; children: ReactNode; @@ -37,33 +38,38 @@ export const ConfigLayout = < onConfirm: () => void; onReset: () => void; selector?: ReactNode; -}) => ( -
} - actions={ -
- {selector} - - {Object.keys(config).length ? ( - - ) : null} -
- } - > - {children} -
-); + titleOther?: ReactNode; +}) => { + const titleProps = titleOther + ? { titleOther } + : { title: "Config", icon: }; + return ( +
+ {selector} + + {Object.keys(config).length ? ( + + ) : null} + + } + > + {children} +
+ ); +}; export const Config = ({ config, @@ -73,6 +79,7 @@ export const Config = ({ onSave, components, selector, + titleOther, }: { config: T; update: Partial; @@ -80,6 +87,7 @@ export const Config = ({ set: React.Dispatch>>; onSave: () => Promise; selector?: ReactNode; + titleOther?: ReactNode; components: Record< string, Record< @@ -96,6 +104,7 @@ export const Config = ({ return ( { diff --git a/frontend/src/components/layouts.tsx b/frontend/src/components/layouts.tsx index 72299434a..da9e6e5fc 100644 --- a/frontend/src/components/layouts.tsx +++ b/frontend/src/components/layouts.tsx @@ -37,6 +37,7 @@ export const Layout = () => { interface PageProps { title?: ReactNode; titleRight?: ReactNode; + titleOther?: ReactNode; children?: ReactNode; subtitle?: ReactNode; actions?: ReactNode; @@ -45,6 +46,7 @@ interface PageProps { export const Page = ({ title, titleRight, + titleOther, subtitle, actions, children, @@ -62,26 +64,28 @@ export const Page = ({ {actions} )} + {titleOther} {children} ); interface SectionProps { title?: ReactNode; - children?: ReactNode; icon?: ReactNode; + titleOther?: ReactNode; + children?: ReactNode; actions?: ReactNode; } -export const Section = ({ title, icon, actions, children }: SectionProps) => ( +export const Section = ({ title, icon, titleOther, actions, children }: SectionProps) => (
- {(title || icon) && ( + {(title || icon) ? (
{icon} -

{title}

+ {title &&

{title}

}
- )} + ) : titleOther} {actions}
{children} diff --git a/frontend/src/components/resources/deployment/config/index.tsx b/frontend/src/components/resources/deployment/config/index.tsx index a9426c271..bb113106c 100644 --- a/frontend/src/components/resources/deployment/config/index.tsx +++ b/frontend/src/components/resources/deployment/config/index.tsx @@ -1,6 +1,6 @@ import { useRead, useWrite } from "@lib/hooks"; import { Types } from "@monitor/client"; -import { useState } from "react"; +import { ReactNode, useState } from "react"; import { AccountSelector, ConfigItem } from "@components/config/util"; import { ImageConfig } from "./components/image"; import { RestartModeSelector } from "./components/restart"; @@ -18,7 +18,7 @@ import { import { LabelsConfig, ServerSelector } from "@components/resources/common"; import { TextUpdateMenu } from "@components/util"; -export const DeploymentConfig = ({ id }: { id: string }) => { +export const DeploymentConfig = ({ id, titleOther }: { id: string; titleOther: ReactNode }) => { const perms = useRead("GetPermissionLevel", { target: { type: "Deployment", id }, }).data; @@ -38,6 +38,7 @@ export const DeploymentConfig = ({ id }: { id: string }) => { return ( useRead("ListDeployments", {}, { refetchInterval: 5000 }).data?.find( (d) => d.id === id ); +const ConfigOrLog = ({ id }: { id: string }) => { + const [view, setView] = useAtom(configOrLog); + const state = useDeployment(id)?.info.state; + const logsDisabled = + state === undefined || + state === Types.DockerContainerState.Unknown || + state === Types.DockerContainerState.NotDeployed; + return ( + + + + + Config + + + Log + + + } + /> + + + + + Config + + + Log + + + } + /> + + + ); +}; + export const DeploymentComponents: RequiredResourceComponents = { Dashboard: DeploymentsChart, @@ -106,9 +166,9 @@ export const DeploymentComponents: RequiredResourceComponents = { RemoveContainer, }, - Page: { DeploymentLogs }, + Page: {}, - Config: DeploymentConfig, + Config: ConfigOrLog, DangerZone: ({ id }) => ( <> diff --git a/frontend/src/components/resources/deployment/log.tsx b/frontend/src/components/resources/deployment/log.tsx index 4d9f9248f..4abef3506 100644 --- a/frontend/src/components/resources/deployment/log.tsx +++ b/frontend/src/components/resources/deployment/log.tsx @@ -1,16 +1,14 @@ import { Section } from "@components/layouts"; import { useRead } from "@lib/hooks"; import { Types } from "@monitor/client"; -import { Tabs, TabsList, TabsTrigger, TabsContent } from "@ui/tabs"; import { Button } from "@ui/button"; import { - TerminalSquare, - AlertOctagon, RefreshCw, ChevronDown, X, + AlertOctagon, } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; +import { ReactNode, useEffect, useRef, useState } from "react"; import { useDeployment } from "."; import { Select, @@ -23,8 +21,9 @@ import { import { Input } from "@ui/input"; import { useToast } from "@ui/use-toast"; import { logToHtml } from "@lib/utils"; +import { ToggleGroup, ToggleGroupItem } from "@ui/toggle-group"; -export const DeploymentLogs = ({ id }: { id: string }) => { +export const DeploymentLogs = ({ id, titleOther }: { id: string; titleOther: ReactNode }) => { const state = useDeployment(id)?.info.state; if ( state === undefined || @@ -33,11 +32,12 @@ export const DeploymentLogs = ({ id }: { id: string }) => { ) { return null; } - return ; + return ; }; -const DeploymentLogsInner = ({ id }: { id: string }) => { +const DeploymentLogsInner = ({ id, titleOther }: { id: string; titleOther: ReactNode }) => { const { toast } = useToast(); + const [stream, setStream] = useState("stdout"); const [tail, set] = useState("100"); const [terms, setTerms] = useState([]); const [search, setSearch] = useState(""); @@ -60,88 +60,77 @@ const DeploymentLogsInner = ({ id }: { id: string }) => { const { Log, refetch, stderr } = terms.length ? SearchLogs(id, terms) - : NoSearchLogs(id, tail); + : NoSearchLogs(id, tail, stream); return ( - -
} - actions={ -
- {terms.map((term, index) => ( - - ))} -
- setSearch(e.target.value)} - onBlur={addTerm} - onKeyDown={(e) => { - if (e.key === "Enter") addTerm(); - }} - className="w-[300px]" - /> - -
- - stdout - - stderr - {stderr && ( - - )} - - - - 0} + ))} +
+ setSearch(e.target.value)} + onBlur={addTerm} + onKeyDown={(e) => { + if (e.key === "Enter") addTerm(); + }} + className="w-[300px]" /> +
- } - > - {Log} -
-
+ + stdout + + stderr + {stderr && ( + + )} + + + + 0} + /> +
+ } + > + {Log} + ); }; -const NoSearchLogs = (id: string, tail: string) => { +const NoSearchLogs = (id: string, tail: string, stream: string) => { const { data: log, refetch } = useRead( "GetLog", { deployment: id, tail: Number(tail) }, { refetchInterval: 30000 } ); return { - Log: ( - <> - {["stdout", "stderr"].map((stream) => ( - - - - ))} - - ), + Log: , refetch, stderr: !!log?.stderr, }; diff --git a/frontend/src/globals.css b/frontend/src/globals.css index c88defe96..8104c6a58 100644 --- a/frontend/src/globals.css +++ b/frontend/src/globals.css @@ -48,8 +48,8 @@ --secondary: 220.1 40.1% 90.2%; --secondary-foreground: 220.1 40.1% 5.2%; - --muted: 220.1 40.1% 98.2%; - --muted-foreground: 220.1 20.1% 40.2%; + --muted: 220.1 40.1% 90.2%; + --muted-foreground: 220.1 20.1% 20.2%; --accent: 220.1 40.1% 90.2%; --accent-foreground: 220.1 40.1% 11.2%; diff --git a/frontend/src/ui/toggle-group.tsx b/frontend/src/ui/toggle-group.tsx new file mode 100644 index 000000000..e322cdd57 --- /dev/null +++ b/frontend/src/ui/toggle-group.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group" +import { VariantProps } from "class-variance-authority" + +import { cn } from "@lib/utils" +import { toggleVariants } from "@//ui/toggle" + +const ToggleGroupContext = React.createContext< + VariantProps +>({ + size: "default", + variant: "default", +}) + +const ToggleGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, children, ...props }, ref) => ( + + + {children} + + +)) + +ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName + +const ToggleGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, children, variant, size, ...props }, ref) => { + const context = React.useContext(ToggleGroupContext) + + return ( + + {children} + + ) +}) + +ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName + +export { ToggleGroup, ToggleGroupItem } diff --git a/frontend/src/ui/toggle.tsx b/frontend/src/ui/toggle.tsx new file mode 100644 index 000000000..c9db1a188 --- /dev/null +++ b/frontend/src/ui/toggle.tsx @@ -0,0 +1,43 @@ +import * as React from "react" +import * as TogglePrimitive from "@radix-ui/react-toggle" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@lib/utils" + +const toggleVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", + { + variants: { + variant: { + default: "bg-transparent", + outline: + "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground", + }, + size: { + default: "h-9 px-3", + sm: "h-8 px-2", + lg: "h-10 px-3", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +const Toggle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, ...props }, ref) => ( + +)) + +Toggle.displayName = TogglePrimitive.Root.displayName + +export { Toggle, toggleVariants } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 9fb7a067e..ffceb7a61 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -889,6 +889,30 @@ "@radix-ui/react-use-layout-effect" "1.0.1" "@radix-ui/react-visually-hidden" "1.0.3" +"@radix-ui/react-toggle-group@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec" + integrity sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-toggle" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-toggle@1.0.3", "@radix-ui/react-toggle@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz#aecb2945630d1dc5c512997556c57aba894e539e" + integrity sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-callback-ref@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"