diff --git a/frontend/src/components/log.tsx b/frontend/src/components/log.tsx index 6a7f6e136..3de220d22 100644 --- a/frontend/src/components/log.tsx +++ b/frontend/src/components/log.tsx @@ -30,6 +30,7 @@ export const LogSection = ({ regular_logs, search_logs, titleOther, + extraParams, }: { regular_logs: ( timestamps: boolean, @@ -46,6 +47,7 @@ export const LogSection = ({ invert: boolean ) => { Log: ReactNode; refetch: () => void; stderr: boolean }; titleOther?: ReactNode; + extraParams?: ReactNode; }) => { const { toast } = useToast(); const [timestamps, setTimestamps] = useLocalStorage( @@ -159,6 +161,7 @@ export const LogSection = ({ onSelect={set} disabled={search.length > 0} /> + {extraParams} } > diff --git a/frontend/src/components/resources/stack/log.tsx b/frontend/src/components/resources/stack/log.tsx index dc4ac3308..0f0bbb3a3 100644 --- a/frontend/src/components/resources/stack/log.tsx +++ b/frontend/src/components/resources/stack/log.tsx @@ -1,8 +1,15 @@ -import { useRead } from "@lib/hooks"; +import { LocalStorageSetter, useLocalStorage, useRead } from "@lib/hooks"; import { Types } from "komodo_client"; import { ReactNode } from "react"; import { useStack } from "."; import { Log, LogSection } from "@components/log"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@ui/dropdown-menu"; +import { CaretSortIcon } from "@radix-ui/react-icons"; export const StackLogs = ({ id, @@ -11,46 +18,113 @@ export const StackLogs = ({ id: string; titleOther: ReactNode; }) => { - const state = useStack(id)?.info.state; + const stackInfo = useStack(id)?.info; + const [selectedServices, setServices] = useLocalStorage( + `stack-${id}-log-services`, + [] + ); if ( - state === undefined || - state === Types.StackState.Unknown || - state === Types.StackState.Down + stackInfo === undefined || + stackInfo.state === Types.StackState.Unknown || + stackInfo.state === Types.StackState.Down ) { return null; } - return ; + return ( + ({ + service: s.service, + selected: selectedServices.includes(s.service), + }))} + setServices={setServices} + /> + ); }; const StackLogsInner = ({ id, titleOther, + services, + setServices, }: { id: string; titleOther: ReactNode; + services: Array<{ service: string; selected: boolean }>; + setServices: (state: string[] | LocalStorageSetter) => void; }) => { + const selected = services.filter((s) => s.selected); return ( - NoSearchLogs(id, tail, timestamps, stream) + NoSearchLogs( + id, + services.filter((s) => s.selected).map((s) => s.service), + tail, + timestamps, + stream + ) } search_logs={(timestamps, terms, invert) => - SearchLogs(id, terms, invert, timestamps) + SearchLogs( + id, + services.filter((s) => s.selected).map((s) => s.service), + terms, + invert, + timestamps + ) } titleOther={titleOther} + extraParams={ + + +
+
Services:
{" "} + {selected.length === 0 + ? "All" + : selected.map((s) => s.service).join(", ")} + +
+
+ + {services.map((s) => { + return ( + { + e.preventDefault(); + if (s.selected) { + setServices((services) => + services.filter((service) => service !== s.service) + ); + } else { + setServices((services) => [...services, s.service]); + } + }} + > + {s.service} + + ); + })} + +
+ } /> ); }; const NoSearchLogs = ( id: string, + services: string[], tail: number, timestamps: boolean, stream: string ) => { const { data: log, refetch } = useRead("GetStackLog", { stack: id, - services: [], + services, tail, timestamps, }); @@ -67,13 +141,14 @@ const NoSearchLogs = ( const SearchLogs = ( id: string, + services: string[], terms: string[], invert: boolean, timestamps: boolean ) => { const { data: log, refetch } = useRead("SearchStackLog", { stack: id, - services: [], + services, terms, combinator: Types.SearchCombinator.And, invert,