Pull request #2231: ADG-8368 Frontend rewritten in TypeScript, added Node 18 support

Merge in DNS/adguard-home from ADG-8368-typescript-node-18 to master

Squashed commit of the following:

commit daa288ae0d76178af24595cc807055902e6f09ab
Merge: 4c89cf720 1085d59a6
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Mon Jun 10 17:22:20 2024 +0200

    merge

commit 4c89cf7209
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jun 6 13:27:18 2024 +0300

    remove install from initial state

commit b943f2011f
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 23:10:55 2024 +0200

    frontend production build fix

commit cd1be2d66d
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 20:23:14 2024 +0200

    production build quickfix

commit 7b8ac01fc2
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Jun 5 19:57:31 2024 +0300

    all: upd node docker

commit 02afed66d5
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 18:23:12 2024 +0200

    changelog fixes

commit 9c0f736f0c
Merge: 62c4fbf1e e04775c4f
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 18:18:29 2024 +0200

    merge

commit 62c4fbf1e3
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 16:22:22 2024 +0200

    empty line in changelog

commit 76b1e44a93
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 16:20:37 2024 +0200

    changelog

commit f783e90040
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 16:19:13 2024 +0200

    filters.js -> filters.ts

commit 3d4ce6554c
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 16:18:03 2024 +0200

    generated file removed

commit e35ba58f2a
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 15:45:21 2024 +0200

    rollback unwanted changes

commit 1f30d4216d
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 15:27:36 2024 +0200

    review fix

commit 6cd4e44f07
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 11:55:39 2024 +0200

    missing generated file restoresd

commit 2ab738b303
Author: Igor Lobanov <bniwredyc@gmail.com>
Date:   Wed Jun 5 11:40:32 2024 +0200

    Frontend rewritten in TypeScript, added Node 18 support
This commit is contained in:
Igor Lobanov
2024-06-10 18:42:23 +03:00
parent 1085d59a65
commit 1afe226ce8
296 changed files with 32122 additions and 32651 deletions

View File

@@ -5,14 +5,18 @@ export const R_HOST = /^(\*\.)?[\w.-]+$/;
export const R_IPV4 = /^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/;
export const R_IPV6 = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
export const R_IPV6 =
/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
export const R_CIDR = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
export const R_CIDR =
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-:]){5})([a-fA-F0-9]{2})$)|^((([a-fA-F0-9][a-fA-F0-9]+[-:]){7})([a-fA-F0-9]{2})$)|^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){2}([a-fA-F0-9]{4})$|^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){3}([a-fA-F0-9]{4})$/;
export const R_MAC =
/^((([a-fA-F0-9][a-fA-F0-9]+[-:]){5})([a-fA-F0-9]{2})$)|^((([a-fA-F0-9][a-fA-F0-9]+[-:]){7})([a-fA-F0-9]{2})$)|^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){2}([a-fA-F0-9]{4})$|^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){3}([a-fA-F0-9]{4})$/;
export const R_MAC_WITHOUT_COLON = /^([a-fA-F0-9]{2}){5}([a-fA-F0-9]{2})$|^([a-fA-F0-9]{2}){7}([a-fA-F0-9]{2})$/;
export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
export const R_CIDR_IPV6 =
/^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
export const R_DOMAIN = /^([a-zA-Z0-9][a-zA-Z0-9-_]*\.)*[a-zA-Z0-9]*[a-zA-Z0-9-_]*[[a-zA-Z0-9]+$/;
@@ -57,8 +61,7 @@ export const STATUS_COLORS = {
export const REPOSITORY = {
URL: 'https://github.com/AdguardTeam/AdGuardHome',
TRACKERS_DB:
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/trackers.json',
TRACKERS_DB: 'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/trackers.json',
ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose',
};
@@ -66,7 +69,8 @@ export const CLIENT_ID_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/C
export const MANUAL_UPDATE_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#manual-update';
export const PORT_53_FAQ_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#bindinuse';
export const PRIVACY_POLICY_LINK = 'https://link.adtidy.org/forward.html?action=privacy&from=ui&app=home';
export const UPSTREAM_CONFIGURATION_WIKI_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams';
export const UPSTREAM_CONFIGURATION_WIKI_LINK =
'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams';
export const FILTERS_RELATIVE_LINK = '#filters';
@@ -99,70 +103,9 @@ export const SHOW_TOOLTIP_DELAY = 200;
export const MODAL_OPEN_TIMEOUT = 150;
export const UNSAFE_PORTS = [
1,
7,
9,
11,
13,
15,
17,
19,
20,
21,
22,
23,
25,
37,
42,
43,
53,
77,
79,
87,
95,
101,
102,
103,
104,
109,
110,
111,
113,
115,
117,
119,
123,
135,
139,
143,
179,
389,
465,
512,
513,
514,
515,
526,
530,
531,
532,
540,
556,
563,
587,
601,
636,
993,
995,
2049,
3659,
4045,
6000,
6665,
6666,
6667,
6668,
6669,
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111,
113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512, 513, 514, 515, 526, 530, 531, 532, 540, 556, 563, 587,
601, 636, 993, 995, 2049, 3659, 4045, 6000, 6665, 6666, 6667, 6668, 6669,
];
export const ALL_INTERFACES_IP = '0.0.0.0';
@@ -171,7 +114,7 @@ export const STATUS_RESPONSE = {
YES: 'yes',
NO: 'no',
ERROR: 'error',
};
} as const;
export const MODAL_TYPE = {
SELECT_MODAL_TYPE: 'SELECT_MODAL_TYPE',
@@ -331,11 +274,20 @@ export const RESPONSE_FILTER = {
},
};
export const RESPONSE_FILTER_QUERIES = Object.values(RESPONSE_FILTER)
.reduce((acc, { QUERY }) => {
export const RESPONSE_FILTER_QUERIES = Object.values(RESPONSE_FILTER).reduce(
(
acc: Record<string, string>,
{
QUERY,
}: {
QUERY: string;
},
) => {
acc[QUERY] = QUERY;
return acc;
}, {});
},
{},
);
export const QUERY_STATUS_COLORS = {
BLUE: 'blue',
@@ -397,7 +349,7 @@ export const DEFAULT_SHORT_DATE_FORMAT_OPTIONS = {
month: 'numeric',
day: 'numeric',
hour12: false,
};
} as const;
export const DEFAULT_DATE_FORMAT_OPTIONS = {
year: 'numeric',
@@ -406,12 +358,12 @@ export const DEFAULT_DATE_FORMAT_OPTIONS = {
hour: 'numeric',
hourCycle: 'h23',
minute: 'numeric',
};
} as const;
export const DETAILED_DATE_FORMAT_OPTIONS = {
...DEFAULT_DATE_FORMAT_OPTIONS,
month: 'long',
};
} as const;
export const SPECIAL_FILTER_ID = {
CUSTOM_FILTERING_RULES: 0,

View File

@@ -1,314 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Trans } from 'react-i18next';
import cn from 'classnames';
import { createOnBlurHandler } from './helpers';
import { R_MAC_WITHOUT_COLON, R_UNIX_ABSOLUTE_PATH, R_WIN_ABSOLUTE_PATH } from './constants';
export const renderField = (props, elementType) => {
const {
input, id, className, placeholder, type, disabled, normalizeOnBlur, onScroll,
autoComplete, meta: { touched, error }, min, max, step,
} = props;
const onBlur = (event) => createOnBlurHandler(event, input, normalizeOnBlur);
const element = React.createElement(elementType, {
...input,
id,
className,
placeholder,
autoComplete,
disabled,
type,
min,
max,
step,
onBlur,
onScroll,
});
return (
<>
{element}
{!disabled && touched && error
&& <span className="form__message form__message--error"><Trans>{error}</Trans></span>}
</>
);
};
renderField.propTypes = {
id: PropTypes.string.isRequired,
input: PropTypes.object.isRequired,
className: PropTypes.string,
placeholder: PropTypes.string,
type: PropTypes.string,
disabled: PropTypes.bool,
autoComplete: PropTypes.bool,
normalizeOnBlur: PropTypes.func,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
onScroll: PropTypes.func,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
};
export const renderTextareaField = (props) => renderField(props, 'textarea');
export const renderInputField = (props) => renderField(props, 'input');
export const renderGroupField = ({
input,
id,
className,
placeholder,
type,
disabled,
autoComplete,
isActionAvailable,
removeField,
meta: { touched, error },
normalizeOnBlur,
}) => {
const onBlur = (event) => createOnBlurHandler(event, input, normalizeOnBlur);
return (
<>
<div className="input-group">
<input
{...input}
id={id}
placeholder={placeholder}
type={type}
className={className}
disabled={disabled}
autoComplete={autoComplete}
onBlur={onBlur}
/>
{isActionAvailable
&& <span className="input-group-append">
<button
type="button"
className="btn btn-secondary btn-icon btn-icon--green"
onClick={removeField}
>
<svg className="icon icon--24">
<use xlinkHref="#cross" />
</svg>
</button>
</span>
}
</div>
{!disabled && touched && error
&& <span className="form__message form__message--error"><Trans>{error}</Trans></span>}
</>
);
};
renderGroupField.propTypes = {
input: PropTypes.object.isRequired,
id: PropTypes.string,
className: PropTypes.string,
placeholder: PropTypes.string,
type: PropTypes.string,
disabled: PropTypes.bool,
autoComplete: PropTypes.bool,
isActionAvailable: PropTypes.bool,
removeField: PropTypes.func,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
normalizeOnBlur: PropTypes.func,
};
export const renderRadioField = ({
input,
placeholder,
subtitle,
disabled,
meta: { touched, error },
}) => <Fragment>
<label className="custom-control custom-radio">
<input {...input} type="radio" className="custom-control-input" disabled={disabled} />
<span className="custom-control-label">{placeholder}</span>
{subtitle && <span
className="checkbox__label-subtitle"
dangerouslySetInnerHTML={{ __html: subtitle }}
/>}
</label>
{!disabled
&& touched
&& error
&& <span className="form__message form__message--error"><Trans>{error}</Trans></span>}
</Fragment>;
renderRadioField.propTypes = {
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
subtitle: PropTypes.string,
disabled: PropTypes.bool,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
};
export const CheckboxField = ({
input,
placeholder,
subtitle,
disabled,
onClick,
modifier = 'checkbox--form',
meta: { touched, error },
}) => <>
<label className={`checkbox ${modifier}`} onClick={onClick}>
<span className="checkbox__marker" />
<input {...input} type="checkbox" className="checkbox__input" disabled={disabled} />
<span className="checkbox__label">
<span className="checkbox__label-text checkbox__label-text--long">
<span className="checkbox__label-title">{placeholder}</span>
{subtitle && <span className="checkbox__label-subtitle">{subtitle}</span>}
</span>
</span>
</label>
{!disabled
&& touched
&& error
&& <div className="form__message form__message--error mt-1"><Trans>{error}</Trans></div>}
</>;
CheckboxField.propTypes = {
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
subtitle: PropTypes.node,
disabled: PropTypes.bool,
onClick: PropTypes.func,
modifier: PropTypes.string,
checked: PropTypes.bool,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
};
export const renderSelectField = ({
input,
meta: { touched, error },
children,
label,
}) => {
const showWarning = touched && error;
return <>
{label && <label><Trans>{label}</Trans></label>}
<select {...input} className='form-control custom-select'>{children}</select>
{showWarning
&& <span className="form__message form__message--error form__message--left-pad"><Trans>{error}</Trans></span>}
</>;
};
renderSelectField.propTypes = {
input: PropTypes.object.isRequired,
disabled: PropTypes.bool,
label: PropTypes.string,
children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]).isRequired,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
};
export const renderServiceField = ({
input,
placeholder,
disabled,
modifier,
icon,
meta: { touched, error },
}) => (
<>
<label className={cn('service custom-switch', { [modifier]: modifier })}>
<input
{...input}
type="checkbox"
className="custom-switch-input"
value={placeholder.toLowerCase()}
disabled={disabled}
/>
<span className="service__switch custom-switch-indicator"></span>
<span className="service__text" title={placeholder}>
{placeholder}
</span>
{icon && (
<div
dangerouslySetInnerHTML={{ __html: window.atob(icon) }}
className="service__icon"
/>
)}
</label>
{!disabled && touched && error && (
<span className="form__message form__message--error">
<Trans>{error}</Trans>
</span>
)}
</>
);
renderServiceField.propTypes = {
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
disabled: PropTypes.bool,
modifier: PropTypes.string,
icon: PropTypes.string,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.string,
}).isRequired,
};
/**
*
* @param {string} ip
* @returns {*}
*/
export const ip4ToInt = (ip) => {
const intIp = ip.split('.').reduce((int, oct) => (int * 256) + parseInt(oct, 10), 0);
return Number.isNaN(intIp) ? 0 : intIp;
};
/**
* @param value {string}
* @returns {*|number}
*/
export const toNumber = (value) => value && parseInt(value, 10);
/**
* @param value {string}
* @returns {*|number}
*/
export const toFloatNumber = (value) => value && parseFloat(value, 10);
/**
* @param value {string}
* @returns {boolean}
*/
export const isValidAbsolutePath = (value) => R_WIN_ABSOLUTE_PATH.test(value)
|| R_UNIX_ABSOLUTE_PATH.test(value);
/**
* @param value {string}
* @returns {*|string}
*/
export const normalizeMac = (value) => {
if (value && R_MAC_WITHOUT_COLON.test(value)) {
return value.match(/.{2}/g).join(':');
}
return value;
};

