1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-05-13 21:37:37 +02:00

Merge pull request #8 from mattermost/remove-show-card

Removing the need of the global showCard
This commit is contained in:
chenilim 2020-10-15 11:33:13 -07:00 committed by GitHub
commit c19d49ccff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 82 deletions

View File

@ -18,17 +18,20 @@ import { BoardCard } from "./boardCard"
import { BoardColumn } from "./boardColumn" import { BoardColumn } from "./boardColumn"
import Button from "./button" import Button from "./button"
import { Editable } from "./editable" import { Editable } from "./editable"
import { CardDialog } from "./cardDialog"
import RootPortal from "./rootPortal"
type Props = { type Props = {
boardTree?: BoardTree boardTree?: BoardTree
showView: (id: string) => void showView: (id: string) => void
showCard: (card: Card) => void
showFilter: (el: HTMLElement) => void showFilter: (el: HTMLElement) => void
setSearchText: (text: string) => void setSearchText: (text: string) => void
} }
type State = { type State = {
isSearching: boolean isSearching: boolean
shownCard?: Card
viewMenu: boolean
isHoverOnCover: boolean isHoverOnCover: boolean
} }
@ -39,7 +42,7 @@ class BoardComponent extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props) super(props)
this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText()} this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText(), viewMenu: false }
} }
componentDidUpdate(prevPros: Props, prevState: State) { componentDidUpdate(prevPros: Props, prevState: State) {
@ -68,6 +71,11 @@ class BoardComponent extends React.Component<Props, State> {
return ( return (
<div className="octo-app"> <div className="octo-app">
{this.state.shownCard &&
<RootPortal>
<CardDialog boardTree={boardTree} card={this.state.shownCard} onClose={() => this.setState({shownCard: undefined})}/>
</RootPortal>}
<div className="octo-frame"> <div className="octo-frame">
<div <div
className="octo-hovercontrols" className="octo-hovercontrols"
@ -198,7 +206,7 @@ class BoardComponent extends React.Component<Props, State> {
card={card} card={card}
visiblePropertyTemplates={visiblePropertyTemplates} visiblePropertyTemplates={visiblePropertyTemplates}
key={card.id} key={card.id}
onClick={() => { this.showCard(card) }} onClick={() => { this.setState({shownCard: card}) }}
onDragStart={() => { this.draggedCard = card }} onDragStart={() => { this.draggedCard = card }}
onDragEnd={() => { this.draggedCard = undefined }} /> onDragEnd={() => { this.draggedCard = undefined }} />
)} )}
@ -214,7 +222,7 @@ class BoardComponent extends React.Component<Props, State> {
card={card} card={card}
visiblePropertyTemplates={visiblePropertyTemplates} visiblePropertyTemplates={visiblePropertyTemplates}
key={card.id} key={card.id}
onClick={() => { this.showCard(card) }} onClick={() => { this.setState({shownCard: card}) }}
onDragStart={() => { this.draggedCard = card }} onDragStart={() => { this.draggedCard = card }}
onDragEnd={() => { this.draggedCard = undefined }} /> onDragEnd={() => { this.draggedCard = undefined }} />
)} )}
@ -228,12 +236,6 @@ class BoardComponent extends React.Component<Props, State> {
) )
} }
async showCard(card?: Card) {
console.log(`showCard: ${card?.title}`)
await this.props.showCard(card)
}
async addCard(groupByValue?: string) { async addCard(groupByValue?: string) {
const { boardTree } = this.props const { boardTree } = this.props
const { activeView, board } = boardTree const { activeView, board } = boardTree
@ -244,7 +246,7 @@ class BoardComponent extends React.Component<Props, State> {
if (boardTree.groupByProperty) { if (boardTree.groupByProperty) {
card.properties[boardTree.groupByProperty.id] = groupByValue card.properties[boardTree.groupByProperty.id] = groupByValue
} }
await mutator.insertBlock(card, "add card", async () => { await this.showCard(card) }, async () => { await this.showCard(undefined) }) await mutator.insertBlock(card, "add card", async () => { await this.setState({shownCard: card}) }, async () => { await this.setState({shownCard: undefined}) })
} }
async propertyNameChanged(option: IPropertyOption, text: string) { async propertyNameChanged(option: IPropertyOption, text: string) {

View File

@ -1,5 +1,6 @@
import React from "react" import React from "react"
import { Block } from "../block" import { Block } from "../block"
import { Card } from "../card"
import { BlockIcons } from "../blockIcons" import { BlockIcons } from "../blockIcons"
import { BoardTree } from "../boardTree" import { BoardTree } from "../boardTree"
import { CardTree } from "../cardTree" import { CardTree } from "../cardTree"
@ -8,6 +9,7 @@ import mutator from "../mutator"
import { IBlock } from "../octoTypes" import { IBlock } from "../octoTypes"
import { OctoUtils } from "../octoUtils" import { OctoUtils } from "../octoUtils"
import { PropertyMenu } from "../propertyMenu" import { PropertyMenu } from "../propertyMenu"
import { OctoListener } from "../octoListener"
import { Utils } from "../utils" import { Utils } from "../utils"
import Button from "./button" import Button from "./button"
import { Editable } from "./editable" import { Editable } from "./editable"
@ -15,26 +17,25 @@ import { MarkdownEditor } from "./markdownEditor"
type Props = { type Props = {
boardTree: BoardTree boardTree: BoardTree
cardTree: CardTree card: Card
onClose: () => void onClose: () => void
} }
type State = { type State = {
isHoverOnCover: boolean isHoverOnCover: boolean
cardTree?: CardTree
} }
class CardDialog extends React.Component<Props, State> { class CardDialog extends React.Component<Props, State> {
private titleRef = React.createRef<Editable>() private titleRef = React.createRef<Editable>()
private keydownHandler: any private cardListener: OctoListener
constructor(props: Props) { constructor(props: Props) {
super(props) super(props)
this.state = { isHoverOnCover: false } this.state = { isHoverOnCover: false }
} }
componentDidMount() { keydownHandler = (e: KeyboardEvent) => {
this.titleRef.current.focus()
this.keydownHandler = (e: KeyboardEvent) => {
if (e.target !== document.body) { return } if (e.target !== document.body) { return }
if (e.keyCode === 27) { if (e.keyCode === 27) {
@ -42,17 +43,40 @@ class CardDialog extends React.Component<Props, State> {
e.stopPropagation() e.stopPropagation()
} }
} }
componentDidMount() {
this.cardListener = new OctoListener()
this.cardListener.open(this.props.card.id, async () => {
await cardTree.sync()
this.setState({cardTree: cardTree})
})
const cardTree = new CardTree(this.props.card.id)
cardTree.sync().then(() => {
this.setState({cardTree})
});
document.addEventListener("keydown", this.keydownHandler) document.addEventListener("keydown", this.keydownHandler)
} }
componentDidUpdate(prevProps: Props, prevState: State) {
if (this.titleRef.current && prevState.cardTree === undefined && this.state.cardTree !== undefined) {
this.titleRef.current.focus()
}
}
componentWillUnmount() { componentWillUnmount() {
document.removeEventListener("keydown", this.keydownHandler) document.removeEventListener("keydown", this.keydownHandler)
} }
render() { render() {
const { boardTree, cardTree } = this.props const { boardTree, card } = this.props
const { cardTree } = this.state
const { board } = boardTree const { board } = boardTree
const { card, comments } = cardTree if (cardTree === undefined) {
return null
}
const { comments } = cardTree
const newCommentPlaceholderText = "Add a comment..." const newCommentPlaceholderText = "Add a comment..."
@ -331,8 +355,7 @@ class CardDialog extends React.Component<Props, State> {
} }
async sendComment(text: string) { async sendComment(text: string) {
const { cardTree } = this.props const { card } = this.props
const { card } = cardTree
Utils.assertValue(card) Utils.assertValue(card)
@ -341,8 +364,8 @@ class CardDialog extends React.Component<Props, State> {
} }
private showContentBlockMenu(e: React.MouseEvent, block: IBlock) { private showContentBlockMenu(e: React.MouseEvent, block: IBlock) {
const { cardTree } = this.props const { card } = this.props
const { card } = cardTree const { cardTree } = this.state
const index = cardTree.contents.indexOf(block) const index = cardTree.contents.indexOf(block)
const options: MenuOption[] = [] const options: MenuOption[] = []
@ -408,8 +431,7 @@ class CardDialog extends React.Component<Props, State> {
} }
private iconClicked(e: React.MouseEvent) { private iconClicked(e: React.MouseEvent) {
const { cardTree } = this.props const { card } = this.props
const { card } = cardTree
Menu.shared.options = [ Menu.shared.options = [
{ id: "random", name: "Random" }, { id: "random", name: "Random" },

View File

@ -16,11 +16,12 @@ import { Utils } from "../utils"
import Button from "./button" import Button from "./button"
import { Editable } from "./editable" import { Editable } from "./editable"
import { TableRow } from "./tableRow" import { TableRow } from "./tableRow"
import { CardDialog } from "./cardDialog"
import RootPortal from "./rootPortal"
type Props = { type Props = {
boardTree?: BoardTree boardTree?: BoardTree
showView: (id: string) => void showView: (id: string) => void
showCard: (card: Card) => void
showFilter: (el: HTMLElement) => void showFilter: (el: HTMLElement) => void
setSearchText: (text: string) => void setSearchText: (text: string) => void
} }
@ -28,6 +29,7 @@ type Props = {
type State = { type State = {
isHoverOnCover: boolean isHoverOnCover: boolean
isSearching: boolean isSearching: boolean
shownCard?: Card
viewMenu: boolean viewMenu: boolean
} }
@ -66,6 +68,10 @@ class TableComponent extends React.Component<Props, State> {
return ( return (
<div className="octo-app"> <div className="octo-app">
{this.state.shownCard &&
<RootPortal>
<CardDialog boardTree={boardTree} card={this.state.shownCard} onClose={() => this.setState({shownCard: undefined})}/>
</RootPortal>}
<div className="octo-frame"> <div className="octo-frame">
<div <div
className="octo-hovercontrols" className="octo-hovercontrols"
@ -187,7 +193,6 @@ class TableComponent extends React.Component<Props, State> {
boardTree={boardTree} boardTree={boardTree}
card={card} card={card}
focusOnMount={focusOnMount} focusOnMount={focusOnMount}
showCard={(c) => { this.showCard(c) }}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
// Enter: Insert new card if on last row // Enter: Insert new card if on last row
@ -345,12 +350,6 @@ class TableComponent extends React.Component<Props, State> {
OldMenu.shared.showAtElement(e.target as HTMLElement) OldMenu.shared.showAtElement(e.target as HTMLElement)
} }
async showCard(card: Card) {
console.log(`showCard: ${card.title}`)
await this.props.showCard(card)
}
focusOnCardTitle(cardId: string) { focusOnCardTitle(cardId: string) {
const tableRowRef = this.cardIdToRowMap.get(cardId) const tableRowRef = this.cardIdToRowMap.get(cardId)
Utils.log(`focusOnCardTitle, ${tableRowRef?.current ?? "undefined"}`) Utils.log(`focusOnCardTitle, ${tableRowRef?.current ?? "undefined"}`)
@ -367,7 +366,7 @@ class TableComponent extends React.Component<Props, State> {
"add card", "add card",
async () => { async () => {
if (show) { if (show) {
this.showCard(card) this.setState({shownCard: card})
} else { } else {
// Focus on this card's title inline on next render // Focus on this card's title inline on next render
this.cardIdToFocusOnRender = card.id this.cardIdToFocusOnRender = card.id

View File

@ -4,20 +4,25 @@ import { Card } from "../card"
import mutator from "../mutator" import mutator from "../mutator"
import { OctoUtils } from "../octoUtils" import { OctoUtils } from "../octoUtils"
import { Editable } from "./editable" import { Editable } from "./editable"
import { CardDialog } from "./cardDialog"
import RootPortal from "./rootPortal"
type Props = { type Props = {
boardTree: BoardTree boardTree: BoardTree
card: Card card: Card
focusOnMount: boolean focusOnMount: boolean
showCard: (card: Card) => void
onKeyDown: (e: React.KeyboardEvent) => void onKeyDown: (e: React.KeyboardEvent) => void
} }
type State = { type State = {
showCard: boolean
} }
class TableRow extends React.Component<Props, State> { class TableRow extends React.Component<Props, State> {
private titleRef = React.createRef<Editable>() private titleRef = React.createRef<Editable>()
state = {
showCard: false
}
componentDidMount() { componentDidMount() {
if (this.props.focusOnMount) { if (this.props.focusOnMount) {
@ -26,7 +31,7 @@ class TableRow extends React.Component<Props, State> {
} }
render() { render() {
const { boardTree, card, showCard, onKeyDown } = this.props const { boardTree, card, onKeyDown } = this.props
const { board, activeView } = boardTree const { board, activeView } = boardTree
const openButonRef = React.createRef<HTMLDivElement>() const openButonRef = React.createRef<HTMLDivElement>()
@ -47,7 +52,11 @@ class TableRow extends React.Component<Props, State> {
/> />
</div> </div>
<div ref={openButonRef} className="octo-hoverbutton" style={{ display: "none" }} onClick={() => { showCard(card) }}>Open</div> <div ref={openButonRef} className="octo-hoverbutton" style={{ display: "none" }} onClick={() => { this.setState({showCard: true}) }}>Open</div>
{this.state.showCard &&
<RootPortal>
<CardDialog boardTree={boardTree} card={card} onClose={() => this.setState({showCard: false})}/>
</RootPortal>}
</div> </div>
{/* Columns, one per property */} {/* Columns, one per property */}

View File

@ -12,7 +12,6 @@ type Props = {
boardTree?: BoardTree boardTree?: BoardTree
showBoard: (id: string) => void showBoard: (id: string) => void
showView: (id: string) => void showView: (id: string) => void
showCard: (card: Card) => void
showFilter: (el: HTMLElement) => void showFilter: (el: HTMLElement) => void
setSearchText: (text: string) => void setSearchText: (text: string) => void
} }
@ -32,7 +31,7 @@ class WorkspaceComponent extends React.Component<Props> {
} }
private mainComponent() { private mainComponent() {
const { boardTree, showCard, showFilter, setSearchText, showView } = this.props const { boardTree, showFilter, setSearchText, showView } = this.props
const { activeView } = boardTree || {} const { activeView } = boardTree || {}
if (!activeView) { if (!activeView) {
@ -41,11 +40,11 @@ class WorkspaceComponent extends React.Component<Props> {
switch (activeView?.viewType) { switch (activeView?.viewType) {
case "board": { case "board": {
return <BoardComponent boardTree={boardTree} showCard={showCard} showFilter={showFilter} setSearchText={setSearchText} showView={showView} /> return <BoardComponent boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
} }
case "table": { case "table": {
return <TableComponent boardTree={boardTree} showCard={showCard} showFilter={showFilter} setSearchText={setSearchText} showView={showView} /> return <TableComponent boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
} }
default: { default: {

View File

@ -18,7 +18,6 @@ interface IBlock {
// These are methods exposed by the top-level page to components // These are methods exposed by the top-level page to components
interface IPageController { interface IPageController {
showCard(card: Card): Promise<void>
showBoard(boardId: string): void showBoard(boardId: string): void
showView(viewId: string): void showView(viewId: string): void
showFilter(anchorElement?: HTMLElement): void showFilter(anchorElement?: HTMLElement): void

View File

@ -107,22 +107,6 @@ export default class BoardPage extends React.Component<Props, State> {
const { workspaceTree, shownCardTree } = this.state const { workspaceTree, shownCardTree } = this.state
const { board, activeView } = this.state.boardTree || {} const { board, activeView } = this.state.boardTree || {}
// TODO Move all this into the root portal component when that is merged
if (this.state.boardTree && this.state.boardTree.board && shownCardTree) {
ReactDOM.render(
<CardDialog boardTree={this.state.boardTree} cardTree={shownCardTree} onClose={() => { this.showCard(undefined) }}></CardDialog>,
Utils.getElementById("overlay")
)
} else {
const overlay = document.getElementById("overlay")
if (overlay) {
ReactDOM.render(
<div />,
overlay
)
}
}
if (this.state.filterAnchorElement) { if (this.state.filterAnchorElement) {
const element = this.state.filterAnchorElement const element = this.state.filterAnchorElement
const bodyRect = document.body.getBoundingClientRect() const bodyRect = document.body.getBoundingClientRect()
@ -156,7 +140,6 @@ export default class BoardPage extends React.Component<Props, State> {
workspaceTree={workspaceTree} workspaceTree={workspaceTree}
boardTree={this.state.boardTree} boardTree={this.state.boardTree}
showView={(id) => { this.showView(id) }} showView={(id) => { this.showView(id) }}
showCard={(card) => { this.showCard(card) }}
showBoard={(id) => { this.showBoard(id) }} showBoard={(id) => { this.showBoard(id) }}
showFilter={(el) => { this.showFilter(el) }} showFilter={(el) => { this.showFilter(el) }}
setSearchText={(text) => { this.setSearchText(text) }} /> setSearchText={(text) => { this.setSearchText(text) }} />
@ -204,25 +187,6 @@ export default class BoardPage extends React.Component<Props, State> {
} }
// IPageController // IPageController
async showCard(card: Card) {
this.cardListener.close()
if (card) {
const cardTree = new CardTree(card.id)
await cardTree.sync()
this.setState({...this.state, shownCardTree: cardTree})
this.cardListener = new OctoListener()
this.cardListener.open(card.id, async () => {
await cardTree.sync()
this.forceUpdate()
})
} else {
this.setState({...this.state, shownCardTree: undefined})
}
}
showBoard(boardId: string) { showBoard(boardId: string) {
const { boardTree } = this.state const { boardTree } = this.state