Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(desk): implement comments (beta) #4886

Merged
merged 102 commits into from
Oct 31, 2023
Merged

feat(desk): implement comments (beta) #4886

merged 102 commits into from
Oct 31, 2023

Conversation

hermanwikner
Copy link
Member

@hermanwikner hermanwikner commented Aug 31, 2023

Description

This pull request introduces a new comments feature, providing the ability to add comments to specific fields within documents. The comments specific logic is implemented in desk, and some updates have been made to core to enable comments to be configured from the desk plugin. Please note that this pull request aims to introduce comments as a beta feature and there is thus room for improvement in the implementation that will be adressed before GA.

The changes made to core and desk respectively are divided into two sections below.

What to review: core (DX + EX)

  • Field Comments:

    • Introduces a new __internal_comments prop for fields. This prop allows the configuration of fields with a comment action that is rendered along with Field Actions. The desk plugin uses this prop, as demonstrated in the following example:

      import {FieldProps} from 'sanity'
      
      export function CommentField(props: FieldProps) {
        return props.renderDefault({
          ...props,
          __internal_comments: {
            button: <CommentButton />, // The button rendered along with field actions
            hasComments: false, // Needed to know if we should display the comment button when the field has comments
            isAddingComment: false, // Needed to keep the field actions visible when authoring a comment
          },
        })
      }
  • Document Comments API:

    • Adds a new (unstable) API to enable/disable the comments feature for documents. In the initial beta release, the comments feature is opt-in, requiring explicit configuration. The API provides both a simple boolean option to enable/disable comments for all documents and a more granular configuration by using the documentType and/or documentId values provided in the context parameter.

      Boolean example – Enable comments for all documents:

      import {defineConfig} from 'sanity'
      
      export default defineConfig({
        // ... 
      
        document: {
          unstable_comments: {
            enabled: true,
          },
        },
      })

      Context example – Enable comments only for 'article' documents:

      import {defineConfig} from 'sanity'
      
      export default defineConfig({
        // ...
      
        document: {
          unstable_comments: {
            enabled: (ctx) => {
              return ctx.documentType === 'article'
            },
          },
        },
      })
  • New exports from the sanity package:

    • The useDidUpdate hook.
    • The resolveConditionalProperty function: We use this function to determine if a comment should be visible or not, ensuring that only comments related to visible fields are displayed.
    • The useFeatureEnabled hook: This hook is essential to check if the comments feature is enabled for the current plan.

What to review: desk (EX)

Summary of critical elements in the implementation:

  • CommentsProvider: This provider is used in DocumentPaneProvider and is responsible for handling all CRUD operations.

  • CommentsSetupProvider: This provider wraps the entire studio through studio.components.layout. It is responsible for the setup of comments (using the setup endpoint) and configuring a client for the addon dataset. This client is accessed with useCommentsSetup in CommentsProvider to enable CRUD operations on the addon dataset.

  • CommentsOnboardingProvider: This provider is relatively straightforward and is responsible for storing a value in local storage if the user dismisses the comments onboarding. It is implemented as a provider because, in the future, there may be multiple instances where onboarding needs to be displayed.

  • useCommentOperations: This hook manages the logic for creating, editing, updating, or deleting comments.

  • useCommentsStore: This hook initiates the initial fetch of all comments, subscribes to a real-time listener, and manages the state using a reducer. The dispatch function in this hook is exported to facilitate immediate and optimistic state updates with callbacks provided by the useCommentOperations. That is, whenever e.g. a create operation is executed, we optimistically update the state in the reducer to make the experience feel snappy and fast.

  • useMentionOptions: This hook returns a list of users who can be mentioned in the current document. The hook performs the following tasks:

    • Retrieves all grant filters using '*[_type == "system.group”]'.
    • Evaluates each user's grant filter against the document's value to determine if the user has read access. If this is the case, it becomes possible to mention the user.
  • useCommentsEnabled: This hook checks whether the comments feature flag (studioComments) are enabled for the project and resolves document.unstable_comments.enabled to determine if the comment feature should be enabled. The default value in document.unstable_comments.enabled should be false, and the user needs to explicitly enable comments in the config to try it out. This hook is used in three different locations:

    1. In CommentField to decide whether to render a field with a comment button or defer to the default field rendering.

    2. In the useMenuItem hook within the document inspector definition to determine whether the inspector button should be set as hidden: true.

    3. In CommentsProvider to determine whether to set up listeners, and so forth, for comments. If not, the provider is still rendered with nullified values.

  • buildCommentBreadcrumbs: This function builds the breadcrumbs for a comment and evaluates the comment against the document value to determine whether it should be displayed. This evaluation is performed because we only want to display comments that have a corresponding field. If there is no associated field (e.g., if the schema definition has changed or an array item has been removed), the comment should not be displayed. This also applies if a conditional hidden callback returns false.

  • buildCommentThreadItems: This function maps over all the comments an groups them in a format that is easier to work with in the UI.

