Refactor IBlock property as map
This commit is contained in:
parent
a84ff6901a
commit
216f087dea
10 changed files with 72 additions and 67 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -35,4 +35,4 @@ bin
|
|||
debug
|
||||
__debug_bin
|
||||
files
|
||||
octo.db
|
||||
octo*.db
|
||||
|
|
|
@ -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)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue