Add limits to buckets

pull/13613/head
Deniz Kusefoglu 2019-04-24 10:48:44 -07:00
parent 843dbfe039
commit 6d6a194150
5 changed files with 116 additions and 15 deletions

View File

@ -6,10 +6,18 @@ import {client} from 'src/utils/api'
// Types // Types
import {RemoteDataState, AppState, Bucket} from 'src/types' import {RemoteDataState, AppState, Bucket} from 'src/types'
// Utils
import {isLimitError, extractMessage} from 'src/cloud/utils/limits'
// Actions // Actions
import {notify} from 'src/shared/actions/notifications' import {notify} from 'src/shared/actions/notifications'
import {getBucketsFailed} from 'src/shared/copy/notifications' import {checkBucketLimits} from 'src/cloud/actions/limits'
// Constants
import {
getBucketsFailed,
resourceLimitReached,
} from 'src/shared/copy/notifications'
import { import {
bucketCreateFailed, bucketCreateFailed,
bucketUpdateFailed, bucketUpdateFailed,
@ -106,10 +114,15 @@ export const createBucket = (bucket: Bucket) => async (
}) })
dispatch(addBucket(createdBucket)) dispatch(addBucket(createdBucket))
} catch (e) { dispatch(checkBucketLimits())
console.error(e) } catch (error) {
console.error(error)
if (isLimitError(error)) {
const message = extractMessage(error)
dispatch(notify(resourceLimitReached('buckets', message)))
} else {
dispatch(notify(bucketCreateFailed())) dispatch(notify(bucketCreateFailed()))
throw e }
} }
} }
@ -149,6 +162,7 @@ export const deleteBucket = (id: string, name: string) => async (
await client.buckets.delete(id) await client.buckets.delete(id)
dispatch(removeBucket(id)) dispatch(removeBucket(id))
dispatch(checkBucketLimits())
} catch (e) { } catch (e) {
console.error(e) console.error(e)
dispatch(notify(bucketDeleteFailed(name))) dispatch(notify(bucketDeleteFailed(name)))

View File

@ -6,7 +6,7 @@ import {connect} from 'react-redux'
// Components // Components
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
import {Input, Button, EmptyState} from '@influxdata/clockface' import {Input, Button, EmptyState} from '@influxdata/clockface'
import {Overlay, Tabs} from 'src/clockface' import {Overlay, Tabs, ComponentStatus} from 'src/clockface'
import FilterList from 'src/shared/components/Filter' import FilterList from 'src/shared/components/Filter'
import BucketList from 'src/buckets/components/BucketList' import BucketList from 'src/buckets/components/BucketList'
import {PrettyBucket} from 'src/buckets/components/BucketRow' import {PrettyBucket} from 'src/buckets/components/BucketRow'
@ -14,6 +14,10 @@ import CreateBucketOverlay from 'src/buckets/components/CreateBucketOverlay'
// Actions // Actions
import {createBucket, updateBucket, deleteBucket} from 'src/buckets/actions' import {createBucket, updateBucket, deleteBucket} from 'src/buckets/actions'
import {
checkBucketLimits as checkBucketLimitsAction,
LimitStatus,
} from 'src/cloud/actions/limits'
// Utils // Utils
import {prettyBuckets} from 'src/shared/utils/prettyBucket' import {prettyBuckets} from 'src/shared/utils/prettyBucket'
@ -32,12 +36,14 @@ import {SortTypes} from 'src/shared/utils/sort'
interface StateProps { interface StateProps {
org: Organization org: Organization
buckets: Bucket[] buckets: Bucket[]
limitStatus: LimitStatus
} }
interface DispatchProps { interface DispatchProps {
createBucket: typeof createBucket createBucket: typeof createBucket
updateBucket: typeof updateBucket updateBucket: typeof updateBucket
deleteBucket: typeof deleteBucket deleteBucket: typeof deleteBucket
checkBucketLimits: typeof checkBucketLimitsAction
} }
interface State { interface State {
@ -66,6 +72,10 @@ class BucketsTab extends PureComponent<Props, State> {
} }
} }
public componentDidMount() {
this.props.checkBucketLimits()
}
public render() { public render() {
const {org, buckets} = this.props const {org, buckets} = this.props
const { const {
@ -93,6 +103,8 @@ class BucketsTab extends PureComponent<Props, State> {
color={ComponentColor.Primary} color={ComponentColor.Primary}
onClick={this.handleOpenModal} onClick={this.handleOpenModal}
testID="Create Bucket" testID="Create Bucket"
status={this.createButtonStatus}
titleText={this.createButtonTitleText}
/> />
</Tabs.TabContentsHeader> </Tabs.TabContentsHeader>
<FilterList<PrettyBucket> <FilterList<PrettyBucket>
@ -163,6 +175,20 @@ class BucketsTab extends PureComponent<Props, State> {
this.setState({searchTerm}) 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 { private get emptyState(): JSX.Element {
const {searchTerm} = this.state const {searchTerm} = this.state
@ -191,17 +217,25 @@ class BucketsTab extends PureComponent<Props, State> {
} }
} }
const mstp = ({buckets, orgs}: AppState): StateProps => { const mstp = ({
return { buckets,
orgs,
cloud: {
limits: {
buckets: {limitStatus},
},
},
}: AppState): StateProps => ({
buckets: buckets.list, buckets: buckets.list,
org: orgs.org, org: orgs.org,
} limitStatus,
} })
const mdtp = { const mdtp = {
createBucket, createBucket,
updateBucket, updateBucket,
deleteBucket, deleteBucket,
checkBucketLimits: checkBucketLimitsAction,
} }
export default connect<StateProps, DispatchProps, {}>( export default connect<StateProps, DispatchProps, {}>(

View File

@ -15,6 +15,7 @@ import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
// Types // Types
import {Organization} from '@influxdata/influx' import {Organization} from '@influxdata/influx'
import {AppState} from 'src/types' import {AppState} from 'src/types'
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
interface StateProps { interface StateProps {
org: Organization org: Organization
@ -41,8 +42,10 @@ class BucketsIndex extends Component<StateProps> {
> >
<GetResources resource={ResourceTypes.Buckets}> <GetResources resource={ResourceTypes.Buckets}>
<GetResources resource={ResourceTypes.Telegrafs}> <GetResources resource={ResourceTypes.Telegrafs}>
<GetAssetLimits>
<BucketsTab /> <BucketsTab />
{this.props.children} {this.props.children}
</GetAssetLimits>
</GetResources> </GetResources>
</GetResources> </GetResources>
</TabbedPageSection> </TabbedPageSection>

View File

@ -46,9 +46,14 @@ export enum ActionTypes {
SetLimits = 'SET_LIMITS', SetLimits = 'SET_LIMITS',
SetLimitsStatus = 'SET_LIMITS_STATUS', SetLimitsStatus = 'SET_LIMITS_STATUS',
SetDashboardLimitStatus = 'SET_DASHBOARD_LIMIT_STATUS', SetDashboardLimitStatus = 'SET_DASHBOARD_LIMIT_STATUS',
SetBucketLimitStatus = 'SET_BUCKET_LIMIT_STATUS',
} }
export type Actions = SetLimits | SetLimitsStatus | SetDashboardLimitStatus export type Actions =
| SetLimits
| SetLimitsStatus
| SetDashboardLimitStatus
| SetBucketLimitStatus
export interface SetLimits { export interface SetLimits {
type: ActionTypes.SetLimits type: ActionTypes.SetLimits
@ -76,6 +81,20 @@ export const setDashboardLimitStatus = (
} }
} }
export interface SetBucketLimitStatus {
type: ActionTypes.SetBucketLimitStatus
payload: {limitStatus: LimitStatus}
}
export const setBucketLimitStatus = (
limitStatus: LimitStatus
): SetBucketLimitStatus => {
return {
type: ActionTypes.SetBucketLimitStatus,
payload: {limitStatus},
}
}
export interface SetLimitsStatus { export interface SetLimitsStatus {
type: ActionTypes.SetLimitsStatus type: ActionTypes.SetLimitsStatus
payload: { payload: {
@ -154,3 +173,30 @@ export const checkDashboardLimits = () => (
console.error(e) console.error(e)
} }
} }
export const checkBucketLimits = () => async (
dispatch,
getState: () => AppState
) => {
try {
const {
buckets: {list},
cloud: {
limits: {
buckets: {maxAllowed},
},
},
} = getState()
const bucketsCount = list.length
if (maxAllowed <= bucketsCount) {
dispatch(setBucketLimitStatus(LimitStatus.EXCEEDED))
dispatch(notify(resourceLimitReached('buckets')))
} else {
dispatch(setBucketLimitStatus(LimitStatus.OK))
}
} catch (e) {
console.error(e)
}
}

View File

@ -57,6 +57,10 @@ export const limitsReducer = (
draftState.dashboards.limitStatus = action.payload.limitStatus draftState.dashboards.limitStatus = action.payload.limitStatus
return return
} }
case ActionTypes.SetBucketLimitStatus: {
draftState.buckets.limitStatus = action.payload.limitStatus
return
}
} }
}) })