sanity-plugin-media 4.3.5 → 5.0.0

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.
Files changed (166) hide show
  1. package/dist/index.d.ts +190 -413
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +2532 -3564
  4. package/dist/index.js.map +1 -1
  5. package/package.json +29 -35
  6. package/dist/index.cjs +0 -5753
  7. package/dist/index.cjs.map +0 -1
  8. package/dist/index.d.cts +0 -462
  9. package/sanity.json +0 -8
  10. package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
  11. package/src/__tests__/fixtures/listenMock.ts +0 -9
  12. package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
  13. package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
  14. package/src/__tests__/fixtures/rootState.ts +0 -27
  15. package/src/__tests__/fixtures/withinDialog.ts +0 -28
  16. package/src/components/AssetGridVirtualized/index.tsx +0 -94
  17. package/src/components/AssetMetadata/index.tsx +0 -122
  18. package/src/components/AssetTableVirtualized/index.tsx +0 -73
  19. package/src/components/AutoTagInputWrapper/index.tsx +0 -87
  20. package/src/components/Browser/Browser.test.tsx +0 -45
  21. package/src/components/Browser/index.tsx +0 -90
  22. package/src/components/Browser/useBrowserInit.ts +0 -126
  23. package/src/components/ButtonAssetCopy/index.tsx +0 -65
  24. package/src/components/ButtonViewGroup/index.tsx +0 -39
  25. package/src/components/CardAsset/CardAsset.test.tsx +0 -323
  26. package/src/components/CardAsset/index.tsx +0 -290
  27. package/src/components/CardUpload/index.tsx +0 -161
  28. package/src/components/Controls/index.tsx +0 -136
  29. package/src/components/DebugControls/index.tsx +0 -80
  30. package/src/components/Dialog/index.tsx +0 -11
  31. package/src/components/DialogAssetEdit/Details.tsx +0 -181
  32. package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
  33. package/src/components/DialogAssetEdit/index.tsx +0 -492
  34. package/src/components/DialogConfirm/index.tsx +0 -88
  35. package/src/components/DialogSearchFacets/index.tsx +0 -42
  36. package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
  37. package/src/components/DialogTagCreate/index.tsx +0 -103
  38. package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
  39. package/src/components/DialogTagEdit/index.tsx +0 -190
  40. package/src/components/DialogTags/index.tsx +0 -45
  41. package/src/components/Dialogs/index.tsx +0 -76
  42. package/src/components/DocumentList/index.tsx +0 -62
  43. package/src/components/FileAssetPreview/index.tsx +0 -37
  44. package/src/components/FileIcon/index.tsx +0 -43
  45. package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
  46. package/src/components/FormBuilderTool/index.tsx +0 -69
  47. package/src/components/FormFieldInputLabel/index.tsx +0 -66
  48. package/src/components/FormFieldInputTags/index.tsx +0 -98
  49. package/src/components/FormFieldInputText/index.tsx +0 -41
  50. package/src/components/FormFieldInputTextarea/index.tsx +0 -43
  51. package/src/components/FormSubmitButton/index.tsx +0 -59
  52. package/src/components/Header/index.tsx +0 -80
  53. package/src/components/Image/index.tsx +0 -41
  54. package/src/components/Items/index.tsx +0 -68
  55. package/src/components/Notifications/index.tsx +0 -24
  56. package/src/components/OrderSelect/index.tsx +0 -66
  57. package/src/components/PickedBar/index.tsx +0 -77
  58. package/src/components/Progress/index.tsx +0 -38
  59. package/src/components/ReduxProvider/index.tsx +0 -96
  60. package/src/components/SearchFacet/index.tsx +0 -66
  61. package/src/components/SearchFacetNumber/index.tsx +0 -133
  62. package/src/components/SearchFacetSelect/index.tsx +0 -110
  63. package/src/components/SearchFacetString/index.tsx +0 -88
  64. package/src/components/SearchFacetTags/index.tsx +0 -121
  65. package/src/components/SearchFacets/index.tsx +0 -72
  66. package/src/components/SearchFacetsControl/index.tsx +0 -140
  67. package/src/components/TableHeader/index.tsx +0 -110
  68. package/src/components/TableHeaderItem/index.tsx +0 -61
  69. package/src/components/TableRowAsset/index.tsx +0 -420
  70. package/src/components/TableRowUpload/index.tsx +0 -164
  71. package/src/components/Tag/index.tsx +0 -200
  72. package/src/components/TagIcon/index.tsx +0 -22
  73. package/src/components/TagView/index.tsx +0 -39
  74. package/src/components/TagViewHeader/index.tsx +0 -70
  75. package/src/components/TagsPanel/index.tsx +0 -40
  76. package/src/components/TagsVirtualized/index.tsx +0 -160
  77. package/src/components/TextInputNumber/index.tsx +0 -32
  78. package/src/components/TextInputSearch/index.tsx +0 -60
  79. package/src/components/Tool/index.tsx +0 -13
  80. package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
  81. package/src/components/UploadDropzone/index.tsx +0 -173
  82. package/src/config/orders.ts +0 -28
  83. package/src/config/searchFacets.ts +0 -312
  84. package/src/constants.ts +0 -87
  85. package/src/contexts/AssetSourceDispatchContext.tsx +0 -37
  86. package/src/contexts/DropzoneDispatchContext.tsx +0 -34
  87. package/src/contexts/ToolOptionsContext.tsx +0 -65
  88. package/src/formSchema/index.test.ts +0 -56
  89. package/src/formSchema/index.ts +0 -39
  90. package/src/hooks/useBreakpointIndex.ts +0 -49
  91. package/src/hooks/useKeyPress.ts +0 -39
  92. package/src/hooks/useOnScreen.ts +0 -34
  93. package/src/hooks/usePortalPopoverProps.ts +0 -13
  94. package/src/hooks/useTypedSelector.ts +0 -7
  95. package/src/hooks/useVersionedClient.ts +0 -6
  96. package/src/index.ts +0 -5
  97. package/src/modules/assets/actions.ts +0 -42
  98. package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
  99. package/src/modules/assets/fetchEpic.test.ts +0 -73
  100. package/src/modules/assets/index.ts +0 -825
  101. package/src/modules/assets/reducer.test.ts +0 -91
  102. package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
  103. package/src/modules/debug/index.ts +0 -28
  104. package/src/modules/dialog/actions.ts +0 -10
  105. package/src/modules/dialog/epics.test.ts +0 -168
  106. package/src/modules/dialog/index.ts +0 -238
  107. package/src/modules/dialog/reducer.test.ts +0 -185
  108. package/src/modules/index.ts +0 -124
  109. package/src/modules/notifications/epics.test.ts +0 -374
  110. package/src/modules/notifications/index.ts +0 -199
  111. package/src/modules/notifications/reducer.test.ts +0 -54
  112. package/src/modules/search/index.test.ts +0 -36
  113. package/src/modules/search/index.ts +0 -167
  114. package/src/modules/selected/index.ts +0 -22
  115. package/src/modules/selectors.test.ts +0 -21
  116. package/src/modules/selectors.ts +0 -17
  117. package/src/modules/tags/epics.test.ts +0 -96
  118. package/src/modules/tags/index.test.ts +0 -42
  119. package/src/modules/tags/index.ts +0 -540
  120. package/src/modules/types.ts +0 -3
  121. package/src/modules/uploads/actions.ts +0 -13
  122. package/src/modules/uploads/epics.test.ts +0 -109
  123. package/src/modules/uploads/index.test.ts +0 -59
  124. package/src/modules/uploads/index.ts +0 -282
  125. package/src/operators/checkTagName.test.ts +0 -29
  126. package/src/operators/checkTagName.ts +0 -33
  127. package/src/operators/debugThrottle.ts +0 -25
  128. package/src/plugin.tsx +0 -54
  129. package/src/schemas/tag.ts +0 -28
  130. package/src/styled/GlobalStyles/index.tsx +0 -40
  131. package/src/styled/react-select/creatable.tsx +0 -184
  132. package/src/styled/react-select/single.tsx +0 -184
  133. package/src/types/index.ts +0 -379
  134. package/src/types/sanity-ui.d.ts +0 -6
  135. package/src/utils/applyMediaTags.ts +0 -87
  136. package/src/utils/blocksToText.test.ts +0 -43
  137. package/src/utils/blocksToText.ts +0 -27
  138. package/src/utils/constructFilter.test.ts +0 -120
  139. package/src/utils/constructFilter.ts +0 -98
  140. package/src/utils/generatePreviewBlobUrl.test.ts +0 -70
  141. package/src/utils/generatePreviewBlobUrl.ts +0 -53
  142. package/src/utils/getAssetResolution.test.ts +0 -13
  143. package/src/utils/getAssetResolution.ts +0 -7
  144. package/src/utils/getDocumentAssetIds.test.ts +0 -50
  145. package/src/utils/getDocumentAssetIds.ts +0 -35
  146. package/src/utils/getSchemeColor.test.ts +0 -12
  147. package/src/utils/getSchemeColor.ts +0 -43
  148. package/src/utils/getTagSelectOptions.test.ts +0 -44
  149. package/src/utils/getTagSelectOptions.ts +0 -16
  150. package/src/utils/getUniqueDocuments.test.ts +0 -26
  151. package/src/utils/getUniqueDocuments.ts +0 -15
  152. package/src/utils/imageDprUrl.test.ts +0 -46
  153. package/src/utils/imageDprUrl.ts +0 -27
  154. package/src/utils/isSupportedAssetType.test.ts +0 -16
  155. package/src/utils/isSupportedAssetType.ts +0 -15
  156. package/src/utils/mediaField.ts +0 -73
  157. package/src/utils/sanitizeFormData.test.ts +0 -59
  158. package/src/utils/sanitizeFormData.ts +0 -26
  159. package/src/utils/typeGuards.test.ts +0 -18
  160. package/src/utils/typeGuards.ts +0 -9
  161. package/src/utils/uploadSanityAsset.test.ts +0 -29
  162. package/src/utils/uploadSanityAsset.ts +0 -97
  163. package/src/utils/withMaxConcurrency.test.ts +0 -43
  164. package/src/utils/withMaxConcurrency.ts +0 -55
  165. package/src/utils/zodFormResolver.ts +0 -17
  166. package/v2-incompatible.js +0 -11
@@ -1,65 +0,0 @@
1
- import {type PropsWithChildren, createContext, useContext, useMemo} from 'react'
2
- import type {DropzoneOptions} from 'react-dropzone'
3
-
4
- import type {MediaToolOptions, Locale} from '../types'
5
-
6
- type ContextProps = {
7
- dropzone: Pick<DropzoneOptions, 'maxSize'>
8
- components: MediaToolOptions['components']
9
- createTagsOnUpload: boolean
10
- creditLine: MediaToolOptions['creditLine']
11
- directUploads: MediaToolOptions['directUploads']
12
- locales?: Locale[]
13
- }
14
-
15
- const ToolOptionsContext = createContext<ContextProps | null>(null)
16
-
17
- type Props = {
18
- options?: MediaToolOptions | void
19
- }
20
-
21
- export const ToolOptionsProvider = ({options, children}: PropsWithChildren<Props>) => {
22
- const value = useMemo<ContextProps>(() => {
23
- let creditLineExcludeSources
24
-
25
- if (options?.creditLine?.excludeSources) {
26
- creditLineExcludeSources = Array.isArray(options?.creditLine?.excludeSources)
27
- ? options.creditLine.excludeSources
28
- : [options?.creditLine?.excludeSources]
29
- }
30
-
31
- return {
32
- dropzone: {maxSize: options?.maximumUploadSize},
33
- components: {
34
- details: options?.components?.details,
35
- },
36
- createTagsOnUpload: options?.createTagsOnUpload ?? true,
37
- creditLine: {
38
- enabled: options?.creditLine?.enabled || false,
39
- excludeSources: creditLineExcludeSources,
40
- },
41
- directUploads: options?.directUploads ?? true,
42
- locales: options?.locales,
43
- }
44
- }, [
45
- options?.creditLine?.enabled,
46
- options?.components,
47
- options?.createTagsOnUpload,
48
- options?.creditLine?.excludeSources,
49
- options?.maximumUploadSize,
50
- options?.directUploads,
51
- options?.locales,
52
- ])
53
-
54
- return <ToolOptionsContext.Provider value={value}>{children}</ToolOptionsContext.Provider>
55
- }
56
-
57
- export const useToolOptions = () => {
58
- const context = useContext(ToolOptionsContext)
59
-
60
- if (!context) {
61
- throw new Error('useToolOptions must be used within an ToolOptionsProvider')
62
- }
63
-
64
- return context
65
- }
@@ -1,56 +0,0 @@
1
- // @vitest-environment node
2
-
3
- import {describe, expect, it} from 'vitest'
4
-
5
- import {assetFormSchema, tagFormSchema, tagOptionSchema} from './index'
6
-
7
- describe('tagOptionSchema', () => {
8
- it('accepts trimmed non-empty label and value', () => {
9
- expect(tagOptionSchema.safeParse({label: 'A', value: 'b'}).success).toBe(true)
10
- })
11
-
12
- it('rejects empty label or value after trim', () => {
13
- expect(tagOptionSchema.safeParse({label: ' ', value: 'x'}).success).toBe(false)
14
- expect(tagOptionSchema.safeParse({label: 'x', value: ''}).success).toBe(false)
15
- })
16
- })
17
-
18
- describe('tagFormSchema', () => {
19
- it('requires non-empty name', () => {
20
- expect(tagFormSchema.safeParse({name: 'x'}).success).toBe(true)
21
- expect(tagFormSchema.safeParse({name: ''}).success).toBe(false)
22
- })
23
- })
24
-
25
- describe('assetFormSchema', () => {
26
- const base = {
27
- altText: '',
28
- creditLine: '',
29
- description: '',
30
- opt: {media: {tags: null}},
31
- originalFilename: 'file.png',
32
- title: '',
33
- }
34
-
35
- it('accepts valid asset form payload', () => {
36
- expect(assetFormSchema.safeParse(base).success).toBe(true)
37
- })
38
-
39
- it('rejects empty originalFilename', () => {
40
- expect(
41
- assetFormSchema.safeParse({
42
- ...base,
43
- originalFilename: ' ',
44
- }).success,
45
- ).toBe(false)
46
- })
47
-
48
- it('validates nested tag options', () => {
49
- expect(
50
- assetFormSchema.safeParse({
51
- ...base,
52
- opt: {media: {tags: [{label: '', value: 'v'}]}},
53
- }).success,
54
- ).toBe(false)
55
- })
56
- })
@@ -1,39 +0,0 @@
1
- import * as z from 'zod'
2
-
3
- // Helper to generate localized string schema
4
- export function localizedStringSchema(locales?: {id: string}[]) {
5
- if (!locales || locales.length === 0) {
6
- return z.string().trim().optional()
7
- }
8
- const shape: Record<string, z.ZodTypeAny> = {}
9
- for (const locale of locales) {
10
- shape[locale.id] = z.string().trim().optional()
11
- }
12
- return z.object(shape).passthrough()
13
- }
14
-
15
- export const tagOptionSchema = z.object({
16
- label: z.string().trim().min(1, {message: 'Label cannot be empty'}),
17
- value: z.string().trim().min(1, {message: 'Value cannot be empty'}),
18
- })
19
-
20
- export function getAssetFormSchema(locales?: {id: string}[]) {
21
- return z.object({
22
- altText: localizedStringSchema(locales),
23
- creditLine: localizedStringSchema(locales),
24
- description: localizedStringSchema(locales),
25
- opt: z.object({
26
- media: z.object({
27
- tags: z.array(tagOptionSchema).nullable(),
28
- }),
29
- }),
30
- originalFilename: z.string().trim().min(1, {message: 'Filename cannot be empty'}),
31
- title: localizedStringSchema(locales),
32
- })
33
- }
34
-
35
- export const assetFormSchema = getAssetFormSchema()
36
-
37
- export const tagFormSchema = z.object({
38
- name: z.string().min(1, {message: 'Name cannot be empty'}),
39
- })
@@ -1,49 +0,0 @@
1
- import {studioTheme} from '@sanity/ui'
2
- import {useEffect, useState} from 'react'
3
-
4
- // Determine the current breakpoint index
5
- // - create MediaQueryLists from every breakpoint defined in our sanity studio theme
6
- // - for each MQL, listen to change events and return the selected breakpoint index
7
- const useBreakpointIndex = (): number => {
8
- const mediaQueryLists = studioTheme?.container?.map((width) =>
9
- window.matchMedia(`(max-width: ${width}px)`),
10
- )
11
-
12
- const getBreakpointIndex = () => mediaQueryLists.findIndex((mql) => mql.matches)
13
-
14
- const [value, setValue] = useState(getBreakpointIndex())
15
-
16
- useEffect(() => {
17
- const handleBreakpoint = () => {
18
- setValue(getBreakpointIndex)
19
- }
20
-
21
- // NOTE: older versions of Safari use the older `addListener` and `removeListener` methods
22
- mediaQueryLists.forEach((mql) => {
23
- try {
24
- mql.addEventListener('change', handleBreakpoint)
25
- } catch (err) {
26
- try {
27
- mql.addListener(handleBreakpoint)
28
- } catch (_err) {
29
- // Do nothing
30
- }
31
- }
32
- })
33
- return () => {
34
- try {
35
- mediaQueryLists.forEach((mql) => mql.removeEventListener('change', handleBreakpoint))
36
- } catch (err) {
37
- try {
38
- mediaQueryLists.forEach((mql) => mql.removeListener(handleBreakpoint))
39
- } catch (_err) {
40
- // Do nothing
41
- }
42
- }
43
- }
44
- }, [])
45
-
46
- return value
47
- }
48
-
49
- export default useBreakpointIndex
@@ -1,39 +0,0 @@
1
- import {isHotkey} from 'is-hotkey-esm'
2
- import {type RefObject, useCallback, useEffect, useRef} from 'react'
3
-
4
- const useKeyPress = (hotkey: string, onPress?: () => void): RefObject<boolean> => {
5
- const keyPressed = useRef(false)
6
-
7
- // If pressed key is our target key then set to true
8
- const downHandler = useCallback(
9
- (e: KeyboardEvent) => {
10
- if (isHotkey(hotkey, e)) {
11
- keyPressed.current = true
12
- if (onPress) {
13
- onPress()
14
- }
15
- }
16
- },
17
- [hotkey, onPress],
18
- )
19
-
20
- // If released key is our target key then set to false
21
- const upHandler = useCallback(() => {
22
- keyPressed.current = false
23
- }, [])
24
-
25
- // Add event listeners
26
- useEffect(() => {
27
- window.addEventListener('keydown', downHandler)
28
- window.addEventListener('keyup', upHandler)
29
- // Remove event listeners on cleanup
30
- return () => {
31
- window.removeEventListener('keydown', downHandler)
32
- window.removeEventListener('keyup', upHandler)
33
- }
34
- }, [downHandler, upHandler])
35
-
36
- return keyPressed
37
- }
38
-
39
- export default useKeyPress
@@ -1,34 +0,0 @@
1
- import {type RefObject, useEffect, useState} from 'react'
2
-
3
- const useOnScreen = (ref: RefObject<HTMLElement>, options = {}, once: boolean) => {
4
- const [isIntersecting, setIntersecting] = useState(false)
5
-
6
- useEffect(() => {
7
- const observer = new IntersectionObserver(([entry]: IntersectionObserverEntry[]) => {
8
- // Update state when observer callback fires
9
- setIntersecting(entry.isIntersecting)
10
-
11
- // Stop observing
12
- if (once && entry.isIntersecting) {
13
- if (ref.current && observer) {
14
- observer.unobserve(ref.current)
15
- }
16
- }
17
- }, options)
18
-
19
- if (ref.current && observer) {
20
- observer.observe(ref.current)
21
- }
22
-
23
- // Stop observing on unmount
24
- return () => {
25
- if (ref.current && observer) {
26
- observer.unobserve(ref.current)
27
- }
28
- }
29
- }, [])
30
-
31
- return isIntersecting
32
- }
33
-
34
- export default useOnScreen
@@ -1,13 +0,0 @@
1
- import {type PopoverProps, usePortal} from '@sanity/ui'
2
-
3
- export function usePortalPopoverProps(): PopoverProps {
4
- const portal = usePortal()
5
-
6
- return {
7
- animate: true,
8
- constrainSize: true,
9
- floatingBoundary: portal.element,
10
- portal: true,
11
- referenceBoundary: portal.element,
12
- }
13
- }
@@ -1,7 +0,0 @@
1
- import {type TypedUseSelectorHook, useSelector} from 'react-redux'
2
-
3
- import type {RootReducerState} from '../modules/types'
4
-
5
- const useTypedSelector: TypedUseSelectorHook<RootReducerState> = useSelector
6
-
7
- export default useTypedSelector
@@ -1,6 +0,0 @@
1
- import type {SanityClient} from '@sanity/client'
2
- import {useClient} from 'sanity'
3
-
4
- const useVersionedClient = (): SanityClient => useClient({apiVersion: '2025-10-02'})
5
-
6
- export default useVersionedClient
package/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export {media, mediaAssetSource} from './plugin'
2
- export {AutoTagInput} from './components/AutoTagInputWrapper'
3
- export type {AutoTagInputProps} from './components/AutoTagInputWrapper'
4
- export {mediaField} from './utils/mediaField'
5
- export type {MediaTagsOptions, MediaToolOptions} from './types'
@@ -1,42 +0,0 @@
1
- import {createAction} from '@reduxjs/toolkit'
2
-
3
- import type {AssetItem, HttpError, Tag} from '../../types'
4
-
5
- export const ASSETS_ACTIONS = {
6
- tagsAddComplete: createAction(
7
- 'actions/tagsAddComplete',
8
- function prepare({assets, tag}: {assets: AssetItem[]; tag: Tag}) {
9
- return {payload: {assets, tag}}
10
- },
11
- ),
12
- tagsAddError: createAction(
13
- 'actions/tagsAddError',
14
- function prepare({assets, error, tag}: {assets: AssetItem[]; error: HttpError; tag: Tag}) {
15
- return {payload: {assets, error, tag}}
16
- },
17
- ),
18
- tagsAddRequest: createAction(
19
- 'actions/tagsAddRequest',
20
- function prepare({assets, tag}: {assets: AssetItem[]; tag: Tag}) {
21
- return {payload: {assets, tag}}
22
- },
23
- ),
24
- tagsRemoveComplete: createAction(
25
- 'actions/tagsRemoveComplete',
26
- function prepare({assets, tag}: {assets: AssetItem[]; tag: Tag}) {
27
- return {payload: {assets, tag}}
28
- },
29
- ),
30
- tagsRemoveError: createAction(
31
- 'actions/tagsRemoveError',
32
- function prepare({assets, error, tag}: {assets: AssetItem[]; error: HttpError; tag: Tag}) {
33
- return {payload: {assets, error, tag}}
34
- },
35
- ),
36
- tagsRemoveRequest: createAction(
37
- 'actions/tagsRemoveRequest',
38
- function prepare({assets, tag}: {assets: AssetItem[]; tag: Tag}) {
39
- return {payload: {assets, tag}}
40
- },
41
- ),
42
- }
@@ -1,87 +0,0 @@
1
- // @vitest-environment node
2
-
3
- import {of} from 'rxjs'
4
- import {describe, expect, it, vi} from 'vitest'
5
-
6
- import {createEpicTestStore} from '../../__tests__/fixtures/createEpicTestStore'
7
- import {createMockSanityClient, mockPatchChain} from '../../__tests__/fixtures/mockSanityClient'
8
- import type {ImageAsset} from '../../types'
9
- import {
10
- assetsActions,
11
- assetsDeleteEpic,
12
- assetsUpdateEpic,
13
- initialState as assetsInitialState,
14
- } from './index'
15
-
16
- const sampleAsset = {
17
- _id: 'a1',
18
- _type: 'sanity.imageAsset',
19
- _createdAt: '',
20
- _updatedAt: '',
21
- _rev: 'r',
22
- originalFilename: 'x.png',
23
- size: 1,
24
- mimeType: 'image/png',
25
- url: '',
26
- } as ImageAsset
27
-
28
- describe('assetsDeleteEpic', () => {
29
- it('dispatches deleteComplete when observable.delete succeeds', async () => {
30
- const client = createMockSanityClient({
31
- observable: {
32
- delete: vi.fn(() => of({})),
33
- },
34
- })
35
-
36
- const store = createEpicTestStore(assetsDeleteEpic, client, {
37
- assets: {
38
- ...assetsInitialState,
39
- assetTypes: ['image'],
40
- allIds: ['a1'],
41
- byIds: {
42
- a1: {_type: 'asset', asset: sampleAsset, picked: false, updating: false},
43
- },
44
- },
45
- })
46
-
47
- store.dispatch(assetsActions.deleteRequest({assets: [sampleAsset]}))
48
-
49
- await vi.waitFor(() => {
50
- expect(store.getState().assets.byIds.a1).toBeUndefined()
51
- expect(client.observable.delete).toHaveBeenCalled()
52
- })
53
- })
54
- })
55
-
56
- describe('assetsUpdateEpic', () => {
57
- it('commits patch and dispatches updateComplete', async () => {
58
- const updated = {...sampleAsset, title: 'Updated'}
59
- const chain = mockPatchChain(updated)
60
- const client = createMockSanityClient({
61
- patch: vi.fn(() => chain),
62
- })
63
-
64
- const store = createEpicTestStore(assetsUpdateEpic, client, {
65
- assets: {
66
- ...assetsInitialState,
67
- assetTypes: ['image'],
68
- allIds: ['a1'],
69
- byIds: {
70
- a1: {_type: 'asset', asset: sampleAsset, picked: false, updating: false},
71
- },
72
- },
73
- })
74
-
75
- store.dispatch(
76
- assetsActions.updateRequest({
77
- asset: sampleAsset,
78
- formData: {title: 'Updated'},
79
- }),
80
- )
81
-
82
- await vi.waitFor(() => {
83
- expect(chain.commit).toHaveBeenCalled()
84
- expect(store.getState().assets.byIds.a1.asset.title).toBe('Updated')
85
- })
86
- })
87
- })
@@ -1,73 +0,0 @@
1
- // @vitest-environment node
2
-
3
- import {of, throwError} from 'rxjs'
4
- import {describe, expect, it, vi} from 'vitest'
5
-
6
- import {createEpicTestStore} from '../../__tests__/fixtures/createEpicTestStore'
7
- import {createMockSanityClient} from '../../__tests__/fixtures/mockSanityClient'
8
- import type {ImageAsset} from '../../types'
9
- import {assetsActions, assetsFetchEpic} from './index'
10
-
11
- function assertFetchSucceeded(store: ReturnType<typeof createEpicTestStore>, asset: ImageAsset) {
12
- expect(store.getState().assets.byIds.a1?.asset).toEqual(asset)
13
- expect(store.getState().assets.fetching).toBe(false)
14
- }
15
-
16
- function assertFetchFailed(store: ReturnType<typeof createEpicTestStore>) {
17
- expect(store.getState().assets.fetchingError?.message).toBe('boom')
18
- }
19
-
20
- const sampleAsset = {
21
- _id: 'a1',
22
- _type: 'sanity.imageAsset',
23
- _createdAt: '',
24
- _updatedAt: '',
25
- _rev: 'r',
26
- originalFilename: 'x.png',
27
- size: 1,
28
- mimeType: 'image/png',
29
- url: '',
30
- } as ImageAsset
31
-
32
- describe('assetsFetchEpic', () => {
33
- it('dispatches fetchComplete when observable.fetch succeeds', async () => {
34
- const client = createMockSanityClient({
35
- observable: {
36
- fetch: vi.fn(() => of({items: [sampleAsset]})),
37
- },
38
- })
39
-
40
- const store = createEpicTestStore(assetsFetchEpic, client)
41
- store.dispatch(
42
- assetsActions.fetchRequest({
43
- params: {},
44
- queryFilter: '_type == "sanity.imageAsset"',
45
- selector: '',
46
- sort: '',
47
- }),
48
- )
49
-
50
- await vi.waitFor(() => assertFetchSucceeded(store, sampleAsset))
51
- })
52
-
53
- it('dispatches fetchError when fetch fails', async () => {
54
- const fetchErr = throwError(() => ({message: 'boom', statusCode: 500}))
55
- const client = createMockSanityClient({
56
- observable: {
57
- fetch: vi.fn(() => fetchErr),
58
- },
59
- })
60
-
61
- const store = createEpicTestStore(assetsFetchEpic, client)
62
- store.dispatch(
63
- assetsActions.fetchRequest({
64
- params: {},
65
- queryFilter: '_type == "sanity.imageAsset"',
66
- selector: '',
67
- sort: '',
68
- }),
69
- )
70
-
71
- await vi.waitFor(() => assertFetchFailed(store))
72
- })
73
- })