From cd9e34499b4fba7b9805362f8707f403d48466cb Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Tue, 8 Dec 2020 10:57:36 -0800 Subject: [PATCH] Put shown cardId in url, to allow direct linking to cards --- webapp/src/components/boardComponent.tsx | 34 +++++++++++++++------- webapp/src/components/tableComponent.tsx | 37 +++++++++++++++++------- webapp/src/utils.ts | 16 ++++++++++ 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/webapp/src/components/boardComponent.tsx b/webapp/src/components/boardComponent.tsx index 194aa4571..e012072a8 100644 --- a/webapp/src/components/boardComponent.tsx +++ b/webapp/src/components/boardComponent.tsx @@ -72,6 +72,7 @@ class BoardComponent extends React.Component { } componentDidMount(): void { + this.showCardInUrl() document.addEventListener('keydown', this.keydownHandler) } @@ -99,6 +100,14 @@ class BoardComponent extends React.Component { } } + 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 {boardTree, showView} = this.props const {groupByProperty} = boardTree @@ -129,8 +138,8 @@ class BoardComponent extends React.Component { key={this.state.shownCardId} boardTree={boardTree} cardId={this.state.shownCardId} - onClose={() => this.setState({shownCardId: undefined})} - showCard={(cardId) => this.setState({shownCardId: cardId})} + onClose={() => this.showCard(undefined)} + showCard={(cardId) => this.showCard(cardId)} /> } @@ -482,10 +491,10 @@ class BoardComponent extends React.Component { this.props.intl.formatMessage({id: 'Mutator.new-card-from-template', defaultMessage: 'new card from template'}), false, async (newCardId) => { - this.setState({shownCardId: newCardId}) + this.showCard(newCardId) }, async () => { - this.setState({shownCardId: undefined}) + this.showCard(undefined) }, ) } @@ -514,10 +523,10 @@ class BoardComponent extends React.Component { card, 'add card', async () => { - this.setState({shownCardId: card.id}) + this.showCard(card.id) }, async () => { - this.setState({shownCardId: undefined}) + this.showCard(undefined) }, ) } @@ -533,15 +542,15 @@ class BoardComponent extends React.Component { cardTemplate, 'add card template', async () => { - this.setState({shownCardId: cardTemplate.id}) + this.showCard(cardTemplate.id) }, async () => { - this.setState({shownCardId: undefined}) + this.showCard(undefined) }, ) } private editCardTemplate = (cardTemplateId: string) => { - this.setState({shownCardId: cardTemplateId}) + this.showCard(cardTemplateId) } private async propertyNameChanged(option: IPropertyOption, text: string): Promise { @@ -577,12 +586,17 @@ class BoardComponent extends React.Component { this.setState({selectedCardIds}) } } else { - this.setState({selectedCardIds: [], shownCardId: card.id}) + this.showCard(card.id) } e.stopPropagation() } + private showCard = (cardId?: string) => { + Utils.replaceUrlQueryParam('c', cardId) + this.setState({selectedCardIds: [], shownCardId: cardId}) + } + private addGroupClicked = async () => { Utils.log('onAddGroupClicked') diff --git a/webapp/src/components/tableComponent.tsx b/webapp/src/components/tableComponent.tsx index 5111092ff..e30ec4131 100644 --- a/webapp/src/components/tableComponent.tsx +++ b/webapp/src/components/tableComponent.tsx @@ -45,6 +45,18 @@ class TableComponent extends React.Component { return true } + componentDidMount(): void { + this.showCardInUrl() + } + + 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 {boardTree, showView} = this.props const {board, cards, activeView} = boardTree @@ -66,8 +78,8 @@ class TableComponent extends React.Component { key={this.state.shownCardId} boardTree={boardTree} cardId={this.state.shownCardId} - onClose={() => this.setState({shownCardId: undefined})} - showCard={(cardId) => this.setState({shownCardId: cardId})} + onClose={() => this.showCard(undefined)} + showCard={(cardId) => this.showCard(cardId)} /> }
@@ -263,9 +275,7 @@ class TableComponent extends React.Component { this.addCard(false) } }} - showCard={(cardId) => { - this.setState({shownCardId: cardId}) - }} + showCard={this.showCard} />) this.cardIdToRowMap.set(card.id, tableRowRef) @@ -295,6 +305,11 @@ class TableComponent extends React.Component { ) } + private showCard = (cardId?: string) => { + Utils.replaceUrlQueryParam('c', cardId) + this.setState({shownCardId: cardId}) + } + private columnWidth(templateId: string): number { return Math.max(Constants.minColumnWidth, this.props.boardTree.activeView.columnWidths[templateId] || 0) } @@ -309,10 +324,10 @@ class TableComponent extends React.Component { this.props.intl.formatMessage({id: 'Mutator.new-card-from-template', defaultMessage: 'new card from template'}), false, async (newCardId) => { - this.setState({shownCardId: newCardId}) + this.showCard(newCardId) }, async () => { - this.setState({shownCardId: undefined}) + this.showCard(undefined) }, ) } @@ -332,7 +347,7 @@ class TableComponent extends React.Component { 'add card', async () => { if (show) { - this.setState({shownCardId: card.id}) + this.showCard(card.id) } else { // Focus on this card's title inline on next render this.cardIdToFocusOnRender = card.id @@ -352,15 +367,15 @@ class TableComponent extends React.Component { cardTemplate, 'add card template', async () => { - this.setState({shownCardId: cardTemplate.id}) + this.showCard(cardTemplate.id) }, async () => { - this.setState({shownCardId: undefined}) + this.showCard(undefined) }, ) } private editCardTemplate = (cardTemplateId: string) => { - this.setState({shownCardId: cardTemplateId}) + this.showCard(cardTemplateId) } private async onDropToColumn(template: IPropertyTemplate) { diff --git a/webapp/src/utils.ts b/webapp/src/utils.ts index f9361589d..7d3c64f3f 100644 --- a/webapp/src/utils.ts +++ b/webapp/src/utils.ts @@ -131,6 +131,22 @@ class Utils { document.getElementsByTagName('head')[0].appendChild(link) } + // URL + + static replaceUrlQueryParam(paramName: string, value?: string): void { + const queryString = new URLSearchParams(window.location.search) + const currentValue = queryString.get(paramName) || '' + if (currentValue !== value) { + const newUrl = new URL(window.location.toString()) + if (value) { + newUrl.searchParams.set(paramName, value) + } else { + newUrl.searchParams.delete(paramName) + } + window.history.pushState({}, document.title, newUrl.toString()) + } + } + // File names static sanitizeFilename(filename: string): string {