chore(ui): add filter and group concepts to tags in redux

pull/16050/head
Bucky Schwarz 2019-11-20 17:04:43 -08:00 committed by Bucky Schwarz
parent 380b4113cc
commit a90899ebf2
6 changed files with 182 additions and 201 deletions

View File

@ -7862,6 +7862,11 @@ components:
type: array
items:
type: string
aggregateFunctionType:
$ref: '#/components/schemas/BuilderAggregateFunctionType'
BuilderAggregateFunctionType:
type: string
enum: ['filter', 'group']
BuilderFunctionsType:
type: object
properties:

View File

@ -23,7 +23,7 @@ module.exports = {
'ts-jest': {
tsConfig: 'tsconfig.test.json',
diagnostics: {
ignoreCodes: [6133] // ignore `'foo' is declared but its value is never read.`
ignoreCodes: [6133, 6192] // ignore unused variable errors
},
},
},

View File

@ -10,220 +10,113 @@ import {
// Types
import {Dispatch} from 'redux-thunk'
import {GetState} from 'src/types'
import {RemoteDataState} from 'src/types'
import {GetState, RemoteDataState} from 'src/types'
import {BuilderAggregateFunctionType} from 'src/client/generatedRoutes'
import {BuilderFunctionsType} from '@influxdata/influx'
export type Action =
| SetBuilderBucketSelectionAction
| SetBuilderBucketsAction
| SetBuilderBucketsStatusAction
| SetBuilderTagKeysAction
| SetBuilderTagKeysStatusAction
| SetBuilderTagValuesAction
| SetBuilderTagValuesStatusAction
| SetBuilderTagKeySelectionAction
| SetBuilderTagValuesSelectionAction
| AddTagSelectorAction
| RemoveTagSelectorAction
| SetFunctionsAction
| SelectAggregateWindowAction
| SetValuesSearchTermAction
| SetKeysSearchTermAction
| SetBuilderTagsStatusAction
| ReturnType<typeof setBuilderAggregateFunctionType>
| ReturnType<typeof setBuilderBucket>
| ReturnType<typeof setBuilderBuckets>
| ReturnType<typeof setBuilderBucketsStatus>
| ReturnType<typeof setBuilderTagKeys>
| ReturnType<typeof setBuilderTagKeysStatus>
| ReturnType<typeof setBuilderTagValues>
| ReturnType<typeof setBuilderTagValuesStatus>
| ReturnType<typeof setBuilderTagKeySelection>
| ReturnType<typeof setBuilderTagValuesSelection>
| ReturnType<typeof addTagSelectorSync>
| ReturnType<typeof removeTagSelectorSync>
| ReturnType<typeof setFunctions>
| ReturnType<typeof selectAggregateWindow>
| ReturnType<typeof setValuesSearchTerm>
| ReturnType<typeof setKeysSearchTerm>
| ReturnType<typeof setBuilderTagsStatus>
interface SetBuilderBucketsStatusAction {
type: 'SET_BUILDER_BUCKETS_STATUS'
payload: {bucketsStatus: RemoteDataState}
}
export const setBuilderAggregateFunctionType = (
builderAggregateFunctionType: BuilderAggregateFunctionType,
index: number
) => ({
type: 'SET_BUILDER_AGGREGATE_FUNCTION_TYPE' as 'SET_BUILDER_AGGREGATE_FUNCTION_TYPE',
payload: {builderAggregateFunctionType, index},
})
const setBuilderBucketsStatus = (
bucketsStatus: RemoteDataState
): SetBuilderBucketsStatusAction => ({
type: 'SET_BUILDER_BUCKETS_STATUS',
const setBuilderBucketsStatus = (bucketsStatus: RemoteDataState) => ({
type: 'SET_BUILDER_BUCKETS_STATUS' as 'SET_BUILDER_BUCKETS_STATUS',
payload: {bucketsStatus},
})
interface SetBuilderBucketsAction {
type: 'SET_BUILDER_BUCKETS'
payload: {buckets: string[]}
}
export const setBuilderBuckets = (
buckets: string[]
): SetBuilderBucketsAction => ({
type: 'SET_BUILDER_BUCKETS',
export const setBuilderBuckets = (buckets: string[]) => ({
type: 'SET_BUILDER_BUCKETS' as 'SET_BUILDER_BUCKETS',
payload: {buckets},
})
interface SetBuilderBucketSelectionAction {
type: 'SET_BUILDER_BUCKET_SELECTION'
payload: {bucket: string; resetSelections: boolean}
}
const setBuilderBucket = (
bucket: string,
resetSelections: boolean
): SetBuilderBucketSelectionAction => ({
type: 'SET_BUILDER_BUCKET_SELECTION',
const setBuilderBucket = (bucket: string, resetSelections: boolean) => ({
type: 'SET_BUILDER_BUCKET_SELECTION' as 'SET_BUILDER_BUCKET_SELECTION',
payload: {bucket, resetSelections},
})
interface SetBuilderTagsStatusAction {
type: 'SET_BUILDER_TAGS_STATUS'
payload: {status: RemoteDataState}
}
export const setBuilderTagsStatus = (
status: RemoteDataState
): SetBuilderTagsStatusAction => ({
type: 'SET_BUILDER_TAGS_STATUS',
export const setBuilderTagsStatus = (status: RemoteDataState) => ({
type: 'SET_BUILDER_TAGS_STATUS' as 'SET_BUILDER_TAGS_STATUS',
payload: {status},
})
interface SetBuilderTagKeysAction {
type: 'SET_BUILDER_TAG_KEYS'
payload: {index: number; keys: string[]}
}
const setBuilderTagKeys = (
index: number,
keys: string[]
): SetBuilderTagKeysAction => ({
type: 'SET_BUILDER_TAG_KEYS',
const setBuilderTagKeys = (index: number, keys: string[]) => ({
type: 'SET_BUILDER_TAG_KEYS' as 'SET_BUILDER_TAG_KEYS',
payload: {index, keys},
})
interface SetBuilderTagKeysStatusAction {
type: 'SET_BUILDER_TAG_KEYS_STATUS'
payload: {index: number; status: RemoteDataState}
}
const setBuilderTagKeysStatus = (
index: number,
status: RemoteDataState
): SetBuilderTagKeysStatusAction => ({
type: 'SET_BUILDER_TAG_KEYS_STATUS',
const setBuilderTagKeysStatus = (index: number, status: RemoteDataState) => ({
type: 'SET_BUILDER_TAG_KEYS_STATUS' as 'SET_BUILDER_TAG_KEYS_STATUS',
payload: {index, status},
})
interface SetBuilderTagValuesAction {
type: 'SET_BUILDER_TAG_VALUES'
payload: {index: number; values: string[]}
}
const setBuilderTagValues = (
index: number,
values: string[]
): SetBuilderTagValuesAction => ({
type: 'SET_BUILDER_TAG_VALUES',
const setBuilderTagValues = (index: number, values: string[]) => ({
type: 'SET_BUILDER_TAG_VALUES' as 'SET_BUILDER_TAG_VALUES',
payload: {index, values},
})
interface SetBuilderTagValuesStatusAction {
type: 'SET_BUILDER_TAG_VALUES_STATUS'
payload: {index: number; status: RemoteDataState}
}
const setBuilderTagValuesStatus = (
index: number,
status: RemoteDataState
): SetBuilderTagValuesStatusAction => ({
type: 'SET_BUILDER_TAG_VALUES_STATUS',
const setBuilderTagValuesStatus = (index: number, status: RemoteDataState) => ({
type: 'SET_BUILDER_TAG_VALUES_STATUS' as 'SET_BUILDER_TAG_VALUES_STATUS',
payload: {index, status},
})
interface SetBuilderTagKeySelectionAction {
type: 'SET_BUILDER_TAG_KEY_SELECTION'
payload: {index: number; key: string}
}
const setBuilderTagKeySelection = (
index: number,
key: string
): SetBuilderTagKeySelectionAction => ({
type: 'SET_BUILDER_TAG_KEY_SELECTION',
const setBuilderTagKeySelection = (index: number, key: string) => ({
type: 'SET_BUILDER_TAG_KEY_SELECTION' as 'SET_BUILDER_TAG_KEY_SELECTION',
payload: {index, key},
})
interface SetBuilderTagValuesSelectionAction {
type: 'SET_BUILDER_TAG_VALUES_SELECTION'
payload: {index: number; values: string[]}
}
const setBuilderTagValuesSelection = (
index: number,
values: string[]
): SetBuilderTagValuesSelectionAction => ({
type: 'SET_BUILDER_TAG_VALUES_SELECTION',
const setBuilderTagValuesSelection = (index: number, values: string[]) => ({
type: 'SET_BUILDER_TAG_VALUES_SELECTION' as 'SET_BUILDER_TAG_VALUES_SELECTION',
payload: {index, values},
})
interface AddTagSelectorAction {
type: 'ADD_TAG_SELECTOR'
}
const addTagSelectorSync = (): AddTagSelectorAction => ({
type: 'ADD_TAG_SELECTOR',
const addTagSelectorSync = () => ({
type: 'ADD_TAG_SELECTOR' as 'ADD_TAG_SELECTOR',
})
interface RemoveTagSelectorAction {
type: 'REMOVE_TAG_SELECTOR'
payload: {index: number}
}
const removeTagSelectorSync = (index: number): RemoveTagSelectorAction => ({
type: 'REMOVE_TAG_SELECTOR',
const removeTagSelectorSync = (index: number) => ({
type: 'REMOVE_TAG_SELECTOR' as 'REMOVE_TAG_SELECTOR',
payload: {index},
})
interface SetFunctionsAction {
type: 'SELECT_BUILDER_FUNCTION'
payload: {functions: BuilderFunctionsType[]}
}
export const setFunctions = (
functions: BuilderFunctionsType[]
): SetFunctionsAction => ({
type: 'SELECT_BUILDER_FUNCTION',
export const setFunctions = (functions: BuilderFunctionsType[]) => ({
type: 'SELECT_BUILDER_FUNCTION' as 'SELECT_BUILDER_FUNCTION',
payload: {functions},
})
interface SelectAggregateWindowAction {
type: 'SELECT_AGGREGATE_WINDOW'
payload: {period: string}
}
export const selectAggregateWindow = (
period: string
): SelectAggregateWindowAction => ({
type: 'SELECT_AGGREGATE_WINDOW',
export const selectAggregateWindow = (period: string) => ({
type: 'SELECT_AGGREGATE_WINDOW' as 'SELECT_AGGREGATE_WINDOW',
payload: {period},
})
interface SetValuesSearchTermAction {
type: 'SET_BUILDER_VALUES_SEARCH_TERM'
payload: {index: number; searchTerm: string}
}
interface SetKeysSearchTermAction {
type: 'SET_BUILDER_KEYS_SEARCH_TERM'
payload: {index: number; searchTerm: string}
}
export const setValuesSearchTerm = (
index: number,
searchTerm: string
): SetValuesSearchTermAction => ({
type: 'SET_BUILDER_VALUES_SEARCH_TERM',
export const setValuesSearchTerm = (index: number, searchTerm: string) => ({
type: 'SET_BUILDER_VALUES_SEARCH_TERM' as 'SET_BUILDER_VALUES_SEARCH_TERM',
payload: {index, searchTerm},
})
export const setKeysSearchTerm = (
index: number,
searchTerm: string
): SetKeysSearchTermAction => ({
type: 'SET_BUILDER_KEYS_SEARCH_TERM',
export const setKeysSearchTerm = (index: number, searchTerm: string) => ({
type: 'SET_BUILDER_KEYS_SEARCH_TERM' as 'SET_BUILDER_KEYS_SEARCH_TERM',
payload: {index, searchTerm},
})

View File

@ -20,11 +20,12 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
// Actions
import {
removeTagSelector,
searchTagKeys,
searchTagValues,
selectTagKey,
selectTagValue,
searchTagValues,
searchTagKeys,
removeTagSelector,
setBuilderAggregateFunctionType,
setKeysSearchTerm,
setValuesSearchTerm,
} from 'src/timeMachine/actions/queryBuilder'
@ -40,10 +41,12 @@ import {
// Types
import {AppState, RemoteDataState} from 'src/types'
import {BuilderAggregateFunctionType} from 'src/client'
const SEARCH_DEBOUNCE_MS = 500
interface StateProps {
aggregateFunctionType: BuilderAggregateFunctionType
emptyText: string
keys: string[]
keysStatus: RemoteDataState
@ -57,13 +60,14 @@ interface StateProps {
}
interface DispatchProps {
onSelectValue: typeof selectTagValue
onSelectTag: typeof selectTagKey
onSearchValues: typeof searchTagValues
onSearchKeys: typeof searchTagKeys
onRemoveTagSelector: typeof removeTagSelector
onSetValuesSearchTerm: typeof setValuesSearchTerm
onSearchKeys: typeof searchTagKeys
onSearchValues: typeof searchTagValues
onSelectTag: typeof selectTagKey
onSelectValue: typeof selectTagValue
onSetBuilderAggregateFunctionType: typeof setBuilderAggregateFunctionType
onSetKeysSearchTerm: typeof setKeysSearchTerm
onSetValuesSearchTerm: typeof setValuesSearchTerm
}
interface OwnProps {
@ -76,13 +80,24 @@ type Props = StateProps & DispatchProps & OwnProps
class TagSelector extends PureComponent<Props> {
private debouncer = new DefaultDebouncer()
// bucky: this will currently always be 'Filter'
// updates to this are imminent
private renderAggregateFunctionType(
aggregateFunctionType: BuilderAggregateFunctionType
) {
if (aggregateFunctionType === 'group') {
return 'Group'
}
return 'Filter'
}
public render() {
const {index} = this.props
const {aggregateFunctionType, index} = this.props
return (
<BuilderCard>
<BuilderCard.Header
title="Filter"
title={this.renderAggregateFunctionType(aggregateFunctionType)}
onDelete={index !== 0 && this.handleRemoveTagSelector}
/>
{this.body}
@ -255,15 +270,19 @@ class TagSelector extends PureComponent<Props> {
const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
const {
keys,
keysSearchTerm,
keysStatus,
values,
valuesStatus,
valuesSearchTerm,
keysSearchTerm,
valuesStatus,
} = getActiveTimeMachine(state).queryBuilder.tags[ownProps.index]
const tags = getActiveQuery(state).builderConfig.tags
const {key: selectedKey, values: selectedValues} = tags[ownProps.index]
const {
key: selectedKey,
values: selectedValues,
aggregateFunctionType,
} = tags[ownProps.index]
let emptyText: string
@ -276,6 +295,7 @@ const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
const isInCheckOverlay = getIsInCheckOverlay(state)
return {
aggregateFunctionType,
emptyText,
keys,
keysStatus,
@ -290,11 +310,12 @@ const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
}
const mdtp = {
onSelectValue: selectTagValue,
onSelectTag: selectTagKey,
onSearchValues: searchTagValues,
onSearchKeys: searchTagKeys,
onRemoveTagSelector: removeTagSelector,
onSearchKeys: searchTagKeys,
onSearchValues: searchTagValues,
onSelectTag: selectTagKey,
onSelectValue: selectTagValue,
onSetBuilderAggregateFunctionType: setBuilderAggregateFunctionType,
onSetKeysSearchTerm: setKeysSearchTerm,
onSetValuesSearchTerm: setValuesSearchTerm,
}

View File

@ -0,0 +1,42 @@
import {createStore} from 'redux'
import {
initialState,
initialStateHelper,
timeMachinesReducer,
} from 'src/timeMachine/reducers'
describe('the Time Machine reducer', () => {
describe('setting the default aggregateFunctionType', () => {
const store = createStore(timeMachinesReducer, initialState())
const expectedAggregatefunctionType = initialStateHelper().queryBuilder
.tags[0].aggregateFunctionType
it('is set when setting a builder bucket selection', () => {
store.dispatch({
type: 'SET_BUILDER_BUCKET_SELECTION',
payload: {bucket: 'foo', resetSelections: true},
})
const actualState = store.getState()
const defaultAggregateFunctionType =
actualState.timeMachines.de.draftQueries[0].builderConfig.tags[0]
.aggregateFunctionType
expect(defaultAggregateFunctionType).toEqual(
expectedAggregatefunctionType
)
})
it('is set when adding a new tag selector', () => {
store.dispatch({type: 'ADD_TAG_SELECTOR'})
const actualState = store.getState()
const defaultAggregateFunctionType =
actualState.timeMachines.de.draftQueries[0].builderConfig.tags[0]
.aggregateFunctionType
expect(defaultAggregateFunctionType).toEqual(
expectedAggregatefunctionType
)
})
})
})

View File

@ -41,6 +41,7 @@ import {Action} from 'src/timeMachine/actions'
import {TimeMachineTab} from 'src/types/timeMachine'
import {RemoteDataState, TimeMachineID} from 'src/types'
import {Color} from 'src/types/colors'
import {BuilderAggregateFunctionType} from 'src/client/generatedRoutes'
interface QueryBuilderState {
buckets: string[]
@ -48,6 +49,7 @@ interface QueryBuilderState {
functions: Array<[{name: string}]>
aggregateWindow: BuilderConfigAggregateWindow
tags: Array<{
aggregateFunctionType: BuilderAggregateFunctionType
valuesSearchTerm: string
keysSearchTerm: string
keys: string[]
@ -115,11 +117,12 @@ export const initialStateHelper = (): TimeMachineState => ({
functions: [],
tags: [
{
valuesSearchTerm: '',
keysSearchTerm: '',
aggregateFunctionType: 'filter',
keys: [],
keysSearchTerm: '',
keysStatus: RemoteDataState.NotStarted,
values: [],
valuesSearchTerm: '',
valuesStatus: RemoteDataState.NotStarted,
},
],
@ -649,6 +652,23 @@ export const timeMachineReducer = (
})
}
case 'SET_BUILDER_AGGREGATE_FUNCTION_TYPE': {
return produce(state, draftState => {
const {index, builderAggregateFunctionType} = action.payload
const draftQuery = draftState.draftQueries[draftState.activeQueryIndex]
if (
draftQuery &&
draftQuery.builderConfig &&
draftQuery.builderConfig.tags[index]
) {
draftQuery.builderConfig.tags[
index
].aggregateFunctionType = builderAggregateFunctionType
}
})
}
case 'SET_BUILDER_BUCKET_SELECTION': {
return produce(state, draftState => {
const builderConfig =
@ -657,7 +677,16 @@ export const timeMachineReducer = (
builderConfig.buckets = [action.payload.bucket]
if (action.payload.resetSelections) {
builderConfig.tags = [{key: '', values: []}]
const defaultAggregateFunctionType = initialStateHelper().queryBuilder
.tags[0].aggregateFunctionType
builderConfig.tags = [
{
key: '',
values: [],
aggregateFunctionType: defaultAggregateFunctionType,
},
]
buildActiveQuery(draftState)
}
})
@ -770,16 +799,14 @@ export const timeMachineReducer = (
case 'ADD_TAG_SELECTOR': {
return produce(state, draftState => {
const draftQuery = draftState.draftQueries[draftState.activeQueryIndex]
const [initialTags] = initialStateHelper().queryBuilder.tags
draftQuery.builderConfig.tags.push({key: '', values: []})
draftState.queryBuilder.tags.push({
valuesSearchTerm: '',
keysSearchTerm: '',
keys: [],
keysStatus: RemoteDataState.NotStarted,
draftQuery.builderConfig.tags.push({
key: '',
values: [],
valuesStatus: RemoteDataState.NotStarted,
aggregateFunctionType: initialTags.aggregateFunctionType,
})
draftState.queryBuilder.tags.push(initialTags)
})
}
@ -1066,14 +1093,7 @@ const initialQueryBuilderState = (
bucketsStatus: RemoteDataState.NotStarted,
functions: [],
aggregateWindow: {period: 'auto'},
tags: builderConfig.tags.map(_ => ({
valuesSearchTerm: '',
keysSearchTerm: '',
keys: [],
keysStatus: RemoteDataState.NotStarted,
values: [],
valuesStatus: RemoteDataState.NotStarted,
})),
tags: initialStateHelper().queryBuilder.tags,
}
}