mirror of
https://github.com/mattermost/focalboard.git
synced 2024-12-24 13:43:12 +02:00
Show views in sidebar
This commit is contained in:
parent
0b07f454bb
commit
277505e6f9
@ -8,10 +8,12 @@ import mutator from '../mutator'
|
||||
import Menu from '../widgets/menu'
|
||||
import MenuWrapper from '../widgets/menuWrapper'
|
||||
import { WorkspaceTree } from '../viewModel/workspaceTree'
|
||||
import { BoardView } from '../blocks/boardView'
|
||||
|
||||
|
||||
type Props = {
|
||||
showBoard: (id: string) => void
|
||||
showView: (id: string, boardId?: string) => void
|
||||
workspaceTree: WorkspaceTree,
|
||||
boardTree?: BoardTree
|
||||
}
|
||||
@ -23,47 +25,51 @@ class Sidebar extends React.Component<Props> {
|
||||
return <div/>
|
||||
}
|
||||
|
||||
const {boards} = workspaceTree
|
||||
const {boards, views} = workspaceTree
|
||||
|
||||
return (
|
||||
<div className='octo-sidebar'>
|
||||
{
|
||||
boards.map((board) => {
|
||||
const displayTitle = board.title || '(Untitled Board)'
|
||||
const boardViews = views.filter(view => view.parentId === board.id)
|
||||
return (
|
||||
<div
|
||||
key={board.id}
|
||||
className='octo-sidebar-item octo-hover-container'
|
||||
>
|
||||
<div
|
||||
className='octo-sidebar-title'
|
||||
onClick={() => {
|
||||
this.boardClicked(board)
|
||||
}}
|
||||
>{board.icon ? `${board.icon} ${displayTitle}` : displayTitle}</div>
|
||||
<div className='octo-spacer'/>
|
||||
<MenuWrapper>
|
||||
<div className='octo-button square octo-hover-item'><div className='imageOptions'/></div>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='delete'
|
||||
name='Delete board'
|
||||
onClick={async () => {
|
||||
const nextBoardId = boards.length > 1 ? boards.find((o) => o.id !== board.id).id : undefined
|
||||
mutator.deleteBlock(
|
||||
board,
|
||||
'delete block',
|
||||
async () => {
|
||||
nextBoardId && this.props.showBoard(nextBoardId!)
|
||||
},
|
||||
async () => {
|
||||
this.props.showBoard(board.id)
|
||||
},
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
<div key={board.id}>
|
||||
<div className='octo-sidebar-item octo-hover-container'>
|
||||
<div className='octo-sidebar-title' onClick={() => { this.boardClicked(board) }}>
|
||||
{board.icon ? `${board.icon} ${displayTitle}` : displayTitle}
|
||||
</div>
|
||||
<div className='octo-spacer'/>
|
||||
<MenuWrapper>
|
||||
<div className='octo-button square octo-hover-item'><div className='imageOptions'/></div>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='delete'
|
||||
name='Delete board'
|
||||
onClick={async () => {
|
||||
const nextBoardId = boards.length > 1 ? boards.find((o) => o.id !== board.id).id : undefined
|
||||
mutator.deleteBlock(
|
||||
board,
|
||||
'delete block',
|
||||
async () => {
|
||||
nextBoardId && this.props.showBoard(nextBoardId!)
|
||||
},
|
||||
async () => {
|
||||
this.props.showBoard(board.id)
|
||||
},
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
</div>
|
||||
{boardViews.map(view => {
|
||||
return <div 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)'}
|
||||
</div>
|
||||
</div>
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@ -105,6 +111,10 @@ class Sidebar extends React.Component<Props> {
|
||||
this.props.showBoard(board.id)
|
||||
}
|
||||
|
||||
private viewClicked(board: Board, view: BoardView) {
|
||||
this.props.showView(view.id, board.id)
|
||||
}
|
||||
|
||||
async addBoardClicked() {
|
||||
const {boardTree, showBoard} = this.props
|
||||
|
||||
@ -127,4 +137,3 @@ class Sidebar extends React.Component<Props> {
|
||||
}
|
||||
|
||||
export { Sidebar }
|
||||
|
||||
|
@ -14,20 +14,21 @@ type Props = {
|
||||
workspaceTree: WorkspaceTree
|
||||
boardTree?: BoardTree
|
||||
showBoard: (id: string) => void
|
||||
showView: (id: string) => void
|
||||
showView: (id: string, boardId?: string) => void
|
||||
showFilter: (el: HTMLElement) => void
|
||||
setSearchText: (text: string) => void
|
||||
}
|
||||
|
||||
class WorkspaceComponent extends React.Component<Props> {
|
||||
render() {
|
||||
const {boardTree, workspaceTree, showBoard} = this.props
|
||||
const {boardTree, workspaceTree, showBoard, showView} = this.props
|
||||
|
||||
Utils.assert(workspaceTree)
|
||||
const element =
|
||||
(<div className='octo-workspace'>
|
||||
<Sidebar
|
||||
showBoard={showBoard}
|
||||
showView={showView}
|
||||
workspaceTree={workspaceTree}
|
||||
boardTree={boardTree}
|
||||
/>
|
||||
|
@ -47,18 +47,22 @@ class OctoClient {
|
||||
})
|
||||
}
|
||||
|
||||
async getBlocks(parentId?: string, type?: string): Promise<IBlock[]> {
|
||||
async getBlocksWithParent(parentId: string, type?: string): Promise<IBlock[]> {
|
||||
let path: string
|
||||
if (parentId && type) {
|
||||
if (type) {
|
||||
path = `/api/v1/blocks?parent_id=${encodeURIComponent(parentId)}&type=${encodeURIComponent(type)}`
|
||||
} else if (parentId) {
|
||||
path = `/api/v1/blocks?parent_id=${encodeURIComponent(parentId)}`
|
||||
} else if (type) {
|
||||
path = `/api/v1/blocks?type=${encodeURIComponent(type)}`
|
||||
} else {
|
||||
path = '/api/v1/blocks'
|
||||
path = `/api/v1/blocks?parent_id=${encodeURIComponent(parentId)}`
|
||||
}
|
||||
return this.getBlocksWithPath(path)
|
||||
}
|
||||
|
||||
async getBlocksWithType(type: string): Promise<IBlock[]> {
|
||||
const path = `/api/v1/blocks?type=${encodeURIComponent(type)}`
|
||||
return this.getBlocksWithPath(path)
|
||||
}
|
||||
|
||||
private async getBlocksWithPath(path: string): Promise<IBlock[]> {
|
||||
const response = await fetch(this.serverUrl + path)
|
||||
const blocks = (await response.json() || []) as IMutableBlock[]
|
||||
this.fixBlocks(blocks)
|
||||
|
@ -141,8 +141,8 @@ export default class BoardPage extends React.Component<Props, State> {
|
||||
<WorkspaceComponent
|
||||
workspaceTree={workspaceTree}
|
||||
boardTree={this.state.boardTree}
|
||||
showView={(id) => {
|
||||
this.showView(id)
|
||||
showView={(id, boardId) => {
|
||||
this.showView(id, boardId)
|
||||
}}
|
||||
showBoard={(id) => {
|
||||
this.showBoard(id)
|
||||
@ -218,10 +218,15 @@ export default class BoardPage extends React.Component<Props, State> {
|
||||
this.attachToBoard(boardId)
|
||||
}
|
||||
|
||||
showView(viewId: string) {
|
||||
this.state.boardTree.setActiveView(viewId)
|
||||
this.setState({...this.state, viewId})
|
||||
const newUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + `?id=${encodeURIComponent(this.state.boardId)}&v=${encodeURIComponent(viewId)}`
|
||||
showView(viewId: string, boardId: string = this.state.boardId) {
|
||||
if (this.state.boardId !== boardId) {
|
||||
this.attachToBoard(boardId, viewId)
|
||||
} else {
|
||||
this.state.boardTree.setActiveView(viewId)
|
||||
this.setState({...this.state, viewId})
|
||||
}
|
||||
|
||||
const newUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + `?id=${encodeURIComponent(boardId)}&v=${encodeURIComponent(viewId)}`
|
||||
window.history.pushState({path: newUrl}, '', newUrl)
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export default class HomePage extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
loadBoards = async () => {
|
||||
const boards = await octoClient.getBlocks(null, 'board')
|
||||
const boards = await octoClient.getBlocksWithType('board')
|
||||
this.setState({boards})
|
||||
}
|
||||
|
||||
|
@ -4,21 +4,29 @@ import {Board} from '../blocks/board'
|
||||
import octoClient from '../octoClient'
|
||||
import {IBlock} from '../blocks/block'
|
||||
import {OctoUtils} from '../octoUtils'
|
||||
import {BoardView} from '../blocks/boardView'
|
||||
|
||||
interface WorkspaceTree {
|
||||
readonly boards: readonly Board[]
|
||||
readonly views: readonly BoardView[]
|
||||
}
|
||||
|
||||
class MutableWorkspaceTree {
|
||||
boards: Board[] = []
|
||||
views: BoardView[] = []
|
||||
|
||||
async sync() {
|
||||
const blocks = await octoClient.getBlocks(undefined, "board")
|
||||
this.rebuild(OctoUtils.hydrateBlocks(blocks))
|
||||
const boards = await octoClient.getBlocksWithType("board")
|
||||
const views = await octoClient.getBlocksWithType("view")
|
||||
this.rebuild(
|
||||
OctoUtils.hydrateBlocks(boards),
|
||||
OctoUtils.hydrateBlocks(views)
|
||||
)
|
||||
}
|
||||
|
||||
private rebuild(blocks: IBlock[]) {
|
||||
this.boards = blocks.filter(block => block.type === "board") as Board[]
|
||||
private rebuild(boards: IBlock[], views: IBlock[]) {
|
||||
this.boards = boards.filter(block => block.type === "board") as Board[]
|
||||
this.views = views.filter(block => block.type === "view") as BoardView[]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,12 +92,13 @@ hr {
|
||||
}
|
||||
|
||||
.octo-sidebar {
|
||||
flex: 0 0 230px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
min-height: 100%;
|
||||
background-color: rgb(247, 246, 243);
|
||||
min-width: 230px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
@ -109,6 +110,12 @@ hr {
|
||||
padding: 3px 20px;
|
||||
}
|
||||
|
||||
.octo-sidebar-item.subitem {
|
||||
color: rgba(25, 23, 18, 0.6);
|
||||
font-weight: 400;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.octo-sidebar-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user