341
client/src/helpers/form.tsx Normal file
View File

@@ -0,0 +1,341 @@
import React, { Fragment } from 'react';
import { Trans } from 'react-i18next';
import cn from 'classnames';
import { createOnBlurHandler } from './helpers';
import { R_MAC_WITHOUT_COLON, R_UNIX_ABSOLUTE_PATH, R_WIN_ABSOLUTE_PATH } from './constants';
interface renderFieldProps {
id: string;
input: object;
className?: string;
placeholder?: string;
type?: string;
disabled?: boolean;
autoComplete?: string;
normalizeOnBlur?: (...args: unknown[]) => unknown;
min?: number;
max?: number;
step?: number;
onScroll?: (...args: unknown[]) => unknown;
meta: {
touched?: boolean;
error?: string;
};
}
export const renderField = (props: renderFieldProps, elementType: any) => {
const {
input,
id,
className,
placeholder,
type,
disabled,
normalizeOnBlur,
onScroll,
autoComplete,
meta: { touched, error },
min,
max,
step,
} = props;
const onBlur = (event: any) => createOnBlurHandler(event, input, normalizeOnBlur);
const element = React.createElement(elementType, {
...input,
id,
className,
placeholder,
autoComplete,
disabled,
type,
min,
max,
step,
onBlur,
onScroll,
});
return (
<>
{element}
{!disabled && touched && error && (
<span className="form__message form__message--error">
<Trans>{error}</Trans>
</span>
)}
</>
);
};
export const renderTextareaField = (props: any) => renderField(props, 'textarea');
export const renderInputField = (props: any) => renderField(props, 'input');
interface renderGroupFieldProps {
input: object;
id?: string;
className?: string;
placeholder?: string;
type?: string;
disabled?: boolean;
autoComplete?: string;
isActionAvailable?: boolean;
removeField?: (...args: unknown[]) => unknown;
meta: {
touched?: boolean;
error?: string;
};
normalizeOnBlur?: (...args: unknown[]) => unknown;
}
export const renderGroupField = ({
input,
id,
className,
placeholder,
type,
disabled,
autoComplete,
isActionAvailable,
removeField,
meta: { touched, error },
normalizeOnBlur,
}: renderGroupFieldProps) => {
const onBlur = (event: any) => createOnBlurHandler(event, input, normalizeOnBlur);
return (
<>
<div className="input-group">
<input
{...input}
id={id}
placeholder={placeholder}
type={type}
className={className}
disabled={disabled}
autoComplete={autoComplete}
onBlur={onBlur}
/>
{isActionAvailable && (
<span className="input-group-append">
<button
type="button"
className="btn btn-secondary btn-icon btn-icon--green"
onClick={removeField}>
<svg className="icon icon--24">
<use xlinkHref="#cross" />
</svg>
</button>
</span>
)}
</div>
{!disabled && touched && error && (
<span className="form__message form__message--error">
<Trans>{error}</Trans>
</span>
)}
</>
);
};
interface renderRadioFieldProps {
input: object;
placeholder?: string;
subtitle?: string;
disabled?: boolean;
meta: {
touched?: boolean;
error?: string;
};
}
export const renderRadioField = ({
input,
placeholder,
subtitle,
disabled,
meta: { touched, error },
}: renderRadioFieldProps) => (
<Fragment>
<label className="custom-control custom-radio">
<input {...input} type="radio" className="custom-control-input" disabled={disabled} />
<span className="custom-control-label">{placeholder}</span>
{subtitle && <span className="checkbox__label-subtitle" dangerouslySetInnerHTML={{ __html: subtitle }} />}
</label>
{!disabled && touched && error && (
<span className="form__message form__message--error">
<Trans>{error}</Trans>
</span>
)}
</Fragment>
);
interface CheckboxFieldProps {
input: object;
placeholder?: string;
subtitle?: React.ReactNode;
disabled?: boolean;
onClick?: (...args: unknown[]) => unknown;
modifier?: string;
checked?: boolean;
meta: {
touched?: boolean;
error?: string;
};
}
export const CheckboxField = ({
input,
placeholder,
subtitle,
disabled,
onClick,
modifier = 'checkbox--form',
meta: { touched, error },
}: CheckboxFieldProps) => (
<>
<label className={`checkbox ${modifier}`} onClick={onClick}>
<span className="checkbox__marker" />
<input {...input} type="checkbox" className="checkbox__input" disabled={disabled} />
<span className="checkbox__label">
<span className="checkbox__label-text checkbox__label-text--long">
<span className="checkbox__label-title">{placeholder}</span>
{subtitle && <span className="checkbox__label-subtitle">{subtitle}</span>}
</span>
</span>
</label>
{!disabled && touched && error && (
<div className="form__message form__message--error mt-1">
<Trans>{error}</Trans>
</div>
)}
</>
);
interface renderSelectFieldProps {
input: object;
disabled?: boolean;
label?: string;
children: unknown[] | React.ReactElement;
meta: {
touched?: boolean;
error?: string;
};
}
export const renderSelectField = ({ input, meta: { touched, error }, children, label }: renderSelectFieldProps) => {
const showWarning = touched && error;
return (
<>
{label && (
<label>
<Trans>{label}</Trans>
</label>
)}
<select {...input} className="form-control custom-select">
{children}
</select>
{showWarning && (
<span className="form__message form__message--error form__message--left-pad">
<Trans>{error}</Trans>
</span>
)}
</>
);
};
interface renderServiceFieldProps {
input: object;
placeholder?: string;
disabled?: boolean;
modifier?: string;
icon?: string;
meta: {
touched?: boolean;
error?: string;
};
}
export const renderServiceField = ({
input,
placeholder,
disabled,
modifier,
icon,
meta: { touched, error },
}: renderServiceFieldProps) => (
<>
<label className={cn('service custom-switch', { [modifier]: modifier })}>
<input
{...input}
type="checkbox"
className="custom-switch-input"
value={placeholder.toLowerCase()}
disabled={disabled}
/>
<span className="service__switch custom-switch-indicator"></span>
<span className="service__text" title={placeholder}>
{placeholder}
</span>
{icon && <div dangerouslySetInnerHTML={{ __html: window.atob(icon) }} className="service__icon" />}
</label>
{!disabled && touched && error && (
<span className="form__message form__message--error">
<Trans>{error}</Trans>
</span>
)}
</>
);
/**
*
* @param {string} ip
* @returns {*}
*/
export const ip4ToInt = (ip: any) => {
const intIp = ip.split('.').reduce((int: any, oct: any) => int * 256 + parseInt(oct, 10), 0);
return Number.isNaN(intIp) ? 0 : intIp;
};
/**
* @param value {string}
* @returns {*|number}
*/
export const toNumber = (value: any) => value && parseInt(value, 10);
/**
* @param value {string}
* @returns {*|number}
*/
export const toFloatNumber = (value: any) => value && parseFloat(value);
/**
* @param value {string}
* @returns {boolean}
*/
export const isValidAbsolutePath = (value: any) => R_WIN_ABSOLUTE_PATH.test(value) || R_UNIX_ABSOLUTE_PATH.test(value);
/**
* @param value {string}
* @returns {*|string}
*/
export const normalizeMac = (value: any) => {
if (value && R_MAC_WITHOUT_COLON.test(value)) {
return value.match(/.{2}/g).join(':');
}
return value;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +0,0 @@
import React from 'react';
import classnames from 'classnames';
import { COMMENT_LINE_DEFAULT_TOKEN } from './constants';
const renderHighlightedLine = (line, idx, commentLineTokens = [COMMENT_LINE_DEFAULT_TOKEN]) => {
const isComment = commentLineTokens.some((token) => line.trim().startsWith(token));
const lineClassName = classnames({
'text-gray': isComment,
'text-transparent': !isComment,
});
return <div className={lineClassName} key={idx}>{line || '\n'}</div>;
};
export const getTextareaCommentsHighlight = (
ref, lines, className = '', commentLineTokens,
) => {
const renderLine = (line, idx) => renderHighlightedLine(line, idx, commentLineTokens);
return <code className={classnames('text-output font-monospace', className)} ref={ref}>{lines?.split('\n').map(renderLine)}</code>;
};
export const syncScroll = (e, ref) => {
// eslint-disable-next-line no-param-reassign
ref.current.scrollTop = e.target.scrollTop;
};

View File

@@ -0,0 +1,32 @@
import React from 'react';
import classnames from 'classnames';
import { COMMENT_LINE_DEFAULT_TOKEN } from './constants';
const renderHighlightedLine = (line: any, idx: any, commentLineTokens = [COMMENT_LINE_DEFAULT_TOKEN]) => {
const isComment = commentLineTokens.some((token) => line.trim().startsWith(token));
const lineClassName = classnames({
'text-gray': isComment,
'text-transparent': !isComment,
});
return (
<div className={lineClassName} key={idx}>
{line || '\n'}
</div>
);
};
export const getTextareaCommentsHighlight = (ref: any, lines: any, commentLineTokens?: any, className = '') => {
const renderLine = (line: any, idx: any) => renderHighlightedLine(line, idx, commentLineTokens);
return (
<code className={classnames('text-output font-monospace', className)} ref={ref}>
{lines?.split('\n').map(renderLine)}
</code>
);
};
export const syncScroll = (e: any, ref: any) => {
// eslint-disable-next-line no-param-reassign
ref.current.scrollTop = e.target.scrollTop;
};

View File

@@ -8,7 +8,7 @@ export const LOCAL_STORAGE_KEYS = {
};
export const LocalStorageHelper = {
setItem(key, value) {
setItem(key: any, value: any) {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
@@ -16,7 +16,7 @@ export const LocalStorageHelper = {
}
},
getItem(key) {
getItem(key: any) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
@@ -26,7 +26,7 @@ export const LocalStorageHelper = {
}
},
removeItem(key) {
removeItem(key: any) {
try {
localStorage.removeItem(key);
} catch (error) {

View File

@@ -1,70 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { normalizeWhois } from './helpers';
import { WHOIS_ICONS } from './constants';
const getFormattedWhois = (whois) => {
const whoisInfo = normalizeWhois(whois);
return (
Object.keys(whoisInfo)
.map((key) => {
const icon = WHOIS_ICONS[key];
return (
<span className="logs__whois text-muted" key={key} title={whoisInfo[key]}>
{icon && (
<>
<svg className="logs__whois-icon icons icon--18">
<use xlinkHref={`#${icon}`} />
</svg>
&nbsp;
</>
)}{whoisInfo[key]}
</span>
);
})
);
};
/**
* @param {string} value
* @param {object} info
* @param {string} info.name
* @param {object} info.whois_info
* @param {boolean} [isDetailed]
* @param {boolean} [isLogs]
* @returns {JSXElement}
*/
export const renderFormattedClientCell = (value, info, isDetailed = false, isLogs = false) => {
let whoisContainer = null;
let nameContainer = value;
if (info) {
const { name, whois_info } = info;
const whoisAvailable = whois_info && Object.keys(whois_info).length > 0;
if (name) {
const nameValue = <div className="logs__text logs__text--link logs__text--nowrap logs__text--client" title={`${name} (${value})`}>
{name}&nbsp;<small>{`(${value})`}</small>
</div>;
if (!isLogs) {
nameContainer = nameValue;
} else {
nameContainer = !whoisAvailable && isDetailed
? <small title={value}>{value}</small>
: nameValue;
}
}
if (whoisAvailable && isDetailed) {
whoisContainer = <div className="logs__text logs__text--wrap logs__text--whois">
{getFormattedWhois(whois_info)}
</div>;
}
}
return <div className="logs__text mw-100" title={value}>
<Link to={`logs?search="${encodeURIComponent(value)}"`}>{nameContainer}</Link>
{whoisContainer}
</div>;
};

View File

@@ -0,0 +1,74 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { normalizeWhois } from './helpers';
import { WHOIS_ICONS } from './constants';
const getFormattedWhois = (whois: any) => {
const whoisInfo = normalizeWhois(whois);
return Object.keys(whoisInfo).map((key) => {
const icon = WHOIS_ICONS[key];
return (
<span className="logs__whois text-muted" key={key} title={whoisInfo[key]}>
{icon && (
<>
<svg className="logs__whois-icon icons icon--18">
<use xlinkHref={`#${icon}`} />
</svg>
&nbsp;
</>
)}
{whoisInfo[key]}
</span>
);
});
};
/**
* @param {string} value
* @param {object} info
* @param {string} info.name
* @param {object} info.whois_info
* @param {boolean} [isDetailed]
* @param {boolean} [isLogs]
* @returns {JSXElement}
*/
export const renderFormattedClientCell = (value: any, info: any, isDetailed = false, isLogs = false) => {
let whoisContainer = null;
let nameContainer = value;
if (info) {
const { name, whois_info } = info;
const whoisAvailable = whois_info && Object.keys(whois_info).length > 0;
if (name) {
const nameValue = (
<div
className="logs__text logs__text--link logs__text--nowrap logs__text--client"
title={`${name} (${value})`}>
{name}&nbsp;<small>{`(${value})`}</small>
</div>
);
if (!isLogs) {
nameContainer = nameValue;
} else {
nameContainer = !whoisAvailable && isDetailed ? <small title={value}>{value}</small> : nameValue;
}
}
if (whoisAvailable && isDetailed) {
whoisContainer = (
<div className="logs__text logs__text--wrap logs__text--whois">{getFormattedWhois(whois_info)}</div>
);
}
}
return (
<div className="logs__text mw-100" title={value}>
<Link to={`logs?search="${encodeURIComponent(value)}"`}>{nameContainer}</Link>
{whoisContainer}
</div>
);
};

View File

@@ -1,5 +1,5 @@
{
"timeUpdated": "2024-05-27T12:08:27.431Z",
"timeUpdated": "2024-03-01T00:10:14.031Z",
"categories": {
"0": "audio_video_player",
"1": "comments",
@@ -12869,13 +12869,6 @@
"url": "http://opensharecount.com/",
"companyId": "open_share_count"
},
"openai": {
"name": "OpenAI",
"categoryId": 8,
"url": "https://openai.com/",
"companyId": "openai",
"source": "AdGuard"
},
"openload": {
"name": "Openload",
"categoryId": 9,
@@ -23480,10 +23473,6 @@
"realmedia.com": "open_adstream",
"realmediadigital.com": "open_adstream",
"opensharecount.com": "open_share_count",
"chatgpt.com": "openai",
"oaistatic.com": "openai",
"oaiusercontent.com": "openai",
"openai.com": "openai",
"oloadcdn.net": "openload",
"openload.co": "openload",
"openstat.net": "openstat",
@@ -24367,10 +24356,6 @@
"spoteffects.net": "spoteffect",
"scdn.co": "spotify",
"spotify.com": "spotify",
"pscdn.co": "spotify",
"spotifycdn.com": "spotify",
"spotifycdn.net": "spotify",
"spotilocal.com": "spotify",
"embed.spotify.com": "spotify_embed",
"spotscenered.info": "spotscenered.info",
"spotx.tv": "spotxchange",
@@ -24690,8 +24675,6 @@
"t.co": "twitter",
"twimg.com": "twitter",
"twitter.com": "twitter",
"twttr.com": "twitter",
"x.com": "twitter",
"ads-twitter.com": "twitter_ads",
"analytics.twitter.com": "twitter_analytics",
"tellapart.com": "twitter_for_business",

View File

@@ -1,4 +1,5 @@
import whotracksmeWebsites from './whotracksme_web.json';
import trackersDb from './trackers.json';
import { REPOSITORY } from '../constants';
@@ -26,7 +27,7 @@ export const sources = {
* @param trackerId
* @return {string}
*/
const getWhotracksmeUrl = (trackerId) => {
const getWhotracksmeUrl = (trackerId: any) => {
const websiteId = whotracksmeWebsites.websites[trackerId];
if (websiteId) {
// Overrides links to websites.
@@ -42,7 +43,7 @@ const getWhotracksmeUrl = (trackerId) => {
* @param {TrackerData} trackerData tracker data
* @returns {source} source metadata or null if no matching tracker found
*/
export const getSourceData = (trackerData) => {
export const getSourceData = (trackerData: any) => {
if (!trackerData || !trackerData.source) {
return null;
}
@@ -69,7 +70,7 @@ export const getSourceData = (trackerData) => {
* @param {TrackerData} trackerData tracker data
* @returns {number} source number
*/
const convertSource = (sourceStr) => {
const convertSource = (sourceStr: any) => {
if (!sourceStr || sourceStr !== 'AdGuard') {
return sources.WHOTRACKSME;
}
@@ -83,13 +84,12 @@ const convertSource = (sourceStr) => {
* @param {String} domainName domain name to check
* @returns {TrackerData} tracker data or null if no matching tracker found
*/
export const getTrackerData = (domainName) => {
export const getTrackerData = (domainName: any) => {
if (!domainName) {
return null;
}
const parts = domainName.split(/\./g)
.reverse();
const parts = domainName.split(/\./g).reverse();
let hostToCheck = '';
// Check every subdomain

View File

@@ -1,6 +1,6 @@
{
"timeUpdated": "2021-12-19T13:50:00.512Z",
"websites": {
"netflix": "netflix.com"
}
"timeUpdated": "2021-12-19T13:50:00.512Z",
"websites": {
"netflix": "netflix.com"
}
}

View File

@@ -1,7 +0,0 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import twosky from 'MainRoot/.twosky.json';
export const {
languages: LANGUAGES,
base_locale: BASE_LOCALE,
} = twosky[0];

View File

@@ -0,0 +1,5 @@
// eslint-disable-next-line import/no-relative-packages
import twosky from '../../../.twosky.json';
export const LANGUAGES = twosky[0].languages;
export const BASE_LOCALE = twosky[0].base_locale;

View File

@@ -1,22 +0,0 @@
import { useState, useEffect } from 'react';
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(
() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
},
[value, delay],
);
return [debouncedValue, setDebouncedValue];
};
export default useDebounce;

View File

@@ -0,0 +1,19 @@
import { useState, useEffect } from 'react';
const useDebounce = (value: any, delay: any) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return [debouncedValue, setDebouncedValue];
};
export default useDebounce;

View File

@@ -18,7 +18,9 @@ import {
R_IPV4_SUBNET,
R_IPV6_SUBNET,
} from './constants';
import { ip4ToInt, isValidAbsolutePath } from './form';
import { isIpInCidr, parseSubnetMask } from './helpers';
// Validation functions
@@ -28,7 +30,7 @@ import { isIpInCidr, parseSubnetMask } from './helpers';
* @param value {string|number}
* @returns {undefined|string}
*/
export const validateRequiredValue = (value) => {
export const validateRequiredValue = (value: any) => {
const formattedValue = typeof value === 'string' ? value.trim() : value;
if (formattedValue || formattedValue === 0 || (formattedValue && formattedValue.length !== 0)) {
return undefined;
@@ -41,7 +43,7 @@ export const validateRequiredValue = (value) => {
* @param _
* @param allValues
*/
export const validateIpv4RangeEnd = (_, allValues) => {
export const validateIpv4RangeEnd = (_: any, allValues: any) => {
if (!allValues || !allValues.v4 || !allValues.v4.range_end || !allValues.v4.range_start) {
return undefined;
}
@@ -59,7 +61,7 @@ export const validateIpv4RangeEnd = (_, allValues) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateIpv4 = (value) => {
export const validateIpv4 = (value: any) => {
if (value && !R_IPV4.test(value)) {
return 'form_error_ip4_format';
}
@@ -71,7 +73,7 @@ export const validateIpv4 = (value) => {
* @param _
* @param allValues
*/
export const validateNotInRange = (value, allValues) => {
export const validateNotInRange = (value: any, allValues: any) => {
if (!allValues.v4) {
return undefined;
}
@@ -104,7 +106,7 @@ export const validateNotInRange = (value, allValues) => {
* @param _
* @param allValues
*/
export const validateGatewaySubnetMask = (_, allValues) => {
export const validateGatewaySubnetMask = (_: any, allValues: any) => {
if (!allValues || !allValues.v4 || !allValues.v4.subnet_mask || !allValues.v4.gateway_ip) {
return 'gateway_or_subnet_invalid';
}
@@ -123,14 +125,12 @@ export const validateGatewaySubnetMask = (_, allValues) => {
* @param value
* @param allValues
*/
export const validateIpForGatewaySubnetMask = (value, allValues) => {
export const validateIpForGatewaySubnetMask = (value: any, allValues: any) => {
if (!allValues || !allValues.v4 || !value) {
return undefined;
}
const {
gateway_ip, subnet_mask,
} = allValues.v4;
const { gateway_ip, subnet_mask } = allValues.v4;
if ((gateway_ip && validateIpv4(gateway_ip)) || (subnet_mask && validateIpv4(subnet_mask))) {
return undefined;
@@ -149,19 +149,22 @@ export const validateIpForGatewaySubnetMask = (value, allValues) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateClientId = (value) => {
export const validateClientId = (value: any) => {
if (!value) {
return undefined;
}
const formattedValue = value.trim();
if (formattedValue && !(
R_IPV4.test(formattedValue)
|| R_IPV6.test(formattedValue)
|| R_MAC.test(formattedValue)
|| R_CIDR.test(formattedValue)
|| R_CIDR_IPV6.test(formattedValue)
|| R_CLIENT_ID.test(formattedValue)
)) {
if (
formattedValue &&
!(
R_IPV4.test(formattedValue) ||
R_IPV6.test(formattedValue) ||
R_MAC.test(formattedValue) ||
R_CIDR.test(formattedValue) ||
R_CIDR_IPV6.test(formattedValue) ||
R_CLIENT_ID.test(formattedValue)
)
) {
return 'form_error_client_id_format';
}
return undefined;
@@ -171,7 +174,7 @@ export const validateClientId = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateConfigClientId = (value) => {
export const validateConfigClientId = (value: any) => {
if (!value) {
return undefined;
}
@@ -186,7 +189,7 @@ export const validateConfigClientId = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateServerName = (value) => {
export const validateServerName = (value: any) => {
if (!value) {
return undefined;
}
@@ -201,7 +204,7 @@ export const validateServerName = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateIpv6 = (value) => {
export const validateIpv6 = (value: any) => {
if (value && !R_IPV6.test(value)) {
return 'form_error_ip6_format';
}
@@ -212,7 +215,7 @@ export const validateIpv6 = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateIp = (value) => {
export const validateIp = (value: any) => {
if (value && !R_IPV4.test(value) && !R_IPV6.test(value)) {
return 'form_error_ip_format';
}
@@ -223,7 +226,7 @@ export const validateIp = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateMac = (value) => {
export const validateMac = (value: any) => {
if (value && !R_MAC.test(value)) {
return 'form_error_mac_format';
}
@@ -234,7 +237,7 @@ export const validateMac = (value) => {
* @param value {number}
* @returns {undefined|string}
*/
export const validatePort = (value) => {
export const validatePort = (value: any) => {
if ((value || value === 0) && (value < STANDARD_WEB_PORT || value > MAX_PORT)) {
return 'form_error_port_range';
}
@@ -245,7 +248,7 @@ export const validatePort = (value) => {
* @param value {number}
* @returns {undefined|string}
*/
export const validateInstallPort = (value) => {
export const validateInstallPort = (value: any) => {
if (value < 1 || value > MAX_PORT) {
return 'form_error_port';
}
@@ -256,7 +259,7 @@ export const validateInstallPort = (value) => {
* @param value {number}
* @returns {undefined|string}
*/
export const validatePortTLS = (value) => {
export const validatePortTLS = (value: any) => {
if (value === 0) {
return undefined;
}
@@ -276,7 +279,7 @@ export const validatePortQuic = validatePortTLS;
* @param value {number}
* @returns {undefined|string}
*/
export const validateIsSafePort = (value) => {
export const validateIsSafePort = (value: any) => {
if (UNSAFE_PORTS.includes(value)) {
return 'form_error_port_unsafe';
}
@@ -287,7 +290,7 @@ export const validateIsSafePort = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateDomain = (value) => {
export const validateDomain = (value: any) => {
if (value && !R_HOST.test(value)) {
return 'form_error_domain_format';
}
@@ -298,8 +301,8 @@ export const validateDomain = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validateAnswer = (value) => {
if (value && (!R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value))) {
export const validateAnswer = (value: any) => {
if (value && !R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value)) {
return 'form_error_answer_format';
}
return undefined;
@@ -309,7 +312,7 @@ export const validateAnswer = (value) => {
* @param value {string}
* @returns {undefined|string}
*/
export const validatePath = (value) => {
export const validatePath = (value: any) => {
if (value && !isValidAbsolutePath(value) && !R_URL_REQUIRES_PROTOCOL.test(value)) {
return 'form_error_url_or_path_format';
}
@@ -320,7 +323,7 @@ export const validatePath = (value) => {
* @param cidr {string}
* @returns {Function}
*/
export const validateIpv4InCidr = (valueIp, allValues) => {
export const validateIpv4InCidr = (valueIp: any, allValues: any) => {
if (!isIpInCidr(valueIp, allValues.cidr)) {
return i18next.t('form_error_subnet', { ip: valueIp, cidr: allValues.cidr });
}
@@ -331,7 +334,7 @@ export const validateIpv4InCidr = (valueIp, allValues) => {
* @param value {string}
* @returns {number}
*/
const utf8StringLength = (value) => {
const utf8StringLength = (value: any) => {
const encoder = new TextEncoder();
const view = encoder.encode(value);
@@ -342,7 +345,7 @@ const utf8StringLength = (value) => {
* @param value {string}
* @returns {Function}
*/
export const validatePasswordLength = (value) => {
export const validatePasswordLength = (value: any) => {
if (value) {
const length = utf8StringLength(value);
if (length < MIN_PASSWORD_LENGTH || length > MAX_PASSWORD_LENGTH) {
@@ -361,7 +364,7 @@ export const validatePasswordLength = (value) => {
* @param value {string}
* @returns {Function}
*/
export const validateIpGateway = (value, allValues) => {
export const validateIpGateway = (value: any, allValues: any) => {
if (value === allValues.gatewayIp) {
return i18next.t('form_error_gateway_ip');
}
@@ -372,7 +375,7 @@ export const validateIpGateway = (value, allValues) => {
* @param value {string}
* @returns {Function}
*/
export const validateIPv4Subnet = (value) => {
export const validateIPv4Subnet = (value: any) => {
if (!R_IPV4_SUBNET.test(value)) {
return i18next.t('rate_limit_subnet_len_ipv4_error');
}
@@ -383,7 +386,7 @@ export const validateIPv4Subnet = (value) => {
* @param value {string}
* @returns {Function}
*/
export const validateIPv6Subnet = (value) => {
export const validateIPv6Subnet = (value: any) => {
if (!R_IPV6_SUBNET.test(value)) {
return i18next.t('rate_limit_subnet_len_ipv6_error');
}
@@ -395,7 +398,7 @@ export const validateIPv6Subnet = (value) => {
* @param value
* @param allValues
*/
export const validatePlainDns = (value, allValues) => {
export const validatePlainDns = (value: any, allValues: any) => {
const { enabled } = allValues;
if (!enabled && !value) {

View File

@@ -6,7 +6,7 @@
* @param right {string} - right version
* @return {boolean} true if versions are equal
*/
export const areEqualVersions = (left, right) => {
export const areEqualVersions = (left: any, right: any) => {
if (!left || !right) {
return false;
}