diff --git a/frontend/src/components/v2/HighlightText/HighlightText.tsx b/frontend/src/components/v2/HighlightText/HighlightText.tsx new file mode 100644 index 000000000..9b1c525eb --- /dev/null +++ b/frontend/src/components/v2/HighlightText/HighlightText.tsx @@ -0,0 +1,43 @@ +export const HighlightText = ({ + text, + highlight, + highlightClassName +}: { + text: string | undefined | null; + highlight: string; + highlightClassName?: string; +}) => { + if (!text) return null; + const searchTerm = highlight.toLowerCase().trim(); + + if (!searchTerm) return {text}; + + const parts: React.ReactNode[] = []; + let lastIndex = 0; + + const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const regex = new RegExp(escapedSearchTerm, "gi"); + + while (true) { + const match = regex.exec(text); + if (match === null) break; + + if (match.index > lastIndex) { + parts.push({text.substring(lastIndex, match.index)}); + } + + parts.push( + + {text.substring(match.index, match.index + match[0].length)} + + ); + + lastIndex = regex.lastIndex; + } + + if (lastIndex < text.length) { + parts.push({text.substring(lastIndex)}); + } + + return parts; +}; diff --git a/frontend/src/components/v2/HighlightText/index.tsx b/frontend/src/components/v2/HighlightText/index.tsx new file mode 100644 index 000000000..a2ff1b504 --- /dev/null +++ b/frontend/src/components/v2/HighlightText/index.tsx @@ -0,0 +1 @@ +export { HighlightText } from "./HighlightText"; diff --git a/frontend/src/pages/admin/EnvironmentPage/components/EnvironmentPageForm.tsx b/frontend/src/pages/admin/EnvironmentPage/components/EnvironmentPageForm.tsx index 8e07e37be..f2c50a3f5 100644 --- a/frontend/src/pages/admin/EnvironmentPage/components/EnvironmentPageForm.tsx +++ b/frontend/src/pages/admin/EnvironmentPage/components/EnvironmentPageForm.tsx @@ -1,16 +1,116 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import { Controller, useForm, useWatch } from "react-hook-form"; -import { faExclamationTriangle, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"; +import { Control, Controller, useForm, useWatch } from "react-hook-form"; +import { + faChevronRight, + faExclamationTriangle, + faMagnifyingGlass +} from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, SecretInput, Tooltip } from "@app/components/v2"; +import { HighlightText } from "@app/components/v2/HighlightText"; import { useGetEnvOverrides, useUpdateServerConfig } from "@app/hooks/api"; type TForm = Record; +export const GroupContainer = ({ + group, + control, + search +}: { + group: { + fields: { + key: string; + value: string; + hasEnvEntry: boolean; + description?: string; + }[]; + name: string; + }; + control: Control; + search: string; +}) => { + const [open, setOpen] = useState(false); + + return ( + + setOpen((o) => !o)} + onKeyDown={(e) => { + if (e.key === "Enter") { + setOpen((o) => !o); + } + }} + > + + + {group.name} + + + {(open || search) && ( + + {group.fields.map((field) => ( + + + + + + + + + + + + {field.hasEnvEntry && ( + + + + )} + + ( + + + + )} + /> + + + ))} + + )} + + ); +}; + export const EnvironmentPageForm = () => { const { data: envOverrides } = useGetEnvOverrides(); const { mutateAsync: updateServerConfig } = useUpdateServerConfig(); @@ -130,57 +230,9 @@ export const EnvironmentPageForm = () => { placeholder="Search for keys, descriptions, and values..." className="flex-1" /> - + {filteredData.map((group) => ( - - {group!.name} - - - {group!.fields.map((field, i) => ( - - - {field.key} - {field.description} - - - - {field.hasEnvEntry && ( - - - - )} - - ( - - - - )} - /> - - - ))} - - - + ))}