mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 07:43:33 +00:00 
			
		
		
		
	Use status components for true/false things
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| import OverlayTrigger from "react-bootstrap/OverlayTrigger"; | import OverlayTrigger from "react-bootstrap/OverlayTrigger"; | ||||||
| import Popover from "react-bootstrap/Popover"; | import Popover from "react-bootstrap/Popover"; | ||||||
| import type { DeadHost, ProxyHost, RedirectionHost, Stream } from "src/api/backend"; | import type { DeadHost, ProxyHost, RedirectionHost, Stream } from "src/api/backend"; | ||||||
|  | import { TrueFalseFormatter } from "src/components"; | ||||||
| import { T } from "src/locale"; | import { T } from "src/locale"; | ||||||
|  |  | ||||||
| const getSection = (title: string, items: ProxyHost[] | RedirectionHost[] | DeadHost[]) => { | const getSection = (title: string, items: ProxyHost[] | RedirectionHost[] | DeadHost[]) => { | ||||||
| @@ -52,11 +53,7 @@ interface Props { | |||||||
| export function CertificateInUseFormatter({ proxyHosts, redirectionHosts, deadHosts, streams }: Props) { | export function CertificateInUseFormatter({ proxyHosts, redirectionHosts, deadHosts, streams }: Props) { | ||||||
| 	const totalCount = proxyHosts?.length + redirectionHosts?.length + deadHosts?.length + streams?.length; | 	const totalCount = proxyHosts?.length + redirectionHosts?.length + deadHosts?.length + streams?.length; | ||||||
| 	if (totalCount === 0) { | 	if (totalCount === 0) { | ||||||
| 		return ( | 		return <TrueFalseFormatter value={false} falseLabel="certificate.not-in-use" />; | ||||||
| 			<span className="badge bg-red-lt"> |  | ||||||
| 				<T id="certificate.not-in-use" /> |  | ||||||
| 			</span> |  | ||||||
| 		); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	proxyHosts.sort(); | 	proxyHosts.sort(); | ||||||
| @@ -76,10 +73,10 @@ export function CertificateInUseFormatter({ proxyHosts, redirectionHosts, deadHo | |||||||
| 	); | 	); | ||||||
|  |  | ||||||
| 	return ( | 	return ( | ||||||
| 		<OverlayTrigger trigger="hover" placement="bottom" overlay={popover}> | 		<OverlayTrigger trigger={["hover", "click", "focus"]} placement="bottom" overlay={popover}> | ||||||
| 			<span className="badge bg-lime-lt"> | 			<div> | ||||||
| 				<T id="certificate.in-use" /> | 				<TrueFalseFormatter value trueLabel="certificate.in-use" /> | ||||||
| 			</span> | 			</div> | ||||||
| 		</OverlayTrigger> | 		</OverlayTrigger> | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import cn from "classnames"; | ||||||
| import type { ReactNode } from "react"; | import type { ReactNode } from "react"; | ||||||
| import { DateTimeFormat, T } from "src/locale"; | import { DateTimeFormat, T } from "src/locale"; | ||||||
|  |  | ||||||
| @@ -6,9 +7,10 @@ interface Props { | |||||||
| 	createdOn?: string; | 	createdOn?: string; | ||||||
| 	niceName?: string; | 	niceName?: string; | ||||||
| 	provider?: string; | 	provider?: string; | ||||||
|  | 	color?: string; | ||||||
| } | } | ||||||
|  |  | ||||||
| const DomainLink = ({ domain }: { domain: string }) => { | const DomainLink = ({ domain, color }: { domain: string; color?: string }) => { | ||||||
| 	// when domain contains a wildcard, make the link go nowhere. | 	// when domain contains a wildcard, make the link go nowhere. | ||||||
| 	let onClick: ((e: React.MouseEvent) => void) | undefined; | 	let onClick: ((e: React.MouseEvent) => void) | undefined; | ||||||
| 	if (domain.includes("*")) { | 	if (domain.includes("*")) { | ||||||
| @@ -20,15 +22,14 @@ const DomainLink = ({ domain }: { domain: string }) => { | |||||||
| 			href={`http://${domain}`} | 			href={`http://${domain}`} | ||||||
| 			target="_blank" | 			target="_blank" | ||||||
| 			onClick={onClick} | 			onClick={onClick} | ||||||
| 			className="badge bg-yellow-lt domain-name me-2" | 			className={cn("badge", color ? `bg-${color}-lt` : null, "domain-name", "me-2")} | ||||||
| 		> | 		> | ||||||
| 			{domain} | 			{domain} | ||||||
| 		</a> | 		</a> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export function DomainsFormatter({ domains, createdOn, niceName, provider }: Props) { | export function DomainsFormatter({ domains, createdOn, niceName, provider, color }: Props) { | ||||||
| 	console.log("PROVIDER:", provider); |  | ||||||
| 	const elms: ReactNode[] = []; | 	const elms: ReactNode[] = []; | ||||||
| 	if (domains.length === 0 && !niceName) { | 	if (domains.length === 0 && !niceName) { | ||||||
| 		elms.push( | 		elms.push( | ||||||
| @@ -45,7 +46,7 @@ export function DomainsFormatter({ domains, createdOn, niceName, provider }: Pro | |||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	domains.map((domain: string) => elms.push(<DomainLink key={domain} domain={domain} />)); | 	domains.map((domain: string) => elms.push(<DomainLink key={domain} domain={domain} color={color} />)); | ||||||
|  |  | ||||||
| 	return ( | 	return ( | ||||||
| 		<div className="flex-fill"> | 		<div className="flex-fill"> | ||||||
|   | |||||||
| @@ -1,13 +0,0 @@ | |||||||
| import cn from "classnames"; |  | ||||||
| import { T } from "src/locale"; |  | ||||||
|  |  | ||||||
| interface Props { |  | ||||||
| 	enabled: boolean; |  | ||||||
| } |  | ||||||
| export function EnabledFormatter({ enabled }: Props) { |  | ||||||
| 	return ( |  | ||||||
| 		<span className={cn("badge", enabled ? "bg-lime-lt" : "bg-red-lt")}> |  | ||||||
| 			<T id={enabled ? "enabled" : "disabled"} /> |  | ||||||
| 		</span> |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| import cn from "classnames"; |  | ||||||
| import { T } from "src/locale"; |  | ||||||
|  |  | ||||||
| interface Props { |  | ||||||
| 	enabled: boolean; |  | ||||||
| } |  | ||||||
| export function StatusFormatter({ enabled }: Props) { |  | ||||||
| 	return ( |  | ||||||
| 		<span className={cn("badge", enabled ? "bg-lime-lt" : "bg-red-lt")}> |  | ||||||
| 			<T id={enabled ? "online" : "offline"} /> |  | ||||||
| 		</span> |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,24 @@ | |||||||
|  | import cn from "classnames"; | ||||||
|  | import { T } from "src/locale"; | ||||||
|  |  | ||||||
|  | interface Props { | ||||||
|  | 	value: boolean; | ||||||
|  | 	trueLabel?: string; | ||||||
|  | 	trueColor?: string; | ||||||
|  | 	falseLabel?: string; | ||||||
|  | 	falseColor?: string; | ||||||
|  | } | ||||||
|  | export function TrueFalseFormatter({ | ||||||
|  | 	value, | ||||||
|  | 	trueLabel = "enabled", | ||||||
|  | 	trueColor = "lime", | ||||||
|  | 	falseLabel = "disabled", | ||||||
|  | 	falseColor = "red", | ||||||
|  | }: Props) { | ||||||
|  | 	return ( | ||||||
|  | 		<span className={cn("status", `status-${value ? trueColor : falseColor}`)}> | ||||||
|  | 			<span className="status-dot status-dot-animated" /> | ||||||
|  | 			<T id={value ? trueLabel : falseLabel} /> | ||||||
|  | 		</span> | ||||||
|  | 	); | ||||||
|  | } | ||||||
| @@ -4,9 +4,8 @@ export * from "./CertificateInUseFormatter"; | |||||||
| export * from "./DateFormatter"; | export * from "./DateFormatter"; | ||||||
| export * from "./DomainsFormatter"; | export * from "./DomainsFormatter"; | ||||||
| export * from "./EmailFormatter"; | export * from "./EmailFormatter"; | ||||||
| export * from "./EnabledFormatter"; |  | ||||||
| export * from "./EventFormatter"; | export * from "./EventFormatter"; | ||||||
| export * from "./GravatarFormatter"; | export * from "./GravatarFormatter"; | ||||||
| export * from "./RolesFormatter"; | export * from "./RolesFormatter"; | ||||||
| export * from "./StatusFormatter"; | export * from "./TrueFalseFormatter"; | ||||||
| export * from "./ValueWithDateFormatter"; | export * from "./ValueWithDateFormatter"; | ||||||
|   | |||||||
| @@ -116,6 +116,7 @@ const Dashboard = () => { | |||||||
| 				<code>{`Todo: | 				<code>{`Todo: | ||||||
|  |  | ||||||
| - check mobile | - check mobile | ||||||
|  | - use statuses for table formatters where applicable: https://docs.tabler.io/ui/components/statuses | ||||||
| - add help docs for host types | - add help docs for host types | ||||||
| - REDO SCREENSHOTS in docs folder | - REDO SCREENSHOTS in docs folder | ||||||
| - search codebase for "TODO" | - search codebase for "TODO" | ||||||
| @@ -125,7 +126,6 @@ const Dashboard = () => { | |||||||
|  |  | ||||||
| More for api, then implement here: | More for api, then implement here: | ||||||
| - Add error message_18n for all backend errors | - Add error message_18n for all backend errors | ||||||
| - minor: certificates expand with hosts needs to omit 'is_deleted' |  | ||||||
| - properly wrap all logger.debug called in isDebug check | - properly wrap all logger.debug called in isDebug check | ||||||
| - add new api endpoint changes to swagger docs | - add new api endpoint changes to swagger docs | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,13 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons- | |||||||
| import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; | import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; | ||||||
| import { useMemo } from "react"; | import { useMemo } from "react"; | ||||||
| import type { DeadHost } from "src/api/backend"; | import type { DeadHost } from "src/api/backend"; | ||||||
| import { CertificateFormatter, DomainsFormatter, EmptyData, GravatarFormatter, StatusFormatter } from "src/components"; | import { | ||||||
|  | 	CertificateFormatter, | ||||||
|  | 	DomainsFormatter, | ||||||
|  | 	EmptyData, | ||||||
|  | 	GravatarFormatter, | ||||||
|  | 	TrueFalseFormatter, | ||||||
|  | } from "src/components"; | ||||||
| import { TableLayout } from "src/components/Table/TableLayout"; | import { TableLayout } from "src/components/Table/TableLayout"; | ||||||
| import { intl, T } from "src/locale"; | import { intl, T } from "src/locale"; | ||||||
|  |  | ||||||
| @@ -48,7 +54,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog | |||||||
| 				id: "enabled", | 				id: "enabled", | ||||||
| 				header: intl.formatMessage({ id: "column.status" }), | 				header: intl.formatMessage({ id: "column.status" }), | ||||||
| 				cell: (info: any) => { | 				cell: (info: any) => { | ||||||
| 					return <StatusFormatter enabled={info.getValue()} />; | 					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />; | ||||||
| 				}, | 				}, | ||||||
| 			}), | 			}), | ||||||
| 			columnHelper.display({ | 			columnHelper.display({ | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import { | |||||||
| 	DomainsFormatter, | 	DomainsFormatter, | ||||||
| 	EmptyData, | 	EmptyData, | ||||||
| 	GravatarFormatter, | 	GravatarFormatter, | ||||||
| 	StatusFormatter, | 	TrueFalseFormatter, | ||||||
| } from "src/components"; | } from "src/components"; | ||||||
| import { TableLayout } from "src/components/Table/TableLayout"; | import { TableLayout } from "src/components/Table/TableLayout"; | ||||||
| import { intl, T } from "src/locale"; | import { intl, T } from "src/locale"; | ||||||
| @@ -70,7 +70,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog | |||||||
| 				id: "enabled", | 				id: "enabled", | ||||||
| 				header: intl.formatMessage({ id: "column.status" }), | 				header: intl.formatMessage({ id: "column.status" }), | ||||||
| 				cell: (info: any) => { | 				cell: (info: any) => { | ||||||
| 					return <StatusFormatter enabled={info.getValue()} />; | 					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />; | ||||||
| 				}, | 				}, | ||||||
| 			}), | 			}), | ||||||
| 			columnHelper.display({ | 			columnHelper.display({ | ||||||
|   | |||||||
| @@ -2,7 +2,13 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons- | |||||||
| import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; | import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; | ||||||
| import { useMemo } from "react"; | import { useMemo } from "react"; | ||||||
| import type { RedirectionHost } from "src/api/backend"; | import type { RedirectionHost } from "src/api/backend"; | ||||||
| import { CertificateFormatter, DomainsFormatter, EmptyData, GravatarFormatter, StatusFormatter } from "src/components"; | import { | ||||||
|  | 	CertificateFormatter, | ||||||
|  | 	DomainsFormatter, | ||||||
|  | 	EmptyData, | ||||||
|  | 	GravatarFormatter, | ||||||
|  | 	TrueFalseFormatter, | ||||||
|  | } from "src/components"; | ||||||
| import { TableLayout } from "src/components/Table/TableLayout"; | import { TableLayout } from "src/components/Table/TableLayout"; | ||||||
| import { intl, T } from "src/locale"; | import { intl, T } from "src/locale"; | ||||||
|  |  | ||||||
| @@ -69,7 +75,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog | |||||||
| 				id: "enabled", | 				id: "enabled", | ||||||
| 				header: intl.formatMessage({ id: "column.status" }), | 				header: intl.formatMessage({ id: "column.status" }), | ||||||
| 				cell: (info: any) => { | 				cell: (info: any) => { | ||||||
| 					return <StatusFormatter enabled={info.getValue()} />; | 					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />; | ||||||
| 				}, | 				}, | ||||||
| 			}), | 			}), | ||||||
| 			columnHelper.display({ | 			columnHelper.display({ | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import { | |||||||
| 	CertificateFormatter, | 	CertificateFormatter, | ||||||
| 	EmptyData, | 	EmptyData, | ||||||
| 	GravatarFormatter, | 	GravatarFormatter, | ||||||
| 	StatusFormatter, | 	TrueFalseFormatter, | ||||||
| 	ValueWithDateFormatter, | 	ValueWithDateFormatter, | ||||||
| } from "src/components"; | } from "src/components"; | ||||||
| import { TableLayout } from "src/components/Table/TableLayout"; | import { TableLayout } from "src/components/Table/TableLayout"; | ||||||
| @@ -83,7 +83,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete, | |||||||
| 				id: "enabled", | 				id: "enabled", | ||||||
| 				header: intl.formatMessage({ id: "column.status" }), | 				header: intl.formatMessage({ id: "column.status" }), | ||||||
| 				cell: (info: any) => { | 				cell: (info: any) => { | ||||||
| 					return <StatusFormatter enabled={info.getValue()} />; | 					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />; | ||||||
| 				}, | 				}, | ||||||
| 			}), | 			}), | ||||||
| 			columnHelper.display({ | 			columnHelper.display({ | ||||||
|   | |||||||
| @@ -5,9 +5,9 @@ import type { User } from "src/api/backend"; | |||||||
| import { | import { | ||||||
| 	EmailFormatter, | 	EmailFormatter, | ||||||
| 	EmptyData, | 	EmptyData, | ||||||
| 	EnabledFormatter, |  | ||||||
| 	GravatarFormatter, | 	GravatarFormatter, | ||||||
| 	RolesFormatter, | 	RolesFormatter, | ||||||
|  | 	TrueFalseFormatter, | ||||||
| 	ValueWithDateFormatter, | 	ValueWithDateFormatter, | ||||||
| } from "src/components"; | } from "src/components"; | ||||||
| import { TableLayout } from "src/components/Table/TableLayout"; | import { TableLayout } from "src/components/Table/TableLayout"; | ||||||
| @@ -83,7 +83,7 @@ export default function Table({ | |||||||
| 				id: "isDisabled", | 				id: "isDisabled", | ||||||
| 				header: intl.formatMessage({ id: "column.status" }), | 				header: intl.formatMessage({ id: "column.status" }), | ||||||
| 				cell: (info: any) => { | 				cell: (info: any) => { | ||||||
| 					return <EnabledFormatter enabled={!info.getValue()} />; | 					return <TrueFalseFormatter value={!info.getValue()} />; | ||||||
| 				}, | 				}, | ||||||
| 			}), | 			}), | ||||||
| 			columnHelper.display({ | 			columnHelper.display({ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user