Show workspace title in sidebar

This commit is contained in:
Chen-I Lim 2021-03-30 15:25:16 -07:00
parent 83ca65a7e6
commit 7be7bed916
8 changed files with 40 additions and 12 deletions

View file

@ -35,6 +35,7 @@ const (
type WorkspaceAuthenticator interface { type WorkspaceAuthenticator interface {
DoesUserHaveWorkspaceAccess(session *model.Session, workspaceID string) bool DoesUserHaveWorkspaceAccess(session *model.Session, workspaceID string) bool
GetWorkspace(session *model.Session, workspaceID string) *model.Workspace
} }
type API struct { type API struct {
@ -902,8 +903,11 @@ func (a *API) handleGetWorkspace(w http.ResponseWriter, r *http.Request) {
errorResponse(w, http.StatusUnauthorized, "", nil) errorResponse(w, http.StatusUnauthorized, "", nil)
return return
} }
workspace = &model.Workspace{
ID: workspaceID, workspace = a.WorkspaceAuthenticator.GetWorkspace(session, workspaceID)
if workspace == nil {
errorResponse(w, http.StatusUnauthorized, "", nil)
return
} }
} else { } else {
workspace, err = a.app().GetRootWorkspace() workspace, err = a.app().GetRootWorkspace()

View file

@ -8,6 +8,7 @@ import (
type MattermostAuth interface { type MattermostAuth interface {
RegisterRoutes(*mux.Router) RegisterRoutes(*mux.Router)
DoesUserHaveWorkspaceAccess(session *model.Session, workspaceID string) bool DoesUserHaveWorkspaceAccess(session *model.Session, workspaceID string) bool
GetWorkspace(session *model.Session, workspaceID string) *model.Workspace
} }
type MattermostAuthParameters struct { type MattermostAuthParameters struct {

View file

@ -7,6 +7,10 @@ type Workspace struct {
// required: true // required: true
ID string `json:"id"` ID string `json:"id"`
// Title of the workspace
// required: false
Title string `json:"title"`
// Token required to register new users // Token required to register new users
// required: true // required: true
SignupToken string `json:"signupToken"` SignupToken string `json:"signupToken"`

View file

@ -2,6 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
interface IWorkspace { interface IWorkspace {
readonly id: string, readonly id: string,
readonly title: string,
readonly signupToken: string, readonly signupToken: string,
readonly settings: Readonly<Record<string, any>> readonly settings: Readonly<Record<string, any>>
readonly modifiedBy?: string, readonly modifiedBy?: string,

View file

@ -39,6 +39,11 @@
} }
} }
.WorkspaceTitle {
padding: 0 16px;
font-weight: 600;
}
.octo-sidebar-list { .octo-sidebar-list {
flex: 1 1 auto; flex: 1 1 auto;
overflow-y: auto; overflow-y: auto;

View file

@ -1,7 +1,8 @@
// 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, {useState, useEffect} from 'react' import React, {useEffect, useState} from 'react'
import {IWorkspace} from '../../blocks/workspace'
import {loadTheme} from '../../theme' import {loadTheme} from '../../theme'
import {WorkspaceTree} from '../../viewModel/workspaceTree' import {WorkspaceTree} from '../../viewModel/workspaceTree'
import IconButton from '../../widgets/buttons/iconButton' import IconButton from '../../widgets/buttons/iconButton'
@ -9,13 +10,14 @@ import HamburgerIcon from '../../widgets/icons/hamburger'
import HideSidebarIcon from '../../widgets/icons/hideSidebar' import HideSidebarIcon from '../../widgets/icons/hideSidebar'
import ShowSidebarIcon from '../../widgets/icons/showSidebar' import ShowSidebarIcon from '../../widgets/icons/showSidebar'
import SidebarSettingsMenu from './sidebarSettingsMenu' import './sidebar.scss'
import SidebarAddBoardMenu from './sidebarAddBoardMenu' import SidebarAddBoardMenu from './sidebarAddBoardMenu'
import SidebarBoardItem from './sidebarBoardItem' import SidebarBoardItem from './sidebarBoardItem'
import SidebarSettingsMenu from './sidebarSettingsMenu'
import SidebarUserMenu from './sidebarUserMenu' import SidebarUserMenu from './sidebarUserMenu'
import './sidebar.scss'
type Props = { type Props = {
workspace?: IWorkspace
showBoard: (id?: string) => void showBoard: (id?: string) => void
showView: (id: string, boardId?: string) => void showView: (id: string, boardId?: string) => void
workspaceTree: WorkspaceTree, workspaceTree: WorkspaceTree,
@ -35,7 +37,7 @@ const Sidebar = React.memo((props: Props) => {
} }
}, []) }, [])
const {workspaceTree} = props const {workspace, workspaceTree} = props
if (!workspaceTree) { if (!workspaceTree) {
return <div/> return <div/>
} }
@ -76,6 +78,11 @@ const Sidebar = React.memo((props: Props) => {
icon={<HideSidebarIcon/>} icon={<HideSidebarIcon/>}
/> />
</div> </div>
{workspace && workspace.id !== '0' &&
<div className='WorkspaceTitle'>
{workspace.title}
</div>
}
<div className='octo-sidebar-list'> <div className='octo-sidebar-list'>
{ {
boards.map((board) => { boards.map((board) => {

View file

@ -3,15 +3,17 @@
import React from 'react' import React from 'react'
import {FormattedMessage} from 'react-intl' import {FormattedMessage} from 'react-intl'
import {IWorkspace} from '../blocks/workspace'
import {Utils} from '../utils' import {Utils} from '../utils'
import {BoardTree} from '../viewModel/boardTree' import {BoardTree} from '../viewModel/boardTree'
import {WorkspaceTree} from '../viewModel/workspaceTree' import {WorkspaceTree} from '../viewModel/workspaceTree'
import Sidebar from './sidebar/sidebar'
import CenterPanel from './centerPanel' import CenterPanel from './centerPanel'
import Sidebar from './sidebar/sidebar'
import './workspace.scss' import './workspace.scss'
type Props = { type Props = {
workspace?: IWorkspace
workspaceTree: WorkspaceTree workspaceTree: WorkspaceTree
boardTree?: BoardTree boardTree?: BoardTree
showBoard: (id?: string) => void showBoard: (id?: string) => void
@ -22,7 +24,7 @@ type Props = {
} }
const Workspace = React.memo((props: Props) => { const Workspace = React.memo((props: Props) => {
const {boardTree, setSearchText, workspaceTree, showBoard, showView, setLanguage} = props const {workspace, boardTree, setSearchText, workspaceTree, showBoard, showView, setLanguage} = props
const {activeView} = boardTree || {} const {activeView} = boardTree || {}
Utils.assert(workspaceTree || !props.readonly) Utils.assert(workspaceTree || !props.readonly)
@ -31,6 +33,7 @@ const Workspace = React.memo((props: Props) => {
<div className='Workspace'> <div className='Workspace'>
{!props.readonly && {!props.readonly &&
<Sidebar <Sidebar
workspace={workspace}
showBoard={showBoard} showBoard={showBoard}
showView={showView} showView={showView}
workspaceTree={workspaceTree} workspaceTree={workspaceTree}

View file

@ -4,6 +4,7 @@ import React from 'react'
import {injectIntl, IntlShape} from 'react-intl' import {injectIntl, IntlShape} from 'react-intl'
import {IBlock} from '../blocks/block' import {IBlock} from '../blocks/block'
import {IWorkspace} from '../blocks/workspace'
import {sendFlashMessage} from '../components/flashMessages' import {sendFlashMessage} from '../components/flashMessages'
import Workspace from '../components/workspace' import Workspace from '../components/workspace'
import mutator from '../mutator' import mutator from '../mutator'
@ -24,6 +25,7 @@ type Props = {
type State = { type State = {
boardId: string boardId: string
viewId: string viewId: string
workspace?: IWorkspace,
workspaceTree: WorkspaceTree workspaceTree: WorkspaceTree
boardTree?: BoardTree boardTree?: BoardTree
syncFailed?: boolean syncFailed?: boolean
@ -143,7 +145,7 @@ class BoardPage extends React.Component<Props, State> {
render(): JSX.Element { render(): JSX.Element {
const {intl} = this.props const {intl} = this.props
const {workspaceTree} = this.state const {workspace, workspaceTree} = this.state
Utils.log(`BoardPage.render (workspace ${this.props.workspaceId}) ${this.state.boardTree?.board?.title}`) Utils.log(`BoardPage.render (workspace ${this.props.workspaceId}) ${this.state.boardTree?.board?.title}`)
@ -164,6 +166,7 @@ class BoardPage extends React.Component<Props, State> {
return ( return (
<div className='BoardPage'> <div className='BoardPage'>
<Workspace <Workspace
workspace={workspace}
workspaceTree={workspaceTree} workspaceTree={workspaceTree}
boardTree={this.state.boardTree} boardTree={this.state.boardTree}
showView={(id, boardId) => { showView={(id, boardId) => {
@ -202,10 +205,10 @@ class BoardPage extends React.Component<Props, State> {
private async sync(boardId: string = this.state.boardId, viewId: string | undefined = this.state.viewId) { private async sync(boardId: string = this.state.boardId, viewId: string | undefined = this.state.viewId) {
Utils.log(`sync start: ${boardId}`) Utils.log(`sync start: ${boardId}`)
let workspace: IWorkspace | undefined
if (!this.props.readonly) { if (!this.props.readonly) {
// Require workspace for editing, not for sharing (readonly) // Require workspace for editing, not for sharing (readonly)
workspace = await octoClient.getWorkspace()
const workspace = await octoClient.getWorkspace()
if (!workspace) { if (!workspace) {
location.href = '/error?id=no_workspace' location.href = '/error?id=no_workspace'
} }
@ -213,7 +216,7 @@ class BoardPage extends React.Component<Props, State> {
const workspaceTree = await MutableWorkspaceTree.sync() const workspaceTree = await MutableWorkspaceTree.sync()
const boardIds = [...workspaceTree.boards.map((o) => o.id), ...workspaceTree.boardTemplates.map((o) => o.id)] const boardIds = [...workspaceTree.boards.map((o) => o.id), ...workspaceTree.boardTemplates.map((o) => o.id)]
this.setState({workspaceTree}) this.setState({workspace, workspaceTree})
let boardIdsToListen: string[] let boardIdsToListen: string[]
if (boardIds.length > 0) { if (boardIds.length > 0) {