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

feat(ui): ability to create a bucket from time machine #17860

Merged
merged 13 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## v2.0.0-beta.10 [Unreleased]

### Features

### Bug Fixes

### UI Improvements

1. [17860](https://github.com/influxdata/influxdb/pull/17860): Allow bucket creation from the Data Explorer and Cell Editor

## v2.0.0-beta.9 [2020-04-23]

### Features
Expand Down
20 changes: 20 additions & 0 deletions ui/cypress/e2e/queryBuilder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ describe('The Query Builder', () => {
cy.getByTestID('cancel-cell-edit--button').click()
cy.contains('Basic Ole Dashboard').should('exist')
})

it('can create a bucket from the buckets list', () => {
cy.get('@org').then((org: Organization) => {
cy.visit(`orgs/${org.id}/data-explorer`)
})

const newBucketName = '٩(。•́‿•̀。)۶'

cy.getByTestID('selector-list add-bucket').click()

cy.getByTestID('bucket-form').should('exist')

cy.getByTestID('bucket-form-name').type(newBucketName)

cy.getByTestID('bucket-form-submit').click()

cy.getByTestID('buckets-list').within(() => {
cy.contains(newBucketName).should('exist')
})
})
})

describe('the group() function', () => {
Expand Down
13 changes: 8 additions & 5 deletions ui/src/buckets/components/BucketOverlayForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import {
ComponentColor,
ComponentStatus,
} from '@influxdata/clockface'
import {RuleType} from 'src/buckets/reducers/createBucket'

interface Props {
name: string
retentionSeconds: number
ruleType: 'expire'
onSubmit: (e: FormEvent<HTMLFormElement>) => void
onCloseModal: () => void
onClose: () => void
onChangeRetentionRule: (seconds: number) => void
onChangeRuleType: (t: 'expire' | null) => void
onChangeRuleType: (t: RuleType) => void
onChangeInput: (e: ChangeEvent<HTMLInputElement>) => void
disableRenaming: boolean
buttonText: string
Expand All @@ -40,7 +41,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
buttonText,
retentionSeconds,
disableRenaming,
onCloseModal,
onClose,
onChangeInput,
onChangeRuleType,
onChangeRetentionRule,
Expand All @@ -50,7 +51,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
const nameInputStatus = disableRenaming && ComponentStatus.Disabled

return (
<Form onSubmit={onSubmit}>
<Form onSubmit={onSubmit} testID="bucket-form">
<Grid>
<Grid.Row>
<Grid.Column>
Expand All @@ -69,6 +70,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
autoFocus={true}
value={name}
onChange={onChangeInput}
testID="bucket-form-name"
/>
)}
</Form.ValidationElement>
Expand All @@ -90,7 +92,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
<Form.Footer>
<Button
text="Cancel"
onClick={onCloseModal}
onClick={onClose}
type={ButtonType.Button}
/>
{buttonText === 'Save Changes' && (
Expand All @@ -102,6 +104,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
)}
<Button
text={buttonText}
testID="bucket-form-submit"
color={this.submitButtonColor}
status={this.submitButtonStatus}
type={ButtonType.Submit}
Expand Down
81 changes: 5 additions & 76 deletions ui/src/buckets/components/BucketsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,21 @@ import {connect} from 'react-redux'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {
Grid,
IconFont,
ComponentSize,
ComponentColor,
Sort,
Button,
EmptyState,
ComponentStatus,
Columns,
Overlay,
} from '@influxdata/clockface'
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
import FilterList from 'src/shared/components/FilterList'
import BucketList from 'src/buckets/components/BucketList'
import CreateBucketOverlay from 'src/buckets/components/CreateBucketOverlay'
import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
import BucketExplainer from 'src/buckets/components/BucketExplainer'
import DemoDataDropdown from 'src/buckets/components/DemoDataDropdown'
import {FeatureFlag} from 'src/shared/utils/featureFlag'
import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown'
import CreateBucketButton from 'src/buckets/components/CreateBucketButton'

// Actions
import {
Expand All @@ -46,24 +41,15 @@ import {
// Utils
import {getNewDemoBuckets} from 'src/cloud/selectors/demodata'
import {extractBucketLimits} from 'src/cloud/utils/limits'
import {getOrg} from 'src/organizations/selectors'
import {getAll} from 'src/resources/selectors'
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
import {SortTypes} from 'src/shared/utils/sort'

// Types
import {
OverlayState,
AppState,
Bucket,
Organization,
ResourceType,
OwnBucket,
} from 'src/types'
import {AppState, Bucket, ResourceType, OwnBucket} from 'src/types'
import {BucketSortKey} from 'src/shared/components/resource_sort_dropdown/generateSortItems'

interface StateProps {
org: Organization
buckets: Bucket[]
limitStatus: LimitStatus
demoDataBuckets: Bucket[]
Expand All @@ -80,7 +66,6 @@ interface DispatchProps {

interface State {
searchTerm: string
overlayState: OverlayState
sortKey: BucketSortKey
sortDirection: Sort
sortType: SortTypes
Expand All @@ -97,7 +82,6 @@ class BucketsTab extends PureComponent<Props, State> {

this.state = {
searchTerm: '',
overlayState: OverlayState.Closed,
sortKey: 'name',
sortDirection: Sort.Ascending,
sortType: SortTypes.String,
Expand All @@ -113,19 +97,12 @@ class BucketsTab extends PureComponent<Props, State> {

public render() {
const {
org,
buckets,
limitStatus,
demoDataBuckets,
getDemoDataBucketMembership,
} = this.props
const {
searchTerm,
overlayState,
sortKey,
sortDirection,
sortType,
} = this.state
const {searchTerm, sortKey, sortDirection, sortType} = this.state

const leftHeaderItems = (
<>
Expand Down Expand Up @@ -155,15 +132,7 @@ class BucketsTab extends PureComponent<Props, State> {
/>
)}
</FeatureFlag>
<Button
text="Create Bucket"
icon={IconFont.Plus}
color={ComponentColor.Primary}
onClick={this.handleOpenModal}
testID="Create Bucket"
status={this.createButtonStatus}
titleText={this.createButtonTitleText}
/>
<CreateBucketButton />
</>
)

Expand Down Expand Up @@ -213,13 +182,6 @@ class BucketsTab extends PureComponent<Props, State> {
</Grid.Column>
</Grid.Row>
</Grid>
<Overlay visible={overlayState === OverlayState.Open}>
<CreateBucketOverlay
org={org}
onCloseModal={this.handleCloseModal}
onCreateBucket={this.handleCreateBucket}
/>
</Overlay>
</>
)
}
Expand All @@ -236,37 +198,10 @@ class BucketsTab extends PureComponent<Props, State> {
this.props.deleteBucket(id, name)
}

private handleCreateBucket = (bucket: OwnBucket) => {
this.props.createBucket(bucket)
this.handleCloseModal()
}

private handleOpenModal = (): void => {
this.setState({overlayState: OverlayState.Open})
}

private handleCloseModal = (): void => {
this.setState({overlayState: OverlayState.Closed})
}

private handleFilterUpdate = (searchTerm: string): void => {
this.setState({searchTerm})
}

private get createButtonStatus(): ComponentStatus {
if (this.props.limitStatus === LimitStatus.EXCEEDED) {
return ComponentStatus.Disabled
}
return ComponentStatus.Default
}

private get createButtonTitleText(): string {
if (this.props.limitStatus === LimitStatus.EXCEEDED) {
return 'This account has the maximum number of buckets allowed'
}
return 'Create a bucket'
}

private get emptyState(): JSX.Element {
const {searchTerm} = this.state

Expand All @@ -276,12 +211,7 @@ class BucketsTab extends PureComponent<Props, State> {
<EmptyState.Text>
Looks like there aren't any <b>Buckets</b>, why not create one?
</EmptyState.Text>
<Button
text="Create Bucket"
icon={IconFont.Plus}
color={ComponentColor.Primary}
onClick={this.handleOpenModal}
/>
<CreateBucketButton />
</EmptyState>
)
}
Expand All @@ -297,7 +227,6 @@ class BucketsTab extends PureComponent<Props, State> {
const mstp = (state: AppState): StateProps => {
const buckets = getAll<Bucket>(state, ResourceType.Buckets)
return {
org: getOrg(state),
buckets,
limitStatus: extractBucketLimits(state.cloud.limits),
demoDataBuckets: getNewDemoBuckets(state, buckets),
Expand Down
97 changes: 97 additions & 0 deletions ui/src/buckets/components/CreateBucketButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Libraries
import React, {FC, useEffect} from 'react'
import {connect} from 'react-redux'

// Components
import {
Button,
IconFont,
ComponentColor,
ComponentStatus,
} from '@influxdata/clockface'

// Actions
import {
checkBucketLimits as checkBucketLimitsAction,
LimitStatus,
} from 'src/cloud/actions/limits'
import {showOverlay, dismissOverlay} from 'src/overlays/actions/overlays'

// Utils
import {extractBucketLimits} from 'src/cloud/utils/limits'

// Types
import {AppState} from 'src/types'

interface StateProps {
limitStatus: LimitStatus
}

interface DispatchProps {
onShowOverlay: typeof showOverlay
onDismissOverlay: typeof dismissOverlay
checkBucketLimits: typeof checkBucketLimitsAction
}

interface OwnProps {}

type Props = OwnProps & StateProps & DispatchProps

const CreateBucketButton: FC<Props> = ({
limitStatus,
checkBucketLimits,
onShowOverlay,
onDismissOverlay,
}) => {
useEffect(() => {
// Check bucket limits when component mounts
checkBucketLimits()
}, [])

const limitExceeded = limitStatus === LimitStatus.EXCEEDED
const text = 'Create Bucket'
let titleText = 'Click to create a bucket'
let buttonStatus = ComponentStatus.Default

if (limitExceeded) {
titleText = 'This account has the maximum number of buckets allowed'
buttonStatus = ComponentStatus.Disabled
}

const handleItemClick = (): void => {
if (limitExceeded) {
return
}

onShowOverlay('create-bucket', null, onDismissOverlay)
}

return (
<Button
icon={IconFont.Plus}
color={ComponentColor.Primary}
text={text}
titleText={titleText}
onClick={handleItemClick}
testID="Create Bucket"
status={buttonStatus}
/>
)
}

const mstp = (state: AppState): StateProps => {
return {
limitStatus: extractBucketLimits(state.cloud.limits),
}
}

const mdtp: DispatchProps = {
onShowOverlay: showOverlay,
onDismissOverlay: dismissOverlay,
checkBucketLimits: checkBucketLimitsAction,
}

export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(CreateBucketButton)
Loading