From 66e59d3029195b82bd06216ecc2d3ac4efa24775 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 8 Oct 2020 20:09:34 -0700 Subject: [PATCH 01/34] Seach text. WIP --- src/client/boardPage.tsx | 5 ++++ src/client/boardTree.ts | 20 ++++++++++++++ src/client/components/boardComponent.tsx | 35 +++++++++++++++++++++--- src/client/octoTypes.ts | 1 + 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/client/boardPage.tsx b/src/client/boardPage.tsx index c7334e3d5..8bb1334e3 100644 --- a/src/client/boardPage.tsx +++ b/src/client/boardPage.tsx @@ -227,6 +227,11 @@ class BoardPage implements IPageController { this.filterAnchorElement = ahchorElement this.render() } + + setSearchText(text?: string) { + this.boardTree.setSearchText(text) + this.render() + } } export { BoardPage } diff --git a/src/client/boardTree.ts b/src/client/boardTree.ts index 74c89dfbb..10459a5bf 100644 --- a/src/client/boardTree.ts +++ b/src/client/boardTree.ts @@ -17,6 +17,7 @@ class BoardTree { activeView?: BoardView groupByProperty?: IPropertyTemplate + private searchText?: string private allCards: IBlock[] = [] get allBlocks(): IBlock[] { return [this.board, ...this.views, ...this.allCards] @@ -93,8 +94,18 @@ class BoardTree { this.applyFilterSortAndGroup() } + getSearchText(): string | undefined { + return this.searchText + } + + setSearchText(text?: string) { + this.searchText = text + this.applyFilterSortAndGroup() + } + applyFilterSortAndGroup() { this.cards = this.filterCards(this.allCards) + this.cards = this.searchFilterCards(this.cards) this.cards = this.sortCards(this.cards) if (this.activeView.groupById) { @@ -104,6 +115,15 @@ class BoardTree { } } + private searchFilterCards(cards: IBlock[]) { + const { searchText } = this + if (!searchText) { return cards.slice() } + + return cards.filter(card => { + if (card.title?.toLowerCase().indexOf(searchText) !== -1) { return true } + }) + } + private setGroupByProperty(propertyId: string) { const { board } = this diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 1b75c6ef3..ef1fca990 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -25,15 +25,26 @@ type Props = { type State = { isHoverOnCover: boolean + isSearching: boolean } class BoardComponent extends React.Component { private draggedCard: IBlock private draggedHeaderOption: IPropertyOption + private searchFieldRef = React.createRef() constructor(props: Props) { super(props) - this.state = { isHoverOnCover: false } + this.state = { + isHoverOnCover: false, + isSearching: false + } + } + + componentDidUpdate(prevPros: Props, prevState: State) { + if (this.state.isSearching && !prevState.isSearching) { + this.searchFieldRef.current.focus() + } } render() { @@ -87,9 +98,12 @@ class BoardComponent extends React.Component {
{ this.groupByClicked(e) }}> Group by {boardTree.groupByProperty?.name}
-
{ this.filterClicked(e) }}>Filter
-
{ this.sortClicked(e) }}>Sort
-
Search
+
{ this.filterClicked(e) }}>Filter
+
{ this.sortClicked(e) }}>Sort
+ {this.state.isSearching + ? { this.searchChanged(text) }} onKeyDown={(e) => { this.onSearchKeyDown(e) }}> + :
{ this.setState({ ...this.state, isSearching: true }) }}>Search
+ }
{ this.optionsClicked(e) }}>
{ this.addCard(undefined) }}>New
@@ -380,6 +394,19 @@ class BoardComponent extends React.Component { await mutator.changePropertyOptionOrder(board, boardTree.groupByProperty, draggedHeaderOption, destIndex) } } + + onSearchKeyDown(e: React.KeyboardEvent) { + if (e.keyCode === 27) { // ESC: Clear search + this.searchFieldRef.current.text = "" + this.setState({...this.state, isSearching: false}) + this.props.pageController.setSearchText(undefined) + e.preventDefault() + } + } + + searchChanged(text?: string) { + this.props.pageController.setSearchText(text) + } } export { BoardComponent } diff --git a/src/client/octoTypes.ts b/src/client/octoTypes.ts index 1a3f994c2..026046329 100644 --- a/src/client/octoTypes.ts +++ b/src/client/octoTypes.ts @@ -26,6 +26,7 @@ interface IPageController { showCard(card: IBlock): Promise showView(viewId: string): void showFilter(anchorElement?: HTMLElement): void + setSearchText(text?: string): void } export { IProperty, IBlock, IPageController } From c98ae89b505d5069a244728397a72fa2fe63bd32 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 8 Oct 2020 20:20:02 -0700 Subject: [PATCH 02/34] Search --- src/client/components/boardComponent.tsx | 9 +++++++-- src/client/components/editable.tsx | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index ef1fca990..c6f41de65 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -101,7 +101,12 @@ class BoardComponent extends React.Component {
{ this.filterClicked(e) }}>Filter
{ this.sortClicked(e) }}>Sort
{this.state.isSearching - ? { this.searchChanged(text) }} onKeyDown={(e) => { this.onSearchKeyDown(e) }}> + ? { this.searchChanged(text) }} + onKeyDown={(e) => { this.onSearchKeyDown(e) }}> :
{ this.setState({ ...this.state, isSearching: true }) }}>Search
}
{ this.optionsClicked(e) }}>
@@ -398,7 +403,7 @@ class BoardComponent extends React.Component { onSearchKeyDown(e: React.KeyboardEvent) { if (e.keyCode === 27) { // ESC: Clear search this.searchFieldRef.current.text = "" - this.setState({...this.state, isSearching: false}) + this.setState({ ...this.state, isSearching: false }) this.props.pageController.setSearchText(undefined) e.preventDefault() } diff --git a/src/client/components/editable.tsx b/src/client/components/editable.tsx index 5b7b1e028..0c388ff55 100644 --- a/src/client/components/editable.tsx +++ b/src/client/components/editable.tsx @@ -102,7 +102,6 @@ class Editable extends React.Component { this.text = newText this.elementRef.current.classList.remove("active") - if (onBlur) { onBlur() } }} From 0bccdc26e91d7c8e28156924f3ae8860ba13935c Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 8 Oct 2020 20:24:34 -0700 Subject: [PATCH 03/34] Search in TableComponent as well --- src/client/components/boardComponent.tsx | 5 +--- src/client/components/tableComponent.tsx | 33 ++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index c6f41de65..89acd61e7 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -35,10 +35,7 @@ class BoardComponent extends React.Component { constructor(props: Props) { super(props) - this.state = { - isHoverOnCover: false, - isSearching: false - } + this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText() } } componentDidUpdate(prevPros: Props, prevState: State) { diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index a7328af42..5177099ad 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -23,16 +23,24 @@ type Props = { type State = { isHoverOnCover: boolean + isSearching: boolean } class TableComponent extends React.Component { private draggedHeaderTemplate: IPropertyTemplate private cardIdToRowMap = new Map>() private cardIdToFocusOnRender: string + private searchFieldRef = React.createRef() constructor(props: Props) { super(props) - this.state = { isHoverOnCover: false } + this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText() } + } + + componentDidUpdate(prevPros: Props, prevState: State) { + if (this.state.isSearching && !prevState.isSearching) { + this.searchFieldRef.current.focus() + } } render() { @@ -83,7 +91,15 @@ class TableComponent extends React.Component {
{ this.propertiesClicked(e) }}>Properties
{ this.filterClicked(e) }}>Filter
{ this.sortClicked(e) }}>Sort
-
Search
+ {this.state.isSearching + ? { this.searchChanged(text) }} + onKeyDown={(e) => { this.onSearchKeyDown(e) }}> + :
{ this.setState({ ...this.state, isSearching: true }) }}>Search
+ }
this.optionsClicked(e)}>
{ this.addCard(true) }}>New
@@ -401,6 +417,19 @@ class TableComponent extends React.Component { const destIndex = template ? board.cardProperties.indexOf(template) : 0 await mutator.changePropertyTemplateOrder(board, draggedHeaderTemplate, destIndex) } + + onSearchKeyDown(e: React.KeyboardEvent) { + if (e.keyCode === 27) { // ESC: Clear search + this.searchFieldRef.current.text = "" + this.setState({ ...this.state, isSearching: false }) + this.props.pageController.setSearchText(undefined) + e.preventDefault() + } + } + + searchChanged(text?: string) { + this.props.pageController.setSearchText(text) + } } export { TableComponent } From c6463e55349961413936ce1a0abaa9ba7f44a03c Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 8 Oct 2020 21:05:57 -0700 Subject: [PATCH 04/34] Search color --- src/client/components/boardComponent.tsx | 1 + src/client/components/tableComponent.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 89acd61e7..ba5343b1c 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -102,6 +102,7 @@ class BoardComponent extends React.Component { ref={this.searchFieldRef} text={boardTree.getSearchText()} placeholderText="Search text" + style={{ color: "#000000" }} onChanged={(text) => { this.searchChanged(text) }} onKeyDown={(e) => { this.onSearchKeyDown(e) }}>
:
{ this.setState({ ...this.state, isSearching: true }) }}>Search
diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index 5177099ad..bd05ea44c 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -96,6 +96,7 @@ class TableComponent extends React.Component { ref={this.searchFieldRef} text={boardTree.getSearchText()} placeholderText="Search text" + style={{ color: "#000000" }} onChanged={(text) => { this.searchChanged(text) }} onKeyDown={(e) => { this.onSearchKeyDown(e) }}> :
{ this.setState({ ...this.state, isSearching: true }) }}>Search
From ae93fe22ced044f7fd4115d445e7ed70013bc044 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 08:52:40 -0700 Subject: [PATCH 05/34] Add Go WebSocket method comments --- server/main/websockets.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/main/websockets.go b/server/main/websockets.go index 317d9a4e8..0316ac3fe 100644 --- a/server/main/websockets.go +++ b/server/main/websockets.go @@ -42,12 +42,14 @@ func (ws *WSServer) GetListeners(blockID string) []*websocket.Conn { return listeners } +// WSServer is a WebSocket server type WSServer struct { upgrader websocket.Upgrader listeners map[string][]*websocket.Conn mu sync.RWMutex } +// NewWSServer creates a new WSServer func NewWSServer() *WSServer { return &WSServer{ listeners: make(map[string][]*websocket.Conn), @@ -59,7 +61,7 @@ func NewWSServer() *WSServer { } } -// WebsocketMsg is send on block changes +// WebsocketMsg is sent on block changes type WebsocketMsg struct { Action string `json:"action"` BlockID string `json:"blockId"` From 92882fee5ffd79635efe1afbdc645baee5e799cc Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 08:55:59 -0700 Subject: [PATCH 06/34] Case-insensitive search --- src/client/boardTree.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/boardTree.ts b/src/client/boardTree.ts index 10459a5bf..146a0ed2d 100644 --- a/src/client/boardTree.ts +++ b/src/client/boardTree.ts @@ -116,11 +116,11 @@ class BoardTree { } private searchFilterCards(cards: IBlock[]) { - const { searchText } = this + const searchText = this.searchText?.toLocaleLowerCase() if (!searchText) { return cards.slice() } return cards.filter(card => { - if (card.title?.toLowerCase().indexOf(searchText) !== -1) { return true } + if (card.title?.toLocaleLowerCase().indexOf(searchText) !== -1) { return true } }) } From c6a0f7f3e9708620b18600e37101fb6c389b9a15 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 09:22:12 -0700 Subject: [PATCH 07/34] Show selected property on sort menu --- src/client/components/boardComponent.tsx | 8 +++++++- src/client/components/tableComponent.tsx | 8 +++++++- src/client/menu.ts | 13 +++++++++++++ src/static/images.css | 9 ++++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index ba5343b1c..647090ee3 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -282,7 +282,13 @@ class BoardComponent extends React.Component { const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { return { id: o.id, name: o.name } }) + Menu.shared.options = propertyTemplates.map((o) => { + return { + id: o.id, + name: o.name, + icon: (sortOption.propertyId === o.id) ? "checked" : undefined + } + }) Menu.shared.onMenuClicked = async (propertyId: string) => { let newSortOptions: ISortOption[] = [] if (sortOption && sortOption.propertyId === propertyId) { diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index bd05ea44c..3627bfddc 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -255,7 +255,13 @@ class TableComponent extends React.Component { const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { return { id: o.id, name: o.name } }) + Menu.shared.options = propertyTemplates.map((o) => { + return { + id: o.id, + name: o.name, + icon: (sortOption.propertyId === o.id) ? "checked" : undefined + } + }) Menu.shared.onMenuClicked = async (propertyId: string) => { let newSortOptions: ISortOption[] = [] if (sortOption && sortOption.propertyId === propertyId) { diff --git a/src/client/menu.ts b/src/client/menu.ts index 58912321c..a79445fed 100644 --- a/src/client/menu.ts +++ b/src/client/menu.ts @@ -4,6 +4,7 @@ type MenuOption = { id: string, name: string, isOn?: boolean, + icon?: "checked" | undefined, type?: "separator" | "color" | "submenu" | "switch" | undefined } @@ -54,6 +55,18 @@ class Menu { this.showSubMenu(rect.right - bodyRect.left, rect.top - bodyRect.top, option.id) } } else { + + if (option.icon) { + let iconName: string + switch (option.icon) { + case "checked": { iconName = "imageMenuCheck" } + default: { Utils.assertFailure(`Unsupported menu icon: ${option.icon}`) } + } + if (iconName) { + optionElement.appendChild(Utils.htmlToElement(`
`)) + } + } + optionElement.onmouseenter = () => { this.hideSubMenu() } diff --git a/src/static/images.css b/src/static/images.css index 23d5390ea..b2c1b2e84 100644 --- a/src/static/images.css +++ b/src/static/images.css @@ -6,7 +6,7 @@ } .imageAdd { - background-image: url('data:image/svg+xml,'); + background-image: url('data:image/svg+xml,'); background-size: 100% 100%; min-width: 24px; min-height: 24px; @@ -25,3 +25,10 @@ min-width: 24px; min-height: 24px; } + +.imageMenuCheck { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +} From 187df20be719c1c89cd86778e20e64f7b3c740a5 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 09:29:49 -0700 Subject: [PATCH 08/34] Show sort direction in sort menu --- src/client/components/boardComponent.tsx | 2 +- src/client/components/tableComponent.tsx | 2 +- src/client/menu.ts | 6 ++++-- src/static/images.css | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 647090ee3..6456d8497 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -286,7 +286,7 @@ class BoardComponent extends React.Component { return { id: o.id, name: o.name, - icon: (sortOption.propertyId === o.id) ? "checked" : undefined + icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined } }) Menu.shared.onMenuClicked = async (propertyId: string) => { diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index 3627bfddc..042f1319e 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -259,7 +259,7 @@ class TableComponent extends React.Component { return { id: o.id, name: o.name, - icon: (sortOption.propertyId === o.id) ? "checked" : undefined + icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined } }) Menu.shared.onMenuClicked = async (propertyId: string) => { diff --git a/src/client/menu.ts b/src/client/menu.ts index a79445fed..35f86763b 100644 --- a/src/client/menu.ts +++ b/src/client/menu.ts @@ -4,7 +4,7 @@ type MenuOption = { id: string, name: string, isOn?: boolean, - icon?: "checked" | undefined, + icon?: "checked" | "sortUp" | "sortDown" | undefined, type?: "separator" | "color" | "submenu" | "switch" | undefined } @@ -59,7 +59,9 @@ class Menu { if (option.icon) { let iconName: string switch (option.icon) { - case "checked": { iconName = "imageMenuCheck" } + case "checked": { iconName = "imageMenuCheck"; break } + case "sortUp": { iconName = "imageMenuSortUp"; break } + case "sortDown": { iconName = "imageMenuSortDown"; break } default: { Utils.assertFailure(`Unsupported menu icon: ${option.icon}`) } } if (iconName) { diff --git a/src/static/images.css b/src/static/images.css index b2c1b2e84..4640988b5 100644 --- a/src/static/images.css +++ b/src/static/images.css @@ -19,6 +19,8 @@ min-height: 24px; } +/*-- Menu images --*/ + .imageSubmenuTriangle { background-image: url('data:image/svg+xml,'); background-size: 100% 100%; @@ -32,3 +34,17 @@ min-width: 24px; min-height: 24px; } + +.imageMenuSortUp { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +} + +.imageMenuSortDown { + background-image: url('data:image/svg+xml,'); + background-size: 100% 100%; + min-width: 24px; + min-height: 24px; +} From 63c7763b41b35f2f540ebf19d9e1cf01e6883c66 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 09:32:36 -0700 Subject: [PATCH 09/34] Refactor: Move sort menu to OctoUtils --- src/client/components/boardComponent.tsx | 34 +-------------------- src/client/components/tableComponent.tsx | 34 +-------------------- src/client/octoUtils.tsx | 39 +++++++++++++++++++++--- 3 files changed, 37 insertions(+), 70 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 6456d8497..16cbbd2d0 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -96,7 +96,7 @@ class BoardComponent extends React.Component { Group by {boardTree.groupByProperty?.name}
{ this.filterClicked(e) }}>Filter
-
{ this.sortClicked(e) }}>Sort
+
{ OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort
{this.state.isSearching ? { pageController.showFilter(e.target as HTMLElement) } - private async sortClicked(e: React.MouseEvent) { - const { mutator, boardTree } = this.props - const { activeView } = boardTree - const { sortOptions } = activeView - const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined - - const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { - return { - id: o.id, - name: o.name, - icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined - } - }) - Menu.shared.onMenuClicked = async (propertyId: string) => { - let newSortOptions: ISortOption[] = [] - if (sortOption && sortOption.propertyId === propertyId) { - // Already sorting by name, so reverse it - newSortOptions = [ - { propertyId, reversed: !sortOption.reversed } - ] - } else { - newSortOptions = [ - { propertyId, reversed: false } - ] - } - - await mutator.changeViewSortOptions(activeView, newSortOptions) - } - Menu.shared.showAtElement(e.target as HTMLElement) - } - private async optionsClicked(e: React.MouseEvent) { const { boardTree } = this.props diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index 042f1319e..3e1e6c8cc 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -90,7 +90,7 @@ class TableComponent extends React.Component {
{ this.propertiesClicked(e) }}>Properties
{ this.filterClicked(e) }}>Filter
-
{ this.sortClicked(e) }}>Sort
+
{ OctoUtils.showSortMenu(e, mutator, boardTree) }}>Sort
{this.state.isSearching ? { pageController.showFilter(e.target as HTMLElement) } - private async sortClicked(e: React.MouseEvent) { - const { mutator, boardTree } = this.props - const { activeView } = boardTree - const { sortOptions } = activeView - const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined - - const propertyTemplates = boardTree.board.cardProperties - Menu.shared.options = propertyTemplates.map((o) => { - return { - id: o.id, - name: o.name, - icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined - } - }) - Menu.shared.onMenuClicked = async (propertyId: string) => { - let newSortOptions: ISortOption[] = [] - if (sortOption && sortOption.propertyId === propertyId) { - // Already sorting by name, so reverse it - newSortOptions = [ - { propertyId, reversed: !sortOption.reversed } - ] - } else { - newSortOptions = [ - { propertyId, reversed: false } - ] - } - - await mutator.changeViewSortOptions(activeView, newSortOptions) - } - Menu.shared.showAtElement(e.target as HTMLElement) - } - private async optionsClicked(e: React.MouseEvent) { const { boardTree } = this.props diff --git a/src/client/octoUtils.tsx b/src/client/octoUtils.tsx index 10b388ada..8ed264a82 100644 --- a/src/client/octoUtils.tsx +++ b/src/client/octoUtils.tsx @@ -1,7 +1,7 @@ import React from "react" import { IPropertyTemplate } from "./board" import { BoardTree } from "./boardTree" -import { BoardView } from "./boardView" +import { BoardView, ISortOption } from "./boardView" import { Editable } from "./components/editable" import { Menu, MenuOption } from "./menu" import { Mutator } from "./mutator" @@ -143,7 +143,7 @@ class OctoUtils { showMenu(e.target as HTMLElement) } } : undefined} - onFocus={mutator ? () => { Menu.shared.hide() } : undefined } + onFocus={mutator ? () => { Menu.shared.hide() } : undefined} > {finalDisplayValue} @@ -176,7 +176,7 @@ class OctoUtils { if (index === 0) { return block.order / 2 } - const previousBlock = blocks[index-1] + const previousBlock = blocks[index - 1] return (block.order + previousBlock.order) / 2 } @@ -185,9 +185,40 @@ class OctoUtils { if (index === blocks.length - 1) { return block.order + 1000 } - const nextBlock = blocks[index+1] + const nextBlock = blocks[index + 1] return (block.order + nextBlock.order) / 2 } + + static showSortMenu(e: React.MouseEvent, mutator: Mutator, boardTree: BoardTree) { + const { activeView } = boardTree + const { sortOptions } = activeView + const sortOption = sortOptions.length > 0 ? sortOptions[0] : undefined + + const propertyTemplates = boardTree.board.cardProperties + Menu.shared.options = propertyTemplates.map((o) => { + return { + id: o.id, + name: o.name, + icon: (sortOption.propertyId === o.id) ? sortOption.reversed ? "sortUp" : "sortDown" : undefined + } + }) + Menu.shared.onMenuClicked = async (propertyId: string) => { + let newSortOptions: ISortOption[] = [] + if (sortOption && sortOption.propertyId === propertyId) { + // Already sorting by name, so reverse it + newSortOptions = [ + { propertyId, reversed: !sortOption.reversed } + ] + } else { + newSortOptions = [ + { propertyId, reversed: false } + ] + } + + await mutator.changeViewSortOptions(activeView, newSortOptions) + } + Menu.shared.showAtElement(e.target as HTMLElement) + } } export { OctoUtils } From 04d4a7beb0f8c5781d69aa16d431d6ed7a3df093 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 09:33:03 -0700 Subject: [PATCH 10/34] cleanup --- src/client/components/boardComponent.tsx | 1 - src/client/components/tableComponent.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 16cbbd2d0..885953c1e 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -4,7 +4,6 @@ import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyOption } from "../board" import { BoardTree } from "../boardTree" -import { ISortOption } from "../boardView" import { CardFilter } from "../cardFilter" import { Constants } from "../constants" import { Menu } from "../menu" diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index 3e1e6c8cc..795ba6e39 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -4,7 +4,6 @@ import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyTemplate } from "../board" import { BoardTree } from "../boardTree" -import { ISortOption } from "../boardView" import { CsvExporter } from "../csvExporter" import { Menu } from "../menu" import { Mutator } from "../mutator" From fec32947bb0a5d272f9052d7e4f2d2afbf2905a7 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Mon, 12 Oct 2020 10:01:58 -0700 Subject: [PATCH 11/34] Cleanup boardPage - layout page frame in code --- html-templates/index.ejs | 6 ------ html-templates/page.ejs | 17 ++--------------- src/client/boardPage.tsx | 27 ++++++++++++++++++++++++++- src/client/boardsPage.ts | 8 +++++++- src/client/components/pageHeader.tsx | 16 ++++++++++++++++ src/static/main.css | 14 +++++--------- 6 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 src/client/components/pageHeader.tsx diff --git a/html-templates/index.ejs b/html-templates/index.ejs index 024e53969..85f4fd368 100644 --- a/html-templates/index.ejs +++ b/html-templates/index.ejs @@ -24,12 +24,6 @@ All Boards

- -
-
- -
-
\ No newline at end of file diff --git a/html-templates/page.ejs b/html-templates/page.ejs index 6766463bd..36c86ecf4 100644 --- a/html-templates/page.ejs +++ b/html-templates/page.ejs @@ -11,21 +11,8 @@ - - - -
-
- -
-
- -
-
- -