From 69018a4944cf0380c8c7c019d72bb4b7528ab25f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 23 Jan 2026 12:33:40 -0800 Subject: [PATCH] components --- .../v2/design-elements/BasePage.tsx | 4 +- .../v2/design-elements/Fallback.tsx | 9 ++ client/src/Components/v2/inputs/Checkbox.tsx | 56 ++++++++++ .../src/Components/v2/inputs/FieldLabel.tsx | 38 +++++++ client/src/Components/v2/inputs/Select.tsx | 102 ++++++++++++++++++ client/src/Components/v2/inputs/index.tsx | 3 + .../Components/v2/monitors/FilterControls.tsx | 11 ++ client/src/Components/v2/monitors/index.tsx | 1 + client/src/Pages/Uptime/Monitors/index.tsx | 18 +++- client/src/locales/en.json | 9 +- 10 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 client/src/Components/v2/inputs/Checkbox.tsx create mode 100644 client/src/Components/v2/inputs/FieldLabel.tsx create mode 100644 client/src/Components/v2/inputs/Select.tsx create mode 100644 client/src/Components/v2/monitors/FilterControls.tsx create mode 100644 client/src/Components/v2/monitors/index.tsx diff --git a/client/src/Components/v2/design-elements/BasePage.tsx b/client/src/Components/v2/design-elements/BasePage.tsx index e3785936b..c853a8d30 100644 --- a/client/src/Components/v2/design-elements/BasePage.tsx +++ b/client/src/Components/v2/design-elements/BasePage.tsx @@ -140,8 +140,8 @@ export const MonitorBasePageWithStates = ({ ); diff --git a/client/src/Components/v2/design-elements/Fallback.tsx b/client/src/Components/v2/design-elements/Fallback.tsx index 9dfeb5122..16eece25a 100644 --- a/client/src/Components/v2/design-elements/Fallback.tsx +++ b/client/src/Components/v2/design-elements/Fallback.tsx @@ -165,6 +165,15 @@ export const EmptyMonitorFallback = ({ /> ))} + + + ); diff --git a/client/src/Components/v2/inputs/Checkbox.tsx b/client/src/Components/v2/inputs/Checkbox.tsx new file mode 100644 index 000000000..195a796dd --- /dev/null +++ b/client/src/Components/v2/inputs/Checkbox.tsx @@ -0,0 +1,56 @@ +import { forwardRef } from "react"; +import Checkbox from "@mui/material/Checkbox"; +import type { CheckboxProps } from "@mui/material/Checkbox"; +import { Square, SquareCheck } from "lucide-react"; +import { useTheme } from "@mui/material/styles"; + +type CheckboxInputProps = CheckboxProps & { + label?: string; +}; +export const CheckboxInput = forwardRef( + function CheckboxInput( + { sx, ...props }: CheckboxInputProps, + ref: React.Ref + ) { + const theme = useTheme(); + return ( + + } + checkedIcon={ + + } + sx={{ + color: theme.palette.text.secondary, + "&.Mui-checked": { + color: theme.palette.primary.main, + }, + "&:hover": { backgroundColor: "transparent" }, + "& svg": { + stroke: "currentColor", + }, + "& svg path, & svg line, & svg polyline, & svg rect": { + stroke: "currentColor", + fill: "none", + }, + + ...sx, + }} + /> + ); + } +); diff --git a/client/src/Components/v2/inputs/FieldLabel.tsx b/client/src/Components/v2/inputs/FieldLabel.tsx new file mode 100644 index 000000000..552991538 --- /dev/null +++ b/client/src/Components/v2/inputs/FieldLabel.tsx @@ -0,0 +1,38 @@ +import Typography from "@mui/material/Typography"; +import { useTheme } from "@mui/material/styles"; + +interface FieldLabelProps { + children: React.ReactNode; + required?: boolean; + htmlFor?: string; +} + +export const FieldLabel = ({ children, required = false, htmlFor }: FieldLabelProps) => { + const theme = useTheme(); + + return ( + + {children} + {required && ( + + * + + )} + + ); +}; diff --git a/client/src/Components/v2/inputs/Select.tsx b/client/src/Components/v2/inputs/Select.tsx new file mode 100644 index 000000000..057b0e72c --- /dev/null +++ b/client/src/Components/v2/inputs/Select.tsx @@ -0,0 +1,102 @@ +import Select from "@mui/material/Select"; +import React from "react"; +import { useTheme } from "@mui/material/styles"; +import type { SelectProps } from "@mui/material/Select"; +import Stack from "@mui/material/Stack"; +import { FieldLabel } from "./FieldLabel"; +import { ChevronDown } from "lucide-react"; +import Typography from "@mui/material/Typography"; + +interface SelectInputProps extends Omit, "label"> { + fieldLabel?: string; + required?: boolean; + placeholder?: string; + placeholderColor?: string; +} + +export const SelectInput = ({ + fieldLabel, + required, + placeholder, + placeholderColor, + ...props +}: SelectInputProps) => { + const theme = useTheme(); + const emptyPlaceholderColor = placeholderColor || theme.palette.text.disabled; + + const renderValue = (selected: any) => { + const isMultiple = Boolean((props as any).multiple); + const isEmpty = isMultiple + ? !Array.isArray(selected) || selected.length === 0 + : selected === undefined || selected === null || selected === ""; + + if (isEmpty && placeholder) { + return {placeholder}; + } + + if (isMultiple) { + const items: string[] = Array.isArray(selected) ? selected : []; + const capitalized = items.map( + (item) => item.charAt(0).toUpperCase() + item.slice(1) + ); + return ({capitalized.join(" | ")}) as any; + } + + const nodes = React.Children.toArray(props.children as React.ReactNode); + for (const node of nodes) { + if (!React.isValidElement(node)) continue; + const el = node as React.ReactElement<{ + value?: unknown; + children?: React.ReactNode; + }>; + if (el.props?.value === selected) { + return (el.props.children ?? selected) as React.ReactNode; + } + } + return selected as React.ReactNode; + }; + + const select = ( + + {...props} + displayEmpty + renderValue={renderValue} + inputProps={{ + ...(props.inputProps || {}), + "aria-placeholder": placeholder, + }} + IconComponent={() => ( + + )} + sx={{ + height: "34px", + "& .MuiSelect-icon": { + right: theme.spacing(3), + }, + "& .MuiOutlinedInput-notchedOutline": { + borderRadius: theme.shape.borderRadius, + borderColor: theme.palette.divider, + }, + "&:hover .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.divider, + }, + ...props.sx, + }} + /> + ); + + if (fieldLabel) { + return ( + + {fieldLabel} + {select} + + ); + } + + return select; +}; diff --git a/client/src/Components/v2/inputs/index.tsx b/client/src/Components/v2/inputs/index.tsx index 9b582f3d7..3cd2516b1 100644 --- a/client/src/Components/v2/inputs/index.tsx +++ b/client/src/Components/v2/inputs/index.tsx @@ -1 +1,4 @@ export { ButtonInput as Button } from "./Button"; +export * from "./FieldLabel"; +export { SelectInput as Select } from "./Select"; +export { CheckboxInput as Checkbox } from "./Checkbox"; diff --git a/client/src/Components/v2/monitors/FilterControls.tsx b/client/src/Components/v2/monitors/FilterControls.tsx new file mode 100644 index 000000000..09776f71e --- /dev/null +++ b/client/src/Components/v2/monitors/FilterControls.tsx @@ -0,0 +1,11 @@ +import Stack from "@mui/material/Stack"; +import { Select } from "@/Components/v2/inputs"; +export const FilterControls = () => { + return ( + + + + + ); +}; diff --git a/client/src/Components/v2/monitors/index.tsx b/client/src/Components/v2/monitors/index.tsx new file mode 100644 index 000000000..aa1464399 --- /dev/null +++ b/client/src/Components/v2/monitors/index.tsx @@ -0,0 +1 @@ +export * from "./FilterControls"; diff --git a/client/src/Pages/Uptime/Monitors/index.tsx b/client/src/Pages/Uptime/Monitors/index.tsx index 9883c1470..5dc1100bf 100644 --- a/client/src/Pages/Uptime/Monitors/index.tsx +++ b/client/src/Pages/Uptime/Monitors/index.tsx @@ -1,15 +1,25 @@ +import { useGet } from "@/Hooks/UseApi"; import { MonitorBasePageWithStates } from "@/Components/v2/design-elements"; +import { type Monitor } from "@/Types/Monitor"; +import { FilterControls } from "@/Components/v2/monitors"; const UptimeMonitorsPage = () => { + const { + data: monitors, + isLoading, + error, + } = useGet("/monitors/team?type=http&type=ping&type=port&type=docker"); + return ( - Test + +
{JSON.stringify(monitors, null, 2)}
); }; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 1b3792e9e..d7c0d1cda 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -128,7 +128,14 @@ "pages": { "uptime": { "fallback": { - "title": "An uptime monitor is used to:" + "title": "An uptime monitor is used to:", + "actionButton": "Create a monitor!", + "checks": [ + "Check if websites or servers are online & responsive", + "Alert teams about downtime or performance issues", + "Monitor HTTP endpoints, pings, containers & ports", + "Track historical uptime and reliability trends" + ] } } },