Skip to content

Commit

Permalink
feat(releases, core): supporting banner display for remote deleted bu…
Browse files Browse the repository at this point in the history
…ndles (#7371)

* feat(releases, core): remote deleted version documents will show as banner instead of toast warning

* chore(releases, core): using UI components where available and supported

* chore(core, releases): removing padding and using ui-component buttons

* tests(structure): adding tests for new deleted document banner consolidation

* chore(structure): fixing test imports and mocks
  • Loading branch information
jordanl17 authored and juice49 committed Oct 7, 2024
1 parent 265d274 commit da9542a
Show file tree
Hide file tree
Showing 23 changed files with 409 additions and 196 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {CheckmarkIcon} from '@sanity/icons'
import {Box, Flex, Menu, MenuButton, MenuDivider, MenuItem, Spinner, Text} from '@sanity/ui'
import {type ReactElement, useCallback, useMemo} from 'react'
// eslint-disable-next-line no-restricted-imports -- MenuItem requires props, only supported by @sanity/ui
import {Box, Flex, Menu, MenuDivider, MenuItem, Spinner, Text} from '@sanity/ui'
import {memo, type ReactElement, useCallback, useMemo} from 'react'
import {styled} from 'styled-components'

import {Tooltip} from '../../../ui-components'
import {MenuButton, Tooltip} from '../../../ui-components'
import {useTranslation} from '../../i18n'
import {type BundleDocument} from '../../store/bundles/types'
import {useBundles} from '../../store/bundles/useBundles'
Expand Down Expand Up @@ -32,7 +33,7 @@ interface BundleListProps {
/**
* @internal
*/
export function BundleMenu(props: BundleListProps): JSX.Element {
export const BundlesMenu = memo(function BundlesMenu(props: BundleListProps): ReactElement {
const {bundles, loading, actions, button, perspective} = props
const {deletedBundles} = useBundles()
const {currentGlobalBundle, setPerspective} = usePerspective(perspective)
Expand Down Expand Up @@ -166,4 +167,4 @@ export function BundleMenu(props: BundleListProps): JSX.Element {
/>
</>
)
}
})
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {beforeEach, describe, expect, it, jest} from '@jest/globals'
import {Button} from '@sanity/ui'
import {fireEvent, render, screen, within} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import {act} from 'react'
import {type BundleDocument, useBundles} from 'sanity'

import {createTestProvider} from '../../../../../test/testUtils/TestProvider'
import {Button} from '../../../../ui-components'
import {usePerspective} from '../../hooks/usePerspective'
import {LATEST} from '../../util/const'
import {BundleMenu} from '../BundleMenu'
import {BundlesMenu} from '../BundlesMenu'

jest.mock('../../hooks/usePerspective', () => ({
usePerspective: jest.fn().mockReturnValue({
Expand All @@ -27,9 +27,9 @@ jest.mock('../../../store/bundles/useBundles', () => ({

const mockUseBundles = useBundles as jest.Mock<typeof useBundles>

describe('BundleMenu', () => {
describe('BundlesMenu', () => {
const mockUsePerspective = usePerspective as jest.Mock
const ButtonTest = <Button>Button Test</Button>
const ButtonTest = <Button text="Button Test" />
const mockBundles: BundleDocument[] = [
{
hue: 'magenta',
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('BundleMenu', () => {

it('should render loading spinner when loading is true', async () => {
const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={[]} loading />, {
render(<BundlesMenu button={ButtonTest} bundles={[]} loading />, {
wrapper,
})

Expand All @@ -93,7 +93,7 @@ describe('BundleMenu', () => {

it('should render latest bundle menu item when bundles are null', async () => {
const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={null} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={null} loading={false} />, {
wrapper,
})

Expand All @@ -111,7 +111,7 @@ describe('BundleMenu', () => {
...bundle,
archivedAt: '2024-07-29T01:49:56.066Z',
}))
render(<BundleMenu button={ButtonTest} bundles={archivedBundles} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={archivedBundles} loading={false} />, {
wrapper,
})

Expand All @@ -130,7 +130,7 @@ describe('BundleMenu', () => {
})

const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={[]} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={[]} loading={false} />, {
wrapper,
})

Expand All @@ -149,7 +149,7 @@ describe('BundleMenu', () => {
})

const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
wrapper,
})

Expand All @@ -163,7 +163,7 @@ describe('BundleMenu', () => {

it('should render bundle menu items when bundles are provided', async () => {
const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
wrapper,
})

Expand All @@ -184,7 +184,7 @@ describe('BundleMenu', () => {
})

const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
wrapper,
})

Expand All @@ -201,7 +201,7 @@ describe('BundleMenu', () => {

const wrapper = await createTestProvider()
render(
<BundleMenu button={ButtonTest} bundles={mockBundles} loading={false} actions={actions} />,
<BundlesMenu button={ButtonTest} bundles={mockBundles} loading={false} actions={actions} />,
{
wrapper,
},
Expand Down Expand Up @@ -229,7 +229,7 @@ describe('BundleMenu', () => {
},
})
const wrapper = await createTestProvider()
render(<BundleMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
render(<BundlesMenu button={ButtonTest} bundles={mockBundles} loading={false} />, {
wrapper,
})

Expand All @@ -256,7 +256,7 @@ describe('BundleMenu', () => {
})
const wrapper = await createTestProvider()
render(
<BundleMenu
<BundlesMenu
button={ButtonTest}
bundles={[
...mockBundles,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {ArrowRightIcon} from '@sanity/icons'
import {Box, Button, Dialog, Flex, useToast} from '@sanity/ui'
import {Box, Flex, useToast} from '@sanity/ui'
import {type FormEvent, useCallback, useState} from 'react'
import {useTranslation} from 'sanity'

import {Button, Dialog} from '../../../../ui-components'
import {type BundleDocument} from '../../../store/bundles/types'
import {useBundleOperations} from '../../../store/bundles/useBundleOperations'
import {usePerspective} from '../../hooks/usePerspective'
Expand Down Expand Up @@ -90,20 +91,14 @@ export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Elemen
formAction === 'edit' ? t('bundle.dialog.edit.title') : t('bundle.dialog.create.title')

return (
<Dialog
animate
header={dialogTitle}
id="create-bundle-dialog"
onClose={onCancel}
zOffset={5000}
width={1}
>
<Dialog header={dialogTitle} id="create-bundle-dialog" onClose={onCancel} width={1}>
<form onSubmit={handleOnSubmit}>
<Box padding={6}>
<Box padding={4}>
<BundleForm onChange={handleOnChange} value={value} />
</Box>
<Flex justify="flex-end" padding={3}>
<Flex justify="flex-end" paddingTop={5}>
<Button
size="large"
disabled={!value.title?.trim() || isSubmitting}
iconRight={ArrowRightIcon}
type="submit"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import {COLOR_HUES, type ColorHueKey} from '@sanity/color'
import {icons, type IconSymbol, SearchIcon} from '@sanity/icons'
import {
Avatar,
Box,
Button,
Container,
Flex,
Popover,
Stack,
TextInput,
useClickOutside,
} from '@sanity/ui'
import {Avatar, Box, Container, Flex, Stack, TextInput, useClickOutside} from '@sanity/ui'
import {useCallback, useState} from 'react'
import {useTranslation} from 'sanity'
import {styled} from 'styled-components'

import {Button, Popover, TooltipDelayGroupProvider} from '../../../../ui-components'
import {type BundleDocument} from '../../../store/bundles/types'
import {BundleBadge} from '../BundleBadge'

Expand Down Expand Up @@ -75,18 +66,24 @@ export function BundleIconEditorPicker(props: {
content={
<Container data-testid="popover-content">
<Flex gap={1} padding={1}>
{COLOR_HUES.map((hue) => (
<Button
key={hue}
mode="bleed"
onClick={handleHueChange(hue)}
padding={1}
selected={value.hue === hue}
data-testid={`hue-button-${hue}`}
>
<Avatar color={hue} size={0} />
</Button>
))}
<TooltipDelayGroupProvider>
{COLOR_HUES.map((hue) => (
<Button
tooltipProps={{content: hue.replace(/-/g, ' ')}}
key={hue}
mode="bleed"
onClick={handleHueChange(hue)}
paddingY={1}
style={{padding: 0}}
selected={value.hue === hue}
data-testid={`hue-button-${hue}`}
>
<Box style={{margin: '0 -4px'}}>
<Avatar color={hue} size={0} style={{padding: 0}} />
</Box>
</Button>
))}
</TooltipDelayGroupProvider>
</Flex>
<StyledStack>
<Box padding={1}>
Expand All @@ -101,18 +98,22 @@ export function BundleIconEditorPicker(props: {
/>
</Box>
<IconPickerFlex gap={1} overflow="auto" padding={1} wrap="wrap">
{Object.entries(icons)
.filter(([key]) => !iconSearchQuery || key.includes(iconSearchQuery.toLowerCase()))
.map(([key, icon]) => (
<Button
icon={icon}
key={key}
mode="bleed"
onClick={handleIconChange(key as IconSymbol)}
padding={2}
data-testId={`icon-button-${key}`}
/>
))}
<TooltipDelayGroupProvider>
{Object.entries(icons)
.filter(
([key]) => !iconSearchQuery || key.includes(iconSearchQuery.toLowerCase()),
)
.map(([key, icon]) => (
<Button
tooltipProps={{content: key.replace(/-/g, ' ')}}
icon={icon}
key={key}
mode="bleed"
onClick={handleIconChange(key as IconSymbol)}
data-testId={`icon-button-${key}`}
/>
))}
</TooltipDelayGroupProvider>
</IconPickerFlex>
</StyledStack>
</Container>
Expand All @@ -124,15 +125,17 @@ export function BundleIconEditorPicker(props: {
>
<div>
<Button
tooltipProps={{content: t('bundle.form.search-icon-tooltip')}}
mode="bleed"
onClick={handleOnPickerOpen}
padding={0}
ref={setButton}
selected={open}
radius="full"
style={{borderRadius: '50%'}}
data-testid="icon-picker-button"
>
<BundleBadge hue={value.hue} icon={value.icon} />
<Box style={{margin: -8}}>
<BundleBadge hue={value.hue} icon={value.icon} />
</Box>
</Button>
</div>
</Popover>
Expand Down
2 changes: 1 addition & 1 deletion packages/sanity/src/core/bundles/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './BundleBadge'
export * from './BundleMenu'
export * from './BundlesMenu'
export * from './panes/BundleActions'
9 changes: 7 additions & 2 deletions packages/sanity/src/core/i18n/bundles/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,15 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
/** Text shown in usage dialog for an image asset when there are zero, one or more documents using the *unnamed* image **/
'asset-source.usage-list.documents-using-image_unnamed_zero': 'No documents are using this image',

/** Label when a release has been deleted by a different user */
'banners.deleted-bundle-banner.text':
"The '<strong>{{title}}</strong>' release has been deleted.",
/** Action message to add document to release */
'bundle.action.add-to-release': 'Add to {{title}}',
/** Action message for when document is already in release */
'bundle.action.already-in-release': 'Already in release {{title}}',
/** Action message for creating releases */
'bundle.action.create': 'Create release',
/** Label when a release has been deleted by a different user */
'bundle.deleted-toast-title': "The '<strong>{{title}}</strong>' release has been deleted",
/** Label for tooltip on deleted release */
'bundle.deleted-tooltip': 'This release has been deleted',
/** Title for creating releases dialog */
Expand All @@ -143,8 +144,12 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'bundle.form.description': 'Description',
/** Placeholder for the icon and colour picker */
'bundle.form.search-icon': 'Search icons',
/** Tooltip label for the icon display */
'bundle.form.search-icon-tooltip': 'Select release icon',
/** Label for the title form field when creating releases */
'bundle.form.title': 'Title',
/** Tooltip for the dropdown to show all versions of document */
'bundle.version-list.tooltip': 'See all document versions',

/** Action message for navigating to next month */
'calendar.action.go-to-next-month': 'Go to next month',
Expand Down
2 changes: 1 addition & 1 deletion packages/sanity/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export {
BundleActions,
BundleBadge,
BundleMenu,
BundlesMenu,
getBundleSlug,
getDocumentIsInPerspective,
LATEST,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
TrashIcon,
UnarchiveIcon,
} from '@sanity/icons'
import {Button, Menu, MenuButton, Spinner, Text, useToast} from '@sanity/ui'
import {Menu, Spinner, Text, useToast} from '@sanity/ui'
import {useState} from 'react'
import {useTranslation} from 'sanity'
import {useRouter} from 'sanity/router'

import {Dialog, MenuItem} from '../../../../ui-components'
import {Button, Dialog, MenuButton, MenuItem} from '../../../../ui-components'
import {BundleDetailsDialog} from '../../../bundles/components/dialog/BundleDetailsDialog'
import {type BundleDocument} from '../../../store/bundles/types'
import {useBundleOperations} from '../../../store/bundles/useBundleOperations'
Expand Down Expand Up @@ -80,7 +80,7 @@ export const BundleMenuButton = ({disabled, bundle, documentCount}: BundleMenuBu
disabled={bundleMenuDisabled || isPerformingOperation}
icon={isPerformingOperation ? Spinner : EllipsisHorizontalIcon}
mode="bleed"
padding={2}
tooltipProps={{content: t('menu.tooltip')}}
aria-label={t('menu.label')}
data-testid="release-menu-button"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {ErrorOutlineIcon} from '@sanity/icons'
import {type PreviewValue} from '@sanity/types'
import {Card, Text, Tooltip} from '@sanity/ui'
import {Card, Text} from '@sanity/ui'
import {type ForwardedRef, forwardRef, useMemo} from 'react'
import {DocumentPreviewPresence, useDocumentPresence} from 'sanity'
import {IntentLink} from 'sanity/router'

import {Tooltip} from '../../../ui-components'
import {useTranslation} from '../../i18n'
import {SanityDefaultPreview} from '../../preview/components/SanityDefaultPreview'
import {getPublishedId} from '../../util/draftUtils'
Expand Down
Loading

0 comments on commit da9542a

Please sign in to comment.