Moving show filter to where is used
This commit is contained in:
parent
3859ad30b1
commit
6e51954866
5 changed files with 98 additions and 107 deletions
|
@ -25,11 +25,11 @@ import Button from './button'
|
|||
import {CardDialog} from './cardDialog'
|
||||
import {Editable} from './editable'
|
||||
import RootPortal from './rootPortal'
|
||||
import {FilterComponent} from './filterComponent'
|
||||
|
||||
type Props = {
|
||||
boardTree?: BoardTree
|
||||
showView: (id: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
setSearchText: (text: string) => void
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ type State = {
|
|||
viewMenu: boolean
|
||||
isHoverOnCover: boolean
|
||||
selectedCards: Card[]
|
||||
showFilter: boolean
|
||||
}
|
||||
|
||||
class BoardComponent extends React.Component<Props, State> {
|
||||
|
@ -75,6 +76,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
isSearching: Boolean(this.props.boardTree?.getSearchText()),
|
||||
viewMenu: false,
|
||||
selectedCards: [],
|
||||
showFilter: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,10 +258,19 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
</MenuWrapper>
|
||||
<div
|
||||
className={hasFilter ? 'octo-button active' : 'octo-button'}
|
||||
onClick={(e) => {
|
||||
this.filterClicked(e)
|
||||
}}
|
||||
>Filter</div>
|
||||
style={{position: 'relative', overflow: 'unset'}}
|
||||
onClick={this.filterClicked}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='TableComponent.filter'
|
||||
defaultMessage='Filter'
|
||||
/>
|
||||
{this.state.showFilter &&
|
||||
<FilterComponent
|
||||
boardTree={boardTree}
|
||||
onClose={this.hideFilter}
|
||||
/>}
|
||||
</div>
|
||||
<MenuWrapper>
|
||||
<div className={hasSort ? 'octo-button active' : 'octo-button'}>
|
||||
<FormattedMessage
|
||||
|
@ -644,8 +655,12 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
await mutator.changePropertyOptionValue(boardTree, boardTree.groupByProperty, option, text)
|
||||
}
|
||||
|
||||
private filterClicked(e: React.MouseEvent) {
|
||||
this.props.showFilter(e.target as HTMLElement)
|
||||
private filterClicked = () => {
|
||||
this.setState({showFilter: true})
|
||||
}
|
||||
|
||||
private hideFilter = () => {
|
||||
this.setState({showFilter: false})
|
||||
}
|
||||
|
||||
private async testAddCards(count: number) {
|
||||
|
|
|
@ -13,74 +13,80 @@ import {Utils} from '../utils'
|
|||
|
||||
type Props = {
|
||||
boardTree: BoardTree
|
||||
pageX: number
|
||||
pageY: number
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
class FilterComponent extends React.Component<Props> {
|
||||
shouldComponentUpdate(): boolean {
|
||||
return true
|
||||
private node: React.RefObject<HTMLDivElement>
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props)
|
||||
this.node = React.createRef()
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
document.addEventListener('click', this.closeOnBlur, true)
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
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()
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const {boardTree} = this.props
|
||||
const {board, activeView} = boardTree
|
||||
|
||||
const backgroundRef = React.createRef<HTMLDivElement>()
|
||||
|
||||
// TODO: Handle FilterGroups (compound filter statements)
|
||||
const filters: FilterClause[] = activeView.filter?.filters.filter((o) => !FilterGroup.isAnInstanceOf(o)) as FilterClause[] || []
|
||||
|
||||
return (
|
||||
<div
|
||||
className='octo-modal-back'
|
||||
ref={backgroundRef}
|
||||
onClick={(e) => {
|
||||
if (e.target === backgroundRef.current) {
|
||||
this.props.onClose()
|
||||
}
|
||||
}}
|
||||
className='octo-modal octo-filter-dialog'
|
||||
style={{position: 'absolute', top: 25, left: -200}}
|
||||
ref={this.node}
|
||||
>
|
||||
{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(',')}`
|
||||
Utils.log(`FilterClause key: ${key}`)
|
||||
return (<div
|
||||
className='octo-filterclause'
|
||||
key={key}
|
||||
>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={(e) => this.propertyClicked(e, filter)}
|
||||
>{propertyName}</div>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={(e) => this.conditionClicked(e, filter)}
|
||||
>{FilterClause.filterConditionDisplayString(filter.condition)}</div>
|
||||
{
|
||||
this.filterValue(filter, template)
|
||||
}
|
||||
<div className='octo-spacer'/>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={() => this.deleteClicked(filter)}
|
||||
>Delete</div>
|
||||
</div>)
|
||||
})}
|
||||
|
||||
<br/>
|
||||
|
||||
<div
|
||||
className='octo-modal octo-filter-dialog'
|
||||
style={{position: 'absolute', left: this.props.pageX, top: this.props.pageY}}
|
||||
>
|
||||
{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(',')}`
|
||||
Utils.log(`FilterClause key: ${key}`)
|
||||
return (<div
|
||||
className='octo-filterclause'
|
||||
key={key}
|
||||
>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={(e) => this.propertyClicked(e, filter)}
|
||||
>{propertyName}</div>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={(e) => this.conditionClicked(e, filter)}
|
||||
>{FilterClause.filterConditionDisplayString(filter.condition)}</div>
|
||||
{
|
||||
this.filterValue(filter, template)
|
||||
}
|
||||
<div className='octo-spacer'/>
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={() => this.deleteClicked(filter)}
|
||||
>Delete</div>
|
||||
</div>)
|
||||
})}
|
||||
|
||||
<br/>
|
||||
|
||||
<div
|
||||
className='octo-button'
|
||||
onClick={() => this.addFilterClicked()}
|
||||
>+ Add Filter</div>
|
||||
</div>
|
||||
className='octo-button'
|
||||
onClick={() => this.addFilterClicked()}
|
||||
>+ Add Filter</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ import {CardDialog} from './cardDialog'
|
|||
import {Editable} from './editable'
|
||||
import RootPortal from './rootPortal'
|
||||
import {TableRow} from './tableRow'
|
||||
import {FilterComponent} from './filterComponent'
|
||||
|
||||
type Props = {
|
||||
boardTree?: BoardTree
|
||||
showView: (id: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
setSearchText: (text: string) => void
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ type State = {
|
|||
isSearching: boolean
|
||||
shownCard?: Card
|
||||
viewMenu: boolean
|
||||
showFilter: boolean
|
||||
}
|
||||
|
||||
class TableComponent extends React.Component<Props, State> {
|
||||
|
@ -46,7 +47,7 @@ class TableComponent extends React.Component<Props, State> {
|
|||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {isHoverOnCover: false, isSearching: Boolean(this.props.boardTree?.getSearchText()), viewMenu: false}
|
||||
this.state = {isHoverOnCover: false, isSearching: Boolean(this.props.boardTree?.getSearchText()), viewMenu: false, showFilter: false}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(): boolean {
|
||||
|
@ -219,14 +220,18 @@ class TableComponent extends React.Component<Props, State> {
|
|||
</MenuWrapper>
|
||||
<div
|
||||
className={hasFilter ? 'octo-button active' : 'octo-button'}
|
||||
onClick={(e) => {
|
||||
this.filterClicked(e)
|
||||
}}
|
||||
style={{position: 'relative', overflow: 'unset'}}
|
||||
onClick={this.filterClicked}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='TableComponent.filter'
|
||||
defaultMessage='Filter'
|
||||
/>
|
||||
{this.state.showFilter &&
|
||||
<FilterComponent
|
||||
boardTree={boardTree}
|
||||
onClose={this.hideFilter}
|
||||
/>}
|
||||
</div>
|
||||
<MenuWrapper>
|
||||
<div className={hasSort ? 'octo-button active' : 'octo-button'}>
|
||||
|
@ -457,8 +462,12 @@ class TableComponent extends React.Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private filterClicked(e: React.MouseEvent) {
|
||||
this.props.showFilter(e.target as HTMLElement)
|
||||
private filterClicked = () => {
|
||||
this.setState({showFilter: true})
|
||||
}
|
||||
|
||||
private hideFilter = () => {
|
||||
this.setState({showFilter: false})
|
||||
}
|
||||
|
||||
private async headerClicked(e: React.MouseEvent<HTMLDivElement>, templateId: string) {
|
||||
|
|
|
@ -15,7 +15,6 @@ type Props = {
|
|||
boardTree?: BoardTree
|
||||
showBoard: (id: string) => void
|
||||
showView: (id: string, boardId?: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
setSearchText: (text: string) => void
|
||||
setLanguage: (lang: string) => void
|
||||
}
|
||||
|
@ -41,7 +40,7 @@ class WorkspaceComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private mainComponent() {
|
||||
const {boardTree, showFilter, setSearchText, showView} = this.props
|
||||
const {boardTree, setSearchText, showView} = this.props
|
||||
const {activeView} = boardTree || {}
|
||||
|
||||
if (!activeView) {
|
||||
|
@ -52,19 +51,17 @@ class WorkspaceComponent extends React.Component<Props> {
|
|||
case 'board': {
|
||||
return (<BoardComponent
|
||||
boardTree={boardTree}
|
||||
showFilter={showFilter}
|
||||
setSearchText={setSearchText}
|
||||
showView={showView}
|
||||
/>)
|
||||
/>)
|
||||
}
|
||||
|
||||
case 'table': {
|
||||
return (<TableComponent
|
||||
boardTree={boardTree}
|
||||
showFilter={showFilter}
|
||||
setSearchText={setSearchText}
|
||||
showView={showView}
|
||||
/>)
|
||||
/>)
|
||||
}
|
||||
|
||||
default: {
|
||||
|
|
|
@ -22,7 +22,6 @@ type State = {
|
|||
viewId: string
|
||||
workspaceTree: MutableWorkspaceTree
|
||||
boardTree?: MutableBoardTree
|
||||
filterAnchorElement?: HTMLElement
|
||||
}
|
||||
|
||||
export default class BoardPage extends React.Component<Props, State> {
|
||||
|
@ -112,34 +111,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
render(): JSX.Element {
|
||||
const {workspaceTree} = this.state
|
||||
|
||||
if (this.state.filterAnchorElement) {
|
||||
const element = this.state.filterAnchorElement
|
||||
const bodyRect = document.body.getBoundingClientRect()
|
||||
const rect = element.getBoundingClientRect()
|
||||
|
||||
// Show at bottom-left of element
|
||||
const maxX = bodyRect.right - 420 - 100
|
||||
const pageX = Math.min(maxX, rect.left - bodyRect.left)
|
||||
const pageY = rect.bottom - bodyRect.top
|
||||
|
||||
ReactDOM.render(
|
||||
<FilterComponent
|
||||
boardTree={this.state.boardTree}
|
||||
pageX={pageX}
|
||||
pageY={pageY}
|
||||
onClose={() => {
|
||||
this.showFilter(undefined)
|
||||
}}
|
||||
/>,
|
||||
Utils.getElementById('modal'),
|
||||
)
|
||||
} else {
|
||||
const modal = document.getElementById('modal')
|
||||
if (modal) {
|
||||
ReactDOM.render(<div/>, modal)
|
||||
}
|
||||
}
|
||||
|
||||
Utils.log(`BoardPage.render ${this.state.boardTree?.board?.title}`)
|
||||
return (
|
||||
<div className='BoardPage'>
|
||||
|
@ -152,9 +123,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
showBoard={(id) => {
|
||||
this.showBoard(id)
|
||||
}}
|
||||
showFilter={(el) => {
|
||||
this.showFilter(el)
|
||||
}}
|
||||
setSearchText={(text) => {
|
||||
this.setSearchText(text)
|
||||
}}
|
||||
|
@ -230,10 +198,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
window.history.pushState({path: newUrl}, '', newUrl)
|
||||
}
|
||||
|
||||
showFilter(anchorElement?: HTMLElement): void {
|
||||
this.setState({...this.state, filterAnchorElement: anchorElement})
|
||||
}
|
||||
|
||||
setSearchText(text?: string): void {
|
||||
this.state.boardTree?.setSearchText(text)
|
||||
this.setState({...this.state, boardTree: this.state.boardTree})
|
||||
|
|
Loading…
Reference in a new issue