From a5fee7896324335c5d0cdfd189376a4a99362ef5 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 20 Aug 2025 17:59:53 +0300 Subject: [PATCH] fix form --- client_v2/src/__locales/en.json | 16 +- .../src/common/ui/Button/Button.module.pcss | 21 + client_v2/src/common/ui/Button/Button.tsx | 2 +- client_v2/src/components/Encryption/Form.tsx | 379 ++++++++++-------- .../Encryption/Status/KeyStatus.tsx | 9 +- .../Encryption/Status/styles.module.pcss | 23 +- .../components/Encryption/styles.module.pcss | 6 + client_v2/src/lib/theme/Form.module.pcss | 2 +- 8 files changed, 263 insertions(+), 195 deletions(-) diff --git a/client_v2/src/__locales/en.json b/client_v2/src/__locales/en.json index 74845df0..ea52611f 100644 --- a/client_v2/src/__locales/en.json +++ b/client_v2/src/__locales/en.json @@ -791,7 +791,7 @@ "settings_notify_statistics_cleared": "Statistics cleared", "encryption_title": "Encryption", "encryption_encrypted_dns": "Encrypted DNS", - "encryption_encrypted_dns_desc": "The AdGuard Home admin interface uses HTTPS. The DNS server can use DNS-over-HTTPS, DNS-over-TLS, and DNS-over-QUIC", + "encryption_encrypted_dns_desc": "The AdGuard Home admin interface uses HTTPS. The DNS server supports DNS-over-HTTPS, DNS-over-TLS, and DNS-over-QUIC", "encryption_plain_dns": "Plain DNS", "encryption_plain_dns_desc": "Plain DNS is enabled by default. You can disable it to force all devices to use encrypted DNS. To do this, you must specify at least one encrypted DNS protocol", "encryption_server": "Server name", @@ -813,13 +813,21 @@ "encryption_chain_valid": "Certificate chain is valid", "encryption_chain_invalid": "Certificate chain is invalid", "encryption_key_valid": "Private key is valid", + "encryption_key_type": "Encryption algorithm: %value%", "encryption_key_invalid": "Private key is invalid", "encryption_subject": "Subject: %value%", "encryption_issuer": "Issuer: %value%", "encryption_expire": "Expires: %value%", "encryption_hostnames": "Hostnames: %value%", "encryption_certificate_has_issues": "Certificate has issues", - "encryption_confirm_clear": "Reset encryption settings?", - "encryption_confirm_clear_desc": "This will reset all encryption settings to default values", - "confirm": "Confirm" + "encryption_confirm_clear": "Reset encryption settings", + "encryption_confirm_clear_desc": "All encryption settings will be reset to their default values", + "reset": "Reset", + "confirm": "Confirm", + "encryption_certificate_error": "Unable to read certificate file", + "encryption_private_key_error": "Private key does not match certificate", + "encryption_certificate_name_error": "The server certificate does not include the server name %value%", + "encryption_invalid_data": "Invalid data", + "encryption_certificate_no_ip": "This certificate does not contain IP addresses. DDR and DNS-over-TLS may not work properly", + "encryption_certificate_self_signed": "This is a self-signed certificate — it may not work on all devices. If you want to use it, make sure that all your devices will accept it" } diff --git a/client_v2/src/common/ui/Button/Button.module.pcss b/client_v2/src/common/ui/Button/Button.module.pcss index 91585bd8..f8b92881 100644 --- a/client_v2/src/common/ui/Button/Button.module.pcss +++ b/client_v2/src/common/ui/Button/Button.module.pcss @@ -115,6 +115,27 @@ } } +.secondary-danger { + color: var(--default-danger-button); + border-color: var(--default-danger-button); + + &:hover, + &:focus { + color: var(--hovered-danger-button); + border-color: var(--hovered-danger-button); + } + + &:active { + color: var(--pressed-danger-button); + border-color: var(--pressed-danger-button); + } + + &:disabled { + color: var(--disabled-danger-button); + border-color: var(--disabled-danger-button); + } +} + .danger { color: var(--gray-0); background: var(--default-danger-button); diff --git a/client_v2/src/common/ui/Button/Button.tsx b/client_v2/src/common/ui/Button/Button.tsx index bda4f4a7..0e13cf52 100644 --- a/client_v2/src/common/ui/Button/Button.tsx +++ b/client_v2/src/common/ui/Button/Button.tsx @@ -5,7 +5,7 @@ import s from './Button.module.pcss'; export type ButtonProps = ComponentProps<'button'> & { size?: 'small' | 'medium' | 'big'; - variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; + variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'secondary-danger'; children?: ReactNode; leftAddon?: ReactNode; rightAddon?: ReactNode; diff --git a/client_v2/src/components/Encryption/Form.tsx b/client_v2/src/components/Encryption/Form.tsx index 45c274a2..d4e42e88 100644 --- a/client_v2/src/components/Encryption/Form.tsx +++ b/client_v2/src/components/Encryption/Form.tsx @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; import { Controller, useForm } from 'react-hook-form'; import i18next from 'i18next'; import cn from 'clsx'; @@ -96,9 +95,10 @@ const defaultValues = { }; export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValidation }: Props) => { - const { t } = useTranslation(); const dispatch = useDispatch(); - const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const [openConfirmReset, setOpenConfirmReset] = useState(false); + const [openPlainDnsDisable, setOpenPlainDnsDisable] = useState(false); + const [stagedFormValues, setStagedFormValues] = useState(null); const { not_after, @@ -106,6 +106,7 @@ export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValid valid_key, valid_cert, valid_pair, + key_type, dns_names, issuer, subject, @@ -157,9 +158,24 @@ export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValid return !isValid || processing || !valid_key || !valid_cert || !valid_pair; }; - const handleResetConfirmOpen = () => setOpenConfirmDialog(true); + const handleResetOpen = () => setOpenConfirmReset(true); - const handleResetConfirmClose = () => setOpenConfirmDialog(false); + const handleResetClose = () => setOpenConfirmReset(false); + + const handlePlainDnsDisableOpen = () => setOpenPlainDnsDisable(true); + + const handlePlainDnsDisableClose = () => { + setOpenPlainDnsDisable(false); + setStagedFormValues(null); + }; + + const handlePlainDnsDisableConfirm = () => { + if (stagedFormValues) { + onSubmit(stagedFormValues); + setStagedFormValues(null); + } + setOpenPlainDnsDisable(false); + }; const handleReset = () => { reset(); @@ -187,13 +203,42 @@ export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValid Object.entries(validationErrors).forEach(([field, message]) => { setError(field as keyof EncryptionFormValues, { type: 'manual', message }); }); - } else { - onSubmit(data); + return; } + + if (data.serve_plain_dns === false) { + setStagedFormValues(data); + handlePlainDnsDisableOpen(); + return; + } + + onSubmit(data); + }; + + const renderCertificateStatus = () => { + if (warning_validation) { + const isWarning = valid_key && valid_cert && valid_pair; + + return ; + } + + if (!certificateChain && !certificatePath) { + return null; + } + + return ( + + ); }; const isDisabled = isSavingDisabled(); - const isWarning = valid_key && valid_cert && valid_pair; return (
@@ -206,8 +251,139 @@ export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValid title={intl.getMessage('encryption_encrypted_dns')} description={intl.getMessage('encryption_encrypted_dns_desc')} checked={field.value} - onChange={field.onChange} - /> + onChange={field.onChange}> +
+
+ ( + + {intl.getMessage('encryption_server')} + + +
+ {intl.getMessage('encryption_server_tooltip_1')} +
+
+ {intl.getMessage('encryption_server_tooltip_2')} +
+ + } + menuSize="large" + /> + + } + placeholder={intl.getMessage('encryption_server_enter')} + errorMessage={fieldState.error?.message} + disabled={!isEnabled} + onBlur={handleBlur} + /> + )} + /> +
+
+ ( + + {intl.getMessage('encryption_https')} + + + + } + placeholder={intl.getMessage('encryption_https')} + errorMessage={fieldState.error?.message} + disabled={!isEnabled} + onChange={(e) => { + const { value } = e.target; + field.onChange(toNumber(value)); + }} + onBlur={handleBlur} + /> + )} + /> +
+
+ ( + + {intl.getMessage('encryption_dot')} + + + + } + placeholder={intl.getMessage('encryption_dot')} + errorMessage={fieldState.error?.message} + disabled={!isEnabled} + onChange={(e) => { + const { value } = e.target; + field.onChange(toNumber(value)); + }} + onBlur={handleBlur} + /> + )} + /> +
+
+ ( + + {intl.getMessage('encryption_doq')} + + + + } + placeholder={intl.getMessage('encryption_doq')} + errorMessage={fieldState.error?.message} + disabled={!isEnabled} + onChange={(e) => { + const { value } = e.target; + field.onChange(toNumber(value)); + }} + onBlur={handleBlur} + /> + )} + /> +
+
+ )} /> @@ -224,139 +400,11 @@ export const Form = ({ initialValues, encryption, onSubmit, debouncedConfigValid description={intl.getMessage('encryption_plain_dns_desc')} checked={field.value} onChange={field.onChange} + disabled={!isEnabled} /> )} /> -
-
- ( - - {intl.getMessage('encryption_server')} - - -
- {intl.getMessage('encryption_server_tooltip_1')} -
-
- {intl.getMessage('encryption_server_tooltip_2')} -
- - } - menuSize="large" - /> - - } - placeholder={t('encryption_server_enter')} - errorMessage={fieldState.error?.message} - disabled={!isEnabled} - onBlur={handleBlur} - /> - )} - /> -
- -
- ( - - {intl.getMessage('encryption_https')} - - - - } - placeholder={t('encryption_https')} - errorMessage={fieldState.error?.message} - disabled={!isEnabled} - onChange={(e) => { - const { value } = e.target; - field.onChange(toNumber(value)); - }} - onBlur={handleBlur} - /> - )} - /> -
- -
- ( - - {intl.getMessage('encryption_dot')} - - - - } - placeholder={t('encryption_dot')} - errorMessage={fieldState.error?.message} - disabled={!isEnabled} - onChange={(e) => { - const { value } = e.target; - field.onChange(toNumber(value)); - }} - onBlur={handleBlur} - /> - )} - /> -
- -
- ( - - {intl.getMessage('encryption_doq')} - - - - } - placeholder={t('encryption_doq')} - errorMessage={fieldState.error?.message} - disabled={!isEnabled} - onChange={(e) => { - const { value } = e.target; - field.onChange(toNumber(value)); - }} - onBlur={handleBlur} - /> - )} - /> -
-
- (