1
0
mirror of https://github.com/NginxProxyManager/nginx-proxy-manager.git synced 2025-10-29 06:49:22 +03:00

Use status components for true/false things

This commit is contained in:
Jamie Curnow
2025-10-27 23:25:00 +10:00
parent fac5f2cbc5
commit 0f718570d6
12 changed files with 60 additions and 53 deletions

View File

@@ -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>
); );
} }

View File

@@ -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">

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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";

View File

@@ -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

View File

@@ -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({

View File

@@ -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({

View File

@@ -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({

View File

@@ -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({

View File

@@ -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({