Add limits to buckets
parent
843dbfe039
commit
6d6a194150
|
@ -6,10 +6,18 @@ import {client} from 'src/utils/api'
|
|||
// Types
|
||||
import {RemoteDataState, AppState, Bucket} from 'src/types'
|
||||
|
||||
// Utils
|
||||
import {isLimitError, extractMessage} from 'src/cloud/utils/limits'
|
||||
|
||||
// Actions
|
||||
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 {
|
||||
bucketCreateFailed,
|
||||
bucketUpdateFailed,
|
||||
|
@ -106,10 +114,15 @@ export const createBucket = (bucket: Bucket) => async (
|
|||
})
|
||||
|
||||
dispatch(addBucket(createdBucket))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(notify(bucketCreateFailed()))
|
||||
throw e
|
||||
dispatch(checkBucketLimits())
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (isLimitError(error)) {
|
||||
const message = extractMessage(error)
|
||||
dispatch(notify(resourceLimitReached('buckets', message)))
|
||||
} else {
|
||||
dispatch(notify(bucketCreateFailed()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +162,7 @@ export const deleteBucket = (id: string, name: string) => async (
|
|||
await client.buckets.delete(id)
|
||||
|
||||
dispatch(removeBucket(id))
|
||||
dispatch(checkBucketLimits())
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(notify(bucketDeleteFailed(name)))
|
||||
|
|
|
@ -6,7 +6,7 @@ import {connect} from 'react-redux'
|
|||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
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 BucketList from 'src/buckets/components/BucketList'
|
||||
import {PrettyBucket} from 'src/buckets/components/BucketRow'
|
||||
|
@ -14,6 +14,10 @@ import CreateBucketOverlay from 'src/buckets/components/CreateBucketOverlay'
|
|||
|
||||
// Actions
|
||||
import {createBucket, updateBucket, deleteBucket} from 'src/buckets/actions'
|
||||
import {
|
||||
checkBucketLimits as checkBucketLimitsAction,
|
||||
LimitStatus,
|
||||
} from 'src/cloud/actions/limits'
|
||||
|
||||
// Utils
|
||||
import {prettyBuckets} from 'src/shared/utils/prettyBucket'
|
||||
|
@ -32,12 +36,14 @@ import {SortTypes} from 'src/shared/utils/sort'
|
|||
interface StateProps {
|
||||
org: Organization
|
||||
buckets: Bucket[]
|
||||
limitStatus: LimitStatus
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
createBucket: typeof createBucket
|
||||
updateBucket: typeof updateBucket
|
||||
deleteBucket: typeof deleteBucket
|
||||
checkBucketLimits: typeof checkBucketLimitsAction
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -66,6 +72,10 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.checkBucketLimits()
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {org, buckets} = this.props
|
||||
const {
|
||||
|
@ -93,6 +103,8 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
color={ComponentColor.Primary}
|
||||
onClick={this.handleOpenModal}
|
||||
testID="Create Bucket"
|
||||
status={this.createButtonStatus}
|
||||
titleText={this.createButtonTitleText}
|
||||
/>
|
||||
</Tabs.TabContentsHeader>
|
||||
<FilterList<PrettyBucket>
|
||||
|
@ -163,6 +175,20 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
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
|
||||
|
||||
|
@ -191,17 +217,25 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const mstp = ({buckets, orgs}: AppState): StateProps => {
|
||||
return {
|
||||
buckets: buckets.list,
|
||||
org: orgs.org,
|
||||
}
|
||||
}
|
||||
const mstp = ({
|
||||
buckets,
|
||||
orgs,
|
||||
cloud: {
|
||||
limits: {
|
||||
buckets: {limitStatus},
|
||||
},
|
||||
},
|
||||
}: AppState): StateProps => ({
|
||||
buckets: buckets.list,
|
||||
org: orgs.org,
|
||||
limitStatus,
|
||||
})
|
||||
|
||||
const mdtp = {
|
||||
createBucket,
|
||||
updateBucket,
|
||||
deleteBucket,
|
||||
checkBucketLimits: checkBucketLimitsAction,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, {}>(
|
||||
|
|
|
@ -15,6 +15,7 @@ import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
|
|||
// Types
|
||||
import {Organization} from '@influxdata/influx'
|
||||
import {AppState} from 'src/types'
|
||||
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
|
||||
|
||||
interface StateProps {
|
||||
org: Organization
|
||||
|
@ -41,8 +42,10 @@ class BucketsIndex extends Component<StateProps> {
|
|||
>
|
||||
<GetResources resource={ResourceTypes.Buckets}>
|
||||
<GetResources resource={ResourceTypes.Telegrafs}>
|
||||
<BucketsTab />
|
||||
{this.props.children}
|
||||
<GetAssetLimits>
|
||||
<BucketsTab />
|
||||
{this.props.children}
|
||||
</GetAssetLimits>
|
||||
</GetResources>
|
||||
</GetResources>
|
||||
</TabbedPageSection>
|
||||
|
|
|
@ -46,9 +46,14 @@ export enum ActionTypes {
|
|||
SetLimits = 'SET_LIMITS',
|
||||
SetLimitsStatus = 'SET_LIMITS_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 {
|
||||
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 {
|
||||
type: ActionTypes.SetLimitsStatus
|
||||
payload: {
|
||||
|
@ -154,3 +173,30 @@ export const checkDashboardLimits = () => (
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ export const limitsReducer = (
|
|||
draftState.dashboards.limitStatus = action.payload.limitStatus
|
||||
return
|
||||
}
|
||||
case ActionTypes.SetBucketLimitStatus: {
|
||||
draftState.buckets.limitStatus = action.payload.limitStatus
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue