Use card id in the url (#1050)
* Use card id in the url * Fix linter error Co-authored-by: Hossein <hahmadia@users.noreply.github.com>
This commit is contained in:
parent
55e506bd0e
commit
171164ec6d
4 changed files with 53 additions and 38 deletions
|
@ -78,7 +78,7 @@ const App = React.memo((): JSX.Element => {
|
|||
<Route path='/shared/:boardId?/:viewId?'>
|
||||
<BoardPage readonly={true}/>
|
||||
</Route>
|
||||
<Route path='/board/:boardId?/:viewId?'>
|
||||
<Route path='/board/:boardId?/:viewId?/:cardId?'>
|
||||
{loggedIn === false && <Redirect to='/login'/>}
|
||||
{loggedIn === true && <BoardPage/>}
|
||||
</Route>
|
||||
|
@ -86,7 +86,7 @@ const App = React.memo((): JSX.Element => {
|
|||
<BoardPage readonly={true}/>
|
||||
</Route>
|
||||
<Route
|
||||
path='/workspace/:workspaceId/:boardId?/:viewId?'
|
||||
path='/workspace/:workspaceId/:boardId?/:viewId?/:cardId?'
|
||||
render={({match}) => {
|
||||
if (loggedIn === false) {
|
||||
let redirectUrl = '/' + Utils.buildURL(`/workspace/${match.params.workspaceId}/`)
|
||||
|
@ -109,7 +109,7 @@ const App = React.memo((): JSX.Element => {
|
|||
>
|
||||
<DashboardPage/>
|
||||
</Route>
|
||||
<Route path='/:boardId?/:viewId?'>
|
||||
<Route path='/:boardId?/:viewId?/:cardId?'>
|
||||
{loggedIn === false && <Redirect to='/login'/>}
|
||||
{loggedIn === true && <BoardPage/>}
|
||||
</Route>
|
||||
|
|
|
@ -37,10 +37,11 @@ type Props = {
|
|||
readonly: boolean
|
||||
addCard: (card: Card) => void
|
||||
addTemplate: (template: Card) => void
|
||||
shownCardId?: string
|
||||
showCard: (cardId?: string) => void
|
||||
}
|
||||
|
||||
type State = {
|
||||
shownCardId?: string
|
||||
selectedCardIds: string[]
|
||||
cardIdToFocusOnRender: string
|
||||
}
|
||||
|
@ -77,10 +78,6 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.showCardInUrl()
|
||||
}
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -93,14 +90,6 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
return true
|
||||
}
|
||||
|
||||
private showCardInUrl() {
|
||||
const queryString = new URLSearchParams(window.location.search)
|
||||
const cardId = queryString.get('c') || undefined
|
||||
if (cardId !== this.state.shownCardId) {
|
||||
this.setState({shownCardId: cardId})
|
||||
}
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const {groupByProperty, activeView, board, views, cards} = this.props
|
||||
const {visible: visibleGroups, hidden: hiddenGroups} = this.getVisibleAndHiddenGroups(cards, activeView.fields.visibleOptionIds, activeView.fields.hiddenOptionIds, groupByProperty)
|
||||
|
@ -117,15 +106,15 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
keyName='ctrl+d,del,esc,backspace'
|
||||
onKeyDown={this.keydownHandler}
|
||||
/>
|
||||
{this.state.shownCardId &&
|
||||
{this.props.shownCardId &&
|
||||
<RootPortal>
|
||||
<CardDialog
|
||||
board={board}
|
||||
activeView={activeView}
|
||||
views={views}
|
||||
cards={cards}
|
||||
key={this.state.shownCardId}
|
||||
cardId={this.state.shownCardId}
|
||||
key={this.props.shownCardId}
|
||||
cardId={this.props.shownCardId}
|
||||
onClose={() => this.showCard(undefined)}
|
||||
showCard={(cardId) => this.showCard(cardId)}
|
||||
readonly={this.props.readonly}
|
||||
|
@ -316,8 +305,8 @@ class CenterPanel extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private showCard = (cardId?: string) => {
|
||||
Utils.replaceUrlQueryParam('c', cardId)
|
||||
this.setState({selectedCardIds: [], shownCardId: cardId})
|
||||
this.setState({selectedCardIds: []})
|
||||
this.props.showCard(cardId)
|
||||
}
|
||||
|
||||
private async deleteSelectedCards() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
import {useRouteMatch} from 'react-router-dom'
|
||||
import React, {useCallback} from 'react'
|
||||
import {generatePath, useRouteMatch, useHistory} from 'react-router-dom'
|
||||
import {FormattedMessage} from 'react-intl'
|
||||
|
||||
import {getCurrentBoard} from '../store/boards'
|
||||
|
@ -19,12 +19,19 @@ type Props = {
|
|||
}
|
||||
|
||||
function CenterContent(props: Props) {
|
||||
const match = useRouteMatch<{boardId: string, viewId: string}>()
|
||||
const match = useRouteMatch<{boardId: string, viewId: string, cardId?: string}>()
|
||||
const board = useAppSelector(getCurrentBoard)
|
||||
const cards = useAppSelector(getCurrentViewCardsSortedFilteredAndGrouped)
|
||||
const activeView = useAppSelector(getView(match.params.viewId))
|
||||
const views = useAppSelector(getCurrentBoardViews)
|
||||
const groupByProperty = useAppSelector(getCurrentViewGroupBy)
|
||||
const history = useHistory()
|
||||
|
||||
const showCard = useCallback((cardId?: string) => {
|
||||
const params = {...match.params, cardId}
|
||||
const newPath = generatePath(match.path, params)
|
||||
history.push(newPath)
|
||||
}, [match, history])
|
||||
|
||||
if (board && activeView) {
|
||||
let property = groupByProperty
|
||||
|
@ -36,6 +43,8 @@ function CenterContent(props: Props) {
|
|||
readonly={props.readonly}
|
||||
board={board}
|
||||
cards={cards}
|
||||
shownCardId={match.params.cardId}
|
||||
showCard={showCard}
|
||||
activeView={activeView}
|
||||
groupByProperty={property}
|
||||
views={views}
|
||||
|
|
|
@ -42,7 +42,7 @@ const BoardPage = (props: Props) => {
|
|||
const dispatch = useAppDispatch()
|
||||
|
||||
const history = useHistory()
|
||||
const match = useRouteMatch<{boardId: string, viewId: string, workspaceId?: string}>()
|
||||
const match = useRouteMatch<{boardId: string, viewId: string, cardId?: string, workspaceId?: string}>()
|
||||
const [websocketClosed, setWebsocketClosed] = useState(false)
|
||||
|
||||
// TODO: Make this less brittle. This only works because this is the root render function
|
||||
|
@ -53,20 +53,37 @@ const BoardPage = (props: Props) => {
|
|||
// Backward compatibility: This can be removed in the future, this is for
|
||||
// transform the old query params into routes
|
||||
useEffect(() => {
|
||||
const queryString = new URLSearchParams(window.location.search)
|
||||
const queryBoardId = queryString.get('id')
|
||||
const queryViewId = queryString.get('v')
|
||||
if (queryBoardId) {
|
||||
const params = {...match.params, boardId: queryBoardId}
|
||||
if (queryViewId) {
|
||||
params.viewId = queryViewId
|
||||
}
|
||||
const newPath = generatePath(match.path, params)
|
||||
history.replace(newPath)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// Backward compatibility: This can be removed in the future, this is for
|
||||
// transform the old query params into routes
|
||||
const queryString = new URLSearchParams(history.location.search)
|
||||
const queryBoardId = queryString.get('id')
|
||||
const params = {...match.params}
|
||||
let needsRedirect = false
|
||||
if (queryBoardId) {
|
||||
params.boardId = queryBoardId
|
||||
needsRedirect = true
|
||||
}
|
||||
const queryViewId = queryString.get('v')
|
||||
if (queryViewId) {
|
||||
params.viewId = queryViewId
|
||||
needsRedirect = true
|
||||
}
|
||||
const queryCardId = queryString.get('c')
|
||||
if (queryCardId) {
|
||||
params.cardId = queryCardId
|
||||
needsRedirect = true
|
||||
}
|
||||
if (needsRedirect) {
|
||||
const newPath = generatePath(match.path, params)
|
||||
history.replace(newPath)
|
||||
return
|
||||
}
|
||||
|
||||
// Backward compatibility end
|
||||
|
||||
const boardId = match.params.boardId
|
||||
const viewId = match.params.viewId
|
||||
|
||||
|
@ -96,7 +113,7 @@ const BoardPage = (props: Props) => {
|
|||
UserSettings.lastViewId = viewId || ''
|
||||
dispatch(setCurrentBoard(boardId || ''))
|
||||
dispatch(setCurrentView(viewId || ''))
|
||||
}, [match.params.boardId, match.params.viewId, history, boardViews])
|
||||
}, [match.params.boardId, match.params.viewId, boardViews])
|
||||
|
||||
useEffect(() => {
|
||||
Utils.setFavicon(board?.fields.icon)
|
||||
|
@ -119,7 +136,7 @@ const BoardPage = (props: Props) => {
|
|||
let token = localStorage.getItem('focalboardSessionId') || ''
|
||||
if (props.readonly) {
|
||||
loadAction = initialReadOnlyLoad
|
||||
const queryString = new URLSearchParams(window.location.search)
|
||||
const queryString = new URLSearchParams(history.location.search)
|
||||
token = token || queryString.get('r') || ''
|
||||
}
|
||||
dispatch(loadAction(match.params.boardId))
|
||||
|
|
Loading…
Reference in a new issue