1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-02-13 19:42:12 +02:00

Ran npm run fix

This commit is contained in:
Chen-I Lim 2020-10-20 12:52:56 -07:00
parent 36a104f45b
commit 9255bd4ded
51 changed files with 407 additions and 406 deletions

View File

@ -69,6 +69,7 @@
"rules": {
"import/no-unresolved": 0, // ts handles this better
"camelcase": 0,
"semi": "off",
"@typescript-eslint/naming-convention": [
2,
{

View File

@ -1,16 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from 'react-router-dom';
} from 'react-router-dom'
import LoginPage from './pages/loginPage';
import BoardPage from './pages/boardPage';
import LoginPage from './pages/loginPage'
import BoardPage from './pages/boardPage'
export default function App() {
return (

View File

@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {BoardTree} from './boardTree';
import mutator from './mutator';
import {IBlock} from './octoTypes';
import {Utils} from './utils';
import {BoardTree} from './boardTree'
import mutator from './mutator'
import {IBlock} from './octoTypes'
import {Utils} from './utils'
interface Archive {
version: number
@ -40,7 +40,7 @@ class Archiver {
const date = new Date()
const filename = `archive-${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}.octo`
const link = document.createElement('a')
link.style.display = 'none';
link.style.display = 'none'
// const file = new Blob([content], { type: "text/json" })
// link.href = URL.createObjectURL(file)
@ -55,8 +55,8 @@ class Archiver {
static importFullArchive(onComplete?: () => void): void {
const input = document.createElement('input')
input.type = 'file';
input.accept = '.octo';
input.type = 'file'
input.accept = '.octo'
input.onchange = async () => {
const file = input.files[0]
const contents = await (new Response(file)).text()
@ -72,16 +72,16 @@ class Archiver {
return false
}
return true
});
})
Utils.log(`Import ${filteredBlocks.length} filtered blocks.`)
await mutator.importFullArchive(filteredBlocks)
Utils.log('Import completed')
onComplete?.()
};
}
input.style.display = 'none';
input.style.display = 'none'
document.body.appendChild(input)
input.click()

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {randomEmojiList} from './emojiList';
import {randomEmojiList} from './emojiList'
class BlockIcons {
static readonly shared = new BlockIcons()

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IBlock} from '../octoTypes';
import {Utils} from '../utils';
import {IBlock} from '../octoTypes'
import {Utils} from '../utils'
class Block implements IBlock {
id: string = Utils.createGuid()

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './block';
import {Block} from './block'
type PropertyType = 'text' | 'number' | 'select' | 'multiSelect' | 'date' | 'person' | 'file' | 'checkbox' | 'url' | 'email' | 'phone' | 'createdTime' | 'createdBy' | 'updatedTime' | 'updatedBy'
@ -34,7 +34,7 @@ class Board extends Block {
constructor(block: any = {}) {
super(block)
this.type = 'board';
this.type = 'board'
if (block.fields?.cardProperties) {
// Deep clone of card properties and their options
@ -45,7 +45,7 @@ class Board extends Block {
type: o.type,
options: o.options ? o.options.map((option) => ({...option})) : [],
}
});
})
} else {
this.cardProperties = []
}

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {FilterGroup} from '../filterGroup';
import {FilterGroup} from '../filterGroup'
import {Block} from './block';
import {Block} from './block'
type IViewType = 'board' | 'table' | 'calendar' | 'list' | 'gallery'
type ISortOption = { propertyId: '__name' | string, reversed: boolean }
@ -46,7 +46,7 @@ class BoardView extends Block {
constructor(block: any = {}) {
super(block)
this.type = 'view';
this.type = 'view'
this.sortOptions = block.fields?.sortOptions?.map((o: ISortOption) => ({...o})) || [] // Deep clone
this.visiblePropertyIds = block.fields?.visiblePropertyIds?.slice() || []
@ -54,7 +54,7 @@ class BoardView extends Block {
// TODO: Remove this fixup code
if (block.schema !== 1) {
this.viewType = block.viewType || 'board';
this.viewType = block.viewType || 'board'
this.groupById = block.groupById
this.sortOptions = block.sortOptions ? block.sortOptions.map((o: ISortOption) => ({...o})) : [] // Deep clone
this.visiblePropertyIds = block.visiblePropertyIds ? block.visiblePropertyIds.slice() : []
@ -62,7 +62,7 @@ class BoardView extends Block {
}
if (!this.viewType) {
this.viewType = 'board';
this.viewType = 'board'
}
}
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './block';
import {Block} from './block'
class Card extends Block {
get icon(): string {
@ -19,7 +19,7 @@ class Card extends Block {
constructor(block: any = {}) {
super(block)
this.type = 'card';
this.type = 'card'
this.properties = {...(block.fields?.properties || {})}
}

View File

@ -1,11 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './block';
import {Block} from './block'
class CommentBlock extends Block {
constructor(block: any = {}) {
super(block)
this.type = 'comment';
this.type = 'comment'
}
}

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IOrderedBlock} from '../octoTypes';
import {IOrderedBlock} from '../octoTypes'
import {Block} from './block';
import {Block} from './block'
class ImageBlock extends Block implements IOrderedBlock {
get order(): number {
@ -21,7 +21,7 @@ class ImageBlock extends Block implements IOrderedBlock {
constructor(block: any = {}) {
super(block)
this.type = 'image';
this.type = 'image'
}
}

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IOrderedBlock} from '../octoTypes';
import {IOrderedBlock} from '../octoTypes'
import {Block} from './block';
import {Block} from './block'
class TextBlock extends Block implements IOrderedBlock {
get order(): number {
@ -14,7 +14,7 @@ class TextBlock extends Block implements IOrderedBlock {
constructor(block: any = {}) {
super(block)
this.type = 'text';
this.type = 'text'
}
}

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './blocks/block';
import {Board, IPropertyOption, IPropertyTemplate} from './blocks/board';
import {BoardView} from './blocks/boardView';
import {Card} from './blocks/card';
import {CardFilter} from './cardFilter';
import octoClient from './octoClient';
import {IBlock} from './octoTypes';
import {OctoUtils} from './octoUtils';
import {Utils} from './utils';
import {Block} from './blocks/block'
import {Board, IPropertyOption, IPropertyTemplate} from './blocks/board'
import {BoardView} from './blocks/boardView'
import {Card} from './blocks/card'
import {CardFilter} from './cardFilter'
import octoClient from './octoClient'
import {IBlock} from './octoTypes'
import {OctoUtils} from './octoUtils'
import {Utils} from './utils'
type Group = { option: IPropertyOption, cards: Card[] }
@ -154,7 +154,7 @@ class BoardTree {
this.emptyGroupCards = this.cards.filter((o) => {
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) {
@ -162,7 +162,7 @@ class BoardTree {
filter((o) => {
const propertyValue = o.properties[groupByPropertyId]
return propertyValue && propertyValue === option.value
});
})
const group: Group = {
option,
@ -194,8 +194,8 @@ class BoardTree {
if (sortOptions.length < 1) {
Utils.log('Default sort')
sortedCards = cards.sort((a, b) => {
const aValue = a.title || '';
const bValue = b.title || '';
const aValue = a.title || ''
const bValue = b.title || ''
// Always put empty values at the bottom
if (aValue && !bValue) {
@ -209,14 +209,14 @@ class BoardTree {
}
return a.createAt - b.createAt
});
})
} else {
sortOptions.forEach((sortOption) => {
if (sortOption.propertyId === '__name') {
Utils.log('Sort by name')
sortedCards = cards.sort((a, b) => {
const aValue = a.title || '';
const bValue = b.title || '';
const aValue = a.title || ''
const bValue = b.title || ''
// Always put empty values at the bottom, newest last
if (aValue && !bValue) {
@ -234,7 +234,7 @@ class BoardTree {
result = -result
}
return result
});
})
} else {
const sortPropertyId = sortOption.propertyId
const template = board.cardProperties.find((o) => o.id === sortPropertyId)
@ -255,8 +255,8 @@ class BoardTree {
return a.createAt - b.createAt
}
const aValue = a.properties[sortPropertyId] || '';
const bValue = b.properties[sortPropertyId] || '';
const aValue = a.properties[sortPropertyId] || ''
const bValue = b.properties[sortPropertyId] || ''
let result = 0
if (template.type === 'select') {
// Always put empty values at the bottom
@ -313,7 +313,7 @@ class BoardTree {
result = -result
}
return result
});
})
}
})
}

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IPropertyTemplate} from './blocks/board';
import {Card} from './blocks/card';
import {FilterClause} from './filterClause';
import {FilterGroup} from './filterGroup';
import {Utils} from './utils';
import {IPropertyTemplate} from './blocks/board'
import {Card} from './blocks/card'
import {FilterClause} from './filterClause'
import {FilterGroup} from './filterGroup'
import {Utils} from './utils'
class CardFilter {
static applyFilterGroup(filterGroup: FilterGroup, templates: IPropertyTemplate[], cards: Card[]): Card[] {
@ -89,7 +89,7 @@ class CardFilter {
filters.forEach((filterClause) => {
const p = this.propertyThatMeetsFilterClause(filterClause as FilterClause, templates)
result[p.id] = p.value
});
})
return result
}

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './blocks/block';
import {Card} from './blocks/card';
import octoClient from './octoClient';
import {IBlock, IOrderedBlock} from './octoTypes';
import {OctoUtils} from './octoUtils';
import {Block} from './blocks/block'
import {Card} from './blocks/card'
import octoClient from './octoClient'
import {IBlock, IOrderedBlock} from './octoTypes'
import {OctoUtils} from './octoUtils'
class CardTree {
card: Card

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Block} from '../blocks/block';
import {IPropertyTemplate} from '../blocks/board';
import {Card} from '../blocks/card';
import {Menu} from '../menu';
import mutator from '../mutator';
import {OctoUtils} from '../octoUtils';
import {Utils} from '../utils';
import {Block} from '../blocks/block'
import {IPropertyTemplate} from '../blocks/board'
import {Card} from '../blocks/card'
import {Menu} from '../menu'
import mutator from '../mutator'
import {OctoUtils} from '../octoUtils'
import {Utils} from '../utils'
type BoardCardProps = {
card: Card
@ -49,7 +49,7 @@ class BoardCard extends React.Component<BoardCardProps, BoardCardState> {
optionsButtonRef.current.style.display = null
}}
onMouseLeave={() => {
optionsButtonRef.current.style.display = 'none';
optionsButtonRef.current.style.display = 'none'
}}
>
<div
@ -86,12 +86,12 @@ class BoardCard extends React.Component<BoardCardProps, BoardCardState> {
switch (id) {
case 'delete': {
mutator.deleteBlock(card, 'delete card')
break;
break
}
case 'duplicate': {
const newCard = Block.duplicate(card)
mutator.insertBlock(newCard, 'duplicate card')
break;
break
}
default: {
Utils.assertFailure(`Unhandled menu id: ${id}`)

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
type Props = {
onDrop?: (e: React.DragEvent<HTMLDivElement>) => void

View File

@ -1,28 +1,28 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Archiver} from '../archiver';
import {BlockIcons} from '../blockIcons';
import {IPropertyOption} from '../blocks/board';
import {Card} from '../blocks/card';
import {BoardTree} from '../boardTree';
import {CardFilter} from '../cardFilter';
import ViewMenu from '../components/viewMenu';
import {Constants} from '../constants';
import {Menu as OldMenu} from '../menu';
import mutator from '../mutator';
import {OctoUtils} from '../octoUtils';
import {Utils} from '../utils';
import Menu from '../widgets/menu';
import MenuWrapper from '../widgets/menuWrapper';
import {Archiver} from '../archiver'
import {BlockIcons} from '../blockIcons'
import {IPropertyOption} from '../blocks/board'
import {Card} from '../blocks/card'
import {BoardTree} from '../boardTree'
import {CardFilter} from '../cardFilter'
import ViewMenu from '../components/viewMenu'
import {Constants} from '../constants'
import {Menu as OldMenu} from '../menu'
import mutator from '../mutator'
import {OctoUtils} from '../octoUtils'
import {Utils} from '../utils'
import Menu from '../widgets/menu'
import MenuWrapper from '../widgets/menuWrapper'
import {BoardCard} from './boardCard';
import {BoardColumn} from './boardColumn';
import Button from './button';
import {CardDialog} from './cardDialog';
import {Editable} from './editable';
import RootPortal from './rootPortal';
import {BoardCard} from './boardCard'
import {BoardColumn} from './boardColumn'
import Button from './button'
import {CardDialog} from './cardDialog'
import {Editable} from './editable'
import RootPortal from './rootPortal'
type Props = {
boardTree?: BoardTree
@ -404,7 +404,7 @@ class BoardComponent extends React.Component<Props, State> {
this.setState({shownCard: card})
}, async () => {
this.setState({shownCard: undefined})
});
})
}
async propertyNameChanged(option: IPropertyOption, text: string) {
@ -431,19 +431,19 @@ class BoardComponent extends React.Component<Props, State> {
switch (id) {
case 'exportBoardArchive': {
Archiver.exportBoardTree(boardTree)
break;
break
}
case 'testAdd100Cards': {
this.testAddCards(100)
break;
break
}
case 'testAdd1000Cards': {
this.testAddCards(1000)
break;
break
}
case 'testRandomizeIcons': {
this.testRandomizeIcons()
break;
break
}
}
}
@ -489,7 +489,7 @@ class BoardComponent extends React.Component<Props, State> {
OldMenu.shared.options = selectProperties.map((o) => {
const isVisible = activeView.visiblePropertyIds.includes(o.id)
return {id: o.id, name: o.name, type: 'switch', isOn: isVisible}
});
})
OldMenu.shared.onMenuToggled = async (id: string, isOn: boolean) => {
const property = selectProperties.find((o) => o.id === id)
@ -503,7 +503,7 @@ class BoardComponent extends React.Component<Props, State> {
newVisiblePropertyIds = [...activeView.visiblePropertyIds, id]
}
await mutator.changeViewVisibleProperties(activeView, newVisiblePropertyIds)
};
}
OldMenu.shared.showAtElement(e.target as HTMLElement)
}
@ -513,14 +513,14 @@ class BoardComponent extends React.Component<Props, State> {
const selectProperties = boardTree.board.cardProperties.filter((o) => o.type === 'select')
OldMenu.shared.options = selectProperties.map((o) => {
return {id: o.id, name: o.name}
});
})
OldMenu.shared.onMenuClicked = async (command: string) => {
if (boardTree.activeView.groupById === command) {
return
}
await mutator.changeViewGroupById(boardTree.activeView, command)
};
}
OldMenu.shared.showAtElement(e.target as HTMLElement)
}
@ -567,7 +567,7 @@ class BoardComponent extends React.Component<Props, State> {
onSearchKeyDown(e: React.KeyboardEvent) {
if (e.keyCode === 27) { // ESC: Clear search
this.searchFieldRef.current.text = '';
this.searchFieldRef.current.text = ''
this.setState({...this.state, isSearching: false})
this.props.setSearchText(undefined)
e.preventDefault()

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import './button.scss';
import './button.scss'
type Props = {
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void

View File

@ -1,24 +1,24 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {BlockIcons} from '../blockIcons';
import {Block} from '../blocks/block';
import {Card} from '../blocks/card';
import {TextBlock} from '../blocks/textBlock';
import {BoardTree} from '../boardTree';
import {CardTree} from '../cardTree';
import {Menu as OldMenu, MenuOption} from '../menu';
import mutator from '../mutator';
import {OctoListener} from '../octoListener';
import {IBlock, IOrderedBlock} from '../octoTypes';
import {OctoUtils} from '../octoUtils';
import {PropertyMenu} from '../propertyMenu';
import {Utils} from '../utils';
import {BlockIcons} from '../blockIcons'
import {Block} from '../blocks/block'
import {Card} from '../blocks/card'
import {TextBlock} from '../blocks/textBlock'
import {BoardTree} from '../boardTree'
import {CardTree} from '../cardTree'
import {Menu as OldMenu, MenuOption} from '../menu'
import mutator from '../mutator'
import {OctoListener} from '../octoListener'
import {IBlock, IOrderedBlock} from '../octoTypes'
import {OctoUtils} from '../octoUtils'
import {PropertyMenu} from '../propertyMenu'
import {Utils} from '../utils'
import Button from './button';
import {Editable} from './editable';
import {MarkdownEditor} from './markdownEditor';
import Button from './button'
import {Editable} from './editable'
import {MarkdownEditor} from './markdownEditor'
type Props = {
boardTree: BoardTree
@ -45,7 +45,7 @@ export default class CardDetail extends React.Component<Props, State> {
this.cardListener.open(this.props.card.id, async () => {
await cardTree.sync()
this.setState({cardTree})
});
})
const cardTree = new CardTree(this.props.card.id)
cardTree.sync().then(() => {
this.setState({cardTree})
@ -54,7 +54,7 @@ export default class CardDetail extends React.Component<Props, State> {
this.titleRef.current.focus()
}
}, 0)
});
})
}
render() {
@ -66,7 +66,7 @@ export default class CardDetail extends React.Component<Props, State> {
}
const {comments} = cardTree
const newCommentPlaceholderText = 'Add a comment...';
const newCommentPlaceholderText = 'Add a comment...'
const backgroundRef = React.createRef<HTMLDivElement>()
const newCommentRef = React.createRef<Editable>()
@ -145,8 +145,8 @@ export default class CardDetail extends React.Component<Props, State> {
const icon = card.icon
// TODO: Replace this placeholder
const username = 'John Smith';
const userImageUrl = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="fill: rgb(192, 192, 192);"><rect width="100" height="100" /></svg>';
const username = 'John Smith'
const userImageUrl = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="fill: rgb(192, 192, 192);"><rect width="100" height="100" /></svg>'
return (
<>
@ -205,28 +205,28 @@ export default class CardDetail extends React.Component<Props, State> {
menu.onNameChanged = (propertyName) => {
Utils.log('menu.onNameChanged')
mutator.renameProperty(board, propertyTemplate.id, propertyName)
};
}
menu.onMenuClicked = async (command) => {
switch (command) {
case 'type-text':
await mutator.changePropertyType(board, propertyTemplate, 'text')
break;
break
case 'type-number':
await mutator.changePropertyType(board, propertyTemplate, 'number')
break;
break
case 'type-createdTime':
await mutator.changePropertyType(board, propertyTemplate, 'createdTime')
break;
break
case 'type-updatedTime':
await mutator.changePropertyType(board, propertyTemplate, 'updatedTime')
break;
break
case 'type-select':
await mutator.changePropertyType(board, propertyTemplate, 'select')
break;
break
case 'delete':
await mutator.deleteProperty(boardTree, propertyTemplate.id)
break;
break
default:
Utils.assertFailure(`Unhandled menu id: ${command}`)
}
@ -263,12 +263,12 @@ export default class CardDetail extends React.Component<Props, State> {
switch (id) {
case 'delete': {
mutator.deleteBlock(activeComment)
break;
break
}
}
}
OldMenu.shared.showAtElement(e.target as HTMLElement)
};
}
return (<div
key={comment.id}
@ -277,7 +277,7 @@ export default class CardDetail extends React.Component<Props, State> {
optionsButtonRef.current.style.display = null
}}
onMouseLeave={() => {
optionsButtonRef.current.style.display = 'none';
optionsButtonRef.current.style.display = 'none'
}}
>
<div className='comment-header'>
@ -317,7 +317,7 @@ export default class CardDetail extends React.Component<Props, State> {
}}
onBlur={() => {
if (!newCommentRef.current.text) {
sendCommentButtonRef.current.style.display = 'none';
sendCommentButtonRef.current.style.display = 'none'
}
}}
onKeyDown={(e) => {
@ -366,14 +366,14 @@ export default class CardDetail extends React.Component<Props, State> {
const order = cardTree.contents.length * 1000
const block = new Block({type: 'text', parentId: card.id, order})
await mutator.insertBlock(block, 'add text')
break;
break
case 'image':
Utils.selectLocalFile(
(file) => {
mutator.createImageBlock(card.id, file, cardTree.contents.length * 1000)
},
'.jpg,.jpeg,.png')
break;
break
}
}
OldMenu.shared.showAtElement(e.target as HTMLElement)
@ -427,7 +427,7 @@ export default class CardDetail extends React.Component<Props, State> {
const newOrder = OctoUtils.getOrderBefore(previousBlock, cardTree.contents)
Utils.log(`moveUp ${newOrder}`)
mutator.changeOrder(block, newOrder, 'move up')
break;
break
}
case 'moveDown': {
if (index >= cardTree.contents.length - 1) {
@ -437,7 +437,7 @@ export default class CardDetail extends React.Component<Props, State> {
const newOrder = OctoUtils.getOrderAfter(nextBlock, cardTree.contents)
Utils.log(`moveDown ${newOrder}`)
mutator.changeOrder(block, newOrder, 'move down')
break;
break
}
case 'insertAbove-text': {
const newBlock = new TextBlock({parentId: card.id})
@ -446,7 +446,7 @@ export default class CardDetail extends React.Component<Props, State> {
newBlock.order = OctoUtils.getOrderBefore(block, cardTree.contents)
Utils.log(`insert block ${block.id}, order: ${block.order}`)
mutator.insertBlock(newBlock, 'insert card text')
break;
break
}
case 'insertAbove-image': {
Utils.selectLocalFile(
@ -455,11 +455,11 @@ export default class CardDetail extends React.Component<Props, State> {
},
'.jpg,.jpeg,.png')
break;
break
}
case 'delete': {
mutator.deleteBlock(block)
break;
break
}
}
}
@ -477,11 +477,11 @@ export default class CardDetail extends React.Component<Props, State> {
switch (optionId) {
case 'remove':
mutator.changeIcon(card, undefined, 'remove icon')
break;
break
case 'random':
const newIcon = BlockIcons.shared.randomIcon()
mutator.changeIcon(card, newIcon)
break;
break
}
}
OldMenu.shared.showAtElement(e.target as HTMLElement)

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Card} from '../blocks/card';
import {BoardTree} from '../boardTree';
import mutator from '../mutator';
import Menu from '../widgets/menu';
import {Card} from '../blocks/card'
import {BoardTree} from '../boardTree'
import mutator from '../mutator'
import Menu from '../widgets/menu'
import CardDetail from './cardDetail';
import Dialog from './dialog';
import CardDetail from './cardDetail'
import Dialog from './dialog'
type Props = {
boardTree: BoardTree

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import MenuWrapper from '../widgets/menuWrapper';
import MenuWrapper from '../widgets/menuWrapper'
import Button from './button';
import Button from './button'
type Props = {
children: React.ReactNode

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Utils} from '../utils';
import {Utils} from '../utils'
type Props = {
onChanged: (text: string) => void
@ -36,23 +36,23 @@ class Editable extends React.Component<Props, State> {
const {isMarkdown} = this.props
if (!value) {
this.elementRef.current.innerText = '';
this.elementRef.current.innerText = ''
} else {
this.elementRef.current.innerHTML = isMarkdown ? Utils.htmlFromMarkdown(value) : Utils.htmlEncode(value)
}
this._text = value || '';
this._text = value || ''
}
private elementRef = React.createRef<HTMLDivElement>()
constructor(props: Props) {
super(props)
this._text = props.text || '';
this._text = props.text || ''
}
componentDidUpdate(prevPros: Props, prevState: State) {
this._text = this.props.text || '';
this._text = this.props.text || ''
}
focus() {
@ -76,7 +76,7 @@ class Editable extends React.Component<Props, State> {
if (text) {
html = isMarkdown ? Utils.htmlFromMarkdown(text) : Utils.htmlEncode(text)
} else {
html = '';
html = ''
}
const element =
@ -102,7 +102,7 @@ class Editable extends React.Component<Props, State> {
onBlur={async () => {
const newText = this.elementRef.current.innerText
const oldText = this.props.text || '';
const oldText = this.props.text || ''
if (newText !== oldText && onChanged) {
onChanged(newText)
}

View File

@ -1,13 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {BoardTree} from '../boardTree';
import {FilterClause, FilterCondition} from '../filterClause';
import {FilterGroup} from '../filterGroup';
import {Menu} from '../menu';
import mutator from '../mutator';
import {Utils} from '../utils';
import {BoardTree} from '../boardTree'
import {FilterClause, FilterCondition} from '../filterClause'
import {FilterGroup} from '../filterGroup'
import {Menu} from '../menu'
import mutator from '../mutator'
import {Utils} from '../utils'
type Props = {
boardTree: BoardTree
@ -42,7 +42,7 @@ class FilterComponent extends React.Component<Props> {
>
{filters.map((filter) => {
const template = board.cardProperties.find((o) => o.id === filter.propertyId)
const propertyName = template ? template.name : '(unknown)'; // TODO: Handle error
const propertyName = template ? template.name : '(unknown)' // TODO: Handle error
const key = `${filter.propertyId}-${filter.condition}-${filter.values.join(',')}`
Utils.log(`FilterClause key: ${key}`)
return (<div

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import EasyMDE from 'easymde';
import React from 'react';
import SimpleMDE from 'react-simplemde-editor';
import EasyMDE from 'easymde'
import React from 'react'
import SimpleMDE from 'react-simplemde-editor'
import {Utils} from '../utils';
import {Utils} from '../utils'
type Props = {
onChanged: (text: string) => void
@ -43,7 +43,7 @@ class MarkdownEditor extends React.Component<Props, State> {
}
componentDidUpdate(prevPros: Props, prevState: State) {
this.text = this.props.text || '';
this.text = this.props.text || ''
}
showEditor() {
@ -123,7 +123,7 @@ class MarkdownEditor extends React.Component<Props, State> {
events={{
blur: () => {
const newText = this.elementRef.current.state.value
const oldText = this.props.text || '';
const oldText = this.props.text || ''
if (newText !== oldText && onChanged) {
const newHtml = newText ? Utils.htmlFromMarkdown(newText) : Utils.htmlFromMarkdown(placeholderText || '')
this.previewRef.current.innerHTML = newHtml

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
type Props = {
}

View File

@ -1,21 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {render} from '@testing-library/react';
import '@testing-library/jest-dom';
import React from 'react'
import {render} from '@testing-library/react'
import '@testing-library/jest-dom'
import RootPortal from './rootPortal';
import RootPortal from './rootPortal'
describe('components/RootPortal', () => {
beforeEach(() => {
// Quick fix to disregard console error when unmounting a component
console.error = jest.fn()
});
})
test('should match snapshot', () => {
const rootPortalDiv = document.createElement('div')
rootPortalDiv.id = 'root-portal';
rootPortalDiv.id = 'root-portal'
const {getByText, container} = render(
<RootPortal>
@ -26,5 +26,5 @@ describe('components/RootPortal', () => {
expect(getByText('Testing Portal')).toBeVisible()
expect(container).toMatchSnapshot()
});
})
})

View File

@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
type Props = {
children: React.ReactNode

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Archiver} from '../archiver';
import {Board} from '../blocks/board';
import {BoardTree} from '../boardTree';
import Menu from '../widgets/menu';
import MenuWrapper from '../widgets/menuWrapper';
import mutator from '../mutator';
import {WorkspaceTree} from '../workspaceTree';
import {Archiver} from '../archiver'
import {Board} from '../blocks/board'
import {BoardTree} from '../boardTree'
import Menu from '../widgets/menu'
import MenuWrapper from '../widgets/menuWrapper'
import mutator from '../mutator'
import {WorkspaceTree} from '../workspaceTree'
type Props = {
showBoard: (id: string) => void
@ -29,7 +29,7 @@ class Sidebar extends React.Component<Props> {
<div className='octo-sidebar'>
{
boards.map((board) => {
const displayTitle = board.title || '(Untitled Board)';
const displayTitle = board.title || '(Untitled Board)'
return (
<div
key={board.id}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
type Props = {
onChanged: (isOn: boolean) => void
@ -39,7 +39,7 @@ class Switch extends React.Component<Props, State> {
const {style} = this.props
const {isOn} = this.state
const className = isOn ? 'octo-switch on' : 'octo-switch';
const className = isOn ? 'octo-switch on' : 'octo-switch'
const element =
(<div
ref={this.elementRef}

View File

@ -1,26 +1,26 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Archiver} from '../archiver';
import {BlockIcons} from '../blockIcons';
import {IPropertyTemplate} from '../blocks/board';
import {Card} from '../blocks/card';
import {BoardTree} from '../boardTree';
import ViewMenu from '../components/viewMenu';
import {CsvExporter} from '../csvExporter';
import {Menu as OldMenu} from '../menu';
import mutator from '../mutator';
import {OctoUtils} from '../octoUtils';
import {Utils} from '../utils';
import Menu from '../widgets/menu';
import MenuWrapper from '../widgets/menuWrapper';
import {Archiver} from '../archiver'
import {BlockIcons} from '../blockIcons'
import {IPropertyTemplate} from '../blocks/board'
import {Card} from '../blocks/card'
import {BoardTree} from '../boardTree'
import ViewMenu from '../components/viewMenu'
import {CsvExporter} from '../csvExporter'
import {Menu as OldMenu} from '../menu'
import mutator from '../mutator'
import {OctoUtils} from '../octoUtils'
import {Utils} from '../utils'
import Menu from '../widgets/menu'
import MenuWrapper from '../widgets/menuWrapper'
import Button from './button';
import {CardDialog} from './cardDialog';
import {Editable} from './editable';
import RootPortal from './rootPortal';
import {TableRow} from './tableRow';
import Button from './button'
import {CardDialog} from './cardDialog'
import {Editable} from './editable'
import RootPortal from './rootPortal'
import {TableRow} from './tableRow'
type Props = {
boardTree?: BoardTree
@ -322,7 +322,7 @@ class TableComponent extends React.Component<Props, State> {
OldMenu.shared.options = selectProperties.map((o) => {
const isVisible = activeView.visiblePropertyIds.includes(o.id)
return {id: o.id, name: o.name, type: 'switch', isOn: isVisible}
});
})
OldMenu.shared.onMenuToggled = async (id: string, isOn: boolean) => {
const property = selectProperties.find((o) => o.id === id)
@ -336,7 +336,7 @@ class TableComponent extends React.Component<Props, State> {
newVisiblePropertyIds = [...activeView.visiblePropertyIds, id]
}
await mutator.changeViewVisibleProperties(activeView, newVisiblePropertyIds)
};
}
OldMenu.shared.showAtElement(e.target as HTMLElement)
}
@ -356,11 +356,11 @@ class TableComponent extends React.Component<Props, State> {
switch (id) {
case 'exportCsv': {
CsvExporter.exportTableCsv(boardTree)
break;
break
}
case 'exportBoardArchive': {
Archiver.exportBoardTree(boardTree)
break;
break
}
}
}
@ -393,14 +393,14 @@ class TableComponent extends React.Component<Props, State> {
{propertyId: templateId, reversed: false},
]
await mutator.changeViewSortOptions(activeView, newSortOptions)
break;
break
}
case 'sortDescending': {
const newSortOptions = [
{propertyId: templateId, reversed: true},
]
await mutator.changeViewSortOptions(activeView, newSortOptions)
break;
break
}
case 'insertLeft': {
if (templateId !== '__name') {
@ -422,20 +422,20 @@ class TableComponent extends React.Component<Props, State> {
}
case 'duplicate': {
await mutator.duplicatePropertyTemplate(boardTree, templateId)
break;
break
}
case 'hide': {
const newVisiblePropertyIds = activeView.visiblePropertyIds.filter((o) => o !== templateId)
await mutator.changeViewVisibleProperties(activeView, newVisiblePropertyIds)
break;
break
}
case 'delete': {
await mutator.deleteProperty(boardTree, templateId)
break;
break
}
default: {
Utils.assertFailure(`Unexpected menu option: ${optionId}`)
break;
break
}
}
}
@ -489,7 +489,7 @@ class TableComponent extends React.Component<Props, State> {
onSearchKeyDown(e: React.KeyboardEvent) {
if (e.keyCode === 27) { // ESC: Clear search
this.searchFieldRef.current.text = '';
this.searchFieldRef.current.text = ''
this.setState({...this.state, isSearching: false})
this.props.setSearchText(undefined)
e.preventDefault()

View File

@ -1,15 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {BoardTree} from '../boardTree';
import {Card} from '../blocks/card';
import mutator from '../mutator';
import {OctoUtils} from '../octoUtils';
import {BoardTree} from '../boardTree'
import {Card} from '../blocks/card'
import mutator from '../mutator'
import {OctoUtils} from '../octoUtils'
import {Editable} from './editable';
import {CardDialog} from './cardDialog';
import RootPortal from './rootPortal';
import {Editable} from './editable'
import {CardDialog} from './cardDialog'
import RootPortal from './rootPortal'
type Props = {
boardTree: BoardTree
@ -54,7 +54,7 @@ class TableRow extends React.Component<Props, State> {
openButonRef.current.style.display = null
}}
onMouseLeave={() => {
openButonRef.current.style.display = 'none';
openButonRef.current.style.display = 'none'
}}
>
<div className='octo-icontitle'>

View File

@ -1,13 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Board} from '../blocks/board';
import {BoardView} from '../blocks/boardView';
import {BoardTree} from '../boardTree';
import mutator from '../mutator';
import {Utils} from '../utils';
import Menu from '../widgets/menu';
import {Board} from '../blocks/board'
import {BoardView} from '../blocks/boardView'
import {BoardTree} from '../boardTree'
import mutator from '../mutator'
import {Utils} from '../utils'
import Menu from '../widgets/menu'
type Props = {
boardTree?: BoardTree
@ -36,8 +36,8 @@ export default class ViewMenu extends React.Component<Props> {
const {board, boardTree, showView} = this.props
Utils.log('addview-board')
const view = new BoardView()
view.title = 'Board View';
view.viewType = 'board';
view.title = 'Board View'
view.viewType = 'board'
view.parentId = board.id
const oldViewId = boardTree.activeView.id
@ -50,7 +50,7 @@ export default class ViewMenu extends React.Component<Props> {
},
async () => {
showView(oldViewId)
});
})
}
handleAddViewTable = async (id: string) => {
@ -58,8 +58,8 @@ export default class ViewMenu extends React.Component<Props> {
Utils.log('addview-table')
const view = new BoardView()
view.title = 'Table View';
view.viewType = 'table';
view.title = 'Table View'
view.viewType = 'table'
view.parentId = board.id
view.visiblePropertyIds = board.cardProperties.map((o) => o.id)
@ -73,7 +73,7 @@ export default class ViewMenu extends React.Component<Props> {
},
async () => {
showView(oldViewId)
});
})
}
render() {

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {BoardTree} from '../boardTree';
import {Utils} from '../utils';
import {WorkspaceTree} from '../workspaceTree';
import {BoardTree} from '../boardTree'
import {Utils} from '../utils'
import {WorkspaceTree} from '../workspaceTree'
import {BoardComponent} from './boardComponent';
import {Sidebar} from './sidebar';
import {TableComponent} from './tableComponent';
import {BoardComponent} from './boardComponent'
import {Sidebar} from './sidebar'
import {TableComponent} from './tableComponent'
type Props = {
workspaceTree: WorkspaceTree
@ -52,7 +52,7 @@ class WorkspaceComponent extends React.Component<Props> {
showFilter={showFilter}
setSearchText={setSearchText}
showView={showView}
/>);
/>)
}
case 'table': {
@ -61,7 +61,7 @@ class WorkspaceComponent extends React.Component<Props> {
showFilter={showFilter}
setSearchText={setSearchText}
showView={showView}
/>);
/>)
}
default: {

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {MenuOption} from './menu';
import {MenuOption} from './menu'
class Constants {
static menuColors: MenuOption[] = [

View File

@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {BoardView} from './blocks/boardView';
import {BoardTree} from './boardTree';
import {OctoUtils} from './octoUtils';
import {Utils} from './utils';
import {BoardView} from './blocks/boardView'
import {BoardTree} from './boardTree'
import {OctoUtils} from './octoUtils'
import {Utils} from './utils'
class CsvExporter {
static exportTableCsv(boardTree: BoardTree, view?: BoardView) {
@ -12,17 +12,17 @@ class CsvExporter {
const rows = CsvExporter.generateTableArray(boardTree, view)
let csvContent = 'data:text/csv;charset=utf-8,';
let csvContent = 'data:text/csv;charset=utf-8,'
rows.forEach((row) => {
const encodedRow = row.join(',')
csvContent += encodedRow + '\r\n';
csvContent += encodedRow + '\r\n'
})
const filename = `${Utils.sanitizeFilename(viewToExport.title)}.csv`
const encodedUri = encodeURI(csvContent)
const link = document.createElement('a')
link.style.display = 'none';
link.style.display = 'none'
link.setAttribute('href', encodedUri)
link.setAttribute('download', filename)
document.body.appendChild(link) // FireFox support
@ -44,7 +44,7 @@ class CsvExporter {
const row: string[] = []
visibleProperties.forEach((template) => {
row.push(template.name)
});
})
rows.push(row)
}
@ -52,7 +52,7 @@ class CsvExporter {
const row: string[] = []
visibleProperties.forEach((template) => {
const propertyValue = card.properties[template.id]
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, template) || '';
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, template) || ''
if (template.type === 'number') {
const numericValue = propertyValue ? Number(propertyValue).toString() : undefined
row.push(numericValue)
@ -62,7 +62,7 @@ class CsvExporter {
}
})
rows.push(row)
});
})
return rows
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Utils} from './utils';
import {Utils} from './utils'
type FilterCondition = 'includes' | 'notIncludes' | 'isEmpty' | 'isNotEmpty'
@ -11,20 +11,20 @@ class FilterClause {
static filterConditionDisplayString(filterCondition: FilterCondition) {
switch (filterCondition) {
case 'includes': return 'includes';
case 'includes': return 'includes'
case 'notIncludes': return "doesn't include"
case 'isEmpty': return 'is empty';
case 'isNotEmpty': return 'is not empty';
case 'isEmpty': return 'is empty'
case 'isNotEmpty': return 'is not empty'
default: {
Utils.assertFailure()
return '(unknown)';
return '(unknown)'
}
}
}
constructor(o: any = {}) {
this.propertyId = o.propertyId || '';
this.condition = o.condition || 'includes';
this.propertyId = o.propertyId || ''
this.condition = o.condition || 'includes'
this.values = o.values?.slice() || []
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {FilterClause} from './filterClause';
import {FilterClause} from './filterClause'
type FilterGroupOperation = 'and' | 'or'
@ -14,7 +14,7 @@ class FilterGroup {
}
constructor(o: any = {}) {
this.operation = o.operation || 'and';
this.operation = o.operation || 'and'
this.filters = o.filters ?
o.filters.map((p: any) => {
if (FilterGroup.isAnInstanceOf(p)) {

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import ReactDOM from 'react-dom';
import React from 'react'
import ReactDOM from 'react-dom'
import App from './app';
import App from './app'
ReactDOM.render(<App/>, document.getElementById('octo-tasks-app'))

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Utils} from './utils';
import {Utils} from './utils'
type MenuOption = {
id: string,
@ -56,7 +56,7 @@ class Menu {
const bodyRect = document.body.getBoundingClientRect()
const rect = optionElement.getBoundingClientRect()
this.showSubMenu(rect.right - bodyRect.left, rect.top - bodyRect.top, option.id)
};
}
} else {
if (option.icon) {
let iconName: string
@ -73,7 +73,7 @@ class Menu {
optionElement.onmouseenter = () => {
this.hideSubMenu()
};
}
optionElement.onclick = (e) => {
if (this.onMenuClicked) {
this.onMenuClicked(option.id, option.type)
@ -81,14 +81,14 @@ class Menu {
this.hide()
e.stopPropagation()
return false
};
}
}
if (option.type === 'color') {
const colorbox = optionElement.insertBefore(Utils.htmlToElement('<div class="menu-colorbox"></div>'), optionElement.firstChild)
colorbox.classList.add(option.id) // id is the css class name for the color
} else if (option.type === 'switch') {
const className = option.isOn ? 'octo-switch on' : 'octo-switch';
const className = option.isOn ? 'octo-switch on' : 'octo-switch'
const switchElement = optionElement.appendChild(Utils.htmlToElement(`<div class="${className}"></div>`))
switchElement.appendChild(Utils.htmlToElement('<div class="octo-switch-inner"></div>'))
switchElement.onclick = (e) => {
@ -104,7 +104,7 @@ class Menu {
}
e.stopPropagation()
return false
};
}
optionElement.onclick = null
}
}
@ -132,7 +132,7 @@ class Menu {
this.onBodyClick = (e: MouseEvent) => {
console.log('onBodyClick')
this.hide()
};
}
this.onBodyKeyDown = (e: KeyboardEvent) => {
console.log(`onBodyKeyDown, target: ${e.target}`)
@ -199,7 +199,7 @@ class Menu {
this.onMenuClicked(subMenuId, type)
}
this.hide()
};
}
this.subMenu.options = options
this.subMenu.showAt(pageX, pageY)

View File

@ -1,16 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './blocks/block';
import {Board, IPropertyOption, IPropertyTemplate, PropertyType} from './blocks/board';
import {BoardView, ISortOption} from './blocks/boardView';
import {Card} from './blocks/card';
import {ImageBlock} from './blocks/imageBlock';
import {BoardTree} from './boardTree';
import {FilterGroup} from './filterGroup';
import octoClient from './octoClient';
import {IBlock, IOrderedBlock} from './octoTypes';
import undoManager from './undomanager';
import {Utils} from './utils';
import {Block} from './blocks/block'
import {Board, IPropertyOption, IPropertyTemplate, PropertyType} from './blocks/board'
import {BoardView, ISortOption} from './blocks/boardView'
import {Card} from './blocks/card'
import {ImageBlock} from './blocks/imageBlock'
import {BoardTree} from './boardTree'
import {FilterGroup} from './filterGroup'
import octoClient from './octoClient'
import {IBlock, IOrderedBlock} from './octoTypes'
import undoManager from './undomanager'
import {Utils} from './utils'
//
// The Mutator is used to make all changes to server state
@ -133,14 +133,14 @@ class Mutator {
const changedBlocks: IBlock[] = [board]
board.cardProperties.splice(index, 0, template)
let description = 'add property';
let description = 'add property'
if (activeView.viewType === 'table') {
oldBlocks.push(new BoardView(activeView))
activeView.visiblePropertyIds.push(template.id)
changedBlocks.push(activeView)
description = 'add column';
description = 'add column'
}
await undoManager.perform(
@ -173,13 +173,13 @@ class Mutator {
}
board.cardProperties.splice(index + 1, 0, newTemplate)
let description = 'duplicate property';
let description = 'duplicate property'
if (activeView.viewType === 'table') {
oldBlocks.push(new BoardView(activeView))
activeView.visiblePropertyIds.push(newTemplate.id)
changedBlocks.push(activeView)
description = 'duplicate column';
description = 'duplicate column'
}
await undoManager.perform(

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IBlock} from './octoTypes';
import {Utils} from './utils';
import {IBlock} from './octoTypes'
import {Utils} from './utils'
//
// OctoClient is the client interface to the server APIs
@ -23,7 +23,7 @@ class OctoClient {
}
async exportFullArchive(): Promise<IBlock[]> {
const path = '/api/v1/blocks/export';
const path = '/api/v1/blocks/export'
const response = await fetch(this.serverUrl + path)
const blocks = (await response.json() || []) as IBlock[]
this.fixBlocks(blocks)
@ -34,7 +34,7 @@ class OctoClient {
Utils.log(`importFullArchive: ${blocks.length} blocks(s)`)
blocks.forEach((block) => {
Utils.log(`\t ${block.type}, ${block.id}`)
});
})
const body = JSON.stringify(blocks)
return await fetch(this.serverUrl + '/api/v1/blocks/import', {
method: 'POST',
@ -55,7 +55,7 @@ class OctoClient {
} else if (type) {
path = `/api/v1/blocks?type=${encodeURIComponent(type)}`
} else {
path = '/api/v1/blocks';
path = '/api/v1/blocks'
}
const response = await fetch(this.serverUrl + path)
@ -99,7 +99,7 @@ class OctoClient {
const now = Date.now()
blocks.forEach((block) => {
block.updateAt = now
});
})
return await this.insertBlocks(blocks)
}
@ -122,7 +122,7 @@ class OctoClient {
Utils.log(`insertBlocks: ${blocks.length} blocks(s)`)
blocks.forEach((block) => {
Utils.log(`\t ${block.type}, ${block.id}`)
});
})
const body = JSON.stringify(blocks)
return await fetch(this.serverUrl + '/api/v1/blocks', {
method: 'POST',

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Utils} from './utils';
import {Utils} from './utils'
//
// OctoListener calls a handler when a block or any of its children changes
@ -36,11 +36,11 @@ class OctoListener {
ws.onopen = () => {
Utils.log('OctoListener webSocket opened.')
ws.send('{}')
};
}
ws.onerror = (e) => {
Utils.logError(`OctoListener websocket onerror. data: ${e}`)
};
}
ws.onclose = (e) => {
Utils.log(`OctoListener websocket onclose, code: ${e.code}, reason: ${e.reason}`)
@ -64,7 +64,7 @@ class OctoListener {
timeoutId = undefined
onChange(message.blockId)
}, this.notificationDelay)
break;
break
default:
Utils.logError(`Unexpected action: ${message.action}`)
}

View File

@ -1,20 +1,20 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Block} from './blocks/block';
import {Board, IPropertyTemplate} from './blocks/board';
import {BoardView, ISortOption} from './blocks/boardView';
import {Card} from './blocks/card';
import {CommentBlock} from './blocks/commentBlock';
import {ImageBlock} from './blocks/imageBlock';
import {TextBlock} from './blocks/textBlock';
import {BoardTree} from './boardTree';
import {Editable} from './components/editable';
import {Menu} from './menu';
import mutator from './mutator';
import {IBlock, IOrderedBlock} from './octoTypes';
import {Utils} from './utils';
import {Block} from './blocks/block'
import {Board, IPropertyTemplate} from './blocks/board'
import {BoardView, ISortOption} from './blocks/boardView'
import {Card} from './blocks/card'
import {CommentBlock} from './blocks/commentBlock'
import {ImageBlock} from './blocks/imageBlock'
import {TextBlock} from './blocks/textBlock'
import {BoardTree} from './boardTree'
import {Editable} from './components/editable'
import {Menu} from './menu'
import mutator from './mutator'
import {IBlock, IOrderedBlock} from './octoTypes'
import {Utils} from './utils'
class OctoUtils {
static propertyDisplayValue(block: IBlock, propertyValue: string | undefined, propertyTemplate: IPropertyTemplate) {
@ -22,10 +22,10 @@ class OctoUtils {
switch (propertyTemplate.type) {
case 'createdTime':
displayValue = Utils.displayDateTime(new Date(block.createAt))
break;
break
case 'updatedTime':
displayValue = Utils.displayDateTime(new Date(block.updateAt))
break;
break
default:
displayValue = propertyValue
}
@ -57,9 +57,9 @@ class OctoUtils {
let element: JSX.Element
if (propertyTemplate.type === 'select') {
let className = 'octo-button octo-propertyvalue';
let className = 'octo-button octo-propertyvalue'
if (!displayValue) {
className += ' empty';
className += ' empty'
}
const showMenu = (clickedElement: HTMLElement) => {
@ -72,9 +72,9 @@ class OctoUtils {
menu.options.push(...propertyTemplate.options.map((o) => ({id: o.value, name: o.value})))
menu.onMenuClicked = (optionId) => {
mutator.changePropertyValue(card, propertyTemplate.id, optionId)
};
}
menu.showAtElement(clickedElement)
};
}
element = (<div
key={propertyTemplate.id}
@ -151,7 +151,7 @@ class OctoUtils {
name: o.name,
icon: (sortOption?.propertyId === o.id) ? sortOption.reversed ? 'sortUp' : 'sortDown' : undefined,
}
});
})
Menu.shared.onMenuClicked = async (propertyId: string) => {
let newSortOptions: ISortOption[] = []
if (sortOption && sortOption.propertyId === propertyId) {
@ -166,7 +166,7 @@ class OctoUtils {
}
await mutator.changeViewSortOptions(activeView, newSortOptions)
};
}
Menu.shared.showAtElement(e.target as HTMLElement)
}

View File

@ -1,18 +1,18 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import ReactDOM from 'react-dom';
import React from 'react'
import ReactDOM from 'react-dom'
import {BoardView} from '../blocks/boardView';
import {BoardTree} from '../boardTree';
import {CardTree} from '../cardTree';
import {FilterComponent} from '../components/filterComponent';
import {WorkspaceComponent} from '../components/workspaceComponent';
import {FlashMessage} from '../flashMessage';
import mutator from '../mutator';
import {OctoListener} from '../octoListener';
import {Utils} from '../utils';
import {WorkspaceTree} from '../workspaceTree';
import {BoardView} from '../blocks/boardView'
import {BoardTree} from '../boardTree'
import {CardTree} from '../cardTree'
import {FilterComponent} from '../components/filterComponent'
import {WorkspaceComponent} from '../components/workspaceComponent'
import {FlashMessage} from '../flashMessage'
import mutator from '../mutator'
import {OctoListener} from '../octoListener'
import {Utils} from '../utils'
import {WorkspaceTree} from '../workspaceTree'
type Props = {
}
@ -166,7 +166,7 @@ export default class BoardPage extends React.Component<Props, State> {
this.boardListener.open(boardId, (blockId: string) => {
console.log(`octoListener.onChanged: ${blockId}`)
this.sync(boardId)
});
})
this.sync(boardId, viewId)
}

View File

@ -1,13 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import {Archiver} from '../archiver';
import {Board} from '../blocks/board';
import Button from '../components/button';
import octoClient from '../octoClient';
import {IBlock} from '../octoTypes';
import {Utils} from '../utils';
import {Archiver} from '../archiver'
import {Board} from '../blocks/board'
import Button from '../components/button'
import octoClient from '../octoClient'
import {IBlock} from '../octoTypes'
import {Utils} from '../utils'
type Props = {}
@ -35,7 +35,7 @@ export default class HomePage extends React.Component<Props, State> {
importClicked = async () => {
Archiver.importFullArchive(() => {
this.loadBoards()
});
})
}
exportClicked = async () => {

View File

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
import Button from '../components/button';
import Button from '../components/button'
import './loginPage.scss';
import './loginPage.scss'
type Props = {}

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IPropertyTemplate, PropertyType} from './blocks/board';
import {Menu} from './menu';
import {Utils} from './utils';
import {IPropertyTemplate, PropertyType} from './blocks/board'
import {Menu} from './menu'
import {Utils} from './utils'
class PropertyMenu extends Menu {
static shared = new PropertyMenu()
@ -31,12 +31,12 @@ class PropertyMenu extends Menu {
const nameTextbox = ul.appendChild(Utils.htmlToElement('<li class="menu-textbox"></li>'))
this.nameTextbox = nameTextbox
let propertyValue = this.property ? this.property.name : '';
let propertyValue = this.property ? this.property.name : ''
nameTextbox.innerText = propertyValue
nameTextbox.contentEditable = 'true';
nameTextbox.contentEditable = 'true'
nameTextbox.onclick = (e) => {
e.stopPropagation()
};
}
nameTextbox.onblur = () => {
if (nameTextbox.innerText !== propertyValue) {
propertyValue = nameTextbox.innerText
@ -47,7 +47,7 @@ class PropertyMenu extends Menu {
}
nameTextbox.onmouseenter = () => {
this.hideSubMenu()
};
}
nameTextbox.onkeydown = (e) => {
if (e.keyCode === 13 || e.keyCode === 27) {
nameTextbox.blur(); e.stopPropagation()
@ -76,20 +76,20 @@ class PropertyMenu extends Menu {
private typeDisplayName(type: PropertyType): string {
switch (type) {
case 'text': return 'Text';
case 'number': return 'Number';
case 'select': return 'Select';
case 'multiSelect': return 'Multi Select';
case 'person': return 'Person';
case 'file': return 'File or Media';
case 'checkbox': return 'Checkbox';
case 'url': return 'URL';
case 'email': return 'Email';
case 'phone': return 'Phone';
case 'createdTime': return 'Created Time';
case 'createdBy': return 'Created By';
case 'updatedTime': return 'Updated Time';
case 'updatedBy': return 'Updated By';
case 'text': return 'Text'
case 'number': return 'Number'
case 'select': return 'Select'
case 'multiSelect': return 'Multi Select'
case 'person': return 'Person'
case 'file': return 'File or Media'
case 'checkbox': return 'Checkbox'
case 'url': return 'URL'
case 'email': return 'Email'
case 'phone': return 'Phone'
case 'createdTime': return 'Created Time'
case 'createdBy': return 'Created By'
case 'updatedTime': return 'Updated Time'
case 'updatedBy': return 'Updated By'
}
Utils.assertFailure(`typeDisplayName, unhandled type: ${type}`)
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import marked from 'marked';
import marked from 'marked'
declare global {
interface Window {
@ -122,10 +122,10 @@ class Utils {
static setFavicon(icon?: string) {
const href = icon ?
`data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">${icon}</text></svg>` :
'';
''
const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.type = 'image/x-icon'
link.rel = 'shortcut icon'
link.href = href
document.getElementsByTagName('head')[0].appendChild(link)
}
@ -138,7 +138,7 @@ class Utils {
const illegalCharacters = ['\\', '/', '?', ':', '<', '>', '*', '|', '"', '.']
illegalCharacters.forEach((character) => {
sanitizedFilename = sanitizedFilename.replace(character, '')
});
})
return sanitizedFilename
}
@ -146,14 +146,14 @@ class Utils {
static selectLocalFile(onSelect?: (file: File) => void, accept = '.jpg,.jpeg,.png'): void {
const input = document.createElement('input')
input.type = 'file';
input.type = 'file'
input.accept = accept
input.onchange = async () => {
const file = input.files![0]
onSelect?.(file)
};
}
input.style.display = 'none';
input.style.display = 'none'
document.body.appendChild(input)
input.click()

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
type MenuOptionProps = {
id: string,

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React from 'react'
type Props = {
children?: React.ReactNode;

View File

@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Block} from './blocks/block';
import {Board} from './blocks/board';
import octoClient from './octoClient';
import {OctoUtils} from './octoUtils';
import {Block} from './blocks/block'
import {Board} from './blocks/board'
import octoClient from './octoClient'
import {OctoUtils} from './octoUtils'
class WorkspaceTree {
boards: Board[] = []