Skip to content

Commit eaffe38

Browse files
committed
console: Extract claim gateway error function in utils
1 parent 0c820ee commit eaffe38

4 files changed

Lines changed: 49 additions & 27 deletions

File tree

pkg/webui/console/containers/gateway-onboarding-form/index.js

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import React, { useCallback, useMemo, useState } from 'react'
1616
import { useSelector, useDispatch } from 'react-redux'
1717
import { merge } from 'lodash'
18-
import { defineMessages } from 'react-intl'
1918

2019
import Form from '@ttn-lw/components/form'
2120

@@ -24,7 +23,7 @@ import GatewayApiKeysModal from '@console/components/gateway-api-keys-modal'
2423
import { composeDataUri, downloadDataUriAsFile } from '@ttn-lw/lib/data-uri'
2524
import PropTypes from '@ttn-lw/lib/prop-types'
2625
import attachPromise from '@ttn-lw/lib/store/actions/attach-promise'
27-
import { getBackendErrorRootCause } from '@ttn-lw/lib/errors/utils'
26+
import { getClaimGatewayErrorMessage } from '@ttn-lw/lib/errors/utils'
2827

2928
import { createGateway, claimGateway, updateGateway } from '@console/store/actions/gateways'
3029
import { createGatewayApiKey } from '@console/store/actions/api-keys'
@@ -37,14 +36,6 @@ import { initialValues as registerInitialValues } from './gateway-provisioning-f
3736
import { initialValues as claimingInitialValues } from './gateway-provisioning-form/gateway-claim-form-section'
3837
import GatewayQRScanSection from './qr-scan-section'
3938

