Skip to content

Commit

Permalink
feat: add preview access sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan committed Oct 18, 2024
1 parent e169186 commit 021ff10
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 191 deletions.
1 change: 1 addition & 0 deletions packages/presentation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"dependencies": {
"@sanity/comlink": "workspace:*",
"@sanity/icons": "^3.4.0",
"@sanity/logos": "^2.1.13",
"@sanity/preview-url-secret": "workspace:*",
"@sanity/ui": "^2.8.9",
"@sanity/uuid": "3.0.2",
Expand Down
7 changes: 6 additions & 1 deletion packages/presentation/src/PresentationTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ const Container = styled(Flex)`
export default function PresentationTool(props: {
tool: Tool<PresentationPluginOptions>
canCreateUrlPreviewSecrets: boolean
canToggleSharePreviewAccess: boolean
canUseSharedPreviewAccess: boolean
}): ReactElement {
const {canCreateUrlPreviewSecrets, tool} = props
const {canCreateUrlPreviewSecrets, canToggleSharePreviewAccess, canUseSharedPreviewAccess, tool} =
props
const components = tool.options?.components
const _previewUrl = tool.options?.previewUrl
const name = tool.name || DEFAULT_TOOL_NAME
Expand Down Expand Up @@ -536,6 +539,8 @@ export default function PresentationTool(props: {
<BoundaryElementProvider element={boundaryElement}>
<PreviewFrame
canSharePreviewAccess={canSharePreviewAccess}
canToggleSharePreviewAccess={canToggleSharePreviewAccess}
canUseSharedPreviewAccess={canUseSharedPreviewAccess}
dispatch={dispatch}
iframe={state.iframe}
initialUrl={initialPreviewUrl}
Expand Down
52 changes: 42 additions & 10 deletions packages/presentation/src/PresentationToolGrantsCheck.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import {schemaIdPrefix, schemaIdSingleton, schemaType} from '@sanity/preview-url-secret/constants'
import {
schemaIdPrefix,
schemaIdSingleton,
schemaType,
schemaTypeSingleton,
} from '@sanity/preview-url-secret/constants'
import {useToast} from '@sanity/ui'
import {uuid} from '@sanity/uuid'
import {useEffect, useState, type ReactElement} from 'react'
Expand All @@ -17,27 +22,40 @@ export default function PresentationToolGrantsCheck(props: {
const willGeneratePreviewUrlSecret =
typeof previewUrl === 'object' || typeof previewUrl === 'function'
const grantsStore = useGrantsStore()
const [draftPermission, setDraftPermission] = useState<PermissionCheckResult | null>(null)
const [previewAccessSharingCreatePermission, setCreateAccessSharingPermission] =
useState<PermissionCheckResult | null>(null)
const [previewAccessSharingUpdatePermission, setUpdateAccessSharingPermission] =
useState<PermissionCheckResult | null>(null)
const [previewAccessSharingReadPermission, setReadAccessSharingPermission] =
useState<PermissionCheckResult | null>(null)
const [previewUrlSecretPermission, setPreviewUrlSecretPermission] =
useState<PermissionCheckResult | null>(null)

useEffect(() => {
if (!willGeneratePreviewUrlSecret) return undefined

const draftPermissionSubscription = grantsStore
.checkDocumentPermission('create', {_id: schemaIdSingleton, _type: schemaType})
.subscribe(setDraftPermission)
const previewCreateAccessSharingPermissionSubscription = grantsStore
.checkDocumentPermission('create', {_id: schemaIdSingleton, _type: schemaTypeSingleton})
.subscribe(setCreateAccessSharingPermission)
const previewUpdateAccessSharingPermissionSubscription = grantsStore
.checkDocumentPermission('update', {_id: schemaIdSingleton, _type: schemaTypeSingleton})
.subscribe(setUpdateAccessSharingPermission)
const previewReadAccessSharingPermissionSubscription = grantsStore
.checkDocumentPermission('read', {_id: schemaIdSingleton, _type: schemaTypeSingleton})
.subscribe(setReadAccessSharingPermission)
const previewUrlSecretPermissionSubscription = grantsStore
.checkDocumentPermission('create', {_id: `${schemaIdPrefix}.${uuid()}`, _type: schemaType})
.subscribe(setPreviewUrlSecretPermission)

return () => {
draftPermissionSubscription.unsubscribe()
previewCreateAccessSharingPermissionSubscription.unsubscribe()
previewUpdateAccessSharingPermissionSubscription.unsubscribe()
previewReadAccessSharingPermissionSubscription.unsubscribe()
previewUrlSecretPermissionSubscription.unsubscribe()
}
}, [grantsStore, willGeneratePreviewUrlSecret])

const canCreateUrlPreviewSecrets = draftPermission?.granted && previewUrlSecretPermission?.granted
const canCreateUrlPreviewSecrets = previewUrlSecretPermission?.granted

useEffect(() => {
if (!willGeneratePreviewUrlSecret || canCreateUrlPreviewSecrets !== false) return undefined
Expand All @@ -54,13 +72,27 @@ export default function PresentationToolGrantsCheck(props: {

if (
willGeneratePreviewUrlSecret &&
(!draftPermission ||
typeof draftPermission.granted === 'undefined' ||
(!previewAccessSharingCreatePermission ||
typeof previewAccessSharingCreatePermission.granted === 'undefined' ||
!previewAccessSharingUpdatePermission ||
typeof previewAccessSharingUpdatePermission.granted === 'undefined' ||
!previewUrlSecretPermission ||
!previewAccessSharingReadPermission ||
typeof previewAccessSharingReadPermission.granted === 'undefined' ||
typeof previewUrlSecretPermission.granted === 'undefined')
) {
return <PresentationSpinner />
}

return <PresentationTool {...props} canCreateUrlPreviewSecrets={canCreateUrlPreviewSecrets!} />
return (
<PresentationTool
{...props}
canCreateUrlPreviewSecrets={canCreateUrlPreviewSecrets === true}
canToggleSharePreviewAccess={
previewAccessSharingCreatePermission?.granted === true &&
previewAccessSharingUpdatePermission?.granted === true
}
canUseSharedPreviewAccess={previewAccessSharingReadPermission?.granted === true}
/>
)
}
7 changes: 7 additions & 0 deletions packages/presentation/src/preview/PreviewFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ const PERSPECTIVE_ICONS: Record<PresentationPerspective, ComponentType> = {
}

export interface PreviewFrameProps extends Pick<PresentationState, 'iframe' | 'visualEditing'> {
// @TODO rename to share preview access is enabled in the config
canSharePreviewAccess: boolean
canToggleSharePreviewAccess: boolean
canUseSharedPreviewAccess: boolean
dispatch: DispatchPresentationAction
initialUrl: URL
loadersConnection: Status
Expand All @@ -103,6 +106,8 @@ export const PreviewFrame = memo(
function PreviewFrameComponent(props, forwardedRef) {
const {
canSharePreviewAccess,
canToggleSharePreviewAccess,
canUseSharedPreviewAccess,
dispatch,
iframe,
initialUrl,
Expand Down Expand Up @@ -562,6 +567,8 @@ export const PreviewFrame = memo(
{canSharePreviewAccess && (
<Flex align="center" flex="none" gap={1} paddingX={1}>
<SharePreviewMenu
canToggleSharePreviewAccess={canToggleSharePreviewAccess}
canUseSharedPreviewAccess={canUseSharedPreviewAccess}
previewLocationRoute={previewLocationRoute}
initialUrl={initialUrl}
perspective={perspective}
Expand Down
Loading

0 comments on commit 021ff10

Please sign in to comment.