mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-04-29 10:32:28 +00:00
Add certificate model for http and dns
change is_ecc to boolean, its still stored as int in sqlite
This commit is contained in:
parent
7455accf58
commit
fc2df47753
@ -51,9 +51,7 @@ func createCertificateHTTP() string {
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"is_ecc": {
|
"is_ecc": {
|
||||||
"type": "integer",
|
"type": "boolean"
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, strictString("http"), intMinOne, stringMinMax(1, 100), domainNames())
|
}`, strictString("http"), intMinOne, stringMinMax(1, 100), domainNames())
|
||||||
@ -83,9 +81,7 @@ func createCertificateDNS() string {
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"is_ecc": {
|
"is_ecc": {
|
||||||
"type": "integer",
|
"type": "boolean"
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, strictString("dns"), intMinOne, intMinOne, stringMinMax(1, 100), domainNames())
|
}`, strictString("dns"), intMinOne, intMinOne, stringMinMax(1, 100), domainNames())
|
||||||
|
@ -57,7 +57,7 @@ type Model struct {
|
|||||||
Status string `json:"status" db:"status" filter:"status,string"`
|
Status string `json:"status" db:"status" filter:"status,string"`
|
||||||
ErrorMessage string `json:"error_message" db:"error_message" filter:"error_message,string"`
|
ErrorMessage string `json:"error_message" db:"error_message" filter:"error_message,string"`
|
||||||
Meta types.JSONB `json:"-" db:"meta"`
|
Meta types.JSONB `json:"-" db:"meta"`
|
||||||
IsECC int `json:"is_ecc" db:"is_ecc" filter:"is_ecc,integer"`
|
IsECC bool `json:"is_ecc" db:"is_ecc" filter:"is_ecc,bool"`
|
||||||
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
IsDeleted bool `json:"is_deleted,omitempty" db:"is_deleted"`
|
||||||
// Expansions:
|
// Expansions:
|
||||||
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
|
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
|
||||||
|
@ -13,7 +13,7 @@ type Template struct {
|
|||||||
Name string
|
Name string
|
||||||
DomainNames []string
|
DomainNames []string
|
||||||
Status string
|
Status string
|
||||||
IsECC int
|
IsECC bool
|
||||||
// These are helpers for template generation
|
// These are helpers for template generation
|
||||||
IsCustom bool
|
IsCustom bool
|
||||||
IsAcme bool // non-custom
|
IsAcme bool // non-custom
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"@typescript-eslint/parser": "^5.30.6",
|
"@typescript-eslint/parser": "^5.30.6",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"chakra-react-select": "^4.5.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"country-flag-icons": "^1.5.5",
|
"country-flag-icons": "^1.5.5",
|
||||||
"date-fns": "2.28.0",
|
"date-fns": "2.28.0",
|
||||||
|
@ -52,12 +52,16 @@ export interface Certificate {
|
|||||||
id: number;
|
id: number;
|
||||||
createdOn: number;
|
createdOn: number;
|
||||||
modifiedOn: number;
|
modifiedOn: number;
|
||||||
|
expiresOn: number | null;
|
||||||
|
type: string;
|
||||||
|
userId: number;
|
||||||
|
certificateAuthorityId: number;
|
||||||
|
dnsProviderId: number;
|
||||||
name: string;
|
name: string;
|
||||||
acmeshServer: string;
|
domainNames: string[];
|
||||||
caBundle: string;
|
status: string;
|
||||||
maxDomains: number;
|
errorMessage: string;
|
||||||
isWildcardSupported: boolean;
|
isEcc: boolean;
|
||||||
isSetup: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CertificateAuthority {
|
export interface CertificateAuthority {
|
||||||
|
@ -47,7 +47,7 @@ const useSetCertificate = () => {
|
|||||||
onError: (error, values, rollback: any) => rollback(),
|
onError: (error, values, rollback: any) => rollback(),
|
||||||
onSuccess: async ({ id }: Certificate) => {
|
onSuccess: async ({ id }: Certificate) => {
|
||||||
queryClient.invalidateQueries(["certificate", id]);
|
queryClient.invalidateQueries(["certificate", id]);
|
||||||
queryClient.invalidateQueries("certificate");
|
queryClient.invalidateQueries("certificates");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -28,7 +28,7 @@ const useCertificates = (
|
|||||||
options = {},
|
options = {},
|
||||||
) => {
|
) => {
|
||||||
return useQuery<CertificatesResponse, Error>(
|
return useQuery<CertificatesResponse, Error>(
|
||||||
["hosts", { offset, limit, sortBy, filters }],
|
["certificates", { offset, limit, sortBy, filters }],
|
||||||
() => fetchCertificates(offset, limit, sortBy, filters),
|
() => fetchCertificates(offset, limit, sortBy, filters),
|
||||||
{
|
{
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
# Certificates Help
|
# Certificates Help
|
||||||
|
|
||||||
|
## HTTP Certificate
|
||||||
|
|
||||||
|
todo
|
||||||
|
|
||||||
|
## DNS Certificate
|
||||||
|
|
||||||
|
todo
|
||||||
|
|
||||||
|
## Custom Certificate
|
||||||
|
|
||||||
|
todo
|
||||||
|
|
||||||
|
## MKCert Certificate
|
||||||
|
|
||||||
todo
|
todo
|
||||||
|
@ -314,6 +314,9 @@
|
|||||||
"certificate-authorities.title": {
|
"certificate-authorities.title": {
|
||||||
"defaultMessage": "Certificate Authorities"
|
"defaultMessage": "Certificate Authorities"
|
||||||
},
|
},
|
||||||
|
"certificate-authority": {
|
||||||
|
"defaultMessage": "Certificate Authority"
|
||||||
|
},
|
||||||
"certificate-authority.acmesh-server": {
|
"certificate-authority.acmesh-server": {
|
||||||
"defaultMessage": "ACME Server"
|
"defaultMessage": "ACME Server"
|
||||||
},
|
},
|
||||||
@ -404,12 +407,24 @@
|
|||||||
"disabled": {
|
"disabled": {
|
||||||
"defaultMessage": "Disabled"
|
"defaultMessage": "Disabled"
|
||||||
},
|
},
|
||||||
|
"dns-provider": {
|
||||||
|
"defaultMessage": "DNS Provider"
|
||||||
|
},
|
||||||
"dns-provider.acmesh-name": {
|
"dns-provider.acmesh-name": {
|
||||||
"defaultMessage": "Acme.sh Provider"
|
"defaultMessage": "Acme.sh Provider"
|
||||||
},
|
},
|
||||||
"dns-provider.create": {
|
"dns-provider.create": {
|
||||||
"defaultMessage": "Create DNS Provider"
|
"defaultMessage": "Create DNS Provider"
|
||||||
},
|
},
|
||||||
|
"dns-providers-empty": {
|
||||||
|
"defaultMessage": "No DNS Providers - Create one first"
|
||||||
|
},
|
||||||
|
"domain_names": {
|
||||||
|
"defaultMessage": "Domain Names"
|
||||||
|
},
|
||||||
|
"domain_names.max": {
|
||||||
|
"defaultMessage": "{count} domain names maximum"
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
@ -524,6 +539,9 @@
|
|||||||
"https-only": {
|
"https-only": {
|
||||||
"defaultMessage": "HTTPS Only"
|
"defaultMessage": "HTTPS Only"
|
||||||
},
|
},
|
||||||
|
"is-ecc": {
|
||||||
|
"defaultMessage": "ECC Certificate"
|
||||||
|
},
|
||||||
"lets-go": {
|
"lets-go": {
|
||||||
"defaultMessage": "Let's go"
|
"defaultMessage": "Let's go"
|
||||||
},
|
},
|
||||||
@ -638,6 +656,9 @@
|
|||||||
"type.http": {
|
"type.http": {
|
||||||
"defaultMessage": "HTTP"
|
"defaultMessage": "HTTP"
|
||||||
},
|
},
|
||||||
|
"type.mkcert": {
|
||||||
|
"defaultMessage": "MKCert"
|
||||||
|
},
|
||||||
"type.proxy": {
|
"type.proxy": {
|
||||||
"defaultMessage": "Proxy Host"
|
"defaultMessage": "Proxy Host"
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
FormControl,
|
|
||||||
FormErrorMessage,
|
|
||||||
FormLabel,
|
|
||||||
Input,
|
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
ModalContent,
|
ModalContent,
|
||||||
@ -16,14 +12,14 @@ import {
|
|||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { Certificate } from "api/npm";
|
import { Certificate } from "api/npm";
|
||||||
import { PrettyButton } from "components";
|
import { PrettyButton } from "components";
|
||||||
import { Formik, Form, Field } from "formik";
|
import { Formik, Form } from "formik";
|
||||||
import { useSetCertificate } from "hooks";
|
import { useSetCertificate } from "hooks";
|
||||||
import { intl } from "locale";
|
import { intl } from "locale";
|
||||||
import { validateString } from "modules/Validations";
|
|
||||||
|
|
||||||
import CustomForm from "./CustomForm";
|
import CustomForm from "./CustomForm";
|
||||||
import DNSForm from "./DNSForm";
|
import DNSForm from "./DNSForm";
|
||||||
import HTTPForm from "./HTTPForm";
|
import HTTPForm from "./HTTPForm";
|
||||||
|
import MKCertForm from "./MKCertForm";
|
||||||
|
|
||||||
interface CertificateCreateModalProps {
|
interface CertificateCreateModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -44,8 +40,9 @@ function CertificateCreateModal({
|
|||||||
|
|
||||||
const onSubmit = async (
|
const onSubmit = async (
|
||||||
payload: Certificate,
|
payload: Certificate,
|
||||||
{ setErrors, setSubmitting }: any,
|
{ /*setErrors,*/ setSubmitting }: any,
|
||||||
) => {
|
) => {
|
||||||
|
payload.type = certType;
|
||||||
const showErr = (msg: string) => {
|
const showErr = (msg: string) => {
|
||||||
toast({
|
toast({
|
||||||
description: intl.formatMessage({
|
description: intl.formatMessage({
|
||||||
@ -60,6 +57,8 @@ function CertificateCreateModal({
|
|||||||
|
|
||||||
setCertificate(payload, {
|
setCertificate(payload, {
|
||||||
onError: (err: any) => {
|
onError: (err: any) => {
|
||||||
|
showErr(err.message);
|
||||||
|
/*
|
||||||
if (err.message === "ca-bundle-does-not-exist") {
|
if (err.message === "ca-bundle-does-not-exist") {
|
||||||
setErrors({
|
setErrors({
|
||||||
caBundle: intl.formatMessage({
|
caBundle: intl.formatMessage({
|
||||||
@ -68,28 +67,52 @@ function CertificateCreateModal({
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
showErr(err.message);
|
showErr(err.message);
|
||||||
}
|
}*/
|
||||||
},
|
},
|
||||||
onSuccess: () => onModalClose(),
|
onSuccess: () => onModalClose(),
|
||||||
onSettled: () => setSubmitting(false),
|
onSettled: () => setSubmitting(false),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getInitialValues = (type: string): any => {
|
||||||
|
switch (type) {
|
||||||
|
case "http":
|
||||||
|
return {
|
||||||
|
certificateAuthorityId: 0,
|
||||||
|
name: "",
|
||||||
|
domainNames: [],
|
||||||
|
isEcc: false,
|
||||||
|
} as any;
|
||||||
|
case "dns":
|
||||||
|
return {
|
||||||
|
certificateAuthorityId: 0,
|
||||||
|
dnsProviderId: 0,
|
||||||
|
name: "",
|
||||||
|
domainNames: [],
|
||||||
|
isEcc: false,
|
||||||
|
} as any;
|
||||||
|
case "custom":
|
||||||
|
return {
|
||||||
|
name: "",
|
||||||
|
domainNames: [],
|
||||||
|
// isEcc: false, // todo, required?
|
||||||
|
// todo: add meta?
|
||||||
|
} as any;
|
||||||
|
case "mkcert":
|
||||||
|
return {
|
||||||
|
name: "",
|
||||||
|
domainNames: [],
|
||||||
|
// isEcc: false, // todo, supported?
|
||||||
|
// todo: add meta?
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={onModalClose} closeOnOverlayClick={false}>
|
<Modal isOpen={isOpen} onClose={onModalClose} closeOnOverlayClick={false}>
|
||||||
<ModalOverlay />
|
<ModalOverlay />
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<Formik
|
<Formik initialValues={getInitialValues(certType)} onSubmit={onSubmit}>
|
||||||
initialValues={
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
acmeshServer: "",
|
|
||||||
caBundle: "",
|
|
||||||
maxDomains: 5,
|
|
||||||
isWildcardSupported: false,
|
|
||||||
} as Certificate
|
|
||||||
}
|
|
||||||
onSubmit={onSubmit}>
|
|
||||||
{({ isSubmitting }) => (
|
{({ isSubmitting }) => (
|
||||||
<Form>
|
<Form>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
@ -98,39 +121,16 @@ function CertificateCreateModal({
|
|||||||
<ModalCloseButton />
|
<ModalCloseButton />
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<Field name="name" validate={validateString(1, 100)}>
|
|
||||||
{({ field, form }: any) => (
|
|
||||||
<FormControl
|
|
||||||
isRequired
|
|
||||||
isInvalid={form.errors.name && form.touched.name}>
|
|
||||||
<FormLabel htmlFor="name">
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: "name",
|
|
||||||
})}
|
|
||||||
</FormLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="name"
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: "name",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormErrorMessage>{form.errors.name}</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{certType === "http" ? <HTTPForm /> : null}
|
{certType === "http" ? <HTTPForm /> : null}
|
||||||
{certType === "dns" ? <DNSForm /> : null}
|
{certType === "dns" ? <DNSForm /> : null}
|
||||||
{certType === "custom" ? <CustomForm /> : null}
|
{certType === "custom" ? <CustomForm /> : null}
|
||||||
|
{certType === "mkcert" ? <MKCertForm /> : null}
|
||||||
|
</Stack>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
{certType !== "" ? (
|
|
||||||
<PrettyButton mr={3} isLoading={isSubmitting}>
|
<PrettyButton mr={3} isLoading={isSubmitting}>
|
||||||
{intl.formatMessage({ id: "form.save" })}
|
{intl.formatMessage({ id: "form.save" })}
|
||||||
</PrettyButton>
|
</PrettyButton>
|
||||||
) : null}
|
|
||||||
<Button onClick={onModalClose} isLoading={isSubmitting}>
|
<Button onClick={onModalClose} isLoading={isSubmitting}>
|
||||||
{intl.formatMessage({ id: "form.cancel" })}
|
{intl.formatMessage({ id: "form.cancel" })}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
|
FormLabel,
|
||||||
|
Select,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { CertificateAuthority } from "api/npm";
|
||||||
|
import { Field, useFormikContext } from "formik";
|
||||||
|
import { useCertificateAuthorities } from "hooks";
|
||||||
|
import { intl } from "locale";
|
||||||
|
|
||||||
|
const fieldName = "certificateAuthorityId";
|
||||||
|
|
||||||
|
interface CertificateAuthorityFieldProps {
|
||||||
|
onChange?: (maxDomains: number, isWildcardSupported: boolean) => any;
|
||||||
|
}
|
||||||
|
function CertificateAuthorityField({
|
||||||
|
onChange,
|
||||||
|
}: CertificateAuthorityFieldProps) {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
const { data, isLoading } = useCertificateAuthorities(0, 999, [{ id: "id" }]);
|
||||||
|
|
||||||
|
const handleOnChange = (e: any) => {
|
||||||
|
if (e.currentTarget.value) {
|
||||||
|
const id = parseInt(e.currentTarget.value, 10);
|
||||||
|
// This step enforces that the formik payload has a
|
||||||
|
// string number instead of a string as the value
|
||||||
|
// for this field
|
||||||
|
setFieldValue(fieldName, id);
|
||||||
|
if (onChange) {
|
||||||
|
// find items in list of data
|
||||||
|
const ca = data?.items.find((item) => item.id === id);
|
||||||
|
if (ca) {
|
||||||
|
onChange(ca.maxDomains, ca.isWildcardSupported);
|
||||||
|
} else {
|
||||||
|
onChange(0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Field name={fieldName}>
|
||||||
|
{({ field, form }: any) => (
|
||||||
|
<FormControl
|
||||||
|
isRequired
|
||||||
|
isInvalid={form.errors[fieldName] && form.touched[fieldName]}>
|
||||||
|
<FormLabel htmlFor={fieldName}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "certificate-authority",
|
||||||
|
})}
|
||||||
|
</FormLabel>
|
||||||
|
<Select
|
||||||
|
{...field}
|
||||||
|
id={fieldName}
|
||||||
|
disabled={isLoading}
|
||||||
|
onChange={(e: any) => {
|
||||||
|
field.onChange(e);
|
||||||
|
handleOnChange(e);
|
||||||
|
}}>
|
||||||
|
<option value="" />
|
||||||
|
{data?.items?.map((item: CertificateAuthority) => {
|
||||||
|
return (
|
||||||
|
<option key={item.id} value={item.id}>
|
||||||
|
{item.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormErrorMessage>{form.errors[fieldName]}</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CertificateAuthorityField };
|
@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
|
FormLabel,
|
||||||
|
Select,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { DNSProvider } from "api/npm";
|
||||||
|
import { Field, useFormikContext } from "formik";
|
||||||
|
import { useDNSProviders } from "hooks";
|
||||||
|
import { intl } from "locale";
|
||||||
|
|
||||||
|
const fieldName = "dnsProviderId";
|
||||||
|
|
||||||
|
function DNSProviderField() {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
const { data, isLoading } = useDNSProviders(0, 999);
|
||||||
|
|
||||||
|
const handleOnChange = (e: any) => {
|
||||||
|
if (e.currentTarget.value) {
|
||||||
|
const id = parseInt(e.currentTarget.value, 10);
|
||||||
|
// This step enforces that the formik payload has a
|
||||||
|
// string number instead of a string as the value
|
||||||
|
// for this field
|
||||||
|
setFieldValue(fieldName, id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Field name={fieldName}>
|
||||||
|
{({ field, form }: any) => (
|
||||||
|
<FormControl
|
||||||
|
isRequired
|
||||||
|
isInvalid={
|
||||||
|
!isLoading &&
|
||||||
|
(!data?.total ||
|
||||||
|
(form.errors[fieldName] && form.touched[fieldName]))
|
||||||
|
}>
|
||||||
|
<FormLabel htmlFor={fieldName}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "dns-provider",
|
||||||
|
})}
|
||||||
|
</FormLabel>
|
||||||
|
<Select
|
||||||
|
{...field}
|
||||||
|
id={fieldName}
|
||||||
|
disabled={isLoading}
|
||||||
|
onChange={(e: any) => {
|
||||||
|
field.onChange(e);
|
||||||
|
handleOnChange(e);
|
||||||
|
}}>
|
||||||
|
<option value="" />
|
||||||
|
{data?.items?.map((item: DNSProvider) => {
|
||||||
|
return (
|
||||||
|
<option key={item.id} value={item.id}>
|
||||||
|
{item.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
<FormErrorMessage>
|
||||||
|
{!isLoading && !data?.total
|
||||||
|
? intl.formatMessage({
|
||||||
|
id: "dns-providers-empty",
|
||||||
|
})
|
||||||
|
: form.errors[fieldName]}
|
||||||
|
</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DNSProviderField };
|
@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
|
FormLabel,
|
||||||
|
FormHelperText,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { CreatableSelect, OptionBase } from "chakra-react-select";
|
||||||
|
import { Field, useFormikContext } from "formik";
|
||||||
|
import { intl } from "locale";
|
||||||
|
|
||||||
|
interface SelectOption extends OptionBase {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
interface DomainNamesFieldProps {
|
||||||
|
maxDomains?: number;
|
||||||
|
isWildcardSupported?: boolean;
|
||||||
|
onChange?: (i: string[]) => any;
|
||||||
|
}
|
||||||
|
function DomainNamesField({
|
||||||
|
maxDomains,
|
||||||
|
isWildcardSupported,
|
||||||
|
onChange,
|
||||||
|
}: DomainNamesFieldProps) {
|
||||||
|
const { values, setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
const getDomainCount = (v: string[] | undefined) => {
|
||||||
|
if (typeof v !== "undefined" && v?.length) {
|
||||||
|
return v.length;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDomainValid = (d: string): boolean => {
|
||||||
|
const dom = d.trim().toLowerCase();
|
||||||
|
const v: any = values;
|
||||||
|
|
||||||
|
// Deny if the list of domains is hit
|
||||||
|
if (maxDomains && getDomainCount(v?.domainNames) >= maxDomains) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dom.length < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent wildcards
|
||||||
|
if (!isWildcardSupported && dom.indexOf("*") !== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent duplicate * in domain
|
||||||
|
if ((dom.match(/\*/g) || []).length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent some invalid characters
|
||||||
|
// @ ,
|
||||||
|
if ((dom.match(/(@|,)/g) || []).length > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will match *.com type domains,
|
||||||
|
return dom.match(/\*\.[^.]+$/m) === null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (values: any) => {
|
||||||
|
const doms = values?.map((i: SelectOption) => {
|
||||||
|
return i.value;
|
||||||
|
});
|
||||||
|
setFieldValue("domainNames", doms);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Field name="domainNames">
|
||||||
|
{({ field, form }: any) => (
|
||||||
|
<FormControl
|
||||||
|
isInvalid={form.errors.domainNames && form.touched.domainNames}>
|
||||||
|
<FormLabel htmlFor="domainNames">
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "domain_names",
|
||||||
|
})}
|
||||||
|
</FormLabel>
|
||||||
|
<CreatableSelect
|
||||||
|
name={field.domainNames}
|
||||||
|
id="domainNames"
|
||||||
|
closeMenuOnSelect={true}
|
||||||
|
isClearable={false}
|
||||||
|
onChange={handleChange}
|
||||||
|
isValidNewOption={isDomainValid}
|
||||||
|
isMulti
|
||||||
|
placeholder="example.com"
|
||||||
|
/>
|
||||||
|
{maxDomains ? (
|
||||||
|
<FormHelperText>
|
||||||
|
{intl.formatMessage(
|
||||||
|
{ id: "domain_names.max" },
|
||||||
|
{ count: maxDomains },
|
||||||
|
)}
|
||||||
|
</FormHelperText>
|
||||||
|
) : null}
|
||||||
|
<FormErrorMessage>{form.errors.domainNames}</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DomainNamesField };
|
@ -0,0 +1,31 @@
|
|||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
|
FormLabel,
|
||||||
|
Switch,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { Field } from "formik";
|
||||||
|
import { intl } from "locale";
|
||||||
|
|
||||||
|
const fieldName = "isEcc";
|
||||||
|
|
||||||
|
function EccField() {
|
||||||
|
return (
|
||||||
|
<Field name={fieldName}>
|
||||||
|
{({ field, form }: any) => (
|
||||||
|
<FormControl
|
||||||
|
isInvalid={form.errors[fieldName] && form.touched[fieldName]}>
|
||||||
|
<FormLabel htmlFor={fieldName}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "is-ecc",
|
||||||
|
})}
|
||||||
|
</FormLabel>
|
||||||
|
<Switch {...field} id={fieldName} />
|
||||||
|
<FormErrorMessage>{form.errors[fieldName]}</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { EccField };
|
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
|
FormLabel,
|
||||||
|
Input,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { Field } from "formik";
|
||||||
|
import { intl } from "locale";
|
||||||
|
import { validateString } from "modules/Validations";
|
||||||
|
|
||||||
|
function NameField() {
|
||||||
|
return (
|
||||||
|
<Field name="name" validate={validateString(1, 100)}>
|
||||||
|
{({ field, form }: any) => (
|
||||||
|
<FormControl
|
||||||
|
isRequired
|
||||||
|
isInvalid={form.errors.name && form.touched.name}>
|
||||||
|
<FormLabel htmlFor="name">
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "name",
|
||||||
|
})}
|
||||||
|
</FormLabel>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
id="name"
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: "name",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<FormErrorMessage>{form.errors.name}</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { NameField };
|
@ -0,0 +1,5 @@
|
|||||||
|
export * from "./CertificateAuthorityField";
|
||||||
|
export * from "./DNSProviderField";
|
||||||
|
export * from "./DomainNamesField";
|
||||||
|
export * from "./EccField";
|
||||||
|
export * from "./NameField";
|
@ -1,5 +1,12 @@
|
|||||||
|
import { DomainNamesField, NameField } from "./Common";
|
||||||
|
|
||||||
function CustomForm() {
|
function CustomForm() {
|
||||||
return <p>Custom form</p>;
|
return (
|
||||||
|
<>
|
||||||
|
<NameField />
|
||||||
|
<DomainNamesField />
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CustomForm;
|
export default CustomForm;
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CertificateAuthorityField,
|
||||||
|
DNSProviderField,
|
||||||
|
DomainNamesField,
|
||||||
|
EccField,
|
||||||
|
NameField,
|
||||||
|
} from "./Common";
|
||||||
|
|
||||||
function DNSForm() {
|
function DNSForm() {
|
||||||
return <p>DNS form</p>;
|
const [maxDomains, setMaxDomains] = useState(0);
|
||||||
|
const [isWildcardSupported, setIsWildcardSupported] = useState(false);
|
||||||
|
|
||||||
|
const handleCAChange = (maxD: number, wildcards: boolean) => {
|
||||||
|
setMaxDomains(maxD);
|
||||||
|
setIsWildcardSupported(wildcards);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NameField />
|
||||||
|
<CertificateAuthorityField onChange={handleCAChange} />
|
||||||
|
<DomainNamesField
|
||||||
|
maxDomains={maxDomains}
|
||||||
|
isWildcardSupported={isWildcardSupported}
|
||||||
|
/>
|
||||||
|
<DNSProviderField />
|
||||||
|
<EccField />
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DNSForm;
|
export default DNSForm;
|
||||||
|
@ -1,5 +1,32 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CertificateAuthorityField,
|
||||||
|
DomainNamesField,
|
||||||
|
EccField,
|
||||||
|
NameField,
|
||||||
|
} from "./Common";
|
||||||
|
|
||||||
function HTTPForm() {
|
function HTTPForm() {
|
||||||
return <p>Http form</p>;
|
const [maxDomains, setMaxDomains] = useState(0);
|
||||||
|
const [isWildcardSupported, setIsWildcardSupported] = useState(false);
|
||||||
|
|
||||||
|
const handleCAChange = (maxD: number, wildcards: boolean) => {
|
||||||
|
setMaxDomains(maxD);
|
||||||
|
setIsWildcardSupported(wildcards);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NameField />
|
||||||
|
<CertificateAuthorityField onChange={handleCAChange} />
|
||||||
|
<DomainNamesField
|
||||||
|
maxDomains={maxDomains}
|
||||||
|
isWildcardSupported={isWildcardSupported}
|
||||||
|
/>
|
||||||
|
<EccField />
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HTTPForm;
|
export default HTTPForm;
|
||||||
|
12
frontend/src/modals/CertificateCreateModal/MKCertForm.tsx
Normal file
12
frontend/src/modals/CertificateCreateModal/MKCertForm.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { DomainNamesField, NameField } from "./Common";
|
||||||
|
|
||||||
|
function MKCertForm() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NameField />
|
||||||
|
<DomainNamesField />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MKCertForm;
|
@ -9,14 +9,17 @@ import {
|
|||||||
MenuDivider,
|
MenuDivider,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { HelpDrawer, PrettyMenuButton } from "components";
|
import { HelpDrawer, PrettyMenuButton } from "components";
|
||||||
|
import { useDNSProviders } from "hooks";
|
||||||
import { intl } from "locale";
|
import { intl } from "locale";
|
||||||
import { CertificateCreateModal } from "modals";
|
import { CertificateCreateModal } from "modals";
|
||||||
import { FiGlobe, FiServer, FiUpload } from "react-icons/fi";
|
import { FiGlobe, FiServer, FiShieldOff, FiUpload } from "react-icons/fi";
|
||||||
|
|
||||||
import TableWrapper from "./TableWrapper";
|
import TableWrapper from "./TableWrapper";
|
||||||
|
|
||||||
function Certificates() {
|
function Certificates() {
|
||||||
const [createShown, setCreateShown] = useState("");
|
const [createShown, setCreateShown] = useState("");
|
||||||
|
const { data: dnsProviders, isLoading: dnsProvidersIsLoading } =
|
||||||
|
useDNSProviders(0, 999);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -37,6 +40,7 @@ function Certificates() {
|
|||||||
{intl.formatMessage({ id: "type.http" })}
|
{intl.formatMessage({ id: "type.http" })}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
isDisabled={dnsProvidersIsLoading || !dnsProviders?.total}
|
||||||
icon={<FiServer />}
|
icon={<FiServer />}
|
||||||
onClick={() => setCreateShown("dns")}>
|
onClick={() => setCreateShown("dns")}>
|
||||||
{intl.formatMessage({ id: "type.dns" })}
|
{intl.formatMessage({ id: "type.dns" })}
|
||||||
@ -47,6 +51,11 @@ function Certificates() {
|
|||||||
onClick={() => setCreateShown("custom")}>
|
onClick={() => setCreateShown("custom")}>
|
||||||
{intl.formatMessage({ id: "type.custom" })}
|
{intl.formatMessage({ id: "type.custom" })}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
icon={<FiShieldOff />}
|
||||||
|
onClick={() => setCreateShown("mkcert")}>
|
||||||
|
{intl.formatMessage({ id: "type.mkcert" })}
|
||||||
|
</MenuItem>
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
@ -1034,6 +1034,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.12.0", "@babel/runtime@^7.8.7":
|
||||||
|
version "7.21.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
|
||||||
|
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.11"
|
||||||
|
|
||||||
"@babel/runtime@^7.3.1":
|
"@babel/runtime@^7.3.1":
|
||||||
version "7.20.7"
|
version "7.20.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd"
|
||||||
@ -1982,7 +1989,7 @@
|
|||||||
source-map "^0.5.7"
|
source-map "^0.5.7"
|
||||||
stylis "4.1.3"
|
stylis "4.1.3"
|
||||||
|
|
||||||
"@emotion/cache@^11.10.5":
|
"@emotion/cache@^11.10.5", "@emotion/cache@^11.4.0":
|
||||||
version "11.10.5"
|
version "11.10.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12"
|
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12"
|
||||||
integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==
|
integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==
|
||||||
@ -2022,7 +2029,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
|
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
|
||||||
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
|
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
|
||||||
|
|
||||||
"@emotion/react@^11.10.6":
|
"@emotion/react@^11.10.6", "@emotion/react@^11.8.1":
|
||||||
version "11.10.6"
|
version "11.10.6"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.6.tgz#dbe5e650ab0f3b1d2e592e6ab1e006e75fd9ac11"
|
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.6.tgz#dbe5e650ab0f3b1d2e592e6ab1e006e75fd9ac11"
|
||||||
integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==
|
integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==
|
||||||
@ -2099,6 +2106,18 @@
|
|||||||
minimatch "^3.1.2"
|
minimatch "^3.1.2"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
|
"@floating-ui/core@^1.2.1":
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.1.tgz#074182a1d277f94569c50a6b456e62585d463c8e"
|
||||||
|
integrity sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg==
|
||||||
|
|
||||||
|
"@floating-ui/dom@^1.0.1":
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.1.tgz#8f93906e1a3b9f606ce78afb058e874344dcbe07"
|
||||||
|
integrity sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==
|
||||||
|
dependencies:
|
||||||
|
"@floating-ui/core" "^1.2.1"
|
||||||
|
|
||||||
"@formatjs/cli@^5.0.2":
|
"@formatjs/cli@^5.0.2":
|
||||||
version "5.0.2"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-5.0.2.tgz#1df27fc52aae0ddcfc34ac0d2d8504fe244e6f0f"
|
resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-5.0.2.tgz#1df27fc52aae0ddcfc34ac0d2d8504fe244e6f0f"
|
||||||
@ -3132,6 +3151,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-transition-group@^4.4.0":
|
||||||
|
version "4.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
|
||||||
|
integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@18.0.15":
|
"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@18.0.15":
|
||||||
version "18.0.15"
|
version "18.0.15"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe"
|
||||||
@ -4271,6 +4297,13 @@ caseless@~0.12.0:
|
|||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||||
integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
|
integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
|
||||||
|
|
||||||
|
chakra-react-select@^4.5.0:
|
||||||
|
version "4.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/chakra-react-select/-/chakra-react-select-4.5.0.tgz#9b596cb8f346608c4c59457dde4b300770e01123"
|
||||||
|
integrity sha512-5oxVH9tmn3kVVLt9m/zT28Efv44mk30BZETubE2MhkGMIeM9oJsiL2+dhgKLNUMLRxglmacY00oGQTSI0JrRTA==
|
||||||
|
dependencies:
|
||||||
|
react-select "5.7.0"
|
||||||
|
|
||||||
chalk@^2.0.0, chalk@^2.4.1:
|
chalk@^2.0.0, chalk@^2.4.1:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
@ -5133,6 +5166,14 @@ dom-converter@^0.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
utila "~0.4"
|
utila "~0.4"
|
||||||
|
|
||||||
|
dom-helpers@^5.0.1:
|
||||||
|
version "5.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
|
||||||
|
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.8.7"
|
||||||
|
csstype "^3.0.2"
|
||||||
|
|
||||||
dom-serializer@0:
|
dom-serializer@0:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||||
@ -8110,6 +8151,11 @@ memfs@^3.1.2, memfs@^3.4.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fs-monkey "^1.0.3"
|
fs-monkey "^1.0.3"
|
||||||
|
|
||||||
|
memoize-one@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||||
|
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
|
||||||
|
|
||||||
meow@^9.0.0:
|
meow@^9.0.0:
|
||||||
version "9.0.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364"
|
resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364"
|
||||||
@ -9737,7 +9783,7 @@ prompts@^2.0.1, prompts@^2.4.2:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.8.1:
|
prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
|
||||||
version "15.8.1"
|
version "15.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||||
@ -10108,6 +10154,21 @@ react-scripts@5.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "^2.3.2"
|
fsevents "^2.3.2"
|
||||||
|
|
||||||
|
react-select@5.7.0:
|
||||||
|
version "5.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.0.tgz#82921b38f1fcf1471a0b62304da01f2896cd8ce6"
|
||||||
|
integrity sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.0"
|
||||||
|
"@emotion/cache" "^11.4.0"
|
||||||
|
"@emotion/react" "^11.8.1"
|
||||||
|
"@floating-ui/dom" "^1.0.1"
|
||||||
|
"@types/react-transition-group" "^4.4.0"
|
||||||
|
memoize-one "^6.0.0"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
react-transition-group "^4.3.0"
|
||||||
|
use-isomorphic-layout-effect "^1.1.2"
|
||||||
|
|
||||||
react-style-singleton@^2.2.1:
|
react-style-singleton@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
|
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
|
||||||
@ -10133,6 +10194,16 @@ react-table@7.8.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2"
|
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2"
|
||||||
integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==
|
integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==
|
||||||
|
|
||||||
|
react-transition-group@^4.3.0:
|
||||||
|
version "4.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
|
||||||
|
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.5.5"
|
||||||
|
dom-helpers "^5.0.1"
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react@^18.2.0:
|
react@^18.2.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||||
@ -11705,6 +11776,11 @@ use-callback-ref@^1.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.0.0"
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
use-isomorphic-layout-effect@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
|
||||||
|
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
|
||||||
|
|
||||||
use-sidecar@^1.1.2:
|
use-sidecar@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
|
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user