Refactor IBlock property as map

This commit is contained in:
Chen-I Lim 2020-10-13 17:00:16 -07:00
parent a84ff6901a
commit 216f087dea
10 changed files with 72 additions and 67 deletions

2
.gitignore vendored
View file

@ -35,4 +35,4 @@ bin
debug
__debug_bin
files
octo.db
octo*.db

View file

@ -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<string, string> = {}
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)
// }
}
}

View file

@ -112,11 +112,6 @@ class BoardPage implements IPageController {
Utils.getElementById("header")
)
ReactDOM.render(
<PageHeader />,
Utils.getElementById("header")
)
if (board) {
Utils.setFavicon(board.icon)
document.title = `OCTO - ${board.title} | ${activeView.title}`

View file

@ -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

View file

@ -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<string, any> {
// 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": {

View file

@ -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

View file

@ -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(

View file

@ -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<string, string> = {}
for (const property of block.properties) {
if (property.id) {
properties[property.id] = property.value
}
}
block.properties = properties
}
}
}

View file

@ -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<string, string>
createAt: number
updateAt: number
@ -30,4 +24,4 @@ interface IPageController {
setSearchText(text?: string): void
}
export { IProperty, IBlock, IPageController }
export { IBlock, IPageController }

View file

@ -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
}