Skip to content

Commit d5df3b7

Browse files
authored
feat: filter out sample buckets from the bucket dropdown (#5112)
1 parent 905a1e3 commit d5df3b7

File tree

4 files changed

+127
-138
lines changed

4 files changed

+127
-138
lines changed

cypress/e2e/shared/fluxQueryBuilder.test.ts

Lines changed: 65 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ describe('FluxQueryBuilder', () => {
1010
cy.setFeatureFlags({
1111
newDataExplorer: true,
1212
}).then(() => {
13+
const writeData = []
14+
for (let i = 0; i < 30; i++) {
15+
writeData.push(`ndbc,air_temp_degc=${i}_degrees station_id=${i}`)
16+
}
17+
cy.writeData(writeData, 'defbuck')
1318
cy.wait(100)
1419
cy.getByTestID('flux-query-builder-toggle').then($toggle => {
1520
cy.wrap($toggle).should('be.visible')
@@ -26,21 +31,12 @@ describe('FluxQueryBuilder', () => {
2631
})
2732

2833
describe('Schema browser', () => {
29-
const bucketName = 'NOAA National Buoy Data'
34+
const bucketName = 'defbuck'
3035
const measurement = 'ndbc'
31-
const searchField = 'air_temp_degc'
32-
const searchTagKey = 'station_id'
33-
34-
it('bucket selector can search and select a bucket, then search and select a measurement', () => {
35-
// no other selectors should be visible, except the bucket selector
36-
cy.getByTestID('bucket-selector--dropdown-button').should('be.visible')
37-
cy.getByTestID('measurement-selector--dropdown-button').should(
38-
'not.exist'
39-
)
40-
cy.getByTestID('field-tag-key-search-bar').should('not.exist')
41-
cy.getByTestID('field-selector').should('not.exist')
42-
cy.getByTestID('tag-selector-key').should('not.exist')
36+
const searchTagKey = 'air_temp_degc'
37+
const searchField = 'station_id'
4338

39+
it('can search buckets, measurements, fields and tag keys dynamically and loads more data when truncated', () => {
4440
// open the bucket list
4541
cy.getByTestID('bucket-selector--dropdown-button').click()
4642

@@ -83,71 +79,59 @@ describe('FluxQueryBuilder', () => {
8379
// upon selection, will show a search bar
8480
// and a list of fields and tag keys
8581
cy.getByTestID('field-tag-key-search-bar').should('be.visible')
86-
cy.getByTestID('field-selector').should('be.visible')
87-
cy.getByTestID('tag-selector-key').should('be.visible')
88-
})
89-
90-
it('search bar can search fields and tag keys dynamically', () => {
91-
// select a bucket
92-
cy.getByTestID('bucket-selector--dropdown-button').click()
93-
cy.getByTestID(`bucket-selector--dropdown--${bucketName}`).click()
94-
95-
// check the monaco editor is mounted to prepare for schema injection
96-
cy.getByTestID('flux-editor').should('be.visible')
97-
98-
// select a measurement
99-
cy.getByTestID('measurement-selector--dropdown-button')
100-
.should('contain', 'Select measurement')
101-
.click()
102-
cy.getByTestID(`searchable-dropdown--item ${measurement}`).click()
82+
cy.getByTestID('field-selector')
83+
.should('be.visible')
84+
.should('not.contain', 'Loading')
85+
cy.getByTestID('tag-selector--key')
86+
.should('be.visible')
87+
.should('not.contain', 'Loading')
10388

10489
// search a feild, should contain only the feild, no tag keys
10590
cy.getByTestID('field-tag-key-search-bar')
10691
.should('be.visible')
10792
.type(searchField)
108-
cy.getByTestID('field-selector').within(() => {
109-
cy.getByTestID('field-selector--list-item--selectable').should(
110-
'contain',
111-
searchField
112-
)
113-
})
93+
cy.getByTestID('field-selector')
94+
.should('be.visible')
95+
.should('not.contain', 'Loading')
96+
.should('not.contain', 'No Fields Found')
97+
cy.getByTestID('tag-selector--key')
98+
.should('be.visible')
99+
.should('not.contain', 'Loading')
100+
cy.getByTestID('tag-selector-key')
101+
.should('be.visible')
102+
.should('contain', 'No Tags Found')
114103

115104
// clear the search bar
116105
cy.getByTestID('dismiss-button').click()
117106

107+
cy.getByTestID('field-selector')
108+
.should('be.visible')
109+
.should('not.contain', 'Loading')
110+
.should('not.contain', 'No Fields Found')
111+
cy.getByTestID('tag-selector--key')
112+
.should('be.visible')
113+
.should('not.contain', 'Loading')
114+
cy.getByTestID('tag-selector-key')
115+
.should('be.visible')
116+
.should('not.contain', 'No Tags Found')
117+
118118
// search a tag key, should not contain any fields
119119
cy.getByTestID('field-tag-key-search-bar')
120120
.should('be.visible')
121121
.type(searchTagKey)
122122

123-
cy.getByTestID('field-selector').within(() => {
124-
cy.getByTestID('field-selector--list-item')
125-
.should('be.visible')
126-
.should('contain', 'No Fields Found')
127-
})
123+
cy.getByTestID('field-selector')
124+
.should('not.contain', 'Loading')
125+
.should('contain', 'No Fields Found')
128126

129-
// not recommend to assert for searchTagKey value
130-
// since it will expand all the tag keys, which triggers
131-
// numbers of API calls that are time consuming and unnecessary
132-
})
133-
134-
it('fields show all items when less than 8 items, and show "Load More" when more than 8 items', () => {
135-
// if less than 8 items, show all items
136-
const bucketNameA = 'Air Sensor Data'
137-
const measurementA = 'airSensors'
138-
139-
// select a bucket
140-
cy.getByTestID('bucket-selector--dropdown-button').click()
141-
cy.getByTestID(`bucket-selector--dropdown--${bucketNameA}`).click()
142-
143-
// check the monaco editor is mounted to prepare for schema injection
144-
cy.getByTestID('flux-editor').should('be.visible')
127+
cy.getByTestID('tag-selector--key')
128+
.should('be.visible')
129+
.should('not.contain', 'Loading')
130+
cy.getByTestID('tag-selector-key')
131+
.should('be.visible')
132+
.should('not.contain', 'No Tags Found')
145133

146-
// select a measurement
147-
cy.getByTestID('measurement-selector--dropdown-button')
148-
.should('contain', 'Select measurement')
149-
.click()
150-
cy.getByTestID(`searchable-dropdown--item ${measurementA}`).click()
134+
cy.getByTestID('field-tag-key-search-bar').clear()
151135

152136
// less than 8 items, no "Load More" button
153137
cy.getByTestID('field-selector').within(() => {
@@ -157,35 +141,27 @@ describe('FluxQueryBuilder', () => {
157141
cy.getByTestID('field-selector--load-more-button').should('not.exist')
158142
})
159143

160-
// if more than 8 items, show "Load More" button
161-
// and load additional 25 items
162-
163-
// select another bucket
164-
cy.getByTestID('bucket-selector--dropdown-button').click()
165-
cy.getByTestID(`bucket-selector--dropdown--${bucketName}`).click()
166-
167-
// select another measurement
168-
cy.getByTestID('measurement-selector--dropdown-button')
169-
.should('contain', 'Select measurement')
170-
.click()
171-
cy.getByTestID(`searchable-dropdown--item ${measurement}`).click()
172-
173144
// more than 8 items, show 'Load More' button
174-
cy.getByTestID('field-selector').within(() => {
175-
cy.getByTestID('field-selector--list-item--selectable')
176-
.should('be.visible')
177-
.should('have.length', 8)
178-
cy.getByTestID('field-selector--load-more-button')
179-
.should('be.visible')
180-
.trigger('click')
181-
.then(() => {
182-
// when load more is chosen, up to 25 additional entries should be shown
183-
cy.getByTestID('field-selector--list-item--selectable')
184-
.should('be.visible')
185-
.should('have.length.above', 8)
186-
.and('have.length.at.most', 33) // 8 + 25
187-
})
145+
cy.getByTestID('tag-selector--key').within(() => {
146+
cy.get('.tag-selector-value--header').click()
188147
})
148+
cy.getByTestID('tag-selector-value--list-item--selectable')
149+
.should('be.visible')
150+
.should('have.length', 8)
151+
cy.getByTestID('tag-selector-value--load-more-button')
152+
.should('be.visible')
153+
.trigger('click')
154+
.then(() => {
155+
// when load more is chosen, up to 25 additional entries should be shown
156+
cy.getByTestID('tag-selector-value--list-item--selectable')
157+
.should('be.visible')
158+
.should('have.length.above', 8)
159+
.and('have.length.at.most', 33) // 8 + 25
160+
})
161+
162+
// not recommend to assert for searchTagKey value
163+
// since it will expand all the tag keys, which triggers
164+
// numbers of API calls that are time consuming and unnecessary
189165
})
190166
})
191167
})

src/dataExplorer/components/Schema.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const Schema: FC = () => {
7676
<FieldsProvider scope={scope}>
7777
<TagsProvider scope={scope}>
7878
<FluxQueryBuilderProvider>
79-
<BucketProvider scope={scope}>
79+
<BucketProvider scope={scope} omitSampleData>
8080
<div className="scroll--container">
8181
<DapperScrollbars>
8282
<div className="schema-browser" data-testid="schema-browser">

src/dataExplorer/components/TagSelector.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const TagValues: FC<Prop> = ({loading, tagKey, tagValues}) => {
8484
key={value}
8585
className="tag-selector-value--list-item--selectable"
8686
onClick={() => handleSelectTagValue(value)}
87+
data-testid="tag-selector-value--list-item--selectable"
8788
>
8889
<code>{value}</code>
8990
</dd>
@@ -112,7 +113,10 @@ const TagValues: FC<Prop> = ({loading, tagKey, tagValues}) => {
112113

113114
return (
114115
<Accordion className="tag-selector-value">
115-
<div onClick={() => handleSelectTagKey(tagKey)}>
116+
<div
117+
onClick={() => handleSelectTagKey(tagKey)}
118+
data-testid="tag-selector--key"
119+
>
116120
<Accordion.AccordionHeader className="tag-selector-value--header">
117121
<SelectorTitle title={tagKey} />
118122
</Accordion.AccordionHeader>

src/shared/contexts/buckets.tsx

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,15 @@ export const BucketContext = createContext<BucketContextType>(DEFAULT_CONTEXT)
5858
const useLocalStorageState = createLocalStorageStateHook('buckets', {})
5959

6060
interface Props {
61+
omitSampleData?: boolean
6162
scope: QueryScope
6263
}
6364

64-
export const BucketProvider: FC<Props> = ({children, scope}) => {
65+
export const BucketProvider: FC<Props> = ({
66+
children,
67+
omitSampleData = false,
68+
scope,
69+
}) => {
6570
const cacheKey = `${scope.region};;<${scope.org}>`
6671
const [bucketCache, setBucketCache] = useLocalStorageState()
6772
const {data} = useContext(PipeContext)
@@ -146,59 +151,34 @@ export const BucketProvider: FC<Props> = ({children, scope}) => {
146151
})
147152
.then(response => {
148153
controller.current = null
149-
const bucks = response.buckets.reduce(
150-
(acc, curr) => {
151-
if (curr.type === 'system') {
152-
acc.system.push(curr)
153-
} else {
154-
acc.user.push(curr)
155-
}
156-
return acc
157-
},
158-
{
159-
system: [],
160-
user: [],
161-
sample: [
162-
{
163-
type: 'sample',
164-
name: 'Air Sensor Data',
165-
id: 'airSensor',
166-
},
167-
{
168-
type: 'sample',
169-
name: 'Coinbase bitcoin price',
170-
id: 'bitcoin',
171-
},
172-
{
173-
type: 'sample',
174-
name: 'NOAA National Buoy Data',
175-
id: 'noaa',
176-
},
177-
{
178-
type: 'sample',
179-
name: 'USGS Earthquakes',
180-
id: 'usgs',
181-
},
182-
],
154+
const base: any = {
155+
system: [],
156+
user: [],
157+
}
158+
159+
const bucks = response.buckets.reduce((acc, curr) => {
160+
if (curr.type === 'system') {
161+
acc.system.push(curr)
162+
} else {
163+
acc.user.push(curr)
183164
}
184-
)
165+
return acc
166+
}, base)
185167

186168
bucks.system.sort((a, b) =>
187169
`${a.name}`.toLowerCase().localeCompare(`${b.name}`.toLowerCase())
188170
)
189171
bucks.user.sort((a, b) =>
190172
`${a.name}`.toLowerCase().localeCompare(`${b.name}`.toLowerCase())
191173
)
192-
bucks.sample.sort((a, b) =>
193-
`${a.name}`.toLowerCase().localeCompare(`${b.name}`.toLowerCase())
194-
)
195174
updateCache({
196175
loading: RemoteDataState.Done,
197176
lastFetch: Date.now(),
198-
buckets: [...bucks.user, ...bucks.system, ...bucks.sample],
177+
buckets: [...bucks.user, ...bucks.system],
199178
})
200179
})
201-
.catch(() => {
180+
.catch(error => {
181+
console.error({error})
202182
controller.current = null
203183
updateCache({
204184
loading: RemoteDataState.Error,
@@ -297,27 +277,56 @@ export const BucketProvider: FC<Props> = ({children, scope}) => {
297277
bucks.user.sort((a, b) =>
298278
`${a.name}`.toLowerCase().localeCompare(`${b.name}`.toLowerCase())
299279
)
300-
bucks.sample.sort((a, b) =>
301-
`${a.name}`.toLowerCase().localeCompare(`${b.name}`.toLowerCase())
302-
)
303280

304281
updateCache({
305-
buckets: [...bucks.user, ...bucks.system, ...bucks.sample],
282+
buckets: [...bucks.user, ...bucks.system],
306283
})
307284
}
308285

309286
const refresh = () => {
310287
fetchBuckets()
311288
}
289+
const outBuckets = useMemo(
290+
() =>
291+
buckets
292+
.filter(b => b.type !== 'sample')
293+
.concat(
294+
omitSampleData
295+
? []
296+
: [
297+
{
298+
type: 'sample',
299+
name: 'Air Sensor Data',
300+
id: 'airSensor',
301+
},
302+
{
303+
type: 'sample',
304+
name: 'Coinbase bitcoin price',
305+
id: 'bitcoin',
306+
},
307+
{
308+
type: 'sample',
309+
name: 'NOAA National Buoy Data',
310+
id: 'noaa',
311+
},
312+
{
313+
type: 'sample',
314+
name: 'USGS Earthquakes',
315+
id: 'usgs',
316+
},
317+
]
318+
),
319+
[buckets]
320+
)
312321

313322
return useMemo(
314323
() => (
315324
<BucketContext.Provider
316-
value={{loading, buckets, createBucket, addBucket, refresh}}
325+
value={{loading, buckets: outBuckets, createBucket, addBucket, refresh}}
317326
>
318327
{children}
319328
</BucketContext.Provider>
320329
),
321-
[data.bucket, loading, buckets]
330+
[data.bucket, loading, outBuckets]
322331
)
323332
}

0 commit comments

Comments
 (0)