diff --git a/client/src/Components/design-elements/CopyButton.tsx b/client/src/Components/design-elements/CopyButton.tsx deleted file mode 100644 index 5d45b9739..000000000 --- a/client/src/Components/design-elements/CopyButton.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import IconButton from "@mui/material/IconButton"; -import Tooltip from "@mui/material/Tooltip"; -import { useTheme } from "@mui/material/styles"; -import { Check, Copy } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { useToast } from "@/Hooks/UseToast"; - -const RESET_DELAY_MS = 1500; - -/** - * `navigator.clipboard` only exists on secure origins, and Checkmate is often - * self-hosted over plain HTTP on a LAN address. Fall back to a hidden textarea - * there rather than leaving the button permanently broken. - */ -const copyText = async (value: string) => { - if (navigator.clipboard?.writeText) { - return navigator.clipboard.writeText(value); - } - - const textarea = document.createElement("textarea"); - textarea.value = value; - textarea.setAttribute("readonly", ""); - textarea.style.position = "fixed"; - textarea.style.opacity = "0"; - document.body.appendChild(textarea); - textarea.select(); - - try { - if (!document.execCommand("copy")) throw new Error("Copy command was rejected"); - } finally { - document.body.removeChild(textarea); - } -}; - -/** - * Copies `value` to the clipboard. Shows a tick for a moment so the click is - * acknowledged without moving the user anywhere. - */ -const CopyButton = ({ value, label }: { value: string; label?: string }) => { - const theme = useTheme(); - const { t } = useTranslation(); - const { toastError } = useToast(); - const [copied, setCopied] = useState(false); - const resetTimer = useRef>(undefined); - - // These rows unmount on pagination, so the tick timer has to be cancelled. - useEffect(() => () => clearTimeout(resetTimer.current), []); - - const handleCopy = async (e: React.MouseEvent) => { - // The button usually sits inside a clickable row. - e.stopPropagation(); - - try { - await copyText(value); - setCopied(true); - clearTimeout(resetTimer.current); - resetTimer.current = setTimeout(() => setCopied(false), RESET_DELAY_MS); - } catch { - toastError(t("common.copyFailed")); - } - }; - - const title = copied ? t("common.copied") : (label ?? t("common.copy")); - - return ( - - - {copied ? ( - - ) : ( - - )} - - - ); -}; - -export default CopyButton; diff --git a/client/src/Components/design-elements/CopyableText.tsx b/client/src/Components/design-elements/CopyableText.tsx deleted file mode 100644 index 5d09e307b..000000000 --- a/client/src/Components/design-elements/CopyableText.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import Stack from "@mui/material/Stack"; -import { useTheme } from "@mui/material/styles"; -import { useTranslation } from "react-i18next"; -import { LAYOUT } from "@/Utils/Theme/constants"; -import CopyButton from "./CopyButton"; - -/** - * Text alongside a copy button, for table cells holding values worth lifting - * out - error messages in particular. - */ -const CopyableText = ({ - value, - fallback = "N/A", - copyLabel, -}: { - value?: string | null; - fallback?: string; - copyLabel?: string; -}) => { - const theme = useTheme(); - const { t } = useTranslation(); - - if (!value) return <>{fallback}; - - return ( - - {value} - - - ); -}; - -export default CopyableText; diff --git a/client/src/Components/design-elements/index.tsx b/client/src/Components/design-elements/index.tsx index e1c1c3965..d7d38d014 100644 --- a/client/src/Components/design-elements/index.tsx +++ b/client/src/Components/design-elements/index.tsx @@ -28,5 +28,3 @@ export * from "./Avatar"; export * from "./StatusCodeLabel"; export * from "./StrategyBadge"; export * from "./StepProgress"; -export { default as CopyButton } from "./CopyButton"; -export { default as CopyableText } from "./CopyableText"; diff --git a/client/src/Pages/Checks/Components/ChecksTable.tsx b/client/src/Pages/Checks/Components/ChecksTable.tsx index 4d5eebbdf..31737f4bb 100644 --- a/client/src/Pages/Checks/Components/ChecksTable.tsx +++ b/client/src/Pages/Checks/Components/ChecksTable.tsx @@ -3,7 +3,6 @@ import { Pagination, StatusLabel, StatusCodeLabel, - CopyableText, } from "@/Components/design-elements"; import Box from "@mui/material/Box"; import type { Header } from "@/Components/design-elements/Table"; @@ -80,7 +79,7 @@ export const ChecksTable = ({ id: "message", content: t("common.table.headers.message"), render: (row) => { - return ; + return row.message || "N/A"; }, }, ]; diff --git a/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx b/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx index ae1d87d45..b100c28c4 100644 --- a/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx +++ b/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx @@ -3,7 +3,6 @@ import { Pagination, StatusLabel, StatusCodeLabel, - CopyableText, } from "@/Components/design-elements"; import Box from "@mui/material/Box"; import type { Header } from "@/Components/design-elements"; @@ -53,7 +52,7 @@ export const ChecksTable = ({ id: "message", content: t("common.table.headers.message"), render: (row) => { - return ; + return row.message || "N/A"; }, }, { diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 9b193ef1f..cbebadded 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -14,10 +14,6 @@ } }, "appName": "Checkmate", - "copy": "Copy", - "copied": "Copied", - "copyMessage": "Copy message", - "copyFailed": "Could not copy to clipboard", "statusCode": { "down": "Down", "networkError": {