Skip to content

Commit af400c1

Browse files
committed
console: Separate tti only parts and gateway fleet only parts
1 parent 987e80e commit af400c1

6 files changed

Lines changed: 149 additions & 97 deletions

File tree

pkg/webui/components/qr-modal-button/index.js

Lines changed: 5 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,19 @@
1515
import React, { useCallback } from 'react'
1616
import { defineMessages } from 'react-intl'
1717

18-
import { IconCamera, IconPlus } from '@ttn-lw/components/icon'
18+
import { IconCamera } from '@ttn-lw/components/icon'
1919
import Link from '@ttn-lw/components/link'
2020
import ModalButton from '@ttn-lw/components/button/modal-button'
21-
import Button from '@ttn-lw/components/button'
22-
import Input from '@ttn-lw/components/input'
2321

2422
import Message from '@ttn-lw/lib/components/message'
2523
import ErrorMessage from '@ttn-lw/lib/components/error-message'
2624

2725
import PropTypes from '@ttn-lw/lib/prop-types'
2826
import sharedMessages from '@ttn-lw/lib/shared-messages'
29-
import { selectPluginTTSCloud } from '@ttn-lw/lib/selectors/env'
3027

3128
import DataSheet from '../data-sheet'
3229
import QR from '../qr'
3330

34-
const smUrl = selectPluginTTSCloud().subscription_management_url
35-
3631
const QrScanDoc = (
3732
<Link.Anchor external secondary href="https://www.thethingsindustries.com/docs/">
3833
Having trouble?
@@ -42,40 +37,10 @@ const QrScanDoc = (
4237
const m = defineMessages({
4338
scanContinue: 'Please scan the QR code to continue. {qrScanDoc}',
4439
apply: 'Apply',
45-
fleetToken: 'Fleet owner token',
46-
addFleet: 'Add to Fleet',
47-
addToFleetTooltip:
48-
'You are registering a Managed gateway. If you want to add it to an existing fleet, click here.',
4940
})
5041

5142
const QRModalButton = props => {
52-
const { message, onApprove, onCancel, onRead, qrData, setQrData, invalidMessage } = props
53-
const [isAddToFleet, setIsAddToFleet] = React.useState(undefined)
54-
const [fleetOwnerToken, setFleetOwnerToken] = React.useState('')
55-
56-
const handleAddToFleet = useCallback(() => {
57-
setIsAddToFleet(true)
58-
}, [])
59-
60-
const handleRemoveFleet = useCallback(() => {
61-
setIsAddToFleet(false)
62-
setFleetOwnerToken('')
63-
setQrData({
64-
...qrData,
65-
gateway: { ...qrData.gateway, _fleet_owner_token: undefined },
66-
})
67-
}, [qrData, setQrData])
68-
69-
const handleFleetTokenChange = useCallback(
70-
value => {
71-
setFleetOwnerToken(value)
72-
setQrData({
73-
...qrData,
74-
gateway: { ...qrData.gateway, _fleet_owner_token: value },
75-
})
76-
},
77-
[qrData, setQrData],
78-
)
43+
const { message, onApprove, onCancel, onRead, qrData, invalidMessage, modalDataChildren } = props
7944

8045
const handleRead = useCallback(
8146
val => {
@@ -90,57 +55,7 @@ const QRModalButton = props => {
9055
qrData.valid ? (
9156
<>
9257
<DataSheet data={qrData.data} />
93-
{qrData.gateway.is_managed && (
94-
<>
95-
{isAddToFleet ? (
96-
<div className="w-full mt-cs-xs">
97-
<div className="d-flex j-between">
98-
<Message content={m.fleetToken} className="c-text-neutral-semilight" />
99-
<Button
100-
message={sharedMessages.remove}
101-
onClick={handleRemoveFleet}
102-
className="c-text-neutral-light fw-bold hover-underline"
103-
/>
104-
</div>
105-
<Message
106-
content={sharedMessages.fleetTokenInfo}
107-
values={{
108-
Link: val => (
109-
<Link.Anchor secondary href={`${smUrl}/dashboard`} external>
110-
{val}
111-
</Link.Anchor>
112-
),
113-
}}
114-
className="mb-cs-xs mt-cs-xxs c-text-neutral-light fs-s"
115-
component="div"
116-
/>
117-
<Input
118-
type="code"
119-
sensitive
120-
className="w-full"
121-
inputWidth="full"
122-
value={fleetOwnerToken}
123-
onChange={handleFleetTokenChange}
124-
/>
125-
<Message
126-
content={sharedMessages.fleetInfo}
127-
className="mt-cs-xs c-text-neutral-light fs-s"
128-
component="div"
129-
/>
130-
</div>
131-
) : (
132-
<Button
133-
tertiary
134-
message={m.addFleet}
135-
icon={IconPlus}
136-
onClick={handleAddToFleet}
137-
className="mt-cs-xs"
138-
tooltip={m.addToFleetTooltip}
139-
tooltipPlacement="bottom"
140-
/>
141-
)}
142-
</>
143-
)}
58+
{modalDataChildren}
14459
</>
14560
) : (
14661
<ErrorMessage content={invalidMessage} />
@@ -185,6 +100,7 @@ const QRModalButton = props => {
185100
QRModalButton.propTypes = {
186101
invalidMessage: PropTypes.message.isRequired,
187102
message: PropTypes.message.isRequired,
103+
modalDataChildren: PropTypes.node,
188104
onApprove: PropTypes.func.isRequired,
189105
onCancel: PropTypes.func.isRequired,
190106
onRead: PropTypes.func.isRequired,
@@ -195,11 +111,11 @@ QRModalButton.propTypes = {
195111
is_managed: PropTypes.bool,
196112
}),
197113
}),
198-
setQrData: PropTypes.func.isRequired,
199114
}
200115

201116
QRModalButton.defaultProps = {
202117
qrData: undefined,
118+
modalDataChildren: null,
203119
}
204120

205121
export default QRModalButton

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids'
3737
import getHostFromUrl from '@ttn-lw/lib/host-from-url'
3838

3939
const { enabled: gsEnabled, base_url: gsBaseURL } = selectGsConfig()
40+
// TTI only.
4041
const smUrl = selectPluginTTSCloud().subscription_management_url
42+
// End TTI.
4143

4244
const m = defineMessages({
4345
claimWarning:
@@ -55,14 +57,17 @@ const initialValues = {
5557
target_gateway_server_address: gsEnabled ? getHostFromUrl(gsBaseURL) : '',
5658
}
5759

60+
// TTI only.
5861
const ownerTokenTypes = [
5962
{ name: 'gateway', title: sharedMessages.gateway },
6063
{ name: 'fleet', title: m.fleet },
6164
]
65+
// End TTI.
6266

6367
const GatewayClaimFormSection = () => {
6468
const { values, addToFieldRegistry, removeFromFieldRegistry, setValues } = useFormikContext()
6569
const isManaged = values._inputMethod === 'managed'
70+
// TTI only.
6671
const isFleet = values._isFleet
6772

6873
const [activeOwnerTokenType, setActiveOwnerTokenType] = React.useState(
@@ -87,6 +92,7 @@ const GatewayClaimFormSection = () => {
8792
},
8893
[setValues],
8994
)
95+
// End TTI.
9096

9197
// Register hidden fields so they don't get cleaned.
9298
useEffect(() => {
@@ -110,6 +116,7 @@ const GatewayClaimFormSection = () => {
110116
className="mb-0"
111117
/>
112118
</Form.InfoField>
119+
{/** TTI only. */}
113120
<Message content={sharedMessages.ownerToken} className="fw-bold" />
114121
<Tabs
115122
active={activeOwnerTokenType}
@@ -126,15 +133,19 @@ const GatewayClaimFormSection = () => {
126133
component="div"
127134
/>
128135
)}
136+
{/** End TTI. */}
129137
</>
130138
)}
131139
<Form.Field
132140
required
133141
title={sharedMessages.ownerToken}
134-
showTitle={false}
142+
// TTI only.
143+
showTitle={!isManaged}
144+
// End TTI.
135145
name="authenticated_identifiers.authentication_code"
136146
tooltipId={tooltipIds.CLAIM_AUTH_CODE}
137147
component={Input}
148+
// TTI only.
138149
description={activeOwnerTokenType === 'fleet' ? sharedMessages.fleetTokenInfo : undefined}
139150
descriptionValues={{
140151
Link: val => (
@@ -143,6 +154,7 @@ const GatewayClaimFormSection = () => {
143154
</Link.Anchor>
144155
),
145156
}}
157+
// End TTI.
146158
encode={btoa}
147159
decode={atob}
148160
sensitive
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright © 2025 The Things Industries B.V.
2+
3+
import React, { useCallback } from 'react'
4+
import { defineMessages } from 'react-intl'
5+
6+
import { IconPlus } from '@ttn-lw/components/icon'
7+
import Link from '@ttn-lw/components/link'
8+
import Button from '@ttn-lw/components/button'
9+
import Input from '@ttn-lw/components/input'
10+
11+
import Message from '@ttn-lw/lib/components/message'
12+
13+
import sharedMessages from '@ttn-lw/lib/shared-messages'
14+
import { selectPluginTTSCloud } from '@ttn-lw/lib/selectors/env'
15+
import PropTypes from '@ttn-lw/lib/prop-types'
16+
17+
const smUrl = selectPluginTTSCloud().subscription_management_url
18+
19+
const m = defineMessages({
20+
addFleet: 'Add to Fleet',
21+
fleetToken: 'Fleet owner token',
22+
addToFleetTooltip:
23+
'You are registering a Managed gateway. If you want to add it to an existing fleet, click here.',
24+
})
25+
26+
const FleetsScan = ({ qrData, setQrData }) => {
27+
const [isAddToFleet, setIsAddToFleet] = React.useState(undefined)
28+
const [fleetOwnerToken, setFleetOwnerToken] = React.useState('')
29+
30+
const handleAddToFleet = useCallback(() => {
31+
setIsAddToFleet(true)
32+
}, [])
33+
34+
const handleRemoveFleet = useCallback(() => {
35+
setIsAddToFleet(false)
36+
setFleetOwnerToken('')
37+
setQrData({
38+
...qrData,
39+
gateway: { ...qrData.gateway, _fleet_owner_token: undefined },
40+
})
41+
}, [qrData, setQrData])
42+
43+
const handleFleetTokenChange = useCallback(
44+
value => {
45+
setFleetOwnerToken(value)
46+
setQrData({
47+
...qrData,
48+
gateway: { ...qrData.gateway, _fleet_owner_token: value },
49+
})
50+
},
51+
[qrData, setQrData],
52+
)
53+
54+
return qrData.gateway.is_managed ? (
55+
<>
56+
{isAddToFleet ? (
57+
<div className="w-full mt-cs-xs">
58+
<div className="d-flex j-between">
59+
<Message content={m.fleetToken} className="c-text-neutral-semilight" />
60+
<Button
61+
message={sharedMessages.remove}
62+
onClick={handleRemoveFleet}
63+
className="c-text-neutral-light fw-bold hover-underline"
64+
/>
65+
</div>
66+
<Message
67+
content={sharedMessages.fleetTokenInfo}
68+
values={{
69+
Link: val => (
70+
<Link.Anchor secondary href={`${smUrl}/dashboard`} external>
71+
{val}
72+
</Link.Anchor>
73+
),
74+
}}
75+
className="mb-cs-xs mt-cs-xxs c-text-neutral-light fs-s"
76+
component="div"
77+
/>
78+
<Input
79+
type="code"
80+
sensitive
81+
className="w-full"
82+
inputWidth="full"
83+
value={fleetOwnerToken}
84+
onChange={handleFleetTokenChange}
85+
/>
86+
<Message
87+
content={sharedMessages.fleetInfo}
88+
className="mt-cs-xs c-text-neutral-light fs-s"
89+
component="div"
90+
/>
91+
</div>
92+
) : (
93+
<Button
94+
tertiary
95+
message={m.addFleet}
96+
icon={IconPlus}
97+
onClick={handleAddToFleet}
98+
className="mt-cs-xs"
99+
tooltip={m.addToFleetTooltip}
100+
tooltipPlacement="bottom"
101+
/>
102+
)}
103+
</>
104+
) : null
105+
}
106+
107+
FleetsScan.propTypes = {
108+
qrData: PropTypes.shape({
109+
gateway: PropTypes.shape({
110+
is_managed: PropTypes.bool,
111+
}),
112+
}).isRequired,
113+
setQrData: PropTypes.func.isRequired,
114+
}
115+
116+
export default FleetsScan

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import sharedMessages from '@ttn-lw/lib/shared-messages'
3131
import { parseGatewayQRCode } from '@console/store/actions/qr-code-generator'
3232
import { getGatewayClaimInfoByEui } from '@console/store/actions/gateways'
3333

34+
import FleetsScan from './fleets-scan.tti'
35+
3436
const m = defineMessages({
3537
hasGatewayQR:
3638
'Does your gateway have a LoRaWAN® Gateway Identification QR Code? Scan it to speed up onboarding.',
@@ -68,6 +70,7 @@ const GatewayQRScanSection = () => {
6870
},
6971
authenticated_identifiers: {
7072
gateway_eui: gateway.gateway_eui,
73+
// TTI only.
7174
authentication_code: gateway._fleet_owner_token
7275
? btoa(gateway._fleet_owner_token)
7376
: gateway.owner_token
@@ -77,6 +80,7 @@ const GatewayQRScanSection = () => {
7780
_gtw_owner_token: gateway.owner_token ?? '',
7881
_fleet_owner_token: gateway._fleet_owner_token ?? '',
7982
_isFleet: Boolean(gateway._fleet_owner_token),
83+
// End TTI.
8084
}))
8185

8286
setQrData({ ...qrData, approved: true })
@@ -92,8 +96,10 @@ const GatewayQRScanSection = () => {
9296
// Get gateway from QR code
9397
const gateway = await dispatch(attachPromise(parseGatewayQRCode(qrCode)))
9498
const gatewayEui = gateway.gateway_eui
99+
// TTI only.
95100
const { is_managed } = await dispatch(attachPromise(getGatewayClaimInfoByEui(gatewayEui)))
96101
gateway.is_managed = is_managed
102+
// End TTI.
97103

98104
const sheetData = [
99105
{
@@ -164,7 +170,9 @@ const GatewayQRScanSection = () => {
164170
onCancel={handleQRCodeCancel}
165171
onRead={handleQRCodeRead}
166172
qrData={qrData}
167-
setQrData={setQrData}
173+
// TTI only.
174+
modalDataChildren={<FleetsScan qrData={qrData} setQrData={setQrData} />}
175+
// End TTI.
168176
/>
169177
)}
170178
</ButtonGroup>

0 commit comments

Comments
 (0)