Update telegrafs in orgs view to use redux

pull/12759/head
Iris Scholten 2019-03-19 12:03:16 -07:00
parent 1797ec6a5e
commit 5bc0ddc67c
9 changed files with 210 additions and 166 deletions

View File

@ -38,8 +38,13 @@ import {
Permission,
} from '@influxdata/influx'
import {Dispatch} from 'redux'
import {addTelegraf} from 'src/telegrafs/actions'
import {addTelegraf, editTelegraf} from 'src/telegrafs/actions'
import {addAuthorization} from 'src/authorizations/actions'
import {notify} from 'src/shared/actions/notifications'
import {
TelegrafConfigCreationError,
TelegrafConfigCreationSuccess,
} from 'src/shared/copy/notifications'
type GetState = () => AppState
@ -365,11 +370,12 @@ export const createOrUpdateTelegrafConfigAsync = () => async (
)
if (telegrafConfigID) {
await client.telegrafConfigs.update(telegrafConfigID, {
const telegraf = await client.telegrafConfigs.update(telegrafConfigID, {
name: telegrafConfigName,
description: telegrafConfigDescription,
plugins,
})
dispatch(editTelegraf(telegraf))
dispatch(setTelegrafConfigID(telegrafConfigID))
return
}
@ -378,78 +384,87 @@ export const createOrUpdateTelegrafConfigAsync = () => async (
}
const createTelegraf = async (dispatch, getState, plugins) => {
const {
dataLoading: {
dataLoaders: {telegrafConfigName, telegrafConfigDescription},
steps: {bucket, orgID, bucketID},
},
} = getState()
const telegrafRequest: TelegrafRequest = {
name: telegrafConfigName,
description: telegrafConfigDescription,
agent: {collectionInterval: DEFAULT_COLLECTION_INTERVAL},
organizationID: orgID,
plugins,
}
// create telegraf config
const tc = await client.telegrafConfigs.create(telegrafRequest)
const permissions = [
{
action: Permission.ActionEnum.Write,
resource: {
type: PermissionResource.TypeEnum.Buckets,
id: bucketID,
orgID,
try {
const {
dataLoading: {
dataLoaders: {telegrafConfigName, telegrafConfigDescription},
steps: {bucket, orgID, bucketID},
},
},
{
action: Permission.ActionEnum.Read,
resource: {type: PermissionResource.TypeEnum.Telegrafs, id: tc.id, orgID},
},
]
} = getState()
const token = {
name: `${telegrafConfigName} token`,
orgID,
description: `WRITE ${bucket} bucket / READ ${telegrafConfigName} telegraf config`,
permissions,
const telegrafRequest: TelegrafRequest = {
name: telegrafConfigName,
description: telegrafConfigDescription,
agent: {collectionInterval: DEFAULT_COLLECTION_INTERVAL},
organizationID: orgID,
plugins,
}
// create telegraf config
const tc = await client.telegrafConfigs.create(telegrafRequest)
const permissions = [
{
action: Permission.ActionEnum.Write,
resource: {
type: PermissionResource.TypeEnum.Buckets,
id: bucketID,
orgID,
},
},
{
action: Permission.ActionEnum.Read,
resource: {
type: PermissionResource.TypeEnum.Telegrafs,
id: tc.id,
orgID,
},
},
]
const token = {
name: `${telegrafConfigName} token`,
orgID,
description: `WRITE ${bucket} bucket / READ ${telegrafConfigName} telegraf config`,
permissions,
}
// create token
const createdToken = await createAuthorization(token)
// add token to data loader state
dispatch(setToken(createdToken.token))
// add token to authorizations state
dispatch(addAuthorization(createdToken))
// create token label
const properties = {
color: '#FFFFFF',
description: `token for telegraf config: ${telegrafConfigName}`,
tokenID: createdToken.id,
} as ILabelProperties // hack to make compiler work
const createdLabel = await client.labels.create({
orgID,
name: '@influxdata.token',
properties,
})
// add label to telegraf config
const label = await client.telegrafConfigs.addLabel(tc.id, createdLabel)
const config = {
...tc,
labels: [label],
}
dispatch(setTelegrafConfigID(tc.id))
dispatch(addTelegraf(config))
dispatch(notify(TelegrafConfigCreationSuccess))
} catch (error) {
dispatch(notify(TelegrafConfigCreationError))
}
// create token
const createdToken = await createAuthorization(token)
// add token to data loader state
dispatch(setToken(createdToken.token))
// add token to authorizations state
dispatch(addAuthorization(createdToken))
// create label
const tokenLabel = {
color: '#FFFFFF',
description: `token for telegraf config: ${telegrafConfigName}`,
tokenID: createdToken.id,
} as ILabelProperties // hack to make compiler work
const createdLabel = await client.labels.create({
orgID,
name: '@influxdata.token',
properties: tokenLabel,
})
// add label to telegraf config
const label = await client.telegrafConfigs.addLabel(tc.id, createdLabel)
const config = {
...tc,
labels: [label],
}
dispatch(setTelegrafConfigID(tc.id))
dispatch(addTelegraf(config))
}
interface SetActiveTelegrafPlugin {

View File

@ -26,7 +26,6 @@ import {notify as notifyAction} from 'src/shared/actions/notifications'
// Constants
import {
TelegrafConfigCreationSuccess,
TelegrafDashboardCreated,
TelegrafDashboardFailed,
} from 'src/shared/copy/notifications'
@ -127,12 +126,10 @@ export class TelegrafPluginInstructions extends PureComponent<Props> {
}
private handleFormSubmit = async () => {
const {onSaveTelegrafConfig, telegrafConfigID, notify} = this.props
const {onSaveTelegrafConfig, telegrafConfigID} = this.props
await onSaveTelegrafConfig()
notify(TelegrafConfigCreationSuccess)
if (!telegrafConfigID) {
this.handleCreateDashboardsForPlugins()
}

View File

@ -1,5 +1,6 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
// Components
import {
@ -21,7 +22,11 @@ import EditableDescription from 'src/shared/components/editable_description/Edit
// Constants
import {DEFAULT_COLLECTOR_NAME} from 'src/dashboards/constants'
interface Props {
// Types
import {AppState} from 'src/types/v2'
import {ILabel} from '@influxdata/influx'
interface OwnProps {
collector: Telegraf
bucket: string
onDelete: (telegraf: Telegraf) => void
@ -31,7 +36,13 @@ interface Props {
onFilterChange: (searchTerm: string) => void
}
export default class CollectorRow extends PureComponent<Props> {
interface StateProps {
labels: ILabel[]
}
type Props = OwnProps & StateProps
class CollectorRow extends PureComponent<Props> {
public render() {
const {collector, bucket} = this.props
@ -106,3 +117,12 @@ export default class CollectorRow extends PureComponent<Props> {
this.props.onOpenInstructions(this.props.collector.id)
}
}
const mstp = ({labels: {list}}: AppState): StateProps => {
return {labels: list}
}
export default connect<StateProps, {}, OwnProps>(
mstp,
null
)(CollectorRow)

View File

@ -20,12 +20,11 @@ import {EmptyState, Grid, Input, InputType, Tabs} from 'src/clockface'
import CollectorsWizard from 'src/dataLoaders/components/collectorsWizard/CollectorsWizard'
import FilterList from 'src/shared/components/Filter'
import NoBucketsWarning from 'src/organizations/components/NoBucketsWarning'
// APIS
import {client} from 'src/utils/api'
import GetLabels from 'src/configuration/components/GetLabels'
// Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import {setBucketInfo} from 'src/dataLoaders/actions/steps'
import {updateTelegraf, deleteTelegraf} from 'src/telegrafs/actions'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
@ -40,17 +39,9 @@ import {
clearDataLoaders,
} from 'src/dataLoaders/actions/dataLoaders'
import {DataLoaderType} from 'src/types/v2/dataLoaders'
import {
telegrafUpdateSuccess,
telegrafUpdateFailed,
telegrafDeleteSuccess,
telegrafDeleteFailed,
} from 'src/shared/copy/v2/notifications'
interface OwnProps {
collectors: Telegraf[]
onChange: () => void
notify: NotificationsActions.PublishNotificationActionCreator
orgName: string
buckets: Bucket[]
}
@ -61,6 +52,8 @@ interface DispatchProps {
onSetTelegrafConfigID: typeof setTelegrafConfigID
onSetTelegrafConfigName: typeof setTelegrafConfigName
onClearDataLoaders: typeof clearDataLoaders
onUpdateTelegraf: typeof updateTelegraf
onDeleteTelegraf: typeof deleteTelegraf
}
type Props = OwnProps & DispatchProps
@ -112,23 +105,25 @@ export class Collectors extends PureComponent<Props, State> {
visible={this.hasNoBuckets}
resourceName="Telegraf Configurations"
/>
<FilterList<Telegraf>
searchTerm={searchTerm}
searchKeys={['plugins.0.config.bucket', 'labels[].name']}
list={collectors}
>
{cs => (
<CollectorList
collectors={cs}
emptyState={this.emptyState}
onDelete={this.handleDeleteTelegraf}
onUpdate={this.handleUpdateTelegraf}
onOpenInstructions={this.handleOpenInstructions}
onOpenTelegrafConfig={this.handleOpenTelegrafConfig}
onFilterChange={this.handleFilterUpdate}
/>
)}
</FilterList>
<GetLabels>
<FilterList<Telegraf>
searchTerm={searchTerm}
searchKeys={['plugins.0.config.bucket', 'labels[].name']}
list={collectors}
>
{cs => (
<CollectorList
collectors={cs}
emptyState={this.emptyState}
onDelete={this.handleDeleteTelegraf}
onUpdate={this.handleUpdateTelegraf}
onOpenInstructions={this.handleOpenInstructions}
onOpenTelegrafConfig={this.handleOpenTelegrafConfig}
onFilterChange={this.handleFilterUpdate}
/>
)}
</FilterList>
</GetLabels>
</Grid.Column>
<Grid.Column
widthSM={Columns.Six}
@ -266,7 +261,6 @@ export class Collectors extends PureComponent<Props, State> {
private handleDismissDataLoaders = () => {
this.setState({dataLoaderOverlay: OverlayState.Closed})
this.props.onChange()
}
private get emptyState(): JSX.Element {
@ -293,27 +287,11 @@ export class Collectors extends PureComponent<Props, State> {
}
private handleDeleteTelegraf = async (telegraf: Telegraf) => {
const {onChange, notify} = this.props
try {
await client.telegrafConfigs.delete(telegraf.id)
onChange()
notify(telegrafDeleteSuccess(telegraf.name))
} catch (e) {
console.error(e)
notify(telegrafDeleteFailed(telegraf.name))
}
await this.props.onDeleteTelegraf(telegraf.id, telegraf.name)
}
private handleUpdateTelegraf = async (telegraf: Telegraf) => {
const {onChange, notify} = this.props
try {
await client.telegrafConfigs.update(telegraf.id, telegraf)
onChange()
notify(telegrafUpdateSuccess(telegraf.name))
} catch (e) {
console.error(e)
notify(telegrafUpdateFailed(telegraf.name))
}
await this.props.onUpdateTelegraf(telegraf)
}
private handleFilterChange = (e: ChangeEvent<HTMLInputElement>): void => {
@ -335,6 +313,8 @@ const mdtp: DispatchProps = {
onSetTelegrafConfigID: setTelegrafConfigID,
onSetTelegrafConfigName: setTelegrafConfigName,
onClearDataLoaders: clearDataLoaders,
onUpdateTelegraf: updateTelegraf,
onDeleteTelegraf: deleteTelegraf,
}
export default connect<null, DispatchProps, OwnProps>(

View File

@ -24,7 +24,7 @@ exports[`CollectorList rendering renders 1`] = `
columnCount={3}
emptyState={<React.Fragment />}
>
<CollectorRow
<Connect(CollectorRow)
bucket=""
collector={
Object {
@ -39,7 +39,7 @@ exports[`CollectorList rendering renders 1`] = `
onOpenTelegrafConfig={[MockFunction]}
onUpdate={[MockFunction]}
/>
<CollectorRow
<Connect(CollectorRow)
bucket=""
collector={
Object {

View File

@ -18,17 +18,16 @@ import GetOrgResources from 'src/organizations/components/GetOrgResources'
// Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
import {getOrgTelegrafs} from 'src/telegrafs/actions'
// Types
import {Bucket, Organization, Telegraf} from '@influxdata/influx'
import {client} from 'src/utils/api'
import {RemoteDataState} from 'src/types'
const getBuckets = async (org: Organization) => {
return client.buckets.getAllByOrg(org.name)
}
const getCollectors = async (org: Organization) => {
return client.telegrafConfigs.getAllByOrg(org)
}
interface RouterProps {
params: {
@ -38,22 +37,44 @@ interface RouterProps {
interface DispatchProps {
notify: NotificationsActions.PublishNotificationActionCreator
getOrgTelegrafs: typeof getOrgTelegrafs
}
interface StateProps {
org: Organization
telegrafs: Telegraf[]
}
type Props = WithRouterProps & RouterProps & DispatchProps & StateProps
interface State {
loading: RemoteDataState
}
@ErrorHandling
class OrgTelegrafsIndex extends Component<Props> {
constructor(props) {
class OrgTelegrafsIndex extends Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = {loading: RemoteDataState.NotStarted}
}
public async componentDidMount() {
const {org} = this.props
this.setState({loading: RemoteDataState.Loading})
try {
await this.props.getOrgTelegrafs(org)
this.setState({loading: RemoteDataState.Done})
} catch (error) {
//TODO: notify of errors
this.setState({loading: RemoteDataState.Error})
}
}
public render() {
const {org, notify} = this.props
const {org, telegrafs} = this.props
const {loading: loadingTelegrafs} = this.state
return (
<Page titleTag={org.name}>
@ -68,37 +89,28 @@ class OrgTelegrafsIndex extends Component<Props> {
url="telegrafs"
title="Telegraf"
>
<GetOrgResources<Telegraf>
organization={org}
fetcher={getCollectors}
<SpinnerContainer
loading={loadingTelegrafs}
spinnerComponent={<TechnoSpinner />}
>
{(collectors, loading, fetch) => (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<GetOrgResources<Bucket>
organization={org}
fetcher={getBuckets}
<GetOrgResources<Bucket>
organization={org}
fetcher={getBuckets}
>
{(buckets, loadingBuckets) => (
<SpinnerContainer
loading={loadingBuckets}
spinnerComponent={<TechnoSpinner />}
>
{(buckets, loading) => (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<Collectors
collectors={collectors}
onChange={fetch}
notify={notify}
buckets={buckets}
orgName={org.name}
/>
</SpinnerContainer>
)}
</GetOrgResources>
</SpinnerContainer>
)}
</GetOrgResources>
<Collectors
collectors={telegrafs}
buckets={buckets}
orgName={org.name}
/>
</SpinnerContainer>
)}
</GetOrgResources>
</SpinnerContainer>
</TabbedPageSection>
</Tabs.TabContents>
</Tabs>
@ -109,16 +121,21 @@ class OrgTelegrafsIndex extends Component<Props> {
}
}
const mstp = (state: AppState, props: WithRouterProps) => {
const {orgs} = state
const mstp = (state: AppState, props: WithRouterProps): StateProps => {
const {
orgs,
telegrafs: {list},
} = state
const org = orgs.find(o => o.id === props.params.orgID)
return {
org,
telegrafs: list,
}
}
const mdtp: DispatchProps = {
notify: notifyActions.notify,
getOrgTelegrafs,
}
export default connect<StateProps, DispatchProps, {}>(

View File

@ -1,15 +1,17 @@
import {ITask as Task} from '@influxdata/influx'
import {ITask as Task, Telegraf} from '@influxdata/influx'
import {Dashboard} from 'src/types/v2'
import {Actions, ActionTypes} from 'src/organizations/actions/orgView'
export interface OrgViewState {
tasks: Task[]
dashboards: Dashboard[]
telegrafs: Telegraf[]
}
const defaultState: OrgViewState = {
tasks: [],
dashboards: [],
telegrafs: [],
}
export default (state = defaultState, action: Actions): OrgViewState => {

View File

@ -8,7 +8,6 @@ interface Props {
id: string
title: string
url: string
children: JSX.Element
}
@ErrorHandling

View File

@ -3,7 +3,7 @@ import {client} from 'src/utils/api'
// Types
import {RemoteDataState} from 'src/types'
import {Telegraf} from '@influxdata/influx'
import {Telegraf, Organization} from '@influxdata/influx'
import {Dispatch} from 'redux-thunk'
// Actions
@ -82,6 +82,20 @@ export const getTelegrafs = () => async (dispatch: Dispatch<Action>) => {
}
}
export const getOrgTelegrafs = (org: Organization) => async dispatch => {
try {
dispatch(setTelegrafs(RemoteDataState.Loading))
const telegrafs = await client.telegrafConfigs.getAllByOrg(org)
dispatch(setTelegrafs(RemoteDataState.Done, telegrafs))
} catch (e) {
console.error(e)
dispatch(setTelegrafs(RemoteDataState.Error))
dispatch(notify(telegrafGetFailed()))
}
}
export const createTelegraf = (telegraf: Telegraf) => async (
dispatch: Dispatch<Action>
) => {