Merge pull request #325 from Telecominfraproject/feature/NETEXP-2883-ap-details-redesign

NOJIRA: Move advanced settings to its own component
This commit is contained in:
Sean Macfarlane
2021-11-03 14:39:57 -04:00
committed by GitHub
4 changed files with 590 additions and 540 deletions

View File

@@ -0,0 +1,507 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { Form, Select as AntdSelect } from 'antd';
import { Input, Select } from 'components/WithRoles';
import _ from 'lodash';
import DisabledText from 'components/DisabledText';
import Tooltip from 'components/Tooltip';
import { sortRadioTypes } from 'utils/sortRadioTypes';
import { USER_FRIENDLY_RATES, USER_FRIENDLY_BANDWIDTHS } from '../../constants';
import styles from '../../../../index.module.scss';
const { Option } = AntdSelect;
const Advanced = ({ extraFields, childProfiles, data, radioTypes, form, Item }) => {
const { details: { advancedRadioMap = {}, radioMap = {} } = {} } = data;
const defaultOptions = (
<Select className={styles.Field}>
<Option value="enabled">Enabled</Option>
<Option value="disabled">Disabled</Option>
</Select>
);
const defaultOptionsBoolean = (
<Select className={styles.Field}>
<Option value="true">Enabled</Option>
<Option value="false">Disabled</Option>
</Select>
);
useEffect(() => {
if (data?.details) {
const currentRadios = Object.keys(advancedRadioMap);
const formData = {
advancedRadioMap: {},
radioMap: {},
};
currentRadios.forEach(radio => {
formData.advancedRadioMap[radio] = {
radioAdminState: advancedRadioMap[radio]?.radioAdminState || 'disabled',
deauthAttackDetection: advancedRadioMap[radio]?.deauthAttackDetection ? 'true' : 'false',
uapsdState: advancedRadioMap[radio]?.uapsdState || 'disabled',
managementRate: {
value: advancedRadioMap[radio]?.managementRate?.value || 'rate1mbps',
},
multicastRate: {
value: advancedRadioMap[radio]?.multicastRate?.value || 'rate6mbps',
},
bestApSettings: {
value: {
dropInSnrPercentage:
advancedRadioMap[radio]?.bestApSettings?.value?.dropInSnrPercentage || 0,
minLoadFactor: advancedRadioMap[radio]?.bestApSettings?.value?.minLoadFactor || 0,
},
},
};
formData.radioMap[radio] = {
rxCellSizeDb: {
value: radioMap[radio]?.rxCellSizeDb?.value || 0,
},
probeResponseThresholdDb: {
value: radioMap[radio]?.probeResponseThresholdDb?.value || 0,
},
clientDisconnectThresholdDb: {
value: radioMap[radio]?.clientDisconnectThresholdDb?.value || 0,
},
eirpTxPower: {
value: radioMap[radio]?.eirpTxPower?.value || 0,
},
};
});
form.setFieldsValue({ ...formData });
}
}, [data]);
useEffect(() => {
if (data?.details) {
const currentRadios = Object.keys(advancedRadioMap);
const formData = {
radioMap: {},
};
currentRadios.forEach(radio => {
const isEnabled =
childProfiles.rf?.[0]?.details?.rfConfigMap?.[radio]?.autoChannelSelection;
formData.radioMap[radio] = {
[isEnabled ? 'channelNumber' : 'manualChannelNumber']: isEnabled
? radioMap[radio]?.channelNumber
: radioMap[radio]?.manualChannelNumber,
[isEnabled ? 'backupChannelNumber' : 'manualBackupChannelNumber']: isEnabled
? radioMap[radio]?.backupChannelNumber
: radioMap[radio]?.manualBackupChannelNumber,
};
});
form.setFieldsValue({ ...formData });
}
}, [data]);
const renderItem = (label, obj = {}, dataIndex, renderInput, options = {}) => {
if (extraFields.some(field => field.label === label)) {
return null;
}
return (
<Item
label={label}
colon={dataIndex !== 'radioType'}
key={label}
hidden={options.hidden ?? false}
>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(obj)).map(i =>
renderInput ? (
renderInput(dataIndex, i, label, options)
) : (
<span key={i} className={styles.spanStyle}>
{dataIndex === 'radioType'
? radioTypes?.[obj[i]?.[dataIndex]]
: obj[i]?.[dataIndex]}
</span>
)
)}
</div>
</Item>
);
};
const renderConditionalItem = (label, obj = {}, dataIndex, dependency) => (
<Item label={label} key={label}>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(obj)).map(key => {
const isEnabled = childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dependency];
if (isEnabled) {
return (
<DisabledText
key={key}
value={
USER_FRIENDLY_RATES[obj[key]?.[dataIndex]?.value] ||
obj[key]?.[dataIndex]?.value ||
'N/A'
}
title={`The ${radioTypes[key]} radio has "${_.startCase(
dependency
)}" enabled in the RF Profile`}
text="Auto"
/>
);
}
return (
<DisabledText
key={key}
value={
USER_FRIENDLY_RATES[
childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dataIndex]
] || childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dataIndex || 'N/A']
}
title={`The ${radioTypes[key]} radio has "${_.startCase(
dependency
)}" disabled in the RF Profile`}
text="Profile"
/>
);
})}
</div>
</Item>
);
const renderInputItem = (dataIndex, key, label, options = {}) => (
<Item
key={options.mapName + key + dataIndex}
name={[options.mapName, key, ...dataIndex]}
rules={[
{ required: true, message: options.error },
({ getFieldValue }) => ({
validator(_rule, value) {
if (
!value ||
(getFieldValue([options.mapName, key, ...dataIndex]) <= options.max &&
getFieldValue([options.mapName, key, ...dataIndex]) >= options.min)
) {
return Promise.resolve();
}
return Promise.reject(new Error(options.error));
},
}),
]}
>
<Input
className={styles.Field}
placeholder={`Enter ${label} for ${radioTypes[key]}`}
type="number"
min={options.min}
max={options.max}
addonAfter={options?.addOnText ? options?.addOnText : ''}
/>
</Item>
);
const renderOptionItem = (dataIndex, key, label, options = {}) => {
return (
<Item
key={key + dataIndex}
name={[options.mapName, key, ...dataIndex]}
rules={[
{
required: true,
message: `Enter ${label} for ${radioTypes[key]}`,
},
]}
>
{typeof options.dropdown === 'function' ? options.dropdown(key) : options.dropdown}
</Item>
);
};
const renderChannelItem = label => {
return (
<Item label={label} colon={false}>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(radioMap)).map(key => {
const isEnabled = childProfiles.rf?.[0]?.details?.rfConfigMap[key].autoChannelSelection;
let channel;
if (label === 'Active Channel') {
channel = isEnabled
? {
dataIndex: 'channelNumber',
addOnText: (
<Tooltip
text="Auto"
title={`The ${radioTypes[key]} radio has "Auto Channel Selection" enabled in the RF Profile`}
/>
),
}
: {
dataIndex: 'manualChannelNumber',
addOnText: 'Manual',
dependencies: ['radioMap', key, 'manualBackupChannelNumber'],
};
}
if (label === 'Backup Channel') {
channel = isEnabled
? {
dataIndex: 'backupChannelNumber',
addOnText: (
<Tooltip
text="Auto"
title={`The ${radioTypes[key]} radio has "Auto Channel Selection" enabled in the RF Profile`}
/>
),
}
: {
dataIndex: 'manualBackupChannelNumber',
addOnText: 'Manual',
dependencies: ['radioMap', key, 'manualChannelNumber'],
};
}
const powerLevels = data?.details?.radioMap?.[key]?.allowedChannelsPowerLevels ?? [];
const allowedChannels = powerLevels
.filter(item => {
if (channel.dataIndex === 'manualBackupChannelNumber') {
return !item.dfs;
}
return item;
})
.map(item => item?.channelNumber)
.sort((a, b) => a - b);
return (
<Item
key={`radioMap${key}${channel.dataIndex}`}
name={['radioMap', key, channel.dataIndex]}
dependencies={[channel.dependencies]}
rules={[
{ required: true, message: `Allowed Channels: ${allowedChannels.join(', ')}` },
({ getFieldValue }) => ({
validator(_rule, value) {
if (!isEnabled) {
if (
parseInt(getFieldValue(['radioMap', key, 'manualChannelNumber']), 10) ===
parseInt(
getFieldValue(['radioMap', key, 'manualBackupChannelNumber']),
10
)
) {
return Promise.reject(
new Error('Active and backup channels must be different')
);
}
const channelNumber = parseInt(
getFieldValue(['radioMap', key, channel.dataIndex]),
10
);
if (!value || allowedChannels.includes(channelNumber)) {
return Promise.resolve();
}
return Promise.reject(
new Error(`Allowed Channels: ${allowedChannels.join(', ')}`)
);
}
return Promise.resolve();
},
}),
]}
>
<Input
className={styles.Field}
placeholder={`Enter ${label} for ${radioTypes[key]}`}
type="number"
min={Math.min(...allowedChannels)}
max={Math.max(...allowedChannels)}
addonAfter={channel.addOnText}
disabled={isEnabled}
/>
</Item>
);
})}
</div>
</Item>
);
};
const renderBandwidthLabels = () => (
<Item label="Channel Bandwidth">
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(radioMap)).map(radio => (
<DisabledText
key={radio}
value={
USER_FRIENDLY_BANDWIDTHS[
childProfiles?.rf?.[0]?.details?.rfConfigMap?.[radio].channelBandwidth
] ?? 'N/A'
}
showTooltip={false}
/>
))}
</div>
</Item>
);
return (
<>
{renderItem(' ', data?.details?.radioMap, 'radioType')}
<p>Radio Specific Parameters:</p>
{renderBandwidthLabels()}
{renderItem('Enable Radio', advancedRadioMap, ['radioAdminState'], renderOptionItem, {
dropdown: defaultOptions,
mapName: 'advancedRadioMap',
})}
{renderItem(
'Deauth Attack Detection',
advancedRadioMap,
['deauthAttackDetection'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: defaultOptionsBoolean,
}
)}
{renderItem('UAPSD', advancedRadioMap, ['uapsdState'], renderOptionItem, {
mapName: 'advancedRadioMap',
dropdown: defaultOptions,
})}
{renderChannelItem('Active Channel')}
{renderChannelItem('Backup Channel')}
{extraFields.map(field =>
renderConditionalItem(field.label, field.obj, field.dataIndex, field.dependencies)
)}
{renderItem(
'Management Rate (Mbps)',
advancedRadioMap,
['managementRate', 'value'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: key => (
<Select className={styles.Field}>
{key === 'is2dot4GHz' && (
<>
<Option value="rate1mbps">1</Option>
<Option value="rate2mbps">2</Option>
<Option value="rate5dot5mbps">5.5</Option>
</>
)}
<Option value="rate6mbps">6</Option>
<Option value="rate9mbps">9</Option>
{key === 'is2dot4GHz' && <Option value="rate11mbps">11</Option>}
<Option value="rate12mbps">12</Option>
<Option value="rate18mbps">18</Option>
<Option value="rate24mbps">24</Option>
</Select>
),
}
)}
{renderItem(
'Multicast Rate (Mbps)',
advancedRadioMap,
['multicastRate', 'value'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: (
<Select className={styles.Field}>
<Option value="rate6mbps">6</Option>
<Option value="rate9mbps">9</Option>
<Option value="rate12mbps">12</Option>
<Option value="rate18mbps">18</Option>
<Option value="rate24mbps">24</Option>
<Option value="rate36mbps">36</Option>
<Option value="rate48mbps">48</Option>
<Option value="rate54mbps">54</Option>
</Select>
),
}
)}
{renderItem(
'Probe Response Threshold',
radioMap,
['probeResponseThresholdDb', 'value'],
renderInputItem,
{
min: -100,
max: -40,
error: '-100 - -40 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
}
)}
{renderItem(
'Client Disconnect Threshold',
radioMap,
['clientDisconnectThresholdDb', 'value'],
renderInputItem,
{
min: -100,
max: 0,
error: '-100 - 0 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
}
)}
{renderItem('EIRP Tx Power', radioMap, ['eirpTxPower', 'value'], renderInputItem, {
min: 1,
max: 32,
error: '1 - 32 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
})}
{renderItem(
'SNR',
advancedRadioMap,
['bestApSettings', 'value', 'dropInSnrPercentage'],
renderInputItem,
{
min: 0,
max: 100,
error: '0 - 100%',
addOnText: '% Drop',
mapName: 'advancedRadioMap',
hidden: true,
}
)}
{renderItem(
'Min Load',
advancedRadioMap,
['bestApSettings', 'value', 'minLoadFactor'],
renderInputItem,
{
min: 0,
max: 100,
error: '0 - 100%',
addOnText: '%',
mapName: 'advancedRadioMap',
hidden: true,
}
)}
</>
);
};
Advanced.propTypes = {
extraFields: PropTypes.instanceOf(Array),
data: PropTypes.instanceOf(Object),
childProfiles: PropTypes.instanceOf(Object),
radioTypes: PropTypes.instanceOf(Object),
form: PropTypes.instanceOf(Object),
Item: PropTypes.node,
};
Advanced.defaultProps = {
extraFields: [],
data: {},
childProfiles: {},
radioTypes: {},
form: null,
Item: Form.Item,
};
export default Advanced;

