Allow tags to be filtered with regex
parent
f8e7cfa92e
commit
bae5b110a4
|
@ -51,7 +51,7 @@ export enum ActionTypes {
|
|||
SetSearchTerm = 'LOGS_SET_SEARCH_TERM',
|
||||
AddFilter = 'LOGS_ADD_FILTER',
|
||||
RemoveFilter = 'LOGS_REMOVE_FILTER',
|
||||
SetFilterOperator = 'LOGS_SET_FILTER_OPERATOR',
|
||||
ChangeFilter = 'LOGS_CHANGE_FILTER',
|
||||
}
|
||||
|
||||
export interface AddFilterAction {
|
||||
|
@ -61,11 +61,12 @@ export interface AddFilterAction {
|
|||
}
|
||||
}
|
||||
|
||||
export interface SetFilterOperatorAction {
|
||||
type: ActionTypes.SetFilterOperator
|
||||
export interface ChangeFilterAction {
|
||||
type: ActionTypes.ChangeFilter
|
||||
payload: {
|
||||
id: string
|
||||
operator: string
|
||||
value: string
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +160,7 @@ export type Action =
|
|||
| SetSearchTerm
|
||||
| AddFilterAction
|
||||
| RemoveFilterAction
|
||||
| SetFilterOperatorAction
|
||||
| ChangeFilterAction
|
||||
|
||||
const getTimeRange = (state: State): TimeRange | null =>
|
||||
getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
|
@ -182,9 +183,9 @@ const getSearchTerm = (state: State): string | null =>
|
|||
const getFilters = (state: State): Filter[] =>
|
||||
getDeep<Filter[]>(state, 'logs.filters', [])
|
||||
|
||||
export const setFilterOperator = (id: string, operator: string) => ({
|
||||
type: ActionTypes.SetFilterOperator,
|
||||
payload: {id, operator},
|
||||
export const changeFilter = (id: string, operator: string, value: string) => ({
|
||||
type: ActionTypes.ChangeFilter,
|
||||
payload: {id, operator, value},
|
||||
})
|
||||
|
||||
export const setSource = (source: Source): SetSourceAction => ({
|
||||
|
|
|
@ -7,12 +7,13 @@ import {ClickOutside} from 'src/shared/components/ClickOutside'
|
|||
interface Props {
|
||||
filter: Filter
|
||||
onDelete: (id: string) => void
|
||||
onChangeOperator: (id: string, newOperator: string) => void
|
||||
onChangeValue: (id: string, newValue: string) => void
|
||||
onChangeFilter: (id: string, newOperator: string, newValue: string) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
editing: boolean
|
||||
value: string
|
||||
operator: string
|
||||
}
|
||||
|
||||
class LogsFilter extends PureComponent<Props, State> {
|
||||
|
@ -21,14 +22,12 @@ class LogsFilter extends PureComponent<Props, State> {
|
|||
|
||||
this.state = {
|
||||
editing: false,
|
||||
value: this.props.filter.value,
|
||||
operator: this.props.filter.operator,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
filter: {id},
|
||||
onDelete,
|
||||
} = this.props
|
||||
const {editing} = this.state
|
||||
|
||||
return (
|
||||
|
@ -45,7 +44,7 @@ class LogsFilter extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleClickOutside = (): void => {
|
||||
this.setState({editing: false})
|
||||
this.stopEditing()
|
||||
}
|
||||
|
||||
private handleStartEdit = (): void => {
|
||||
|
@ -76,8 +75,9 @@ class LogsFilter extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private get renderEditor(): JSX.Element {
|
||||
const {operator, value} = this.state
|
||||
const {
|
||||
filter: {key, operator, value},
|
||||
filter: {key},
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -106,56 +106,36 @@ class LogsFilter extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleOperatorInput = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||
const {
|
||||
filter: {id},
|
||||
onChangeOperator,
|
||||
} = this.props
|
||||
const operator = getDeep(e, 'target.value', '').trim()
|
||||
|
||||
const cleanValue = this.enforceOperatorChars(e.target.value)
|
||||
|
||||
onChangeOperator(id, cleanValue)
|
||||
this.setState({operator})
|
||||
}
|
||||
|
||||
private handleValueInput = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||
const {
|
||||
filter: {id},
|
||||
onChangeValue,
|
||||
} = this.props
|
||||
|
||||
onChangeValue(id, e.target.value)
|
||||
}
|
||||
|
||||
private enforceOperatorChars = text => {
|
||||
return text
|
||||
.split('')
|
||||
.filter(t => ['!', '~', `=`].includes(t))
|
||||
.join('')
|
||||
const value = getDeep(e, 'target.value', '').trim()
|
||||
this.setState({value})
|
||||
}
|
||||
|
||||
private handleKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault()
|
||||
this.setState({editing: false})
|
||||
this.stopEditing()
|
||||
}
|
||||
}
|
||||
|
||||
private handleToggleOperator = () => {
|
||||
private stopEditing(): void {
|
||||
const id = getDeep(this.props, 'filter.id', '')
|
||||
const {operator, value} = this.state
|
||||
|
||||
let nextOperator = '=='
|
||||
if (this.operator === '==') {
|
||||
nextOperator = '!='
|
||||
let state = {}
|
||||
if (['!=', '==', '=~'].includes(operator) && value !== '') {
|
||||
this.props.onChangeFilter(id, operator, value)
|
||||
} else {
|
||||
const {filter} = this.props
|
||||
state = {operator: filter.operator, value: filter.value}
|
||||
}
|
||||
|
||||
this.props.onChangeOperator(id, nextOperator)
|
||||
}
|
||||
|
||||
private get toggleOperatorText(): string {
|
||||
return this.operator === '==' ? '!=' : '=='
|
||||
}
|
||||
|
||||
private get operator(): string {
|
||||
return getDeep(this.props, 'filter.operator', '')
|
||||
this.setState({...state, editing: false})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ interface Props {
|
|||
numResults: number
|
||||
filters: Filter[]
|
||||
onDelete: (id: string) => void
|
||||
onFilterOperatorChange: (id: string, operator: string) => void
|
||||
onFilterChange: (id: string, operator: string, value: string) => void
|
||||
}
|
||||
|
||||
class LogsFilters extends PureComponent<Props> {
|
||||
|
@ -31,22 +31,10 @@ class LogsFilters extends PureComponent<Props> {
|
|||
key={filter.id}
|
||||
filter={filter}
|
||||
onDelete={this.props.onDelete}
|
||||
onChangeOperator={this.props.onFilterOperatorChange}
|
||||
onChangeValue={this.handleChangeFilterValue}
|
||||
onChangeFilter={this.props.onFilterChange}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
private handleChangeFilterValue = (id: string, value: string): void => {
|
||||
// const {filters, onUpdateFilters} = this.props
|
||||
// const filteredFilters = filters.map(filter => {
|
||||
// if (filter.id === id) {
|
||||
// return {...filter, value}
|
||||
// }
|
||||
// return filter
|
||||
// })
|
||||
// onUpdateFilters(filteredFilters)
|
||||
}
|
||||
}
|
||||
|
||||
export default LogsFilters
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
setSearchTermAsync,
|
||||
addFilter,
|
||||
removeFilter,
|
||||
setFilterOperator,
|
||||
changeFilter,
|
||||
} from 'src/logs/actions'
|
||||
import {getSourcesAsync} from 'src/shared/actions/sources'
|
||||
import LogViewerHeader from 'src/logs/components/LogViewerHeader'
|
||||
|
@ -38,7 +38,7 @@ interface Props {
|
|||
setSearchTermAsync: (searchTerm: string) => void
|
||||
addFilter: (filter: Filter) => void
|
||||
removeFilter: (id: string) => void
|
||||
setFilterOperator: (id: string, operator: string) => void
|
||||
changeFilter: (id: string, operator: string, value: string) => void
|
||||
timeRange: TimeRange
|
||||
histogramData: object[]
|
||||
tableData: {
|
||||
|
@ -105,7 +105,7 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
numResults={count}
|
||||
filters={filters || []}
|
||||
onDelete={this.handleFilterDelete}
|
||||
onFilterOperatorChange={this.handleFilterOperatorChange}
|
||||
onFilterChange={this.handleFilterChange}
|
||||
/>
|
||||
<LogsTable
|
||||
data={this.props.tableData}
|
||||
|
@ -147,7 +147,6 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
id: uuid.v4(),
|
||||
key: selection.key,
|
||||
value: selection.tag,
|
||||
enabled: true,
|
||||
operator: '==',
|
||||
})
|
||||
this.props.executeQueriesAsync()
|
||||
|
@ -215,8 +214,12 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
private handleFilterOperatorChange = (id: string, operator: string) => {
|
||||
this.props.setFilterOperator(id, operator)
|
||||
private handleFilterChange = (
|
||||
id: string,
|
||||
operator: string,
|
||||
value: string
|
||||
) => {
|
||||
this.props.changeFilter(id, operator, value)
|
||||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
|
@ -274,7 +277,7 @@ const mapDispatchToProps = {
|
|||
setSearchTermAsync,
|
||||
addFilter,
|
||||
removeFilter,
|
||||
setFilterOperator,
|
||||
changeFilter,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LogsPage)
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
Action,
|
||||
RemoveFilterAction,
|
||||
AddFilterAction,
|
||||
SetFilterOperatorAction,
|
||||
ChangeFilterAction,
|
||||
} from 'src/logs/actions'
|
||||
import {LogsState} from 'src/types/logs'
|
||||
|
||||
|
@ -40,15 +40,15 @@ const addFilter = (state: LogsState, action: AddFilterAction): LogsState => {
|
|||
return {...state, filters: [..._.get(state, 'filters', []), filter]}
|
||||
}
|
||||
|
||||
const setFilterOperator = (
|
||||
const changeFilter = (
|
||||
state: LogsState,
|
||||
action: SetFilterOperatorAction
|
||||
action: ChangeFilterAction
|
||||
): LogsState => {
|
||||
const {id, operator} = action.payload
|
||||
const {id, operator, value} = action.payload
|
||||
|
||||
const mappedFilters = _.map(_.get(state, 'filters', []), f => {
|
||||
if (f.id === id) {
|
||||
return {...f, operator}
|
||||
return {...f, operator, value}
|
||||
}
|
||||
return f
|
||||
})
|
||||
|
@ -84,8 +84,8 @@ export default (state: LogsState = defaultState, action: Action) => {
|
|||
return addFilter(state, action)
|
||||
case ActionTypes.RemoveFilter:
|
||||
return removeFilter(state, action)
|
||||
case ActionTypes.SetFilterOperator:
|
||||
return setFilterOperator(state, action)
|
||||
case ActionTypes.ChangeFilter:
|
||||
return changeFilter(state, action)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
|
|
@ -99,13 +99,21 @@ const operatorMapping = (operator: string): string => {
|
|||
}
|
||||
}
|
||||
|
||||
const valueMapping = (operator: string, value): string => {
|
||||
if (operator === '=~') {
|
||||
return `${new RegExp(value)}`
|
||||
} else {
|
||||
return `'${value}'`
|
||||
}
|
||||
}
|
||||
|
||||
export const filtersClause = (filters: Filter[]): string => {
|
||||
return _.map(
|
||||
filters,
|
||||
(filter: Filter) =>
|
||||
`"${keyMapping(filter.key)}" ${operatorMapping(filter.operator)} '${
|
||||
filter.value
|
||||
}'`
|
||||
`"${keyMapping(filter.key)}" ${operatorMapping(
|
||||
filter.operator
|
||||
)} ${valueMapping(filter.operator, filter.value)}`
|
||||
).join(' AND ')
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue