From dbfde1a2382f9396032bfb80155ee03b740c6b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 24 Jan 2023 19:57:04 +0100 Subject: [PATCH] Fixing some things --- mattermost-plugin/webapp/src/rhsCard.tsx | 88 ++++++++++------ webapp/src/hooks/connectToBoard.tsx | 126 +++++++++++------------ 2 files changed, 116 insertions(+), 98 deletions(-) diff --git a/mattermost-plugin/webapp/src/rhsCard.tsx b/mattermost-plugin/webapp/src/rhsCard.tsx index a569130d9..0d890aa62 100644 --- a/mattermost-plugin/webapp/src/rhsCard.tsx +++ b/mattermost-plugin/webapp/src/rhsCard.tsx @@ -1,14 +1,17 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect} from 'react' +import React, {useEffect, useCallback} from 'react' import {Provider as ReduxProvider} from 'react-redux' -import {IntlProvider} from 'react-intl' +import {IntlProvider, useIntl} from 'react-intl' import {DndProvider} from 'react-dnd' import {HTML5Backend} from 'react-dnd-html5-backend' import {TouchBackend} from 'react-dnd-touch-backend' import store from '../../../webapp/src/store' -import {updateCards, getRHSCardID, getRHSCard, getRHSBoardID} from '../../../webapp/src/store/cards' +import {getRHSCard, getRHSBoardID} from '../../../webapp/src/store/cards' +import {getCardAttachments} from '../../../webapp/src/store/attachments' +import mutator from '../../../webapp/src/mutator' + import {getBoard} from '../../../webapp/src/store/boards' import {Block} from '../../../webapp/src/blocks/block' import {fetchMe, getMe} from '../../../webapp/src/store/users' @@ -20,11 +23,10 @@ import {loadBoardData} from '../../../webapp/src/store/initialLoad' import {useAppSelector} from '../../../webapp/src/store/hooks' import {getMessages} from '../../../webapp/src/i18n' import CardDetail from '../../../webapp/src/components/cardDetail/cardDetail' +import {sendFlashMessage} from '../../../webapp/src/components/flashMessages' import useConnectToBoard from '../../../webapp/src/hooks/connectToBoard' import {Utils} from '../../../webapp/src/utils' -import octoClient from '../../../webapp/src/octoClient' - import '../../../webapp/src/styles/variables.scss' import '../../../webapp/src/styles/main.scss' import '../../../webapp/src/styles/labels.scss' @@ -40,8 +42,9 @@ const RHSCardContent = () => { const views = useAppSelector(getViewsByBoard) const comments = useAppSelector(getCardComments(card?.id)) const contents = useAppSelector(getCardContents(card?.id)) - const language = useAppSelector(getLanguage) const activeView = views[boardID] && views[boardID][0] + const attachments = useAppSelector(getCardAttachments(card.id)) + const intl = useIntl() useEffect(() => { if (boardID) { @@ -51,34 +54,63 @@ const RHSCardContent = () => { } }, [boardID]) + const deleteBlock = useCallback(async (block: Block) => { + if (!card) { + return + } + const description = intl.formatMessage({id: 'AttachmentBlock.DeleteAction', defaultMessage: 'delete'}) + await mutator.deleteBlock(block, description) + sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.delete', defaultMessage: 'Attachment Deleted Successfully.'}), severity: 'normal'}) + }, [card?.boardId, card?.id, card?.fields.contentOrder]) + // TODO: Check the permissions here const readonly = false - useConnectToBoard(store.dispatch, '', me?.id || '', boardID || '', Boolean(readonly), boardID || '') + useConnectToBoard(store.dispatch, me?.id || '', boardID || '', Boolean(readonly), boardID || '') if (!board || !card || !activeView) { return null } + return ( + {}} + onClose={() => {}} + /> + ) +} + +const RHSCardWithIntl = () => { + const language = useAppSelector(getLanguage) + return ( - {}} - onClose={() => {}} - addAttachment={() => {}} - /> +
e.stopPropagation()} + onKeyPress={(e: React.KeyboardEvent) => e.stopPropagation()} + onKeyUp={(e: React.KeyboardEvent) => e.stopPropagation()} + > + {/* TODO: Remove this hack to avoid the capture of the cursor by the create post component */} +
+ +
) } @@ -87,19 +119,7 @@ const RHSCard = () => { return ( -
e.stopPropagation()} - onKeyPress={(e: React.KeyboardEvent) => e.stopPropagation()} - onKeyUp={(e: React.KeyboardEvent) => e.stopPropagation()} - > - {/* TODO: Remove this hack to avoid the capture of the cursor by the create post component */} -
- -
+ ) diff --git a/webapp/src/hooks/connectToBoard.tsx b/webapp/src/hooks/connectToBoard.tsx index 2d76adfce..f610eff65 100644 --- a/webapp/src/hooks/connectToBoard.tsx +++ b/webapp/src/hooks/connectToBoard.tsx @@ -1,87 +1,89 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {useEffect, useState} from 'react' +import {useMemo} from 'react' import {batch} from 'react-redux' import {Block} from '../blocks/block' import {ContentBlock} from '../blocks/contentBlock' +import {AttachmentBlock} from '../blocks/attachmentBlock' +import {Utils} from '../utils' import {CommentBlock} from '../blocks/commentBlock' -import {Board} from '../blocks/board' +import {Board, BoardMember} from '../blocks/board' import {Card} from '../blocks/card' import {BoardView} from '../blocks/boardView' -import wsClient, {Subscription, WSClient} from '../wsclient' -import {updateBoards} from '../store/boards' +import {Subscription, WSClient} from '../wsclient' +import { + updateBoards, + updateMembersEnsuringBoardsAndUsers, + fetchBoardMembers, + addMyBoardMemberships, +} from '../store/boards' import {updateViews} from '../store/views' import {updateCards} from '../store/cards' import {updateContents} from '../store/contents' import {updateComments} from '../store/comments' +import {updateAttachments} from '../store/attachments' import {followBlock, unfollowBlock} from '../store/users' import {initialLoad, initialReadOnlyLoad} from '../store/initialLoad' +import {Constants} from '../constants' -const websocketTimeoutForBanner = 5000 +import {useWebsockets} from './websockets' -export default function useConnectToBoard(dispatch: any, readToken: string, myID: string, teamId: string|undefined, readonly: boolean, boardId: string): void { - const [websocketClosed, setWebsocketClosed] = useState(false) - useEffect(() => { - let loadAction: any = initialLoad /* eslint-disable-line @typescript-eslint/no-explicit-any */ - let token = localStorage.getItem('focalboardSessionId') || '' +export default function useConnectToBoard(dispatch: any, myID: string, teamId: string, readonly: boolean, boardId: string): void { + const loadAction: (boardId: string) => any = useMemo(() => { if (readonly) { - loadAction = initialReadOnlyLoad - token = token || readToken || '' + return initialReadOnlyLoad } + return initialLoad + }, [readonly]) - dispatch(loadAction(boardId)) + useWebsockets(teamId, (wsClient: WSClient) =>{ + const incrementalBlockUpdate = (_: WSClient, blocks: Block[]) => { + const teamBlocks = blocks - let subscribedToTeam = false - if (wsClient.state === 'open') { - wsClient.authenticate(token) - wsClient.subscribeToTeam(teamId || '0') - subscribedToTeam = true - } - - const incrementalUpdateBoard = (_: WSClient, boards: Board[]) => { - // only takes into account the boards that belong to the team - const teamBoards = boards.filter((b: Board) => b.teamId === '0' || b.teamId === teamId) - dispatch(updateBoards(teamBoards.filter((b: Board) => b.deleteAt !== 0))) - } - - const incrementalUpdateBlock = (_: WSClient, blocks: Block[]) => { batch(() => { - dispatch(updateViews(blocks.filter((b: Block) => b.type === 'view' || b.deleteAt !== 0) as BoardView[])) - dispatch(updateCards(blocks.filter((b: Block) => b.type === 'card' || b.deleteAt !== 0) as Card[])) - dispatch(updateComments(blocks.filter((b: Block) => b.type === 'comment' || b.deleteAt !== 0) as CommentBlock[])) - dispatch(updateContents(blocks.filter((b: Block) => b.type !== 'card' && b.type !== 'view' && b.type !== 'board' && b.type !== 'comment') as ContentBlock[])) + dispatch(updateViews(teamBlocks.filter((b: Block) => b.type === 'view' || b.deleteAt !== 0) as BoardView[])) + dispatch(updateCards(teamBlocks.filter((b: Block) => b.type === 'card' || b.deleteAt !== 0) as Card[])) + dispatch(updateComments(teamBlocks.filter((b: Block) => b.type === 'comment' || b.deleteAt !== 0) as CommentBlock[])) + dispatch(updateAttachments(teamBlocks.filter((b: Block) => b.type === 'attachment' || b.deleteAt !== 0) as AttachmentBlock[])) + dispatch(updateContents(teamBlocks.filter((b: Block) => b.type !== 'card' && b.type !== 'view' && b.type !== 'board' && b.type !== 'comment' && b.type !== 'attachment') as ContentBlock[])) }) } - let timeout: ReturnType - const updateWebsocketState = (_: WSClient, newState: 'init'|'open'|'close'): void => { - if (newState === 'open') { - const newToken = localStorage.getItem('focalboardSessionId') || '' - wsClient.authenticate(newToken) - wsClient.subscribeToTeam(teamId || '0') - subscribedToTeam = true - } + const incrementalBoardUpdate = (_: WSClient, boards: Board[]) => { + // only takes into account the entities that belong to the team or the user boards + const teamBoards = boards.filter((b: Board) => b.teamId === Constants.globalTeamId || b.teamId === teamId) + const activeBoard = teamBoards.find((b: Board) => b.id === boardId) + dispatch(updateBoards(teamBoards)) - if (timeout) { - clearTimeout(timeout) - } - - if (newState === 'close') { - timeout = setTimeout(() => { - setWebsocketClosed(true) - subscribedToTeam = false - }, websocketTimeoutForBanner) - } else { - setWebsocketClosed(false) + if (activeBoard) { + dispatch(fetchBoardMembers({ + teamId, + boardId: boardId, + })) } } - wsClient.addOnChange(incrementalUpdateBoard, 'board') - wsClient.addOnChange(incrementalUpdateBlock, 'block') - wsClient.addOnReconnect(() => dispatch(loadAction(boardId))) - wsClient.addOnStateChange(updateWebsocketState) + const incrementalBoardMemberUpdate = (_: WSClient, members: BoardMember[]) => { + dispatch(updateMembersEnsuringBoardsAndUsers(members)) + + if (myID) { + const myBoardMemberships = members.filter((boardMember) => boardMember.userId === myID) + dispatch(addMyBoardMemberships(myBoardMemberships)) + } + } + + const dispatchLoadAction = () => { + dispatch(loadAction(boardId)) + } + + Utils.log('useWEbsocket adding onChange handler') + wsClient.addOnChange(incrementalBlockUpdate, 'block') + wsClient.addOnChange(incrementalBoardUpdate, 'board') + wsClient.addOnChange(incrementalBoardMemberUpdate, 'boardMembers') + wsClient.addOnReconnect(dispatchLoadAction) + wsClient.setOnFollowBlock((_: WSClient, subscription: Subscription): void => { if (subscription.subscriberId === myID) { dispatch(followBlock(subscription)) @@ -92,17 +94,13 @@ export default function useConnectToBoard(dispatch: any, readToken: string, myID dispatch(unfollowBlock(subscription)) } }) + return () => { - if (timeout) { - clearTimeout(timeout) - } - if (subscribedToTeam) { - wsClient.unsubscribeToTeam(teamId || '0') - } - wsClient.removeOnChange(incrementalUpdateBlock, 'block') - wsClient.removeOnChange(incrementalUpdateBoard, 'board') - wsClient.removeOnReconnect(() => dispatch(loadAction(boardId))) - wsClient.removeOnStateChange(updateWebsocketState) + Utils.log('useWebsocket cleanup') + wsClient.removeOnChange(incrementalBlockUpdate, 'block') + wsClient.removeOnChange(incrementalBoardUpdate, 'board') + wsClient.removeOnChange(incrementalBoardMemberUpdate, 'boardMembers') + wsClient.removeOnReconnect(dispatchLoadAction) } }, [teamId, readonly, boardId, myID]) }