diff --git a/.gitignore b/.gitignore index d8b88e56b..e3dd6f49c 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,4 @@ bin debug __debug_bin files -octo.db +octo*.db diff --git a/src/client/block.ts b/src/client/block.ts index d77acbf1f..421469e2b 100644 --- a/src/client/block.ts +++ b/src/client/block.ts @@ -1,4 +1,4 @@ -import { IBlock, IProperty } from "./octoTypes" +import { IBlock } from "./octoTypes" import { Utils } from "./utils" class Block implements IBlock { @@ -9,7 +9,7 @@ class Block implements IBlock { icon?: string url?: string order: number - properties: IProperty[] = [] + properties: Record = {} createAt: number = Date.now() updateAt: number = 0 deleteAt: number = 0 @@ -37,34 +37,45 @@ class Block implements IBlock { this.icon = block.icon this.url = block.url this.order = block.order - this.properties = block.properties ? block.properties.map((o: IProperty) => ({...o})) : [] // Deep clone this.createAt = block.createAt || now this.updateAt = block.updateAt || now this.deleteAt = block.deleteAt || 0 + + // this.properties = block.properties ? block.properties.map((o: IProperty) => ({ ...o })) : [] // Deep clone + 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 || {} } + } } static getPropertyValue(block: IBlock, id: string): string | undefined { if (!block.properties) { return undefined } - const property = block.properties.find( o => o.id === id ) - if (!property) { return undefined } - return property.value + return block.properties[id] } static setProperty(block: IBlock, id: string, value?: string) { - if (!block.properties) { block.properties = [] } - if (!value) { - // Remove property - block.properties = block.properties.filter( o => o.id !== id ) - return - } + block.properties[id] = value + // if (!block.properties) { block.properties = [] } + // if (!value) { + // // Remove property + // block.properties = block.properties.filter(o => o.id !== id) + // return + // } - const property = block.properties.find( o => o.id === id ) - if (property) { - property.value = value - } else { - const newProperty: IProperty = { id, value } - block.properties.push(newProperty) - } + // const property = block.properties.find(o => o.id === id) + // if (property) { + // property.value = value + // } else { + // const newProperty: IProperty = { id, value } + // block.properties.push(newProperty) + // } } } diff --git a/src/client/boardPage.tsx b/src/client/boardPage.tsx index ad5eb650f..bc9009a62 100644 --- a/src/client/boardPage.tsx +++ b/src/client/boardPage.tsx @@ -112,11 +112,6 @@ class BoardPage implements IPageController { Utils.getElementById("header") ) - ReactDOM.render( - , - Utils.getElementById("header") - ) - if (board) { Utils.setFavicon(board.icon) document.title = `OCTO - ${board.title} | ${activeView.title}` diff --git a/src/client/boardTree.ts b/src/client/boardTree.ts index 146a0ed2d..0d4d84e93 100644 --- a/src/client/boardTree.ts +++ b/src/client/boardTree.ts @@ -145,16 +145,16 @@ class BoardTree { const groupByPropertyId = this.groupByProperty.id this.emptyGroupCards = this.cards.filter(o => { - const property = o.properties.find(p => p.id === groupByPropertyId) - return !property || !property.value || !this.groupByProperty.options.find(option => option.value === property.value) + const propertyValue = o.properties[groupByPropertyId] + return !propertyValue || !this.groupByProperty.options.find(option => option.value === propertyValue) }) const propertyOptions = this.groupByProperty.options || [] for (const option of propertyOptions) { const cards = this.cards .filter(o => { - const property = o.properties.find(p => p.id === groupByPropertyId) - return property && property.value === option.value + const propertyValue = o.properties[groupByPropertyId] + return propertyValue && propertyValue === option.value }) const group: Group = { @@ -220,10 +220,8 @@ class BoardTree { if (b.title && !a.title) { return 1 } if (!a.title && !b.title) { return a.createAt - b.createAt } - const aProperty = a.properties.find(o => o.id === sortPropertyId) - const bProperty = b.properties.find(o => o.id === sortPropertyId) - const aValue = aProperty ? aProperty.value : "" - const bValue = bProperty ? bProperty.value : "" + const aValue = a.properties[sortPropertyId] || "" + const bValue = b.properties[sortPropertyId] || "" let result = 0 if (template.type === "select") { // Always put empty values at the bottom diff --git a/src/client/cardFilter.ts b/src/client/cardFilter.ts index fe7b982c3..82641f89c 100644 --- a/src/client/cardFilter.ts +++ b/src/client/cardFilter.ts @@ -1,7 +1,7 @@ import { IPropertyTemplate } from "./board" import { FilterClause } from "./filterClause" import { FilterGroup } from "./filterGroup" -import { IBlock, IProperty } from "./octoTypes" +import { IBlock } from "./octoTypes" import { Utils } from "./utils" class CardFilter { @@ -39,8 +39,7 @@ class CardFilter { } static isClauseMet(filter: FilterClause, templates: IPropertyTemplate[], card: IBlock): boolean { - const property = card.properties.find(o => o.id === filter.propertyId) - const value = property?.value + const value = card.properties[filter.propertyId] switch (filter.condition) { case "includes": { if (filter.values.length < 1) { break } // No values = ignore clause (always met) @@ -61,7 +60,7 @@ class CardFilter { return true } - static propertiesThatMeetFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[]): IProperty[] { + 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 [] } @@ -75,7 +74,7 @@ class CardFilter { } } - static propertyThatMeetsFilterClause(filterClause: FilterClause, templates: IPropertyTemplate[]): IProperty { + static propertyThatMeetsFilterClause(filterClause: FilterClause, templates: IPropertyTemplate[]): { id: string, value?: string } { const template = templates.find(o => o.id === filterClause.propertyId) switch (filterClause.condition) { case "includes": { diff --git a/src/client/csvExporter.ts b/src/client/csvExporter.ts index 15dfa9dd6..97060bb18 100644 --- a/src/client/csvExporter.ts +++ b/src/client/csvExporter.ts @@ -49,10 +49,10 @@ class CsvExporter { cards.forEach(card => { const row: string[] = [] visibleProperties.forEach(template => { - const property = card.properties.find(o => o.id === template.id) - const displayValue = OctoUtils.propertyDisplayValue(card, property, template) || "" + const propertyValue = card.properties[template.id] + const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, template) || "" if (template.type === "number") { - const numericValue = property?.value ? Number(property?.value).toString() : undefined + const numericValue = propertyValue ? Number(propertyValue).toString() : undefined row.push(numericValue) } else { // Export as string diff --git a/src/client/mutator.ts b/src/client/mutator.ts index b88099c07..18c062e7b 100644 --- a/src/client/mutator.ts +++ b/src/client/mutator.ts @@ -245,9 +245,9 @@ class Mutator { } }) cards.forEach(card => { - if (card.properties.findIndex(o => o.id === propertyId) !== -1) { + if (card.properties[propertyId]) { oldBlocks.push(new Block(card)) - card.properties = card.properties.filter(o => o.id !== propertyId) + delete card.properties[propertyId] changedBlocks.push(card) } }) @@ -366,13 +366,12 @@ class Mutator { // Change the value on all cards that have this property too for (const card of cards) { - card.properties.forEach(property => { - if (property.id === propertyTemplate.id && property.value === oldValue) { - oldBlocks.push(new Block(card)) - property.value = value - changedBlocks.push(card) - } - }) + const propertyValue = card.properties[propertyTemplate.id] + if (propertyValue && propertyValue === oldValue) { + oldBlocks.push(new Block(card)) + card.properties[propertyTemplate.id] = value + changedBlocks.push(card) + } } await undoManager.perform( diff --git a/src/client/octoClient.ts b/src/client/octoClient.ts index 16088876e..85b138498 100644 --- a/src/client/octoClient.ts +++ b/src/client/octoClient.ts @@ -64,9 +64,18 @@ class OctoClient { fixBlocks(blocks: IBlock[]) { for (const block of blocks) { - if (!block.properties) { block.properties = [] } + if (!block.properties) { block.properties = {} } - block.properties = block.properties.filter(property => property && property.id) + 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 + } } } diff --git a/src/client/octoTypes.ts b/src/client/octoTypes.ts index 62672528c..d02c379e5 100644 --- a/src/client/octoTypes.ts +++ b/src/client/octoTypes.ts @@ -1,9 +1,3 @@ -// A property on a bock -interface IProperty { - id: string - value?: string -} - // A block is the fundamental data type interface IBlock { id: string @@ -14,7 +8,7 @@ interface IBlock { url?: string // TODO: Move to properties (_url) icon?: string order: number - properties: IProperty[] // TODO: Change to map + properties: Record createAt: number updateAt: number @@ -30,4 +24,4 @@ interface IPageController { setSearchText(text?: string): void } -export { IProperty, IBlock, IPageController } +export { IBlock, IPageController } diff --git a/src/client/octoUtils.tsx b/src/client/octoUtils.tsx index 8ed264a82..c44f876b8 100644 --- a/src/client/octoUtils.tsx +++ b/src/client/octoUtils.tsx @@ -5,7 +5,7 @@ import { BoardView, ISortOption } from "./boardView" import { Editable } from "./components/editable" import { Menu, MenuOption } from "./menu" import { Mutator } from "./mutator" -import { IBlock, IPageController, IProperty } from "./octoTypes" +import { IBlock, IPageController } from "./octoTypes" import { Utils } from "./utils" class OctoUtils { @@ -78,7 +78,7 @@ class OctoUtils { Menu.shared.showAtElement(e.target as HTMLElement) } - static propertyDisplayValue(block: IBlock, property: IProperty, propertyTemplate: IPropertyTemplate) { + static propertyDisplayValue(block: IBlock, propertyValue: string | undefined, propertyTemplate: IPropertyTemplate) { let displayValue: string switch (propertyTemplate.type) { case "createdTime": @@ -88,7 +88,7 @@ class OctoUtils { displayValue = Utils.displayDateTime(new Date(block.updateAt)) break default: - displayValue = property ? property.value : undefined + displayValue = propertyValue } return displayValue @@ -103,13 +103,13 @@ class OctoUtils { } private static propertyValueElement(mutator: Mutator | undefined, card: IBlock, propertyTemplate: IPropertyTemplate, emptyDisplayValue: string = "Empty"): JSX.Element { - const property = card.properties.find(o => o.id === propertyTemplate.id) - const displayValue = OctoUtils.propertyDisplayValue(card, property, propertyTemplate) + const propertyValue = card.properties[propertyTemplate.id] + const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, propertyTemplate) const finalDisplayValue = displayValue || emptyDisplayValue let propertyColorCssClassName: string - if (property && propertyTemplate.type === "select") { - const cardPropertyValue = propertyTemplate.options.find(o => o.value === property.value) + if (propertyValue && propertyTemplate.type === "select") { + const cardPropertyValue = propertyTemplate.options.find(o => o.value === propertyValue) if (cardPropertyValue) { propertyColorCssClassName = cardPropertyValue.color }