1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-06-03 22:27:30 +02:00

npm run fix and replaced tabs with spaces

This commit is contained in:
Chen-I Lim 2020-10-21 15:03:12 -07:00
parent 262f3c043d
commit a8a274ff0f
27 changed files with 999 additions and 932 deletions

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {IBlock} from '../blocks/block' import {IBlock} from '../blocks/block'
import {MutableBlock} from './block' import {MutableBlock} from './block'
type PropertyType = 'text' | 'number' | 'select' | 'multiSelect' | 'date' | 'person' | 'file' | 'checkbox' | 'url' | 'email' | 'phone' | 'createdTime' | 'createdBy' | 'updatedTime' | 'updatedBy' type PropertyType = 'text' | 'number' | 'select' | 'multiSelect' | 'date' | 'person' | 'file' | 'checkbox' | 'url' | 'email' | 'phone' | 'createdTime' | 'createdBy' | 'updatedTime' | 'updatedBy'

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {IBlock} from '../blocks/block' import {IBlock} from '../blocks/block'
import {MutableBlock} from './block' import {MutableBlock} from './block'
interface CommentBlock extends IBlock { type CommentBlock = IBlock
}
class MutableCommentBlock extends MutableBlock { class MutableCommentBlock extends MutableBlock {
constructor(block: any = {}) { constructor(block: any = {}) {

View File

@ -1,5 +1,8 @@
import { IBlock } from "../blocks/block" // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
import { MutableBlock } from "./block" // See LICENSE.txt for license information.
import {IBlock} from '../blocks/block'
import {MutableBlock} from './block'
interface IOrderedBlock extends IBlock { interface IOrderedBlock extends IBlock {
readonly order: number readonly order: number

View File

@ -2,9 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {IOrderedBlock, MutableOrderedBlock} from './orderedBlock' import {IOrderedBlock, MutableOrderedBlock} from './orderedBlock'
interface TextBlock extends IOrderedBlock { type TextBlock = IOrderedBlock
}
class MutableTextBlock extends MutableOrderedBlock { class MutableTextBlock extends MutableOrderedBlock {
constructor(block: any = {}) { constructor(block: any = {}) {

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react' import React from 'react'
import {MutableBlock} from '../blocks/block' import {MutableBlock} from '../blocks/block'
import {IPropertyTemplate} from '../blocks/board' import {IPropertyTemplate} from '../blocks/board'

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react' import React from 'react'
import {BlockIcons} from '../blockIcons' import {BlockIcons} from '../blockIcons'
import {MutableCommentBlock} from '../blocks/commentBlock' import {MutableCommentBlock} from '../blocks/commentBlock'
import {IOrderedBlock} from '../blocks/orderedBlock' import {IOrderedBlock} from '../blocks/orderedBlock'
@ -14,12 +15,11 @@ import { IBlock } from '../blocks/block'
import {OctoUtils} from '../octoUtils' import {OctoUtils} from '../octoUtils'
import {PropertyMenu} from '../propertyMenu' import {PropertyMenu} from '../propertyMenu'
import {Utils} from '../utils' import {Utils} from '../utils'
import Button from './button' import Button from './button'
import {Editable} from './editable' import {Editable} from './editable'
import {MarkdownEditor} from './markdownEditor' import {MarkdownEditor} from './markdownEditor'
type Props = { type Props = {
boardTree: BoardTree boardTree: BoardTree
cardId: string cardId: string
@ -98,7 +98,9 @@ export default class CardDetail extends React.Component<Props, State> {
</div> </div>
</div> </div>
<MarkdownEditor <MarkdownEditor
text={cardText} placeholderText='Edit text...' onChanged={(text) => { text={cardText}
placeholderText='Edit text...'
onChanged={(text) => {
Utils.log(`change text ${block.id}, ${text}`) Utils.log(`change text ${block.id}, ${text}`)
mutator.changeTitle(block, text, 'edit card text') mutator.changeTitle(block, text, 'edit card text')
}} }}
@ -123,7 +125,7 @@ export default class CardDetail extends React.Component<Props, State> {
<img <img
src={url} src={url}
alt={block.title} alt={block.title}
></img> />
</div>) </div>)
} }

View File

@ -51,7 +51,7 @@ class Editable extends React.Component<Props, State> {
this._text = props.text || '' this._text = props.text || ''
} }
componentDidUpdate(prevPros: Props, prevState: State) { componentDidUpdate() {
this._text = this.props.text || '' this._text = this.props.text || ''
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react' import React from 'react'
import {Archiver} from '../archiver' import {Archiver} from '../archiver'
import {Board, MutableBoard} from '../blocks/board' import {Board, MutableBoard} from '../blocks/board'
import {BoardTree} from '../viewModel/boardTree' import {BoardTree} from '../viewModel/boardTree'
@ -10,7 +11,6 @@ import MenuWrapper from '../widgets/menuWrapper'
import {WorkspaceTree} from '../viewModel/workspaceTree' import {WorkspaceTree} from '../viewModel/workspaceTree'
import {BoardView} from '../blocks/boardView' import {BoardView} from '../blocks/boardView'
type Props = { type Props = {
showBoard: (id: string) => void showBoard: (id: string) => void
showView: (id: string, boardId?: string) => void showView: (id: string, boardId?: string) => void
@ -32,11 +32,16 @@ class Sidebar extends React.Component<Props> {
{ {
boards.map((board) => { boards.map((board) => {
const displayTitle = board.title || '(Untitled Board)' const displayTitle = board.title || '(Untitled Board)'
const boardViews = views.filter(view => view.parentId === board.id) const boardViews = views.filter((view) => view.parentId === board.id)
return ( return (
<div key={board.id}> <div key={board.id}>
<div className='octo-sidebar-item octo-hover-container'> <div className='octo-sidebar-item octo-hover-container'>
<div className='octo-sidebar-title' onClick={() => { this.boardClicked(board) }}> <div
className='octo-sidebar-title'
onClick={() => {
this.boardClicked(board)
}}
>
{board.icon ? `${board.icon} ${displayTitle}` : displayTitle} {board.icon ? `${board.icon} ${displayTitle}` : displayTitle}
</div> </div>
<div className='octo-spacer'/> <div className='octo-spacer'/>
@ -63,12 +68,20 @@ class Sidebar extends React.Component<Props> {
</Menu> </Menu>
</MenuWrapper> </MenuWrapper>
</div> </div>
{boardViews.map(view => { {boardViews.map((view) => {
return <div key={view.id} className='octo-sidebar-item subitem octo-hover-container'> return (<div
<div className='octo-sidebar-title' onClick={() => { this.viewClicked(board, view) }}> key={view.id}
className='octo-sidebar-item subitem octo-hover-container'
>
<div
className='octo-sidebar-title'
onClick={() => {
this.viewClicked(board, view)
}}
>
{view.title || '(Untitled View)'} {view.title || '(Untitled View)'}
</div> </div>
</div> </div>)
})} })}
</div> </div>
) )

View File

@ -97,7 +97,7 @@ class Mutator {
} }
async changeIcon(block: Card | Board, icon: string, description = 'change icon') { async changeIcon(block: Card | Board, icon: string, description = 'change icon') {
var newBlock: IBlock let newBlock: IBlock
switch (block.type) { switch (block.type) {
case 'card': { case 'card': {
const card = new MutableCard(block) const card = new MutableCard(block)
@ -265,7 +265,7 @@ class Mutator {
Utils.assert(board.cardProperties.includes(template)) Utils.assert(board.cardProperties.includes(template))
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === template.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === template.id)
newTemplate.options.push(option) newTemplate.options.push(option)
await this.updateBlock(newBoard, board, description) await this.updateBlock(newBoard, board, description)
@ -275,8 +275,8 @@ class Mutator {
const {board} = boardTree const {board} = boardTree
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === template.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === template.id)
newTemplate.options = newTemplate.options.filter(o => o.value !== option.value) newTemplate.options = newTemplate.options.filter((o) => o.value !== option.value)
await this.updateBlock(newBoard, board, 'delete option') await this.updateBlock(newBoard, board, 'delete option')
} }
@ -286,7 +286,7 @@ class Mutator {
Utils.log(`srcIndex: ${srcIndex}, destIndex: ${destIndex}`) Utils.log(`srcIndex: ${srcIndex}, destIndex: ${destIndex}`)
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === template.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === template.id)
newTemplate.options.splice(destIndex, 0, newTemplate.options.splice(srcIndex, 1)[0]) newTemplate.options.splice(destIndex, 0, newTemplate.options.splice(srcIndex, 1)[0])
await this.updateBlock(newBoard, board, 'reorder options') await this.updateBlock(newBoard, board, 'reorder options')
@ -299,8 +299,8 @@ class Mutator {
const oldBlocks: IBlock[] = [board] const oldBlocks: IBlock[] = [board]
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === propertyTemplate.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === propertyTemplate.id)
const newOption = newTemplate.options.find(o => o.value === oldValue) const newOption = newTemplate.options.find((o) => o.value === oldValue)
newOption.value = value newOption.value = value
const changedBlocks: IBlock[] = [newBoard] const changedBlocks: IBlock[] = [newBoard]
@ -323,8 +323,8 @@ class Mutator {
async changePropertyOptionColor(board: Board, template: IPropertyTemplate, option: IPropertyOption, color: string) { async changePropertyOptionColor(board: Board, template: IPropertyTemplate, option: IPropertyOption, color: string) {
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === template.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === template.id)
const newOption = newTemplate.options.find(o => o.value === option.value) const newOption = newTemplate.options.find((o) => o.value === option.value)
newOption.color = color newOption.color = color
await this.updateBlock(newBoard, board, 'change option color') await this.updateBlock(newBoard, board, 'change option color')
} }
@ -337,7 +337,7 @@ class Mutator {
async changePropertyType(board: Board, propertyTemplate: IPropertyTemplate, type: PropertyType) { async changePropertyType(board: Board, propertyTemplate: IPropertyTemplate, type: PropertyType) {
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const newTemplate = newBoard.cardProperties.find(o => o.id === propertyTemplate.id) const newTemplate = newBoard.cardProperties.find((o) => o.id === propertyTemplate.id)
newTemplate.type = type newTemplate.type = type
await this.updateBlock(newBoard, board, 'change property type') await this.updateBlock(newBoard, board, 'change property type')
} }
@ -356,7 +356,7 @@ class Mutator {
await this.updateBlock(newView, view, 'filter') await this.updateBlock(newView, view, 'filter')
} }
async changeViewVisibleProperties(view: BoardView, visiblePropertyIds: string[], description: string = 'show / hide property') { async changeViewVisibleProperties(view: BoardView, visiblePropertyIds: string[], description = 'show / hide property') {
const newView = new MutableBoardView(view) const newView = new MutableBoardView(view)
newView.visiblePropertyIds = visiblePropertyIds newView.visiblePropertyIds = visiblePropertyIds
await this.updateBlock(newView, view, description) await this.updateBlock(newView, view, description)

View File

@ -49,7 +49,7 @@ class OctoListener {
this.ws = ws this.ws = ws
ws.onopen = () => { ws.onopen = () => {
Utils.log(`OctoListener webSocket opened.`) Utils.log('OctoListener webSocket opened.')
this.addBlocks(blockIds) this.addBlocks(blockIds)
this.isInitialized = true this.isInitialized = true
} }
@ -73,7 +73,7 @@ class OctoListener {
ws.onmessage = (e) => { ws.onmessage = (e) => {
Utils.log(`OctoListener websocket onmessage. data: ${e.data}`) Utils.log(`OctoListener websocket onmessage. data: ${e.data}`)
if (ws !== this.ws) { if (ws !== this.ws) {
Utils.log(`Ignoring closed ws`) Utils.log('Ignoring closed ws')
return return
} }
@ -115,13 +115,13 @@ class OctoListener {
addBlocks(blockIds: string[]): void { addBlocks(blockIds: string[]): void {
if (!this.isOpen) { if (!this.isOpen) {
Utils.assertFailure(`OctoListener.addBlocks: ws is not open`) Utils.assertFailure('OctoListener.addBlocks: ws is not open')
return return
} }
const command: WSCommand = { const command: WSCommand = {
action: 'ADD', action: 'ADD',
blockIds blockIds,
} }
this.ws.send(JSON.stringify(command)) this.ws.send(JSON.stringify(command))
@ -130,13 +130,13 @@ class OctoListener {
removeBlocks(blockIds: string[]): void { removeBlocks(blockIds: string[]): void {
if (!this.isOpen) { if (!this.isOpen) {
Utils.assertFailure(`OctoListener.removeBlocks: ws is not open`) Utils.assertFailure('OctoListener.removeBlocks: ws is not open')
return return
} }
const command: WSCommand = { const command: WSCommand = {
action: 'REMOVE', action: 'REMOVE',
blockIds blockIds,
} }
this.ws.send(JSON.stringify(command)) this.ws.send(JSON.stringify(command))

View File

@ -168,7 +168,7 @@ export default class BoardPage extends React.Component<Props, State> {
Utils.log(`sync start: ${boardId}`) Utils.log(`sync start: ${boardId}`)
await workspaceTree.sync() await workspaceTree.sync()
const boardIds = workspaceTree.boards.map(o => o.id) const boardIds = workspaceTree.boards.map((o) => o.id)
this.workspaceListener.open(boardIds, async (blockId) => { this.workspaceListener.open(boardIds, async (blockId) => {
Utils.log(`workspaceListener.onChanged: ${blockId}`) Utils.log(`workspaceListener.onChanged: ${blockId}`)
this.sync() this.sync()

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react' import React from 'react'
import {Archiver} from '../archiver' import {Archiver} from '../archiver'
import {MutableBoard} from '../blocks/board' import {MutableBoard} from '../blocks/board'
import Button from '../components/button' import Button from '../components/button'
@ -8,7 +9,6 @@ import octoClient from '../octoClient'
import {IBlock} from '../blocks/block' import {IBlock} from '../blocks/block'
import {Utils} from '../utils' import {Utils} from '../utils'
type Props = {} type Props = {}
type State = { type State = {

View File

@ -50,9 +50,9 @@ class MutableBoardTree implements BoardTree {
} }
private rebuild(blocks: IBlock[]) { private rebuild(blocks: IBlock[]) {
this.board = blocks.find(block => block.type === "board") as Board this.board = blocks.find((block) => block.type === 'board') as Board
this.views = blocks.filter(block => block.type === "view") as MutableBoardView[] this.views = blocks.filter((block) => block.type === 'view') as MutableBoardView[]
this.allCards = blocks.filter(block => block.type === "card") as Card[] this.allCards = blocks.filter((block) => block.type === 'card') as Card[]
this.cards = [] this.cards = []
this.ensureMinimumSchema() this.ensureMinimumSchema()
@ -64,14 +64,14 @@ class MutableBoardTree implements BoardTree {
let didChange = false let didChange = false
// At least one select property // At least one select property
const selectProperties = board.cardProperties.find(o => o.type === "select") const selectProperties = board.cardProperties.find((o) => o.type === 'select')
if (!selectProperties) { if (!selectProperties) {
const newBoard = new MutableBoard(board) const newBoard = new MutableBoard(board)
const property: IPropertyTemplate = { const property: IPropertyTemplate = {
id: Utils.createGuid(), id: Utils.createGuid(),
name: "Status", name: 'Status',
type: "select", type: 'select',
options: [] options: [],
} }
newBoard.cardProperties.push(property) newBoard.cardProperties.push(property)
this.board = newBoard this.board = newBoard
@ -82,7 +82,7 @@ class MutableBoardTree implements BoardTree {
if (this.views.length < 1) { if (this.views.length < 1) {
const view = new MutableBoardView() const view = new MutableBoardView()
view.parentId = board.id view.parentId = board.id
view.groupById = board.cardProperties.find(o => o.type === "select")?.id view.groupById = board.cardProperties.find((o) => o.type === 'select')?.id
this.views.push(view) this.views.push(view)
didChange = true didChange = true
} }
@ -91,15 +91,15 @@ class MutableBoardTree implements BoardTree {
} }
setActiveView(viewId: string) { setActiveView(viewId: string) {
this.activeView = this.views.find(o => o.id === viewId) this.activeView = this.views.find((o) => o.id === viewId)
if (!this.activeView) { if (!this.activeView) {
Utils.logError(`Cannot find BoardView: ${viewId}`) Utils.logError(`Cannot find BoardView: ${viewId}`)
this.activeView = this.views[0] this.activeView = this.views[0]
} }
// Fix missing group by (e.g. for new views) // Fix missing group by (e.g. for new views)
if (this.activeView.viewType === "board" && !this.activeView.groupById) { if (this.activeView.viewType === 'board' && !this.activeView.groupById) {
this.activeView.groupById = this.board.cardProperties.find(o => o.type === "select")?.id this.activeView.groupById = this.board.cardProperties.find((o) => o.type === 'select')?.id
} }
this.applyFilterSortAndGroup() this.applyFilterSortAndGroup()
} }
@ -126,7 +126,7 @@ class MutableBoardTree implements BoardTree {
if (this.activeView.groupById) { if (this.activeView.groupById) {
this.setGroupByProperty(this.activeView.groupById) this.setGroupByProperty(this.activeView.groupById)
} else { } else {
Utils.assert(this.activeView.viewType !== "board") Utils.assert(this.activeView.viewType !== 'board')
} }
Utils.assert(this.cards !== undefined) Utils.assert(this.cards !== undefined)
@ -134,21 +134,26 @@ class MutableBoardTree implements BoardTree {
private searchFilterCards(cards: Card[]): Card[] { private searchFilterCards(cards: Card[]): Card[] {
const searchText = this.searchText?.toLocaleLowerCase() const searchText = this.searchText?.toLocaleLowerCase()
if (!searchText) { return cards.slice() } if (!searchText) {
return cards.slice()
}
return cards.filter(card => { return cards.filter((card) => {
if (card.title?.toLocaleLowerCase().indexOf(searchText) !== -1) { return true } if (card.title?.toLocaleLowerCase().indexOf(searchText) !== -1) {
return true
}
}) })
} }
private setGroupByProperty(propertyId: string) { private setGroupByProperty(propertyId: string) {
const {board} = this const {board} = this
let property = board.cardProperties.find(o => o.id === propertyId) let property = board.cardProperties.find((o) => o.id === propertyId)
// TODO: Handle multi-select // TODO: Handle multi-select
if (!property || property.type !== "select") { if (!property || property.type !== 'select') {
Utils.logError(`this.view.groupById card property not found: ${propertyId}`) Utils.logError(`this.view.groupById card property not found: ${propertyId}`)
property = board.cardProperties.find(o => o.type === "select") property = board.cardProperties.find((o) => o.type === 'select')
Utils.assertValue(property) Utils.assertValue(property)
} }
this.groupByProperty = property this.groupByProperty = property
@ -161,22 +166,22 @@ class MutableBoardTree implements BoardTree {
const groupByPropertyId = this.groupByProperty.id const groupByPropertyId = this.groupByProperty.id
this.emptyGroupCards = this.cards.filter(o => { this.emptyGroupCards = this.cards.filter((o) => {
const propertyValue = o.properties[groupByPropertyId] const propertyValue = o.properties[groupByPropertyId]
return !propertyValue || !this.groupByProperty.options.find(option => option.value === propertyValue) return !propertyValue || !this.groupByProperty.options.find((option) => option.value === propertyValue)
}) })
const propertyOptions = this.groupByProperty.options || [] const propertyOptions = this.groupByProperty.options || []
for (const option of propertyOptions) { for (const option of propertyOptions) {
const cards = this.cards const cards = this.cards.
.filter(o => { filter((o) => {
const propertyValue = o.properties[groupByPropertyId] const propertyValue = o.properties[groupByPropertyId]
return propertyValue && propertyValue === option.value return propertyValue && propertyValue === option.value
}) })
const group: Group = { const group: Group = {
option, option,
cards cards,
} }
this.groups.push(group) this.groups.push(group)
@ -186,50 +191,68 @@ class MutableBoardTree implements BoardTree {
private filterCards(cards: Card[]): Card[] { private filterCards(cards: Card[]): Card[] {
const {board} = this const {board} = this
const filterGroup = this.activeView?.filter const filterGroup = this.activeView?.filter
if (!filterGroup) { return cards.slice() } if (!filterGroup) {
return cards.slice()
}
return CardFilter.applyFilterGroup(filterGroup, board.cardProperties, cards) return CardFilter.applyFilterGroup(filterGroup, board.cardProperties, cards)
} }
private sortCards(cards: Card[]): Card[] { private sortCards(cards: Card[]): Card[] {
if (!this.activeView) { Utils.assertFailure(); return cards } if (!this.activeView) {
Utils.assertFailure(); return cards
}
const {board} = this const {board} = this
const {sortOptions} = this.activeView const {sortOptions} = this.activeView
let sortedCards: Card[] = [] let sortedCards: Card[] = []
if (sortOptions.length < 1) { if (sortOptions.length < 1) {
Utils.log(`Default sort`) Utils.log('Default sort')
sortedCards = cards.sort((a, b) => { sortedCards = cards.sort((a, b) => {
const aValue = a.title || "" const aValue = a.title || ''
const bValue = b.title || "" const bValue = b.title || ''
// Always put empty values at the bottom // Always put empty values at the bottom
if (aValue && !bValue) { return -1 } if (aValue && !bValue) {
if (bValue && !aValue) { return 1 } return -1
if (!aValue && !bValue) { return a.createAt - b.createAt } }
if (bValue && !aValue) {
return 1
}
if (!aValue && !bValue) {
return a.createAt - b.createAt
}
return a.createAt - b.createAt return a.createAt - b.createAt
}) })
} else { } else {
sortOptions.forEach(sortOption => { sortOptions.forEach((sortOption) => {
if (sortOption.propertyId === "__name") { if (sortOption.propertyId === '__name') {
Utils.log(`Sort by name`) Utils.log('Sort by name')
sortedCards = cards.sort((a, b) => { sortedCards = cards.sort((a, b) => {
const aValue = a.title || "" const aValue = a.title || ''
const bValue = b.title || "" const bValue = b.title || ''
// Always put empty values at the bottom, newest last // Always put empty values at the bottom, newest last
if (aValue && !bValue) { return -1 } if (aValue && !bValue) {
if (bValue && !aValue) { return 1 } return -1
if (!aValue && !bValue) { return a.createAt - b.createAt } }
if (bValue && !aValue) {
return 1
}
if (!aValue && !bValue) {
return a.createAt - b.createAt
}
let result = aValue.localeCompare(bValue) let result = aValue.localeCompare(bValue)
if (sortOption.reversed) { result = -result } if (sortOption.reversed) {
result = -result
}
return result return result
}) })
} else { } else {
const sortPropertyId = sortOption.propertyId const sortPropertyId = sortOption.propertyId
const template = board.cardProperties.find(o => o.id === sortPropertyId) const template = board.cardProperties.find((o) => o.id === sortPropertyId)
if (!template) { if (!template) {
Utils.logError(`Missing template for property id: ${sortPropertyId}`) Utils.logError(`Missing template for property id: ${sortPropertyId}`)
return cards.slice() return cards.slice()
@ -237,47 +260,73 @@ class MutableBoardTree implements BoardTree {
Utils.log(`Sort by ${template?.name}`) Utils.log(`Sort by ${template?.name}`)
sortedCards = cards.sort((a, b) => { sortedCards = cards.sort((a, b) => {
// Always put cards with no titles at the bottom // Always put cards with no titles at the bottom
if (a.title && !b.title) { return -1 } if (a.title && !b.title) {
if (b.title && !a.title) { return 1 } return -1
if (!a.title && !b.title) { return a.createAt - b.createAt } }
if (b.title && !a.title) {
return 1
}
if (!a.title && !b.title) {
return a.createAt - b.createAt
}
const aValue = a.properties[sortPropertyId] || "" const aValue = a.properties[sortPropertyId] || ''
const bValue = b.properties[sortPropertyId] || "" const bValue = b.properties[sortPropertyId] || ''
let result = 0 let result = 0
if (template.type === "select") { if (template.type === 'select') {
// Always put empty values at the bottom // Always put empty values at the bottom
if (aValue && !bValue) { return -1 } if (aValue && !bValue) {
if (bValue && !aValue) { return 1 } return -1
if (!aValue && !bValue) { return a.createAt - b.createAt } }
if (bValue && !aValue) {
return 1
}
if (!aValue && !bValue) {
return a.createAt - b.createAt
}
// Sort by the option order (not alphabetically by value) // Sort by the option order (not alphabetically by value)
const aOrder = template.options.findIndex(o => o.value === aValue) const aOrder = template.options.findIndex((o) => o.value === aValue)
const bOrder = template.options.findIndex(o => o.value === bValue) const bOrder = template.options.findIndex((o) => o.value === bValue)
result = aOrder - bOrder result = aOrder - bOrder
} else if (template.type === "number" || template.type === "date") { } else if (template.type === 'number' || template.type === 'date') {
// Always put empty values at the bottom // Always put empty values at the bottom
if (aValue && !bValue) { return -1 } if (aValue && !bValue) {
if (bValue && !aValue) { return 1 } return -1
if (!aValue && !bValue) { return a.createAt - b.createAt } }
if (bValue && !aValue) {
return 1
}
if (!aValue && !bValue) {
return a.createAt - b.createAt
}
result = Number(aValue) - Number(bValue) result = Number(aValue) - Number(bValue)
} else if (template.type === "createdTime") { } else if (template.type === 'createdTime') {
result = a.createAt - b.createAt result = a.createAt - b.createAt
} else if (template.type === "updatedTime") { } else if (template.type === 'updatedTime') {
result = a.updateAt - b.updateAt result = a.updateAt - b.updateAt
} else { } else {
// Text-based sort // Text-based sort
// Always put empty values at the bottom // Always put empty values at the bottom
if (aValue && !bValue) { return -1 } if (aValue && !bValue) {
if (bValue && !aValue) { return 1 } return -1
if (!aValue && !bValue) { return a.createAt - b.createAt } }
if (bValue && !aValue) {
return 1
}
if (!aValue && !bValue) {
return a.createAt - b.createAt
}
result = aValue.localeCompare(bValue) result = aValue.localeCompare(bValue)
} }
if (sortOption.reversed) { result = -result } if (sortOption.reversed) {
result = -result
}
return result return result
}) })
} }

View File

@ -26,13 +26,13 @@ class MutableCardTree implements CardTree {
} }
private rebuild(blocks: IBlock[]) { private rebuild(blocks: IBlock[]) {
this.card = blocks.find(o => o.id === this.cardId) as Card this.card = blocks.find((o) => o.id === this.cardId) as Card
this.comments = blocks this.comments = blocks.
.filter(block => block.type === "comment") filter((block) => block.type === 'comment').
.sort((a, b) => a.createAt - b.createAt) sort((a, b) => a.createAt - b.createAt)
const contentBlocks = blocks.filter(block => block.type === "text" || block.type === "image") as IOrderedBlock[] const contentBlocks = blocks.filter((block) => block.type === 'text' || block.type === 'image') as IOrderedBlock[]
this.contents = contentBlocks.sort((a, b) => a.order - b.order) this.contents = contentBlocks.sort((a, b) => a.order - b.order)
} }
} }

View File

@ -16,17 +16,17 @@ class MutableWorkspaceTree {
views: BoardView[] = [] views: BoardView[] = []
async sync() { async sync() {
const boards = await octoClient.getBlocksWithType("board") const boards = await octoClient.getBlocksWithType('board')
const views = await octoClient.getBlocksWithType("view") const views = await octoClient.getBlocksWithType('view')
this.rebuild( this.rebuild(
OctoUtils.hydrateBlocks(boards), OctoUtils.hydrateBlocks(boards),
OctoUtils.hydrateBlocks(views) OctoUtils.hydrateBlocks(views),
) )
} }
private rebuild(boards: IBlock[], views: IBlock[]) { private rebuild(boards: IBlock[], views: IBlock[]) {
this.boards = boards.filter(block => block.type === "board") as Board[] this.boards = boards.filter((block) => block.type === 'board') as Board[]
this.views = views.filter(block => block.type === "view") as BoardView[] this.views = views.filter((block) => block.type === 'view') as BoardView[]
} }
} }