40-
const m = defineMessages({
41-
claimGatewayNotFound:
42-
"`NotFound`: the gateway doesn't exist. This is most likely a typo in the EUI. An edge case is that The Things Stack is configured for the staging environment.",
43-
claimGatewayFailedPrecondition:
44-
"`FailedPrecondition`: the owner token is correct, but either there's no gateway subscription attached and active, or it is a correct gateway activation code and it has expired.",
45-
claimGatewayPermissionDenied: '`PermissionDenied`: the owner token is invalid.',
46-
})
47-
4839
const GatewayOnboardingForm = props => {
4940
const { onSuccess } = props
5041
const userId = useSelector(selectUserId)
@@ -151,17 +142,9 @@ const GatewayOnboardingForm = props => {
151142

152143
onSuccess(cleanValues.target_gateway_id, inputMethod === 'managed')
153144
} catch (error) {
154-
const rootCause = getBackendErrorRootCause(error)
155-
const errorCode = rootCause?.code ?? -1
156-
157-
const errorMessages = {
158-
5: m.claimGatewayNotFound, // NOT_FOUND
159-
9: m.claimGatewayFailedPrecondition, // FAILED_PRECONDITION
160-
7: m.claimGatewayPermissionDenied, // PERMISSION_DENIED
161-
}
162-
163-
if (errorMessages[errorCode]) {
164-
setError(errorMessages[errorCode])
145+
const message = getClaimGatewayErrorMessage(error)
146+
if (message) {
147+
setError(message)
165148
} else {
166149
// Fallback for unexpected/unhandled errors
167150
setError(error)

pkg/webui/lib/errors/utils.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import * as Sentry from '@sentry/react'
1616
import { isPlainObject, isObject } from 'lodash'
17+
import { defineMessages } from 'react-intl'
1718

1819
import { error as errorLog, warn } from '@ttn-lw/lib/log'
1920
import interpolate from '@ttn-lw/lib/interpolate'
@@ -588,3 +589,39 @@ export const ingestError = (error, extras = {}, tags = {}) => {
588589
})
589590
}
590591
}
592+
593+
/**
594+
* Maps claim-related backend errors to appropriate user messages.
595+
*
596+
* @param {object} error - The error object.
597+
* @returns {object|undefined} - The corresponding error message, or undefined if no match.
598+
*/
599+
export const getClaimGatewayErrorMessage = error => {
600+
const m = defineMessages({
601+
notFound: "Gateway doesn't exist. Please confirm that the gateway EUI is correct.",
602+
subscriptionNotActive:
603+
'No gateway subscription attached and active. Please subscribe to the gateway or activate your subscription.',
604+
activationCodeExpired: 'Activation code expired. Please extend your subscription.',
605+
permissionDenied: 'The owner token is invalid.',
606+
})
607+
608+
const rootCause = getBackendErrorRootCause(error)
609+
const errorCode = rootCause?.code
610+
const backendErrorMessage = rootCause?.message_format
611+
switch (errorCode) {
612+
case 5: // NOT_FOUND
613+
return m.notFound
614+
case 9: // FAILED_PRECONDITION
615+
if (backendErrorMessage.includes('gateway subscription not attached and active')) {
616+
return m.subscriptionNotActive
617+
}
618+
if (backendErrorMessage.includes('activation code expired')) {
619+
return m.activationCodeExpired
620+
}
621+
return undefined
622+
case 7: // PERMISSION_DENIED
623+
return m.permissionDenied
624+
default:
625+
return undefined
626+
}
627+
}

pkg/webui/locales/en.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,6 @@
650650
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.continue": "To continue, please confirm the Gateway EUI so we can determine onboarding options",
651651
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.emtyEui": "Continue without EUI",
652652
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.noEui": "No gateway EUI",
653-
"console.containers.gateway-onboarding-form.index.claimGatewayNotFound": "`NotFound`: the gateway doesn't exist. This is most likely a typo in the EUI. An edge case is that The Things Stack is configured for the staging environment.",
654-
"console.containers.gateway-onboarding-form.index.claimGatewayFailedPrecondition": "`FailedPrecondition`: the owner token is correct, but either there's no gateway subscription attached and active, or it is a correct gateway activation code and it has expired.",
655-
"console.containers.gateway-onboarding-form.index.claimGatewayPermissionDenied": "`PermissionDenied`: the owner token is invalid.",
656653
"console.containers.gateway-onboarding-form.qr-scan-section.index.hasGatewayQR": "Does your gateway have a LoRaWAN® Gateway Identification QR Code? Scan it to speed up onboarding.",
657654
"console.containers.gateway-onboarding-form.qr-scan-section.index.gatewayGuide": "Gateway registration help",
658655
"console.containers.gateway-onboarding-form.qr-scan-section.index.invalidQRCode": "Invalid QR code data. Please note that only TTIGPRO1 Gateway Identification QR Code can be scanned. Some gateways have unrelated QR codes printed on them that cannot be used.",
@@ -1087,6 +1084,10 @@
10871084
"lib.errors.status-code-messages.501": "Not implemented",
10881085
"lib.errors.status-code-messages.503": "Service unavailable",
10891086
"lib.errors.status-code-messages.504": "Gateway timeout",
1087+
"lib.errors.utils.notFound": "Gateway doesn't exist. Please confirm that the gateway EUI is correct.",
1088+
"lib.errors.utils.subscriptionNotActive": "No gateway subscription attached and active. Please subscribe to the gateway or activate your subscription.",
1089+
"lib.errors.utils.activationCodeExpired": "Activation code expired. Please extend your subscription.",
1090+
"lib.errors.utils.permissionDenied": "The owner token is invalid.",
10901091
"lib.field-description-messages.idLocation": "Enter a value using lowercase letters, numbers, and dashes. You can choose this freely.",
10911092
"lib.field-description-messages.freqPlanDescription": "A frequency plan defines data rates that your end device or gateway is setup to use. It is important that gateways and end devices within reach use the same frequency plan to be able to communicate.",
10921093
"lib.field-description-messages.freqPlanLocation": "Your end device or gateway manufacturer should provide information about the applicable frequency plan for a particular device. In some cases they are printed on the device itself but they should always be in the hardware manual or data sheet.",

pkg/webui/locales/ja.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,6 @@
650650
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.continue": "",
651651
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.emtyEui": "",
652652
"console.containers.gateway-onboarding-form.gateway-provisioning-form.index.noEui": "",
653-
"console.containers.gateway-onboarding-form.index.claimGatewayNotFound": "",
654-
"console.containers.gateway-onboarding-form.index.claimGatewayFailedPrecondition": "",
655-
"console.containers.gateway-onboarding-form.index.claimGatewayPermissionDenied": "",
656653
"console.containers.gateway-onboarding-form.qr-scan-section.index.hasGatewayQR": "",
657654
"console.containers.gateway-onboarding-form.qr-scan-section.index.gatewayGuide": "",
658655
"console.containers.gateway-onboarding-form.qr-scan-section.index.invalidQRCode": "",
@@ -1087,6 +1084,10 @@
10871084
"lib.errors.status-code-messages.501": "",
10881085
"lib.errors.status-code-messages.503": "",
10891086
"lib.errors.status-code-messages.504": "",
1087+
"lib.errors.utils.notFound": "",
1088+
"lib.errors.utils.subscriptionNotActive": "",
1089+
"lib.errors.utils.activationCodeExpired": "",
1090+
"lib.errors.utils.permissionDenied": "",
10901091
"lib.field-description-messages.idLocation": "",
10911092
"lib.field-description-messages.freqPlanDescription": "周波数プランは、エンドデバイスやゲートウェイが使用するように設定されたデータレートを定義します。ゲートウェイとエンドデバイスが通信できるようにするためには、同じ周波数プランを使用することが重要です",
10921093
"lib.field-description-messages.freqPlanLocation": "エンドデバイスやゲートウェイのメーカーは、特定のデバイスに適用される周波数プランに関する情報を提供するはずです。場合によっては、デバイス自体に印刷されていることもありますが、常にハードウェアマニュアルまたはデータシートに記載されているはずです",

0 commit comments

Comments
 (0)