mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-11-08 03:15:14 +00:00
Wrap intl in span identifying translation
This commit is contained in:
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";
|
||||
|
||||
Reference in New Issue
Block a user