Notes for release

n/a

@vercel
Copy link

vercel bot commented Aug 31, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
performance-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 31, 2023 11:23am
test-studio ✅ Ready (Inspect) Visit Preview 1 resolved Oct 31, 2023 11:23am
1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
studio-workshop ⬜️ Ignored (Inspect) Visit Preview Oct 31, 2023 11:23am

@github-actions
Copy link
Contributor

github-actions bot commented Aug 31, 2023

Component Testing Report Updated Oct 31, 2023 11:28 AM (UTC)

File Status Duration Passed Skipped Failed
comments/CommentInput.spec.tsx ❌ Failed (Inspect) 29s 11 0 1
formBuilder/ArrayInput.spec.tsx ✅ Passed (Inspect) 5s 3 0 0
formBuilder/inputs/PortableText/Annotations.spec.tsx ✅ Passed (Inspect) 12s 3 0 0
formBuilder/inputs/PortableText/Decorators.spec.tsx ✅ Passed (Inspect) 11s 6 0 0
formBuilder/inputs/PortableText/FocusTracking.spec.tsx ✅ Passed (Inspect) 30s 15 0 0
formBuilder/inputs/PortableText/Input.spec.tsx ✅ Passed (Inspect) 14s 9 0 0
formBuilder/inputs/PortableText/ObjectBlock.spec.tsx ✅ Passed (Inspect) 55s 18 0 0
formBuilder/inputs/PortableText/Styles.spec.tsx ✅ Passed (Inspect) 11s 6 0 0
formBuilder/inputs/PortableText/Toolbar.spec.tsx ✅ Passed (Inspect) 6s 3 0 0

Copy link
Contributor

@pedrobonamin pedrobonamin left a comment

Choose a reason for hiding this comment

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

Great job! This is going to be a fantastic feature.
Left some questions and a suggestion, happy to discuss.

Looking forward to this !

hermanwikner and others added 20 commits October 31, 2023 12:18
* Enter will submit the comment
* Input field is reset after submission or discard
* Setting focus is handled through the same function everywhere.
…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.
export function CommentsLayout(props: LayoutProps) {
return (
<CommentsSetupProvider>
<CommentsOnboardingProvider>{props.renderDefault(props)}</CommentsOnboardingProvider>
Copy link
Member Author

Choose a reason for hiding this comment

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

I think we should change order of these, the onboarding provider should probably be outermost

Copy link
Contributor

@robinpyon robinpyon left a comment

Choose a reason for hiding this comment

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

Great work @hermanwikner! As mentioned, another pass on desk components will be forthcoming, but all the core changes LGTM

Copy link
Member

@bjoerge bjoerge left a comment

Choose a reason for hiding this comment

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

🚢 🚀 ✨ 💬

@hermanwikner hermanwikner added this pull request to the merge queue Oct 31, 2023
Merged via the queue into next with commit 0803464 Oct 31, 2023
30 checks passed
@hermanwikner hermanwikner deleted the feat/comments-mvi-1 branch October 31, 2023 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants