feat(ui/dataLoaders): Add new scraper from scrapers tab
parent
b031e22003
commit
d7f18beaee
|
@ -69,7 +69,11 @@ export interface DataLoaderStepProps {
|
|||
interface OwnProps {
|
||||
onCompleteSetup: () => void
|
||||
visible: boolean
|
||||
bucket: Bucket
|
||||
bucket?: Bucket
|
||||
buckets: Bucket[]
|
||||
startingType?: DataLoaderType
|
||||
startingStep?: number
|
||||
startingSubstep?: Substep
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
|
@ -116,24 +120,22 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
public stepSkippable = [true, true, true]
|
||||
|
||||
public componentDidMount() {
|
||||
const {bucket} = this.props
|
||||
if (bucket) {
|
||||
const {organization, organizationID, name, id} = bucket
|
||||
|
||||
this.props.onSetBucketInfo(organization, organizationID, name, id)
|
||||
}
|
||||
this.handleSetBucketInfo()
|
||||
this.handleSetStartingValues()
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Props) {
|
||||
const {bucket} = this.props
|
||||
const {bucket, buckets} = this.props
|
||||
|
||||
const prevID = _.get(prevProps.bucket, 'id', '')
|
||||
const curID = _.get(bucket, 'id', '')
|
||||
const prevBucket = prevProps.bucket || prevProps.buckets[0]
|
||||
const curBucket = bucket || buckets[0]
|
||||
|
||||
const prevID = _.get(prevBucket, 'id', '')
|
||||
const curID = _.get(curBucket, 'id', '')
|
||||
const isDifferentBucket = prevID !== curID
|
||||
|
||||
if (isDifferentBucket && bucket) {
|
||||
const {organization, organizationID, name, id} = bucket
|
||||
this.props.onSetBucketInfo(organization, organizationID, name, id)
|
||||
if (isDifferentBucket && curBucket) {
|
||||
this.handleSetBucketInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,6 +158,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
visible,
|
||||
bucket,
|
||||
username,
|
||||
buckets,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -194,6 +197,7 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
onSetConfigArrayValue={onSetConfigArrayValue}
|
||||
org={_.get(bucket, 'organization', '')}
|
||||
username={username}
|
||||
buckets={buckets}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -201,10 +205,43 @@ class DataLoadersWizard extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleSetBucketInfo = () => {
|
||||
const {bucket, buckets} = this.props
|
||||
if (bucket || buckets.length) {
|
||||
const b = bucket || buckets[0]
|
||||
const {organization, organizationID, name, id} = b
|
||||
|
||||
this.props.onSetBucketInfo(organization, organizationID, name, id)
|
||||
}
|
||||
}
|
||||
|
||||
private handleSetStartingValues = () => {
|
||||
const {startingStep, startingType, startingSubstep} = this.props
|
||||
|
||||
const hasStartingStep = startingStep || startingStep === 0
|
||||
const hasStartingSubstep = startingSubstep || startingSubstep === 0
|
||||
const hasStartingType =
|
||||
startingType || startingType === DataLoaderType.Empty
|
||||
|
||||
if (hasStartingType) {
|
||||
this.props.onSetDataLoadersType(startingType)
|
||||
}
|
||||
|
||||
if (hasStartingSubstep) {
|
||||
this.props.onSetSubstepIndex(
|
||||
hasStartingStep ? startingStep : 0,
|
||||
startingSubstep
|
||||
)
|
||||
} else if (hasStartingStep) {
|
||||
this.props.onSetCurrentStepIndex(startingStep)
|
||||
}
|
||||
}
|
||||
|
||||
private handleDismiss = () => {
|
||||
this.props.onClearDataLoaders()
|
||||
this.props.onClearSteps()
|
||||
this.props.onCompleteSetup()
|
||||
this.handleSetStartingValues()
|
||||
}
|
||||
|
||||
private get progressHeader(): JSX.Element {
|
||||
|
|
|
@ -23,8 +23,9 @@ import {
|
|||
} from 'src/onboarding/actions/dataLoaders'
|
||||
|
||||
// Types
|
||||
import {DataLoadersState} from 'src/types/v2/dataLoaders'
|
||||
import {DataLoadersState, DataLoaderStep} from 'src/types/v2/dataLoaders'
|
||||
import {DataLoaderStepProps} from 'src/dataLoaders/components/DataLoadersWizard'
|
||||
import {Bucket} from 'src/api'
|
||||
|
||||
interface Props {
|
||||
onboardingStepProps: DataLoaderStepProps
|
||||
|
@ -35,6 +36,7 @@ interface Props {
|
|||
onSetActiveTelegrafPlugin: typeof setActiveTelegrafPlugin
|
||||
onSetPluginConfiguration: typeof setPluginConfiguration
|
||||
bucketName: string
|
||||
buckets: Bucket[]
|
||||
dataLoaders: DataLoadersState
|
||||
currentStepIndex: number
|
||||
onSaveTelegrafConfig: typeof createOrUpdateTelegrafConfigAsync
|
||||
|
@ -65,10 +67,11 @@ class StepSwitcher extends PureComponent<Props> {
|
|||
bucketName,
|
||||
username,
|
||||
org,
|
||||
buckets,
|
||||
} = this.props
|
||||
|
||||
switch (currentStepIndex) {
|
||||
case 0:
|
||||
case DataLoaderStep.Select:
|
||||
return (
|
||||
<SelectDataSourceStep
|
||||
{...onboardingStepProps}
|
||||
|
@ -80,11 +83,12 @@ class StepSwitcher extends PureComponent<Props> {
|
|||
onRemovePluginBundle={onRemovePluginBundle}
|
||||
/>
|
||||
)
|
||||
case 1:
|
||||
case DataLoaderStep.Configure:
|
||||
return (
|
||||
<ConfigureDataSourceStep
|
||||
{...onboardingStepProps}
|
||||
{...dataLoaders}
|
||||
buckets={buckets}
|
||||
bucket={bucketName}
|
||||
username={username}
|
||||
org={org}
|
||||
|
@ -96,7 +100,7 @@ class StepSwitcher extends PureComponent<Props> {
|
|||
onSetConfigArrayValue={onSetConfigArrayValue}
|
||||
/>
|
||||
)
|
||||
case 2:
|
||||
case DataLoaderStep.Verify:
|
||||
return (
|
||||
<VerifyDataStep
|
||||
{...onboardingStepProps}
|
||||
|
|
|
@ -416,11 +416,11 @@ export const saveScraperTarget = () => async (
|
|||
getState: GetState
|
||||
) => {
|
||||
const {
|
||||
onboarding: {bucketID, orgID},
|
||||
dataLoading: {
|
||||
dataLoaders: {
|
||||
scraperTarget: {url, id},
|
||||
},
|
||||
steps: {bucketID, orgID},
|
||||
},
|
||||
} = getState()
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ const setup = (override = {}) => {
|
|||
bucket: '',
|
||||
org: '',
|
||||
username: '',
|
||||
buckets: [],
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
DataLoaderType,
|
||||
ConfigurationState,
|
||||
} from 'src/types/v2/dataLoaders'
|
||||
import {Bucket} from 'src/api'
|
||||
|
||||
export interface OwnProps extends DataLoaderStepProps {
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
|
@ -39,6 +40,7 @@ export interface OwnProps extends DataLoaderStepProps {
|
|||
bucket: string
|
||||
org: string
|
||||
username: string
|
||||
buckets: Bucket[]
|
||||
}
|
||||
|
||||
type Props = OwnProps
|
||||
|
@ -61,11 +63,13 @@ export class ConfigureDataSourceStep extends PureComponent<Props> {
|
|||
bucket,
|
||||
org,
|
||||
username,
|
||||
buckets,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="onboarding-step wizard--skippable">
|
||||
<ConfigureDataSourceSwitcher
|
||||
buckets={buckets}
|
||||
bucket={bucket}
|
||||
org={org}
|
||||
username={username}
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
|
||||
// Types
|
||||
import {TelegrafPlugin, DataLoaderType} from 'src/types/v2/dataLoaders'
|
||||
import {Bucket} from 'src/api'
|
||||
|
||||
export interface Props {
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
|
@ -27,6 +28,7 @@ export interface Props {
|
|||
onAddConfigValue: typeof addConfigValue
|
||||
onRemoveConfigValue: typeof removeConfigValue
|
||||
dataLoaderType: DataLoaderType
|
||||
buckets: Bucket[]
|
||||
bucket: string
|
||||
org: string
|
||||
username: string
|
||||
|
@ -52,6 +54,7 @@ class ConfigureDataSourceSwitcher extends PureComponent<Props> {
|
|||
onClickNext,
|
||||
onClickPrevious,
|
||||
onClickSkip,
|
||||
buckets,
|
||||
} = this.props
|
||||
|
||||
switch (dataLoaderType) {
|
||||
|
@ -85,6 +88,7 @@ class ConfigureDataSourceSwitcher extends PureComponent<Props> {
|
|||
onClickNext={onClickNext}
|
||||
onClickBack={onClickPrevious}
|
||||
onClickSkip={onClickSkip}
|
||||
buckets={buckets}
|
||||
/>
|
||||
)
|
||||
case DataLoaderType.CSV:
|
||||
|
|
|
@ -6,6 +6,7 @@ import {connect} from 'react-redux'
|
|||
import {Form} from 'src/clockface'
|
||||
import FancyScrollbar from 'src/shared/components/fancy_scrollbar/FancyScrollbar'
|
||||
import OnboardingButtons from 'src/onboarding/components/OnboardingButtons'
|
||||
import ScraperTarget from 'src/onboarding/components/configureStep/ScraperTarget'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
|
@ -13,13 +14,16 @@ import {
|
|||
setScraperTargetURL,
|
||||
saveScraperTarget,
|
||||
} from 'src/onboarding/actions/dataLoaders'
|
||||
|
||||
// Types
|
||||
import {Bucket} from 'src/api'
|
||||
import {AppState} from 'src/types/v2/index'
|
||||
import ScraperTarget from 'src/onboarding/components/configureStep/ScraperTarget'
|
||||
|
||||
interface OwnProps {
|
||||
onClickNext: () => void
|
||||
onClickBack: () => void
|
||||
onClickSkip: () => void
|
||||
buckets: Bucket[]
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
|
@ -29,7 +33,7 @@ interface DispatchProps {
|
|||
}
|
||||
|
||||
interface StateProps {
|
||||
bucket: string
|
||||
scraperBucket: string
|
||||
url: string
|
||||
currentBucket: string
|
||||
}
|
||||
|
@ -38,15 +42,21 @@ type Props = OwnProps & DispatchProps & StateProps
|
|||
|
||||
export class Scraping extends PureComponent<Props> {
|
||||
public componentDidMount() {
|
||||
const {bucket, currentBucket, onSetScraperTargetBucket} = this.props
|
||||
if (!bucket) {
|
||||
onSetScraperTargetBucket(currentBucket)
|
||||
const {
|
||||
buckets,
|
||||
scraperBucket,
|
||||
currentBucket,
|
||||
onSetScraperTargetBucket,
|
||||
} = this.props
|
||||
|
||||
if (!scraperBucket) {
|
||||
onSetScraperTargetBucket(currentBucket || buckets[0].name)
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
bucket,
|
||||
scraperBucket,
|
||||
onClickBack,
|
||||
onClickSkip,
|
||||
onSetScraperTargetURL,
|
||||
|
@ -64,7 +74,7 @@ export class Scraping extends PureComponent<Props> {
|
|||
and to write to a bucket
|
||||
</h5>
|
||||
<ScraperTarget
|
||||
bucket={bucket}
|
||||
bucket={scraperBucket}
|
||||
buckets={this.buckets}
|
||||
onSelectBucket={this.handleSelectBucket}
|
||||
onChangeURL={onSetScraperTargetURL}
|
||||
|
@ -85,9 +95,9 @@ export class Scraping extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private get buckets(): string[] {
|
||||
const {currentBucket} = this.props
|
||||
const {buckets} = this.props
|
||||
|
||||
return currentBucket ? [currentBucket] : []
|
||||
return buckets.map(b => b.name)
|
||||
}
|
||||
|
||||
private handleSelectBucket = (bucket: string) => {
|
||||
|
@ -109,7 +119,7 @@ const mstp = ({
|
|||
}: AppState): StateProps => {
|
||||
return {
|
||||
currentBucket: bucket,
|
||||
bucket: scraperTarget.bucket,
|
||||
scraperBucket: scraperTarget.bucket,
|
||||
url: scraperTarget.url,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {OverlayTechnology, IndexList} from 'src/clockface'
|
|||
// Types
|
||||
import {OverlayState} from 'src/types/v2'
|
||||
import DataLoadersWizard from 'src/dataLoaders/components/DataLoadersWizard'
|
||||
import {DataLoaderStep, DataLoaderType} from 'src/types/v2/dataLoaders'
|
||||
|
||||
interface Props {
|
||||
buckets: PrettyBucket[]
|
||||
|
@ -68,6 +69,10 @@ export default class BucketList extends PureComponent<Props, State> {
|
|||
visible={this.isDataLoadersWizardVisible}
|
||||
onCompleteSetup={this.handleDismissDataLoaders}
|
||||
bucket={this.bucket}
|
||||
buckets={buckets}
|
||||
startingStep={DataLoaderStep.Select}
|
||||
startingSubstep={0}
|
||||
startingType={DataLoaderType.Empty}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@ interface Props {
|
|||
onDelete: (telegrafID: string) => void
|
||||
}
|
||||
|
||||
export default class BucketList extends PureComponent<Props> {
|
||||
export default class CollectorList extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {emptyState} = this.props
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ export default class ScraperList extends PureComponent<Props> {
|
|||
<>
|
||||
<IndexList>
|
||||
<IndexList.Header>
|
||||
<IndexList.HeaderCell columnName="Name" width="50%" />
|
||||
<IndexList.HeaderCell columnName="URL" width="50%" />
|
||||
<IndexList.HeaderCell columnName="Bucket" width="50%" />
|
||||
</IndexList.Header>
|
||||
<IndexList.Body columnCount={3} emptyState={emptyState}>
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class ScraperRow extends PureComponent<Props> {
|
|||
return (
|
||||
<>
|
||||
<IndexList.Row>
|
||||
<IndexList.Cell>{scraper.name}</IndexList.Cell>
|
||||
<IndexList.Cell>{scraper.url}</IndexList.Cell>
|
||||
<IndexList.Cell>{scraper.bucket}</IndexList.Cell>
|
||||
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
|
||||
<ConfirmationButton
|
||||
|
|
|
@ -14,40 +14,83 @@ import {
|
|||
ComponentSize,
|
||||
EmptyState,
|
||||
} from 'src/clockface'
|
||||
import DataLoadersWizard from 'src/dataLoaders/components/DataLoadersWizard'
|
||||
|
||||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {ScraperTargetResponses, ScraperTargetResponse} from 'src/api'
|
||||
|
||||
// Types
|
||||
import {ScraperTargetResponses, ScraperTargetResponse, Bucket} from 'src/api'
|
||||
import {OverlayState} from 'src/types/v2'
|
||||
import {DataLoaderType, DataLoaderStep} from 'src/types/v2/dataLoaders'
|
||||
|
||||
interface Props {
|
||||
scrapers: ScraperTargetResponses
|
||||
onChange: () => void
|
||||
orgName: string
|
||||
buckets: Bucket[]
|
||||
}
|
||||
|
||||
interface State {
|
||||
overlayState: OverlayState
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
export default class OrgOptions extends PureComponent<Props> {
|
||||
export default class Scrapers extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {overlayState: OverlayState.Closed}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {scrapers} = this.props
|
||||
const {scrapers, buckets} = this.props
|
||||
return (
|
||||
<>
|
||||
<TabbedPageHeader>
|
||||
<h1>Scrapers</h1>
|
||||
<Button
|
||||
text="Create Scraper"
|
||||
icon={IconFont.Plus}
|
||||
color={ComponentColor.Primary}
|
||||
/>
|
||||
{this.createScraperButton}
|
||||
</TabbedPageHeader>
|
||||
<ScraperList
|
||||
scrapers={scrapers}
|
||||
emptyState={this.emptyState}
|
||||
onDeleteScraper={this.handleDeleteScraper}
|
||||
/>
|
||||
<DataLoadersWizard
|
||||
visible={this.isOverlayVisible}
|
||||
onCompleteSetup={this.handleDismissDataLoaders}
|
||||
startingType={DataLoaderType.Scraping}
|
||||
startingStep={DataLoaderStep.Configure}
|
||||
buckets={buckets}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get isOverlayVisible(): boolean {
|
||||
return this.state.overlayState === OverlayState.Open
|
||||
}
|
||||
|
||||
private get createScraperButton(): JSX.Element {
|
||||
return (
|
||||
<Button
|
||||
text="Create Scraper"
|
||||
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
|
||||
return (
|
||||
|
@ -55,11 +98,7 @@ export default class OrgOptions extends PureComponent<Props> {
|
|||
<EmptyState.Text
|
||||
text={`${orgName} does not own any scrapers, why not create one?`}
|
||||
/>
|
||||
<Button
|
||||
text="Create Scraper"
|
||||
icon={IconFont.Plus}
|
||||
color={ComponentColor.Primary}
|
||||
/>
|
||||
{this.createScraperButton}
|
||||
</EmptyState>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -180,11 +180,21 @@ class OrganizationView extends PureComponent<Props> {
|
|||
>
|
||||
{(scrapers, loading, fetch) => (
|
||||
<Spinner loading={loading}>
|
||||
<Scrapers
|
||||
scrapers={scrapers}
|
||||
onChange={fetch}
|
||||
orgName={org.name}
|
||||
/>
|
||||
<GetOrgResources<Bucket[]>
|
||||
organization={org}
|
||||
fetcher={getBuckets}
|
||||
>
|
||||
{(buckets, loading) => (
|
||||
<Spinner loading={loading}>
|
||||
<Scrapers
|
||||
scrapers={scrapers}
|
||||
onChange={fetch}
|
||||
orgName={org.name}
|
||||
buckets={buckets}
|
||||
/>
|
||||
</Spinner>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
</Spinner>
|
||||
)}
|
||||
</GetOrgResources>
|
||||
|
|
|
@ -37,6 +37,12 @@ import {
|
|||
import {RemoteDataState} from 'src/types'
|
||||
import {WritePrecision} from 'src/api'
|
||||
|
||||
export enum DataLoaderStep {
|
||||
'Select',
|
||||
'Configure',
|
||||
'Verify',
|
||||
}
|
||||
|
||||
interface ScraperTarget {
|
||||
bucket: string
|
||||
url: string
|
||||
|
|
Loading…
Reference in New Issue