fix: Collab feedback fixes (#7298)

* hide the widget names

* blocking multiselect in comment mode

* wrapped the name

* the latest comment will be on top

* isolated a condition for selection canvas

* added unresolve tooltip

* added resolved thread tooltip

* updated sorted comment cards when user gets the update/insert/delete events
This commit is contained in:
Pranav Kanade 2021-09-10 16:17:17 +05:30 committed by GitHub
parent 594e0ef2e1
commit 3c0b33763e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 47 additions and 11 deletions

View File

@ -10,6 +10,8 @@ import {
getCommentThreadsFetched, getCommentThreadsFetched,
getSortedAndFilteredAppCommentThreadIds, getSortedAndFilteredAppCommentThreadIds,
shouldShowResolved as shouldShowResolvedSelector, shouldShowResolved as shouldShowResolvedSelector,
getLastUpdatedCommentThreadId,
getUnreadCommentsCount,
} from "selectors/commentsSelectors"; } from "selectors/commentsSelectors";
import { getCurrentApplicationId } from "selectors/editorSelectors"; import { getCurrentApplicationId } from "selectors/editorSelectors";
@ -38,6 +40,8 @@ export const useSortedCommentThreadIds = (commentThreadIds: string[]) => {
const currentUser = useSelector(getCurrentUser); const currentUser = useSelector(getCurrentUser);
const currentUsername = currentUser?.username; const currentUsername = currentUser?.username;
const unreadCommentsCount = useSelector(getUnreadCommentsCount);
const lastUpdatedCommentThreadId = useSelector(getLastUpdatedCommentThreadId);
return useMemo( return useMemo(
() => () =>
@ -54,6 +58,8 @@ export const useSortedCommentThreadIds = (commentThreadIds: string[]) => {
shouldShowResolved, shouldShowResolved,
appCommentsFilter, appCommentsFilter,
currentUsername, currentUsername,
lastUpdatedCommentThreadId,
unreadCommentsCount,
], ],
); );
}; };

View File

