sanity-plugin-media 4.3.6 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -17
- package/dist/index.cjs +0 -4721
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -239
- package/dist/index.d.cts.map +0 -1
- package/sanity.json +0 -8
- package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
- package/src/__tests__/fixtures/listenMock.ts +0 -9
- package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
- package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
- package/src/__tests__/fixtures/rootState.ts +0 -27
- package/src/__tests__/fixtures/withinDialog.ts +0 -28
- package/src/components/AssetGridVirtualized/index.tsx +0 -94
- package/src/components/AssetMetadata/index.tsx +0 -122
- package/src/components/AssetTableVirtualized/index.tsx +0 -73
- package/src/components/AutoTagInputWrapper/index.tsx +0 -85
- package/src/components/Browser/Browser.test.tsx +0 -45
- package/src/components/Browser/index.tsx +0 -90
- package/src/components/Browser/useBrowserInit.ts +0 -126
- package/src/components/ButtonAssetCopy/index.tsx +0 -65
- package/src/components/ButtonViewGroup/index.tsx +0 -39
- package/src/components/CardAsset/CardAsset.test.tsx +0 -323
- package/src/components/CardAsset/index.tsx +0 -290
- package/src/components/CardUpload/index.tsx +0 -161
- package/src/components/Controls/index.tsx +0 -136
- package/src/components/DebugControls/index.tsx +0 -80
- package/src/components/Dialog/index.tsx +0 -11
- package/src/components/DialogAssetEdit/Details.tsx +0 -181
- package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
- package/src/components/DialogAssetEdit/index.tsx +0 -493
- package/src/components/DialogConfirm/index.tsx +0 -90
- package/src/components/DialogSearchFacets/index.tsx +0 -42
- package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
- package/src/components/DialogTagCreate/index.tsx +0 -111
- package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
- package/src/components/DialogTagEdit/index.tsx +0 -201
- package/src/components/DialogTags/index.tsx +0 -45
- package/src/components/Dialogs/index.tsx +0 -76
- package/src/components/DocumentList/index.tsx +0 -62
- package/src/components/FileAssetPreview/index.tsx +0 -37
- package/src/components/FileIcon/index.tsx +0 -43
- package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
- package/src/components/FormBuilderTool/index.tsx +0 -69
- package/src/components/FormFieldInputLabel/index.tsx +0 -66
- package/src/components/FormFieldInputTags/index.tsx +0 -98
- package/src/components/FormFieldInputText/index.tsx +0 -41
- package/src/components/FormFieldInputTextarea/index.tsx +0 -43
- package/src/components/FormSubmitButton/index.tsx +0 -59
- package/src/components/Header/index.tsx +0 -80
- package/src/components/Image/index.tsx +0 -41
- package/src/components/Items/index.tsx +0 -68
- package/src/components/Notifications/index.tsx +0 -24
- package/src/components/OrderSelect/index.tsx +0 -66
- package/src/components/PickedBar/index.tsx +0 -77
- package/src/components/Progress/index.tsx +0 -38
- package/src/components/ReduxProvider/index.tsx +0 -96
- package/src/components/SearchFacet/index.tsx +0 -66
- package/src/components/SearchFacetNumber/index.tsx +0 -133
- package/src/components/SearchFacetSelect/index.tsx +0 -110
- package/src/components/SearchFacetString/index.tsx +0 -88
- package/src/components/SearchFacetTags/index.tsx +0 -121
- package/src/components/SearchFacets/index.tsx +0 -72
- package/src/components/SearchFacetsControl/index.tsx +0 -140
- package/src/components/TableHeader/index.tsx +0 -110
- package/src/components/TableHeaderItem/index.tsx +0 -61
- package/src/components/TableRowAsset/index.tsx +0 -419
- package/src/components/TableRowUpload/index.tsx +0 -164
- package/src/components/Tag/index.tsx +0 -200
- package/src/components/TagIcon/index.tsx +0 -22
- package/src/components/TagView/index.tsx +0 -39
- package/src/components/TagViewHeader/index.tsx +0 -70
- package/src/components/TagsPanel/index.tsx +0 -40
- package/src/components/TagsVirtualized/index.tsx +0 -160
- package/src/components/TextInputNumber/index.tsx +0 -32
- package/src/components/TextInputSearch/index.tsx +0 -60
- package/src/components/Tool/index.tsx +0 -13
- package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
- package/src/components/UploadDropzone/index.tsx +0 -173
- package/src/config/orders.ts +0 -28
- package/src/config/searchFacets.ts +0 -312
- package/src/constants.ts +0 -87
- package/src/contexts/AssetSourceDispatchContext.tsx +0 -38
- package/src/contexts/DropzoneDispatchContext.tsx +0 -32
- package/src/contexts/ToolOptionsContext.tsx +0 -66
- package/src/formSchema/index.test.ts +0 -56
- package/src/formSchema/index.ts +0 -39
- package/src/hooks/useBreakpointIndex.ts +0 -50
- package/src/hooks/useKeyPress.ts +0 -39
- package/src/hooks/usePortalPopoverProps.ts +0 -13
- package/src/hooks/useTypedSelector.ts +0 -7
- package/src/hooks/useVersionedClient.ts +0 -6
- package/src/index.ts +0 -5
- package/src/modules/assets/actions.ts +0 -42
- package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
- package/src/modules/assets/fetchEpic.test.ts +0 -73
- package/src/modules/assets/index.ts +0 -782
- package/src/modules/assets/reducer.test.ts +0 -91
- package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
- package/src/modules/debug/index.ts +0 -28
- package/src/modules/dialog/actions.ts +0 -10
- package/src/modules/dialog/epics.test.ts +0 -168
- package/src/modules/dialog/index.ts +0 -238
- package/src/modules/dialog/reducer.test.ts +0 -185
- package/src/modules/index.ts +0 -117
- package/src/modules/notifications/epics.test.ts +0 -374
- package/src/modules/notifications/index.ts +0 -199
- package/src/modules/notifications/reducer.test.ts +0 -54
- package/src/modules/search/index.test.ts +0 -36
- package/src/modules/search/index.ts +0 -167
- package/src/modules/selected/index.ts +0 -22
- package/src/modules/selectors.test.ts +0 -21
- package/src/modules/selectors.ts +0 -17
- package/src/modules/tags/epics.test.ts +0 -96
- package/src/modules/tags/index.test.ts +0 -42
- package/src/modules/tags/index.ts +0 -540
- package/src/modules/types.ts +0 -3
- package/src/modules/uploads/actions.ts +0 -13
- package/src/modules/uploads/epics.test.ts +0 -109
- package/src/modules/uploads/index.test.ts +0 -59
- package/src/modules/uploads/index.ts +0 -272
- package/src/operators/checkTagName.test.ts +0 -29
- package/src/operators/checkTagName.ts +0 -33
- package/src/operators/debugThrottle.ts +0 -25
- package/src/plugin.tsx +0 -54
- package/src/schemas/tag.ts +0 -28
- package/src/styled/GlobalStyles/index.tsx +0 -40
- package/src/styled/react-select/creatable.tsx +0 -184
- package/src/styled/react-select/single.tsx +0 -184
- package/src/types/index.ts +0 -346
- package/src/types/sanity-ui.d.ts +0 -5
- package/src/utils/applyMediaTags.ts +0 -87
- package/src/utils/blocksToText.test.ts +0 -43
- package/src/utils/blocksToText.ts +0 -27
- package/src/utils/constructFilter.test.ts +0 -120
- package/src/utils/constructFilter.ts +0 -98
- package/src/utils/generatePreviewBlobUrl.test.ts +0 -68
- package/src/utils/generatePreviewBlobUrl.ts +0 -53
- package/src/utils/getAssetResolution.test.ts +0 -13
- package/src/utils/getAssetResolution.ts +0 -7
- package/src/utils/getDocumentAssetIds.test.ts +0 -50
- package/src/utils/getDocumentAssetIds.ts +0 -35
- package/src/utils/getSchemeColor.test.ts +0 -12
- package/src/utils/getSchemeColor.ts +0 -43
- package/src/utils/getTagSelectOptions.test.ts +0 -44
- package/src/utils/getTagSelectOptions.ts +0 -16
- package/src/utils/getUniqueDocuments.test.ts +0 -26
- package/src/utils/getUniqueDocuments.ts +0 -15
- package/src/utils/imageDprUrl.test.ts +0 -46
- package/src/utils/imageDprUrl.ts +0 -27
- package/src/utils/isSupportedAssetType.test.ts +0 -16
- package/src/utils/isSupportedAssetType.ts +0 -15
- package/src/utils/mediaField.ts +0 -73
- package/src/utils/sanitizeFormData.test.ts +0 -59
- package/src/utils/sanitizeFormData.ts +0 -26
- package/src/utils/typeGuards.test.ts +0 -18
- package/src/utils/typeGuards.ts +0 -9
- package/src/utils/uploadSanityAsset.test.ts +0 -29
- package/src/utils/uploadSanityAsset.ts +0 -97
- package/src/utils/withMaxConcurrency.test.ts +0 -43
- package/src/utils/withMaxConcurrency.ts +0 -55
- package/src/utils/zodFormResolver.ts +0 -17
- package/v2-incompatible.js +0 -11
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import {WarningOutlineIcon} from '@sanity/icons'
|
|
2
|
-
import {Box, Button, Flex, Stack, Text} from '@sanity/ui'
|
|
3
|
-
import {type ReactNode} from 'react'
|
|
4
|
-
import {useDispatch} from 'react-redux'
|
|
5
|
-
|
|
6
|
-
import {dialogActions} from '../../modules/dialog'
|
|
7
|
-
import type {DialogConfirmProps} from '../../types'
|
|
8
|
-
import Dialog from '../Dialog'
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
children?: ReactNode
|
|
12
|
-
dialog: DialogConfirmProps
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const DialogConfirm = (props: Props) => {
|
|
16
|
-
const {children, dialog} = props
|
|
17
|
-
|
|
18
|
-
// Redux
|
|
19
|
-
const dispatch = useDispatch()
|
|
20
|
-
|
|
21
|
-
// Callbacks
|
|
22
|
-
const handleClose = () => {
|
|
23
|
-
dispatch(dialogActions.remove({id: dialog?.id}))
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const handleConfirm = () => {
|
|
27
|
-
// Close target dialog, if provided
|
|
28
|
-
if (dialog?.closeDialogId) {
|
|
29
|
-
dispatch(dialogActions.remove({id: dialog?.closeDialogId}))
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (dialog?.confirmCallbackAction) {
|
|
33
|
-
dispatch(dialog.confirmCallbackAction)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Close self
|
|
37
|
-
handleClose()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const Footer = () => (
|
|
41
|
-
<Box padding={3}>
|
|
42
|
-
<Flex justify="space-between">
|
|
43
|
-
<Button fontSize={1} mode="bleed" onClick={handleClose} text="Cancel" />
|
|
44
|
-
<Button
|
|
45
|
-
fontSize={1}
|
|
46
|
-
onClick={handleConfirm}
|
|
47
|
-
text={dialog?.confirmText}
|
|
48
|
-
tone={dialog?.tone}
|
|
49
|
-
/>
|
|
50
|
-
</Flex>
|
|
51
|
-
</Box>
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
const Header = () => (
|
|
55
|
-
<Flex align="center">
|
|
56
|
-
<Box paddingX={1}>
|
|
57
|
-
<WarningOutlineIcon />
|
|
58
|
-
</Box>
|
|
59
|
-
<Box marginLeft={2}>{dialog?.headerTitle}</Box>
|
|
60
|
-
</Flex>
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<Dialog
|
|
65
|
-
animate
|
|
66
|
-
// oxlint-disable-next-line react/react-compiler
|
|
67
|
-
footer={<Footer />}
|
|
68
|
-
// oxlint-disable-next-line react/react-compiler
|
|
69
|
-
header={<Header />}
|
|
70
|
-
id="confirm"
|
|
71
|
-
onClose={handleClose}
|
|
72
|
-
width={1}
|
|
73
|
-
>
|
|
74
|
-
<Box paddingX={4} paddingY={4}>
|
|
75
|
-
<Stack space={3}>
|
|
76
|
-
{dialog?.title && <Text size={1}>{dialog.title}</Text>}
|
|
77
|
-
{dialog?.description && (
|
|
78
|
-
<Text muted size={1}>
|
|
79
|
-
<em>{dialog.description}</em>
|
|
80
|
-
</Text>
|
|
81
|
-
)}
|
|
82
|
-
</Stack>
|
|
83
|
-
</Box>
|
|
84
|
-
|
|
85
|
-
{children}
|
|
86
|
-
</Dialog>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export default DialogConfirm
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {Box} from '@sanity/ui'
|
|
2
|
-
import {type ReactNode, useCallback} from 'react'
|
|
3
|
-
import {useDispatch} from 'react-redux'
|
|
4
|
-
|
|
5
|
-
import {dialogActions} from '../../modules/dialog'
|
|
6
|
-
import type {DialogSearchFacetsProps} from '../../types'
|
|
7
|
-
import Dialog from '../Dialog'
|
|
8
|
-
import SearchFacets from '../SearchFacets'
|
|
9
|
-
import SearchFacetsControl from '../SearchFacetsControl'
|
|
10
|
-
|
|
11
|
-
type Props = {
|
|
12
|
-
children: ReactNode
|
|
13
|
-
dialog: DialogSearchFacetsProps
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const DialogSearchFacets = (props: Props) => {
|
|
17
|
-
const {
|
|
18
|
-
children,
|
|
19
|
-
dialog: {id},
|
|
20
|
-
} = props
|
|
21
|
-
|
|
22
|
-
// Redux
|
|
23
|
-
const dispatch = useDispatch()
|
|
24
|
-
|
|
25
|
-
// Callbacks
|
|
26
|
-
const handleClose = useCallback(() => {
|
|
27
|
-
dispatch(dialogActions.clear())
|
|
28
|
-
}, [dispatch])
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Dialog animate header="Filters" id={id} onClose={handleClose} width={1}>
|
|
32
|
-
<Box padding={3}>
|
|
33
|
-
<SearchFacets layout="stack" />
|
|
34
|
-
<SearchFacetsControl />
|
|
35
|
-
</Box>
|
|
36
|
-
|
|
37
|
-
{children}
|
|
38
|
-
</Dialog>
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default DialogSearchFacets
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import {screen, waitFor} from '@testing-library/react'
|
|
2
|
-
import userEvent from '@testing-library/user-event'
|
|
3
|
-
import {describe, expect, it, vi} from 'vitest'
|
|
4
|
-
|
|
5
|
-
import {renderWithProviders} from '../../__tests__/fixtures/renderWithProviders'
|
|
6
|
-
import {createTestRootState} from '../../__tests__/fixtures/rootState'
|
|
7
|
-
import {getDialogRoot, inputByName, withinDialog} from '../../__tests__/fixtures/withinDialog'
|
|
8
|
-
import {tagsActions} from '../../modules/tags'
|
|
9
|
-
import DialogTagCreate from './index'
|
|
10
|
-
|
|
11
|
-
describe('DialogTagCreate', () => {
|
|
12
|
-
it('dispatches tag create flow when form is valid', async () => {
|
|
13
|
-
const user = userEvent.setup()
|
|
14
|
-
const {store} = renderWithProviders(
|
|
15
|
-
<DialogTagCreate dialog={{id: 'dlg-1', type: 'tagCreate'}}>
|
|
16
|
-
<span />
|
|
17
|
-
</DialogTagCreate>,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
const dlg = withinDialog(/create tag/i, screen)
|
|
21
|
-
await user.type(inputByName(/create tag/i, screen, 'name'), 'my-tag')
|
|
22
|
-
await user.click(dlg.getByRole('button', {name: /save and close/i}))
|
|
23
|
-
|
|
24
|
-
expect(store.getState().tags.creating).toBe(true)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('dispatches createRequest with a trimmed tag name', async () => {
|
|
28
|
-
const user = userEvent.setup()
|
|
29
|
-
const {store} = renderWithProviders(
|
|
30
|
-
<DialogTagCreate dialog={{id: 'dlg-1', type: 'tagCreate'}}>
|
|
31
|
-
<span />
|
|
32
|
-
</DialogTagCreate>,
|
|
33
|
-
)
|
|
34
|
-
const dispatchSpy = vi.spyOn(store, 'dispatch')
|
|
35
|
-
const dlg = withinDialog(/create tag/i, screen)
|
|
36
|
-
|
|
37
|
-
await user.type(inputByName(/create tag/i, screen, 'name'), ' spaced ')
|
|
38
|
-
await user.click(dlg.getByRole('button', {name: /save and close/i}))
|
|
39
|
-
|
|
40
|
-
await waitFor(() => {
|
|
41
|
-
let createAction
|
|
42
|
-
for (const call of dispatchSpy.mock.calls) {
|
|
43
|
-
const action = call[0]
|
|
44
|
-
if (tagsActions.createRequest.match(action)) {
|
|
45
|
-
createAction = action
|
|
46
|
-
break
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
expect(createAction).toBeDefined()
|
|
50
|
-
expect(createAction?.payload).toEqual({name: 'spaced'})
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('keeps Save disabled until the name is non-empty and valid', async () => {
|
|
55
|
-
const user = userEvent.setup()
|
|
56
|
-
renderWithProviders(
|
|
57
|
-
<DialogTagCreate dialog={{id: 'dlg-1', type: 'tagCreate'}}>
|
|
58
|
-
<span />
|
|
59
|
-
</DialogTagCreate>,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
expect(
|
|
63
|
-
withinDialog(/create tag/i, screen).getByRole('button', {name: /save and close/i}),
|
|
64
|
-
).toBeDisabled()
|
|
65
|
-
|
|
66
|
-
const nameInput = inputByName(/create tag/i, screen, 'name')
|
|
67
|
-
await user.type(nameInput, 'a')
|
|
68
|
-
await user.tab()
|
|
69
|
-
await waitFor(() => {
|
|
70
|
-
expect(
|
|
71
|
-
withinDialog(/create tag/i, screen).getByRole('button', {name: /save and close/i}),
|
|
72
|
-
).not.toBeDisabled()
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('clears the entire dialog stack when the dialog close control is used', async () => {
|
|
77
|
-
const user = userEvent.setup()
|
|
78
|
-
const base = createTestRootState({
|
|
79
|
-
dialog: {
|
|
80
|
-
items: [
|
|
81
|
-
{id: 'dlg-1', type: 'tagCreate'},
|
|
82
|
-
{id: 'tags', type: 'tags'},
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
const {store} = renderWithProviders(
|
|
88
|
-
<DialogTagCreate dialog={{id: 'dlg-1', type: 'tagCreate'}}>
|
|
89
|
-
<span />
|
|
90
|
-
</DialogTagCreate>,
|
|
91
|
-
{preloaded: base},
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
const dlg = withinDialog(/create tag/i, screen)
|
|
95
|
-
await user.click(dlg.getByRole('button', {name: /close dialog/i}))
|
|
96
|
-
|
|
97
|
-
expect(store.getState().dialog.items).toEqual([])
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('shows an error indicator beside the name when tag creation failed on the server', async () => {
|
|
101
|
-
const base = createTestRootState({
|
|
102
|
-
tags: {
|
|
103
|
-
...createTestRootState().tags,
|
|
104
|
-
creatingError: {message: 'Tag already exists', statusCode: 409},
|
|
105
|
-
},
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
renderWithProviders(
|
|
109
|
-
<DialogTagCreate dialog={{id: 'dlg-1', type: 'tagCreate'}}>
|
|
110
|
-
<span />
|
|
111
|
-
</DialogTagCreate>,
|
|
112
|
-
{preloaded: base},
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
await waitFor(() => {
|
|
116
|
-
expect(
|
|
117
|
-
getDialogRoot(/create tag/i, screen).querySelector('[data-sanity-icon="error-outline"]'),
|
|
118
|
-
).toBeTruthy()
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
})
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import {Box, Flex} from '@sanity/ui'
|
|
2
|
-
import {type ReactNode, useEffect} from 'react'
|
|
3
|
-
import {type SubmitHandler, useForm} from 'react-hook-form'
|
|
4
|
-
import {useDispatch} from 'react-redux'
|
|
5
|
-
|
|
6
|
-
import {tagFormSchema} from '../../formSchema'
|
|
7
|
-
import useTypedSelector from '../../hooks/useTypedSelector'
|
|
8
|
-
import {dialogActions} from '../../modules/dialog'
|
|
9
|
-
import {tagsActions} from '../../modules/tags'
|
|
10
|
-
import type {DialogTagCreateProps, TagFormData} from '../../types'
|
|
11
|
-
import sanitizeFormData from '../../utils/sanitizeFormData'
|
|
12
|
-
import zodFormResolver from '../../utils/zodFormResolver'
|
|
13
|
-
import Dialog from '../Dialog'
|
|
14
|
-
import FormFieldInputText from '../FormFieldInputText'
|
|
15
|
-
import FormSubmitButton from '../FormSubmitButton'
|
|
16
|
-
|
|
17
|
-
type Props = {
|
|
18
|
-
children: ReactNode
|
|
19
|
-
dialog: DialogTagCreateProps
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const DialogTagCreate = (props: Props) => {
|
|
23
|
-
const {
|
|
24
|
-
children,
|
|
25
|
-
dialog: {id},
|
|
26
|
-
} = props
|
|
27
|
-
|
|
28
|
-
const dispatch = useDispatch()
|
|
29
|
-
|
|
30
|
-
const creating = useTypedSelector((state) => state.tags.creating)
|
|
31
|
-
const creatingError = useTypedSelector((state) => state.tags.creatingError)
|
|
32
|
-
|
|
33
|
-
const {
|
|
34
|
-
// Read the formState before render to subscribe the form state through Proxy
|
|
35
|
-
formState: {errors, isDirty, isValid},
|
|
36
|
-
handleSubmit,
|
|
37
|
-
register,
|
|
38
|
-
setError,
|
|
39
|
-
} = useForm<TagFormData>({
|
|
40
|
-
defaultValues: {
|
|
41
|
-
name: '',
|
|
42
|
-
},
|
|
43
|
-
mode: 'onChange',
|
|
44
|
-
resolver: zodFormResolver<TagFormData>(tagFormSchema),
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const formUpdating = creating
|
|
48
|
-
|
|
49
|
-
const handleClose = () => {
|
|
50
|
-
dispatch(dialogActions.clear())
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// - submit react-hook-form
|
|
54
|
-
const onSubmit: SubmitHandler<TagFormData> = (formData) => {
|
|
55
|
-
const sanitizedFormData = sanitizeFormData(formData)
|
|
56
|
-
|
|
57
|
-
dispatch(tagsActions.createRequest({name: sanitizedFormData['name']}))
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (creatingError) {
|
|
62
|
-
setError('name', {
|
|
63
|
-
message: creatingError?.message,
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
}, [creatingError, setError])
|
|
67
|
-
|
|
68
|
-
const Footer = () => (
|
|
69
|
-
<Box padding={3}>
|
|
70
|
-
<Flex justify="flex-end">
|
|
71
|
-
{/* Submit button */}
|
|
72
|
-
<FormSubmitButton
|
|
73
|
-
disabled={formUpdating || !isDirty || !isValid}
|
|
74
|
-
isValid={isValid}
|
|
75
|
-
onClick={handleSubmit(onSubmit)}
|
|
76
|
-
/>
|
|
77
|
-
</Flex>
|
|
78
|
-
</Box>
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<Dialog
|
|
83
|
-
animate
|
|
84
|
-
// oxlint-disable-next-line react/react-compiler
|
|
85
|
-
footer={<Footer />}
|
|
86
|
-
header="Create Tag"
|
|
87
|
-
id={id}
|
|
88
|
-
onClose={handleClose}
|
|
89
|
-
width={1}
|
|
90
|
-
>
|
|
91
|
-
{/* Form fields */}
|
|
92
|
-
<Box as="form" padding={4} onSubmit={handleSubmit(onSubmit)}>
|
|
93
|
-
{/* Hidden button to enable enter key submissions */}
|
|
94
|
-
<button style={{display: 'none'}} tabIndex={-1} type="submit" />
|
|
95
|
-
|
|
96
|
-
{/* Title */}
|
|
97
|
-
<FormFieldInputText
|
|
98
|
-
{...register('name')}
|
|
99
|
-
disabled={formUpdating}
|
|
100
|
-
error={errors?.name?.message}
|
|
101
|
-
label="Name"
|
|
102
|
-
name="name"
|
|
103
|
-
/>
|
|
104
|
-
</Box>
|
|
105
|
-
|
|
106
|
-
{children}
|
|
107
|
-
</Dialog>
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export default DialogTagCreate
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import {fireEvent, screen, waitFor} from '@testing-library/react'
|
|
2
|
-
import userEvent from '@testing-library/user-event'
|
|
3
|
-
import {Subject} from 'rxjs'
|
|
4
|
-
import {describe, expect, it, vi} from 'vitest'
|
|
5
|
-
|
|
6
|
-
import {createMockSanityClient} from '../../__tests__/fixtures/mockSanityClient'
|
|
7
|
-
import {renderWithProviders} from '../../__tests__/fixtures/renderWithProviders'
|
|
8
|
-
import {createTestRootState} from '../../__tests__/fixtures/rootState'
|
|
9
|
-
import {inputByName, withinDialog} from '../../__tests__/fixtures/withinDialog'
|
|
10
|
-
import {tagsActions} from '../../modules/tags'
|
|
11
|
-
import type {Tag} from '../../types'
|
|
12
|
-
import DialogTagEdit from './index'
|
|
13
|
-
|
|
14
|
-
const tag: Tag = {
|
|
15
|
-
_id: 't1',
|
|
16
|
-
_type: 'media.tag',
|
|
17
|
-
_createdAt: '',
|
|
18
|
-
_updatedAt: '',
|
|
19
|
-
_rev: 'r1',
|
|
20
|
-
name: {_type: 'slug', current: 'alpha'},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const tagsPreloaded = {
|
|
24
|
-
allIds: ['t1'],
|
|
25
|
-
byIds: {
|
|
26
|
-
t1: {_type: 'tag' as const, tag, picked: false, updating: false},
|
|
27
|
-
},
|
|
28
|
-
creating: false,
|
|
29
|
-
fetchCount: -1,
|
|
30
|
-
fetching: false,
|
|
31
|
-
panelVisible: true,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
vi.mock('../../hooks/useVersionedClient', () => ({
|
|
35
|
-
default: () =>
|
|
36
|
-
createMockSanityClient({
|
|
37
|
-
listen: vi.fn(() => new Subject()),
|
|
38
|
-
}),
|
|
39
|
-
}))
|
|
40
|
-
|
|
41
|
-
describe('DialogTagEdit', () => {
|
|
42
|
-
it('dispatches updateRequest when name changes and form submits', async () => {
|
|
43
|
-
const user = userEvent.setup()
|
|
44
|
-
const {store} = renderWithProviders(
|
|
45
|
-
<DialogTagEdit dialog={{id: 'dlg-1', type: 'tagEdit', tagId: 't1'}}>
|
|
46
|
-
<span />
|
|
47
|
-
</DialogTagEdit>,
|
|
48
|
-
{
|
|
49
|
-
preloaded: {
|
|
50
|
-
tags: tagsPreloaded,
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
const dlg = withinDialog(/edit tag/i, screen)
|
|
56
|
-
const input = inputByName(/edit tag/i, screen, 'name')
|
|
57
|
-
await user.clear(input)
|
|
58
|
-
await user.type(input, 'beta')
|
|
59
|
-
await user.click(dlg.getByRole('button', {name: /save and close/i}))
|
|
60
|
-
|
|
61
|
-
expect(store.getState().tags.byIds['t1']!.updating).toBe(true)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('dispatches updateRequest with slug-shaped form data', async () => {
|
|
65
|
-
const user = userEvent.setup()
|
|
66
|
-
const {store} = renderWithProviders(
|
|
67
|
-
<DialogTagEdit dialog={{id: 'dlg-1', type: 'tagEdit', tagId: 't1'}}>
|
|
68
|
-
<span />
|
|
69
|
-
</DialogTagEdit>,
|
|
70
|
-
{
|
|
71
|
-
preloaded: {
|
|
72
|
-
tags: tagsPreloaded,
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
)
|
|
76
|
-
const dispatchSpy = vi.spyOn(store, 'dispatch')
|
|
77
|
-
const dlg = withinDialog(/edit tag/i, screen)
|
|
78
|
-
|
|
79
|
-
const input = inputByName(/edit tag/i, screen, 'name')
|
|
80
|
-
await user.clear(input)
|
|
81
|
-
await user.type(input, 'gamma')
|
|
82
|
-
await user.click(dlg.getByRole('button', {name: /save and close/i}))
|
|
83
|
-
|
|
84
|
-
await waitFor(() => {
|
|
85
|
-
let updateAction
|
|
86
|
-
for (const call of dispatchSpy.mock.calls) {
|
|
87
|
-
const action = call[0]
|
|
88
|
-
if (tagsActions.updateRequest.match(action)) {
|
|
89
|
-
updateAction = action
|
|
90
|
-
break
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
expect(updateAction).toBeDefined()
|
|
94
|
-
expect(updateAction?.payload).toMatchObject({
|
|
95
|
-
closeDialogId: 't1',
|
|
96
|
-
formData: {
|
|
97
|
-
name: {_type: 'slug', current: 'gamma'},
|
|
98
|
-
},
|
|
99
|
-
tag,
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('does not enable Save until the name is edited', () => {
|
|
105
|
-
renderWithProviders(
|
|
106
|
-
<DialogTagEdit dialog={{id: 'dlg-1', type: 'tagEdit', tagId: 't1'}}>
|
|
107
|
-
<span />
|
|
108
|
-
</DialogTagEdit>,
|
|
109
|
-
{
|
|
110
|
-
preloaded: {
|
|
111
|
-
tags: tagsPreloaded,
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
const dlg = withinDialog(/edit tag/i, screen)
|
|
117
|
-
expect(dlg.getByRole('button', {name: /save and close/i})).toBeDisabled()
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('removes only this dialog when closed', async () => {
|
|
121
|
-
const user = userEvent.setup()
|
|
122
|
-
const base = createTestRootState({
|
|
123
|
-
dialog: {
|
|
124
|
-
items: [
|
|
125
|
-
{id: 'dlg-1', type: 'tagEdit', tagId: 't1'},
|
|
126
|
-
{id: 'tags', type: 'tags'},
|
|
127
|
-
],
|
|
128
|
-
},
|
|
129
|
-
tags: tagsPreloaded,
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
const {store} = renderWithProviders(
|
|
133
|
-
<DialogTagEdit dialog={{id: 'dlg-1', type: 'tagEdit', tagId: 't1'}}>
|
|
134
|
-
<span />
|
|
135
|
-
</DialogTagEdit>,
|
|
136
|
-
{preloaded: base},
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
const dlg = withinDialog(/edit tag/i, screen)
|
|
140
|
-
await user.click(dlg.getByRole('button', {name: /close dialog/i}))
|
|
141
|
-
|
|
142
|
-
expect(store.getState().dialog.items).toEqual([{id: 'tags', type: 'tags'}])
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('opens the delete confirmation dialog when Delete is clicked', async () => {
|
|
146
|
-
const {store} = renderWithProviders(
|
|
147
|
-
<DialogTagEdit dialog={{id: 'dlg-1', type: 'tagEdit', tagId: 't1'}}>
|
|
148
|
-
<span />
|
|
149
|
-
</DialogTagEdit>,
|
|
150
|
-
{
|
|
151
|
-
preloaded: {
|
|
152
|
-
tags: tagsPreloaded,
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
const dlg = withinDialog(/edit tag/i, screen)
|
|
158
|
-
fireEvent.click(dlg.getByRole('button', {name: /^delete$/i}))
|
|
159
|
-
|
|
160
|
-
const confirm = store.getState().dialog.items.find((d) => d.type === 'confirm')
|
|
161
|
-
expect(confirm).toBeDefined()
|
|
162
|
-
expect(confirm?.title).toMatch(/permanently delete/i)
|
|
163
|
-
expect(confirm?.headerTitle).toBe('Confirm deletion')
|
|
164
|
-
})
|
|
165
|
-
})
|