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:
Jesús Espino 2021-08-26 11:27:06 +02:00 committed by GitHub
parent 55e506bd0e
commit 171164ec6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 38 deletions

View file

@ -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>

View file

@ -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() {

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 {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}

View file

@ -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))