@ -91,11 +91,13 @@ const UserName = styled.span`
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; /* number of lines to show */ -webkit-line-clamp: 1; /* number of lines to show */
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
word-break: break-word;
`; `;
const HeaderSection = styled.div` const HeaderSection = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
max-width: 100%;
& ${Profile} { & ${Profile} {
flex-shrink: 0; flex-shrink: 0;

View File

@ -3,7 +3,11 @@ import styled, { withTheme } from "styled-components";
import Icon, { IconSize } from "components/ads/Icon"; import Icon, { IconSize } from "components/ads/Icon";
import { Theme } from "constants/DefaultTheme"; import { Theme } from "constants/DefaultTheme";
import Tooltip from "components/ads/Tooltip"; import Tooltip from "components/ads/Tooltip";
import { createMessage, RESOLVE_THREAD } from "constants/messages"; import {
createMessage,
RESOLVE_THREAD,
RESOLVED_THREAD,
} from "constants/messages";
import { Colors } from "constants/Colors"; import { Colors } from "constants/Colors";
const Container = styled.div` const Container = styled.div`
@ -64,7 +68,10 @@ const ResolveCommentButton = withTheme(
return ( return (
<Container onClick={_handleClick}> <Container onClick={_handleClick}>
<Tooltip content={createMessage(RESOLVE_THREAD)} hoverOpenDelay={1000}> <Tooltip
content={createMessage(resolved ? RESOLVED_THREAD : RESOLVE_THREAD)}
hoverOpenDelay={1000}
>
<StyledResolveIcon <StyledResolveIcon
fillColor={fillColor} fillColor={fillColor}
keepColors keepColors

View File

@ -21,6 +21,7 @@ const WidgetTypes = WidgetFactory.widgetTypes;
import { snipingModeSelector } from "selectors/editorSelectors"; import { snipingModeSelector } from "selectors/editorSelectors";
import { bindDataToWidget } from "../../../actions/propertyPaneActions"; import { bindDataToWidget } from "../../../actions/propertyPaneActions";
import { hideErrors } from "selectors/debuggerSelectors"; import { hideErrors } from "selectors/debuggerSelectors";
import { commentModeSelector } from "../../../selectors/commentsSelectors";
const PositionStyle = styled.div<{ topRow: number; isSnipingMode: boolean }>` const PositionStyle = styled.div<{ topRow: number; isSnipingMode: boolean }>`
position: absolute; position: absolute;
@ -57,6 +58,7 @@ type WidgetNameComponentProps = {
export function WidgetNameComponent(props: WidgetNameComponentProps) { export function WidgetNameComponent(props: WidgetNameComponentProps) {
const showPropertyPane = useShowPropertyPane(); const showPropertyPane = useShowPropertyPane();
const dispatch = useDispatch(); const dispatch = useDispatch();
const isCommentMode = useSelector(commentModeSelector);
const isSnipingMode = useSelector(snipingModeSelector); const isSnipingMode = useSelector(snipingModeSelector);
const showTableFilterPane = useShowTableFilterPane(); const showTableFilterPane = useShowTableFilterPane();
// Dispatch hook handy to set a widget as focused/selected // Dispatch hook handy to set a widget as focused/selected
@ -132,6 +134,7 @@ export function WidgetNameComponent(props: WidgetNameComponentProps) {
selectedWidgets.includes(props.widgetId); selectedWidgets.includes(props.widgetId);
const shouldShowWidgetName = () => { const shouldShowWidgetName = () => {
return ( return (
!isCommentMode &&
!isMultiSelectedWidget && !isMultiSelectedWidget &&
(isSnipingMode (isSnipingMode
? focusedWidget === props.widgetId ? focusedWidget === props.widgetId

View File

@ -515,6 +515,7 @@ export const DOWNLOAD_FILE_NAME_ERROR = () => "File name was not provided";
export const MORE_OPTIONS = () => "More Options"; export const MORE_OPTIONS = () => "More Options";
export const ADD_REACTION = () => "Add Reaction"; export const ADD_REACTION = () => "Add Reaction";
export const RESOLVE_THREAD = () => "Resolve Thread"; export const RESOLVE_THREAD = () => "Resolve Thread";
export const RESOLVED_THREAD = () => "Resolved Thread";
export const EMOJI = () => "Emoji"; export const EMOJI = () => "Emoji";
// Sniping mode messages // Sniping mode messages

View File

@ -24,6 +24,7 @@ import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
import WidgetFactory from "utils/WidgetFactory"; import WidgetFactory from "utils/WidgetFactory";
import { AppState } from "reducers"; import { AppState } from "reducers";
import { useWidgetDragResize } from "utils/hooks/dragResizeHooks"; import { useWidgetDragResize } from "utils/hooks/dragResizeHooks";
import { commentModeSelector } from "selectors/commentsSelectors";
const WidgetTypes = WidgetFactory.widgetTypes; const WidgetTypes = WidgetFactory.widgetTypes;
const StyledSelectionBox = styled.div` const StyledSelectionBox = styled.div`
@ -171,6 +172,7 @@ function WidgetsMultiSelectBox(props: {
snapRowSpace: number; snapRowSpace: number;
}): any { }): any {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isCommentMode = useSelector(commentModeSelector);
const canvasWidgets = useSelector(getCanvasWidgets); const canvasWidgets = useSelector(getCanvasWidgets);
const selectedWidgetIDs = useSelector(getSelectedWidgets); const selectedWidgetIDs = useSelector(getSelectedWidgets);
const selectedWidgets = selectedWidgetIDs.map( const selectedWidgets = selectedWidgetIDs.map(
@ -188,7 +190,7 @@ function WidgetsMultiSelectBox(props: {
* 3. multiple widgets are selected * 3. multiple widgets are selected
*/ */
const shouldRender = useMemo(() => { const shouldRender = useMemo(() => {
if (isDragging) { if (isDragging || isCommentMode) {
return false; return false;
} }
const parentIDs = selectedWidgets const parentIDs = selectedWidgets
@ -203,7 +205,7 @@ function WidgetsMultiSelectBox(props: {
hasCommonParent && hasCommonParent &&
get(selectedWidgets, "0.parentId") === props.widgetId get(selectedWidgets, "0.parentId") === props.widgetId
); );
}, [selectedWidgets, isDragging]); }, [selectedWidgets, isDragging, isCommentMode]);
const draggableRef = useRef<HTMLDivElement>(null); const draggableRef = useRef<HTMLDivElement>(null);
const { setDraggingState } = useWidgetDragResize(); const { setDraggingState } = useWidgetDragResize();

View File

@ -19,6 +19,7 @@ import { useCanvasDragToScroll } from "utils/hooks/useCanvasDragToScroll";
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
import { XYCord } from "utils/hooks/useCanvasDragging"; import { XYCord } from "utils/hooks/useCanvasDragging";
import { theme } from "constants/DefaultTheme"; import { theme } from "constants/DefaultTheme";
import { commentModeSelector } from "../../selectors/commentsSelectors";
const StyledSelectionCanvas = styled.canvas` const StyledSelectionCanvas = styled.canvas`
position: absolute; position: absolute;
@ -56,6 +57,7 @@ export function CanvasSelectionArena({
snapRowSpace: number; snapRowSpace: number;
}) { }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isCommentMode = useSelector(commentModeSelector);
const canvasRef = React.useRef<HTMLCanvasElement>(null); const canvasRef = React.useRef<HTMLCanvasElement>(null);
const parentWidget = useSelector((state: AppState) => const parentWidget = useSelector((state: AppState) =>
getWidget(state, parentId || ""), getWidget(state, parentId || ""),
@ -439,7 +441,10 @@ export function CanvasSelectionArena({
snapRowSpace, snapRowSpace,
]); ]);
return appMode === APP_MODE.EDIT && !(isDragging || isResizing) ? ( const shouldShow =
appMode === APP_MODE.EDIT && !(isDragging || isResizing || isCommentMode);
return shouldShow ? (
<StyledSelectionCanvas <StyledSelectionCanvas
data-testid={`canvas-${widgetId}`} data-testid={`canvas-${widgetId}`}
id={`canvas-${widgetId}`} id={`canvas-${widgetId}`}

View File

@ -45,6 +45,7 @@ const initialState: CommentsReduxState = {
draftComments: {}, draftComments: {},
unpublishedThreadDraftComment: null, unpublishedThreadDraftComment: null,
commentThreadsFetched: false, commentThreadsFetched: false,
lastUpdatedCommentThreadId: null,
}; };
/** /**

View File

@ -15,7 +15,7 @@ const handleUpdateCommentThreadEvent = (
applicationId, applicationId,
); );
return { ...updatedState }; return { ...updatedState, lastUpdatedCommentThreadId: commentThreadId };
}; };
export default handleUpdateCommentThreadEvent; export default handleUpdateCommentThreadEvent;

View File

@ -49,6 +49,7 @@ const handleNewCommentThreadEvent = (
return { return {
...state, ...state,
lastUpdatedCommentThreadId: thread.id,
showUnreadIndicator, showUnreadIndicator,
}; };
}; };

View File

@ -41,7 +41,7 @@ const handleUpdateCommentThreadEvent = (
const showUnreadIndicator = !state.isCommentMode; const showUnreadIndicator = !state.isCommentMode;
return { ...state, showUnreadIndicator }; return { ...state, showUnreadIndicator, lastUpdatedCommentThreadId: id };
}; };
export default handleUpdateCommentThreadEvent; export default handleUpdateCommentThreadEvent;

View File

@ -23,4 +23,5 @@ export interface CommentsReduxState {
unpublishedThreadDraftComment: EditorState | null; unpublishedThreadDraftComment: EditorState | null;
draftComments: Record<string, EditorState>; draftComments: Record<string, EditorState>;
commentThreadsFetched: boolean; commentThreadsFetched: boolean;
lastUpdatedCommentThreadId: string | null;
} }

View File

@ -99,18 +99,20 @@ export const getSortedAndFilteredAppCommentThreadIds = (
if (!commentThreadsMap[a] || !commentThreadsMap[b]) return -1; if (!commentThreadsMap[a] || !commentThreadsMap[b]) return -1;
const { const {
isViewed: isAViewed,
pinnedState: isAPinned, pinnedState: isAPinned,
updationTime: updationTimeA, updationTime: updationTimeA,
} = commentThreadsMap[a]; } = commentThreadsMap[a];
const { const {
isViewed: isBViewed,
pinnedState: isBPinned, pinnedState: isBPinned,
updationTime: updationTimeB, updationTime: updationTimeB,
} = commentThreadsMap[b]; } = commentThreadsMap[b];
const sortIdx = getSortIndexBool( let sortIdx = getSortIndexBool(!!isAPinned?.active, !!isBPinned?.active);
!!isAPinned?.active, if (sortIdx !== 0) return sortIdx;
!!isBPinned?.active,
); sortIdx = getSortIndexBool(!!isBViewed, !!isAViewed);
if (sortIdx !== 0) return sortIdx; if (sortIdx !== 0) return sortIdx;
const result = getSortIndexTime(updationTimeA, updationTimeB); const result = getSortIndexTime(updationTimeA, updationTimeB);
@ -145,6 +147,11 @@ export const getSortedAndFilteredAppCommentThreadIds = (
return result; return result;
}; };
export const getUnreadCommentsCount = (state: AppState) =>
state.ui.comments.unreadCommentThreadsCount;
export const getLastUpdatedCommentThreadId = (state: AppState) =>
state.ui.comments.lastUpdatedCommentThreadId;
export const shouldShowResolved = (state: AppState) => export const shouldShowResolved = (state: AppState) =>
state.ui.comments.shouldShowResolvedAppCommentThreads; state.ui.comments.shouldShowResolvedAppCommentThreads;