@sanity/cross-dataset-duplicator 0.4.0 → 1.1.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 (64) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +53 -57
  3. package/lib/index.esm.js +1 -0
  4. package/lib/index.esm.js.map +1 -0
  5. package/lib/index.js +1 -21
  6. package/lib/index.js.map +1 -1
  7. package/lib/src/index.d.ts +548 -0
  8. package/package.json +64 -38
  9. package/sanity.json +2 -10
  10. package/src/actions/DuplicateToAction.tsx +20 -8
  11. package/src/components/CrossDatasetDuplicator.tsx +34 -49
  12. package/src/components/CrossDatasetDuplicatorAction.tsx +14 -0
  13. package/src/components/CrossDatasetDuplicatorTool.tsx +18 -0
  14. package/src/components/{DuplicatorTool.tsx → Duplicator.tsx} +179 -181
  15. package/src/components/DuplicatorQuery.tsx +36 -13
  16. package/src/components/DuplicatorWrapper.tsx +66 -0
  17. package/src/components/ResetSecret.tsx +9 -9
  18. package/src/components/SelectButtons.tsx +13 -9
  19. package/src/components/StatusBadge.tsx +13 -9
  20. package/src/context/ConfigProvider.tsx +30 -0
  21. package/src/helpers/clientConfig.ts +1 -1
  22. package/src/helpers/constants.ts +10 -1
  23. package/src/helpers/getDocumentsInArray.ts +28 -21
  24. package/src/helpers/index.ts +6 -10
  25. package/src/index.ts +5 -0
  26. package/src/plugin.tsx +31 -0
  27. package/src/tool/index.ts +11 -10
  28. package/src/types/index.ts +17 -7
  29. package/v2-incompatible.js +11 -0
  30. package/.babelrc +0 -3
  31. package/.eslintignore +0 -1
  32. package/config.dist.json +0 -5
  33. package/lib/actions/DuplicateToAction.js +0 -44
  34. package/lib/actions/DuplicateToAction.js.map +0 -1
  35. package/lib/actions/index.js +0 -29
  36. package/lib/actions/index.js.map +0 -1
  37. package/lib/components/CrossDatasetDuplicator.js +0 -81
  38. package/lib/components/CrossDatasetDuplicator.js.map +0 -1
  39. package/lib/components/DuplicatorQuery.js +0 -105
  40. package/lib/components/DuplicatorQuery.js.map +0 -1
  41. package/lib/components/DuplicatorTool.js +0 -556
  42. package/lib/components/DuplicatorTool.js.map +0 -1
  43. package/lib/components/Feedback.js +0 -23
  44. package/lib/components/Feedback.js.map +0 -1
  45. package/lib/components/ResetSecret.js +0 -34
  46. package/lib/components/ResetSecret.js.map +0 -1
  47. package/lib/components/SelectButtons.js +0 -84
  48. package/lib/components/SelectButtons.js.map +0 -1
  49. package/lib/components/StatusBadge.js +0 -85
  50. package/lib/components/StatusBadge.js.map +0 -1
  51. package/lib/helpers/clientConfig.js +0 -11
  52. package/lib/helpers/clientConfig.js.map +0 -1
  53. package/lib/helpers/constants.js +0 -9
  54. package/lib/helpers/constants.js.map +0 -1
  55. package/lib/helpers/getDocumentsInArray.js +0 -74
  56. package/lib/helpers/getDocumentsInArray.js.map +0 -1
  57. package/lib/helpers/index.js +0 -27
  58. package/lib/helpers/index.js.map +0 -1
  59. package/lib/tool/index.js +0 -18
  60. package/lib/tool/index.js.map +0 -1
  61. package/lib/types/index.js +0 -2
  62. package/lib/types/index.js.map +0 -1
  63. package/src/actions/index.ts +0 -22
  64. package/src/index.js +0 -7
@@ -0,0 +1,66 @@
1
+ import React, {useState, useEffect} from 'react'
2
+ import {Grid, Card, Container, Button} from '@sanity/ui'
3
+ import {SanityDocument, useClient} from 'sanity'
4
+
5
+ import type {DuplicatorProps} from './Duplicator'
6
+ import Duplicator from './Duplicator'
7
+
8
+ export default function DuplicatorWrapper(props: DuplicatorProps) {
9
+ const {docs, token, pluginConfig} = props
10
+ const [inbound, setInbound] = useState<SanityDocument[]>([])
11
+ const {follow = []} = pluginConfig
12
+
13
+ // Make the first mode the default if there's only one
14
+ const [mode, setMode] = useState<'inbound' | 'outbound'>(
15
+ follow.length === 1 ? follow[0] : `outbound`
16
+ )
17
+ const client = useClient()
18
+
19
+ // "Inbound" will start with all documents that reference the first one
20
+ // And then you can gather "Outbound" references thereafter
21
+ useEffect(() => {
22
+ ;(async () => {
23
+ if (follow.includes(`inbound`)) {
24
+ const inboundReferences = await client.fetch(`*[references($id)]`, {id: docs[0]._id})
25
+ setInbound([...props.docs, ...inboundReferences])
26
+ }
27
+ })()
28
+ // eslint-disable-next-line react-hooks/exhaustive-deps
29
+ }, [])
30
+
31
+ return (
32
+ <Container>
33
+ {follow.length > 1 && (follow.includes(`inbound`) || follow.includes(`outbound`)) ? (
34
+ <Card paddingX={4} paddingBottom={4} marginBottom={4} borderBottom>
35
+ <Grid columns={2} gap={4}>
36
+ {follow.includes(`outbound`) ? (
37
+ <Button
38
+ mode="ghost"
39
+ tone="primary"
40
+ selected={mode === 'outbound'}
41
+ onClick={() => setMode('outbound')}
42
+ text="Outbound"
43
+ />
44
+ ) : null}
45
+ {follow.includes(`inbound`) ? (
46
+ <Button
47
+ mode="ghost"
48
+ tone="primary"
49
+ selected={mode === 'inbound'}
50
+ onClick={() => setMode('inbound')}
51
+ disabled={inbound.length === 0}
52
+ text={inbound.length > 0 ? `Inbound (${inbound.length})` : 'No inbound references'}
53
+ />
54
+ ) : null}
55
+ </Grid>
56
+ </Card>
57
+ ) : null}
58
+ <Duplicator
59
+ docs={mode === 'outbound' ? docs : inbound}
60
+ token={token}
61
+ // draftIds={[]}
62
+ pluginConfig={pluginConfig}
63
+ />
64
+ </Container>
65
+ )
66
+ }
@@ -1,22 +1,22 @@
1
1
  import React from 'react'
2
+ import {useClient} from 'sanity'
2
3
  import {Button, Flex} from '@sanity/ui'
3
- import sanityClient from 'part:@sanity/base/client'
4
4
 
5
- import { clientConfig } from '../helpers/clientConfig'
6
- import { SECRET_NAMESPACE } from '../helpers/constants'
5
+ import {clientConfig} from '../helpers/clientConfig'
6
+ import {SECRET_NAMESPACE} from '../helpers/constants'
7
7
 
8
- const client = sanityClient.withConfig(clientConfig)
8
+ export default function ResetSecret() {
9
+ const client = useClient(clientConfig)
9
10
 
10
- function handleClick() {
11
- client.delete({query: `*[_id == "secrets.${SECRET_NAMESPACE}"]`})
12
- }
11
+ const handleClick = React.useCallback(() => {
12
+ client.delete({query: `*[_id == "secrets.${SECRET_NAMESPACE}"]`})
13
+ }, [client])
13
14
 
14
- export default function ResetSecret() {
15
15
  return (
16
16
  <Flex align="center" justify="flex-end" paddingX={[2, 2, 2, 5]} paddingY={5}>
17
17
  <Button
18
18
  text="Reset Secret"
19
- onClick={() => handleClick()}
19
+ onClick={handleClick}
20
20
  mode="ghost"
21
21
  tone="critical"
22
22
  fontSize={1}
@@ -1,10 +1,13 @@
1
1
  import React, {useState, useEffect} from 'react'
2
2
  import {Button, Card, Flex} from '@sanity/ui'
3
- import {typeIsAsset} from '../helpers'
4
- import {PayloadItem} from '../types'
3
+
4
+ import {PayloadItem} from './Duplicator'
5
+ import {isAssetId} from '@sanity/asset-utils'
5
6
 
6
7
  const buttons = [`All`, `None`, null, `New`, `Existing`, `Older`, null, `Documents`, `Assets`]
7
8
 
9
+ type Action = 'ALL' | 'NONE' | 'NEW' | 'EXISTING' | 'OLDER' | 'ASSETS' | 'DOCUMENTS'
10
+
8
11
  type SelectButtonsProps = {
9
12
  payload: PayloadItem[]
10
13
  setPayload: Function
@@ -12,16 +15,16 @@ type SelectButtonsProps = {
12
15
 
13
16
  export default function SelectButtons(props: SelectButtonsProps) {
14
17
  const {payload, setPayload} = props
15
- const [disabledActions, setDisabledActions] = useState([])
18
+ const [disabledActions, setDisabledActions] = useState<Action[]>([])
16
19
 
17
20
  // Set intiial disabled button
18
21
  useEffect(() => {
19
22
  if (!disabledActions?.length && payload.every((item) => item.include)) {
20
23
  setDisabledActions([`ALL`])
21
24
  }
22
- }, [])
25
+ }, [disabledActions?.length, payload])
23
26
 
24
- function handleSelectButton(action = ``) {
27
+ function handleSelectButton(action?: Action) {
25
28
  if (!action || !payload.length) return
26
29
 
27
30
  const newPayload = [...payload]
@@ -43,10 +46,10 @@ export default function SelectButtons(props: SelectButtonsProps) {
43
46
  newPayload.map((item) => (item.include = Boolean(item.status === 'OVERWRITE')))
44
47
  break
45
48
  case 'ASSETS':
46
- newPayload.map((item) => (item.include = typeIsAsset(item.doc._type)))
49
+ newPayload.map((item) => (item.include = isAssetId(item.doc._id)))
47
50
  break
48
51
  case 'DOCUMENTS':
49
- newPayload.map((item) => (item.include = !typeIsAsset(item.doc._type)))
52
+ newPayload.map((item) => (item.include = !isAssetId(item.doc._id)))
50
53
  break
51
54
  default:
52
55
  break
@@ -67,10 +70,11 @@ export default function SelectButtons(props: SelectButtonsProps) {
67
70
  mode="bleed"
68
71
  padding={2}
69
72
  text={action}
70
- disabled={disabledActions.includes(action.toUpperCase())}
71
- onClick={() => handleSelectButton(action.toUpperCase())}
73
+ disabled={disabledActions.includes(action.toUpperCase() as Action)}
74
+ onClick={() => handleSelectButton(action.toUpperCase() as Action)}
72
75
  />
73
76
  ) : (
77
+ // eslint-disable-next-line react/no-array-index-key
74
78
  <Card key={`divider-${actionIndex}`} borderLeft />
75
79
  )
76
80
  )}
@@ -23,10 +23,10 @@ const assetTones: StatusTones = {
23
23
  OVERWRITE: `critical`,
24
24
  UPDATE: `critical`,
25
25
  CREATE: `positive`,
26
- UNPUBLISHED: `default`
26
+ UNPUBLISHED: `default`,
27
27
  }
28
28
 
29
- type messageTypes = {
29
+ export type MessageTypes = {
30
30
  EXISTS: string
31
31
  OVERWRITE: string
32
32
  UPDATE: string
@@ -34,7 +34,7 @@ type messageTypes = {
34
34
  UNPUBLISHED: string
35
35
  }
36
36
 
37
- const documentMessages: messageTypes = {
37
+ const documentMessages: MessageTypes = {
38
38
  // Only happens once document is copied the first time, and _updatedAt is the same
39
39
  EXISTS: `This document already exists at the Destination with the same ID with the same Updated time.`,
40
40
  // Is true immediately after transaction as _updatedAt is updated by API after mutation
@@ -45,10 +45,10 @@ const documentMessages: messageTypes = {
45
45
  UPDATE: `An older version of this document exists at the Destination, and it will be overwritten with this version.`,
46
46
  // Document at destination doesn't exist
47
47
  CREATE: `This document will be created at the destination.`,
48
- UNPUBLISHED: `A Draft version of this Document exists in this Dataset, but only the Published version will be duplicated to the destination.`
48
+ UNPUBLISHED: `A Draft version of this Document exists in this Dataset, but only the Published version will be duplicated to the destination.`,
49
49
  }
50
50
 
51
- const assetMessages: messageTypes = {
51
+ const assetMessages: MessageTypes = {
52
52
  EXISTS: `This Asset already exists at the Destination`,
53
53
  OVERWRITE: `This Asset already exists at the Destination`,
54
54
  UPDATE: `This Asset already exists at the Destination`,
@@ -56,7 +56,7 @@ const assetMessages: messageTypes = {
56
56
  UNPUBLISHED: ``,
57
57
  }
58
58
 
59
- const assetStatus: messageTypes = {
59
+ const assetStatus: MessageTypes = {
60
60
  EXISTS: `RE-UPLOAD`,
61
61
  OVERWRITE: `RE-UPLOAD`,
62
62
  UPDATE: `RE-UPLOAD`,
@@ -65,15 +65,19 @@ const assetStatus: messageTypes = {
65
65
  }
66
66
 
67
67
  type StatusBadgeProps = {
68
- status: 'EXISTS' | 'OVERWRITE' | 'UPDATE' | 'CREATE' | 'UNPUBLISHED' | undefined
69
68
  isAsset: boolean
69
+ status?: keyof MessageTypes
70
70
  }
71
71
 
72
72
  export default function StatusBadge(props: StatusBadgeProps) {
73
73
  const {status, isAsset} = props
74
74
 
75
+ if (!status) {
76
+ return null
77
+ }
78
+
75
79
  const badgeTone = isAsset ? assetTones[status] : documentTones[status]
76
-
80
+
77
81
  if (!badgeTone) {
78
82
  return (
79
83
  <Badge muted padding={2} fontSize={1} mode="outline">
@@ -81,7 +85,7 @@ export default function StatusBadge(props: StatusBadgeProps) {
81
85
  </Badge>
82
86
  )
83
87
  }
84
-
88
+
85
89
  const badgeText = isAsset ? assetMessages[status] : documentMessages[status]
86
90
  const badgeStatus = isAsset ? assetStatus[status] : status
87
91
 
@@ -0,0 +1,30 @@
1
+ import React, {useContext} from 'react'
2
+ import {createContext} from 'react'
3
+ import {LayoutProps} from 'sanity'
4
+
5
+ import {DEFAULT_CONFIG} from '../helpers/constants'
6
+ import {PluginConfig} from '../types'
7
+
8
+ const CrossDatasetDuplicatorContext = createContext(DEFAULT_CONFIG)
9
+
10
+ type ConfigProviderProps = LayoutProps & {pluginConfig: PluginConfig}
11
+
12
+ /**
13
+ * Plugin config context hook from the Cross Dataset Duplicator plugin
14
+ * @public
15
+ */
16
+ export function useCrossDatasetDuplicatorConfig() {
17
+ const pluginConfig = useContext(CrossDatasetDuplicatorContext)
18
+
19
+ return pluginConfig
20
+ }
21
+
22
+ export function ConfigProvider(props: ConfigProviderProps) {
23
+ const {pluginConfig, ...rest} = props
24
+
25
+ return (
26
+ <CrossDatasetDuplicatorContext.Provider value={pluginConfig}>
27
+ {props.renderDefault(rest)}
28
+ </CrossDatasetDuplicatorContext.Provider>
29
+ )
30
+ }
@@ -1 +1 @@
1
- export const clientConfig = {apiVersion: `2021-05-19`}
1
+ export const clientConfig = {apiVersion: `2021-05-19`}
@@ -1 +1,10 @@
1
- export const SECRET_NAMESPACE = `CrossDatasetDuplicator`
1
+ import {PluginConfig} from '../types'
2
+
3
+ export const SECRET_NAMESPACE = `CrossDatasetDuplicator`
4
+
5
+ export const DEFAULT_CONFIG: PluginConfig = {
6
+ tool: true,
7
+ types: [],
8
+ filter: '',
9
+ follow: ['outbound'],
10
+ }
@@ -1,20 +1,23 @@
1
- import { extract } from '@sanity/mutator'
2
- import { SanityDocument } from '../types'
1
+ import {extractWithPath} from '@sanity/mutator'
2
+ import {SanityClient, SanityDocument} from 'sanity'
3
+ import {PluginConfig} from '../types'
3
4
 
4
- import config from 'config:@sanity/cross-dataset-duplicator'
5
+ type OptionsBag = {
6
+ fetchIds: string[]
7
+ client: SanityClient
8
+ pluginConfig: PluginConfig
9
+ currentIds?: Set<string> | null
10
+ projection?: string
11
+ }
5
12
 
6
13
  // Recursively fetch Documents from an array of _id's and their references
7
14
  // Heavy use of Set is to avoid recursively querying for id's already in the payload
8
- export async function getDocumentsInArray(
9
- fetchIds: string[],
10
- client: any,
11
- currentIds?: Set<string>,
12
- projection?: string,
13
- ) {
14
- const collection = []
15
+ export async function getDocumentsInArray(options: OptionsBag): Promise<SanityDocument[]> {
16
+ const {fetchIds, client, pluginConfig, currentIds, projection} = options
17
+ const collection: SanityDocument[] = []
15
18
 
16
19
  // Find initial docs
17
- const filter = ['_id in $fetchIds', config.filter].filter(Boolean).join(' && ')
20
+ const filter = ['_id in $fetchIds', pluginConfig.filter].filter(Boolean).join(' && ')
18
21
  const query = `*[${filter}]${projection ?? ``}`
19
22
  const data: SanityDocument[] = await client.fetch(query, {
20
23
  fetchIds: fetchIds ?? [],
@@ -24,11 +27,11 @@ export async function getDocumentsInArray(
24
27
  return []
25
28
  }
26
29
 
27
- const localCurrentIds = currentIds ?? new Set()
30
+ const localCurrentIds = currentIds ?? new Set<string>()
28
31
 
29
32
  // Find new ids in the returned data
30
33
  // Unless we started with an empty set, get the _ids from the data
31
- const newDataIds: Set<string> = new Set(
34
+ const newDataIds = new Set<string>(
32
35
  data
33
36
  .map((dataDoc) => dataDoc._id)
34
37
  .filter((id) => (currentIds?.size ? !localCurrentIds.has(id) : Boolean(id)))
@@ -36,25 +39,29 @@ export async function getDocumentsInArray(
36
39
 
37
40
  if (newDataIds.size) {
38
41
  collection.push(...data)
42
+ // @ts-ignore
39
43
  localCurrentIds.add(...newDataIds)
40
44
 
41
45
  // Check new data for more references
42
46
  await Promise.all(
43
47
  data.map(async (doc) => {
44
48
  const expr = `.._ref`
45
- const references = extract(expr, doc)
49
+ const references: string[] = extractWithPath(expr, doc).map((ref) => ref.value as string)
46
50
 
47
51
  if (references.length) {
48
52
  // Find references not already in the Collection
49
- const newReferenceIds = new Set(references.filter((refId) => !localCurrentIds.has(refId)))
53
+ const newReferenceIds = new Set<string>(
54
+ references.filter((ref) => !localCurrentIds.has(ref))
55
+ )
50
56
 
51
57
  if (newReferenceIds.size) {
52
- // Recusive query for new documents
53
- const referenceDocs = await getDocumentsInArray(
54
- Array.from(newReferenceIds),
58
+ // Recursive query for new documents
59
+ const referenceDocs = await getDocumentsInArray({
60
+ fetchIds: Array.from(newReferenceIds),
61
+ currentIds: localCurrentIds,
55
62
  client,
56
- localCurrentIds
57
- )
63
+ pluginConfig,
64
+ })
58
65
 
59
66
  if (referenceDocs?.length) {
60
67
  collection.push(...referenceDocs)
@@ -67,7 +74,7 @@ export async function getDocumentsInArray(
67
74
 
68
75
  // Create a unique array of objects from collection
69
76
  // Set() wasn't working for unique id's ¯\_(ツ)_/¯
70
- const uniqueCollection = collection.filter(Boolean).reduce((acc, cur) => {
77
+ const uniqueCollection = collection.filter(Boolean).reduce((acc: SanityDocument[], cur) => {
71
78
  if (acc.some((doc) => doc._id === cur._id)) {
72
79
  return acc
73
80
  }
@@ -1,23 +1,19 @@
1
- export function typeIsAsset(type = ``) {
2
- if (!type) return false
1
+ import {CSSProperties} from 'react'
3
2
 
4
- return ['sanity.imageAsset', 'sanity.fileAsset'].includes(type)
5
- }
6
-
7
- export function createInitialMessage(docCount = 0, refsCount = 0) {
3
+ export function createInitialMessage(docCount = 0, refsCount = 0): string {
8
4
  const message = [
9
5
  docCount === 1 ? `This Document contains` : `These ${docCount} Documents contain`,
10
6
  refsCount === 1 ? `1 Reference.` : `${refsCount} References.`,
11
7
  refsCount === 1 ? `That Document` : `Those Documents`,
12
- `may have References too. If referenced Documents do not exist at the target Destination, this transaction will fail.`
8
+ `may have References too. If referenced Documents do not exist at the target Destination, this transaction will fail.`,
13
9
  ]
14
10
 
15
11
  return message.join(` `)
16
12
  }
17
13
 
18
- export const stickyStyles = {
14
+ export const stickyStyles = (isDarkMode = true): CSSProperties => ({
19
15
  position: 'sticky',
20
16
  top: 0,
21
17
  zIndex: 100,
22
- backgroundColor: `rgba(255,255,255,0.95)`,
23
- }
18
+ backgroundColor: isDarkMode ? `rgba(10,10,10,0.95)` : `rgba(255,255,255,0.95)`,
19
+ })
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './types'
2
+ export * from './plugin'
3
+ export * from './actions/DuplicateToAction'
4
+ export {useCrossDatasetDuplicatorConfig} from './context/ConfigProvider'
5
+ export {CrossDatasetDuplicatorAction} from './components/CrossDatasetDuplicatorAction'
package/src/plugin.tsx ADDED
@@ -0,0 +1,31 @@
1
+ import {definePlugin} from 'sanity'
2
+
3
+ import {DuplicateToAction} from './actions/DuplicateToAction'
4
+ import {ConfigProvider} from './context/ConfigProvider'
5
+ import {DEFAULT_CONFIG} from './helpers/constants'
6
+ import {crossDatasetDuplicatorTool} from './tool'
7
+ import {PluginConfig} from './types'
8
+
9
+ /**
10
+ * Plugin: Cross Dataset Duplicator
11
+ * @public
12
+ */
13
+ export const crossDatasetDuplicator = definePlugin<PluginConfig | void>((config = {}) => {
14
+ const pluginConfig = {...DEFAULT_CONFIG, ...config}
15
+ const {types} = pluginConfig
16
+
17
+ return {
18
+ name: '@sanity/cross-dataset-duplicator',
19
+ tools: (prev) => (pluginConfig.tool ? [...prev, crossDatasetDuplicatorTool()] : prev),
20
+ studio: {
21
+ components: {
22
+ layout: (props) => ConfigProvider({...props, pluginConfig}),
23
+ },
24
+ },
25
+ document: {
26
+ actions: (prev, {schemaType}) => {
27
+ return types && types.includes(schemaType) ? [...prev, DuplicateToAction] : prev
28
+ },
29
+ },
30
+ }
31
+ })
package/src/tool/index.ts CHANGED
@@ -1,13 +1,14 @@
1
+ import type {Tool} from 'sanity'
1
2
  import {LaunchIcon} from '@sanity/icons'
2
- import config from 'config:@sanity/cross-dataset-duplicator'
3
3
 
4
- import CrossDatasetDuplicator from '../components/CrossDatasetDuplicator'
4
+ import {CrossDatasetDuplicatorTool, MultiToolConfig} from '../components/CrossDatasetDuplicatorTool'
5
5
 
6
- export default config?.tool
7
- ? {
8
- title: 'Duplicator',
9
- name: 'duplicator',
10
- icon: LaunchIcon,
11
- component: CrossDatasetDuplicator,
12
- }
13
- : null
6
+ export const crossDatasetDuplicatorTool = (): Tool<MultiToolConfig> => ({
7
+ title: 'Duplicator',
8
+ name: 'duplicator',
9
+ icon: LaunchIcon,
10
+ component: CrossDatasetDuplicatorTool,
11
+ options: {
12
+ docs: [],
13
+ },
14
+ })
@@ -1,10 +1,20 @@
1
- export type SanityDocument = {
2
- _id: string
3
- _type: string
1
+ import {SanityDocument} from 'sanity'
2
+
3
+ /**
4
+ * Plugin configuration
5
+ * @public
6
+ */
7
+ export interface PluginConfig {
8
+ tool?: boolean
9
+ types?: string[]
10
+ filter?: string
11
+ follow?: ('inbound' | 'outbound')[]
4
12
  }
5
13
 
6
- export type PayloadItem = {
7
- include: boolean
8
- status: 'EXISTS' | 'OVERWRITE' | 'UPDATE' | 'CREATE'
9
- doc: SanityDocument
14
+ /**
15
+ * Cross Dataset Duplicator document action props
16
+ * @public
17
+ */
18
+ export type CrossDatasetDuplicatorActionProps = {
19
+ docs: SanityDocument[]
10
20
  }
@@ -0,0 +1,11 @@
1
+ const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
2
+ const {name, version, sanityExchangeUrl} = require('./package.json')
3
+
4
+ export default showIncompatiblePluginDialog({
5
+ name: name,
6
+ versions: {
7
+ v3: version,
8
+ v2: undefined,
9
+ },
10
+ sanityExchangeUrl,
11
+ })
package/.babelrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "sanipack/babel"
3
- }
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- lib
package/config.dist.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "tool": true,
3
- "types": [],
4
- "follow": []
5
- }
@@ -1,44 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = DuplicateToAction;
7
- var _react = _interopRequireWildcard(require("react"));
8
- var _icons = require("@sanity/icons");
9
- var _CrossDatasetDuplicator = _interopRequireDefault(require("../components/CrossDatasetDuplicator"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
12
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
- function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
14
- function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
15
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
16
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
17
- function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
18
- function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
19
- function DuplicateToAction(_ref) {
20
- var draft = _ref.draft,
21
- published = _ref.published,
22
- onComplete = _ref.onComplete;
23
- var _useState = (0, _react.useState)(false),
24
- _useState2 = _slicedToArray(_useState, 2),
25
- dialogOpen = _useState2[0],
26
- setDialogOpen = _useState2[1];
27
- return {
28
- disabled: draft,
29
- title: draft ? "Document must be Published to begin" : null,
30
- label: 'Duplicate to...',
31
- dialog: dialogOpen && published && {
32
- type: 'modal',
33
- title: 'Cross Dataset Duplicator',
34
- content: /*#__PURE__*/_react.default.createElement(_CrossDatasetDuplicator.default, {
35
- docs: [published],
36
- mode: "action"
37
- }),
38
- onClose: () => onComplete()
39
- },
40
- onHandle: () => setDialogOpen(true),
41
- icon: _icons.LaunchIcon
42
- };
43
- }
44
- //# sourceMappingURL=DuplicateToAction.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DuplicateToAction.js","names":["DuplicateToAction","draft","published","onComplete","useState","dialogOpen","setDialogOpen","disabled","title","label","dialog","type","content","onClose","onHandle","icon","LaunchIcon"],"sources":["../../src/actions/DuplicateToAction.tsx"],"sourcesContent":["import React, {useState} from 'react'\nimport {LaunchIcon} from '@sanity/icons'\n\nimport CrossDatasetDuplicator from '../components/CrossDatasetDuplicator'\n\nexport default function DuplicateToAction({draft, published, onComplete}) {\n const [dialogOpen, setDialogOpen] = useState(false)\n\n return {\n disabled: draft,\n title: draft ? `Document must be Published to begin` : null,\n label: 'Duplicate to...',\n dialog: dialogOpen && published && {\n type: 'modal',\n title: 'Cross Dataset Duplicator',\n content: <CrossDatasetDuplicator docs={[published]} mode=\"action\" />,\n onClose: () => onComplete(),\n },\n onHandle: () => setDialogOpen(true),\n icon: LaunchIcon,\n }\n}\n"],"mappings":";;;;;;AAAA;AACA;AAEA;AAAyE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAE1D,SAASA,iBAAiB,OAAiC;EAAA,IAA/BC,KAAK,QAALA,KAAK;IAAEC,SAAS,QAATA,SAAS;IAAEC,UAAU,QAAVA,UAAU;EACrE,gBAAoC,IAAAC,eAAQ,EAAC,KAAK,CAAC;IAAA;IAA5CC,UAAU;IAAEC,aAAa;EAEhC,OAAO;IACLC,QAAQ,EAAEN,KAAK;IACfO,KAAK,EAAEP,KAAK,2CAA2C,IAAI;IAC3DQ,KAAK,EAAE,iBAAiB;IACxBC,MAAM,EAAEL,UAAU,IAAIH,SAAS,IAAI;MACjCS,IAAI,EAAE,OAAO;MACbH,KAAK,EAAE,0BAA0B;MACjCI,OAAO,eAAE,6BAAC,+BAAsB;QAAC,IAAI,EAAE,CAACV,SAAS,CAAE;QAAC,IAAI,EAAC;MAAQ,EAAG;MACpEW,OAAO,EAAE,MAAMV,UAAU;IAC3B,CAAC;IACDW,QAAQ,EAAE,MAAMR,aAAa,CAAC,IAAI,CAAC;IACnCS,IAAI,EAAEC;EACR,CAAC;AACH"}
@@ -1,29 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = resolveDocumentActions;
7
- var _documentActions = _interopRequireWildcard(require("part:@sanity/base/document-actions"));
8
- var _crossDatasetDuplicator = _interopRequireDefault(require("config:@sanity/cross-dataset-duplicator"));
9
- var _DuplicateToAction = _interopRequireDefault(require("./DuplicateToAction"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
12
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
- function resolveDocumentActions(props) {
14
- var _config$types;
15
- var duplicatorTypes = (_config$types = _crossDatasetDuplicator.default === null || _crossDatasetDuplicator.default === void 0 ? void 0 : _crossDatasetDuplicator.default.types) !== null && _config$types !== void 0 ? _config$types : [];
16
- var defaultActions = (0, _documentActions.default)(props);
17
-
18
- // Insert 'Duplicate to...' after 'Duplicate' only on config'd types
19
- if (duplicatorTypes.includes(props === null || props === void 0 ? void 0 : props.type)) {
20
- return defaultActions.reduce((acc, cur) => {
21
- if (cur === _documentActions.DuplicateAction) {
22
- return [...acc, cur, _DuplicateToAction.default];
23
- }
24
- return [...acc, cur];
25
- }, []);
26
- }
27
- return defaultActions;
28
- }
29
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["resolveDocumentActions","props","duplicatorTypes","config","types","defaultActions","defaultResolve","includes","type","reduce","acc","cur","DuplicateAction","DuplicateToAction"],"sources":["../../src/actions/index.ts"],"sourcesContent":["import defaultResolve, {DuplicateAction} from 'part:@sanity/base/document-actions'\nimport config from 'config:@sanity/cross-dataset-duplicator'\n\nimport DuplicateToAction from './DuplicateToAction'\n\nexport default function resolveDocumentActions(props) { \n const duplicatorTypes = config?.types ?? []\n const defaultActions = defaultResolve(props)\n\n // Insert 'Duplicate to...' after 'Duplicate' only on config'd types\n if (duplicatorTypes.includes(props?.type)) {\n return defaultActions.reduce((acc, cur) => {\n if (cur === DuplicateAction) {\n return [...acc, cur, DuplicateToAction]\n }\n\n return [...acc, cur]\n }, [])\n }\n\n return defaultActions\n}\n"],"mappings":";;;;;;AAAA;AACA;AAEA;AAAmD;AAAA;AAAA;AAEpC,SAASA,sBAAsB,CAACC,KAAK,EAAE;EAAA;EACpD,IAAMC,eAAe,oBAAGC,+BAAM,aAANA,+BAAM,uBAANA,+BAAM,CAAEC,KAAK,yDAAI,EAAE;EAC3C,IAAMC,cAAc,GAAG,IAAAC,wBAAc,EAACL,KAAK,CAAC;;EAE5C;EACA,IAAIC,eAAe,CAACK,QAAQ,CAACN,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEO,IAAI,CAAC,EAAE;IACzC,OAAOH,cAAc,CAACI,MAAM,CAAC,CAACC,GAAG,EAAEC,GAAG,KAAK;MACzC,IAAIA,GAAG,KAAKC,gCAAe,EAAE;QAC3B,OAAO,CAAC,GAAGF,GAAG,EAAEC,GAAG,EAAEE,0BAAiB,CAAC;MACzC;MAEA,OAAO,CAAC,GAAGH,GAAG,EAAEC,GAAG,CAAC;IACtB,CAAC,EAAE,EAAE,CAAC;EACR;EAEA,OAAON,cAAc;AACvB"}