{!disabled && touched && error
- &&
{error}}
-
+ &&
{error}}
+ >
);
};
@@ -115,7 +118,7 @@ renderGroupField.propTypes = {
removeField: PropTypes.func,
meta: PropTypes.shape({
touched: PropTypes.bool,
- error: PropTypes.object,
+ error: PropTypes.string,
}).isRequired,
normalizeOnBlur: PropTypes.func,
};
@@ -137,7 +140,8 @@ export const renderRadioField = ({
{!disabled
&& touched
- && (error &&
{error})}
+ && error
+ &&
{error}}
;
renderRadioField.propTypes = {
@@ -147,11 +151,11 @@ renderRadioField.propTypes = {
disabled: PropTypes.bool,
meta: PropTypes.shape({
touched: PropTypes.bool,
- error: PropTypes.object,
+ error: PropTypes.string,
}).isRequired,
};
-export const renderSelectField = ({
+export const renderCheckboxField = ({
input,
placeholder,
subtitle,
@@ -163,7 +167,8 @@ export const renderSelectField = ({
}) => <>
{!disabled
&& touched
- && error &&
{error}}
+ && error
+ &&
{error}}
>;
-renderSelectField.propTypes = {
+renderCheckboxField.propTypes = {
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
subtitle: PropTypes.string,
@@ -191,7 +197,37 @@ renderSelectField.propTypes = {
checked: PropTypes.bool,
meta: PropTypes.shape({
touched: PropTypes.bool,
- error: PropTypes.object,
+ error: PropTypes.string,
+ }).isRequired,
+};
+
+export const renderSelectField = ({
+ input,
+ meta: { touched, error },
+ children,
+ label,
+}) => {
+ const showWarning = touched && error;
+ const selectClass = classNames('form-control custom-select', {
+ 'select--no-warning': !showWarning,
+ });
+
+ return <>
+ {label &&
}
+
+ {showWarning
+ &&
{error}}
+ >;
+};
+
+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,
};
@@ -218,7 +254,7 @@ export const renderServiceField = ({
{!disabled && touched && error
- &&
{error}}
+ &&
{error}}
;
renderServiceField.propTypes = {
@@ -229,10 +265,12 @@ renderServiceField.propTypes = {
icon: PropTypes.string,
meta: PropTypes.shape({
touched: PropTypes.bool,
- error: PropTypes.object,
+ error: PropTypes.string,
}).isRequired,
};
+export const getLastIpv4Octet = (ipv4) => parseInt(ipv4.slice(ipv4.lastIndexOf('.') + 1), 10);
+
/**
* @param value {string}
* @returns {*|number}
diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js
index 6003d0b8..baae34f5 100644
--- a/client/src/helpers/helpers.js
+++ b/client/src/helpers/helpers.js
@@ -19,6 +19,7 @@ import {
DEFAULT_LANGUAGE,
DEFAULT_TIME_FORMAT,
DETAILED_DATE_FORMAT_OPTIONS,
+ DHCP_VALUES_PLACEHOLDERS,
FILTERED,
FILTERED_STATUS,
IP_MATCH_LIST_STATUS,
@@ -190,7 +191,7 @@ export const captitalizeWords = (text) => text.split(/[ -_]/g)
export const getInterfaceIp = (option) => {
const onlyIPv6 = option.ip_addresses.every((ip) => ip.includes(':'));
- let interfaceIP = option.ip_addresses[0];
+ let [interfaceIP] = option.ip_addresses;
if (!onlyIPv6) {
option.ip_addresses.forEach((ip) => {
@@ -203,16 +204,9 @@ export const getInterfaceIp = (option) => {
return interfaceIP;
};
-export const getIpList = (interfaces) => {
- let list = [];
-
- Object.keys(interfaces)
- .forEach((item) => {
- list = [...list, ...interfaces[item].ip_addresses];
- });
-
- return list.sort();
-};
+export const getIpList = (interfaces) => Object.values(interfaces)
+ .reduce((acc, curr) => acc.concat(curr.ip_addresses), [])
+ .sort();
export const getDnsAddress = (ip, port = '') => {
const isStandardDnsPort = port === STANDARD_DNS_PORT;
@@ -668,11 +662,12 @@ export const getLogsUrlParams = (search, response_status) => `?${queryString.str
response_status,
})}`;
-export const processContent = (content) => (Array.isArray(content)
- ? content.filter(([, value]) => value).reduce((acc, val) => acc.concat(val), [])
- : content
-);
-
+export const processContent = (
+ content,
+) => (Array.isArray(content)
+ ? content.filter(([, value]) => value)
+ .reduce((acc, val) => acc.concat(val), [])
+ : content);
/**
* @param object {object}
* @param sortKey {string}
@@ -746,3 +741,65 @@ export const sortIp = (a, b) => {
return 0;
}
};
+
+/**
+ * @param ip {string}
+ * @param gateway_ip {string}
+ * @returns {{range_end: string, subnet_mask: string, range_start: string,
+ * lease_duration: string, gateway_ip: string}}
+ */
+export const calculateDhcpPlaceholdersIpv4 = (ip, gateway_ip) => {
+ const LAST_OCTET_IDX = 3;
+ const LAST_OCTET_RANGE_START = 100;
+ const LAST_OCTET_RANGE_END = 200;
+
+ const addr = ipaddr.parse(ip);
+ addr.octets[LAST_OCTET_IDX] = LAST_OCTET_RANGE_START;
+ const range_start = addr.toString();
+
+ addr.octets[LAST_OCTET_IDX] = LAST_OCTET_RANGE_END;
+ const range_end = addr.toString();
+
+ const {
+ subnet_mask,
+ lease_duration,
+ } = DHCP_VALUES_PLACEHOLDERS.ipv4;
+
+ return {
+ gateway_ip: gateway_ip || ip,
+ subnet_mask,
+ range_start,
+ range_end,
+ lease_duration,
+ };
+};
+
+export const calculateDhcpPlaceholdersIpv6 = () => {
+ const {
+ range_start,
+ range_end,
+ lease_duration,
+ } = DHCP_VALUES_PLACEHOLDERS.ipv6;
+
+ return {
+ range_start,
+ range_end,
+ lease_duration,
+ };
+};
+
+/**
+ * Add ip_addresses property - concatenated ipv4_addresses and ipv6_addresses for every interface
+ * @param interfaces
+ * @param interfaces.ipv4_addresses {string[]}
+ * @param interfaces.ipv6_addresses {string[]}
+ * @returns interfaces Interfaces enriched with ip_addresses property
+ */
+export const enrichWithConcatenatedIpAddresses = (interfaces) => Object.entries(interfaces)
+ .reduce((acc, [k, v]) => {
+ const ipv4_addresses = v.ipv4_addresses ?? [];
+ const ipv6_addresses = v.ipv6_addresses ?? [];
+
+ acc[k].ip_addresses = ipv4_addresses.concat(ipv6_addresses);
+ return acc;
+ }, interfaces);
diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js
index 947cc96f..45055154 100644
--- a/client/src/helpers/validators.js
+++ b/client/src/helpers/validators.js
@@ -1,7 +1,6 @@
-import { Trans } from 'react-i18next';
-import React from 'react';
import i18next from 'i18next';
import {
+ MAX_PORT,
R_CIDR,
R_CIDR_IPV6,
R_HOST,
@@ -9,10 +8,10 @@ import {
R_IPV6,
R_MAC,
R_URL_REQUIRES_PROTOCOL,
+ STANDARD_WEB_PORT,
UNSAFE_PORTS,
} from './constants';
-import { isValidAbsolutePath } from './form';
-
+import { getLastIpv4Octet, isValidAbsolutePath } from './form';
// Validation functions
// https://redux-form.com/8.3.0/examples/fieldlevelvalidation/
@@ -26,7 +25,7 @@ export const validateRequiredValue = (value) => {
if (formattedValue || formattedValue === 0 || (formattedValue && formattedValue.length !== 0)) {
return undefined;
}
- return
form_error_required;
+ return 'form_error_required';
};
/**
@@ -35,11 +34,28 @@ export const validateRequiredValue = (value) => {
*/
export const getMaxValueValidator = (maximum) => (value) => {
if (value && value > maximum) {
- i18next.t('value_not_larger_than', { maximum });
+ return i18next.t('value_not_larger_than', { maximum });
}
return undefined;
};
+/**
+ * @param value {string}
+ * @returns {undefined|string}
+ */
+export const validateIpv4RangeEnd = (_, allValues) => {
+ if (!allValues || !allValues.v4 || !allValues.v4.range_end || !allValues.v4.range_start) {
+ return undefined;
+ }
+
+ const { range_end, range_start } = allValues.v4;
+
+ if (getLastIpv4Octet(range_end) <= getLastIpv4Octet(range_start)) {
+ return 'range_end_error';
+ }
+
+ return undefined;
+};
/**
* @param value {string}
@@ -47,7 +63,7 @@ export const getMaxValueValidator = (maximum) => (value) => {
*/
export const validateIpv4 = (value) => {
if (value && !R_IPV4.test(value)) {
- return
form_error_ip4_format;
+ return 'form_error_ip4_format';
}
return undefined;
};
@@ -63,12 +79,12 @@ export const validateClientId = (value) => {
const formattedValue = value ? value.trim() : value;
if (formattedValue && !(
R_IPV4.test(formattedValue)
- || R_IPV6.test(formattedValue)
- || R_MAC.test(formattedValue)
- || R_CIDR.test(formattedValue)
- || R_CIDR_IPV6.test(formattedValue)
+ || R_IPV6.test(formattedValue)
+ || R_MAC.test(formattedValue)
+ || R_CIDR.test(formattedValue)
+ || R_CIDR_IPV6.test(formattedValue)
)) {
- return
form_error_client_id_format;
+ return 'form_error_client_id_format';
}
return undefined;
};
@@ -79,7 +95,7 @@ export const validateClientId = (value) => {
*/
export const validateIpv6 = (value) => {
if (value && !R_IPV6.test(value)) {
- return
form_error_ip6_format;
+ return 'form_error_ip6_format';
}
return undefined;
};
@@ -90,7 +106,7 @@ export const validateIpv6 = (value) => {
*/
export const validateIp = (value) => {
if (value && !R_IPV4.test(value) && !R_IPV6.test(value)) {
- return
form_error_ip_format;
+ return 'form_error_ip_format';
}
return undefined;
};
@@ -101,76 +117,76 @@ export const validateIp = (value) => {
*/
export const validateMac = (value) => {
if (value && !R_MAC.test(value)) {
- return
form_error_mac_format;
+ return 'form_error_mac_format';
}
return undefined;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {undefined|string}
*/
export const validateIsPositiveValue = (value) => {
if ((value || value === 0) && value <= 0) {
- return
form_error_positive;
+ return 'form_error_positive';
}
return undefined;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {boolean|*}
*/
export const validateBiggerOrEqualZeroValue = (value) => {
if (value < 0) {
- return
form_error_negative;
+ return 'form_error_negative';
}
return false;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {undefined|string}
*/
export const validatePort = (value) => {
- if ((value || value === 0) && (value < 80 || value > 65535)) {
- return
form_error_port_range;
+ if ((value || value === 0) && (value < STANDARD_WEB_PORT || value > MAX_PORT)) {
+ return 'form_error_port_range';
}
return undefined;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {undefined|string}
*/
export const validateInstallPort = (value) => {
- if (value < 1 || value > 65535) {
- return
form_error_port;
+ if (value < 1 || value > MAX_PORT) {
+ return 'form_error_port';
}
return undefined;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {undefined|string}
*/
export const validatePortTLS = (value) => {
if (value === 0) {
return undefined;
}
- if (value && (value < 80 || value > 65535)) {
- return
form_error_port_range;
+ if (value && (value < STANDARD_WEB_PORT || value > MAX_PORT)) {
+ return 'form_error_port_range';
}
return undefined;
};
/**
- * @param value {string}
+ * @param value {number}
* @returns {undefined|string}
*/
export const validateIsSafePort = (value) => {
if (UNSAFE_PORTS.includes(value)) {
- return
form_error_port_unsafe;
+ return 'form_error_port_unsafe';
}
return undefined;
};
@@ -181,7 +197,7 @@ export const validateIsSafePort = (value) => {
*/
export const validateDomain = (value) => {
if (value && !R_HOST.test(value)) {
- return
form_error_domain_format;
+ return 'form_error_domain_format';
}
return undefined;
};
@@ -192,7 +208,7 @@ export const validateDomain = (value) => {
*/
export const validateAnswer = (value) => {
if (value && (!R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value))) {
- return
form_error_answer_format;
+ return 'form_error_answer_format';
}
return undefined;
};
@@ -203,7 +219,7 @@ export const validateAnswer = (value) => {
*/
export const validatePath = (value) => {
if (value && !isValidAbsolutePath(value) && !R_URL_REQUIRES_PROTOCOL.test(value)) {
- return
form_error_url_or_path_format;
+ return 'form_error_url_or_path_format';
}
return undefined;
};
diff --git a/client/src/i18n.js b/client/src/i18n.js
index ee776147..b8bfffc4 100644
--- a/client/src/i18n.js
+++ b/client/src/i18n.js
@@ -30,9 +30,11 @@ import sl from './__locales/sl.json';
import tr from './__locales/tr.json';
import srCS from './__locales/sr-cs.json';
import hr from './__locales/hr.json';
+import hu from './__locales/hu.json';
import fa from './__locales/fa.json';
import th from './__locales/th.json';
import ro from './__locales/ro.json';
+import siLk from './__locales/si-lk.json';
import { setHtmlLangAttr } from './helpers/helpers';
const resources = {
@@ -114,6 +116,9 @@ const resources = {
hr: {
translation: hr,
},
+ hu: {
+ translation: hu,
+ },
fa: {
translation: fa,
},
@@ -123,6 +128,9 @@ const resources = {
ro: {
translation: ro,
},
+ 'si-lk': {
+ translation: siLk,
+ },
};
const availableLanguages = Object.keys(LANGUAGES);
diff --git a/client/src/install/Setup/AddressList.js b/client/src/install/Setup/AddressList.js
index aeeed246..90bccfd2 100644
--- a/client/src/install/Setup/AddressList.js
+++ b/client/src/install/Setup/AddressList.js
@@ -4,50 +4,40 @@ import PropTypes from 'prop-types';
import { getIpList, getDnsAddress, getWebAddress } from '../../helpers/helpers';
import { ALL_INTERFACES_IP } from '../../helpers/constants';
-const AddressList = (props) => {
- let webAddress = getWebAddress(props.address, props.port);
- let dnsAddress = getDnsAddress(props.address, props.port);
+const renderItem = ({
+ ip, port, isDns,
+}) => {
+ const webAddress = getWebAddress(ip, port);
+ const dnsAddress = getDnsAddress(ip, port);
- if (props.address === ALL_INTERFACES_IP) {
- return getIpList(props.interfaces).map((ip) => {
- webAddress = getWebAddress(ip, props.port);
- dnsAddress = getDnsAddress(ip, props.port);
-
- if (props.isDns) {
- return (
-
-
- {dnsAddress}
-
-
- );
- }
-
- return (
-
-
- {webAddress}
-
-
- );
- });
+ return
{isDns
+ ? {dnsAddress}
+ : {webAddress}
}
-
- if (props.isDns) {
- return (
-
- {dnsAddress}
-
- );
- }
-
- return (
-
- {webAddress}
-
- );
+ ;
};
+const AddressList = ({
+ address,
+ interfaces,
+ port,
+ isDns,
+}) =>
{
+ address === ALL_INTERFACES_IP
+ ? getIpList(interfaces)
+ .map((ip) => renderItem({
+ ip,
+ port,
+ isDns,
+ }))
+ : renderItem({
+ ip: address,
+ port,
+ isDns,
+ })
+}
+
;
+
AddressList.propTypes = {
interfaces: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
@@ -58,4 +48,10 @@ AddressList.propTypes = {
isDns: PropTypes.bool,
};
+renderItem.propTypes = {
+ ip: PropTypes.string.isRequired,
+ port: PropTypes.string.isRequired,
+ isDns: PropTypes.bool.isRequired,
+};
+
export default AddressList;
diff --git a/client/src/install/Setup/Devices.js b/client/src/install/Setup/Devices.js
index 59f25dea..c6d0af90 100644
--- a/client/src/install/Setup/Devices.js
+++ b/client/src/install/Setup/Devices.js
@@ -26,7 +26,7 @@ let Devices = (props) => (
interfaces={props.interfaces}
address={props.dnsIp}
port={props.dnsPort}
- isDns={true}
+ isDns
/>