Merge pull request #11259 from influxdata/feat/add-collector-wizard
feat(ui/dataLoaders): Add new collector from collectors tabpull/11208/head
commit
51b3248303
|
@ -44,6 +44,7 @@ import {
|
|||
DataLoadersState,
|
||||
DataLoaderType,
|
||||
Substep,
|
||||
DataLoaderStep,
|
||||
} from 'src/types/v2/dataLoaders'
|
||||
import {Notification, NotificationFunc} from 'src/types'
|
||||
import {AppState} from 'src/types/v2'
|
||||
|
@ -105,6 +106,7 @@ interface StateProps {
|
|||
currentStepIndex: number
|
||||
substep: Substep
|
||||
username: string
|
||||
selectedBucket: string
|
||||
}
|
||||
|
||||
type Props = OwnProps & StateProps & DispatchProps
|
||||
|
@ -158,7 +160,9 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
visible,
|
||||
bucket,
|
||||
username,
|
||||
onSetBucketInfo,
|
||||
buckets,
|
||||
selectedBucket,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -184,6 +188,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
currentStepIndex={currentStepIndex}
|
||||
onboardingStepProps={this.stepProps}
|
||||
bucketName={_.get(bucket, 'name', '')}
|
||||
selectedBucket={selectedBucket}
|
||||
dataLoaders={dataLoaders}
|
||||
onSetDataLoadersType={onSetDataLoadersType}
|
||||
onUpdateTelegrafPluginConfig={onUpdateTelegrafPluginConfig}
|
||||
|
@ -195,6 +200,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
onAddPluginBundle={onAddPluginBundle}
|
||||
onRemovePluginBundle={onRemovePluginBundle}
|
||||
onSetConfigArrayValue={onSetConfigArrayValue}
|
||||
onSetBucketInfo={onSetBucketInfo}
|
||||
org={_.get(bucket, 'organization', '')}
|
||||
username={username}
|
||||
buckets={buckets}
|
||||
|
@ -274,7 +280,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
const {onSetSubstepIndex, onSetActiveTelegrafPlugin} = this.props
|
||||
|
||||
onSetActiveTelegrafPlugin('')
|
||||
onSetSubstepIndex(0, 'streaming')
|
||||
onSetSubstepIndex(DataLoaderStep.Select, 'streaming')
|
||||
}
|
||||
|
||||
private handleClickSideBarTab = (telegrafPluginID: string) => {
|
||||
|
@ -291,7 +297,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
0
|
||||
)
|
||||
|
||||
onSetSubstepIndex(1, index)
|
||||
onSetSubstepIndex(DataLoaderStep.Configure, index)
|
||||
onSetActiveTelegrafPlugin(telegrafPluginID)
|
||||
}
|
||||
|
||||
|
@ -332,7 +338,7 @@ const mstp = ({
|
|||
links,
|
||||
dataLoading: {
|
||||
dataLoaders,
|
||||
steps: {stepStatuses, currentStep, substep},
|
||||
steps: {stepStatuses, currentStep, substep, bucket},
|
||||
},
|
||||
me: {name},
|
||||
}: AppState): StateProps => ({
|
||||
|
@ -342,6 +348,7 @@ const mstp = ({
|
|||
currentStepIndex: currentStep,
|
||||
substep,
|
||||
username: name,
|
||||
selectedBucket: bucket,
|
||||
})
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
setPluginConfiguration,
|
||||
setConfigArrayValue,
|
||||
} from 'src/onboarding/actions/dataLoaders'
|
||||
import {setBucketInfo} from 'src/onboarding/actions/steps'
|
||||
|
||||
// Types
|
||||
import {DataLoadersState, DataLoaderStep} from 'src/types/v2/dataLoaders'
|
||||
|
@ -43,8 +44,10 @@ interface Props {
|
|||
onAddPluginBundle: typeof addPluginBundleWithPlugins
|
||||
onRemovePluginBundle: typeof removePluginBundleWithPlugins
|
||||
onSetConfigArrayValue: typeof setConfigArrayValue
|
||||
onSetBucketInfo: typeof setBucketInfo
|
||||
org: string
|
||||
username: string
|
||||
selectedBucket: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -68,6 +71,8 @@ class StepSwitcher extends PureComponent<Props> {
|
|||
username,
|
||||
org,
|
||||
buckets,
|
||||
onSetBucketInfo,
|
||||
selectedBucket,
|
||||
} = this.props
|
||||
|
||||
switch (currentStepIndex) {
|
||||
|
@ -77,10 +82,13 @@ class StepSwitcher extends PureComponent<Props> {
|
|||
{...onboardingStepProps}
|
||||
{...dataLoaders}
|
||||
onSetDataLoadersType={onSetDataLoadersType}
|
||||
buckets={buckets}
|
||||
bucket={bucketName}
|
||||
selectedBucket={selectedBucket}
|
||||
onSetActiveTelegrafPlugin={onSetActiveTelegrafPlugin}
|
||||
onAddPluginBundle={onAddPluginBundle}
|
||||
onRemovePluginBundle={onRemovePluginBundle}
|
||||
onSetBucketInfo={onSetBucketInfo}
|
||||
/>
|
||||
)
|
||||
case DataLoaderStep.Configure:
|
||||
|
|
|
@ -70,6 +70,11 @@
|
|||
flex: 1 0 calc(100% - 240px);
|
||||
}
|
||||
|
||||
.wizard-step--group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.onboarding-step {
|
||||
min-width: 100%;
|
||||
|
@ -122,8 +127,8 @@
|
|||
}
|
||||
|
||||
.wizard-step--filter {
|
||||
float:right;
|
||||
padding-bottom: 15px;
|
||||
align-self: flex-end;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
@ -351,4 +356,4 @@
|
|||
.wizard--bookend-step {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import _ from 'lodash'
|
|||
import {
|
||||
writeLineProtocol,
|
||||
createTelegrafConfig,
|
||||
getTelegrafConfigs,
|
||||
updateTelegrafConfig,
|
||||
createScraperTarget,
|
||||
updateScraperTarget,
|
||||
getTelegrafConfig,
|
||||
} from 'src/onboarding/apis/index'
|
||||
|
||||
// Utils
|
||||
|
@ -284,13 +284,11 @@ export const createOrUpdateTelegrafConfigAsync = (authToken: string) => async (
|
|||
) => {
|
||||
const {
|
||||
dataLoading: {
|
||||
dataLoaders: {telegrafPlugins},
|
||||
dataLoaders: {telegrafPlugins, telegrafConfigID},
|
||||
steps: {org, bucket, orgID},
|
||||
},
|
||||
} = getState()
|
||||
|
||||
const telegrafConfigsFromServer = await getTelegrafConfigs(orgID)
|
||||
|
||||
const influxDB2Out = {
|
||||
name: TelegrafPluginOutputInfluxDBV2.NameEnum.InfluxdbV2,
|
||||
type: TelegrafPluginOutputInfluxDBV2.TypeEnum.Output,
|
||||
|
@ -309,6 +307,15 @@ export const createOrUpdateTelegrafConfigAsync = (authToken: string) => async (
|
|||
}
|
||||
})
|
||||
|
||||
if (telegrafConfigID) {
|
||||
const telegrafConfig = await getTelegrafConfig(telegrafConfigID)
|
||||
const id = _.get(telegrafConfig, '0.id', '')
|
||||
|
||||
await updateTelegrafConfig(id, {...telegrafConfig, plugins})
|
||||
dispatch(setTelegrafConfigID(id))
|
||||
return
|
||||
}
|
||||
|
||||
const telegrafRequest: TelegrafRequest = {
|
||||
name: 'new config',
|
||||
agent: {collectionInterval: DEFAULT_COLLECTION_INTERVAL},
|
||||
|
@ -316,14 +323,6 @@ export const createOrUpdateTelegrafConfigAsync = (authToken: string) => async (
|
|||
plugins,
|
||||
}
|
||||
|
||||
if (telegrafConfigsFromServer.length) {
|
||||
const id = _.get(telegrafConfigsFromServer, '0.id', '')
|
||||
|
||||
await updateTelegrafConfig(id, telegrafRequest)
|
||||
dispatch(setTelegrafConfigID(id))
|
||||
return
|
||||
}
|
||||
|
||||
const created = await createTelegrafConfig(telegrafRequest)
|
||||
dispatch(setTelegrafConfigID(created.id))
|
||||
}
|
||||
|
|
|
@ -91,6 +91,18 @@ export const trySources = async (): Promise<boolean> => {
|
|||
}
|
||||
}
|
||||
|
||||
export const getTelegrafConfig = async (
|
||||
telegrafConfigID
|
||||
): Promise<Telegraf> => {
|
||||
try {
|
||||
const response = await telegrafsAPI.telegrafsTelegrafIDGet(telegrafConfigID)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const getTelegrafConfigs = async (org: string): Promise<Telegraf[]> => {
|
||||
try {
|
||||
const data = await telegrafsAPI.telegrafsGet(org)
|
||||
|
|
|
@ -36,6 +36,9 @@ const setup = (override = {}) => {
|
|||
location: null,
|
||||
router: null,
|
||||
routes: [],
|
||||
selectedBucket: '',
|
||||
onSetBucketInfo: jest.fn(),
|
||||
buckets: [],
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
addPluginBundleWithPlugins,
|
||||
removePluginBundleWithPlugins,
|
||||
} from 'src/onboarding/actions/dataLoaders'
|
||||
import {setBucketInfo} from 'src/onboarding/actions/steps'
|
||||
|
||||
// Constants
|
||||
import {StepStatus} from 'src/clockface/constants/wizard'
|
||||
|
@ -28,8 +29,9 @@ import {
|
|||
DataLoaderType,
|
||||
BundleName,
|
||||
} from 'src/types/v2/dataLoaders'
|
||||
import {Bucket} from 'src/api'
|
||||
|
||||
export interface OwnProps extends DataLoaderStepProps {
|
||||
export interface Props extends DataLoaderStepProps {
|
||||
bucket: string
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
pluginBundles: BundleName[]
|
||||
|
@ -39,22 +41,13 @@ export interface OwnProps extends DataLoaderStepProps {
|
|||
onSetDataLoadersType: (type: DataLoaderType) => void
|
||||
onSetActiveTelegrafPlugin: typeof setActiveTelegrafPlugin
|
||||
onSetStepStatus: (index: number, status: StepStatus) => void
|
||||
}
|
||||
|
||||
type Props = OwnProps
|
||||
|
||||
interface State {
|
||||
showStreamingSources: boolean
|
||||
onSetBucketInfo: typeof setBucketInfo
|
||||
buckets: Bucket[]
|
||||
selectedBucket: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
export class SelectDataSourceStep extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {showStreamingSources: false}
|
||||
}
|
||||
|
||||
export class SelectDataSourceStep extends PureComponent<Props> {
|
||||
public componentDidMount() {
|
||||
if (this.isStreaming && this.props.type !== DataLoaderType.Streaming) {
|
||||
this.props.onSetDataLoadersType(DataLoaderType.Streaming)
|
||||
|
@ -121,6 +114,10 @@ export class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
pluginBundles={this.props.pluginBundles}
|
||||
telegrafPlugins={this.props.telegrafPlugins}
|
||||
onTogglePluginBundle={this.handleTogglePluginBundle}
|
||||
buckets={this.props.buckets}
|
||||
bucket={this.props.bucket}
|
||||
selectedBucket={this.props.selectedBucket}
|
||||
onSelectBucket={this.handleSelectBucket}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -132,6 +129,12 @@ export class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleSelectBucket = (bucket: Bucket) => {
|
||||
const {organization, organizationID, id, name} = bucket
|
||||
|
||||
this.props.onSetBucketInfo(organization, organizationID, name, id)
|
||||
}
|
||||
|
||||
private get showSkip(): boolean {
|
||||
const {telegrafPlugins} = this.props
|
||||
if (telegrafPlugins.length < 1) {
|
||||
|
|
|
@ -15,6 +15,10 @@ const setup = (override = {}) => {
|
|||
telegrafPlugins: [],
|
||||
pluginBundles: [],
|
||||
onTogglePluginBundle: jest.fn(),
|
||||
buckets: [],
|
||||
bucket: '',
|
||||
selectedBucket: '',
|
||||
onSelectBucket: jest.fn(),
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
// Libraries
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import uuid from 'uuid'
|
||||
import _ from 'lodash'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import CardSelectCard from 'src/clockface/components/card_select/CardSelectCard'
|
||||
import {GridSizer, Input, IconFont, ComponentSize} from 'src/clockface'
|
||||
import {
|
||||
GridSizer,
|
||||
Input,
|
||||
IconFont,
|
||||
ComponentSize,
|
||||
Dropdown,
|
||||
FormElement,
|
||||
Grid,
|
||||
Columns,
|
||||
} from 'src/clockface'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
|
@ -15,11 +25,16 @@ import {
|
|||
|
||||
// Types
|
||||
import {TelegrafPlugin, BundleName} from 'src/types/v2/dataLoaders'
|
||||
import {Bucket} from 'src/api'
|
||||
|
||||
export interface Props {
|
||||
buckets: Bucket[]
|
||||
bucket: string
|
||||
selectedBucket: string
|
||||
pluginBundles: BundleName[]
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
onTogglePluginBundle: (telegrafPlugin: string, isSelected: boolean) => void
|
||||
onSelectBucket: (bucket: Bucket) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -59,17 +74,31 @@ class StreamingSelector extends PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<div className="wizard-step--grid-container">
|
||||
<div className="wizard-step--filter">
|
||||
<Input
|
||||
size={ComponentSize.Medium}
|
||||
icon={IconFont.Search}
|
||||
widthPixels={290}
|
||||
value={searchTerm}
|
||||
onBlur={this.handleFilterBlur}
|
||||
onChange={this.handleFilterChange}
|
||||
placeholder="Filter Plugins..."
|
||||
/>
|
||||
</div>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthSM={Columns.Five}>
|
||||
<FormElement label="Bucket">
|
||||
<Dropdown
|
||||
selectedID={this.selectedBucketID}
|
||||
onChange={this.handleSelectBucket}
|
||||
>
|
||||
{this.dropdownBuckets}
|
||||
</Dropdown>
|
||||
</FormElement>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthSM={Columns.Five} offsetSM={Columns.Two}>
|
||||
<FormElement label="">
|
||||
<Input
|
||||
customClass={'wizard-step--filter'}
|
||||
size={ComponentSize.Small}
|
||||
icon={IconFont.Search}
|
||||
value={searchTerm}
|
||||
onBlur={this.handleFilterBlur}
|
||||
onChange={this.handleFilterChange}
|
||||
placeholder="Filter Plugins..."
|
||||
/>
|
||||
</FormElement>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
<GridSizer
|
||||
wait={ANIMATION_LENGTH}
|
||||
recalculateFlag={gridSizerUpdateFlag}
|
||||
|
@ -92,6 +121,28 @@ class StreamingSelector extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleSelectBucket = (bucketName: string) => {
|
||||
const bucket = this.props.buckets.find(b => b.name === bucketName)
|
||||
|
||||
this.props.onSelectBucket(bucket)
|
||||
}
|
||||
|
||||
private get selectedBucketID(): string {
|
||||
const {bucket, selectedBucket, buckets} = this.props
|
||||
|
||||
return selectedBucket || bucket || _.get(buckets, '0.name', '')
|
||||
}
|
||||
|
||||
private get dropdownBuckets(): JSX.Element[] {
|
||||
const {buckets} = this.props
|
||||
|
||||
return buckets.map(b => (
|
||||
<Dropdown.Item key={b.name} value={b.name} id={b.name}>
|
||||
{b.name}
|
||||
</Dropdown.Item>
|
||||
))
|
||||
}
|
||||
|
||||
private get filteredBundles(): BundleName[] {
|
||||
const {searchTerm} = this.state
|
||||
|
||||
|
|
|
@ -17,42 +17,56 @@ import {
|
|||
Grid,
|
||||
Columns,
|
||||
} from 'src/clockface'
|
||||
import DataLoadersWizard from 'src/dataLoaders/components/DataLoadersWizard'
|
||||
|
||||
// APIS
|
||||
import {
|
||||
getTelegrafConfigTOML,
|
||||
deleteTelegrafConfig,
|
||||
} from 'src/organizations/apis/index'
|
||||
|
||||
// Actions
|
||||
import * as NotificationsActions from 'src/types/actions/notifications'
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
|
||||
// Constants
|
||||
import {getTelegrafConfigFailed} from 'src/shared/copy/v2/notifications'
|
||||
|
||||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {Telegraf} from 'src/api'
|
||||
import {
|
||||
getTelegrafConfigTOML,
|
||||
deleteTelegrafConfig,
|
||||
} from 'src/organizations/apis/index'
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
|
||||
// Types
|
||||
import {Telegraf, Bucket} from 'src/api'
|
||||
import {DataLoaderType, DataLoaderStep} from 'src/types/v2/dataLoaders'
|
||||
import {OverlayState} from 'src/types/v2'
|
||||
|
||||
interface Props {
|
||||
collectors: Telegraf[]
|
||||
onChange: () => void
|
||||
notify: NotificationsActions.PublishNotificationActionCreator
|
||||
orgName: string
|
||||
buckets: Bucket[]
|
||||
}
|
||||
|
||||
interface State {
|
||||
overlayState: OverlayState
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
export default class Collectors extends PureComponent<Props> {
|
||||
export default class Collectors extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {overlayState: OverlayState.Closed}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {collectors} = this.props
|
||||
const {collectors, buckets} = this.props
|
||||
return (
|
||||
<>
|
||||
<TabbedPageHeader>
|
||||
<h1>Telegraf Configurations</h1>
|
||||
<Button
|
||||
text="Create Configuration"
|
||||
icon={IconFont.Plus}
|
||||
color={ComponentColor.Primary}
|
||||
/>
|
||||
{this.createButton}
|
||||
</TabbedPageHeader>
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
|
@ -74,9 +88,42 @@ export default class Collectors extends PureComponent<Props> {
|
|||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
<DataLoadersWizard
|
||||
visible={this.isOverlayVisible}
|
||||
onCompleteSetup={this.handleDismissDataLoaders}
|
||||
startingType={DataLoaderType.Streaming}
|
||||
startingStep={DataLoaderStep.Select}
|
||||
startingSubstep={'streaming'}
|
||||
buckets={buckets}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get isOverlayVisible(): boolean {
|
||||
return this.state.overlayState === OverlayState.Open
|
||||
}
|
||||
|
||||
private get createButton(): JSX.Element {
|
||||
return (
|
||||
<Button
|
||||
text="Create Configuration"
|
||||
icon={IconFont.Plus}
|
||||
color={ComponentColor.Primary}
|
||||
onClick={this.handleAddScraper}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private handleAddScraper = () => {
|
||||
this.setState({overlayState: OverlayState.Open})
|
||||
}
|
||||
|
||||
private handleDismissDataLoaders = () => {
|
||||
this.setState({overlayState: OverlayState.Closed})
|
||||
this.props.onChange()
|
||||
}
|
||||
|
||||
private get emptyState(): JSX.Element {
|
||||
const {orgName} = this.props
|
||||
|
||||
|
@ -86,11 +133,7 @@ export default class Collectors extends PureComponent<Props> {
|
|||
text={`${orgName} does not own any Telegraf Configurations , why not create one?`}
|
||||
highlightWords={['Telegraf', 'Configurations']}
|
||||
/>
|
||||
<Button
|
||||
text="Create Configuration"
|
||||
icon={IconFont.Plus}
|
||||
color={ComponentColor.Primary}
|
||||
/>
|
||||
{this.createButton}
|
||||
</EmptyState>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -165,12 +165,22 @@ class OrganizationView extends PureComponent<Props> {
|
|||
>
|
||||
{(collectors, loading, fetch) => (
|
||||
<Spinner loading={loading}>
|
||||
<Collectors
|
||||
collectors={collectors}
|
||||
onChange={fetch}
|
||||
notify={notify}
|
||||
orgName={org.name}
|
||||
/>
|
||||
<GetOrgResources<Bucket[]>
|
||||
organization={org}
|
||||
fetcher={getBuckets}
|
||||
>
|
||||
{(buckets, loading) => (
|
||||
<Spinner loading={loading}>
|
||||
<Collectors
|
||||
collectors={collectors}
|
||||
onChange={fetch}
|
||||
notify={notify}
|
||||
buckets={buckets}
|
||||
orgName={org.name}
|
||||
/>
|
||||
</Spinner>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
</Spinner>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
|
|
Loading…
Reference in New Issue