Skip to content

Commit

Permalink
feat(desk): implement comments (beta) (#4886)
Browse files Browse the repository at this point in the history
* feat: comments wip

* add handle to commentslist, scroll down to comment fix

* fix(comments): only calculate current caret element on demand (#4935)

* feat(comments): minor UI updates (#4929)

- Tooltip delays (500 in, 0 out), <TooltipDelayGroupProvider> wraps comment actions
- Optically aligned icons (still temporary, changes forthcoming in @sanity/icons)
- Display total comment (not thread) count per field
- Minor changes to open/resolved selects, comment context menu alignment + field headers
- Primary tone on new comment container, also broken out into a separate component
- Other super minor tweaks, slightly more condensed comments, PTE container
- Bump @sanity/ui to 1.8.2
- Uses current dataset name when querying for metacontent comments

* feat: improve comment breadcrumbs

* feat: disable replying/creating new comments when resolved

* feat: scroll to comment when opening inspector

* feat: use correct feature key in `useCommentsEnabled`

* refactor: scroll to thread, feature enable check, build breadcrumbs

* feat: ui updates

* dev(test-studio): add comments debug schema

* feat: ui updates, refactor, add array item schema title in breadcrumbs

* refactor(comments): inline text filtering for mentions menu

* refactor(comments): remove unused 'expanded' context

This is no longer in use it seems like. Removing for simplicity.

* refactor(comments): introduce focus to end of content as explicit fn

Make a explicit function to focus the editor at the end of the
edited comment content as focusEditor fn is now used internally
in the context provider.

Also simplify an effect that focuses the component this way.

* fix(comments): fix issue with focusing editor through effect

Make sure the editor is mounted before trying to call focus on it.

* feat: validate comments against schema and document value

* dev(test-studio): update comments debug schema

* feat: improve comment breadcrumbs

* refactor(comments): remove unused 'expanded' context

This is no longer in use it seems like. Removing for simplicity.

* fix: resolve conflicts

* fix: scroll to comment

* refactor: types, add comments, clean up

* fix: delete comment dialog message

* feat: update pte list config

* fix(comments): create better placement for mentionmenu popover

* fix: move static props outside the render scope, a11y improvements

* feat: add comment creation error handling

* dev(test-studio): update comments debug schema

* fix: sort order when creating a new thread + scroll to comment issues

* refactor: minor improvements

* feat: improve perf by memoizing the comments list component

* fix: add proper tags to comments list

* feat: cache system groups response to prevent unnecessary requests

* fix: breadcrumbs build

* test: build comment breadcrumbs

* fix(core/comments): ensure proper authentication config on comment client

Re-use the authentication configured for the default client.
Authentication method vary if the browser supports cookies or not.

* dev(test-studio): temporarily disable `assist` and `tsdoc` plugins

* refactor: move comments from `core` to `desk`

* feat: add `createPathWithParams` to pane router

* feat: implement comments setup

* feat: add `useCommentsSetup` hook

* feat: add `client` option to `useCommentsStore` and `useCommentOperations`

* refactor: remove unused context

* test: update `buildCommentBreadcrumbs` test

* feat: add copy link to comment feature, UI tweaks and clean up

* refactor: export `useMentionOptions` options interface

* refactor: update comment workshop stories

* fix: attach workspace title to comments notification context (#4992)

* feat: add highlight/scroll logic + general improvements

* fix(comments): handle text overflow in editable surfaces, optically align field titles (#5004)

* fix(comments): add viewport specific max-height to editable comment areas

* fix(comments): optically align thread field titles

* fixup! fix(comments): add viewport specific max-height to editable comment areas

* fix: field highlight effect array issue by using `AnimatePresence`

* feat: implement comment discard logic

* feat: disable comments by default

* dev(test-studio): enable comments

* fix: ensure created comments create URLs with inspect and comment params (#5012)

* chore: add code owner for comments

* fix: re-focus input when cancelling comment discard when creating new thread

* refactor: simplify discard controller

* fix: reset comment id ref from params when scroll completed

* fix: move group to top when new thread is created + select the path

* fix: tweak field highlight overlay

* test(comments): add test-ids

Add a couple of test-ids we will need when writing tests.

* refactor(comments): refactor focus handling in the CommentInput

This will fix some bugs we have been seeing related to setting focus in the comment input.
Use the PTE Editable selection prop to control selecting end of the content.
Call focus on the editor without side-effects.

* test(playwright-ct): add tests for CommentInput

Add some basic tests for the comment input. More to come.

* fix(comments): use current editor value over snapshot to update comment

* test(playwright-ct): update props after refactor

* fix: store document references as plain objects (#5021)

* feat: implement breadcrumbs button

* feat: reset select path when changing status view

* fix: reset select path when closing inspector

* feat: improve selected path logic, update ui when creating new thread

* fix: revert the storing of cross dataset references in comment documents

* feat: add  to notification context (#5041)

* dev(test-studio): remove temporary workspace

* dev(test-studio): re-enable `tsdoc` and `assist` plugins

* chore: update `yarn.lock`

* chore: bump sanity ui

* refactor: remove `useFieldCommentsCount` hook

* feat: handle network connection reconnect in `useCommentsStore`

* feat: disable comments (input and actions) while running setup

* fix: retry comment create issue

* fix: `focusOnMount` issue

* chore: update yarn.lock

* feat: add comments onboarding

* refactor: setup when creating the first comment

* fix: update comments onboarding local storage key

* fix: scroll to comment

* refactor(comments): refactor how input and focus is handled

* Enter will submit the comment
* Input field is reset after submission or discard
* Setting focus is handled through the same function everywhere.

* test(playwrigh-ct): add test for comment submission

* refactor(comments): Performance opt: Don't re-render replies every time.

* refactor(comments): refactor key event handling in the comment input and consumers

This will let comment input key events propagate to the parent components for
handling spesific functionality for that parent.

This also reduces the need for additional key handlers in the parent components,
and makes it easier to compose functionality as there is only one originating source
of those events.

* fix: comments onboarding copy

* refactor: make code more readable in `FormFieldBaseHeader`

* fix: incorrect interface name in `CommentsSetupProvider`

* fix: remove unused CSS in `CommentFieldButton`

* fix: wrap local storage functions in try/catch in `CommentsOnboardingProvider`

* refactor: get rid of `satisfies` where possible

* fix(core): invalid tsdoc in `useDidUpdate`

* fix: add request tag in `CommentsSetupProvider`

* fix(studio-e2e-testing): remove `commentAction` field action

* Update packages/sanity/src/desk/comments/src/context/setup/CommentsSetupProvider.tsx

Co-authored-by: Robin Pyon <[email protected]>

---------

Co-authored-by: Robin Pyon <[email protected]>
Co-authored-by: Per-Kristian Nordnes <[email protected]>
  • Loading branch information
3 people authored Oct 31, 2023
1 parent 2013203 commit 0803464
Show file tree
Hide file tree
Showing 131 changed files with 7,496 additions and 148 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@
# Tom owns the Shopify templates
/packages/@sanity/cli/src/actions/init-project/templates/shopify* @thebiggianthead
/packages/@sanity/cli/templates/shopify* @thebiggianthead

/packages/sanity/src/desk/comments/ @hermanwikner
3 changes: 1 addition & 2 deletions dev/studio-e2e-testing/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {defaultDocumentNode, newDocumentOptions, structure} from 'sanity-test-st
import {presenceTool} from 'sanity-test-studio/plugins/presence'
import {copyAction} from 'sanity-test-studio/fieldActions/copyAction'
import {assistFieldActionGroup} from 'sanity-test-studio/fieldActions/assistFieldActionGroup'
import {commentAction} from 'sanity-test-studio/fieldActions/commentFieldAction'
import {customInspector} from 'sanity-test-studio/inspectors/custom'
import {pasteAction} from 'sanity-test-studio/fieldActions/pasteAction'
import {Branding} from './components/Branding'
Expand Down Expand Up @@ -45,7 +44,7 @@ const sharedSettings = definePlugin({
},
unstable_fieldActions: (prev, ctx) => {
if (['fieldActionsTest', 'stringsTest'].includes(ctx.documentType)) {
return [...prev, commentAction, assistFieldActionGroup, copyAction, pasteAction]
return [...prev, assistFieldActionGroup, copyAction, pasteAction]
}

return prev
Expand Down
22 changes: 0 additions & 22 deletions dev/test-studio/fieldActions/commentFieldAction.tsx

This file was deleted.

8 changes: 5 additions & 3 deletions dev/test-studio/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {deskTool} from 'sanity/desk'
import {muxInput} from 'sanity-plugin-mux-input'
import {assist} from '@sanity/assist'
import {googleMapsInput} from '@sanity/google-maps-input'
// eslint-disable-next-line import/no-extraneous-dependencies
import {tsdoc} from '@sanity/tsdoc/studio'
import {theme as tailwindTheme} from './sanity.theme.mjs'
import {imageAssetSource} from './assetSources'
Expand Down Expand Up @@ -39,7 +38,6 @@ import {vercelTheme} from './themes/vercel'
import {GoogleLogo, TailwindLogo, VercelLogo} from './components/workspaceLogos'
import {copyAction} from './fieldActions/copyAction'
import {assistFieldActionGroup} from './fieldActions/assistFieldActionGroup'
import {commentAction} from './fieldActions/commentFieldAction'
import {customInspector} from './inspectors/custom'
import {pasteAction} from './fieldActions/pasteAction'

Expand Down Expand Up @@ -70,12 +68,16 @@ const sharedSettings = definePlugin({
},
unstable_fieldActions: (prev, ctx) => {
if (['fieldActionsTest', 'stringsTest'].includes(ctx.documentType)) {
return [...prev, commentAction, assistFieldActionGroup, copyAction, pasteAction]
return [...prev, assistFieldActionGroup, copyAction, pasteAction]
}

return prev
},
newDocumentOptions,

unstable_comments: {
enabled: true,
},
},
plugins: [
deskTool({
Expand Down
115 changes: 115 additions & 0 deletions dev/test-studio/schema/debug/comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {defineType} from 'sanity'

const DESCRIPTION = 'Comments added to this field should be hidden when the toggle above is checked'

export const commentsDebug = defineType({
name: 'commentsDebug',
type: 'document',
title: 'Comments debug',
fields: [
{
name: 'string',
type: 'string',
title: 'String title',
},
{
name: 'hideFields',
type: 'boolean',
title: 'Hide fields',
},
{
type: 'object',
name: 'object',
title: 'Object title',
fields: [
{
type: 'string',
name: 'string',
title: 'String title',
hidden: ({document}) => Boolean(document?.hideFields),
description: DESCRIPTION,
},
{
type: 'number',
name: 'number',
title: 'Number title',
},
],
},
{
type: 'array',
name: 'arrayOfObjects',
title: 'Array 1',
of: [
{
name: 'arrayObject',
type: 'object',
title: 'Array object 1',
fields: [
{
name: 'string',
type: 'string',
title: 'String 1',
},
{
name: 'image',
type: 'image',
title: 'Image 1',
hidden: ({document}) => {
return Boolean(document?.hideFields)
},
description: DESCRIPTION,
},
{
name: 'nestedArray',
type: 'array',
title: 'Array 2',
of: [
{
name: 'nestedArrayObject1',
type: 'object',
title: 'Nested array object 1',
fields: [
{
name: 'string',
type: 'string',
title: 'String 2.1',
},
{
name: 'image',
type: 'image',
title: 'Image 2.1',
hidden: ({document}) => {
return Boolean(document?.hideFields)
},
description: DESCRIPTION,
},
],
},
{
type: 'object',
name: 'nestedArrayObject2',
title: 'Nested array object 2',
fields: [
{
name: 'string',
type: 'string',
title: 'String 2.2',
},
],
},
],
},
],
},
],
},
{
name: 'image',
type: 'image',
title: 'Image title',
hidden: ({document}) => Boolean(document?.hideFields),
description: DESCRIPTION,
},
],
})
2 changes: 2 additions & 0 deletions dev/test-studio/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import {circularCrossDatasetReferenceTest} from './debug/circularCrossDatasetRef
import {allNativeInputComponents} from './debug/allNativeInputComponents'
import fieldGroupsWithFieldsets from './debug/fieldGroupsWithFieldsets'
import ptReference from './debug/ptReference'
import {commentsDebug} from './debug/comments'

// @todo temporary, until code input is v3 compatible
const codeInputType = {
Expand Down Expand Up @@ -159,6 +160,7 @@ export const schemaTypes = [
code,
codeInputType, // @todo temporary, until code input is v3 compatible
color,
commentsDebug,
conditionalFields,
conditionalFieldset,
customBlock,
Expand Down
25 changes: 13 additions & 12 deletions dev/test-studio/structure/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,50 +34,51 @@ export const PLUGIN_INPUT_TYPES = [
]

export const DEBUG_INPUT_TYPES = [
'languageFilterDebug',
'actionsTest',
'simpleArrayOfObjects',
'simpleReferences',
'formInputDebug',
'allNativeInputComponents',
'collapsibleObjects',
'commentsDebug',
'conditionalFieldsTest',
'customInputsTest',
'customInputsWithPatches',
'documentActionsTest',
'collapsibleObjects',
'documentWithHoistedPt',
'empty',
'fieldActionsTest',
'fieldComponentsTest',
'fieldsetsTest',
'fieldValidationInferReproDoc',
'focusTest',
'documentWithHoistedPt',
'formInputDebug',
'initialValuesTest',
'inspectorsTest',
'invalidPreviews',
'thesis',
'languageFilterDebug',
'manyFieldsTest',
'noTitleField',
'poppers',
'presence',
'previewImageUrlTest',
'previewMediaTest',
'previewSelectBugRepro',
'ptReference',
'radio',
'readOnlyTest',
'recursiveDocument',
'recursiveArraysTest',
'recursiveDocument',
'recursiveObjectTest',
'recursivePopoverTest',
'reservedKeywordsTest',
'scrollBug',
'select',
'simpleArrayOfObjects',
'simpleReferences',
'thesis',
'typeWithNoToplevelStrings',
'uploadsTest',
'validationTest',
'allNativeInputComponents',
'scrollBug',
'ptReference',
'virtualizationInObject',
'virtualizationDebug',
'virtualizationInObject',
]

export const CI_INPUT_TYPES = ['conditionalFieldset', 'validationCI', 'textsTest']
Expand Down
1 change: 1 addition & 0 deletions packages/sanity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
"@sanity/logos": "^2.0.2",
"@sanity/mutator": "3.18.1",
"@sanity/portable-text-editor": "3.18.1",
"@portabletext/react": "^3.0.0",
"@sanity/schema": "3.18.1",
"@sanity/types": "3.18.1",
"@sanity/ui": "^1.8.3",
Expand Down
49 changes: 49 additions & 0 deletions packages/sanity/playwright-ct/tests/comments/CommentInput.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {expect, test} from '@playwright/experimental-ct-react'
import React from 'react'
import {testHelpers} from '../utils/testHelpers'
import {CommentsInputStory} from './CommentInputStory'

test.describe('Comments', () => {
test.describe('CommentInput', () => {
test('Should render', async ({mount, page}) => {
await mount(<CommentsInputStory />)
const $editable = page.getByTestId('comment-input-editable')
await expect($editable).toBeVisible()
})

test('Should be able to type into', async ({mount, page}) => {
const {insertPortableText} = testHelpers({page})
await mount(<CommentsInputStory />)
const $editable = page.getByTestId('comment-input-editable')
await expect($editable).toBeEditable()
await insertPortableText('My first comment!', $editable)
await expect($editable).toHaveText('My first comment!')
})

test('Should bring up mentions menu when typing @', async ({mount, page}) => {
await mount(<CommentsInputStory />)
const $editable = page.getByTestId('comment-input-editable')
await $editable.waitFor({state: 'visible'})
await page.keyboard.type('@')
await expect(page.getByTestId('comments-mentions-menu')).toBeVisible()
})

test('Should be able to submit', async ({mount, page}) => {
const {insertPortableText} = testHelpers({page})
let submitted = false
const onSubmit = () => {
submitted = true
}
await mount(<CommentsInputStory onSubmit={onSubmit} />)
const $editable = page.getByTestId('comment-input-editable')
await expect($editable).toBeEditable()
// Test that blank comments can't be submitted
await page.keyboard.press('Enter')
expect(submitted).toBe(false)
await insertPortableText('This is a comment!', $editable)
await expect($editable).toHaveText('This is a comment!')
await page.keyboard.press('Enter')
expect(submitted).toBe(true)
})
})
})
47 changes: 47 additions & 0 deletions packages/sanity/playwright-ct/tests/comments/CommentInputStory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, {useState} from 'react'
import {CurrentUser, PortableTextBlock} from '@sanity/types'
import {noop} from 'lodash'
import {CommentInput} from '../../../src/desk/comments/src/components/pte/comment-input/CommentInput'
import {TestWrapper} from '../formBuilder/utils/TestWrapper'

const currentUser: CurrentUser = {
email: '',
id: '',
name: '',
role: '',
roles: [],
profileImage: '',
provider: '',
}

const SCHEMA_TYPES: [] = []

export function CommentsInputStory({
onDiscardCancel = noop,
onDiscardConfirm = noop,
onSubmit = noop,
value = null,
}: {
onDiscardCancel?: () => void
onDiscardConfirm?: () => void
onSubmit?: () => void
value?: PortableTextBlock[] | null
}) {
const [valueState, setValueState] = useState<PortableTextBlock[] | null>(value)
return (
<TestWrapper schemaTypes={SCHEMA_TYPES}>
<CommentInput
focusOnMount
placeholder="Your comment..."
focusLock
currentUser={currentUser}
onChange={setValueState}
value={valueState}
mentionOptions={{data: [], error: null, loading: false}}
onDiscardConfirm={onDiscardConfirm}
onDiscardCancel={onDiscardCancel}
onSubmit={onSubmit}
/>
</TestWrapper>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const StaticUserAvatar = forwardRef(function StaticUserAvatar(
props: Omit<UserAvatarProps, 'user'> & {user: User},
ref: React.ForwardedRef<HTMLDivElement>,
) {
const {user, animateArrowFrom, position, size, status, tone} = props
const {user, animateArrowFrom, position, size, status, tone, ...restProps} = props
const [imageLoadError, setImageLoadError] = useState<null | Error>(null)
const userColor = useUserColor(user.id)
const imageUrl = imageLoadError ? undefined : user?.imageUrl
Expand All @@ -98,6 +98,7 @@ const StaticUserAvatar = forwardRef(function StaticUserAvatar(
size={typeof size === 'string' ? LEGACY_TO_UI_AVATAR_SIZES[size] : size}
status={status}
title={user?.displayName}
{...restProps}
/>
)
})
Expand Down
Loading

2 comments on commit 0803464

@vercel
Copy link

@vercel vercel bot commented on 0803464 Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

performance-studio – ./

performance-studio-git-next.sanity.build
performance-studio.sanity.build

@vercel
Copy link

@vercel vercel bot commented on 0803464 Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-studio – ./

test-studio-git-next.sanity.build
test-studio.sanity.build

Please sign in to comment.