You've already forked nginx-proxy-manager
							
							
				mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-11-04 04:11:42 +03:00 
			
		
		
		
	API lib cleanup, 404 hosts WIP
This commit is contained in:
		
							
								
								
									
										112
									
								
								frontend/src/components/Form/SSLCertificateField.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								frontend/src/components/Form/SSLCertificateField.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
import { IconShield } from "@tabler/icons-react";
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
interface CertOption {
 | 
			
		||||
	readonly value: number | "new";
 | 
			
		||||
	readonly label: string;
 | 
			
		||||
	readonly subLabel: string;
 | 
			
		||||
	readonly icon: React.ReactNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Option = (props: OptionProps<CertOption>) => {
 | 
			
		||||
	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;
 | 
			
		||||
	required?: boolean;
 | 
			
		||||
	allowNew?: boolean;
 | 
			
		||||
}
 | 
			
		||||
export function SSLCertificateField({
 | 
			
		||||
	name = "certificateId",
 | 
			
		||||
	label = "ssl-certificate",
 | 
			
		||||
	id = "certificateId",
 | 
			
		||||
	required,
 | 
			
		||||
	allowNew,
 | 
			
		||||
}: Props) {
 | 
			
		||||
	const { isLoading, isError, error, data } = useCertificates();
 | 
			
		||||
 | 
			
		||||
	const { setFieldValue } = useFormikContext();
 | 
			
		||||
 | 
			
		||||
	const handleChange = (v: any, _actionMeta: ActionMeta<CertOption>) => {
 | 
			
		||||
		setFieldValue(name, v?.value);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const options: CertOption[] =
 | 
			
		||||
		data?.map((cert: Certificate) => ({
 | 
			
		||||
			value: cert.id,
 | 
			
		||||
			label: cert.niceName,
 | 
			
		||||
			subLabel: `${cert.provider === "letsencrypt" ? "Let's Encrypt" : cert.provider} — Expires: ${
 | 
			
		||||
				cert.expiresOn ? DateTimeFormat(cert.expiresOn) : "N/A"
 | 
			
		||||
			}`,
 | 
			
		||||
			icon: <IconShield size={14} className="text-pink" />,
 | 
			
		||||
		})) || [];
 | 
			
		||||
 | 
			
		||||
	// Prepend the Add New option
 | 
			
		||||
	if (allowNew) {
 | 
			
		||||
		options?.unshift({
 | 
			
		||||
			value: "new",
 | 
			
		||||
			label: "Request a new HTTP certificate",
 | 
			
		||||
			subLabel: "with Let's Encrypt",
 | 
			
		||||
			icon: <IconShield size={14} className="text-lime" />,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Prepend the None option
 | 
			
		||||
	if (!required) {
 | 
			
		||||
		options?.unshift({
 | 
			
		||||
			value: 0,
 | 
			
		||||
			label: "None",
 | 
			
		||||
			subLabel: "This host will not use HTTPS",
 | 
			
		||||
			icon: <IconShield size={14} className="text-red" />,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<Field name={name}>
 | 
			
		||||
			{({ field, form }: any) => (
 | 
			
		||||
				<div className="mb-3">
 | 
			
		||||
					<label className="form-label" htmlFor={id}>
 | 
			
		||||
						{intl.formatMessage({ 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
 | 
			
		||||
							defaultValue={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>
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user