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(core): option to exclude draft perspective #8028

Merged
merged 3 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/sanity/src/core/i18n/bundles/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,8 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'release.form.placeholer-describe-release': 'Describe the release…',
/** Tooltip for button to hide release visibility */
'release.layer.hide': 'Hide release',
/** Label for draft perspective in navbar */
'release.navbar.drafts': 'Drafts',
/** Label for published releases in navbar */
'release.navbar.published': 'Published',
/** Tooltip for releases navigation in navbar */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ export function usePerspective(): PerspectiveValue {

const toggleExcludedPerspective = useCallback(
(excluded: string) => {
if (excluded === LATEST._id) return
const existingPerspectives = excludedPerspectives || []

const nextExcludedPerspectives = existingPerspectives.includes(excluded)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {CreateReleaseDialog} from '../components/dialog/CreateReleaseDialog'
import {usePerspective} from '../hooks/usePerspective'
import {type ReleaseDocument, type ReleaseType} from '../store/types'
import {useReleases} from '../store/useReleases'
import {LATEST} from '../util/const'
import {
getRangePosition,
GlobalPerspectiveMenuItem,
Expand Down Expand Up @@ -125,6 +126,10 @@ export function GlobalPerspectiveMenu(): JSX.Element {
rangePosition={isRangeVisible ? getRangePosition(range, 0) : undefined}
release={'published'}
/>
<GlobalPerspectiveMenuItem
rangePosition={isRangeVisible ? getRangePosition(range, 1) : undefined}
release={LATEST}
/>
</StyledPublishedBox>
<>
{orderedReleaseTypes.map((releaseType) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {type ReleaseId} from '@sanity/client'
import {DotIcon, EyeClosedIcon, EyeOpenIcon, LockIcon} from '@sanity/icons'
// eslint-disable-next-line no-restricted-imports -- custom use for MenuItem & Button not supported by ui-components
import {Box, Button, Flex, MenuItem, Stack, Text} from '@sanity/ui'
Expand All @@ -8,11 +9,13 @@ import {Tooltip} from '../../../ui-components/tooltip'
import {useTranslation} from '../../i18n/hooks/useTranslation'
import {ReleaseAvatar} from '../components/ReleaseAvatar'
import {usePerspective} from '../hooks/usePerspective'
import {type ReleaseDocument} from '../store/types'
import {isReleaseDocument, type ReleaseDocument} from '../store/types'
import {type LATEST} from '../util/const'
import {getReleaseIdFromReleaseDocumentId} from '../util/getReleaseIdFromReleaseDocumentId'
import {getReleaseTone} from '../util/getReleaseTone'
import {
formatRelativeLocalePublishDate,
isDraftPerspective,
isPublishedPerspective,
isReleaseScheduledOrScheduling,
} from '../util/util'
Expand Down Expand Up @@ -78,67 +81,67 @@ export function getRangePosition(range: LayerRange, index: number): rangePositio
export const GlobalPerspectiveMenuItem = forwardRef<
HTMLDivElement,
{
release: ReleaseDocument | 'published'
release: ReleaseDocument | 'published' | typeof LATEST
rangePosition: rangePosition
}
>((props, ref) => {
const {release, rangePosition} = props
const {
globalReleaseDocumentId,
setPerspectiveFromReleaseDocumentId,
setPerspective,
selectedPerspective,
selectedPerspectiveName,
toggleExcludedPerspective,
isPerspectiveExcluded,
} = usePerspective()
const isReleasePublishedPerspective = isPublishedPerspective(release)
const isUnnamedRelease = !isReleasePublishedPerspective && !release.metadata.title
const releaseId = isReleasePublishedPerspective ? 'published' : release._id
const active = releaseId === globalReleaseDocumentId
const first = rangePosition === 'first'
const within = rangePosition === 'within'
const last = rangePosition === 'last'
const inRange = first || within || last

const releasePerspectiveId = isReleasePublishedPerspective
? releaseId
: getReleaseIdFromReleaseDocumentId(releaseId)
const isReleasePerspectiveExcluded = isPerspectiveExcluded(releasePerspectiveId)

// eslint-disable-next-line no-nested-ternary
Copy link
Contributor Author

@pedrobonamin pedrobonamin Dec 13, 2024

Choose a reason for hiding this comment

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

This will be removed once we refactor latest to just be LATEST = "drafts" as part of #8029

const releaseId: 'published' | 'drafts' | ReleaseId = isReleaseDocument(release)
? (getReleaseIdFromReleaseDocumentId(release._id) as ReleaseId)
: isDraftPerspective(release)
? (release._id as 'drafts')
: (release as 'published')

const active = selectedPerspectiveName
? releaseId === selectedPerspectiveName
: isDraftPerspective(release)

const isReleasePerspectiveExcluded = isPerspectiveExcluded(releaseId)

const {t} = useTranslation()

const displayTitle = useMemo(() => {
if (isUnnamedRelease) {
return t('release.placeholder-untitled-release')
}
if (isPublishedPerspective(release)) return t('release.navbar.published')
if (isDraftPerspective(release)) return t('release.navbar.drafts')

return isReleasePublishedPerspective ? t('release.navbar.published') : release.metadata?.title
}, [isReleasePublishedPerspective, isUnnamedRelease, release, t])
return release.metadata.title || t('release.placeholder-untitled-release')
}, [release, t])

const handleToggleReleaseVisibility = useCallback(
(event: MouseEvent<HTMLDivElement>) => {
event.stopPropagation()
toggleExcludedPerspective(releasePerspectiveId)
toggleExcludedPerspective(releaseId)
},
[toggleExcludedPerspective, releasePerspectiveId],
[toggleExcludedPerspective, releaseId],
)

const handleOnReleaseClick = useCallback(
() =>
isReleasePublishedPerspective
? setPerspective(releaseId)
: setPerspectiveFromReleaseDocumentId(releaseId),
[releaseId, isReleasePublishedPerspective, setPerspective, setPerspectiveFromReleaseDocumentId],
() => setPerspective(releaseId),
[releaseId, setPerspective],
)

const canReleaseBeExcluded =
!isPublishedPerspective(release) && !isReleaseScheduledOrScheduling(release) && inRange && !last
const canReleaseBeExcluded = useMemo(() => {
if (release === 'published') return false
if (isDraftPerspective(release)) return isReleaseDocument(selectedPerspective)
if (isReleaseScheduledOrScheduling(release)) return false
return rangePosition && ['first', 'within'].includes(rangePosition)
}, [rangePosition, release, selectedPerspective])

return (
<GlobalPerspectiveMenuItemIndicator
$isPublished={isReleasePublishedPerspective}
$first={first}
$last={last}
$inRange={inRange}
$isDraft={isDraftPerspective(release)}
$first={rangePosition === 'first'}
$last={rangePosition === 'last'}
$inRange={Boolean(rangePosition)}
ref={ref}
>
<MenuItem onClick={handleOnReleaseClick} padding={1} pressed={active}>
Expand All @@ -156,7 +159,6 @@ export const GlobalPerspectiveMenuItem = forwardRef<
) : (
<ReleaseAvatar tone={getReleaseTone(release)} />
)}
{/* )} */}
</Text>
</Box>
<Stack
Expand All @@ -171,7 +173,7 @@ export const GlobalPerspectiveMenuItem = forwardRef<
<Text size={1} weight="medium">
{displayTitle}
</Text>
{!isPublishedPerspective(release) &&
{isReleaseDocument(release) &&
release.metadata.releaseType === 'scheduled' &&
(release.publishAt || release.metadata.intendedPublishAt) && (
<Text muted size={1}>
Expand All @@ -193,7 +195,7 @@ export const GlobalPerspectiveMenuItem = forwardRef<
/>
</Tooltip>
)}
{!isPublishedPerspective(release) && isReleaseScheduledOrScheduling(release) && (
{isReleaseDocument(release) && isReleaseScheduledOrScheduling(release) && (
<Box padding={2}>
<Text size={1} data-testid="release-lock-icon">
<LockIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export const GlobalPerspectiveMenuItemIndicator = styled.div<{
$inRange: boolean
$last: boolean
$first: boolean
$isPublished: boolean
$isDraft: boolean
}>(
({$inRange, $last, $first, $isPublished}) => css`
({$inRange, $last, $first, $isDraft}) => css`
position: relative;

--indicator-left: ${INDICATOR_LEFT_OFFSET}px;
Expand All @@ -32,9 +32,7 @@ export const GlobalPerspectiveMenuItemIndicator = styled.div<{
left: var(--indicator-left);
bottom: -var(--indicator-bottom);
width: var(--indicator-width);
height: ${$isPublished
? 'calc(var(--indicator-bottom) + 12px)'
: 'var(--indicator-bottom)'};
height: ${$isDraft ? 'calc(var(--indicator-bottom) + 12px)' : 'var(--indicator-bottom)'};
background-color: var(--indicator-color);
}
`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,7 @@ describe('ReleasesNav', () => {
})

it('should set a given perspective from the menu', async () => {
expect(usePerspectiveMockReturn.setPerspectiveFromReleaseDocumentId).toHaveBeenCalledWith(
'_.releases.active-scheduled-2',
)
expect(usePerspectiveMockReturn.setPerspective).not.toHaveBeenCalled()
expect(usePerspectiveMockReturn.setPerspective).toHaveBeenCalledWith('active-scheduled-2')
})

it('should allow for hiding of any deeper layered releases', async () => {
Expand Down Expand Up @@ -230,6 +227,21 @@ describe('ReleasesNav', () => {
).not.toBeInTheDocument()
})

it('should allow for hiding of draft perspective', async () => {
const drafts = within(screen.getByTestId('release-menu'))
.getByText('Drafts')
.closest('button')!

expect(within(drafts).queryByTestId('release-toggle-visibility')).toBeInTheDocument()
// toggle to hide
fireEvent.click(within(drafts).getByTestId('release-toggle-visibility'))
expect(usePerspectiveMockReturn.toggleExcludedPerspective).toHaveBeenCalledWith('drafts')

// toggle to include
fireEvent.click(within(drafts).getByTestId('release-toggle-visibility'))
expect(usePerspectiveMockReturn.toggleExcludedPerspective).toHaveBeenCalledWith('drafts')
})

it('should not allow hiding of the current perspective', async () => {
const currentRelease = within(screen.getByTestId('release-menu'))
.getByText('active Scheduled 2')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ function isElementVisibleInContainer(container: ScrollElement, element: ScrollEl
const containerRect = container.getBoundingClientRect()
const elementRect = element.getBoundingClientRect()

// 32.5px is padding on published element + padding of perspective menu item
const isVisible = elementRect.top >= containerRect.top + 32.5
// 32.5px is padding on published/draft element + padding of perspective/draft menu item
const isVisible = elementRect.top >= containerRect.top + 32.5 * 2

return isVisible
}
Expand Down
Loading