From 3c9c5b6aea14e74bfb03bd77d7c73fa644257539 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 14 Oct 2020 17:35:15 -0700 Subject: [PATCH 1/4] Refactor IBlock to use fields --- config.json | 1 + server/main/config.go | 2 +- server/main/octoDatabase.go | 20 ++-- src/client/app.tsx | 3 + src/client/block.ts | 22 +--- src/client/board.ts | 16 +-- src/client/boardTree.ts | 32 ++++-- src/client/boardView.ts | 6 +- src/client/card.ts | 18 ++++ src/client/cardFilter.ts | 8 +- src/client/cardTree.ts | 5 +- src/client/components/boardCard.tsx | 4 +- src/client/components/boardComponent.tsx | 20 ++-- src/client/components/cardDialog.tsx | 2 +- src/client/components/tableComponent.tsx | 11 +- src/client/components/tableRow.tsx | 6 +- src/client/components/workspaceComponent.tsx | 4 +- src/client/mutator.ts | 20 ++-- src/client/octoClient.ts | 23 ++-- src/client/octoTypes.ts | 7 +- src/client/octoUtils.tsx | 11 +- src/client/pages/boardPage.tsx | 4 +- src/client/pages/homePage.tsx | 106 +++++++++---------- 23 files changed, 179 insertions(+), 172 deletions(-) create mode 100644 src/client/card.ts diff --git a/config.json b/config.json index 5ea8eb1f9..30ff1f6c3 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,5 @@ { + "serverRoot": "http://localhost:8000", "port": 8000, "dbtype": "sqlite3", "dbconfig": "./octo.db", diff --git a/server/main/config.go b/server/main/config.go index b7ab3f2f4..7cd2e1e20 100644 --- a/server/main/config.go +++ b/server/main/config.go @@ -21,7 +21,7 @@ func readConfigFile() (*Configuration, error) { viper.SetConfigName("config") // name of config file (without extension) viper.SetConfigType("json") // REQUIRED if the config file does not have the extension in the name viper.AddConfigPath(".") // optionally look for config in the working directory - viper.SetDefault("ServerRoot", "http://localhost") + viper.SetDefault("ServerRoot", "http://localhost:8000") viper.SetDefault("Port", 8000) viper.SetDefault("DBType", "sqlite3") viper.SetDefault("DBConfigString", "./octo.db") diff --git a/server/main/octoDatabase.go b/server/main/octoDatabase.go index dfae0d2f9..487322a1d 100644 --- a/server/main/octoDatabase.go +++ b/server/main/octoDatabase.go @@ -48,16 +48,16 @@ func NewSQLStore(dbType, connectionString string) (*SQLStore, error) { // Block is the basic data unit type Block struct { - ID string `json:"id"` - ParentID string `json:"parentId"` - Schema int64 `json:"schema"` - Type string `json:"type"` - Title string `json:"title"` - Properties map[string]interface{} `json:"properties"` - Fields map[string]interface{} `json:"fields"` - CreateAt int64 `json:"createAt"` - UpdateAt int64 `json:"updateAt"` - DeleteAt int64 `json:"deleteAt"` + ID string `json:"id"` + ParentID string `json:"parentId"` + Schema int64 `json:"schema"` + Type string `json:"type"` + Title string `json:"title"` + Order int64 `json:"order"` + Fields map[string]interface{} `json:"fields"` + CreateAt int64 `json:"createAt"` + UpdateAt int64 `json:"updateAt"` + DeleteAt int64 `json:"deleteAt"` } func (s *SQLStore) createTablesIfNotExists() error { diff --git a/src/client/app.tsx b/src/client/app.tsx index d7bdbc5b0..e0c781904 100644 --- a/src/client/app.tsx +++ b/src/client/app.tsx @@ -31,6 +31,9 @@ export default function App() {
+ + ) diff --git a/src/client/block.ts b/src/client/block.ts index 08aba81e3..4bf7c609d 100644 --- a/src/client/block.ts +++ b/src/client/block.ts @@ -7,10 +7,7 @@ class Block implements IBlock { parentId: string type: string title: string - icon?: string - url?: string order: number - properties: Record = {} fields: Record = {} createAt: number = Date.now() updateAt: number = 0 @@ -37,32 +34,15 @@ class Block implements IBlock { this.parentId = block.parentId this.type = block.type + // Shallow copy here. Derived classes must make deep copies of their known properties in their constructors. this.fields = block.fields ? { ...block.fields } : {} this.title = block.title - this.icon = block.icon - this.url = block.url this.order = block.order this.createAt = block.createAt || now this.updateAt = block.updateAt || now this.deleteAt = block.deleteAt || 0 - - if (block.schema !== 1) { - if (Array.isArray(block.properties)) { - // HACKHACK: Port from old schema - this.properties = {} - for (const property of block.properties) { - if (property.id) { - this.properties[property.id] = property.value - } - } - } else { - this.properties = { ...block.properties || {} } - } - } else { - this.properties = { ...block.properties } // Shallow copy here. Derived classes must make deep copies of their known properties in their constructors. - } } } diff --git a/src/client/board.ts b/src/client/board.ts index f01ba7f61..ea28c30bb 100644 --- a/src/client/board.ts +++ b/src/client/board.ts @@ -16,6 +16,9 @@ interface IPropertyTemplate { } class Board extends Block { + get icon(): string { return this.fields.icon as string } + set icon(value: string) { this.fields.icon = value } + get cardProperties(): IPropertyTemplate[] { return this.fields.cardProperties as IPropertyTemplate[] } set cardProperties(value: IPropertyTemplate[]) { this.fields.cardProperties = value } @@ -25,7 +28,7 @@ class Board extends Block { if (block.fields?.cardProperties) { // Deep clone of card properties and their options - this.cardProperties = block.fields?.cardProperties.map((o: IPropertyTemplate) => { + this.cardProperties = block.fields.cardProperties.map((o: IPropertyTemplate) => { return { id: o.id, name: o.name, @@ -36,17 +39,6 @@ class Board extends Block { } else { this.cardProperties = [] } - - if (block.schema !== 1) { - this.cardProperties = block.cardProperties?.map((o: IPropertyTemplate) => { - return { - id: o.id, - name: o.name, - type: o.type, - options: o.options ? o.options.map(option => ({ ...option })) : [] - } - }) || [] - } } } diff --git a/src/client/boardTree.ts b/src/client/boardTree.ts index 0d4d84e93..285bb2440 100644 --- a/src/client/boardTree.ts +++ b/src/client/boardTree.ts @@ -1,24 +1,25 @@ import { Board, IPropertyOption, IPropertyTemplate } from "./board" import { BoardView } from "./boardView" +import { Card } from "./card" import { CardFilter } from "./cardFilter" import { OctoClient } from "./octoClient" import { IBlock } from "./octoTypes" import { Utils } from "./utils" -type Group = { option: IPropertyOption, cards: IBlock[] } +type Group = { option: IPropertyOption, cards: Card[] } class BoardTree { board!: Board views: BoardView[] = [] - cards: IBlock[] = [] - emptyGroupCards: IBlock[] = [] + cards: Card[] = [] + emptyGroupCards: Card[] = [] groups: Group[] = [] activeView?: BoardView groupByProperty?: IPropertyTemplate private searchText?: string - private allCards: IBlock[] = [] + private allCards: Card[] = [] get allBlocks(): IBlock[] { return [this.board, ...this.views, ...this.allCards] } @@ -44,7 +45,7 @@ class BoardTree { this.views = viewBlocks.map(o => new BoardView(o)) const cardBlocks = blocks.filter(block => block.type === "card") - this.allCards = cardBlocks + this.allCards = cardBlocks.map(o => new Card(o)) this.cards = [] this.ensureMinimumSchema() @@ -104,18 +105,25 @@ class BoardTree { } applyFilterSortAndGroup() { + Utils.assert(this.allCards !== undefined) + this.cards = this.filterCards(this.allCards) + Utils.assert(this.cards !== undefined) this.cards = this.searchFilterCards(this.cards) + Utils.assert(this.cards !== undefined) this.cards = this.sortCards(this.cards) + Utils.assert(this.cards !== undefined) if (this.activeView.groupById) { this.setGroupByProperty(this.activeView.groupById) } else { Utils.assert(this.activeView.viewType !== "board") } + + Utils.assert(this.cards !== undefined) } - private searchFilterCards(cards: IBlock[]) { + private searchFilterCards(cards: Card[]): Card[] { const searchText = this.searchText?.toLocaleLowerCase() if (!searchText) { return cards.slice() } @@ -166,7 +174,7 @@ class BoardTree { } } - private filterCards(cards: IBlock[]): IBlock[] { + private filterCards(cards: Card[]): Card[] { const { board } = this const filterGroup = this.activeView?.filter if (!filterGroup) { return cards.slice() } @@ -174,11 +182,11 @@ class BoardTree { return CardFilter.applyFilterGroup(filterGroup, board.cardProperties, cards) } - private sortCards(cards: IBlock[]): IBlock[] { + private sortCards(cards: Card[]): Card[] { if (!this.activeView) { Utils.assertFailure(); return cards } const { board } = this const { sortOptions } = this.activeView - let sortedCards: IBlock[] + let sortedCards: Card[] = [] if (sortOptions.length < 1) { Utils.log(`Default sort`) @@ -213,7 +221,11 @@ class BoardTree { } else { const sortPropertyId = sortOption.propertyId const template = board.cardProperties.find(o => o.id === sortPropertyId) - Utils.log(`Sort by ${template.name}`) + if (!template) { + Utils.logError(`Missing template for property id: ${sortPropertyId}`) + return cards.slice() + } + Utils.log(`Sort by ${template?.name}`) sortedCards = cards.sort((a, b) => { // Always put cards with no titles at the bottom if (a.title && !b.title) { return -1 } diff --git a/src/client/boardView.ts b/src/client/boardView.ts index c1aed1b23..9b7c8692a 100644 --- a/src/client/boardView.ts +++ b/src/client/boardView.ts @@ -25,9 +25,9 @@ class BoardView extends Block { this.type = "view" - this.sortOptions = block.properties?.sortOptions?.map((o: ISortOption) => ({ ...o })) || [] // Deep clone - this.visiblePropertyIds = block.properties?.visiblePropertyIds?.slice() || [] - this.filter = new FilterGroup(block.properties?.filter) + this.sortOptions = block.fields?.sortOptions?.map((o: ISortOption) => ({ ...o })) || [] // Deep clone + this.visiblePropertyIds = block.fields?.visiblePropertyIds?.slice() || [] + this.filter = new FilterGroup(block.fields?.filter) // TODO: Remove this fixup code if (block.schema !== 1) { diff --git a/src/client/card.ts b/src/client/card.ts new file mode 100644 index 000000000..5150b2c05 --- /dev/null +++ b/src/client/card.ts @@ -0,0 +1,18 @@ +import { Block } from "./block" + +class Card extends Block { + get icon(): string { return this.fields.icon as string } + set icon(value: string) { this.fields.icon = value } + + get properties(): Record { return this.fields.properties as Record } + set properties(value: Record) { this.fields.properties = value } + + constructor(block: any = {}) { + super(block) + this.type = "card" + + this.properties = { ...(block.fields?.properties || {}) } + } +} + +export { Card } diff --git a/src/client/cardFilter.ts b/src/client/cardFilter.ts index 82641f89c..7e69aba21 100644 --- a/src/client/cardFilter.ts +++ b/src/client/cardFilter.ts @@ -1,15 +1,15 @@ import { IPropertyTemplate } from "./board" +import { Card } from "./card" import { FilterClause } from "./filterClause" import { FilterGroup } from "./filterGroup" -import { IBlock } from "./octoTypes" import { Utils } from "./utils" class CardFilter { - static applyFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[], cards: IBlock[]): IBlock[] { + static applyFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[], cards: Card[]): Card[] { return cards.filter(card => this.isFilterGroupMet(filterGroup, templates, card)) } - static isFilterGroupMet(filterGroup: FilterGroup, templates: IPropertyTemplate[], card: IBlock): boolean { + static isFilterGroupMet(filterGroup: FilterGroup, templates: IPropertyTemplate[], card: Card): boolean { const { filters } = filterGroup if (filterGroup.filters.length < 1) { @@ -38,7 +38,7 @@ class CardFilter { } } - static isClauseMet(filter: FilterClause, templates: IPropertyTemplate[], card: IBlock): boolean { + static isClauseMet(filter: FilterClause, templates: IPropertyTemplate[], card: Card): boolean { const value = card.properties[filter.propertyId] switch (filter.condition) { case "includes": { diff --git a/src/client/cardTree.ts b/src/client/cardTree.ts index 28b2d44d0..819d522b3 100644 --- a/src/client/cardTree.ts +++ b/src/client/cardTree.ts @@ -1,8 +1,9 @@ +import { Card } from "./card" import { OctoClient } from "./octoClient" import { IBlock } from "./octoTypes" class CardTree { - card: IBlock + card: Card comments: IBlock[] contents: IBlock[] isSynched: boolean @@ -18,7 +19,7 @@ class CardTree { } private rebuild(blocks: IBlock[]) { - this.card = blocks.find(o => o.id === this.cardId) + this.card = new Card(blocks.find(o => o.id === this.cardId)) this.comments = blocks .filter(block => block.type === "comment") diff --git a/src/client/components/boardCard.tsx b/src/client/components/boardCard.tsx index 65e7af493..39ca5fb96 100644 --- a/src/client/components/boardCard.tsx +++ b/src/client/components/boardCard.tsx @@ -1,15 +1,15 @@ import React from "react" import { Block } from "../block" import { IPropertyTemplate } from "../board" +import { Card } from "../card" import { Menu } from "../menu" import { Mutator } from "../mutator" -import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { Utils } from "../utils" type BoardCardProps = { mutator: Mutator - card: IBlock + card: Card visiblePropertyTemplates: IPropertyTemplate[] onClick?: (e: React.MouseEvent) => void onDragStart?: (e: React.DragEvent) => void diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 510c37d54..46bff9a3c 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -1,15 +1,14 @@ import React from "react" import { Archiver } from "../archiver" -import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyOption } from "../board" import { BoardTree } from "../boardTree" +import { Card } from "../card" import { CardFilter } from "../cardFilter" import ViewMenu from "../components/viewMenu" import { Constants } from "../constants" import { Menu as OldMenu } from "../menu" import { Mutator } from "../mutator" -import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { Utils } from "../utils" import { BoardCard } from "./boardCard" @@ -21,7 +20,7 @@ type Props = { mutator: Mutator, boardTree?: BoardTree showView: (id: string) => void - showCard: (card: IBlock) => void + showCard: (card: Card) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } @@ -33,7 +32,7 @@ type State = { } class BoardComponent extends React.Component { - private draggedCard: IBlock + private draggedCard: Card private draggedHeaderOption: IPropertyOption private searchFieldRef = React.createRef() @@ -239,7 +238,7 @@ class BoardComponent extends React.Component { OldMenu.shared.showAtElement(e.target as HTMLElement) } - async showCard(card?: IBlock) { + async showCard(card?: Card) { console.log(`showCard: ${card?.title}`) await this.props.showCard(card) @@ -249,8 +248,9 @@ class BoardComponent extends React.Component { const { mutator, boardTree } = this.props const { activeView, board } = boardTree - const properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties) - const card = new Block({ type: "card", parentId: boardTree.board.id, properties }) + const card = new Card() + card.parentId = boardTree.board.id + card.properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties) if (boardTree.groupByProperty) { card.properties[boardTree.groupByProperty.id] = groupByValue } @@ -325,8 +325,9 @@ class BoardComponent extends React.Component { let optionIndex = 0 for (let i = 0; i < count; i++) { - const properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties) - const card = new Block({ type: "card", parentId: boardTree.board.id, properties }) + const card = new Card() + card.parentId = boardTree.board.id + card.properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties) if (boardTree.groupByProperty && boardTree.groupByProperty.options.length > 0) { // Cycle through options const option = boardTree.groupByProperty.options[optionIndex] @@ -387,6 +388,7 @@ class BoardComponent extends React.Component { color: "#cccccc" } + Utils.assert(boardTree.groupByProperty) await mutator.insertPropertyOption(boardTree, boardTree.groupByProperty, option, "add group") } diff --git a/src/client/components/cardDialog.tsx b/src/client/components/cardDialog.tsx index 2a47ac310..e664c55c9 100644 --- a/src/client/components/cardDialog.tsx +++ b/src/client/components/cardDialog.tsx @@ -79,7 +79,7 @@ class CardDialog extends React.Component { }} /> } else if (block.type === "image") { - const url = block.url + const url = block.fields.url return
{ this.showContentBlockMenu(e, block) }}> diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index a55508ae5..e3e6a3581 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -4,11 +4,11 @@ import { Block } from "../block" import { BlockIcons } from "../blockIcons" import { IPropertyTemplate } from "../board" import { BoardTree } from "../boardTree" -import { CsvExporter } from "../csvExporter" +import { Card } from "../card" import ViewMenu from "../components/viewMenu" +import { CsvExporter } from "../csvExporter" import { Menu as OldMenu } from "../menu" import { Mutator } from "../mutator" -import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { Utils } from "../utils" import Button from "./button" @@ -19,7 +19,7 @@ type Props = { mutator: Mutator, boardTree?: BoardTree showView: (id: string) => void - showCard: (card: IBlock) => void + showCard: (card: Card) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } @@ -363,7 +363,7 @@ class TableComponent extends React.Component { OldMenu.shared.showAtElement(e.target as HTMLElement) } - async showCard(card: IBlock) { + async showCard(card: Card) { console.log(`showCard: ${card.title}`) await this.props.showCard(card) @@ -378,7 +378,8 @@ class TableComponent extends React.Component { async addCard(show: boolean = false) { const { mutator, boardTree } = this.props - const card = new Block({ type: "card", parentId: boardTree.board.id }) + const card = new Card() + card.parentId = boardTree.board.id await mutator.insertBlock( card, "add card", diff --git a/src/client/components/tableRow.tsx b/src/client/components/tableRow.tsx index fc6d6d7d2..3625fef47 100644 --- a/src/client/components/tableRow.tsx +++ b/src/client/components/tableRow.tsx @@ -1,16 +1,16 @@ import React from "react" import { BoardTree } from "../boardTree" +import { Card } from "../card" import { Mutator } from "../mutator" -import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { Editable } from "./editable" type Props = { mutator: Mutator boardTree: BoardTree - card: IBlock + card: Card focusOnMount: boolean - showCard: (card: IBlock) => void + showCard: (card: Card) => void onKeyDown: (e: React.KeyboardEvent) => void } diff --git a/src/client/components/workspaceComponent.tsx b/src/client/components/workspaceComponent.tsx index eed77b353..e7c37a30f 100644 --- a/src/client/components/workspaceComponent.tsx +++ b/src/client/components/workspaceComponent.tsx @@ -1,7 +1,7 @@ import React from "react" import { BoardTree } from "../boardTree" +import { Card } from "../card" import { Mutator } from "../mutator" -import { IBlock } from "../octoTypes" import { Utils } from "../utils" import { WorkspaceTree } from "../workspaceTree" import { BoardComponent } from "./boardComponent" @@ -14,7 +14,7 @@ type Props = { boardTree?: BoardTree showBoard: (id: string) => void showView: (id: string) => void - showCard: (card: IBlock) => void + showCard: (card: Card) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } diff --git a/src/client/mutator.ts b/src/client/mutator.ts index ef77bc346..918134935 100644 --- a/src/client/mutator.ts +++ b/src/client/mutator.ts @@ -2,6 +2,7 @@ import { Block } from "./block" import { Board, IPropertyOption, IPropertyTemplate, PropertyType } from "./board" import { BoardTree } from "./boardTree" import { BoardView, ISortOption } from "./boardView" +import { Card } from "./card" import { FilterGroup } from "./filterGroup" import { OctoClient } from "./octoClient" import { IBlock } from "./octoTypes" @@ -87,7 +88,7 @@ class Mutator { ) } - async changeIcon(block: IBlock, icon: string, description: string = "change icon") { + async changeIcon(block: Card | Board, icon: string, description: string = "change icon") { const { octo, undoManager } = this const oldValue = block.icon @@ -291,6 +292,8 @@ class Mutator { const { octo, undoManager } = this const { board } = boardTree + Utils.assert(board.cardProperties.includes(template)) + const oldValue = template.options const newValue = template.options.slice() newValue.push(option) @@ -405,18 +408,18 @@ class Mutator { ) } - async changePropertyValue(block: IBlock, propertyId: string, value?: string, description: string = "change property") { + async changePropertyValue(card: Card, propertyId: string, value?: string, description: string = "change property") { const { octo, undoManager } = this - const oldValue = block.properties[propertyId] + const oldValue = card.properties[propertyId] await undoManager.perform( async () => { - block.properties[propertyId] = value - await octo.updateBlock(block) + card.properties[propertyId] = value + await octo.updateBlock(card) }, async () => { - block.properties[propertyId] = oldValue - await octo.updateBlock(block) + card.properties[propertyId] = oldValue + await octo.updateBlock(card) }, description ) @@ -531,7 +534,8 @@ class Mutator { return undefined } - const block = new Block({ type: "image", parentId, url, order }) + const block = new Block({ type: "image", parentId, order }) + block.fields.url = url await undoManager.perform( async () => { diff --git a/src/client/octoClient.ts b/src/client/octoClient.ts index 85b138498..1c804bce9 100644 --- a/src/client/octoClient.ts +++ b/src/client/octoClient.ts @@ -57,25 +57,20 @@ class OctoClient { } const response = await fetch(this.serverUrl + path) - const blocks = await response.json() as IBlock[] + const blocks = (await response.json() || []) as IBlock[] this.fixBlocks(blocks) return blocks } - fixBlocks(blocks: IBlock[]) { + fixBlocks(blocks: IBlock[]): void { + // TODO for (const block of blocks) { - if (!block.properties) { block.properties = {} } - - if (Array.isArray(block.properties)) { - // PORT from old schema - const properties: Record = {} - for (const property of block.properties) { - if (property.id) { - properties[property.id] = property.value - } - } - block.properties = properties - } + if (!block.fields) { block.fields = {} } + const o = block as any + if (o.cardProperties) { block.fields.cardProperties = o.cardProperties; delete o.cardProperties } + if (o.properties) { block.fields.properties = o.properties; delete o.properties } + if (o.icon) { block.fields.icon = o.icon; delete o.icon } + if (o.url) { block.fields.url = o.url; delete o.url } } } diff --git a/src/client/octoTypes.ts b/src/client/octoTypes.ts index 7047c87c6..8b0ada85a 100644 --- a/src/client/octoTypes.ts +++ b/src/client/octoTypes.ts @@ -1,3 +1,5 @@ +import { Card } from "./card" + // A block is the fundamental data type interface IBlock { id: string @@ -6,10 +8,7 @@ interface IBlock { schema: number type: string title?: string - url?: string // TODO: Move to properties (_url) - icon?: string order: number - properties: Record fields: Record createAt: number @@ -19,7 +18,7 @@ interface IBlock { // These are methods exposed by the top-level page to components interface IPageController { - showCard(card: IBlock): Promise + showCard(card: Card): Promise showBoard(boardId: string): void showView(viewId: string): void showFilter(anchorElement?: HTMLElement): void diff --git a/src/client/octoUtils.tsx b/src/client/octoUtils.tsx index 4fedbd32b..5072c4665 100644 --- a/src/client/octoUtils.tsx +++ b/src/client/octoUtils.tsx @@ -1,9 +1,10 @@ import React from "react" import { IPropertyTemplate } from "./board" import { BoardTree } from "./boardTree" -import { BoardView, ISortOption } from "./boardView" +import { ISortOption } from "./boardView" +import { Card } from "./card" import { Editable } from "./components/editable" -import { Menu, MenuOption } from "./menu" +import { Menu } from "./menu" import { Mutator } from "./mutator" import { IBlock } from "./octoTypes" import { Utils } from "./utils" @@ -25,15 +26,15 @@ class OctoUtils { return displayValue } - static propertyValueReadonlyElement(card: IBlock, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element { + static propertyValueReadonlyElement(card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element { return this.propertyValueElement(undefined, card, propertyTemplate, emptyDisplayValue) } - static propertyValueEditableElement(mutator: Mutator, card: IBlock, propertyTemplate: IPropertyTemplate, emptyDisplayValue?: string): JSX.Element { + static propertyValueEditableElement(mutator: Mutator, card: Card, propertyTemplate: IPropertyTemplate, emptyDisplayValue?: string): JSX.Element { return this.propertyValueElement(mutator, card, propertyTemplate, emptyDisplayValue) } - private static propertyValueElement(mutator: Mutator | undefined, card: IBlock, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element { + private static propertyValueElement(mutator: Mutator | undefined, 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 diff --git a/src/client/pages/boardPage.tsx b/src/client/pages/boardPage.tsx index ad4ee5f03..ca2da0502 100644 --- a/src/client/pages/boardPage.tsx +++ b/src/client/pages/boardPage.tsx @@ -2,6 +2,7 @@ import React from "react" import ReactDOM from "react-dom" import { BoardTree } from "../boardTree" import { BoardView } from "../boardView" +import { Card } from "../card" import { CardTree } from "../cardTree" import { CardDialog } from "../components/cardDialog" import { FilterComponent } from "../components/filterComponent" @@ -10,7 +11,6 @@ import { FlashMessage } from "../flashMessage" import { Mutator } from "../mutator" import { OctoClient } from "../octoClient" import { OctoListener } from "../octoListener" -import { IBlock } from "../octoTypes" import { UndoManager } from "../undomanager" import { Utils } from "../utils" import { WorkspaceTree } from "../workspaceTree" @@ -210,7 +210,7 @@ export default class BoardPage extends React.Component { // IPageController - async showCard(card: IBlock) { + async showCard(card: Card) { this.cardListener.close() if (card) { diff --git a/src/client/pages/homePage.tsx b/src/client/pages/homePage.tsx index df2b1e762..05fed1d02 100644 --- a/src/client/pages/homePage.tsx +++ b/src/client/pages/homePage.tsx @@ -1,76 +1,74 @@ -import React from 'react'; - -import { IBlock } from "../octoTypes" +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 { IBlock } from "../octoTypes" import { UndoManager } from "../undomanager" import { Utils } from "../utils" -import Button from '../components/button'; -type Props = {}; +type Props = {} type State = { - boards: IBlock[]; -}; + boards: IBlock[] +} export default class HomePage extends React.Component { - constructor(props: Props) { - super(props); - this.state = { - boards: [], - } - } + constructor(props: Props) { + super(props) + this.state = { + boards: [], + } + } - componentDidMount() { - this.loadBoards(); - } + componentDidMount() { + this.loadBoards() + } - loadBoards = async () => { - const octo = new OctoClient() + loadBoards = async () => { + const octo = new OctoClient() const boards = await octo.getBlocks(null, "board") - this.setState({boards}); - } + this.setState({ boards }) + } - importClicked = async () => { - const octo = new OctoClient() - const mutator = new Mutator(octo, UndoManager.shared) - Archiver.importFullArchive(mutator, () => { - this.loadBoards() - }) - } + importClicked = async () => { + const octo = new OctoClient() + const mutator = new Mutator(octo, UndoManager.shared) + Archiver.importFullArchive(mutator, () => { + this.loadBoards() + }) + } - exportClicked = async () => { - const octo = new OctoClient() - const mutator = new Mutator(octo, UndoManager.shared) - Archiver.exportFullArchive(mutator) - } + exportClicked = async () => { + const octo = new OctoClient() + const mutator = new Mutator(octo, UndoManager.shared) + Archiver.exportFullArchive(mutator) + } - addClicked = async () => { - const octo = new OctoClient() + addClicked = async () => { + const octo = new OctoClient() const board = new Board() await octo.insertBlock(board) } - public render(): React.ReactNode { - return ( -
- -
- -
- - {this.state.boards.map((board) => ( -

- - {board.icon && {board.icon}} - {board.title} - {Utils.displayDate(new Date(board.updateAt))} - -

- ))} -
- ); - } + render(): React.ReactNode { + return ( +
+ +
+ +
+ + {this.state.boards.map((board) => ( +

+ + {board.title} + {Utils.displayDate(new Date(board.updateAt))} + +

+ ))} +
+ ) + } } From 5c8d86930785dca5aea1f9db139e103ea4c74ea2 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 14 Oct 2020 17:38:57 -0700 Subject: [PATCH 2/4] Fix show filters --- src/client/components/switch.tsx | 2 +- src/client/pages/boardPage.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/client/components/switch.tsx b/src/client/components/switch.tsx index 281c936c0..3354e239d 100644 --- a/src/client/components/switch.tsx +++ b/src/client/components/switch.tsx @@ -52,7 +52,7 @@ class Switch extends React.Component { private async onClicked() { const newIsOn = !this.state.isOn - await this.setState({ isOn: newIsOn }) + this.setState({ isOn: newIsOn }) const { onChanged } = this.props diff --git a/src/client/pages/boardPage.tsx b/src/client/pages/boardPage.tsx index ca2da0502..f824cdc2a 100644 --- a/src/client/pages/boardPage.tsx +++ b/src/client/pages/boardPage.tsx @@ -24,6 +24,7 @@ type State = { workspaceTree: WorkspaceTree boardTree?: BoardTree shownCardTree?: CardTree + filterAnchorElement?: HTMLElement } export default class BoardPage extends React.Component { @@ -32,7 +33,6 @@ export default class BoardPage extends React.Component { updateTitleTimeout: number updatePropertyLabelTimeout: number - private filterAnchorElement?: HTMLElement private octo = new OctoClient() private boardListener = new OctoListener() private cardListener = new OctoListener() @@ -126,8 +126,8 @@ export default class BoardPage extends React.Component { } } - if (this.filterAnchorElement) { - const element = this.filterAnchorElement + if (this.state.filterAnchorElement) { + const element = this.state.filterAnchorElement const bodyRect = document.body.getBoundingClientRect() const rect = element.getBoundingClientRect() // Show at bottom-left of element @@ -246,8 +246,8 @@ export default class BoardPage extends React.Component { window.history.pushState({ path: newUrl }, "", newUrl) } - showFilter(ahchorElement?: HTMLElement) { - this.filterAnchorElement = ahchorElement + showFilter(anchorElement?: HTMLElement) { + this.setState({...this.state, filterAnchorElement: anchorElement}) } setSearchText(text?: string) { From efba6147651fd461ac2e9a84427ce069f234e40f Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 14 Oct 2020 17:40:27 -0700 Subject: [PATCH 3/4] Fix text search --- src/client/pages/boardPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/pages/boardPage.tsx b/src/client/pages/boardPage.tsx index f824cdc2a..cd35e991b 100644 --- a/src/client/pages/boardPage.tsx +++ b/src/client/pages/boardPage.tsx @@ -252,5 +252,6 @@ export default class BoardPage extends React.Component { setSearchText(text?: string) { this.state.boardTree?.setSearchText(text) + this.setState({...this.state, boardTree: this.state.boardTree}) } } From 9ac8d2b0f9c46042500bf72bcc7980636cb7af29 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 14 Oct 2020 17:58:11 -0700 Subject: [PATCH 4/4] Fix filter assert --- src/client/cardFilter.ts | 19 ++++++++++++++----- src/client/components/boardComponent.tsx | 7 ++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/client/cardFilter.ts b/src/client/cardFilter.ts index 7e69aba21..28dd14768 100644 --- a/src/client/cardFilter.ts +++ b/src/client/cardFilter.ts @@ -55,22 +55,31 @@ class CardFilter { case "isNotEmpty": { return !!value } + default: { + Utils.assertFailure(`Invalid filter condition ${filter.condition}`) + } } - Utils.assertFailure(`Invalid filter condition ${filter.condition}`) return true } - static propertiesThatMeetFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[]): Record { + static propertiesThatMeetFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[]): Record { // TODO: Handle filter groups const filters = filterGroup.filters.filter(o => !FilterGroup.isAnInstanceOf(o)) - if (filters.length < 1) { return [] } + if (filters.length < 1) { return {} } if (filterGroup.operation === "or") { // Just need to meet the first clause const property = this.propertyThatMeetsFilterClause(filters[0] as FilterClause, templates) - return [property] + const result: Record = {} + result[property.id] = property.value + return result } else { - return filters.map(filterClause => this.propertyThatMeetsFilterClause(filterClause as FilterClause, templates)) + const result: Record = {} + filters.forEach(filterClause => { + const p = this.propertyThatMeetsFilterClause(filterClause as FilterClause, templates) + result[p.id] = p.value + }) + return result } } diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 46bff9a3c..1266f893e 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -7,6 +7,7 @@ import { Card } from "../card" import { CardFilter } from "../cardFilter" import ViewMenu from "../components/viewMenu" import { Constants } from "../constants" +import { randomEmojiList } from "../emojiList" import { Menu as OldMenu } from "../menu" import { Mutator } from "../mutator" import { OctoUtils } from "../octoUtils" @@ -309,9 +310,11 @@ class BoardComponent extends React.Component { } case "testAdd100Cards": { this.testAddCards(100) + break } case "testAdd1000Cards": { this.testAddCards(1000) + break } } } @@ -322,6 +325,7 @@ class BoardComponent extends React.Component { const { mutator, boardTree } = this.props const { board, activeView } = boardTree + const startCount = boardTree?.cards?.length let optionIndex = 0 for (let i = 0; i < count; i++) { @@ -333,7 +337,8 @@ class BoardComponent extends React.Component { const option = boardTree.groupByProperty.options[optionIndex] optionIndex = (optionIndex + 1) % boardTree.groupByProperty.options.length card.properties[boardTree.groupByProperty.id] = option.value - card.title = `Test Card ${i + 1}` + card.title = `Test Card ${startCount + i + 1}` + card.icon = BlockIcons.shared.randomIcon() } await mutator.insertBlock(card, "test add card") }