mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-11-04 09:25:15 +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 Popover from "react-bootstrap/Popover";
 | 
			
		||||
import type { DeadHost, ProxyHost, RedirectionHost, Stream } from "src/api/backend";
 | 
			
		||||
import { TrueFalseFormatter } from "src/components";
 | 
			
		||||
import { T } from "src/locale";
 | 
			
		||||
 | 
			
		||||
const getSection = (title: string, items: ProxyHost[] | RedirectionHost[] | DeadHost[]) => {
 | 
			
		||||
@@ -52,11 +53,7 @@ interface Props {
 | 
			
		||||
export function CertificateInUseFormatter({ proxyHosts, redirectionHosts, deadHosts, streams }: Props) {
 | 
			
		||||
	const totalCount = proxyHosts?.length + redirectionHosts?.length + deadHosts?.length + streams?.length;
 | 
			
		||||
	if (totalCount === 0) {
 | 
			
		||||
		return (
 | 
			
		||||
			<span className="badge bg-red-lt">
 | 
			
		||||
				<T id="certificate.not-in-use" />
 | 
			
		||||
			</span>
 | 
			
		||||
		);
 | 
			
		||||
		return <TrueFalseFormatter value={false} falseLabel="certificate.not-in-use" />;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	proxyHosts.sort();
 | 
			
		||||
@@ -76,10 +73,10 @@ export function CertificateInUseFormatter({ proxyHosts, redirectionHosts, deadHo
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<OverlayTrigger trigger="hover" placement="bottom" overlay={popover}>
 | 
			
		||||
			<span className="badge bg-lime-lt">
 | 
			
		||||
				<T id="certificate.in-use" />
 | 
			
		||||
			</span>
 | 
			
		||||
		<OverlayTrigger trigger={["hover", "click", "focus"]} placement="bottom" overlay={popover}>
 | 
			
		||||
			<div>
 | 
			
		||||
				<TrueFalseFormatter value trueLabel="certificate.in-use" />
 | 
			
		||||
			</div>
 | 
			
		||||
		</OverlayTrigger>
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import cn from "classnames";
 | 
			
		||||
import type { ReactNode } from "react";
 | 
			
		||||
import { DateTimeFormat, T } from "src/locale";
 | 
			
		||||
 | 
			
		||||
@@ -6,9 +7,10 @@ interface Props {
 | 
			
		||||
	createdOn?: string;
 | 
			
		||||
	niceName?: 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.
 | 
			
		||||
	let onClick: ((e: React.MouseEvent) => void) | undefined;
 | 
			
		||||
	if (domain.includes("*")) {
 | 
			
		||||
@@ -20,15 +22,14 @@ const DomainLink = ({ domain }: { domain: string }) => {
 | 
			
		||||
			href={`http://${domain}`}
 | 
			
		||||
			target="_blank"
 | 
			
		||||
			onClick={onClick}
 | 
			
		||||
			className="badge bg-yellow-lt domain-name me-2"
 | 
			
		||||
			className={cn("badge", color ? `bg-${color}-lt` : null, "domain-name", "me-2")}
 | 
			
		||||
		>
 | 
			
		||||
			{domain}
 | 
			
		||||
		</a>
 | 
			
		||||
	);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function DomainsFormatter({ domains, createdOn, niceName, provider }: Props) {
 | 
			
		||||
	console.log("PROVIDER:", provider);
 | 
			
		||||
export function DomainsFormatter({ domains, createdOn, niceName, provider, color }: Props) {
 | 
			
		||||
	const elms: ReactNode[] = [];
 | 
			
		||||
	if (domains.length === 0 && !niceName) {
 | 
			
		||||
		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 (
 | 
			
		||||
		<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 "./DomainsFormatter";
 | 
			
		||||
export * from "./EmailFormatter";
 | 
			
		||||
export * from "./EnabledFormatter";
 | 
			
		||||
export * from "./EventFormatter";
 | 
			
		||||
export * from "./GravatarFormatter";
 | 
			
		||||
export * from "./RolesFormatter";
 | 
			
		||||
export * from "./StatusFormatter";
 | 
			
		||||
export * from "./TrueFalseFormatter";
 | 
			
		||||
export * from "./ValueWithDateFormatter";
 | 
			
		||||
 
 | 
			
		||||
@@ -116,6 +116,7 @@ const Dashboard = () => {
 | 
			
		||||
				<code>{`Todo:
 | 
			
		||||
 | 
			
		||||
- check mobile
 | 
			
		||||
- use statuses for table formatters where applicable: https://docs.tabler.io/ui/components/statuses
 | 
			
		||||
- add help docs for host types
 | 
			
		||||
- REDO SCREENSHOTS in docs folder
 | 
			
		||||
- search codebase for "TODO"
 | 
			
		||||
@@ -125,7 +126,6 @@ const Dashboard = () => {
 | 
			
		||||
 | 
			
		||||
More for api, then implement here:
 | 
			
		||||
- 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
 | 
			
		||||
- 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 { useMemo } from "react";
 | 
			
		||||
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 { intl, T } from "src/locale";
 | 
			
		||||
 | 
			
		||||
@@ -48,7 +54,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
 | 
			
		||||
				id: "enabled",
 | 
			
		||||
				header: intl.formatMessage({ id: "column.status" }),
 | 
			
		||||
				cell: (info: any) => {
 | 
			
		||||
					return <StatusFormatter enabled={info.getValue()} />;
 | 
			
		||||
					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />;
 | 
			
		||||
				},
 | 
			
		||||
			}),
 | 
			
		||||
			columnHelper.display({
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import {
 | 
			
		||||
	DomainsFormatter,
 | 
			
		||||
	EmptyData,
 | 
			
		||||
	GravatarFormatter,
 | 
			
		||||
	StatusFormatter,
 | 
			
		||||
	TrueFalseFormatter,
 | 
			
		||||
} from "src/components";
 | 
			
		||||
import { TableLayout } from "src/components/Table/TableLayout";
 | 
			
		||||
import { intl, T } from "src/locale";
 | 
			
		||||
@@ -70,7 +70,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
 | 
			
		||||
				id: "enabled",
 | 
			
		||||
				header: intl.formatMessage({ id: "column.status" }),
 | 
			
		||||
				cell: (info: any) => {
 | 
			
		||||
					return <StatusFormatter enabled={info.getValue()} />;
 | 
			
		||||
					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />;
 | 
			
		||||
				},
 | 
			
		||||
			}),
 | 
			
		||||
			columnHelper.display({
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,13 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-
 | 
			
		||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
 | 
			
		||||
import { useMemo } from "react";
 | 
			
		||||
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 { intl, T } from "src/locale";
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +75,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
 | 
			
		||||
				id: "enabled",
 | 
			
		||||
				header: intl.formatMessage({ id: "column.status" }),
 | 
			
		||||
				cell: (info: any) => {
 | 
			
		||||
					return <StatusFormatter enabled={info.getValue()} />;
 | 
			
		||||
					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />;
 | 
			
		||||
				},
 | 
			
		||||
			}),
 | 
			
		||||
			columnHelper.display({
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import {
 | 
			
		||||
	CertificateFormatter,
 | 
			
		||||
	EmptyData,
 | 
			
		||||
	GravatarFormatter,
 | 
			
		||||
	StatusFormatter,
 | 
			
		||||
	TrueFalseFormatter,
 | 
			
		||||
	ValueWithDateFormatter,
 | 
			
		||||
} from "src/components";
 | 
			
		||||
import { TableLayout } from "src/components/Table/TableLayout";
 | 
			
		||||
@@ -83,7 +83,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
 | 
			
		||||
				id: "enabled",
 | 
			
		||||
				header: intl.formatMessage({ id: "column.status" }),
 | 
			
		||||
				cell: (info: any) => {
 | 
			
		||||
					return <StatusFormatter enabled={info.getValue()} />;
 | 
			
		||||
					return <TrueFalseFormatter value={info.getValue()} trueLabel="online" falseLabel="offline" />;
 | 
			
		||||
				},
 | 
			
		||||
			}),
 | 
			
		||||
			columnHelper.display({
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,9 @@ import type { User } from "src/api/backend";
 | 
			
		||||
import {
 | 
			
		||||
	EmailFormatter,
 | 
			
		||||
	EmptyData,
 | 
			
		||||
	EnabledFormatter,
 | 
			
		||||
	GravatarFormatter,
 | 
			
		||||
	RolesFormatter,
 | 
			
		||||
	TrueFalseFormatter,
 | 
			
		||||
	ValueWithDateFormatter,
 | 
			
		||||
} from "src/components";
 | 
			
		||||
import { TableLayout } from "src/components/Table/TableLayout";
 | 
			
		||||
@@ -83,7 +83,7 @@ export default function Table({
 | 
			
		||||
				id: "isDisabled",
 | 
			
		||||
				header: intl.formatMessage({ id: "column.status" }),
 | 
			
		||||
				cell: (info: any) => {
 | 
			
		||||
					return <EnabledFormatter enabled={!info.getValue()} />;
 | 
			
		||||
					return <TrueFalseFormatter value={!info.getValue()} />;
 | 
			
		||||
				},
 | 
			
		||||
			}),
 | 
			
		||||
			columnHelper.display({
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user