Skip to content

Commit

Permalink
feat(core): rename useMentionOptions to useUserListWithPermission and…
Browse files Browse the repository at this point in the history
… move to core (#5778)

* feat(core): rename useMentionOptions to useUserListWithPermission and move to core

* fix(core): add error catch to useUserListWithPermissions hook

* chore(core): rename canBeMentioned for granted in useUserListWithPermissions

* chore: update TSdoc description
  • Loading branch information
pedrobonamin committed Feb 20, 2024
1 parent 3941d86 commit 5da8891
Show file tree
Hide file tree
Showing 21 changed files with 125 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {type CurrentUser, type PortableTextBlock} from '@sanity/types'
import {noop} from 'lodash'
import {useState} from 'react'
import {type UserListWithPermissionsHookValue} from 'sanity'

import {type MentionOptionsHookValue} from '../../../src/structure/comments'
import {CommentInput} from '../../../src/structure/comments/src/components/pte/comment-input/CommentInput'
import {TestWrapper} from '../formBuilder/utils/TestWrapper'

Expand All @@ -18,13 +18,13 @@ const currentUser: CurrentUser = {

const SCHEMA_TYPES: [] = []

const MENTION_DATA: MentionOptionsHookValue = {
const MENTION_DATA: UserListWithPermissionsHookValue = {
data: [
{
id: 'l33t',
displayName: 'Test Person',
email: 'test@test.com',
canBeMentioned: true,
granted: true,
},
],
loading: false,
Expand Down
1 change: 1 addition & 0 deletions packages/sanity/src/core/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export * from './useTemplates'
export * from './useTimeAgo'
export * from './useTools'
export * from './useUnitFormatter'
export * from './useUserListWithPermissions'
export * from './useValidationStatus'
Original file line number Diff line number Diff line change
@@ -1,39 +1,71 @@
/* eslint-disable max-nested-callbacks */
import {type SanityDocument} from '@sanity/client'
import {type User} from '@sanity/types'
import {sortBy} from 'lodash'
import {useEffect, useMemo, useState} from 'react'
import {concat, forkJoin, map, mergeMap, type Observable, of, switchMap} from 'rxjs'

import {
DEFAULT_STUDIO_CLIENT_OPTIONS,
type DocumentValuePermission,
grantsPermissionOn,
type ProjectData,
useClient,
useProjectStore,
useUserStore,
} from 'sanity'
} from '../store'
import {DEFAULT_STUDIO_CLIENT_OPTIONS} from '../studioClient'
import {useClient} from './useClient'

type Loadable<T> = {
data: T | null
error: Error | null
loading: boolean
}

import {type Loadable, type MentionOptionsHookValue, type MentionOptionUser} from '../types'
/**
* @beta
* @hidden
*/
export type UserListWithPermissionsHookValue = Loadable<UserWithPermission[]>

/**
* @beta
* @hidden
*/
export interface UserWithPermission extends User {
granted: boolean
}

const INITIAL_STATE: MentionOptionsHookValue = {
const INITIAL_STATE: UserListWithPermissionsHookValue = {
data: [],
error: null,
loading: true,
}

export interface MentionHookOptions {
/**
* @beta
*/
export interface UserListWithPermissionsOptions {
documentValue: SanityDocument | null
permission: DocumentValuePermission
}

let cachedSystemGroups: [] | null = null

export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookValue {
const {documentValue} = opts
/**
* @beta
* Returns a list of users with the specified permission on the document.
* If no document is provided it will return all as `granted: true`
*/
export function useUserListWithPermissions(
opts: UserListWithPermissionsOptions,
): UserListWithPermissionsHookValue {
const {documentValue, permission} = opts

const projectStore = useProjectStore()
const userStore = useUserStore()
const client = useClient(DEFAULT_STUDIO_CLIENT_OPTIONS)

const [state, setState] = useState<MentionOptionsHookValue>(INITIAL_STATE)
const [state, setState] = useState<UserListWithPermissionsHookValue>(INITIAL_STATE)

const list$ = useMemo(() => {
// 1. Get the project members and filter out the robot users
Expand All @@ -42,7 +74,7 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
.pipe(map((res: ProjectData) => res.members?.filter((m) => !m.isRobot)))

// 2. Map the members to users to get more data of the users such as displayName (used for filtering)
const users$: Observable<MentionOptionUser[]> = members$.pipe(
const users$: Observable<UserWithPermission[]> = members$.pipe(
switchMap(async (members) => {
const ids = members.map(({id}) => id)
const users = await userStore.getUsers(ids)
Expand All @@ -52,7 +84,7 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
res.map((user) => ({
displayName: user.displayName,
id: user.id,
canBeMentioned: false,
granted: false,
})),
),
)
Expand All @@ -61,8 +93,8 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
const cached = cachedSystemGroups
const systemGroup$ = cached ? of(cached) : client.observable.fetch('*[_type == "system.group"]')

// 4. Check if the user has read permission on the document and set the `canBeMentioned` property
const grants$: Observable<MentionOptionUser[]> = forkJoin([users$, systemGroup$]).pipe(
// 4. Check if the user has read permission on the document and set the `granted` property
const grants$: Observable<UserWithPermission[]> = forkJoin([users$, systemGroup$]).pipe(
mergeMap(async ([users, groups]) => {
if (!cached) {
cachedSystemGroups = groups
Expand All @@ -81,13 +113,13 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
const {granted} = await grantsPermissionOn(
user.id,
flattenedGrants,
'read',
permission,
documentValue,
)

return {
...user,
canBeMentioned: granted,
granted: granted,
}
})

Expand All @@ -98,7 +130,7 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
)

// 5. Sort the users alphabetically
const $alphabetical: Observable<Loadable<MentionOptionUser[]>> = grants$.pipe(
const $alphabetical: Observable<Loadable<UserWithPermission[]>> = grants$.pipe(
map((res) => ({
error: null,
loading: false,
Expand All @@ -107,13 +139,18 @@ export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookV
)

return $alphabetical
}, [client.observable, documentValue, projectStore, userStore])
}, [client.observable, documentValue, projectStore, userStore, permission])

useEffect(() => {
const initial$ = of(INITIAL_STATE)
const state$ = concat(initial$, list$)

const sub = state$.subscribe(setState)
const sub = state$.subscribe({
next: setState,
error: (error) => {
setState({data: [], error, loading: false})
},
})

return () => {
sub.unsubscribe()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import {
useClickOutside,
} from '@sanity/ui'
import {useCallback, useMemo, useRef, useState} from 'react'
import {type CurrentUser, type PortableTextBlock, Translate, useTranslation} from 'sanity'
import {
type CurrentUser,
type PortableTextBlock,
Translate,
type UserListWithPermissionsHookValue,
useTranslation,
} from 'sanity'
import styled from 'styled-components'

import {Button, Popover, Tooltip} from '../../../../ui-components'
Expand All @@ -19,7 +25,6 @@ import {
type CommentInputHandle,
type CommentMessage,
hasCommentMessageValue,
type MentionOptionsHookValue,
} from '../../src'

const ContentStack = styled(Stack)`
Expand All @@ -31,7 +36,7 @@ interface CommentsFieldButtonProps {
currentUser: CurrentUser
fieldTitle: string
isRunningSetup: boolean
mentionOptions: MentionOptionsHookValue
mentionOptions: UserListWithPermissionsHookValue
onChange: (value: PortableTextBlock[]) => void
onClick?: () => void
onCommentAdd: () => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import {Container, Flex} from '@sanity/ui'
import {useBoolean, useSelect} from '@sanity/ui-workshop'
import {uuid} from '@sanity/uuid'
import {useCallback, useMemo, useState} from 'react'
import {useCurrentUser} from 'sanity'
import {useCurrentUser, useUserListWithPermissions} from 'sanity'

import {CommentsList} from '../components'
import {useMentionOptions} from '../hooks'
import {
type CommentCreatePayload,
type CommentDocument,
Expand Down Expand Up @@ -172,6 +171,7 @@ const MENTION_HOOK_OPTIONS = {
_rev: '1',
_updatedAt: '2021-05-04T14:54:37Z',
},
permission: 'read' as const,
}

const STATUS_OPTIONS: Record<CommentStatus, CommentStatus> = {open: 'open', resolved: 'resolved'}
Expand All @@ -192,7 +192,7 @@ export default function CommentsListStory() {

const currentUser = useCurrentUser()

const mentionOptions = useMentionOptions(MENTION_HOOK_OPTIONS)
const mentionOptions = useUserListWithPermissions(MENTION_HOOK_OPTIONS)

const handleReplySubmit = useCallback(
(payload: CommentCreatePayload) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Container, Flex} from '@sanity/ui'
import {useUserListWithPermissions} from 'sanity'

import {MentionsMenu} from '../components/mentions'
import {useMentionOptions} from '../hooks'

const DOC = {
documentValue: {
Expand All @@ -11,10 +11,11 @@ const DOC = {
_createdAt: '2021-05-04T14:54:37Z',
_updatedAt: '2021-05-04T14:54:37Z',
},
permission: 'read' as const,
}

export default function MentionsMenuStory() {
const {data, loading} = useMentionOptions(DOC)
const {data, loading} = useUserListWithPermissions(DOC)

return (
<Flex height="fill" align="center">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {Card, Code} from '@sanity/ui'

import {useMentionOptions} from '../hooks'
import {useUserListWithPermissions} from 'sanity'

const DOCUMENT = {
_id: '1e1744ab-43d5-4fff-8a2a-28c58bf0434a',
Expand All @@ -11,8 +10,9 @@ const DOCUMENT = {
}

export default function MentionOptionsHookStory() {
const {data, loading} = useMentionOptions({
const {data, loading} = useUserListWithPermissions({
documentValue: DOCUMENT,
permission: 'read',
})

if (loading) return <div>Loading...</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export default defineScope({
},
{
name: 'mention-options-hook',
title: 'useMentionOptions',
component: lazy(() => import('./MentionOptionsHookStory')),
title: 'UserListWithPermissionsOptions',
component: lazy(() => import('./UserListWithPermissionsOptionsHookStory')),
},
{
name: 'comments-list',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import {uuid} from '@sanity/uuid'
import type * as React from 'react'
import {useCallback, useMemo} from 'react'
import {useTranslation} from 'sanity'
import {type UserListWithPermissionsHookValue, useTranslation} from 'sanity'
import styled, {css} from 'styled-components'

import {commentsLocaleNamespace} from '../../../i18n'
Expand All @@ -18,7 +18,6 @@ import {
type CommentListBreadcrumbs,
type CommentMessage,
type CommentsUIMode,
type MentionOptionsHookValue,
} from '../../types'
import {CommentBreadcrumbs} from '../CommentBreadcrumbs'
import {CreateNewThreadInput} from './CreateNewThreadInput'
Expand Down Expand Up @@ -46,7 +45,7 @@ interface CommentThreadLayoutProps {
currentUser: CurrentUser
fieldPath: string
isSelected: boolean
mentionOptions: MentionOptionsHookValue
mentionOptions: UserListWithPermissionsHookValue
mode: CommentsUIMode
onNewThreadCreate: (payload: CommentCreatePayload) => void
onPathSelect?: (nextPath: CommentsSelectedPath) => void
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {type CurrentUser} from '@sanity/types'
import {BoundaryElementProvider, Flex, Stack} from '@sanity/ui'
import {forwardRef, memo, useCallback, useImperativeHandle, useMemo, useState} from 'react'
import {type UserListWithPermissionsHookValue} from 'sanity'

import {type CommentsSelectedPath} from '../../context'
import {
Expand All @@ -10,7 +11,6 @@ import {
type CommentStatus,
type CommentsUIMode,
type CommentThreadItem,
type MentionOptionsHookValue,
} from '../../types'
import {CommentsListItem} from './CommentsListItem'
import {CommentsListStatus} from './CommentsListStatus'
Expand Down Expand Up @@ -50,7 +50,7 @@ export interface CommentsListProps {
currentUser: CurrentUser
error: Error | null
loading: boolean
mentionOptions: MentionOptionsHookValue
mentionOptions: UserListWithPermissionsHookValue
mode: CommentsUIMode
onCopyLink?: (id: string) => void
onCreateRetry: (id: string) => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {ChevronDownIcon} from '@sanity/icons'
import {type CurrentUser} from '@sanity/types'
import {Flex, Stack, useLayer} from '@sanity/ui'
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {useTranslation} from 'sanity'
import {type UserListWithPermissionsHookValue, useTranslation} from 'sanity'
import styled, {css} from 'styled-components'

import {Button} from '../../../../../ui-components'
Expand All @@ -17,7 +17,6 @@ import {
type CommentReactionOption,
type CommentStatus,
type CommentsUIMode,
type MentionOptionsHookValue,
} from '../../types'
import {SpacerAvatar} from '../avatars'
import {CommentInput, type CommentInputHandle} from '../pte'
Expand Down Expand Up @@ -83,7 +82,7 @@ interface CommentsListItemProps {
canReply?: boolean
currentUser: CurrentUser
isSelected: boolean
mentionOptions: MentionOptionsHookValue
mentionOptions: UserListWithPermissionsHookValue
mode: CommentsUIMode
onCopyLink?: (id: string) => void
onCreateRetry: (id: string) => void
Expand Down

0 comments on commit 5da8891

Please sign in to comment.