diff --git a/CHANGELOG.md b/CHANGELOG.md index cea2227c35..f23ea50c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ For details about compatibility between different releases, see the **Commitment - Rate limiting classes for individual HTTP paths. - Rate limiting keys for HTTP endpoints now contain the caller API key ID when available. The caller IP is still available as a fallback. +- Allow users to set multiple frequency plans only in the same band in the Console. ### Changed diff --git a/cypress/e2e/console/gateways/create.spec.js b/cypress/e2e/console/gateways/create.spec.js index c532680428..bc9ca5843d 100644 --- a/cypress/e2e/console/gateways/create.spec.js +++ b/cypress/e2e/console/gateways/create.spec.js @@ -159,7 +159,12 @@ describe('Gateway create', () => { .first() .selectOption(gateway.frequency_plan) cy.findByRole('button', { name: /Add frequency plan/ }).click() - cy.findByText('Frequency plan').parent().parent().find('input').eq(2).selectOption('US_902_928') + cy.findByText('Frequency plan') + .parent() + .parent() + .find('input') + .eq(2) + .selectOption('EU_863_870_TTN') cy.findByRole('button', { name: 'Register gateway' }).click() cy.findByTestId('error-notification').should('not.exist') @@ -169,7 +174,7 @@ describe('Gateway create', () => { ) cy.findByRole('heading', { name: `eui-${gateway.eui}` }) cy.findByText('Frequency plan') - cy.findByText('EU_863_870 , US_902_928_FSB_1').should('be.visible') + cy.findByText('EU_863_870 , EU_863_870_TTN').should('be.visible') cy.findByTestId('error-notification').should('not.exist') }) diff --git a/cypress/e2e/console/gateways/edit.spec.js b/cypress/e2e/console/gateways/edit.spec.js index a7552e1128..4a6eba6a3e 100644 --- a/cypress/e2e/console/gateways/edit.spec.js +++ b/cypress/e2e/console/gateways/edit.spec.js @@ -294,7 +294,7 @@ describe('Gateway general settings', () => { }) it('succeeds editing multiple frequency plans', () => { - const newFrequencyPlan = 'Asia 920-923 MHz' + const newFrequencyPlan = 'Europe 863-870 MHz, 6 channels for roaming (Draft)' cy.loginConsole({ user_id: user.ids.user_id, password: user.password }) cy.visit( `${Cypress.config('consoleRootPath')}/gateways/${gateway2.ids.gateway_id}/general-settings`, diff --git a/pkg/webui/components/key-value-map/entry.js b/pkg/webui/components/key-value-map/entry.js index 14f0fc625a..b509198db9 100644 --- a/pkg/webui/components/key-value-map/entry.js +++ b/pkg/webui/components/key-value-map/entry.js @@ -44,6 +44,7 @@ const Entry = ({ removeMessage, distinctOptions, atLeastOneEntry, + filterByTag, }) => { const [currentValue, setCurrentValue] = useState(value) const [newOptions, setNewOptions] = useState(undefined) @@ -98,8 +99,15 @@ const Entry = ({ } else { newOptions = options.filter(v => !fieldValue.includes(v.value)) } - setNewOptions(newOptions) - }, [currentValue, options, fieldValue]) + + let taggedOptions = newOptions + if (fieldValue.length >= 2 && filterByTag) { + const selectedOption = options.find(v => v.value === fieldValue[0]) + taggedOptions = newOptions.filter(v => selectedOption.tag === v.tag) + } + + setNewOptions(taggedOptions) + }, [currentValue, options, fieldValue, filterByTag]) const showRemoveButton = atLeastOneEntry ? index !== 0 : true @@ -157,6 +165,7 @@ Entry.propTypes = { atLeastOneEntry: PropTypes.bool, distinctOptions: PropTypes.bool, fieldValue: PropTypes.any, + filterByTag: PropTypes.bool, index: PropTypes.number.isRequired, indexAsKey: PropTypes.bool.isRequired, inputElement: PropTypes.elementType.isRequired, @@ -184,6 +193,7 @@ Entry.defaultProps = { distinctOptions: false, fieldValue: undefined, atLeastOneEntry: false, + filterByTag: false, } export default Entry diff --git a/pkg/webui/components/key-value-map/index.js b/pkg/webui/components/key-value-map/index.js index 0eb44e7a32..b908a8f6e9 100644 --- a/pkg/webui/components/key-value-map/index.js +++ b/pkg/webui/components/key-value-map/index.js @@ -46,6 +46,7 @@ const KeyValueMap = ({ valuePlaceholder, distinctOptions, atLeastOneEntry, + filterByTag, }) => { const handleEntryChange = useCallback( (index, newValues) => { @@ -98,6 +99,7 @@ const KeyValueMap = ({ removeMessage={removeMessage} distinctOptions={distinctOptions} atLeastOneEntry={atLeastOneEntry} + filterByTag={filterByTag} /> ))} @@ -122,6 +124,7 @@ KeyValueMap.propTypes = { className: PropTypes.string, disabled: PropTypes.bool, distinctOptions: PropTypes.bool, + filterByTag: PropTypes.bool, indexAsKey: PropTypes.bool, inputElement: PropTypes.elementType, isReadOnly: PropTypes.func, @@ -157,6 +160,7 @@ KeyValueMap.defaultProps = { removeMessage: undefined, distinctOptions: false, atLeastOneEntry: false, + filterByTag: false, } export default KeyValueMap diff --git a/pkg/webui/console/containers/freq-plans-select/gs-frequency-plan-select.js b/pkg/webui/console/containers/freq-plans-select/gs-frequency-plan-select.js index f3eb89f04b..74b8a5f0ae 100644 --- a/pkg/webui/console/containers/freq-plans-select/gs-frequency-plan-select.js +++ b/pkg/webui/console/containers/freq-plans-select/gs-frequency-plan-select.js @@ -69,6 +69,7 @@ const GatewayFrequencyPlansSelect = () => { additionalInputProps={{ options: freqPlanOptions }} distinctOptions atLeastOneEntry + filterByTag required /> ) diff --git a/pkg/webui/console/containers/freq-plans-select/utils.js b/pkg/webui/console/containers/freq-plans-select/utils.js index 2509bd20c7..0526a8fd1c 100644 --- a/pkg/webui/console/containers/freq-plans-select/utils.js +++ b/pkg/webui/console/containers/freq-plans-select/utils.js @@ -14,12 +14,13 @@ import { defineMessages } from 'react-intl' -export const formatOptions = plans => plans.map(plan => ({ value: plan.id, label: plan.name })) +export const formatOptions = plans => + plans.map(plan => ({ value: plan.id, label: plan.name, tag: plan.band_id })) export const m = defineMessages({ warning: 'Frequency plans unavailable', none: 'Do not set a frequency plan', selectFrequencyPlan: 'Select a frequency plan...', addFrequencyPlan: 'Add frequency plan', frequencyPlanDescription: - 'Note: most gateways use a single frequency plan. Some 16 and 64 channel gateways however allow setting multiple.', + 'Note: most gateways use a single frequency plan. Some 16 and 64 channel gateways however allow setting multiple within the same band.', }) diff --git a/pkg/webui/locales/en.json b/pkg/webui/locales/en.json index 8f4e19e56c..fe0159557d 100644 --- a/pkg/webui/locales/en.json +++ b/pkg/webui/locales/en.json @@ -514,7 +514,7 @@ "console.containers.freq-plans-select.utils.none": "Do not set a frequency plan", "console.containers.freq-plans-select.utils.selectFrequencyPlan": "Select a frequency plan...", "console.containers.freq-plans-select.utils.addFrequencyPlan": "Add frequency plan", - "console.containers.freq-plans-select.utils.frequencyPlanDescription": "Note: most gateways use a single frequency plan. Some 16 and 64 channel gateways however allow setting multiple.", + "console.containers.freq-plans-select.utils.frequencyPlanDescription": "Note: most gateways use a single frequency plan. Some 16 and 64 channel gateways however allow setting multiple within the same band.", "console.containers.gateway-connection.index.lastSeenAvailableTooltip": "The elapsed time since the network registered the last activity of this gateway. This is determined from received uplinks, or sent status messages of this gateway.", "console.containers.gateway-connection.index.disconnectedTooltip": "The gateway has currently no TCP connection established with the Gateway Server. For (rare) UDP based gateways, this can also mean that the gateway initiated no pull/push data request within the last 30 seconds.", "console.containers.gateway-connection.index.connectedTooltip": "This gateway is connected to the Gateway Server but the network has not registered any activity (sent uplinks or status messages) from it yet.",