Skip to content

Commit

Permalink
basic comments resolution (#4594)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruggi authored Dec 4, 2023
1 parent a900021 commit c73874f
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 29 deletions.
2 changes: 1 addition & 1 deletion editor/liveblocks.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ export type RoomEvent = {
// Optionally, when using Comments, ThreadMetadata represents metadata on
// each thread. Can only contain booleans, strings, and numbers.
export type ThreadMetadata = {
// resolved: boolean;
// quote: string;
// time: number;
type: 'canvas'
x: number // x and y is global when sceneId is undefined, and local to the scene when sceneId is not null
y: number
sceneId?: string
remixLocationRoute?: string
resolved: boolean
}

export const {
Expand Down
8 changes: 5 additions & 3 deletions editor/src/components/canvas/controls/comment-indicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import type { ThreadData } from '@liveblocks/client'
import { useAtom } from 'jotai'
import React from 'react'
import type { ThreadMetadata } from '../../../../liveblocks.config'
import { useEditThreadMetadata, useStorage, useThreads } from '../../../../liveblocks.config'
import { useEditThreadMetadata, useStorage } from '../../../../liveblocks.config'
import {
useCanvasLocationOfThread,
useIsOnAnotherRemixRoute,
useActiveThreads,
} from '../../../core/commenting/comment-hooks'
import type { CanvasPoint, CanvasVector, WindowPoint } from '../../../core/shared/math-utils'
import {
Expand Down Expand Up @@ -55,7 +56,7 @@ export const CommentIndicators = React.memo(() => {
CommentIndicators.displayName = 'CommentIndicators'

const CommentIndicatorsInner = React.memo(() => {
const { threads } = useThreads()
const threads = useActiveThreads()

return (
<React.Fragment>
Expand Down Expand Up @@ -138,7 +139,8 @@ const CommentIndicator = React.memo(({ thread }: CommentIndicatorProps) => {
position: 'fixed',
top: position.y,
left: position.x,
opacity: isOnAnotherRoute ? 0.25 : 1,
opacity: isOnAnotherRoute || thread.metadata.resolved ? 0.25 : 1,
filter: thread.metadata.resolved ? 'grayscale(1)' : undefined,
width: IndicatorSize,
'&:hover': {
transform: 'scale(1.15)',
Expand Down
2 changes: 2 additions & 0 deletions editor/src/components/canvas/controls/comment-popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => {
return createThread({
body,
metadata: {
resolved: false,
type: 'canvas',
x: comment.location.position.x,
y: comment.location.position.y,
Expand All @@ -86,6 +87,7 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => {
return createThread({
body,
metadata: {
resolved: false,
type: 'canvas',
x: comment.location.offset.x,
y: comment.location.offset.y,
Expand Down
6 changes: 6 additions & 0 deletions editor/src/components/editor/action-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,11 @@ export interface UpdateImportsFromCollaborationUpdate {
imports: MapLike<ImportDetails>
}

export interface SetShowResolvedThreads {
action: 'SET_SHOW_RESOLVED_THREADS'
showResolvedThreads: boolean
}

export type EditorAction =
| ClearSelection
| InsertJSXElement
Expand Down Expand Up @@ -1251,6 +1256,7 @@ export type EditorAction =
| UpdateTopLevelElementsFromCollaborationUpdate
| UpdateExportsDetailFromCollaborationUpdate
| UpdateImportsFromCollaborationUpdate
| SetShowResolvedThreads

export type DispatchPriority =
| 'everyone'
Expand Down
8 changes: 8 additions & 0 deletions editor/src/components/editor/actions/action-creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ import type {
DeleteFileFromCollaboration,
UpdateExportsDetailFromCollaborationUpdate,
UpdateImportsFromCollaborationUpdate,
SetShowResolvedThreads,
} from '../action-types'
import type { InsertionSubjectWrapper, Mode } from '../editor-modes'
import { EditorModes, insertionSubject } from '../editor-modes'
Expand Down Expand Up @@ -1707,3 +1708,10 @@ export function updateImportsFromCollaborationUpdate(
imports: imports,
}
}

export function setShowResolvedThreads(showResolvedThreads: boolean): SetShowResolvedThreads {
return {
action: 'SET_SHOW_RESOLVED_THREADS',
showResolvedThreads: showResolvedThreads,
}
}
1 change: 1 addition & 0 deletions editor/src/components/editor/actions/action-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export function isTransientAction(action: EditorAction): boolean {
case 'START_POST_ACTION_SESSION':
case 'TRUNCATE_HISTORY':
case 'UPDATE_PROJECT_SERVER_STATE':
case 'SET_SHOW_RESOLVED_THREADS':
return true

case 'TRUE_UP_ELEMENTS':
Expand Down
5 changes: 5 additions & 0 deletions editor/src/components/editor/actions/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ import type {
DeleteFileFromCollaboration,
UpdateExportsDetailFromCollaborationUpdate,
UpdateImportsFromCollaborationUpdate,
SetShowResolvedThreads,
} from '../action-types'
import { isLoggedIn } from '../action-types'
import type { Mode } from '../editor-modes'
Expand Down Expand Up @@ -920,6 +921,7 @@ export function restoreEditorState(
internalClipboard: currentEditor.internalClipboard,
filesModifiedByAnotherUser: currentEditor.filesModifiedByAnotherUser,
activeFrames: currentEditor.activeFrames,
showResolvedThreads: currentEditor.showResolvedThreads,
}
}

Expand Down Expand Up @@ -5527,6 +5529,9 @@ export const UPDATE_FNS = {
}
}
},
SET_SHOW_RESOLVED_THREADS: (action: SetShowResolvedThreads, editor: EditorModel): EditorModel => {
return { ...editor, showResolvedThreads: action.showResolvedThreads }
},
}

function copySelectionToClipboardMutating(
Expand Down
5 changes: 5 additions & 0 deletions editor/src/components/editor/store/editor-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@ export interface EditorState {
internalClipboard: InternalClipboard
filesModifiedByAnotherUser: Array<string>
activeFrames: ActiveFrame[]
showResolvedThreads: boolean
}

export function editorState(
Expand Down Expand Up @@ -1561,6 +1562,7 @@ export function editorState(
internalClipboardData: InternalClipboard,
filesModifiedByAnotherUser: Array<string>,
activeFrames: ActiveFrame[],
showResolvedThreads: boolean,
): EditorState {
return {
id: id,
Expand Down Expand Up @@ -1642,6 +1644,7 @@ export function editorState(
internalClipboard: internalClipboardData,
filesModifiedByAnotherUser: filesModifiedByAnotherUser,
activeFrames: activeFrames,
showResolvedThreads: showResolvedThreads,
}
}

Expand Down Expand Up @@ -2518,6 +2521,7 @@ export function createEditorState(dispatch: EditorDispatch): EditorState {
},
filesModifiedByAnotherUser: [],
activeFrames: [],
showResolvedThreads: false,
}
}

Expand Down Expand Up @@ -2894,6 +2898,7 @@ export function editorModelFromPersistentModel(
},
filesModifiedByAnotherUser: [],
activeFrames: [],
showResolvedThreads: false,
}
return editor
}
Expand Down
2 changes: 2 additions & 0 deletions editor/src/components/editor/store/editor-update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ export function runSimpleLocalEditorAction(
return UPDATE_FNS.UPDATE_EXPORTS_DETAIL_FROM_COLLABORATION_UPDATE(action, state, serverState)
case 'UPDATE_IMPORTS_FROM_COLLABORATION_UPDATE':
return UPDATE_FNS.UPDATE_IMPORTS_FROM_COLLABORATION_UPDATE(action, state, serverState)
case 'SET_SHOW_RESOLVED_THREADS':
return UPDATE_FNS.SET_SHOW_RESOLVED_THREADS(action, state)
default:
return state
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4570,6 +4570,11 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall<EditorState> = (
newValue.activeFrames,
)

const showResolvedThreadsResults = BooleanKeepDeepEquality(
oldValue.showResolvedThreads,
newValue.showResolvedThreads,
)

const areEqual =
idResult.areEqual &&
vscodeBridgeIdResult.areEqual &&
Expand Down Expand Up @@ -4648,7 +4653,8 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall<EditorState> = (
colorSwatchesResults.areEqual &&
internalClipboardResults.areEqual &&
filesModifiedByAnotherUserResults.areEqual &&
activeFramesResults.areEqual
activeFramesResults.areEqual &&
showResolvedThreadsResults.areEqual

if (areEqual) {
return keepDeepEqualityResult(oldValue, true)
Expand Down Expand Up @@ -4733,6 +4739,7 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall<EditorState> = (
internalClipboardResults.value,
filesModifiedByAnotherUserResults.value,
activeFramesResults.value,
showResolvedThreadsResults.value,
)

return keepDeepEqualityResult(newEditorState, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,5 @@ export const EmptyEditorStateForKeysOnly: EditorState = {
},
filesModifiedByAnotherUser: [],
activeFrames: [],
showResolvedThreads: false,
}
118 changes: 96 additions & 22 deletions editor/src/components/inspector/sections/comment-section.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import '@liveblocks/react-comments/styles.css'
import React from 'react'
import { FlexColumn, FlexRow, InspectorSubsectionHeader, useColorTheme } from '../../../uuiui'
import {
Button,
FlexColumn,
FlexRow,
InspectorSubsectionHeader,
useColorTheme,
} from '../../../uuiui'
import { Comment } from '@liveblocks/react-comments'
import { stopPropagation } from '../common/inspector-utils'
import type { ThreadMetadata } from '../../../../liveblocks.config'
import { useThreads } from '../../../../liveblocks.config'
import type { ThreadData } from '@liveblocks/client'
import { useDispatch } from '../../editor/store/dispatch-context'
import { canvasPoint, canvasRectangle } from '../../../core/shared/math-utils'
import { scrollToPosition, switchEditorMode } from '../../editor/actions/action-creators'
import {
scrollToPosition,
setShowResolvedThreads,
switchEditorMode,
} from '../../editor/actions/action-creators'
import {
EditorModes,
existingComment,
Expand All @@ -18,9 +27,14 @@ import {
import { MultiplayerWrapper } from '../../../utils/multiplayer-wrapper'
import { useAtom } from 'jotai'
import { RemixNavigationAtom } from '../../canvas/remix/utopia-remix-root-component'
import { useIsOnAnotherRemixRoute } from '../../../core/commenting/comment-hooks'
import {
useUnresolvedThreads,
useIsOnAnotherRemixRoute,
useResolveThread,
useResolvedThreads,
} from '../../../core/commenting/comment-hooks'
import { Substores, useEditorState } from '../../editor/store/store-hook'
import { when } from '../../../utils/react-conditionals'
import { unless, when } from '../../../utils/react-conditionals'

export const CommentSection = React.memo(() => {
return (
Expand All @@ -45,13 +59,43 @@ export const CommentSection = React.memo(() => {
CommentSection.displayName = 'CommentSection'

const ThreadPreviews = React.memo(() => {
const { threads } = useThreads()
const dispatch = useDispatch()
const { threads: activeThreads } = useUnresolvedThreads()
const { threads: resolvedThreads } = useResolvedThreads()

const showResolved = useEditorState(
Substores.restOfEditor,
(store) => store.editor.showResolvedThreads,
'ThreadPreviews showResolvedThreads',
)

const toggleShowResolved = React.useCallback(() => {
dispatch([
setShowResolvedThreads(!showResolved),
switchEditorMode(EditorModes.selectMode(null, false, 'none')),
])
}, [showResolved, dispatch])

return (
<FlexColumn style={{ gap: 5 }}>
{threads.map((thread) => (
{activeThreads.map((thread) => (
<ThreadPreview key={thread.id} thread={thread} />
))}
{when(
resolvedThreads.length > 0,
<Button
highlight
spotlight
style={{ padding: 10, margin: '10px' }}
onClick={toggleShowResolved}
>
{showResolved ? 'Hide' : 'Show'} resolved threads
</Button>,
)}
{when(
showResolved,
resolvedThreads.map((thread) => <ThreadPreview key={thread.id} thread={thread} />),
)}
</FlexColumn>
)
})
Expand Down Expand Up @@ -100,6 +144,17 @@ const ThreadPreview = React.memo(({ thread }: ThreadPreviewProps) => {
])
}, [dispatch, remixNavigationState, isOnAnotherRoute, remixLocationRoute, point, thread.id])

const resolveThread = useResolveThread()

const onResolveThread = React.useCallback(
(e: React.MouseEvent) => {
e.stopPropagation()
resolveThread(thread)
dispatch([switchEditorMode(EditorModes.selectMode(null, false, 'none'))])
},
[resolveThread, dispatch, thread],
)

const comment = thread.comments[0]
if (comment == null) {
return null
Expand All @@ -110,23 +165,42 @@ const ThreadPreview = React.memo(({ thread }: ThreadPreviewProps) => {
<div
key={comment.id}
onClick={onClick}
style={{ backgroundColor: isSelected ? `${colorTheme.primary10.value}` : 'transparent' }}
style={{
backgroundColor: isSelected
? colorTheme.primary10.value
: thread.metadata.resolved
? colorTheme.bg2.value
: 'transparent',
}}
>
<Comment comment={comment} showActions={false} style={{ backgroundColor: 'transparent' }} />
{when(
repliesCount > 0,
<div
style={{
paddingBottom: 10,
paddingLeft: 44,
fontSize: 9,
color: colorTheme.fg6.value,
marginTop: -5,
}}
>
{repliesCount} {repliesCount > 1 ? 'replies' : 'reply'}
</div>,
)}
<div
style={{
paddingBottom: 10,
paddingLeft: 44,
paddingRight: 10,
marginTop: -5,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
{when(
repliesCount > 0,
<div
style={{
fontSize: 9,
color: colorTheme.fg6.value,
}}
>
{repliesCount} {repliesCount > 1 ? 'replies' : 'reply'}
</div>,
)}
{unless(repliesCount > 0, <div />)}
<Button highlight spotlight style={{ padding: '0 6px' }} onClick={onResolveThread}>
{thread.metadata.resolved ? 'Unresolve' : 'Resolve'}
</Button>
</div>
</div>
)
})
Expand Down
Loading

0 comments on commit c73874f

Please sign in to comment.