Skip to content

Commit 6492c7b

Browse files
feat(Buckets): Create/Edit forms allow for custom retention periods (#5959)
* chore: commit this for now * feat(Buckets): Create/Edit forms allow for custom retention periods * fix: lint errors * fix: text * feat(Buckets): show full names, (days / months) etc * chore: styles * chore: lint * feat: support plural, remove trailing spaces * feat: plural suppport, dropdown selected bug fix * feat: disallow 0 as input * chore: styling * chore: prettier * feat: some error handling * chore: bring clockface changes in * chore: lint * fix: test * feat: limits for free users * chore: address comments * fix: lint * fix: undo hard coded limit * fix: imports * fix: remove styling glitch * fix: undo limit! * fix: lint
1 parent 9878450 commit 6492c7b

File tree

9 files changed

+265
-72
lines changed

9 files changed

+265
-72
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
"dependencies": {
165165
"@codingame/monaco-jsonrpc": "^0.3.1",
166166
"@docsearch/react": "^3.0.0-alpha.37",
167-
"@influxdata/clockface": "^6.3.7",
167+
"@influxdata/clockface": "^6.3.8",
168168
"@influxdata/flux-lsp-browser": "0.8.35",
169169
"@influxdata/giraffe": "^2.37.0",
170170
"@influxdata/influxdb-templates": "0.9.0",

src/buckets/components/Retention.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, {PureComponent} from 'react'
33
import {connect} from 'react-redux'
44

55
// Components
6-
import {SelectGroup, ButtonShape} from '@influxdata/clockface'
6+
import {SelectGroup, ButtonShape, ComponentStatus} from '@influxdata/clockface'
77
import DurationSelector, {
88
DurationOption,
99
} from 'src/shared/components/DurationSelector'
@@ -43,6 +43,7 @@ interface OwnProps {
4343
onChangeRetentionRule: (seconds: number) => void
4444
onChangeRuleType: (type: 'expire' | null) => void
4545
useSimplifiedForm?: boolean
46+
status?: ComponentStatus
4647
}
4748

4849
type Props = OwnProps & StateProps
@@ -54,6 +55,7 @@ class Retention extends PureComponent<Props> {
5455
maxRetentionSeconds,
5556
type,
5657
useSimplifiedForm = false,
58+
status,
5759
} = this.props
5860

5961
return (
@@ -91,6 +93,7 @@ class Retention extends PureComponent<Props> {
9193
selectedDuration={`${retentionSeconds}s`}
9294
onSelectDuration={this.handleSelectDuration}
9395
durations={this.durations}
96+
status={status}
9497
/>
9598
)}
9699
</>

src/buckets/components/createBucketForm/BucketOverlayForm.tsx

Lines changed: 90 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,44 @@
11
// Libraries
2-
import React, {PureComponent, ChangeEvent, FormEvent} from 'react'
2+
import React, {ChangeEvent, FormEvent, PureComponent} from 'react'
33

44
// Components
5-
import {Form, Input, Button, Accordion, Overlay} from '@influxdata/clockface'
5+
// Types
6+
import {
7+
Accordion,
8+
BannerPanel,
9+
Button,
10+
ButtonType,
11+
ComponentColor,
12+
ComponentSize,
13+
ComponentStatus,
14+
FlexBox,
15+
Form,
16+
Gradients,
17+
InfluxColors,
18+
Input,
19+
JustifyContent,
20+
Overlay,
21+
} from '@influxdata/clockface'
622
import Retention from 'src/buckets/components/Retention'
723
import {SchemaToggle} from 'src/buckets/components/createBucketForm/SchemaToggle'
824

925
// Constants
1026
import {
11-
isSystemBucket,
1227
BUCKET_NAME_MINIMUM_CHARACTERS,
28+
isSystemBucket,
1329
} from 'src/buckets/constants'
14-
15-
// Types
16-
import {
17-
ButtonType,
18-
ComponentColor,
19-
ComponentStatus,
20-
} from '@influxdata/clockface'
2130
import {RuleType} from 'src/buckets/reducers/createBucket'
2231
import {CLOUD} from 'src/shared/constants'
2332

2433
import {
2534
MeasurementSchemaSection,
2635
SchemaUpdateInfo,
2736
} from 'src/buckets/components/createBucketForm/MeasurementSchemaSection'
37+
import {extractBucketMaxRetentionSeconds} from 'src/cloud/utils/limits'
38+
import {AppState} from 'src/types'
39+
import {connect} from 'react-redux'
40+
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
41+
import './BucketOverlayFormStyles.scss'
2842

2943
let MeasurementSchemaList = null,
3044
MeasurementSchemaCreateRequest = null,
@@ -41,7 +55,7 @@ if (CLOUD) {
4155
* need the schemaType that is already set;
4256
* if !isEditing (it is false)
4357
* then need the 'onChangeSchemaType' method*/
44-
interface Props {
58+
interface OwnProps {
4559
name: string
4660
retentionSeconds: number
4761
ruleType: 'expire'
@@ -66,19 +80,27 @@ interface Props {
6680
useSimplifiedBucketForm?: boolean
6781
}
6882

83+
interface StateProps {
84+
maxRetentionSeconds: number
85+
}
86+
87+
type Props = OwnProps & StateProps
88+
6989
interface State {
7090
showAdvanced: boolean
7191
schemaType: 'implicit' | 'explicit'
7292
newMeasurementSchemas: typeof MeasurementSchemaCreateRequest[]
7393
measurementSchemaUpdates: SchemaUpdateInfo[]
94+
retentionPeriodMaxReached: boolean
7495
}
7596

76-
export default class BucketOverlayForm extends PureComponent<Props> {
97+
class BucketOverlayForm extends PureComponent<Props> {
7798
public state: State = {
7899
showAdvanced: false,
79100
schemaType: 'implicit',
80101
newMeasurementSchemas: [],
81102
measurementSchemaUpdates: [],
103+
retentionPeriodMaxReached: false,
82104
}
83105

84106
onChangeSchemaTypeInternal = (newSchemaType: typeof SchemaType) => {
@@ -97,6 +119,7 @@ export default class BucketOverlayForm extends PureComponent<Props> {
97119
this.props.onUpdateMeasurementSchemas(schemas)
98120
this.setState({measurementSchemaUpdates: schemas})
99121
}
122+
private upgradeBannerStyle = {marginBottom: '28px'}
100123

101124
public render() {
102125
const {
@@ -197,21 +220,44 @@ export default class BucketOverlayForm extends PureComponent<Props> {
197220
/>
198221
)}
199222
</Form.ValidationElement>
200-
<Form.Element
223+
<Form.ValidationElement
201224
label={
202225
useSimplifiedBucketForm
203226
? 'Data Retention Preferences'
204227
: 'Delete Data'
205228
}
229+
value={retentionSeconds.toString()}
230+
validationFunc={this.handleRetentionSecondsValidation}
231+
className="retention--dropdown"
206232
>
207-
<Retention
208-
type={ruleType}
209-
retentionSeconds={retentionSeconds}
210-
onChangeRuleType={onChangeRuleType}
211-
onChangeRetentionRule={onChangeRetentionRule}
212-
useSimplifiedForm={useSimplifiedBucketForm}
213-
/>
214-
</Form.Element>
233+
{status => (
234+
<Retention
235+
type={ruleType}
236+
retentionSeconds={retentionSeconds}
237+
onChangeRuleType={onChangeRuleType}
238+
onChangeRetentionRule={onChangeRetentionRule}
239+
useSimplifiedForm={useSimplifiedBucketForm}
240+
status={status}
241+
/>
242+
)}
243+
</Form.ValidationElement>
244+
{this.state.retentionPeriodMaxReached && (
245+
<BannerPanel
246+
size={ComponentSize.ExtraSmall}
247+
gradient={Gradients.PolarExpress}
248+
hideMobileIcon={true}
249+
textColor={InfluxColors.Yeti}
250+
style={this.upgradeBannerStyle}
251+
>
252+
<FlexBox
253+
justifyContent={JustifyContent.SpaceBetween}
254+
stretchToFitWidth={true}
255+
>
256+
<h6>Need retention period more than 30 days?</h6>
257+
<CloudUpgradeButton size={ComponentSize.ExtraSmall} />
258+
</FlexBox>
259+
</BannerPanel>
260+
)}
215261
{useSimplifiedBucketForm ? null : makeAdvancedSection()}
216262
</Overlay.Body>
217263
<Overlay.Footer>
@@ -259,6 +305,19 @@ export default class BucketOverlayForm extends PureComponent<Props> {
259305
return null
260306
}
261307

308+
private handleRetentionSecondsValidation = (value: string): string | null => {
309+
const {maxRetentionSeconds} = this.props
310+
if (Number(value) <= 0) {
311+
return ` `
312+
}
313+
314+
if (maxRetentionSeconds && Number(value) > maxRetentionSeconds) {
315+
this.setState({retentionPeriodMaxReached: true})
316+
return ' '
317+
}
318+
319+
return null
320+
}
262321
private get nameHelpText(): string {
263322
if (this.props.isEditing) {
264323
return 'To rename bucket use the RENAME button below'
@@ -278,13 +337,21 @@ export default class BucketOverlayForm extends PureComponent<Props> {
278337
}
279338

280339
private get submitButtonStatus(): ComponentStatus {
281-
const {name} = this.props
340+
const {name, retentionSeconds} = this.props
282341
const nameHasErrors = this.handleNameValidation(name)
342+
const durationHasErrors = this.handleRetentionSecondsValidation(
343+
retentionSeconds.toString()
344+
)
283345

284-
if (nameHasErrors) {
346+
if (nameHasErrors || durationHasErrors) {
285347
return ComponentStatus.Disabled
286348
}
287349

288350
return ComponentStatus.Default
289351
}
290352
}
353+
const mstp = (state: AppState) => ({
354+
maxRetentionSeconds: extractBucketMaxRetentionSeconds(state),
355+
})
356+
357+
export default connect<StateProps, {}, OwnProps>(mstp)(BucketOverlayForm)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.retention--dropdown {
2+
.cf-form--element-error {
3+
display: none;
4+
}
5+
}

src/shared/components/DurationSelector.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('DurationSelector', () => {
4747
)
4848

4949
expect(
50-
getByText(getByTestId('duration-selector--button'), '1h')
50+
getByText(getByTestId('duration-selector--button'), '1 hour')
5151
).toBeDefined()
5252
})
5353
})

0 commit comments

Comments
 (0)