View File

@@ -11,16 +11,14 @@ import {
Empty,
Typography,
} from 'antd';
import _ from 'lodash';
import { Card } from 'components/Skeleton';
import { Input, Select, RoleProtectedBtn } from 'components/WithRoles';
import _ from 'lodash';
import ThemeContext from 'contexts/ThemeContext';
import DisabledText from 'components/DisabledText';
import Tooltip from 'components/Tooltip';
import { sortRadioTypes } from 'utils/sortRadioTypes';
import { pageLayout } from 'utils/form';
import { USER_FRIENDLY_RATES, USER_FRIENDLY_BANDWIDTHS } from './constants';
import Advanced from './components/Advanced';
import styles from '../../index.module.scss';
@@ -112,80 +110,8 @@ const General = ({
longitude,
serial,
lastModifiedTimestamp,
details: { advancedRadioMap = {}, radioMap = {} } = {},
} = data;
useEffect(() => {
if (data?.details) {
const currentRadios = Object.keys(advancedRadioMap);
const formData = {
advancedRadioMap: {},
radioMap: {},
};
currentRadios.forEach(radio => {
formData.advancedRadioMap[radio] = {
radioAdminState: advancedRadioMap[radio]?.radioAdminState || 'disabled',
deauthAttackDetection: advancedRadioMap[radio]?.deauthAttackDetection ? 'true' : 'false',
uapsdState: advancedRadioMap[radio]?.uapsdState || 'disabled',
managementRate: {
value: advancedRadioMap[radio]?.managementRate?.value || 'rate1mbps',
},
multicastRate: {
value: advancedRadioMap[radio]?.multicastRate?.value || 'rate6mbps',
},
bestApSettings: {
value: {
dropInSnrPercentage:
advancedRadioMap[radio]?.bestApSettings?.value?.dropInSnrPercentage || 0,
minLoadFactor: advancedRadioMap[radio]?.bestApSettings?.value?.minLoadFactor || 0,
},
},
};
formData.radioMap[radio] = {
rxCellSizeDb: {
value: radioMap[radio]?.rxCellSizeDb?.value || 0,
},
probeResponseThresholdDb: {
value: radioMap[radio]?.probeResponseThresholdDb?.value || 0,
},
clientDisconnectThresholdDb: {
value: radioMap[radio]?.clientDisconnectThresholdDb?.value || 0,
},
eirpTxPower: {
value: radioMap[radio]?.eirpTxPower?.value || 0,
},
};
});
form.setFieldsValue({ ...formData });
}
}, [data]);
useEffect(() => {
if (data?.details) {
const currentRadios = Object.keys(advancedRadioMap);
const formData = {
radioMap: {},
};
currentRadios.forEach(radio => {
const isEnabled =
childProfiles.rf?.[0]?.details?.rfConfigMap?.[radio]?.autoChannelSelection;
formData.radioMap[radio] = {
[isEnabled ? 'channelNumber' : 'manualChannelNumber']: isEnabled
? radioMap[radio]?.channelNumber
: radioMap[radio]?.manualChannelNumber,
[isEnabled ? 'backupChannelNumber' : 'manualBackupChannelNumber']: isEnabled
? radioMap[radio]?.backupChannelNumber
: radioMap[radio]?.manualBackupChannelNumber,
};
});
form.setFieldsValue({ ...formData });
}
}, [selectedProfile]);
const handleOnSave = () => {
form
.validateFields()
@@ -235,264 +161,6 @@ const General = ({
});
};
const defaultOptions = (
<Select className={styles.Field}>
<Option value="enabled">Enabled</Option>
<Option value="disabled">Disabled</Option>
</Select>
);
const defaultOptionsBoolean = (
<Select className={styles.Field}>
<Option value="true">Enabled</Option>
<Option value="false">Disabled</Option>
</Select>
);
const renderItem = (label, obj = {}, dataIndex, renderInput, options = {}) => {
if (extraFields.some(field => field.label === label)) {
return null;
}
return (
<Item
label={label}
colon={dataIndex !== 'radioType'}
key={label}
hidden={options.hidden ?? false}
>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(obj)).map(i =>
renderInput ? (
renderInput(dataIndex, i, label, options)
) : (
<span key={i} className={styles.spanStyle}>
{dataIndex === 'radioType'
? radioTypes?.[obj[i]?.[dataIndex]]
: obj[i]?.[dataIndex]}
</span>
)
)}
</div>
</Item>
);
};
const renderConditionalItem = (label, obj = {}, dataIndex, dependency) => (
<Item label={label} key={label}>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(obj)).map(key => {
const isEnabled = childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dependency];
if (isEnabled) {
return (
<DisabledText
key={key}
value={
USER_FRIENDLY_RATES[obj[key]?.[dataIndex]?.value] ||
obj[key]?.[dataIndex]?.value ||
'N/A'
}
title={`The ${radioTypes[key]} radio has "${_.startCase(
dependency
)}" enabled in the RF Profile`}
text="Auto"
/>
);
}
return (
<DisabledText
key={key}
value={
USER_FRIENDLY_RATES[
childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dataIndex]
] || childProfiles.rf?.[0]?.details?.rfConfigMap?.[key]?.[dataIndex || 'N/A']
}
title={`The ${radioTypes[key]} radio has "${_.startCase(
dependency
)}" disabled in the RF Profile`}
text="Profile"
/>
);
})}
</div>
</Item>
);
const renderInputItem = (dataIndex, key, label, options = {}) => (
<Item
key={options.mapName + key + dataIndex}
name={[options.mapName, key, ...dataIndex]}
rules={[
{ required: true, message: options.error },
({ getFieldValue }) => ({
validator(_rule, value) {
if (
!value ||
(getFieldValue([options.mapName, key, ...dataIndex]) <= options.max &&
getFieldValue([options.mapName, key, ...dataIndex]) >= options.min)
) {
return Promise.resolve();
}
return Promise.reject(new Error(options.error));
},
}),
]}
>
<Input
className={styles.Field}
placeholder={`Enter ${label} for ${radioTypes[key]}`}
type="number"
min={options.min}
max={options.max}
addonAfter={options?.addOnText ? options?.addOnText : ''}
/>
</Item>
);
const renderOptionItem = (dataIndex, key, label, options = {}) => {
return (
<Item
key={key + dataIndex}
name={[options.mapName, key, ...dataIndex]}
rules={[
{
required: true,
message: `Enter ${label} for ${radioTypes[key]}`,
},
]}
>
{typeof options.dropdown === 'function' ? options.dropdown(key) : options.dropdown}
</Item>
);
};
const renderChannelItem = label => {
return (
<Item label={label} colon={false}>
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(radioMap)).map(key => {
const isEnabled = childProfiles.rf?.[0]?.details?.rfConfigMap[key].autoChannelSelection;
let channel;
if (label === 'Active Channel') {
channel = isEnabled
? {
dataIndex: 'channelNumber',
addOnText: (
<Tooltip
text="Auto"
title={`The ${radioTypes[key]} radio has "Auto Channel Selection" enabled in the RF Profile`}
/>
),
}
: {
dataIndex: 'manualChannelNumber',
addOnText: 'Manual',
dependencies: ['radioMap', key, 'manualBackupChannelNumber'],
};
}
if (label === 'Backup Channel') {
channel = isEnabled
? {
dataIndex: 'backupChannelNumber',
addOnText: (
<Tooltip
text="Auto"
title={`The ${radioTypes[key]} radio has "Auto Channel Selection" enabled in the RF Profile`}
/>
),
}
: {
dataIndex: 'manualBackupChannelNumber',
addOnText: 'Manual',
dependencies: ['radioMap', key, 'manualChannelNumber'],
};
}
const powerLevels = data?.details?.radioMap?.[key]?.allowedChannelsPowerLevels ?? [];
const allowedChannels = powerLevels
.filter(item => {
if (channel.dataIndex === 'manualBackupChannelNumber') {
return !item.dfs;
}
return item;
})
.map(item => item?.channelNumber)
.sort((a, b) => a - b);
return (
<Item
key={`radioMap${key}${channel.dataIndex}`}
name={['radioMap', key, channel.dataIndex]}
dependencies={[channel.dependencies]}
rules={[
{ required: true, message: `Allowed Channels: ${allowedChannels.join(', ')}` },
({ getFieldValue }) => ({
validator(_rule, value) {
if (!isEnabled) {
if (
parseInt(getFieldValue(['radioMap', key, 'manualChannelNumber']), 10) ===
parseInt(
getFieldValue(['radioMap', key, 'manualBackupChannelNumber']),
10
)
) {
return Promise.reject(
new Error('Active and backup channels must be different')
);
}
const channelNumber = parseInt(
getFieldValue(['radioMap', key, channel.dataIndex]),
10
);
if (!value || allowedChannels.includes(channelNumber)) {
return Promise.resolve();
}
return Promise.reject(
new Error(`Allowed Channels: ${allowedChannels.join(', ')}`)
);
}
return Promise.resolve();
},
}),
]}
>
<Input
className={styles.Field}
placeholder={`Enter ${label} for ${radioTypes[key]}`}
type="number"
min={Math.min(...allowedChannels)}
max={Math.max(...allowedChannels)}
addonAfter={channel.addOnText}
disabled={isEnabled}
/>
</Item>
);
})}
</div>
</Item>
);
};
const renderBandwidthLabels = () => (
<Item label="Channel Bandwidth">
<div className={styles.InlineDiv}>
{sortRadioTypes(Object.keys(radioMap)).map(radio => (
<DisabledText
key={radio}
value={
USER_FRIENDLY_BANDWIDTHS[
childProfiles?.rf?.[0]?.details?.rfConfigMap?.[radio].channelBandwidth
] ?? 'N/A'
}
showTooltip={false}
/>
))}
</div>
</Item>
);
if (errorProfiles) {
return (
<Alert
@@ -605,141 +273,13 @@ const General = ({
{extraGeneralCards}
<Collapse expandIconPosition="right">
<Panel header="Advanced Settings" name="settings">
{renderItem(' ', data?.details?.radioMap, 'radioType')}
<p>Radio Specific Parameters:</p>
{renderBandwidthLabels()}
{renderItem('Enable Radio', advancedRadioMap, ['radioAdminState'], renderOptionItem, {
dropdown: defaultOptions,
mapName: 'advancedRadioMap',
})}
{renderItem(
'Deauth Attack Detection',
advancedRadioMap,
['deauthAttackDetection'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: defaultOptionsBoolean,
}
)}
{renderItem('UAPSD', advancedRadioMap, ['uapsdState'], renderOptionItem, {
mapName: 'advancedRadioMap',
dropdown: defaultOptions,
})}
{renderChannelItem('Active Channel')}
{renderChannelItem('Backup Channel')}
{extraFields.map(field =>
renderConditionalItem(field.label, field.obj, field.dataIndex, field.dependencies)
)}
{renderItem(
'Management Rate (Mbps)',
advancedRadioMap,
['managementRate', 'value'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: key => (
<Select className={styles.Field}>
{key === 'is2dot4GHz' && (
<>
<Option value="rate1mbps">1</Option>
<Option value="rate2mbps">2</Option>
<Option value="rate5dot5mbps">5.5</Option>
</>
)}
<Option value="rate6mbps">6</Option>
<Option value="rate9mbps">9</Option>
{key === 'is2dot4GHz' && <Option value="rate11mbps">11</Option>}
<Option value="rate12mbps">12</Option>
<Option value="rate18mbps">18</Option>
<Option value="rate24mbps">24</Option>
</Select>
),
}
)}
{renderItem(
'Multicast Rate (Mbps)',
advancedRadioMap,
['multicastRate', 'value'],
renderOptionItem,
{
mapName: 'advancedRadioMap',
dropdown: (
<Select className={styles.Field}>
<Option value="rate6mbps">6</Option>
<Option value="rate9mbps">9</Option>
<Option value="rate12mbps">12</Option>
<Option value="rate18mbps">18</Option>
<Option value="rate24mbps">24</Option>
<Option value="rate36mbps">36</Option>
<Option value="rate48mbps">48</Option>
<Option value="rate54mbps">54</Option>
</Select>
),
}
)}
{renderItem(
'Probe Response Threshold',
radioMap,
['probeResponseThresholdDb', 'value'],
renderInputItem,
{
min: -100,
max: -40,
error: '-100 - -40 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
}
)}
{renderItem(
'Client Disconnect Threshold',
radioMap,
['clientDisconnectThresholdDb', 'value'],
renderInputItem,
{
min: -100,
max: 0,
error: '-100 - 0 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
}
)}
{renderItem('EIRP Tx Power', radioMap, ['eirpTxPower', 'value'], renderInputItem, {
min: 1,
max: 32,
error: '1 - 32 dBm',
addOnText: 'dBm',
mapName: 'radioMap',
})}
{renderItem(
'SNR',
advancedRadioMap,
['bestApSettings', 'value', 'dropInSnrPercentage'],
renderInputItem,
{
min: 0,
max: 100,
error: '0 - 100%',
addOnText: '% Drop',
mapName: 'advancedRadioMap',
hidden: true,
}
)}
{renderItem(
'Min Load',
advancedRadioMap,
['bestApSettings', 'value', 'minLoadFactor'],
renderInputItem,
{
min: 0,
max: 100,
error: '0 - 100%',
addOnText: '%',
mapName: 'advancedRadioMap',
hidden: true,
}
)}
<Advanced
extraFields={extraFields}
childProfiles={childProfiles}
data={data}
radioTypes={radioTypes}
form={form}
/>
</Panel>
</Collapse>
</Form>

View File

@@ -34,6 +34,7 @@
:global(.ant-form-item) {
flex: 1;
}
}
.InlineBlockDiv {
display: inline-block;
@@ -63,6 +64,7 @@
}
.InlineDiv > * {
flex: 1;
margin: 0 10px 0 0;
}
@@ -117,4 +119,3 @@
a {
color: white;
}
}

View File

@@ -19,6 +19,8 @@ export { default as BlockedList } from 'containers/BlockedList';
export { default as ClientDeviceDetails } from 'containers/ClientDeviceDetails';
export { default as NetworkTableContainer } from 'containers/NetworkTableContainer';
export { default as APFirmware } from 'containers/AccessPointDetails/components/Firmware';
export { default as APAdvanced } from 'containers/AccessPointDetails/components/General/components/Advanced';
export { default as ThemeProvider } from 'contexts/ThemeProvider';
export { default as RolesProvider } from 'contexts/RolesProvider';
@@ -42,13 +44,13 @@ export { default as ScrollToTop } from 'components/ScrollToTop';
export { default as LineGraphTooltip } from 'components/GraphTooltips/LineGraphTooltip';
export { default as PieGraphTooltip } from 'components/GraphTooltips/PieGraphTooltip';
export { default as Skeleton } from 'components/Skeleton';
export { default as Timer } from 'components/Timer';
export {
Table as SkeletonTable,
List as SkeletonList,
Card as SkeletonCard,
} from 'components/Skeleton';
export { default as DisabledText } from 'components/DisabledText';
export { default as Timer } from 'components/Timer';
export { default as WithRoles } from 'components/WithRoles';
export { Input, Select, Switch, RoleProtectedBtn } from 'components/WithRoles';