Refactor FilterComponent to use Modal
This commit is contained in:
parent
55620f45df
commit
fa136c99da
4 changed files with 85 additions and 153 deletions
|
@ -1,35 +1,4 @@
|
|||
.FilterComponent {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: -200px;
|
||||
z-index: 10;
|
||||
|
||||
min-width: 430px;
|
||||
box-shadow: rgba(var(--main-fg), 0.1) 0px 0px 0px 1px, rgba(var(--main-fg), 0.1) 0px 2px 4px;
|
||||
background-color: rgb(var(--main-bg));
|
||||
padding: 10px;
|
||||
|
||||
@media screen and (max-width: 430px) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hideOnWidescreen {
|
||||
/* Hide controls (e.g. close button) on larger screens */
|
||||
@media not screen and (max-width: 430px) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
> .toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.octo-filterclause {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -10,11 +10,11 @@ import mutator from '../mutator'
|
|||
import {Utils} from '../utils'
|
||||
import {BoardTree} from '../viewModel/boardTree'
|
||||
import Button from '../widgets/buttons/button'
|
||||
import IconButton from '../widgets/buttons/iconButton'
|
||||
import CloseIcon from '../widgets/icons/close'
|
||||
import Menu from '../widgets/menu'
|
||||
import MenuWrapper from '../widgets/menuWrapper'
|
||||
|
||||
import './filterComponent.scss'
|
||||
import Modal from './modal'
|
||||
|
||||
type Props = {
|
||||
boardTree: BoardTree
|
||||
|
@ -23,33 +23,10 @@ type Props = {
|
|||
}
|
||||
|
||||
class FilterComponent extends React.Component<Props> {
|
||||
private node: React.RefObject<HTMLDivElement>
|
||||
|
||||
public shouldComponentUpdate(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props)
|
||||
this.node = React.createRef()
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
document.addEventListener('click', this.closeOnBlur, true)
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener('click', this.closeOnBlur, true)
|
||||
}
|
||||
|
||||
private closeOnBlur = (e: Event) => {
|
||||
if (this.node && this.node.current && e.target && this.node.current.contains(e.target as Node)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
private conditionClicked = (optionId: string, filter: FilterClause): void => {
|
||||
const {boardTree} = this.props
|
||||
const {activeView: view} = boardTree
|
||||
|
@ -75,97 +52,92 @@ class FilterComponent extends React.Component<Props> {
|
|||
const filters: FilterClause[] = activeView.filter?.filters.filter((o) => !FilterGroup.isAnInstanceOf(o)) as FilterClause[] || []
|
||||
|
||||
return (
|
||||
<div
|
||||
className='FilterComponent'
|
||||
ref={this.node}
|
||||
<Modal
|
||||
onClose={this.props.onClose}
|
||||
>
|
||||
<div className='toolbar hideOnWidescreen'>
|
||||
<IconButton
|
||||
onClick={this.closeClicked}
|
||||
icon={<CloseIcon/>}
|
||||
title={'Close dialog'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{filters.map((filter) => {
|
||||
const template = board.cardProperties.find((o) => o.id === filter.propertyId)
|
||||
const propertyName = template ? template.name : '(unknown)' // TODO: Handle error
|
||||
const key = `${filter.propertyId}-${filter.condition}-${filter.values.join(',')}`
|
||||
return (
|
||||
<div
|
||||
className='octo-filterclause'
|
||||
key={key}
|
||||
>
|
||||
<MenuWrapper>
|
||||
<Button>{propertyName}</Button>
|
||||
<Menu>
|
||||
{board.cardProperties.filter((o) => o.type === 'select').map((o) => (
|
||||
<div
|
||||
className='FilterComponent'
|
||||
>
|
||||
{filters.map((filter) => {
|
||||
const template = board.cardProperties.find((o) => o.id === filter.propertyId)
|
||||
const propertyName = template ? template.name : '(unknown)' // TODO: Handle error
|
||||
const key = `${filter.propertyId}-${filter.condition}-${filter.values.join(',')}`
|
||||
return (
|
||||
<div
|
||||
className='octo-filterclause'
|
||||
key={key}
|
||||
>
|
||||
<MenuWrapper>
|
||||
<Button>{propertyName}</Button>
|
||||
<Menu>
|
||||
{board.cardProperties.filter((o) => o.type === 'select').map((o) => (
|
||||
<Menu.Text
|
||||
key={o.id}
|
||||
id={o.id}
|
||||
name={o.name}
|
||||
onClick={(optionId: string) => {
|
||||
const filterIndex = activeView.filter.filters.indexOf(filter)
|
||||
Utils.assert(filterIndex >= 0, "Can't find filter")
|
||||
const filterGroup = new FilterGroup(activeView.filter)
|
||||
const newFilter = filterGroup.filters[filterIndex] as FilterClause
|
||||
Utils.assert(newFilter, `No filter at index ${filterIndex}`)
|
||||
if (newFilter.propertyId !== optionId) {
|
||||
newFilter.propertyId = optionId
|
||||
newFilter.values = []
|
||||
mutator.changeViewFilter(activeView, filterGroup)
|
||||
}
|
||||
}}
|
||||
/>))}
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
<MenuWrapper>
|
||||
<Button>{FilterClause.filterConditionDisplayString(filter.condition, intl)}</Button>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
key={o.id}
|
||||
id={o.id}
|
||||
name={o.name}
|
||||
onClick={(optionId: string) => {
|
||||
const filterIndex = activeView.filter.filters.indexOf(filter)
|
||||
Utils.assert(filterIndex >= 0, "Can't find filter")
|
||||
const filterGroup = new FilterGroup(activeView.filter)
|
||||
const newFilter = filterGroup.filters[filterIndex] as FilterClause
|
||||
Utils.assert(newFilter, `No filter at index ${filterIndex}`)
|
||||
if (newFilter.propertyId !== optionId) {
|
||||
newFilter.propertyId = optionId
|
||||
newFilter.values = []
|
||||
mutator.changeViewFilter(activeView, filterGroup)
|
||||
}
|
||||
}}
|
||||
/>))}
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
<MenuWrapper>
|
||||
<Button>{FilterClause.filterConditionDisplayString(filter.condition, intl)}</Button>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='includes'
|
||||
name={intl.formatMessage({id: 'Filter.includes', defaultMessage: 'includes'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
id='includes'
|
||||
name={intl.formatMessage({id: 'Filter.includes', defaultMessage: 'includes'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='notIncludes'
|
||||
name={intl.formatMessage({id: 'Filter.not-includes', defaultMessage: 'doesn\'t include'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='isEmpty'
|
||||
name={intl.formatMessage({id: 'Filter.is-empty', defaultMessage: 'is empty'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='isNotEmpty'
|
||||
name={intl.formatMessage({id: 'Filter.is-not-empty', defaultMessage: 'is not empty'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
{
|
||||
template && this.filterValue(filter, template)
|
||||
}
|
||||
<div className='octo-spacer'/>
|
||||
<Button onClick={() => this.deleteClicked(filter)}>
|
||||
<FormattedMessage
|
||||
id='FilterComponent.delete'
|
||||
defaultMessage='Delete'
|
||||
/>
|
||||
<Menu.Text
|
||||
id='notIncludes'
|
||||
name={intl.formatMessage({id: 'Filter.not-includes', defaultMessage: 'doesn\'t include'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='isEmpty'
|
||||
name={intl.formatMessage({id: 'Filter.is-empty', defaultMessage: 'is empty'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='isNotEmpty'
|
||||
name={intl.formatMessage({id: 'Filter.is-not-empty', defaultMessage: 'is not empty'})}
|
||||
onClick={(id) => this.conditionClicked(id, filter)}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
{
|
||||
template && this.filterValue(filter, template)
|
||||
}
|
||||
<div className='octo-spacer'/>
|
||||
<Button onClick={() => this.deleteClicked(filter)}>
|
||||
<FormattedMessage
|
||||
id='FilterComponent.delete'
|
||||
defaultMessage='Delete'
|
||||
/>
|
||||
</Button>
|
||||
</div>)
|
||||
})}
|
||||
</Button>
|
||||
</div>)
|
||||
})}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<Button onClick={() => this.addFilterClicked()}>
|
||||
<FormattedMessage
|
||||
id='FilterComponent.add-filter'
|
||||
defaultMessage='+ Add filter'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<Button onClick={() => this.addFilterClicked()}>
|
||||
<FormattedMessage
|
||||
id='FilterComponent.add-filter'
|
||||
defaultMessage='+ Add filter'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -219,10 +191,6 @@ class FilterComponent extends React.Component<Props> {
|
|||
return undefined
|
||||
}
|
||||
|
||||
private closeClicked = () => {
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
private deleteClicked(filter: FilterClause) {
|
||||
const {boardTree} = this.props
|
||||
const {activeView: view} = boardTree
|
||||
|
|
|
@ -28,9 +28,4 @@
|
|||
.octo-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
position: relative;
|
||||
overflow: unset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
|
||||
{/* Filter */}
|
||||
|
||||
<div className='filter-container'>
|
||||
<ModalWrapper>
|
||||
<Button
|
||||
active={hasFilter}
|
||||
onClick={this.showFilterDialog}
|
||||
|
@ -186,7 +186,7 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
boardTree={boardTree}
|
||||
onClose={this.hideFilterDialog}
|
||||
/>}
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
|
||||
{/* Sort */}
|
||||
|
||||
|
|
Loading…
Reference in a new issue