1
0
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:
Chen-I Lim 2020-10-21 13:20:00 -07:00
parent 0b07f454bb
commit 277505e6f9
7 changed files with 90 additions and 56 deletions

View File

@ -8,10 +8,12 @@ import mutator from '../mutator'
import Menu from '../widgets/menu' import Menu from '../widgets/menu'
import MenuWrapper from '../widgets/menuWrapper' import MenuWrapper from '../widgets/menuWrapper'
import { WorkspaceTree } from '../viewModel/workspaceTree' import { WorkspaceTree } from '../viewModel/workspaceTree'
import { BoardView } from '../blocks/boardView'
type Props = { type Props = {
showBoard: (id: string) => void showBoard: (id: string) => void
showView: (id: string, boardId?: string) => void
workspaceTree: WorkspaceTree, workspaceTree: WorkspaceTree,
boardTree?: BoardTree boardTree?: BoardTree
} }
@ -23,24 +25,20 @@ class Sidebar extends React.Component<Props> {
return <div/> return <div/>
} }
const {boards} = workspaceTree const {boards, views} = workspaceTree
return ( return (
<div className='octo-sidebar'> <div className='octo-sidebar'>
{ {
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)
return ( return (
<div <div key={board.id}>
key={board.id} <div className='octo-sidebar-item octo-hover-container'>
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-sidebar-title'
onClick={() => {
this.boardClicked(board)
}}
>{board.icon ? `${board.icon} ${displayTitle}` : displayTitle}</div>
<div className='octo-spacer'/> <div className='octo-spacer'/>
<MenuWrapper> <MenuWrapper>
<div className='octo-button square octo-hover-item'><div className='imageOptions'/></div> <div className='octo-button square octo-hover-item'><div className='imageOptions'/></div>
@ -65,6 +63,14 @@ class Sidebar extends React.Component<Props> {
</Menu> </Menu>
</MenuWrapper> </MenuWrapper>
</div> </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) this.props.showBoard(board.id)
} }
private viewClicked(board: Board, view: BoardView) {
this.props.showView(view.id, board.id)
}
async addBoardClicked() { async addBoardClicked() {
const {boardTree, showBoard} = this.props const {boardTree, showBoard} = this.props
@ -127,4 +137,3 @@ class Sidebar extends React.Component<Props> {
} }
export { Sidebar } export { Sidebar }

View File

@ -14,20 +14,21 @@ type Props = {
workspaceTree: WorkspaceTree workspaceTree: WorkspaceTree
boardTree?: BoardTree boardTree?: BoardTree
showBoard: (id: string) => void showBoard: (id: string) => void
showView: (id: string) => void showView: (id: string, boardId?: string) => void
showFilter: (el: HTMLElement) => void showFilter: (el: HTMLElement) => void
setSearchText: (text: string) => void setSearchText: (text: string) => void
} }
class WorkspaceComponent extends React.Component<Props> { class WorkspaceComponent extends React.Component<Props> {
render() { render() {
const {boardTree, workspaceTree, showBoard} = this.props const {boardTree, workspaceTree, showBoard, showView} = this.props
Utils.assert(workspaceTree) Utils.assert(workspaceTree)
const element = const element =
(<div className='octo-workspace'> (<div className='octo-workspace'>
<Sidebar <Sidebar
showBoard={showBoard} showBoard={showBoard}
showView={showView}
workspaceTree={workspaceTree} workspaceTree={workspaceTree}
boardTree={boardTree} boardTree={boardTree}
/> />

View File

@ -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 let path: string
if (parentId && type) { if (type) {
path = `/api/v1/blocks?parent_id=${encodeURIComponent(parentId)}&type=${encodeURIComponent(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 { } 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 response = await fetch(this.serverUrl + path)
const blocks = (await response.json() || []) as IMutableBlock[] const blocks = (await response.json() || []) as IMutableBlock[]
this.fixBlocks(blocks) this.fixBlocks(blocks)

View File

@ -141,8 +141,8 @@ export default class BoardPage extends React.Component<Props, State> {
<WorkspaceComponent <WorkspaceComponent
workspaceTree={workspaceTree} workspaceTree={workspaceTree}
boardTree={this.state.boardTree} boardTree={this.state.boardTree}
showView={(id) => { showView={(id, boardId) => {
this.showView(id) this.showView(id, boardId)
}} }}
showBoard={(id) => { showBoard={(id) => {
this.showBoard(id) this.showBoard(id)
@ -218,10 +218,15 @@ export default class BoardPage extends React.Component<Props, State> {
this.attachToBoard(boardId) this.attachToBoard(boardId)
} }
showView(viewId: string) { showView(viewId: string, boardId: string = this.state.boardId) {
if (this.state.boardId !== boardId) {
this.attachToBoard(boardId, viewId)
} else {
this.state.boardTree.setActiveView(viewId) this.state.boardTree.setActiveView(viewId)
this.setState({...this.state, 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)}` }
const newUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + `?id=${encodeURIComponent(boardId)}&v=${encodeURIComponent(viewId)}`
window.history.pushState({path: newUrl}, '', newUrl) window.history.pushState({path: newUrl}, '', newUrl)
} }

View File

@ -28,7 +28,7 @@ export default class HomePage extends React.Component<Props, State> {
} }
loadBoards = async () => { loadBoards = async () => {
const boards = await octoClient.getBlocks(null, 'board') const boards = await octoClient.getBlocksWithType('board')
this.setState({boards}) this.setState({boards})
} }

View File

@ -4,21 +4,29 @@ import {Board} from '../blocks/board'
import octoClient from '../octoClient' import octoClient from '../octoClient'
import {IBlock} from '../blocks/block' import {IBlock} from '../blocks/block'
import {OctoUtils} from '../octoUtils' import {OctoUtils} from '../octoUtils'
import {BoardView} from '../blocks/boardView'
interface WorkspaceTree { interface WorkspaceTree {
readonly boards: readonly Board[] readonly boards: readonly Board[]
readonly views: readonly BoardView[]
} }
class MutableWorkspaceTree { class MutableWorkspaceTree {
boards: Board[] = [] boards: Board[] = []
views: BoardView[] = []
async sync() { async sync() {
const blocks = await octoClient.getBlocks(undefined, "board") const boards = await octoClient.getBlocksWithType("board")
this.rebuild(OctoUtils.hydrateBlocks(blocks)) const views = await octoClient.getBlocksWithType("view")
this.rebuild(
OctoUtils.hydrateBlocks(boards),
OctoUtils.hydrateBlocks(views)
)
} }
private rebuild(blocks: IBlock[]) { private rebuild(boards: IBlock[], views: IBlock[]) {
this.boards = blocks.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[]
} }
} }

View File

@ -92,12 +92,13 @@ hr {
} }
.octo-sidebar { .octo-sidebar {
flex: 0 0 230px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100%; min-height: 100%;
background-color: rgb(247, 246, 243); background-color: rgb(247, 246, 243);
min-width: 230px;
padding: 20px 0; padding: 20px 0;
} }
@ -109,6 +110,12 @@ hr {
padding: 3px 20px; padding: 3px 20px;
} }
.octo-sidebar-item.subitem {
color: rgba(25, 23, 18, 0.6);
font-weight: 400;
margin-left: 20px;
}
.octo-sidebar-title { .octo-sidebar-title {
cursor: pointer; cursor: pointer;
} }