mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-11-04 17:35:15 +00:00
Wrap intl in span identifying translation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button } from "src/components";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
export function ErrorNotFound() {
|
||||
const navigate = useNavigate();
|
||||
@@ -8,11 +8,15 @@ export function ErrorNotFound() {
|
||||
return (
|
||||
<div className="container-tight py-4">
|
||||
<div className="empty">
|
||||
<p className="empty-title">{intl.formatMessage({ id: "notfound.title" })}</p>
|
||||
<p className="empty-subtitle text-secondary">{intl.formatMessage({ id: "notfound.text" })}</p>
|
||||
<p className="empty-title">
|
||||
<T id="notfound.title" />
|
||||
</p>
|
||||
<p className="empty-subtitle text-secondary">
|
||||
<T id="notfound.text" />
|
||||
</p>
|
||||
<div className="empty-action">
|
||||
<Button type="button" size="md" onClick={() => navigate("/")}>
|
||||
{intl.formatMessage({ id: "notfound.action" })}
|
||||
<T id="notfound.action" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
99
frontend/src/components/Form/AccessField.tsx
Normal file
99
frontend/src/components/Form/AccessField.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { IconLock, IconLockOpen2 } from "@tabler/icons-react";
|
||||
import { Field, useFormikContext } from "formik";
|
||||
import type { ReactNode } from "react";
|
||||
import Select, { type ActionMeta, components, type OptionProps } from "react-select";
|
||||
import type { AccessList } from "src/api/backend";
|
||||
import { useAccessLists } from "src/hooks";
|
||||
import { DateTimeFormat, intl, T } from "src/locale";
|
||||
|
||||
interface AccessOption {
|
||||
readonly value: number;
|
||||
readonly label: string;
|
||||
readonly subLabel: string;
|
||||
readonly icon: ReactNode;
|
||||
}
|
||||
|
||||
const Option = (props: OptionProps<AccessOption>) => {
|
||||
return (
|
||||
<components.Option {...props}>
|
||||
<div className="flex-fill">
|
||||
<div className="font-weight-medium">
|
||||
{props.data.icon} <strong>{props.data.label}</strong>
|
||||
</div>
|
||||
<div className="text-secondary mt-1 ps-3">{props.data.subLabel}</div>
|
||||
</div>
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
}
|
||||
export function AccessField({ name = "accessListId", label = "access.title", id = "accessListId" }: Props) {
|
||||
const { isLoading, isError, error, data } = useAccessLists();
|
||||
const { setFieldValue } = useFormikContext();
|
||||
|
||||
const handleChange = (newValue: any, _actionMeta: ActionMeta<AccessOption>) => {
|
||||
setFieldValue(name, newValue?.value);
|
||||
};
|
||||
|
||||
const options: AccessOption[] =
|
||||
data?.map((item: AccessList) => ({
|
||||
value: item.id || 0,
|
||||
label: item.name,
|
||||
subLabel: intl.formatMessage(
|
||||
{ id: "access.subtitle" },
|
||||
{
|
||||
users: item?.items?.length,
|
||||
rules: item?.clients?.length,
|
||||
date: item?.createdOn ? DateTimeFormat(item?.createdOn) : "N/A",
|
||||
},
|
||||
),
|
||||
icon: <IconLock size={14} className="text-lime" />,
|
||||
})) || [];
|
||||
|
||||
// Public option
|
||||
options?.unshift({
|
||||
value: 0,
|
||||
label: intl.formatMessage({ id: "access.public" }),
|
||||
subLabel: "No basic auth required",
|
||||
icon: <IconLockOpen2 size={14} className="text-red" />,
|
||||
});
|
||||
|
||||
return (
|
||||
<Field name={name}>
|
||||
{({ field, form }: any) => (
|
||||
<div className="mb-3">
|
||||
<label className="form-label" htmlFor={id}>
|
||||
<T id={label} />
|
||||
</label>
|
||||
{isLoading ? <div className="placeholder placeholder-lg col-12 my-3 placeholder-glow" /> : null}
|
||||
{isError ? <div className="invalid-feedback">{`${error}`}</div> : null}
|
||||
{!isLoading && !isError ? (
|
||||
<Select
|
||||
className="react-select-container"
|
||||
classNamePrefix="react-select"
|
||||
defaultValue={options.find((o) => o.value === field.value) || options[0]}
|
||||
options={options}
|
||||
components={{ Option }}
|
||||
styles={{
|
||||
option: (base) => ({
|
||||
...base,
|
||||
height: "100%",
|
||||
}),
|
||||
}}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
) : null}
|
||||
{form.errors[field.name] ? (
|
||||
<div className="invalid-feedback">
|
||||
{form.errors[field.name] && form.touched[field.name] ? form.errors[field.name] : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
36
frontend/src/components/Form/BasicAuthField.tsx
Normal file
36
frontend/src/components/Form/BasicAuthField.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useFormikContext } from "formik";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
export function BasicAuthField({ name = "items", id = "items" }: Props) {
|
||||
const { setFieldValue } = useFormikContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-6">
|
||||
<label className="form-label" htmlFor="...">
|
||||
<T id="username" />
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<label className="form-label" htmlFor="...">
|
||||
<T id="password" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row mb-3">
|
||||
<div className="col-6">
|
||||
<input id="name" type="text" required autoComplete="off" className="form-control" />
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<input id="pw" type="password" required autoComplete="off" className="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<button className="btn">+</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -10,7 +10,6 @@ interface DNSProviderOption {
|
||||
readonly label: string;
|
||||
readonly credentials: string;
|
||||
}
|
||||
|
||||
export function DNSProviderFields() {
|
||||
const { values, setFieldValue } = useFormikContext();
|
||||
const { data: dnsProviders, isLoading } = useDnsProviders();
|
||||
@@ -100,6 +99,7 @@ export function DNSProviderFields() {
|
||||
<input
|
||||
id="propagationSeconds"
|
||||
type="number"
|
||||
x
|
||||
className="form-control"
|
||||
min={0}
|
||||
max={600}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Field, useFormikContext } from "formik";
|
||||
import type { ReactNode } from "react";
|
||||
import type { ActionMeta, MultiValue } from "react-select";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import { intl } from "src/locale";
|
||||
import { intl, T } from "src/locale";
|
||||
import { validateDomain, validateDomains } from "src/modules/Validations";
|
||||
|
||||
export type SelectOption = {
|
||||
type SelectOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
color?: string;
|
||||
@@ -35,14 +36,14 @@ export function DomainNamesField({
|
||||
setFieldValue(name, doms);
|
||||
};
|
||||
|
||||
const helperTexts: string[] = [];
|
||||
const helperTexts: ReactNode[] = [];
|
||||
if (maxDomains) {
|
||||
helperTexts.push(intl.formatMessage({ id: "domain-names.max" }, { count: maxDomains }));
|
||||
helperTexts.push(<T id="domain-names.max" data={{ count: maxDomains }} />);
|
||||
}
|
||||
if (!isWildcardPermitted) {
|
||||
helperTexts.push(intl.formatMessage({ id: "domain-names.wildcards-not-permitted" }));
|
||||
helperTexts.push(<T id="domain-names.wildcards-not-permitted" />);
|
||||
} else if (!dnsProviderWildcardSupported) {
|
||||
helperTexts.push(intl.formatMessage({ id: "domain-names.wildcards-not-supported" }));
|
||||
helperTexts.push(<T id="domain-names.wildcards-not-supported" />);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -50,7 +51,7 @@ export function DomainNamesField({
|
||||
{({ field, form }: any) => (
|
||||
<div className="mb-3">
|
||||
<label className="form-label" htmlFor={id}>
|
||||
{intl.formatMessage({ id: label })}
|
||||
<T id={label} />
|
||||
</label>
|
||||
<CreatableSelect
|
||||
className="react-select-container"
|
||||
@@ -68,8 +69,8 @@ export function DomainNamesField({
|
||||
{form.errors[field.name] && form.touched[field.name] ? (
|
||||
<small className="text-danger">{form.errors[field.name]}</small>
|
||||
) : helperTexts.length ? (
|
||||
helperTexts.map((i) => (
|
||||
<small key={i} className="text-info">
|
||||
helperTexts.map((i, idx) => (
|
||||
<small key={idx} className="text-info">
|
||||
{i}
|
||||
</small>
|
||||
))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import CodeEditor from "@uiw/react-textarea-code-editor";
|
||||
import { Field } from "formik";
|
||||
import { intl } from "src/locale";
|
||||
import { intl, T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
@@ -17,7 +17,7 @@ export function NginxConfigField({
|
||||
{({ field }: any) => (
|
||||
<div className="mt-3">
|
||||
<label htmlFor={id} className="form-label">
|
||||
{intl.formatMessage({ id: label })}
|
||||
<T id={label} />
|
||||
</label>
|
||||
<CodeEditor
|
||||
language="nginx"
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Field, useFormikContext } from "formik";
|
||||
import Select, { type ActionMeta, components, type OptionProps } from "react-select";
|
||||
import type { Certificate } from "src/api/backend";
|
||||
import { useCertificates } from "src/hooks";
|
||||
import { DateTimeFormat, intl } from "src/locale";
|
||||
import { DateTimeFormat, T } from "src/locale";
|
||||
|
||||
interface CertOption {
|
||||
readonly value: number | "new";
|
||||
@@ -106,7 +106,7 @@ export function SSLCertificateField({
|
||||
{({ field, form }: any) => (
|
||||
<div className="mb-3">
|
||||
<label className="form-label" htmlFor={id}>
|
||||
{intl.formatMessage({ id: label })}
|
||||
<T id={label} />
|
||||
</label>
|
||||
{isLoading ? <div className="placeholder placeholder-lg col-12 my-3 placeholder-glow" /> : null}
|
||||
{isError ? <div className="invalid-feedback">{`${error}`}</div> : null}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cn from "classnames";
|
||||
import { Field, useFormikContext } from "formik";
|
||||
import { DNSProviderFields, DomainNamesField } from "src/components";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields
|
||||
@@ -49,7 +49,7 @@ export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomain
|
||||
disabled={!hasCertificate}
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
{intl.formatMessage({ id: "domains.force-ssl" })}
|
||||
<T id="domains.force-ssl" />
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
@@ -67,7 +67,7 @@ export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomain
|
||||
disabled={!hasCertificate}
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
{intl.formatMessage({ id: "domains.http2-support" })}
|
||||
<T id="domains.http2-support" />
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
@@ -87,7 +87,7 @@ export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomain
|
||||
disabled={!hasCertificate || !sslForced}
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
{intl.formatMessage({ id: "domains.hsts-enabled" })}
|
||||
<T id="domains.hsts-enabled" />
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
@@ -105,7 +105,7 @@ export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomain
|
||||
disabled={!hasCertificate || !hstsEnabled}
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
{intl.formatMessage({ id: "domains.hsts-subdomains" })}
|
||||
<T id="domains.hsts-subdomains" />
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
@@ -131,7 +131,7 @@ export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomain
|
||||
onChange={(e) => handleToggleChange(e, field.name)}
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
{intl.formatMessage({ id: "domains.use-dns" })}
|
||||
<T id="domains.use-dns" />
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from "./AccessField";
|
||||
export * from "./BasicAuthField";
|
||||
export * from "./DNSProviderFields";
|
||||
export * from "./DomainNamesField";
|
||||
export * from "./NginxConfigField";
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
|
||||
import Alert from "react-bootstrap/Alert";
|
||||
import { Loading, LoadingPage } from "src/components";
|
||||
import { useUser } from "src/hooks";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
permission: string;
|
||||
@@ -64,7 +64,11 @@ function HasPermission({
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
return !hideError ? <Alert variant="danger">{intl.formatMessage({ id: "no-permission-error" })}</Alert> : null;
|
||||
return !hideError ? (
|
||||
<Alert variant="danger">
|
||||
<T id="no-permission-error" />
|
||||
</Alert>
|
||||
) : null;
|
||||
}
|
||||
|
||||
export { HasPermission };
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { intl } from "src/locale";
|
||||
import type { ReactNode } from "react";
|
||||
import { T } from "src/locale";
|
||||
import styles from "./Loading.module.css";
|
||||
|
||||
interface Props {
|
||||
label?: string;
|
||||
label?: string | ReactNode;
|
||||
noLogo?: boolean;
|
||||
}
|
||||
export function Loading({ label, noLogo }: Props) {
|
||||
@@ -13,7 +14,7 @@ export function Loading({ label, noLogo }: Props) {
|
||||
<img className={styles.logo} src="/images/logo-no-text.svg" alt="" />
|
||||
</div>
|
||||
)}
|
||||
<div className="text-secondary mb-3">{label || intl.formatMessage({ id: "loading" })}</div>
|
||||
<div className="text-secondary mb-3">{label || <T id="loading" />}</div>
|
||||
<div className="progress progress-sm">
|
||||
<div className="progress-bar progress-bar-indeterminate" />
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import cn from "classnames";
|
||||
import { Flag } from "src/components";
|
||||
import { useLocaleState } from "src/context";
|
||||
import { useTheme } from "src/hooks";
|
||||
import { changeLocale, getFlagCodeForLocale, intl, localeOptions } from "src/locale";
|
||||
import { changeLocale, getFlagCodeForLocale, localeOptions, T } from "src/locale";
|
||||
import styles from "./LocalePicker.module.css";
|
||||
|
||||
function LocalePicker() {
|
||||
@@ -35,34 +35,13 @@ function LocalePicker() {
|
||||
changeTo(item[0]);
|
||||
}}
|
||||
>
|
||||
<Flag countryCode={getFlagCodeForLocale(item[0])} />{" "}
|
||||
{intl.formatMessage({ id: `locale-${item[1]}` })}
|
||||
<Flag countryCode={getFlagCodeForLocale(item[0])} /> <T id={`locale-${item[1]}`} />
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// <div className={className}>
|
||||
// <Menu>
|
||||
// <MenuButton as={Button} {...additionalProps}>
|
||||
// <Flag countryCode={getFlagCodeForLocale(locale)} />
|
||||
// </MenuButton>
|
||||
// <MenuList>
|
||||
// {localeOptions.map((item) => {
|
||||
// return (
|
||||
// <MenuItem
|
||||
// icon={<Flag countryCode={getFlagCodeForLocale(item[0])} />}
|
||||
// onClick={() => changeTo(item[0])}
|
||||
// key={`locale-${item[0]}`}>
|
||||
// <span>{intl.formatMessage({ id: `locale-${item[1]}` })}</span>
|
||||
// </MenuItem>
|
||||
// );
|
||||
// })}
|
||||
// </MenuList>
|
||||
// </Menu>
|
||||
// </Box>
|
||||
}
|
||||
|
||||
export { LocalePicker };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useHealth } from "src/hooks";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
export function SiteFooter() {
|
||||
const health = useHealth();
|
||||
@@ -25,7 +25,7 @@ export function SiteFooter() {
|
||||
className="link-secondary"
|
||||
rel="noopener"
|
||||
>
|
||||
{intl.formatMessage({ id: "footer.github-fork" })}
|
||||
<T id="footer.github-fork" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useState } from "react";
|
||||
import { LocalePicker, ThemeSwitcher } from "src/components";
|
||||
import { useAuthState } from "src/context";
|
||||
import { useUser } from "src/hooks";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
import { ChangePasswordModal, UserModal } from "src/modals";
|
||||
import styles from "./SiteHeader.module.css";
|
||||
|
||||
@@ -66,9 +66,7 @@ export function SiteHeader() {
|
||||
<div className="d-none d-xl-block ps-2">
|
||||
<div>{currentUser?.nickname}</div>
|
||||
<div className="mt-1 small text-secondary">
|
||||
{intl.formatMessage({
|
||||
id: isAdmin ? "role.admin" : "role.standard-user",
|
||||
})}
|
||||
<T id={isAdmin ? "role.admin" : "role.standard-user"} />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -82,7 +80,7 @@ export function SiteHeader() {
|
||||
}}
|
||||
>
|
||||
<IconUser width={18} />
|
||||
{intl.formatMessage({ id: "user.edit-profile" })}
|
||||
<T id="user.edit-profile" />
|
||||
</a>
|
||||
<a
|
||||
href="?"
|
||||
@@ -93,7 +91,7 @@ export function SiteHeader() {
|
||||
}}
|
||||
>
|
||||
<IconLock width={18} />
|
||||
{intl.formatMessage({ id: "user.change-password" })}
|
||||
<T id="user.change-password" />
|
||||
</a>
|
||||
<div className="dropdown-divider" />
|
||||
<a
|
||||
@@ -105,7 +103,7 @@ export function SiteHeader() {
|
||||
}}
|
||||
>
|
||||
<IconLogout width={18} />
|
||||
{intl.formatMessage({ id: "user.logout" })}
|
||||
<T id="user.logout" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import cn from "classnames";
|
||||
import React from "react";
|
||||
import { HasPermission, NavLink } from "src/components";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface MenuItem {
|
||||
label: string;
|
||||
@@ -108,7 +108,9 @@ const getMenuItem = (item: MenuItem, onClick?: () => void) => {
|
||||
<span className="nav-link-icon d-md-none d-lg-inline-block">
|
||||
{item.icon && React.createElement(item.icon, { height: 24, width: 24 })}
|
||||
</span>
|
||||
<span className="nav-link-title">{intl.formatMessage({ id: item.label })}</span>
|
||||
<span className="nav-link-title">
|
||||
<T id={item.label} />
|
||||
</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
</HasPermission>
|
||||
@@ -136,7 +138,9 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => {
|
||||
<span className="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<IconDeviceDesktop height={24} width={24} />
|
||||
</span>
|
||||
<span className="nav-link-title">{intl.formatMessage({ id: item.label })}</span>
|
||||
<span className="nav-link-title">
|
||||
<T id={item.label} />
|
||||
</span>
|
||||
</a>
|
||||
<div className="dropdown-menu">
|
||||
{item.items?.map((subitem, idx) => {
|
||||
@@ -148,7 +152,7 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => {
|
||||
hideError
|
||||
>
|
||||
<NavLink to={subitem.to} isDropdownItem onClick={onClick}>
|
||||
{intl.formatMessage({ id: subitem.label })}
|
||||
<T id={subitem.label} />
|
||||
</NavLink>
|
||||
</HasPermission>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import type { Certificate } from "src/api/backend";
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
certificate?: Certificate;
|
||||
}
|
||||
export function CertificateFormatter({ certificate }: Props) {
|
||||
if (certificate) {
|
||||
return intl.formatMessage({ id: "lets-encrypt" });
|
||||
}
|
||||
|
||||
return intl.formatMessage({ id: "http-only" });
|
||||
return <T id={certificate ? "lets-encrypt" : "http-only"} />;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DateTimeFormat, intl } from "src/locale";
|
||||
import { DateTimeFormat, T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
domains: string[];
|
||||
@@ -34,7 +34,7 @@ export function DomainsFormatter({ domains, createdOn }: Props) {
|
||||
</div>
|
||||
{createdOn ? (
|
||||
<div className="text-secondary mt-1">
|
||||
{intl.formatMessage({ id: "created-on" }, { date: DateTimeFormat(createdOn) })}
|
||||
<T id="created-on" data={{ date: DateTimeFormat(createdOn) }} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { intl } from "src/locale";
|
||||
import cn from "classnames";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
enabled: boolean;
|
||||
}
|
||||
export function EnabledFormatter({ enabled }: Props) {
|
||||
if (enabled) {
|
||||
return <span className="badge bg-lime-lt">{intl.formatMessage({ id: "enabled" })}</span>;
|
||||
}
|
||||
return <span className="badge bg-red-lt">{intl.formatMessage({ id: "disabled" })}</span>;
|
||||
return (
|
||||
<span className={cn("badge", enabled ? "bg-lime-lt" : "bg-red-lt")}>
|
||||
<T id={enabled ? "enabled" : "disabled"} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { IconArrowsCross, IconBolt, IconBoltOff, IconDisc, IconUser } from "@tabler/icons-react";
|
||||
import type { AuditLog } from "src/api/backend";
|
||||
import { DateTimeFormat, intl } from "src/locale";
|
||||
|
||||
const getEventTitle = (event: AuditLog) => (
|
||||
<span>{intl.formatMessage({ id: `event.${event.action}-${event.objectType}` })}</span>
|
||||
);
|
||||
import { DateTimeFormat, T } from "src/locale";
|
||||
|
||||
const getEventValue = (event: AuditLog) => {
|
||||
switch (event.objectType) {
|
||||
@@ -63,7 +59,9 @@ export function EventFormatter({ row }: Props) {
|
||||
return (
|
||||
<div className="flex-fill">
|
||||
<div className="font-weight-medium">
|
||||
{getIcon(row)} {getEventTitle(row)} — <span className="badge">{getEventValue(row)}</span>
|
||||
{getIcon(row)}
|
||||
<T id={`event.${row.action}-${row.objectType}`} />
|
||||
— <span className="badge">{getEventValue(row)}</span>
|
||||
</div>
|
||||
<div className="text-secondary mt-1">{DateTimeFormat(row.createdOn)}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { intl } from "src/locale";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
roles: string[];
|
||||
@@ -12,7 +12,7 @@ export function RolesFormatter({ roles }: Props) {
|
||||
<>
|
||||
{r.map((role: string) => (
|
||||
<span key={role} className="badge bg-yellow-lt me-1">
|
||||
{intl.formatMessage({ id: `role.${role}` })}
|
||||
<T id={`role.${role}`} />
|
||||
</span>
|
||||
))}
|
||||
</>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { intl } from "src/locale";
|
||||
import cn from "classnames";
|
||||
import { T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
enabled: boolean;
|
||||
}
|
||||
export function StatusFormatter({ enabled }: Props) {
|
||||
if (enabled) {
|
||||
return <span className="badge bg-lime-lt">{intl.formatMessage({ id: "online" })}</span>;
|
||||
}
|
||||
return <span className="badge bg-red-lt">{intl.formatMessage({ id: "offline" })}</span>;
|
||||
return (
|
||||
<span className={cn("badge", enabled ? "bg-lime-lt" : "bg-red-lt")}>
|
||||
<T id={enabled ? "online" : "offline"} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DateTimeFormat, intl } from "src/locale";
|
||||
import { DateTimeFormat, T } from "src/locale";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
@@ -13,9 +13,7 @@ export function ValueWithDateFormatter({ value, createdOn, disabled }: Props) {
|
||||
</div>
|
||||
{createdOn ? (
|
||||
<div className={`text-secondary mt-1 ${disabled ? "text-red" : ""}`}>
|
||||
{disabled
|
||||
? intl.formatMessage({ id: "disabled" })
|
||||
: intl.formatMessage({ id: "created-on" }, { date: DateTimeFormat(createdOn) })}
|
||||
<T id={disabled ? "disabled" : "created-on"} data={{ date: DateTimeFormat(createdOn) }} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user