Merge branch 'main' into remove-show-card
This commit is contained in:
commit
e740ce43d5
22 changed files with 329 additions and 360 deletions
|
@ -1,5 +1,5 @@
|
|||
import { BoardTree } from "./boardTree"
|
||||
import { Mutator } from "./mutator"
|
||||
import mutator from "./mutator"
|
||||
import { IBlock } from "./octoTypes"
|
||||
import { Utils } from "./utils"
|
||||
|
||||
|
@ -21,7 +21,7 @@ class Archiver {
|
|||
this.exportArchive(archive)
|
||||
}
|
||||
|
||||
static async exportFullArchive(mutator: Mutator) {
|
||||
static async exportFullArchive() {
|
||||
const blocks = await mutator.exportFullArchive()
|
||||
const archive: Archive = {
|
||||
version: 1,
|
||||
|
@ -50,7 +50,7 @@ class Archiver {
|
|||
// TODO: Remove or reuse link
|
||||
}
|
||||
|
||||
static importFullArchive(mutator: Mutator, onImported?: () => void): void {
|
||||
static importFullArchive(onImported?: () => void): void {
|
||||
const input = document.createElement("input")
|
||||
input.type = "file"
|
||||
input.accept = ".octo"
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Board, IPropertyOption, IPropertyTemplate } from "./board"
|
|||
import { BoardView } from "./boardView"
|
||||
import { Card } from "./card"
|
||||
import { CardFilter } from "./cardFilter"
|
||||
import { OctoClient } from "./octoClient"
|
||||
import octoClient from "./octoClient"
|
||||
import { IBlock } from "./octoTypes"
|
||||
import { Utils } from "./utils"
|
||||
|
||||
|
@ -24,13 +24,11 @@ class BoardTree {
|
|||
return [this.board, ...this.views, ...this.allCards]
|
||||
}
|
||||
|
||||
constructor(
|
||||
private octo: OctoClient,
|
||||
private boardId: string) {
|
||||
constructor(private boardId: string) {
|
||||
}
|
||||
|
||||
async sync() {
|
||||
const blocks = await this.octo.getSubtree(this.boardId)
|
||||
const blocks = await octoClient.getSubtree(this.boardId)
|
||||
this.rebuild(blocks)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Card } from "./card"
|
||||
import { OctoClient } from "./octoClient"
|
||||
import octoClient from "./octoClient"
|
||||
import { IBlock } from "./octoTypes"
|
||||
|
||||
class CardTree {
|
||||
|
@ -8,13 +8,11 @@ class CardTree {
|
|||
contents: IBlock[]
|
||||
isSynched: boolean
|
||||
|
||||
constructor(
|
||||
private octo: OctoClient,
|
||||
private cardId: string) {
|
||||
constructor(private cardId: string) {
|
||||
}
|
||||
|
||||
async sync() {
|
||||
const blocks = await this.octo.getSubtree(this.cardId)
|
||||
const blocks = await octoClient.getSubtree(this.cardId)
|
||||
this.rebuild(blocks)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@ import { Block } from "../block"
|
|||
import { IPropertyTemplate } from "../board"
|
||||
import { Card } from "../card"
|
||||
import { Menu } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { OctoUtils } from "../octoUtils"
|
||||
import { Utils } from "../utils"
|
||||
|
||||
type BoardCardProps = {
|
||||
mutator: Mutator
|
||||
card: Card
|
||||
visiblePropertyTemplates: IPropertyTemplate[]
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void
|
||||
|
@ -58,7 +57,7 @@ class BoardCard extends React.Component<BoardCardProps, BoardCardState> {
|
|||
}
|
||||
|
||||
private showOptionsMenu(e: React.MouseEvent) {
|
||||
const { mutator, card } = this.props
|
||||
const { card } = this.props
|
||||
|
||||
e.stopPropagation()
|
||||
|
||||
|
|
|
@ -6,10 +6,12 @@ import { BoardTree } from "../boardTree"
|
|||
import { Card } from "../card"
|
||||
import { CardFilter } from "../cardFilter"
|
||||
import ViewMenu from "../components/viewMenu"
|
||||
import MenuWrapper from "../widgets/menuWrapper"
|
||||
import Menu from "../widgets/menu"
|
||||
import { Constants } from "../constants"
|
||||
import { randomEmojiList } from "../emojiList"
|
||||
import { Menu as OldMenu } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { OctoUtils } from "../octoUtils"
|
||||
import { Utils } from "../utils"
|
||||
import { BoardCard } from "./boardCard"
|
||||
|
@ -20,7 +22,6 @@ import { CardDialog } from "./cardDialog"
|
|||
import RootPortal from "./rootPortal"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator,
|
||||
boardTree?: BoardTree
|
||||
showView: (id: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
|
@ -28,10 +29,10 @@ type Props = {
|
|||
}
|
||||
|
||||
type State = {
|
||||
isHoverOnCover: boolean
|
||||
isSearching: boolean
|
||||
shownCard: IBlock | null
|
||||
shownCard: Card | null
|
||||
viewMenu: boolean
|
||||
isHoverOnCover: boolean
|
||||
}
|
||||
|
||||
class BoardComponent extends React.Component<Props, State> {
|
||||
|
@ -51,7 +52,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { mutator, boardTree, showView } = this.props
|
||||
const { boardTree, showView } = this.props
|
||||
|
||||
if (!boardTree || !boardTree.board) {
|
||||
return (
|
||||
|
@ -92,7 +93,13 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
|
||||
<div className="octo-icontitle">
|
||||
{board.icon ?
|
||||
<div className="octo-button octo-icon" onClick={(e) => { this.iconClicked(e) }}>{board.icon}</div>
|
||||
<MenuWrapper>
|
||||
<div className="octo-button octo-icon">{board.icon}</div>
|
||||
<Menu>
|
||||
<Menu.Text id='random' name='Random' onClick={() => mutator.changeIcon(board, undefined, "remove icon")}/>
|
||||
<Menu.Text id='remove' name='Remove Icon' onClick={() => mutator.changeIcon(board, BlockIcons.shared.randomIcon())}/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
: undefined}
|
||||
<Editable className="title" text={board.title} placeholderText="Untitled Board" onChanged={(text) => { mutator.changeTitle(board, text) }} />
|
||||
</div>
|
||||
|
@ -100,28 +107,26 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
<div className="octo-board">
|
||||
<div className="octo-controls">
|
||||
<Editable style={{ color: "#000000", fontWeight: 600 }} text={activeView.title} placeholderText="Untitled View" onChanged={(text) => { mutator.changeTitle(activeView, text) }} />
|
||||
<div
|
||||
className="octo-button"
|
||||
style={{ color: "#000000", fontWeight: 600 }}
|
||||
onClick={() => this.setState({ viewMenu: true })}
|
||||
>
|
||||
{this.state.viewMenu &&
|
||||
<ViewMenu
|
||||
board={board}
|
||||
onClose={() => this.setState({ viewMenu: false })}
|
||||
mutator={mutator}
|
||||
boardTree={boardTree}
|
||||
showView={showView}
|
||||
/>}
|
||||
<div className="imageDropdown"></div>
|
||||
</div>
|
||||
<MenuWrapper>
|
||||
<div
|
||||
className="octo-button"
|
||||
style={{ color: "#000000", fontWeight: 600 }}
|
||||
>
|
||||
<div className="imageDropdown"></div>
|
||||
</div>
|
||||
<ViewMenu
|
||||
board={board}
|
||||
boardTree={boardTree}
|
||||
showView={showView}
|
||||
/>
|
||||
</MenuWrapper>
|
||||
<div className="octo-spacer"></div>
|
||||
<div className="octo-button" onClick={(e) => { this.propertiesClicked(e) }}>Properties</div>
|
||||
<div className="octo-button" id="groupByButton" onClick={(e) => { this.groupByClicked(e) }}>
|
||||
Group by <span style={groupByStyle} id="groupByLabel">{boardTree.groupByProperty?.name}</span>
|
||||
</div>
|
||||
<div className={hasFilter ? "octo-button active" : "octo-button"} onClick={(e) => { this.filterClicked(e) }}>Filter</div>
|
||||
<div className={hasSort ? "octo-button active" : "octo-button"} onClick={(e) => { OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort</div>
|
||||
<div className={hasSort ? "octo-button active" : "octo-button"} onClick={(e) => { OctoUtils.showSortMenu(e, boardTree) }}>Sort</div>
|
||||
{this.state.isSearching
|
||||
? <Editable
|
||||
ref={this.searchFieldRef}
|
||||
|
@ -170,7 +175,16 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
onChanged={(text) => { this.propertyNameChanged(group.option, text) }} />
|
||||
<Button text={`${group.cards.length}`} />
|
||||
<div className="octo-spacer" />
|
||||
<Button onClick={(e) => { this.valueOptionClicked(e, group.option) }}><div className="imageOptions" /></Button>
|
||||
<MenuWrapper>
|
||||
<Button><div className="imageOptions" /></Button>
|
||||
<Menu>
|
||||
<Menu.Text id='delete' name='Delete' onClick={() => mutator.deletePropertyOption(boardTree, boardTree.groupByProperty, group.option)}/>
|
||||
<Menu.Separator/>
|
||||
{Constants.menuColors.map((color) =>
|
||||
<Menu.Color key={color.id} id={color.id} name={color.name} onClick={() => mutator.changePropertyOptionColor(boardTree.board, group.option, color.id)} />
|
||||
)}
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
<Button onClick={() => { this.addCard(group.option.value) }}><div className="imageAdd" /></Button>
|
||||
</div>
|
||||
)}
|
||||
|
@ -189,7 +203,6 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
<BoardColumn onDrop={(e) => { this.onDropToColumn(undefined) }}>
|
||||
{boardTree.emptyGroupCards.map(card =>
|
||||
<BoardCard
|
||||
mutator={mutator}
|
||||
card={card}
|
||||
visiblePropertyTemplates={visiblePropertyTemplates}
|
||||
key={card.id}
|
||||
|
@ -206,7 +219,6 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
<BoardColumn onDrop={(e) => { this.onDropToColumn(group.option) }} key={group.option.value}>
|
||||
{group.cards.map(card =>
|
||||
<BoardCard
|
||||
mutator={mutator}
|
||||
card={card}
|
||||
visiblePropertyTemplates={visiblePropertyTemplates}
|
||||
key={card.id}
|
||||
|
@ -224,30 +236,8 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private iconClicked(e: React.MouseEvent) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { board } = boardTree
|
||||
|
||||
OldMenu.shared.options = [
|
||||
{ id: "random", name: "Random" },
|
||||
{ id: "remove", name: "Remove Icon" },
|
||||
]
|
||||
OldMenu.shared.onMenuClicked = (optionId: string, type?: string) => {
|
||||
switch (optionId) {
|
||||
case "remove":
|
||||
mutator.changeIcon(board, undefined, "remove icon")
|
||||
break
|
||||
case "random":
|
||||
const newIcon = BlockIcons.shared.randomIcon()
|
||||
mutator.changeIcon(board, newIcon)
|
||||
break
|
||||
}
|
||||
}
|
||||
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
||||
}
|
||||
|
||||
async addCard(groupByValue?: string) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { activeView, board } = boardTree
|
||||
|
||||
const card = new Card()
|
||||
|
@ -260,36 +250,11 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
async propertyNameChanged(option: IPropertyOption, text: string) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
|
||||
await mutator.changePropertyOptionValue(boardTree, boardTree.groupByProperty, option, text)
|
||||
}
|
||||
|
||||
async valueOptionClicked(e: React.MouseEvent<HTMLElement>, option: IPropertyOption) {
|
||||
const { mutator, boardTree } = this.props
|
||||
|
||||
OldMenu.shared.options = [
|
||||
{ id: "delete", name: "Delete" },
|
||||
{ id: "", name: "", type: "separator" },
|
||||
...Constants.menuColors
|
||||
]
|
||||
OldMenu.shared.onMenuClicked = async (optionId: string, type?: string) => {
|
||||
switch (optionId) {
|
||||
case "delete":
|
||||
console.log(`Delete property value: ${option.value}`)
|
||||
await mutator.deletePropertyOption(boardTree, boardTree.groupByProperty, option)
|
||||
break
|
||||
default:
|
||||
if (type === "color") {
|
||||
// id is the color
|
||||
await mutator.changePropertyOptionColor(boardTree.board, option, optionId)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
||||
}
|
||||
|
||||
private filterClicked(e: React.MouseEvent) {
|
||||
this.props.showFilter(e.target as HTMLElement)
|
||||
}
|
||||
|
@ -323,7 +288,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private async testAddCards(count: number) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board, activeView } = boardTree
|
||||
|
||||
const startCount = boardTree?.cards?.length
|
||||
|
@ -346,7 +311,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private async propertiesClicked(e: React.MouseEvent) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { activeView } = boardTree
|
||||
|
||||
const selectProperties = boardTree.board.cardProperties
|
||||
|
@ -372,7 +337,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private async groupByClicked(e: React.MouseEvent) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
|
||||
const selectProperties = boardTree.board.cardProperties.filter(o => o.type === "select")
|
||||
OldMenu.shared.options = selectProperties.map((o) => { return { id: o.id, name: o.name } })
|
||||
|
@ -387,7 +352,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
async addGroupClicked() {
|
||||
console.log(`onAddGroupClicked`)
|
||||
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
|
||||
const option: IPropertyOption = {
|
||||
value: "New group",
|
||||
|
@ -399,7 +364,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
async onDropToColumn(option: IPropertyOption) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { draggedCard, draggedHeaderOption } = this
|
||||
const propertyValue = option ? option.value : undefined
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from "react"
|
||||
import { Block } from "../block"
|
||||
import { Card } from "../card"
|
||||
import { BlockIcons } from "../blockIcons"
|
||||
import { BoardTree } from "../boardTree"
|
||||
import { CardTree } from "../cardTree"
|
||||
import { Menu, MenuOption } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { IBlock } from "../octoTypes"
|
||||
import { OctoUtils } from "../octoUtils"
|
||||
import { PropertyMenu } from "../propertyMenu"
|
||||
import { OctoListener } from "../octoListener"
|
||||
import { OctoClient } from "../octoClient"
|
||||
import { Utils } from "../utils"
|
||||
import Button from "./button"
|
||||
import { Editable } from "./editable"
|
||||
|
@ -17,8 +17,7 @@ import { MarkdownEditor } from "./markdownEditor"
|
|||
|
||||
type Props = {
|
||||
boardTree: BoardTree
|
||||
card: IBlock
|
||||
mutator: Mutator
|
||||
card: Card
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
|
@ -51,7 +50,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
await cardTree.sync()
|
||||
this.setState({cardTree: cardTree})
|
||||
})
|
||||
const cardTree = new CardTree(new OctoClient(), this.props.card.id)
|
||||
const cardTree = new CardTree(this.props.card.id)
|
||||
cardTree.sync().then(() => {
|
||||
this.setState({cardTree})
|
||||
});
|
||||
|
@ -70,7 +69,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { boardTree, mutator, card } = this.props
|
||||
const { boardTree, card } = this.props
|
||||
const { cardTree } = this.state
|
||||
const { board } = boardTree
|
||||
if (cardTree === null) {
|
||||
|
@ -227,7 +226,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
}
|
||||
menu.showAtElement(e.target as HTMLElement)
|
||||
}}>{propertyTemplate.name}</div>
|
||||
{OctoUtils.propertyValueEditableElement(mutator, card, propertyTemplate)}
|
||||
{OctoUtils.propertyValueEditableElement(card, propertyTemplate)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
@ -356,7 +355,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
async sendComment(text: string) {
|
||||
const { mutator, card } = this.props
|
||||
const { card } = this.props
|
||||
|
||||
Utils.assertValue(card)
|
||||
|
||||
|
@ -365,7 +364,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private showContentBlockMenu(e: React.MouseEvent, block: IBlock) {
|
||||
const { mutator, card } = this.props
|
||||
const { card } = this.props
|
||||
const { cardTree } = this.state
|
||||
const index = cardTree.contents.indexOf(block)
|
||||
|
||||
|
@ -432,7 +431,7 @@ class CardDialog extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private iconClicked(e: React.MouseEvent) {
|
||||
const { mutator, card } = this.props
|
||||
const { card } = this.props
|
||||
|
||||
Menu.shared.options = [
|
||||
{ id: "random", name: "Random" },
|
||||
|
|
|
@ -3,11 +3,10 @@ import { BoardTree } from "../boardTree"
|
|||
import { FilterClause, FilterCondition } from "../filterClause"
|
||||
import { FilterGroup } from "../filterGroup"
|
||||
import { Menu } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { Utils } from "../utils"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator
|
||||
boardTree: BoardTree
|
||||
pageX: number
|
||||
pageY: number
|
||||
|
@ -67,7 +66,7 @@ class FilterComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private propertyClicked(e: React.MouseEvent, filter: FilterClause) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board, activeView: view } = boardTree
|
||||
|
||||
const filterIndex = view.filter.filters.indexOf(filter)
|
||||
|
@ -90,7 +89,7 @@ class FilterComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private conditionClicked(e: React.MouseEvent, filter: FilterClause) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { activeView: view } = boardTree
|
||||
|
||||
const filterIndex = view.filter.filters.indexOf(filter)
|
||||
|
@ -115,7 +114,7 @@ class FilterComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private valuesClicked(e: React.MouseEvent, filter: FilterClause) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board, activeView: view } = boardTree
|
||||
|
||||
const template = board.cardProperties.find(o => o.id === filter.propertyId)
|
||||
|
@ -143,7 +142,7 @@ class FilterComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private deleteClicked(filter: FilterClause) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { activeView: view } = boardTree
|
||||
|
||||
const filterGroup = new FilterGroup(view.filter)
|
||||
|
@ -153,7 +152,7 @@ class FilterComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private addFilterClicked() {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board, activeView: view } = boardTree
|
||||
|
||||
const filters = view.filter?.filters.filter(o => !FilterGroup.isAnInstanceOf(o)) as FilterClause[] || []
|
||||
|
|
|
@ -3,12 +3,11 @@ import { Archiver } from "../archiver"
|
|||
import { Board } from "../board"
|
||||
import { BoardTree } from "../boardTree"
|
||||
import { Menu, MenuOption } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { IPageController } from "../octoTypes"
|
||||
import { WorkspaceTree } from "../workspaceTree"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator
|
||||
showBoard: (id: string) => void
|
||||
workspaceTree: WorkspaceTree,
|
||||
boardTree?: BoardTree
|
||||
|
@ -51,7 +50,7 @@ class Sidebar extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private showOptions(e: React.MouseEvent, board: Board) {
|
||||
const { mutator, showBoard, workspaceTree } = this.props
|
||||
const { showBoard, workspaceTree } = this.props
|
||||
const { boards } = workspaceTree
|
||||
|
||||
const options: MenuOption[] = []
|
||||
|
@ -79,8 +78,6 @@ class Sidebar extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private settingsClicked(e: React.MouseEvent) {
|
||||
const { mutator } = this.props
|
||||
|
||||
Menu.shared.options = [
|
||||
{ id: "import", name: "Import Archive" },
|
||||
{ id: "export", name: "Export Archive" },
|
||||
|
@ -88,13 +85,13 @@ class Sidebar extends React.Component<Props> {
|
|||
Menu.shared.onMenuClicked = (optionId: string, type?: string) => {
|
||||
switch (optionId) {
|
||||
case "import": {
|
||||
Archiver.importFullArchive(mutator, () => {
|
||||
Archiver.importFullArchive(() => {
|
||||
this.forceUpdate()
|
||||
})
|
||||
break
|
||||
}
|
||||
case "export": {
|
||||
Archiver.exportFullArchive(mutator)
|
||||
Archiver.exportFullArchive()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +109,7 @@ class Sidebar extends React.Component<Props> {
|
|||
}
|
||||
|
||||
async addBoardClicked() {
|
||||
const { mutator, boardTree, showBoard } = this.props
|
||||
const { boardTree, showBoard } = this.props
|
||||
|
||||
const oldBoardId = boardTree?.board?.id
|
||||
const board = new Board()
|
||||
|
|
|
@ -6,9 +6,11 @@ import { IPropertyTemplate } from "../board"
|
|||
import { BoardTree } from "../boardTree"
|
||||
import { Card } from "../card"
|
||||
import ViewMenu from "../components/viewMenu"
|
||||
import MenuWrapper from "../widgets/menuWrapper"
|
||||
import Menu from "../widgets/menu"
|
||||
import { CsvExporter } from "../csvExporter"
|
||||
import { Menu as OldMenu } from "../menu"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { OctoUtils } from "../octoUtils"
|
||||
import { Utils } from "../utils"
|
||||
import Button from "./button"
|
||||
|
@ -18,7 +20,6 @@ import { CardDialog } from "./cardDialog"
|
|||
import RootPortal from "./rootPortal"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator,
|
||||
boardTree?: BoardTree
|
||||
showView: (id: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
|
@ -50,7 +51,7 @@ class TableComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { mutator, boardTree, showView } = this.props
|
||||
const { boardTree, showView } = this.props
|
||||
|
||||
if (!boardTree || !boardTree.board) {
|
||||
return (
|
||||
|
@ -88,7 +89,13 @@ class TableComponent extends React.Component<Props, State> {
|
|||
|
||||
<div className="octo-icontitle">
|
||||
{board.icon ?
|
||||
<div className="octo-button octo-icon" onClick={(e) => { this.iconClicked(e) }}>{board.icon}</div>
|
||||
<MenuWrapper>
|
||||
<div className="octo-button octo-icon">{board.icon}</div>
|
||||
<Menu>
|
||||
<Menu.Text id='random' name='Random' onClick={() => mutator.changeIcon(board, undefined, "remove icon")}/>
|
||||
<Menu.Text id='remove' name='Remove Icon' onClick={() => mutator.changeIcon(board, BlockIcons.shared.randomIcon())}/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
: undefined}
|
||||
<Editable className="title" text={board.title} placeholderText="Untitled Board" onChanged={(text) => { mutator.changeTitle(board, text) }} />
|
||||
</div>
|
||||
|
@ -96,25 +103,23 @@ class TableComponent extends React.Component<Props, State> {
|
|||
<div className="octo-table">
|
||||
<div className="octo-controls">
|
||||
<Editable style={{ color: "#000000", fontWeight: 600 }} text={activeView.title} placeholderText="Untitled View" onChanged={(text) => { mutator.changeTitle(activeView, text) }} />
|
||||
<div
|
||||
className="octo-button"
|
||||
style={{ color: "#000000", fontWeight: 600 }}
|
||||
onClick={() => this.setState({ viewMenu: true })}
|
||||
>
|
||||
{this.state.viewMenu &&
|
||||
<ViewMenu
|
||||
board={board}
|
||||
onClose={() => this.setState({ viewMenu: false })}
|
||||
mutator={mutator}
|
||||
boardTree={boardTree}
|
||||
showView={showView}
|
||||
/>}
|
||||
<div className="imageDropdown"></div>
|
||||
</div>
|
||||
<MenuWrapper>
|
||||
<div
|
||||
className="octo-button"
|
||||
style={{ color: "#000000", fontWeight: 600 }}
|
||||
>
|
||||
<div className="imageDropdown"></div>
|
||||
</div>
|
||||
<ViewMenu
|
||||
board={board}
|
||||
boardTree={boardTree}
|
||||
showView={showView}
|
||||
/>
|
||||
</MenuWrapper>
|
||||
<div className="octo-spacer"></div>
|
||||
<div className="octo-button" onClick={(e) => { this.propertiesClicked(e) }}>Properties</div>
|
||||
<div className={hasFilter ? "octo-button active" : "octo-button"} onClick={(e) => { this.filterClicked(e) }}>Filter</div>
|
||||
<div className={hasSort ? "octo-button active" : "octo-button"} onClick={(e) => { OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort</div>
|
||||
<div className={hasSort ? "octo-button active" : "octo-button"} onClick={(e) => { OctoUtils.showSortMenu(e, boardTree) }}>Sort</div>
|
||||
{this.state.isSearching
|
||||
? <Editable
|
||||
ref={this.searchFieldRef}
|
||||
|
@ -185,7 +190,6 @@ class TableComponent extends React.Component<Props, State> {
|
|||
const tableRow = <TableRow
|
||||
key={card.id}
|
||||
ref={tableRowRef}
|
||||
mutator={mutator}
|
||||
boardTree={boardTree}
|
||||
card={card}
|
||||
focusOnMount={focusOnMount}
|
||||
|
@ -218,30 +222,8 @@ class TableComponent extends React.Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private iconClicked(e: React.MouseEvent) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { board } = boardTree
|
||||
|
||||
OldMenu.shared.options = [
|
||||
{ id: "random", name: "Random" },
|
||||
{ id: "remove", name: "Remove Icon" },
|
||||
]
|
||||
OldMenu.shared.onMenuClicked = (optionId: string, type?: string) => {
|
||||
switch (optionId) {
|
||||
case "remove":
|
||||
mutator.changeIcon(board, undefined, "remove icon")
|
||||
break
|
||||
case "random":
|
||||
const newIcon = BlockIcons.shared.randomIcon()
|
||||
mutator.changeIcon(board, newIcon)
|
||||
break
|
||||
}
|
||||
}
|
||||
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
||||
}
|
||||
|
||||
private async propertiesClicked(e: React.MouseEvent) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { activeView } = boardTree
|
||||
|
||||
const selectProperties = boardTree.board.cardProperties
|
||||
|
@ -294,7 +276,7 @@ class TableComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private async headerClicked(e: React.MouseEvent<HTMLDivElement>, templateId: string) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board } = boardTree
|
||||
const { activeView } = boardTree
|
||||
|
||||
|
@ -375,7 +357,7 @@ class TableComponent extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
async addCard(show: boolean = false) {
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
|
||||
const card = new Card()
|
||||
card.parentId = boardTree.board.id
|
||||
|
@ -397,7 +379,7 @@ class TableComponent extends React.Component<Props, State> {
|
|||
const { draggedHeaderTemplate } = this
|
||||
if (!draggedHeaderTemplate) { return }
|
||||
|
||||
const { mutator, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
const { board } = boardTree
|
||||
|
||||
Utils.assertValue(mutator)
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import React from "react"
|
||||
import { BoardTree } from "../boardTree"
|
||||
import { Card } from "../card"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { OctoUtils } from "../octoUtils"
|
||||
import { Editable } from "./editable"
|
||||
import { CardDialog } from "./cardDialog"
|
||||
import RootPortal from "./rootPortal"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator
|
||||
boardTree: BoardTree
|
||||
card: Card
|
||||
focusOnMount: boolean
|
||||
|
@ -32,7 +31,7 @@ class TableRow extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { mutator, boardTree, card, onKeyDown } = this.props
|
||||
const { boardTree, card, onKeyDown } = this.props
|
||||
const { board, activeView } = boardTree
|
||||
|
||||
const openButonRef = React.createRef<HTMLDivElement>()
|
||||
|
@ -56,7 +55,7 @@ class TableRow extends React.Component<Props, State> {
|
|||
<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} mutator={mutator} onClose={() => this.setState({showCard: false})}/>
|
||||
<CardDialog boardTree={boardTree} card={card} onClose={() => this.setState({showCard: false})}/>
|
||||
</RootPortal>}
|
||||
</div>
|
||||
|
||||
|
@ -66,7 +65,7 @@ class TableRow extends React.Component<Props, State> {
|
|||
.filter(template => activeView.visiblePropertyIds.includes(template.id))
|
||||
.map(template => {
|
||||
return <div className="octo-table-cell" key={template.id}>
|
||||
{OctoUtils.propertyValueEditableElement(mutator, card, template)}
|
||||
{OctoUtils.propertyValueEditableElement(card, template)}
|
||||
</div>
|
||||
})}
|
||||
</div>
|
||||
|
|
|
@ -2,21 +2,19 @@ import React from "react"
|
|||
import { Board } from "../board"
|
||||
import { BoardTree } from "../boardTree"
|
||||
import { BoardView } from "../boardView"
|
||||
import { Mutator } from "../mutator"
|
||||
import mutator from "../mutator"
|
||||
import { Utils } from "../utils"
|
||||
import Menu from "../widgets/menu"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator,
|
||||
boardTree?: BoardTree
|
||||
board: Board,
|
||||
showView: (id: string) => void
|
||||
onClose: () => void,
|
||||
}
|
||||
|
||||
export default class ViewMenu extends React.Component<Props> {
|
||||
handleDeleteView = async (id: string) => {
|
||||
const { board, boardTree, mutator, showView } = this.props
|
||||
const { board, boardTree, showView } = this.props
|
||||
Utils.log(`deleteView`)
|
||||
const view = boardTree.activeView
|
||||
const nextView = boardTree.views.find(o => o !== view)
|
||||
|
@ -32,7 +30,7 @@ export default class ViewMenu extends React.Component<Props> {
|
|||
}
|
||||
|
||||
handleAddViewBoard = async (id: string) => {
|
||||
const { board, boardTree, mutator, showView } = this.props
|
||||
const { board, boardTree, showView } = this.props
|
||||
Utils.log(`addview-board`)
|
||||
const view = new BoardView()
|
||||
view.title = "Board View"
|
||||
|
@ -49,7 +47,7 @@ export default class ViewMenu extends React.Component<Props> {
|
|||
}
|
||||
|
||||
handleAddViewTable = async (id: string) => {
|
||||
const { board, boardTree, mutator, showView } = this.props
|
||||
const { board, boardTree, showView } = this.props
|
||||
|
||||
Utils.log(`addview-table`)
|
||||
const view = new BoardView()
|
||||
|
@ -68,9 +66,9 @@ export default class ViewMenu extends React.Component<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { onClose, boardTree } = this.props
|
||||
const { boardTree } = this.props
|
||||
return (
|
||||
<Menu onClose={onClose}>
|
||||
<Menu>
|
||||
{boardTree.views.map((view) => (<Menu.Text key={view.id} id={view.id} name={view.title} onClick={this.handleViewClick} />))}
|
||||
<Menu.Separator />
|
||||
{boardTree.views.length > 1 && <Menu.Text id="__deleteView" name="Delete View" onClick={this.handleDeleteView} />}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from "react"
|
||||
import { BoardTree } from "../boardTree"
|
||||
import { Card } from "../card"
|
||||
import { Mutator } from "../mutator"
|
||||
import { Utils } from "../utils"
|
||||
import { WorkspaceTree } from "../workspaceTree"
|
||||
import { BoardComponent } from "./boardComponent"
|
||||
|
@ -9,7 +8,6 @@ import { Sidebar } from "./sidebar"
|
|||
import { TableComponent } from "./tableComponent"
|
||||
|
||||
type Props = {
|
||||
mutator: Mutator,
|
||||
workspaceTree: WorkspaceTree
|
||||
boardTree?: BoardTree
|
||||
showBoard: (id: string) => void
|
||||
|
@ -20,12 +18,12 @@ type Props = {
|
|||
|
||||
class WorkspaceComponent extends React.Component<Props> {
|
||||
render() {
|
||||
const { mutator, boardTree, workspaceTree, showBoard } = this.props
|
||||
const { boardTree, workspaceTree, showBoard } = this.props
|
||||
|
||||
Utils.assert(workspaceTree)
|
||||
const element =
|
||||
<div className="octo-workspace">
|
||||
<Sidebar mutator={mutator} showBoard={showBoard} workspaceTree={workspaceTree} boardTree={boardTree}></Sidebar>
|
||||
<Sidebar showBoard={showBoard} workspaceTree={workspaceTree} boardTree={boardTree}></Sidebar>
|
||||
{this.mainComponent()}
|
||||
</div>
|
||||
|
||||
|
@ -33,7 +31,7 @@ class WorkspaceComponent extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private mainComponent() {
|
||||
const { mutator, boardTree, showFilter, setSearchText, showView } = this.props
|
||||
const { boardTree, showFilter, setSearchText, showView } = this.props
|
||||
const { activeView } = boardTree || {}
|
||||
|
||||
if (!activeView) {
|
||||
|
@ -42,11 +40,11 @@ class WorkspaceComponent extends React.Component<Props> {
|
|||
|
||||
switch (activeView?.viewType) {
|
||||
case "board": {
|
||||
return <BoardComponent mutator={mutator} boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
|
||||
return <BoardComponent boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
|
||||
}
|
||||
|
||||
case "table": {
|
||||
return <TableComponent mutator={mutator} boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
|
||||
return <TableComponent boardTree={boardTree} showFilter={showFilter} setSearchText={setSearchText} showView={showView} />
|
||||
}
|
||||
|
||||
default: {
|
||||
|
|
|
@ -4,9 +4,9 @@ import { BoardTree } from "./boardTree"
|
|||
import { BoardView, ISortOption } from "./boardView"
|
||||
import { Card } from "./card"
|
||||
import { FilterGroup } from "./filterGroup"
|
||||
import { OctoClient } from "./octoClient"
|
||||
import octoClient from "./octoClient"
|
||||
import { IBlock } from "./octoTypes"
|
||||
import { UndoManager } from "./undomanager"
|
||||
import undoManager from "./undomanager"
|
||||
import { Utils } from "./utils"
|
||||
|
||||
//
|
||||
|
@ -14,37 +14,33 @@ import { Utils } from "./utils"
|
|||
// It also ensures that the Undo-manager is called for each action
|
||||
//
|
||||
class Mutator {
|
||||
constructor(private octo: OctoClient, private undoManager = UndoManager.shared) {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
async insertBlock(block: IBlock, description: string = "add", afterRedo?: () => Promise<void>, beforeUndo?: () => Promise<void>) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.insertBlock(block)
|
||||
await octoClient.insertBlock(block)
|
||||
await afterRedo?.()
|
||||
},
|
||||
async () => {
|
||||
await beforeUndo?.()
|
||||
await octo.deleteBlock(block.id)
|
||||
await octoClient.deleteBlock(block.id)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async insertBlocks(blocks: IBlock[], description: string = "add", afterRedo?: () => Promise<void>, beforeUndo?: () => Promise<void>) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.insertBlocks(blocks)
|
||||
await octoClient.insertBlocks(blocks)
|
||||
await afterRedo?.()
|
||||
},
|
||||
async () => {
|
||||
await beforeUndo?.()
|
||||
for (const block of blocks) {
|
||||
await octo.deleteBlock(block.id)
|
||||
await octoClient.deleteBlock(block.id)
|
||||
}
|
||||
},
|
||||
description
|
||||
|
@ -52,8 +48,6 @@ class Mutator {
|
|||
}
|
||||
|
||||
async deleteBlock(block: IBlock, description?: string, beforeRedo?: () => Promise<void>, afterUndo?: () => Promise<void>) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
if (!description) {
|
||||
description = `delete ${block.type}`
|
||||
}
|
||||
|
@ -61,10 +55,10 @@ class Mutator {
|
|||
await undoManager.perform(
|
||||
async () => {
|
||||
await beforeRedo?.()
|
||||
await octo.deleteBlock(block.id)
|
||||
await octoClient.deleteBlock(block.id)
|
||||
},
|
||||
async () => {
|
||||
await octo.insertBlock(block)
|
||||
await octoClient.insertBlock(block)
|
||||
await afterUndo?.()
|
||||
},
|
||||
description
|
||||
|
@ -72,51 +66,45 @@ class Mutator {
|
|||
}
|
||||
|
||||
async changeTitle(block: IBlock, title: string, description: string = "change title") {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = block.title
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
block.title = title
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
async () => {
|
||||
block.title = oldValue
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async changeIcon(block: Card | Board, icon: string, description: string = "change icon") {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = block.icon
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
block.icon = icon
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
async () => {
|
||||
block.icon = oldValue
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async changeOrder(block: IBlock, order: number, description: string = "change order") {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = block.order
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
block.order = order
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
async () => {
|
||||
block.order = oldValue
|
||||
await octo.updateBlock(block)
|
||||
await octoClient.updateBlock(block)
|
||||
},
|
||||
description
|
||||
)
|
||||
|
@ -125,7 +113,6 @@ class Mutator {
|
|||
// Property Templates
|
||||
|
||||
async insertPropertyTemplate(boardTree: BoardTree, index: number = -1, template?: IPropertyTemplate) {
|
||||
const { octo, undoManager } = this
|
||||
const { board, activeView } = boardTree
|
||||
|
||||
if (index < 0) { index = board.cardProperties.length }
|
||||
|
@ -156,17 +143,16 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.updateBlocks(changedBlocks)
|
||||
await octoClient.updateBlocks(changedBlocks)
|
||||
},
|
||||
async () => {
|
||||
await octo.updateBlocks(oldBlocks)
|
||||
await octoClient.updateBlocks(oldBlocks)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async duplicatePropertyTemplate(boardTree: BoardTree, propertyId: string) {
|
||||
const { octo, undoManager } = this
|
||||
const { board, activeView } = boardTree
|
||||
|
||||
const oldBlocks: IBlock[] = [new Board(board)]
|
||||
|
@ -194,10 +180,10 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.updateBlocks(changedBlocks)
|
||||
await octoClient.updateBlocks(changedBlocks)
|
||||
},
|
||||
async () => {
|
||||
await octo.updateBlocks(oldBlocks)
|
||||
await octoClient.updateBlocks(oldBlocks)
|
||||
},
|
||||
description
|
||||
)
|
||||
|
@ -206,8 +192,6 @@ class Mutator {
|
|||
}
|
||||
|
||||
async changePropertyTemplateOrder(board: Board, template: IPropertyTemplate, destIndex: number) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const templates = board.cardProperties
|
||||
const oldValue = templates
|
||||
const newValue = templates.slice()
|
||||
|
@ -219,18 +203,17 @@ class Mutator {
|
|||
await undoManager.perform(
|
||||
async () => {
|
||||
board.cardProperties = newValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
board.cardProperties = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
"reorder properties"
|
||||
)
|
||||
}
|
||||
|
||||
async deleteProperty(boardTree: BoardTree, propertyId: string) {
|
||||
const { octo, undoManager } = this
|
||||
const { board, views, cards } = boardTree
|
||||
|
||||
const oldBlocks: IBlock[] = [new Board(board)]
|
||||
|
@ -255,18 +238,16 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.updateBlocks(changedBlocks)
|
||||
await octoClient.updateBlocks(changedBlocks)
|
||||
},
|
||||
async () => {
|
||||
await octo.updateBlocks(oldBlocks)
|
||||
await octoClient.updateBlocks(oldBlocks)
|
||||
},
|
||||
"delete property"
|
||||
)
|
||||
}
|
||||
|
||||
async renameProperty(board: Board, propertyId: string, name: string) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldBlocks: IBlock[] = [new Board(board)]
|
||||
const changedBlocks: IBlock[] = [board]
|
||||
|
||||
|
@ -277,10 +258,10 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.updateBlocks(changedBlocks)
|
||||
await octoClient.updateBlocks(changedBlocks)
|
||||
},
|
||||
async () => {
|
||||
await octo.updateBlocks(oldBlocks)
|
||||
await octoClient.updateBlocks(oldBlocks)
|
||||
},
|
||||
"rename property"
|
||||
)
|
||||
|
@ -289,7 +270,6 @@ class Mutator {
|
|||
// Properties
|
||||
|
||||
async insertPropertyOption(boardTree: BoardTree, template: IPropertyTemplate, option: IPropertyOption, description: string = "add option") {
|
||||
const { octo, undoManager } = this
|
||||
const { board } = boardTree
|
||||
|
||||
Utils.assert(board.cardProperties.includes(template))
|
||||
|
@ -301,19 +281,18 @@ class Mutator {
|
|||
await undoManager.perform(
|
||||
async () => {
|
||||
template.options = newValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
// TODO: Also remove property on cards
|
||||
template.options = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async deletePropertyOption(boardTree: BoardTree, template: IPropertyTemplate, option: IPropertyOption) {
|
||||
const { octo, undoManager } = this
|
||||
const { board } = boardTree
|
||||
|
||||
const oldValue = template.options.slice()
|
||||
|
@ -324,19 +303,17 @@ class Mutator {
|
|||
await undoManager.perform(
|
||||
async () => {
|
||||
template.options = newValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
template.options = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
"delete option"
|
||||
)
|
||||
}
|
||||
|
||||
async changePropertyOptionOrder(board: Board, template: IPropertyTemplate, option: IPropertyOption, destIndex: number) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = template.options
|
||||
const newValue = template.options.slice()
|
||||
|
||||
|
@ -347,18 +324,17 @@ class Mutator {
|
|||
await undoManager.perform(
|
||||
async () => {
|
||||
template.options = newValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
template.options = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
"reorder options"
|
||||
)
|
||||
}
|
||||
|
||||
async changePropertyOptionValue(boardTree: BoardTree, propertyTemplate: IPropertyTemplate, option: IPropertyOption, value: string) {
|
||||
const { octo, undoManager } = this
|
||||
const { board, cards } = boardTree
|
||||
|
||||
const oldValue = option.value
|
||||
|
@ -379,10 +355,10 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.updateBlocks(changedBlocks)
|
||||
await octoClient.updateBlocks(changedBlocks)
|
||||
},
|
||||
async () => {
|
||||
await octo.updateBlocks(oldBlocks)
|
||||
await octoClient.updateBlocks(oldBlocks)
|
||||
},
|
||||
"rename option"
|
||||
)
|
||||
|
@ -391,52 +367,46 @@ class Mutator {
|
|||
}
|
||||
|
||||
async changePropertyOptionColor(board: Board, option: IPropertyOption, color: string) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = option.color
|
||||
|
||||
undoManager.perform(
|
||||
async () => {
|
||||
option.color = color
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
option.color = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
"change option color"
|
||||
)
|
||||
}
|
||||
|
||||
async changePropertyValue(card: Card, propertyId: string, value?: string, description: string = "change property") {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = card.properties[propertyId]
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
card.properties[propertyId] = value
|
||||
await octo.updateBlock(card)
|
||||
await octoClient.updateBlock(card)
|
||||
},
|
||||
async () => {
|
||||
card.properties[propertyId] = oldValue
|
||||
await octo.updateBlock(card)
|
||||
await octoClient.updateBlock(card)
|
||||
},
|
||||
description
|
||||
)
|
||||
}
|
||||
|
||||
async changePropertyType(board: Board, propertyTemplate: IPropertyTemplate, type: PropertyType) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = propertyTemplate.type
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
propertyTemplate.type = type
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
async () => {
|
||||
propertyTemplate.type = oldValue
|
||||
await octo.updateBlock(board)
|
||||
await octoClient.updateBlock(board)
|
||||
},
|
||||
"change property type"
|
||||
)
|
||||
|
@ -445,72 +415,64 @@ class Mutator {
|
|||
// Views
|
||||
|
||||
async changeViewSortOptions(view: BoardView, sortOptions: ISortOption[]) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = view.sortOptions
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
view.sortOptions = sortOptions
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
async () => {
|
||||
view.sortOptions = oldValue
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
"sort"
|
||||
)
|
||||
}
|
||||
|
||||
async changeViewFilter(view: BoardView, filter?: FilterGroup) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = view.filter
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
view.filter = filter
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
async () => {
|
||||
view.filter = oldValue
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
"filter"
|
||||
)
|
||||
}
|
||||
|
||||
async changeViewVisibleProperties(view: BoardView, visiblePropertyIds: string[]) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = view.visiblePropertyIds
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
view.visiblePropertyIds = visiblePropertyIds
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
async () => {
|
||||
view.visiblePropertyIds = oldValue
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
"hide / show property"
|
||||
)
|
||||
}
|
||||
|
||||
async changeViewGroupById(view: BoardView, groupById: string) {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const oldValue = view.groupById
|
||||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
view.groupById = groupById
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
async () => {
|
||||
view.groupById = oldValue
|
||||
await octo.updateBlock(view)
|
||||
await octoClient.updateBlock(view)
|
||||
},
|
||||
"group by"
|
||||
)
|
||||
|
@ -518,18 +480,16 @@ class Mutator {
|
|||
|
||||
// Not a mutator, but convenient to put here since Mutator wraps OctoClient
|
||||
async exportFullArchive() {
|
||||
return this.octo.exportFullArchive()
|
||||
return octoClient.exportFullArchive()
|
||||
}
|
||||
|
||||
// Not a mutator, but convenient to put here since Mutator wraps OctoClient
|
||||
async importFullArchive(blocks: IBlock[]) {
|
||||
return this.octo.importFullArchive(blocks)
|
||||
return octoClient.importFullArchive(blocks)
|
||||
}
|
||||
|
||||
async createImageBlock(parentId: string, file: File, order = 1000): Promise<IBlock | undefined> {
|
||||
const { octo, undoManager } = this
|
||||
|
||||
const url = await octo.uploadFile(file)
|
||||
const url = await octoClient.uploadFile(file)
|
||||
if (!url) {
|
||||
return undefined
|
||||
}
|
||||
|
@ -539,16 +499,35 @@ class Mutator {
|
|||
|
||||
await undoManager.perform(
|
||||
async () => {
|
||||
await octo.insertBlock(block)
|
||||
await octoClient.insertBlock(block)
|
||||
},
|
||||
async () => {
|
||||
await octo.deleteBlock(block.id)
|
||||
await octoClient.deleteBlock(block.id)
|
||||
},
|
||||
"group by"
|
||||
)
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
async undo() {
|
||||
await undoManager.undo()
|
||||
}
|
||||
|
||||
undoDescription(): string | undefined {
|
||||
return undoManager.undoDescription
|
||||
}
|
||||
|
||||
async redo() {
|
||||
await undoManager.redo()
|
||||
}
|
||||
|
||||
redoDescription(): string | undefined {
|
||||
return undoManager.redoDescription
|
||||
}
|
||||
}
|
||||
|
||||
export { Mutator }
|
||||
const mutator = new Mutator()
|
||||
export default mutator
|
||||
|
||||
export { mutator }
|
||||
|
|
|
@ -152,4 +152,6 @@ class OctoClient {
|
|||
}
|
||||
}
|
||||
|
||||
export { OctoClient }
|
||||
const client = new OctoClient()
|
||||
|
||||
export default client
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ISortOption } from "./boardView"
|
|||
import { Card } from "./card"
|
||||
import { Editable } from "./components/editable"
|
||||
import { Menu } from "./menu"
|
||||
import { Mutator } from "./mutator"
|
||||
import mutator from "./mutator"
|
||||
import { IBlock } from "./octoTypes"
|
||||
import { Utils } from "./utils"
|
||||
|
||||
|
@ -27,14 +27,14 @@ class OctoUtils {
|
|||
}
|
||||
|
||||
static propertyValueReadonlyElement(card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element {
|
||||
return this.propertyValueElement(undefined, card, propertyTemplate, emptyDisplayValue)
|
||||
return this.propertyValueElement(true, card, propertyTemplate, emptyDisplayValue)
|
||||
}
|
||||
|
||||
static propertyValueEditableElement(mutator: Mutator, card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue?: string): JSX.Element {
|
||||
return this.propertyValueElement(mutator, card, propertyTemplate, emptyDisplayValue)
|
||||
static propertyValueEditableElement(card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue?: string): JSX.Element {
|
||||
return this.propertyValueElement(false, card, propertyTemplate, emptyDisplayValue)
|
||||
}
|
||||
|
||||
private static propertyValueElement(mutator: Mutator | undefined, card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element {
|
||||
private static propertyValueElement(readOnly: boolean, card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element {
|
||||
const propertyValue = card.properties[propertyTemplate.id]
|
||||
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, propertyTemplate)
|
||||
const finalDisplayValue = displayValue || emptyDisplayValue
|
||||
|
@ -69,18 +69,18 @@ class OctoUtils {
|
|||
key={propertyTemplate.id}
|
||||
className={`${className} ${propertyColorCssClassName}`}
|
||||
tabIndex={0}
|
||||
onClick={mutator ? (e) => { showMenu(e.target as HTMLElement) } : undefined}
|
||||
onKeyDown={mutator ? (e) => {
|
||||
onClick={!readOnly ? (e) => { showMenu(e.target as HTMLElement) } : undefined}
|
||||
onKeyDown={!readOnly ? (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
showMenu(e.target as HTMLElement)
|
||||
}
|
||||
} : undefined}
|
||||
onFocus={mutator ? () => { Menu.shared.hide() } : undefined}
|
||||
onFocus={!readOnly ? () => { Menu.shared.hide() } : undefined}
|
||||
>
|
||||
{finalDisplayValue}
|
||||
</div>
|
||||
} else if (propertyTemplate.type === "text" || propertyTemplate.type === "number") {
|
||||
if (mutator) {
|
||||
if (!readOnly) {
|
||||
element = <Editable
|
||||
key={propertyTemplate.id}
|
||||
className="octo-propertyvalue"
|
||||
|
@ -121,7 +121,7 @@ class OctoUtils {
|
|||
return (block.order + nextBlock.order) / 2
|
||||
}
|
||||
|
||||
static showSortMenu(e: React.MouseEvent, mutator: Mutator, boardTree: BoardTree) {
|
||||
static showSortMenu(e: React.MouseEvent, boardTree: BoardTree) {
|
||||
const { activeView } = boardTree
|
||||
const { sortOptions } = activeView
|
||||
const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined
|
||||
|
|
|
@ -8,10 +8,9 @@ import { CardDialog } from "../components/cardDialog"
|
|||
import { FilterComponent } from "../components/filterComponent"
|
||||
import { WorkspaceComponent } from "../components/workspaceComponent"
|
||||
import { FlashMessage } from "../flashMessage"
|
||||
import { Mutator } from "../mutator"
|
||||
import { OctoClient } from "../octoClient"
|
||||
import mutator from "../mutator"
|
||||
import octoClient from "../octoClient"
|
||||
import { OctoListener } from "../octoListener"
|
||||
import { UndoManager } from "../undomanager"
|
||||
import { Utils } from "../utils"
|
||||
import { WorkspaceTree } from "../workspaceTree"
|
||||
|
||||
|
@ -33,7 +32,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
updateTitleTimeout: number
|
||||
updatePropertyLabelTimeout: number
|
||||
|
||||
private octo = new OctoClient()
|
||||
private boardListener = new OctoListener()
|
||||
private cardListener = new OctoListener()
|
||||
|
||||
|
@ -46,7 +44,7 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
this.state = {
|
||||
boardId,
|
||||
viewId,
|
||||
workspaceTree: new WorkspaceTree(this.octo),
|
||||
workspaceTree: new WorkspaceTree(),
|
||||
}
|
||||
|
||||
Utils.log(`BoardPage. boardId: ${boardId}`)
|
||||
|
@ -73,8 +71,8 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
|
||||
if (e.keyCode === 90 && !e.shiftKey && (e.ctrlKey || e.metaKey) && !e.altKey) { // Cmd+Z
|
||||
Utils.log(`Undo`)
|
||||
const description = UndoManager.shared.undoDescription
|
||||
await UndoManager.shared.undo()
|
||||
const description = mutator.undoDescription()
|
||||
await mutator.undo()
|
||||
if (description) {
|
||||
FlashMessage.show(`Undo ${description}`)
|
||||
} else {
|
||||
|
@ -82,8 +80,8 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
}
|
||||
} else if (e.keyCode === 90 && e.shiftKey && (e.ctrlKey || e.metaKey) && !e.altKey) { // Shift+Cmd+Z
|
||||
Utils.log(`Redo`)
|
||||
const description = UndoManager.shared.redoDescription
|
||||
await UndoManager.shared.redo()
|
||||
const description = mutator.redoDescription()
|
||||
await mutator.redo()
|
||||
if (description) {
|
||||
FlashMessage.show(`Redo ${description}`)
|
||||
} else {
|
||||
|
@ -108,7 +106,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
render() {
|
||||
const { workspaceTree, shownCardTree } = this.state
|
||||
const { board, activeView } = this.state.boardTree || {}
|
||||
const mutator = new Mutator(this.octo)
|
||||
|
||||
if (this.state.filterAnchorElement) {
|
||||
const element = this.state.filterAnchorElement
|
||||
|
@ -121,7 +118,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
|
||||
ReactDOM.render(
|
||||
<FilterComponent
|
||||
mutator={mutator}
|
||||
boardTree={this.state.boardTree}
|
||||
pageX={pageX}
|
||||
pageY={pageY}
|
||||
|
@ -141,7 +137,6 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
return (
|
||||
<div className='BoardPage'>
|
||||
<WorkspaceComponent
|
||||
mutator={mutator}
|
||||
workspaceTree={workspaceTree}
|
||||
boardTree={this.state.boardTree}
|
||||
showView={(id) => { this.showView(id) }}
|
||||
|
@ -170,7 +165,7 @@ export default class BoardPage extends React.Component<Props, State> {
|
|||
await workspaceTree.sync()
|
||||
|
||||
if (boardId) {
|
||||
const boardTree = new BoardTree(this.octo, boardId)
|
||||
const boardTree = new BoardTree(boardId)
|
||||
await boardTree.sync()
|
||||
|
||||
// Default to first view
|
||||
|
|
|
@ -2,10 +2,9 @@ import React from 'react'
|
|||
import { Archiver } from "../archiver"
|
||||
import { Board } from "../board"
|
||||
import Button from '../components/button'
|
||||
import { Mutator } from "../mutator"
|
||||
import { OctoClient } from "../octoClient"
|
||||
import mutator from '../mutator'
|
||||
import octoClient from "../octoClient"
|
||||
import { IBlock } from "../octoTypes"
|
||||
import { UndoManager } from "../undomanager"
|
||||
import { Utils } from "../utils"
|
||||
|
||||
type Props = {}
|
||||
|
@ -27,29 +26,23 @@ export default class HomePage extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
loadBoards = async () => {
|
||||
const octo = new OctoClient()
|
||||
const boards = await octo.getBlocks(null, "board")
|
||||
const boards = await octoClient.getBlocks(null, "board")
|
||||
this.setState({ boards })
|
||||
}
|
||||
|
||||
importClicked = async () => {
|
||||
const octo = new OctoClient()
|
||||
const mutator = new Mutator(octo, UndoManager.shared)
|
||||
Archiver.importFullArchive(mutator, () => {
|
||||
Archiver.importFullArchive(() => {
|
||||
this.loadBoards()
|
||||
})
|
||||
}
|
||||
|
||||
exportClicked = async () => {
|
||||
const octo = new OctoClient()
|
||||
const mutator = new Mutator(octo, UndoManager.shared)
|
||||
Archiver.exportFullArchive(mutator)
|
||||
Archiver.exportFullArchive()
|
||||
}
|
||||
|
||||
addClicked = async () => {
|
||||
const octo = new OctoClient()
|
||||
const board = new Board()
|
||||
await octo.insertBlock(board)
|
||||
await octoClient.insertBlock(board)
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
|
|
|
@ -9,8 +9,6 @@ interface UndoCommand {
|
|||
// General-purpose undo manager
|
||||
//
|
||||
class UndoManager {
|
||||
static shared = new UndoManager()
|
||||
|
||||
onStateDidChange?: () => void
|
||||
|
||||
private commands: UndoCommand[] = []
|
||||
|
@ -164,4 +162,5 @@ class UndoManager {
|
|||
}
|
||||
}
|
||||
|
||||
export { UndoManager }
|
||||
const undoManager = new UndoManager()
|
||||
export default undoManager
|
||||
|
|
|
@ -40,7 +40,7 @@ class SubMenuOption extends React.Component<SubMenuOptionProps, SubMenuState> {
|
|||
<div className='name menu-name'>{this.props.name}</div>
|
||||
<div className="imageSubmenuTriangle" style={{float: 'right'}}></div>
|
||||
{this.state.isOpen &&
|
||||
<Menu onClose={this.close}>
|
||||
<Menu>
|
||||
{this.props.children}
|
||||
</Menu>
|
||||
}
|
||||
|
@ -54,13 +54,17 @@ type ColorOptionProps = MenuOptionProps & {
|
|||
}
|
||||
|
||||
class ColorOption extends React.Component<ColorOptionProps> {
|
||||
handleOnClick = () => {
|
||||
this.props.onClick(this.props.id)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {name, icon} = this.props;
|
||||
const {id, name, icon} = this.props;
|
||||
return (
|
||||
<div className='MenuOption ColorOption menu-option'>
|
||||
<div className='MenuOption ColorOption menu-option' onClick={this.handleOnClick}>
|
||||
<div className='name'>{name}</div>
|
||||
{icon && <div className={'icon ' + icon}></div>}
|
||||
<div className='menu-colorbox'></div>
|
||||
<div className={`menu-colorbox ${id}`}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -113,7 +117,6 @@ class TextOption extends React.Component<TextOptionProps> {
|
|||
|
||||
type MenuProps = {
|
||||
children: React.ReactNode
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export default class Menu extends React.Component<MenuProps> {
|
||||
|
@ -123,30 +126,6 @@ export default class Menu extends React.Component<MenuProps> {
|
|||
static Separator = SeparatorOption
|
||||
static Text = TextOption
|
||||
|
||||
onBodyClick = (e: MouseEvent) => {
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
onBodyKeyDown = (e: KeyboardEvent) => {
|
||||
// Ignore keydown events on other elements
|
||||
if (e.target !== document.body) { return }
|
||||
if (e.keyCode === 27) {
|
||||
// ESC
|
||||
this.props.onClose()
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener("click", this.onBodyClick)
|
||||
document.addEventListener("keydown", this.onBodyKeyDown)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener("click", this.onBodyClick)
|
||||
document.removeEventListener("keydown", this.onBodyKeyDown)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="Menu menu noselect">
|
||||
|
|
94
src/client/widgets/menuWrapper.tsx
Normal file
94
src/client/widgets/menuWrapper.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
onToggle?: (open: boolean) => void;
|
||||
isDisabled?: boolean;
|
||||
stopPropagationOnToggle?: boolean;
|
||||
}
|
||||
|
||||
type State = {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
export default class MenuWrapper extends React.PureComponent<Props, State> {
|
||||
private node: React.RefObject<HTMLDivElement>;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
if (!Array.isArray(props.children) || props.children.length !== 2) {
|
||||
throw new Error('MenuWrapper needs exactly 2 children');
|
||||
}
|
||||
this.state = {
|
||||
open: false,
|
||||
};
|
||||
this.node = React.createRef();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
document.addEventListener('click', this.closeOnBlur, true);
|
||||
document.addEventListener('keyup', this.keyboardClose, true);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
document.removeEventListener('click', this.closeOnBlur, true);
|
||||
document.removeEventListener('keyup', this.keyboardClose, true);
|
||||
}
|
||||
|
||||
private keyboardClose = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.close();
|
||||
}
|
||||
|
||||
if (e.key === 'Tab') {
|
||||
this.closeOnBlur(e);
|
||||
}
|
||||
}
|
||||
|
||||
private closeOnBlur = (e: Event) => {
|
||||
if (this.node && this.node.current && e.target && this.node.current.contains(e.target as Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
|
||||
public close = () => {
|
||||
if (this.state.open) {
|
||||
this.setState({open: false});
|
||||
}
|
||||
}
|
||||
|
||||
toggle = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
/**
|
||||
* This is only here so that we can toggle the menus in the sidebar, because the default behavior of the mobile
|
||||
* version (ie the one that uses a modal) needs propagation to close the modal after selecting something
|
||||
* We need to refactor this so that the modal is explicitly closed on toggle, but for now I am aiming to preserve the existing logic
|
||||
* so as to not break other things
|
||||
**/
|
||||
if (this.props.stopPropagationOnToggle) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
const newState = !this.state.open;
|
||||
this.setState({open: newState});
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {children} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={'MenuWrapper'}
|
||||
onClick={this.toggle}
|
||||
ref={this.node}
|
||||
>
|
||||
{children ? Object.values(children)[0] : null}
|
||||
{children && this.state.open ? Object.values(children)[1] : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,16 +1,12 @@
|
|||
import { Board } from "./board"
|
||||
import { OctoClient } from "./octoClient"
|
||||
import octoClient from "./octoClient"
|
||||
import { IBlock } from "./octoTypes"
|
||||
|
||||
class WorkspaceTree {
|
||||
boards: Board[] = []
|
||||
|
||||
constructor(
|
||||
private octo: OctoClient) {
|
||||
}
|
||||
|
||||
async sync() {
|
||||
const blocks = await this.octo.getBlocks(undefined, "board")
|
||||
const blocks = await octoClient.getBlocks(undefined, "board")
|
||||
this.rebuild(blocks)
|
||||
}
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ hr {
|
|||
touch-action: none;
|
||||
}
|
||||
|
||||
.menu-option .menu-name {
|
||||
.menu-option .name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
@ -454,24 +454,24 @@ hr {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.octo-frame > .octo-icontitle > .octo-icon {
|
||||
.octo-frame .octo-icontitle .octo-icon {
|
||||
font-size: 36px;
|
||||
line-height: 36px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.octo-board-card > .octo-icontitle {
|
||||
.octo-board-card .octo-icontitle {
|
||||
flex: 1 1 auto;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.octo-board-card > .octo-icontitle > .octo-icon {
|
||||
.octo-board-card .octo-icontitle .octo-icon {
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.octo-table-cell > .octo-icontitle > .octo-icon {
|
||||
.octo-table-cell .octo-icontitle .octo-icon {
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue