Skip to content

Commit

Permalink
Merge pull request #6398 from TheThingsNetwork/fix/class-components
Browse files Browse the repository at this point in the history
Remove MQTT and Device Overview class components
  • Loading branch information
ryaplots authored Jul 18, 2023
2 parents 61247c4 + 090c7a8 commit 37c6bf1
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 421 deletions.
7 changes: 7 additions & 0 deletions pkg/webui/console/store/reducers/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
UPDATE_APP_SUCCESS,
DELETE_APP_SUCCESS,
GET_APP_EVENT_MESSAGE_SUCCESS,
GET_MQTT_INFO_SUCCESS,
} from '@console/store/actions/applications'

const application = (state = {}, application) => ({
Expand All @@ -38,6 +39,7 @@ const defaultState = {
derived: {},
selectedApplication: null,
applicationDeviceCounts: {},
mqtt: {},
}

const applications = (state = defaultState, { type, payload, event }) => {
Expand Down Expand Up @@ -120,6 +122,11 @@ const applications = (state = defaultState, { type, payload, event }) => {
}
}
return state
case GET_MQTT_INFO_SUCCESS:
return {
...state,
mqtt: payload,
}
default:
return state
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('Applications reducer', () => {
derived: {},
selectedApplication: null,
applicationDeviceCounts: {},
mqtt: {},
}

it('returns the initial state', () => {
Expand Down
2 changes: 2 additions & 0 deletions pkg/webui/console/store/selectors/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,5 @@ export const selectApplicationLinkSkipPayloadCrypto = state => {

return link.skip_payload_crypto || false
}

export const selectMqttConnectionInfo = state => selectApplicationStore(state).mqtt
281 changes: 127 additions & 154 deletions pkg/webui/console/views/application-integrations-mqtt/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,36 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React from 'react'
import React, { useCallback, useState } from 'react'
import { Container, Col, Row } from 'react-grid-system'
import { connect } from 'react-redux'
import bind from 'autobind-decorator'
import { useDispatch, useSelector } from 'react-redux'
import { defineMessages } from 'react-intl'
import { useParams } from 'react-router-dom'

import PageTitle from '@ttn-lw/components/page-title'
import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb'
import { withBreadcrumb } from '@ttn-lw/components/breadcrumbs/context'
import { useBreadcrumbs } from '@ttn-lw/components/breadcrumbs/context'
import DataSheet from '@ttn-lw/components/data-sheet'
import Button from '@ttn-lw/components/button'
import Link from '@ttn-lw/components/link'

import Message from '@ttn-lw/lib/components/message'
import ErrorView from '@ttn-lw/lib/components/error-view'
import RequireRequest from '@ttn-lw/lib/components/require-request'

import withFeatureRequirement from '@console/lib/components/with-feature-requirement'
import Require from '@console/lib/components/require'

import SubViewError from '@console/views/sub-view-error'

import attachPromise from '@ttn-lw/lib/store/actions/attach-promise'
import PropTypes from '@ttn-lw/lib/prop-types'
import sharedMessages from '@ttn-lw/lib/shared-messages'

import { mayViewMqttConnectionInfo } from '@console/lib/feature-checks'

import { createApplicationApiKey } from '@console/store/actions/api-keys'
import { getMqttInfo } from '@console/store/actions/applications'

import { selectSelectedApplicationId } from '@console/store/selectors/applications'
import { selectMqttConnectionInfo } from '@console/store/selectors/applications'

const m = defineMessages({
publicAddress: 'Public address',
Expand All @@ -58,161 +58,134 @@ const m = defineMessages({
connectionInfo: 'Connection information',
})

@connect(
state => ({
appId: selectSelectedApplicationId(state),
}),
{
createApiKey: (appId, key) => attachPromise(createApplicationApiKey(appId, key)),
getMqttConnectionInfo: id => attachPromise(getMqttInfo(id)),
},
)
@withFeatureRequirement(mayViewMqttConnectionInfo, {
redirect: ({ appId }) => `/applications/${appId}`,
})
@withBreadcrumb('apps.single.integrations.mqtt', props => {
const { appId } = props
const ApplicationMqtt = () => {
const { appId } = useParams()
const connectionInfo = useSelector(selectMqttConnectionInfo)
const [apiKey, setApiKey] = useState()
const dispatch = useDispatch()

return (
<Breadcrumb path={`/applications/${appId}/integrations/mqtt`} content={sharedMessages.mqtt} />
useBreadcrumbs(
'apps.single.integrations.mqtt',
<Breadcrumb path={`/applications/${appId}/integrations/mqtt`} content={sharedMessages.mqtt} />,
)
})
export default class ApplicationMqtt extends React.Component {
static propTypes = {
appId: PropTypes.string.isRequired,
createApiKey: PropTypes.func.isRequired,
getMqttConnectionInfo: PropTypes.func.isRequired,
}

state = {
connectionInfo: undefined,
}

async componentDidMount() {
const { appId, getMqttConnectionInfo } = this.props
const connectionInfo = await getMqttConnectionInfo(appId)

this.setState({ connectionInfo })
}

@bind
async handleGeneratePasswordClick() {
const { appId, createApiKey } = this.props
const handleGeneratePasswordClick = useCallback(async () => {
const key = {
name: `mqtt-password-key-${Date.now()}`,
rights: ['RIGHT_APPLICATION_TRAFFIC_READ', 'RIGHT_APPLICATION_TRAFFIC_DOWN_WRITE'],
}
const result = await createApiKey(appId, key)

this.setState({
key: result,
})
}

render() {
const { appId } = this.props
const { connectionInfo, key } = this.state
const connectionData = [
{ header: m.host, items: [] },
{ header: m.connectionCredentials, items: [] },
const result = await dispatch(attachPromise(createApplicationApiKey(appId, key)))
setApiKey(result)
}, [appId, dispatch])

const connectionData = [
{ header: m.host, items: [] },
{ header: m.connectionCredentials, items: [] },
]
const fetchingMessage = <Message content={sharedMessages.fetching} />

if (connectionInfo) {
const { public_address, public_tls_address, username } = connectionInfo
connectionData[0].items = [
{
key: m.publicAddress,
type: 'code',
sensitive: false,
value: public_address,
},
{
key: m.publicTlsAddress,
type: 'code',
sensitive: false,
value: public_tls_address,
},
]
const fetchingMessage = <Message content={sharedMessages.fetching} />

if (connectionInfo) {
const { public_address, public_tls_address, username } = connectionInfo
connectionData[0].items = [
{
key: m.publicAddress,
type: 'code',
sensitive: false,
value: public_address,
},
{
key: m.publicTlsAddress,
type: 'code',
sensitive: false,
value: public_tls_address,
},
]
connectionData[1].items = [
{
key: sharedMessages.username,
type: 'code',
sensitive: false,
value: username,
},
]
} else {
connectionData[0].items = [
{
key: m.publicAddress,
value: fetchingMessage,
},
{
key: m.publicTlsAddress,
value: fetchingMessage,
},
]
connectionData[1].items = [
{
key: sharedMessages.username,
value: fetchingMessage,
},
]
}

if (key) {
connectionData[1].items.push({
key: sharedMessages.password,
connectionData[1].items = [
{
key: sharedMessages.username,
type: 'code',
value: key.key,
})
} else {
connectionData[1].items.push({
key: sharedMessages.password,
value: (
<>
<Button
message={m.generateApiKey}
onClick={this.handleGeneratePasswordClick}
className="mr-cs-s"
/>
<Link to={`/applications/${appId}/api-keys`} naked secondary>
<Message content={m.goToApiKeys} />
</Link>
</>
),
})
}

return (
<ErrorView errorRender={SubViewError}>
<Container>
<PageTitle title={sharedMessages.mqtt} />
<Row>
<Col lg={8} md={12}>
<Message content={m.mqttInfoText} className="mt-0" />
<div>
<Message
component="h4"
content={sharedMessages.furtherResources}
className="mb-cs-xxs"
/>
<Link.DocLink path="/integrations/mqtt" secondary>
<Message content={m.mqttServer} />
</Link.DocLink>
{' | '}
<Link.Anchor href="https://www.mqtt.org" external secondary>
<Message content={m.officialMqttWebsite} />
</Link.Anchor>
</div>
<hr className="mb-ls-s" />
<Message content={m.connectionInfo} component="h3" />
<DataSheet data={connectionData} />
</Col>
</Row>
</Container>
</ErrorView>
)
sensitive: false,
value: username,
},
]
} else {
connectionData[0].items = [
{
key: m.publicAddress,
value: fetchingMessage,
},
{
key: m.publicTlsAddress,
value: fetchingMessage,
},
]
connectionData[1].items = [
{
key: sharedMessages.username,
value: fetchingMessage,
},
]
}
if (apiKey) {
connectionData[1].items.push({
key: sharedMessages.password,
type: 'code',
value: apiKey.key,
})
} else {
connectionData[1].items.push({
key: sharedMessages.password,
value: (
<>
<Button
message={m.generateApiKey}
onClick={handleGeneratePasswordClick}
className="mr-cs-s"
/>
<Link to={`/applications/${appId}/api-keys`} naked secondary>
<Message content={m.goToApiKeys} />
</Link>
</>
),
})
}

return (
<RequireRequest requestAction={getMqttInfo(appId)}>
<Require
featureCheck={mayViewMqttConnectionInfo}
otherwise={{ redirect: `/applications/${appId}` }}
>
<ErrorView errorRender={SubViewError}>
<Container>
<PageTitle title={sharedMessages.mqtt} />
<Row>
<Col lg={8} md={12}>
<Message content={m.mqttInfoText} className="mt-0" />
<div>
<Message
component="h4"
content={sharedMessages.furtherResources}
className="mb-cs-xxs"
/>
<Link.DocLink path="/integrations/mqtt" secondary>
<Message content={m.mqttServer} />
</Link.DocLink>
{' | '}
<Link.Anchor href="https://www.mqtt.org" external secondary>
<Message content={m.officialMqttWebsite} />
</Link.Anchor>
</div>
<hr className="mb-ls-s" />
<Message content={m.connectionInfo} component="h3" />
<DataSheet data={connectionData} />
</Col>
</Row>
</Container>
</ErrorView>
</Require>
</RequireRequest>
)
}

export default ApplicationMqtt
Loading

0 comments on commit 37c6bf1

Please sign in to comment.