Introduce component for individual filters
parent
f2fff2385b
commit
6bbed0cadd
|
@ -0,0 +1,94 @@
|
||||||
|
import React, {PureComponent} from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import {Filter} from 'src/logs/containers/LogsPage'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
filter: Filter
|
||||||
|
onDelete: (id: string) => () => void
|
||||||
|
onToggleStatus: (id: string) => () => void
|
||||||
|
onToggleOperator: (id: string) => () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
expanded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogsFilter extends PureComponent<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
expanded: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {
|
||||||
|
filter: {id},
|
||||||
|
onDelete,
|
||||||
|
} = this.props
|
||||||
|
const {expanded} = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className={this.className} onMouseLeave={this.handleMouseLeave}>
|
||||||
|
{this.label}
|
||||||
|
<div className="logs-viewer--filter-remove" onClick={onDelete(id)} />
|
||||||
|
{expanded && this.renderTooltip}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get label(): JSX.Element {
|
||||||
|
const {
|
||||||
|
filter: {key, operator, value},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
onMouseEnter={this.handleMouseEnter}
|
||||||
|
>{`${key} ${operator} ${value}`}</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get className(): string {
|
||||||
|
const {expanded} = this.state
|
||||||
|
const {
|
||||||
|
filter: {enabled},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return classnames('logs-viewer--filter', {
|
||||||
|
active: expanded,
|
||||||
|
disabled: !enabled,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleMouseEnter = (): void => {
|
||||||
|
this.setState({expanded: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleMouseLeave = (): void => {
|
||||||
|
this.setState({expanded: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
private get renderTooltip(): JSX.Element {
|
||||||
|
const {
|
||||||
|
filter: {id, enabled, operator},
|
||||||
|
onDelete,
|
||||||
|
onToggleStatus,
|
||||||
|
onToggleOperator,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const toggleStatusText = enabled ? 'Disable' : 'Enable'
|
||||||
|
const toggleOperatorText = operator === '==' ? '!=' : '=='
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul className="logs-viewer--filter-tooltip">
|
||||||
|
<li onClick={onToggleStatus(id)}>{toggleStatusText}</li>
|
||||||
|
<li onClick={onToggleOperator(id)}>{toggleOperatorText}</li>
|
||||||
|
<li onClick={onDelete(id)}>Delete</li>
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogsFilter
|
|
@ -1,5 +1,6 @@
|
||||||
import React, {PureComponent} from 'react'
|
import React, {PureComponent} from 'react'
|
||||||
import {Filter} from 'src/logs/containers/LogsPage'
|
import {Filter} from 'src/logs/containers/LogsPage'
|
||||||
|
import FilterBlock from 'src/logs/components/LogsFilter'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
numResults: number
|
numResults: number
|
||||||
|
@ -25,31 +26,25 @@ class LogsFilters extends PureComponent<Props> {
|
||||||
const {filters} = this.props
|
const {filters} = this.props
|
||||||
|
|
||||||
return filters.map(filter => (
|
return filters.map(filter => (
|
||||||
<li className="logs-viewer--filter">
|
<FilterBlock
|
||||||
<span>
|
key={filter.id}
|
||||||
{filter.key}
|
filter={filter}
|
||||||
{filter.operator}
|
onDelete={this.handleDeleteFilter}
|
||||||
{filter.value}
|
onToggleStatus={this.handleToggleFilterStatus}
|
||||||
</span>
|
onToggleOperator={this.handleToggleFilterOperator}
|
||||||
<button
|
/>
|
||||||
className="logs-viewer--filter-remove"
|
|
||||||
onClick={this.handleDeleteFilter(filter.id)}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleDeleteFilter = (id: string) => (): void => {
|
private handleDeleteFilter = (id: string) => (): void => {
|
||||||
const {filters, onUpdateFilters} = this.props
|
const {filters, onUpdateFilters} = this.props
|
||||||
|
|
||||||
const filteredFilters = filters.map(
|
const filteredFilters = filters.filter(filter => filter.id !== id)
|
||||||
filter => (filter.id === id ? null : filter)
|
|
||||||
)
|
|
||||||
|
|
||||||
onUpdateFilters(filteredFilters)
|
onUpdateFilters(filteredFilters)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleToggleFilter = (id: string) => (): void => {
|
private handleToggleFilterStatus = (id: string) => (): void => {
|
||||||
const {filters, onUpdateFilters} = this.props
|
const {filters, onUpdateFilters} = this.props
|
||||||
|
|
||||||
const filteredFilters = filters.map(filter => {
|
const filteredFilters = filters.map(filter => {
|
||||||
|
@ -62,6 +57,28 @@ class LogsFilters extends PureComponent<Props> {
|
||||||
|
|
||||||
onUpdateFilters(filteredFilters)
|
onUpdateFilters(filteredFilters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleToggleFilterOperator = (id: string) => (): void => {
|
||||||
|
const {filters, onUpdateFilters} = this.props
|
||||||
|
|
||||||
|
const filteredFilters = filters.map(filter => {
|
||||||
|
if (filter.id === id) {
|
||||||
|
return {...filter, operator: this.toggleOperator(filter.operator)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter
|
||||||
|
})
|
||||||
|
|
||||||
|
onUpdateFilters(filteredFilters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private toggleOperator = (op: string): string => {
|
||||||
|
if (op === '==') {
|
||||||
|
return '!='
|
||||||
|
}
|
||||||
|
|
||||||
|
return '=='
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LogsFilters
|
export default LogsFilters
|
||||||
|
|
|
@ -34,13 +34,23 @@ interface State {
|
||||||
filters: Filter[]
|
filters: Filter[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DUMMY_FILTERS = [
|
||||||
|
{
|
||||||
|
id: '0',
|
||||||
|
key: 'host',
|
||||||
|
value: 'prod1-rsavage.local',
|
||||||
|
operator: '==',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
class LogsPage extends PureComponent<Props, State> {
|
class LogsPage extends PureComponent<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
searchString: '',
|
searchString: '',
|
||||||
filters: [],
|
filters: DUMMY_FILTERS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ $logs-viewer-gutter: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logs-viewer--filter {
|
.logs-viewer--filter {
|
||||||
|
position: relative;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -103,8 +104,20 @@ $logs-viewer-gutter: 60px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: $g5-pepper;
|
background-color: $g5-pepper;
|
||||||
color: $g13-mist;
|
color: $g13-mist;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: $g4-onyx;
|
||||||
|
color: $g9-mountain;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $g6-smoke;
|
||||||
|
color: $g15-platinum;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logs-viewer--filter-remove {
|
.logs-viewer--filter-remove {
|
||||||
|
@ -144,4 +157,38 @@ $logs-viewer-gutter: 60px;
|
||||||
background-color: $c-dreamsicle;
|
background-color: $c-dreamsicle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-viewer--filter-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
border-radius: $radius;
|
||||||
|
z-index: 9999;
|
||||||
|
@extend %drop-shadow;
|
||||||
|
background-color: $g4-onyx;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
height: 26px;
|
||||||
|
line-height: 26px;
|
||||||
|
padding: 0 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $g11-sidewalk;
|
||||||
|
transition: background-color 0.25s ease, color 0.25s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: $g5-pepper;
|
||||||
|
color: $g18-cloud;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue