Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove MQTT and Device Overview class components #6398

Merged
merged 7 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
283 changes: 129 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,38 @@
// 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 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,
selectSelectedApplicationId,
} from '@console/store/selectors/applications'

const m = defineMessages({
publicAddress: 'Public address',
Expand All @@ -58,161 +60,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 = useSelector(selectSelectedApplicationId)
ryaplots marked this conversation as resolved.
Show resolved Hide resolved
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