Skip to content

Commit

Permalink
Merge pull request #6615 from TheThingsNetwork/feature/multi-select-f…
Browse files Browse the repository at this point in the history
…requency-plans

Support setting multiple frequency plans for gateways from the Console
  • Loading branch information
ryaplots authored Oct 19, 2023
2 parents dceeff8 + 3886390 commit d23194d
Show file tree
Hide file tree
Showing 21 changed files with 506 additions and 285 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ For details about compatibility between different releases, see the **Commitment
- It is now possible to trigger a resending of the email validation email from within the Console. The new action is part of the error screen that users see when they log into the Console without having their contact info validated yet (and the network requires validation before usage).
- Updated Japanese translations for the Console and backend.
- `--grpc.correlation-ids-ignore-methods` configuration option, which allows certain gRPC methods to be skipped from the correlation ID middleware which adds a correlation ID with the name of the gRPC method. Methods bear the format used by `--grpc.log-ignore-methods`, such as `/ttn.lorawan.v3.GsNs/HandleUplink`.
- Support for setting multiple frequency plans for gateways from the Console.

### Changed

Expand Down
49 changes: 44 additions & 5 deletions cypress/e2e/console/gateways/create.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Gateway create', () => {
cy.findByLabelText('Gateway EUI').should('be.visible')
cy.findByLabelText('Gateway ID').should('be.visible')
cy.findByLabelText('Gateway name').should('be.visible')
cy.findByLabelText('Frequency plan').should('be.visible')
cy.findByTestId('key-value-map').should('be.visible')
cy.findByLabelText(/Require authenticated connection/).should('exist')
cy.findByLabelText(/Share status within network/).should('exist')
cy.findByLabelText(/Share location within network/).should('exist')
Expand All @@ -54,7 +54,11 @@ describe('Gateway create', () => {
cy.findByLabelText('Gateway EUI').blur()
cy.findByLabelText('Gateway ID').should('have.value', `eui-${gateway.eui}`)
cy.findByLabelText('Gateway name').type('Test Gateway')
cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan)
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption(gateway.frequency_plan)
cy.findByRole('button', { name: 'Register gateway' }).click()

cy.location('pathname').should(
Expand Down Expand Up @@ -87,7 +91,11 @@ describe('Gateway create', () => {
cy.findByLabelText('Gateway EUI').blur()
cy.findByLabelText('Gateway ID').should('have.value', `eui-${gateway.eui}`)
cy.findByLabelText('Gateway name').type('Test Gateway')
cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan)
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption(gateway.frequency_plan)
cy.findByLabelText(/Require authenticated connection/).check()
cy.findByLabelText(/Generate API key for CUPS/).check()
cy.findByLabelText(/Generate API key for LNS/).check()
Expand Down Expand Up @@ -121,7 +129,11 @@ describe('Gateway create', () => {
}

cy.findByLabelText('Gateway EUI').type(gateway.eui)
cy.findByLabelText('Frequency plan').selectOption('no-frequency-plan')
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption('no-frequency-plan')
cy.findByText(/Without choosing a frequency plan/)
cy.findByRole('button', { name: 'Register gateway' }).click()

Expand All @@ -134,6 +146,33 @@ describe('Gateway create', () => {
cy.findByTestId('error-notification').should('not.exist')
})

it('succeeds adding gateway with multiple frequency plans', () => {
const gateway = {
frequency_plan: 'EU_863_870',
eui: generateHexValue(16),
}

cy.findByLabelText('Gateway EUI').type(gateway.eui)
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.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.findByRole('button', { name: 'Register gateway' }).click()

cy.findByTestId('error-notification').should('not.exist')
cy.location('pathname').should(
'eq',
`${Cypress.config('consoleRootPath')}/gateways/eui-${gateway.eui}`,
)
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.findByTestId('error-notification').should('not.exist')
})

describe('Gateway Server disabled', () => {
beforeEach(() => {
cy.augmentStackConfig(disableGatewayServer)
Expand All @@ -149,7 +188,7 @@ describe('Gateway create', () => {

cy.findByLabelText('Gateway EUI').type(gateway.eui)

cy.findByLabelText('Frequency plan').should('not.exist')
cy.findByTestId('key-value-map').should('not.exist')
cy.findByRole('button', { name: 'Register gateway' }).click()

cy.location('pathname').should(
Expand Down
56 changes: 53 additions & 3 deletions cypress/e2e/console/gateways/edit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { generateCollaborator } from '../../../support/utils'
describe('Gateway general settings', () => {
let user
let gateway
let gateway2
const collabUserId = 'test-collab-user'
const collabUser = {
ids: { user_id: collabUserId },
Expand Down Expand Up @@ -46,7 +47,20 @@ describe('Gateway general settings', () => {
key: 'value',
},
}
gateway2 = {
ids: { gateway_id: 'test-gateway-frequency-plans', eui: '0000000000000001' },
name: 'Test Gateway Frequency Plans',
description: 'Gateway for testing multiple frequency plans',
schedule_anytime_delay: '523ms',
enforce_duty_cycle: true,
gateway_server_address: 'localhost',
attributes: {
key: 'value',
},
frequency_plan_ids: ['EU_863_870', 'US_902_928_FSB_1'],
}
cy.createGateway(gateway, user.ids.user_id)
cy.createGateway(gateway2, user.ids.user_id)
})

it('displays newly created gateway values', () => {
Expand Down Expand Up @@ -122,9 +136,9 @@ describe('Gateway general settings', () => {
cy.findByRole('button', { name: 'Save changes' }).should('be.visible')
cy.findByRole('button', { name: /Delete gateway/ }).should('be.visible')
cy.findByRole('heading', { name: 'LoRaWAN options' }).should('be.visible')
cy.findByLabelText('Frequency plan').should('not.exist')
cy.findByText('Frequency plan').should('not.exist')
cy.findByRole('button', { name: 'Expand' }).click()
cy.findByLabelText('Frequency plan').should('be.visible')
cy.findByText('Frequency plan').should('be.visible')
cy.findByLabelText(/Enforce duty cycle/)
.should('exist')
.and('have.attr', 'value', 'true')
Expand Down Expand Up @@ -192,7 +206,11 @@ describe('Gateway general settings', () => {
cy.findByLabelText(/Enforce duty cycle/).uncheck()
cy.findByLabelText('Schedule any time delay').clear()
cy.findByLabelText('Schedule any time delay').type('1')
cy.findByLabelText('Frequency plan').type(`${newFrequencyPlan}{enter}`)
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption(newFrequencyPlan)
cy.findByRole('button', { name: 'Save changes' }).click()
})

Expand Down Expand Up @@ -275,6 +293,38 @@ describe('Gateway general settings', () => {
})
})

it('succeeds editing multiple frequency plans', () => {
const newFrequencyPlan = 'Asia 920-923 MHz'
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
cy.visit(
`${Cypress.config('consoleRootPath')}/gateways/${gateway2.ids.gateway_id}/general-settings`,
)

cy.findByText('LoRaWAN options', { selector: 'h3' })
.closest('[data-test-id="collapsible-section"]')
.within(() => {
cy.findByRole('button', { name: 'Expand' }).click()
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption(newFrequencyPlan)
cy.findByRole('button', { name: 'Save changes' }).click()
})

cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('toast-notification').findByText('Gateway updated').should('be.visible')
cy.reload()

cy.findByText('LoRaWAN options', { selector: 'h3' })
.closest('[data-test-id="collapsible-section"]')
.within(() => {
cy.findByRole('button', { name: 'Expand' }).click()
cy.findByText('Frequency plan')
cy.findByText(newFrequencyPlan)
})
})

it('succeeds deleting the gateway', () => {
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
cy.visit(
Expand Down
6 changes: 5 additions & 1 deletion cypress/e2e/smoke/gateways/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ const gatewayCreate = defineSmokeTest('succeeds creating gateway', () => {
cy.findByRole('link', { name: /Register gateway/ }).click()
cy.findByLabelText('Gateway EUI').type(gateway.eui)
cy.findByLabelText('Gateway name').type(gateway.name)
cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan_id)
cy.findByText('Frequency plan')
.parents('div[data-test-id="form-field"]')
.find('input')
.first()
.selectOption(gateway.frequency_plan_id)
cy.findByRole('button', { name: 'Register gateway' }).click()

cy.location('pathname').should(
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/smoke/gateways/subpages.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const gatewaySubpages = defineSmokeTest('check all gateway sub-pages', () => {
.closest('[data-test-id="collapsible-section"]')
.within(() => {
cy.findByRole('button', { name: 'Expand' }).click()
cy.findByLabelText('Frequency plan').should('be.visible')
cy.findByText('Frequency plan').should('be.visible')
cy.findByRole('button', { name: /Save changes/ }).should('be.visible')
cy.findByTestId('error-notification').should('not.exist')
cy.findByRole('button', { name: 'Collapse' }).click()
Expand Down
2 changes: 1 addition & 1 deletion pkg/webui/components/form/field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const FormField = props => {
const hasTooltip = Boolean(tooltipId)
const hasTitle = Boolean(title)
const showError = touched && !isEmpty(errors)
const showWarning = isEmpty(errors) && Boolean(warning)
const showWarning = !showError && Boolean(warning)
const error = showError && errors[0]
const showDescription = !showError && !showWarning && Boolean(description)
const tooltipIcon = hasTooltip ? <Tooltip id={tooltipId} glossaryTerm={title} /> : null
Expand Down
Loading

0 comments on commit d23194d

Please sign in to comment.