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