Skip to content

Commit 99e4a67

Browse files
authored
fix(4669/4671/4696/4697): template notebook generated from bucket, must also include retentionRules. (#4718)
When we generate a new notebook from a template using a referenced bucket, then we need to fetch and populate the associated bucket within the initial notebooks crud object. Otherwise, additional code downstream which relies upon this bucket object will error (in this specific case, the `bucket.retentionRules` was missing).
1 parent a33d5cb commit 99e4a67

File tree

5 files changed

+128
-42
lines changed

5 files changed

+128
-42
lines changed

cypress/e2e/shared/buckets.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,72 @@ describe('Buckets', () => {
164164
})
165165
})
166166

167+
describe('explore a newly created bucket', () => {
168+
beforeEach(() => {
169+
cy.setFeatureFlags({
170+
exploreWithFlows: true,
171+
})
172+
})
173+
it('with redirect to notebooks', () => {
174+
const newBucket = 'Bucket for templating'
175+
cy.getByTestID(`bucket--card--name ${newBucket}`).should('not.exist')
176+
177+
cy.getByTestID('Create Bucket').click()
178+
cy.getByTestID('overlay--container').within(() => {
179+
cy.getByInputName('name').type(newBucket)
180+
cy.get('.cf-button')
181+
.contains('Create')
182+
.click()
183+
})
184+
185+
cy.getByTestID(`bucket--card--name ${newBucket}`)
186+
.should('exist')
187+
.click()
188+
189+
cy.getByTestID('page-title').contains(newBucket)
190+
})
191+
it('with notebooks using the bucket crud object', () => {
192+
const newBucket = 'Bucket for templating 1'
193+
cy.getByTestID(`bucket--card--name ${newBucket}`).should('not.exist')
194+
195+
cy.getByTestID('Create Bucket').click()
196+
cy.getByTestID('overlay--container').within(() => {
197+
cy.getByInputName('name').type(newBucket)
198+
cy.get('.cf-button')
199+
.contains('Create')
200+
.click()
201+
})
202+
203+
cy.getByTestID(`bucket--card--name ${newBucket}`).should('exist')
204+
cy.log('Bucket created')
205+
206+
cy.intercept('PATCH', '/api/v2private/notebooks/*').as('updateNotebook')
207+
208+
cy.getByTestID(`bucket--card--name ${newBucket}`)
209+
.parent()
210+
.parent()
211+
.within(() => {
212+
cy.get('.copy-bucket-id')
213+
.invoke('text')
214+
.then(text => {
215+
const bucketId = text.split('ID:')[0].trim()
216+
cy.getByTestID(`bucket--card--name ${newBucket}`)
217+
.should('exist')
218+
.click()
219+
220+
cy.wait('@updateNotebook').then(interception => {
221+
expect(JSON.stringify(interception.response?.body)).to.include(
222+
newBucket
223+
)
224+
expect(JSON.stringify(interception.response?.body)).to.include(
225+
bucketId
226+
)
227+
})
228+
})
229+
})
230+
})
231+
})
232+
167233
describe('routing directly to the edit overlay', () => {
168234
it('reroutes to buckets view if bucket does not exist', () => {
169235
cy.get('@org').then(({id}: Organization) => {

src/buckets/components/BucketCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const BucketCard: FC<Props & RouteComponentProps<{orgID: string}>> = ({
3838
}) => {
3939
const handleNameClick = () => {
4040
if (isFlagEnabled('exploreWithFlows')) {
41-
history.push(`/${PROJECT_NAME.toLowerCase()}/from/bucket/${bucket.name}`)
41+
history.push(
42+
`/${PROJECT_NAME.toLowerCase()}/from/bucket/${bucket.name}/${bucket.id}`
43+
)
4244
} else {
4345
history.push(`/orgs/${orgID}/data-explorer?bucket=${bucket.name}`)
4446
}

src/flows/pipes/QueryBuilder/BucketSelector.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,10 @@ const BucketSelector: FC = () => {
2525
return
2626
}
2727
const allBuckets = new Set(buckets.map(b => b.name))
28-
data.buckets
29-
.filter(b => !allBuckets.has(b.name))
30-
.forEach(b => {
31-
addBucket({
32-
name: b.name,
33-
type: b.type,
34-
} as Bucket)
35-
})
28+
const missingBuckets = data.buckets.filter(b => !allBuckets.has(b.name))
29+
missingBuckets.forEach(b => {
30+
addBucket(b as Bucket)
31+
})
3632
}, [loading, buckets, data.buckets])
3733

3834
if (loading === RemoteDataState.Done && !buckets.length) {
Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,61 @@
11
import {DEFAULT_TIME_RANGE} from 'src/shared/constants/timeRanges'
22
import {AUTOREFRESH_DEFAULT} from 'src/shared/constants'
33
import {PIPE_DEFINITIONS} from 'src/flows'
4+
import {getBucket, getBuckets, Buckets} from 'src/client'
45

56
export default register =>
67
register({
78
type: 'bucket',
8-
init: name =>
9-
Promise.resolve({
10-
name: `Explore the ${name} bucket`,
11-
spec: {
12-
readOnly: false,
13-
range: DEFAULT_TIME_RANGE,
14-
refresh: AUTOREFRESH_DEFAULT,
15-
pipes: [
16-
{
17-
type: 'queryBuilder',
18-
title: 'Build a Query',
19-
visible: true,
20-
...JSON.parse(
21-
JSON.stringify(PIPE_DEFINITIONS['queryBuilder'].initial)
22-
),
23-
buckets: [{name, type: 'user'}],
9+
init: (name: string, bucketID: string | undefined) =>
10+
getBucket({bucketID})
11+
.then(res => {
12+
if (res.status == 200) {
13+
return Promise.resolve({
14+
...res,
15+
data: {buckets: [res.data]} as Buckets,
16+
})
17+
}
18+
return getBuckets({query: {name}})
19+
})
20+
.then(res => {
21+
// handle both get request payloads
22+
const data = (res.data as Buckets).buckets
23+
const name =
24+
res.status == 200
25+
? `Explore the ${data[0].name} bucket`
26+
: `Select a bucket`
27+
const buckets = res.status == 200 ? data : []
28+
return Promise.resolve({
29+
name,
30+
spec: {
31+
readOnly: false,
32+
range: DEFAULT_TIME_RANGE,
33+
refresh: AUTOREFRESH_DEFAULT,
34+
pipes: [
35+
{
36+
type: 'queryBuilder',
37+
title: 'Build a Query',
38+
visible: true,
39+
...JSON.parse(
40+
JSON.stringify(PIPE_DEFINITIONS['queryBuilder'].initial)
41+
),
42+
buckets,
43+
},
44+
{
45+
title: 'Validate the Data',
46+
visible: true,
47+
type: 'table',
48+
},
49+
{
50+
title: 'Visualize the Result',
51+
visible: true,
52+
type: 'visualization',
53+
...JSON.parse(
54+
JSON.stringify(PIPE_DEFINITIONS['visualization'].initial)
55+
),
56+
},
57+
],
2458
},
25-
{
26-
title: 'Validate the Data',
27-
visible: true,
28-
type: 'table',
29-
},
30-
{
31-
title: 'Visualize the Result',
32-
visible: true,
33-
type: 'visualization',
34-
...JSON.parse(
35-
JSON.stringify(PIPE_DEFINITIONS['visualization'].initial)
36-
),
37-
},
38-
],
39-
},
40-
}),
59+
})
60+
}),
4161
})

src/writeData/components/fileUploads/CsvMethod.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ const CsvMethod: FC = () => {
5151

5252
const handleSeeUploadedData = () => {
5353
if (isFlagEnabled('exploreWithFlows')) {
54-
history.push(`/${PROJECT_NAME.toLowerCase()}/from/bucket/${bucket.name}`)
54+
history.push(
55+
`/${PROJECT_NAME.toLowerCase()}/from/bucket/${bucket.name}/${bucket.id}`
56+
)
5557
} else {
5658
history.push(`/orgs/${orgId}/data-explorer?bucket=${bucket.name}`)
5759
}

0 commit comments

Comments
 (0)