sanity-plugin-workflow 1.0.6 → 2.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/README.md +2 -17
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1647 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -71
- package/lib/index.d.ts +0 -20
- package/lib/index.esm.js +0 -2135
- package/lib/index.esm.js.map +0 -1
- package/lib/index.js +0 -2147
- package/lib/index.js.map +0 -1
- package/sanity.json +0 -8
- package/src/actions/AssignWorkflow.tsx +0 -47
- package/src/actions/BeginWorkflow.tsx +0 -63
- package/src/actions/CompleteWorkflow.tsx +0 -64
- package/src/actions/UpdateWorkflow.tsx +0 -126
- package/src/badges/AssigneesBadge.tsx +0 -53
- package/src/badges/StateBadge.tsx +0 -28
- package/src/components/DocumentCard/AvatarGroup.tsx +0 -43
- package/src/components/DocumentCard/CompleteButton.tsx +0 -56
- package/src/components/DocumentCard/EditButton.tsx +0 -28
- package/src/components/DocumentCard/Field.tsx +0 -38
- package/src/components/DocumentCard/Validate.tsx +0 -21
- package/src/components/DocumentCard/ValidationStatus.tsx +0 -37
- package/src/components/DocumentCard/core/DraftStatus.tsx +0 -32
- package/src/components/DocumentCard/core/PublishedStatus.tsx +0 -39
- package/src/components/DocumentCard/core/TimeAgo.tsx +0 -11
- package/src/components/DocumentCard/index.tsx +0 -200
- package/src/components/DocumentList.tsx +0 -169
- package/src/components/Filters.tsx +0 -174
- package/src/components/FloatingCard.tsx +0 -36
- package/src/components/StateTitle/Status.tsx +0 -27
- package/src/components/StateTitle/index.tsx +0 -78
- package/src/components/UserAssignment.tsx +0 -121
- package/src/components/UserAssignmentInput.tsx +0 -27
- package/src/components/UserDisplay.tsx +0 -57
- package/src/components/Verify.tsx +0 -297
- package/src/components/WorkflowContext.tsx +0 -71
- package/src/components/WorkflowSignal.tsx +0 -30
- package/src/components/WorkflowTool.tsx +0 -437
- package/src/constants/index.ts +0 -31
- package/src/helpers/arraysContainMatchingString.ts +0 -6
- package/src/helpers/filterItemsAndSort.ts +0 -41
- package/src/helpers/generateMultipleOrderRanks.ts +0 -80
- package/src/helpers/initialRank.ts +0 -13
- package/src/hooks/useWorkflowDocuments.tsx +0 -167
- package/src/hooks/useWorkflowMetadata.tsx +0 -49
- package/src/index.ts +0 -97
- package/src/schema/workflow/workflow.metadata.ts +0 -68
- package/src/tools/index.ts +0 -15
- package/src/types/index.ts +0 -71
- package/v2-incompatible.js +0 -11
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {CheckmarkIcon} from '@sanity/icons'
|
|
2
|
-
import {ToastContextValue, useToast} from '@sanity/ui'
|
|
3
|
-
import {useCallback} from 'react'
|
|
4
|
-
import {DocumentActionProps, SanityClient, useClient} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import {useWorkflowContext} from '../components/WorkflowContext'
|
|
7
|
-
import {API_VERSION} from '../constants'
|
|
8
|
-
|
|
9
|
-
export const handleDeleteMetadata = async (
|
|
10
|
-
client: SanityClient,
|
|
11
|
-
toast: ToastContextValue,
|
|
12
|
-
id: string
|
|
13
|
-
) => {
|
|
14
|
-
try {
|
|
15
|
-
await client.delete(`workflow-metadata.${id}`)
|
|
16
|
-
toast.push({
|
|
17
|
-
status: 'success',
|
|
18
|
-
title: 'Workflow completed',
|
|
19
|
-
})
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error(error)
|
|
22
|
-
toast.push({
|
|
23
|
-
status: 'error',
|
|
24
|
-
title: 'Could not complete Workflow',
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function CompleteWorkflow(props: DocumentActionProps) {
|
|
30
|
-
const {id} = props
|
|
31
|
-
const {metadata, loading, error, states} = useWorkflowContext(id)
|
|
32
|
-
const client = useClient({apiVersion: API_VERSION})
|
|
33
|
-
const toast = useToast()
|
|
34
|
-
|
|
35
|
-
if (error) {
|
|
36
|
-
console.error(error)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const handle = useCallback(async () => {
|
|
40
|
-
await handleDeleteMetadata(client, toast, id)
|
|
41
|
-
}, [client, toast, id])
|
|
42
|
-
|
|
43
|
-
if (!metadata) {
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const state = states.find((s) => s.id === metadata.state)
|
|
48
|
-
const isLastState = state?.id === states[states.length - 1].id
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
icon: CheckmarkIcon,
|
|
52
|
-
type: 'dialog',
|
|
53
|
-
disabled: loading || error || !isLastState,
|
|
54
|
-
label: `Complete Workflow`,
|
|
55
|
-
title: isLastState
|
|
56
|
-
? `Removes the document from the Workflow process`
|
|
57
|
-
: `Cannot remove from workflow until in the last state`,
|
|
58
|
-
onHandle: async () => {
|
|
59
|
-
await handle()
|
|
60
|
-
props.onComplete()
|
|
61
|
-
},
|
|
62
|
-
color: 'positive',
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import {ArrowLeftIcon, ArrowRightIcon} from '@sanity/icons'
|
|
2
|
-
import {useToast} from '@sanity/ui'
|
|
3
|
-
import {useCurrentUser, useValidationStatus} from 'sanity'
|
|
4
|
-
import {DocumentActionProps, useClient} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import {useWorkflowContext} from '../components/WorkflowContext'
|
|
7
|
-
import {API_VERSION} from '../constants'
|
|
8
|
-
import {arraysContainMatchingString} from '../helpers/arraysContainMatchingString'
|
|
9
|
-
import {State} from '../types'
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line complexity
|
|
12
|
-
export function UpdateWorkflow(props: DocumentActionProps, actionState: State) {
|
|
13
|
-
const {id, type} = props
|
|
14
|
-
|
|
15
|
-
const user = useCurrentUser()
|
|
16
|
-
const client = useClient({apiVersion: API_VERSION})
|
|
17
|
-
const toast = useToast()
|
|
18
|
-
const currentUser = useCurrentUser()
|
|
19
|
-
|
|
20
|
-
const {metadata, loading, error, states} = useWorkflowContext(id)
|
|
21
|
-
const currentState = states.find((s) => s.id === metadata?.state)
|
|
22
|
-
const {assignees = []} = metadata ?? {}
|
|
23
|
-
|
|
24
|
-
// TODO: Shouldn't the document action props contain this?
|
|
25
|
-
const {validation, isValidating} = useValidationStatus(id, type)
|
|
26
|
-
const hasValidationErrors =
|
|
27
|
-
currentState?.requireValidation &&
|
|
28
|
-
!isValidating &&
|
|
29
|
-
validation?.length > 0 &&
|
|
30
|
-
validation.find((v) => v.level === 'error')
|
|
31
|
-
|
|
32
|
-
if (error) {
|
|
33
|
-
console.error(error)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const onHandle = (documentId: string, newState: State) => {
|
|
37
|
-
client
|
|
38
|
-
.patch(`workflow-metadata.${documentId}`)
|
|
39
|
-
.set({state: newState.id})
|
|
40
|
-
.commit()
|
|
41
|
-
.then(() => {
|
|
42
|
-
props.onComplete()
|
|
43
|
-
toast.push({
|
|
44
|
-
status: 'success',
|
|
45
|
-
title: `Document state now "${newState.title}"`,
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
.catch((err) => {
|
|
49
|
-
props.onComplete()
|
|
50
|
-
console.error(err)
|
|
51
|
-
toast.push({
|
|
52
|
-
status: 'error',
|
|
53
|
-
title: `Document state update failed`,
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Remove button if:
|
|
59
|
-
// Document is not in Workflow OR
|
|
60
|
-
// The current State is the same as this actions State
|
|
61
|
-
if (!metadata || (currentState && currentState.id === actionState.id)) {
|
|
62
|
-
return null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const currentStateIndex = states.findIndex((s) => s.id === currentState?.id)
|
|
66
|
-
const actionStateIndex = states.findIndex((s) => s.id === actionState.id)
|
|
67
|
-
const direction = actionStateIndex > currentStateIndex ? 'promote' : 'demote'
|
|
68
|
-
const DirectionIcon = direction === 'promote' ? ArrowRightIcon : ArrowLeftIcon
|
|
69
|
-
const directionLabel = direction === 'promote' ? 'Promote' : 'Demote'
|
|
70
|
-
|
|
71
|
-
const userRoleCanUpdateState =
|
|
72
|
-
user?.roles?.length && actionState?.roles?.length
|
|
73
|
-
? // If the Action state is limited to specific roles
|
|
74
|
-
// check that the current user has one of those roles
|
|
75
|
-
arraysContainMatchingString(
|
|
76
|
-
user.roles.map((r) => r.name),
|
|
77
|
-
actionState.roles
|
|
78
|
-
)
|
|
79
|
-
: // No roles specified on the next state, so anyone can update
|
|
80
|
-
actionState?.roles?.length !== 0
|
|
81
|
-
|
|
82
|
-
const actionStateIsAValidTransition =
|
|
83
|
-
currentState?.id && currentState?.transitions?.length
|
|
84
|
-
? // If the Current State limits transitions to specific States
|
|
85
|
-
// Check that the Action State is in Current State's transitions array
|
|
86
|
-
currentState.transitions.includes(actionState.id)
|
|
87
|
-
: // Otherwise this isn't a problem
|
|
88
|
-
true
|
|
89
|
-
|
|
90
|
-
const userAssignmentCanUpdateState = actionState.requireAssignment
|
|
91
|
-
? // If the Action State requires assigned users
|
|
92
|
-
// Check the current user ID is in the assignees array
|
|
93
|
-
currentUser && assignees?.length && assignees.includes(currentUser.id)
|
|
94
|
-
: // Otherwise this isn't a problem
|
|
95
|
-
true
|
|
96
|
-
|
|
97
|
-
let title = `${directionLabel} State to "${actionState.title}"`
|
|
98
|
-
|
|
99
|
-
if (!userRoleCanUpdateState) {
|
|
100
|
-
title = `Your User role cannot ${directionLabel} State to "${actionState.title}"`
|
|
101
|
-
} else if (!actionStateIsAValidTransition) {
|
|
102
|
-
title = `You cannot ${directionLabel} State to "${actionState.title}" from "${currentState?.title}"`
|
|
103
|
-
} else if (!userAssignmentCanUpdateState) {
|
|
104
|
-
title = `You must be assigned to the document to ${directionLabel} State to "${actionState.title}"`
|
|
105
|
-
} else if (currentState?.requireValidation && isValidating) {
|
|
106
|
-
title = `Document is validating, cannot ${directionLabel} State to "${actionState.title}"`
|
|
107
|
-
} else if (hasValidationErrors) {
|
|
108
|
-
title = `Document has validation errors, cannot ${directionLabel} State to "${actionState.title}"`
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
icon: DirectionIcon,
|
|
113
|
-
disabled:
|
|
114
|
-
loading ||
|
|
115
|
-
error ||
|
|
116
|
-
(currentState?.requireValidation && isValidating) ||
|
|
117
|
-
hasValidationErrors ||
|
|
118
|
-
!currentState ||
|
|
119
|
-
!userRoleCanUpdateState ||
|
|
120
|
-
!actionStateIsAValidTransition ||
|
|
121
|
-
!userAssignmentCanUpdateState,
|
|
122
|
-
title,
|
|
123
|
-
label: actionState.title,
|
|
124
|
-
onHandle: () => onHandle(id, actionState),
|
|
125
|
-
}
|
|
126
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {CurrentUser, DocumentBadgeDescription} from 'sanity'
|
|
2
|
-
import {useProjectUsers} from 'sanity-plugin-utils'
|
|
3
|
-
|
|
4
|
-
import {useWorkflowContext} from '../components/WorkflowContext'
|
|
5
|
-
import {API_VERSION} from '../constants'
|
|
6
|
-
|
|
7
|
-
export function AssigneesBadge(
|
|
8
|
-
documentId: string,
|
|
9
|
-
currentUser: CurrentUser | null
|
|
10
|
-
): DocumentBadgeDescription | null {
|
|
11
|
-
const {metadata, loading, error} = useWorkflowContext(documentId)
|
|
12
|
-
const userList = useProjectUsers({apiVersion: API_VERSION})
|
|
13
|
-
|
|
14
|
-
if (loading || error || !metadata) {
|
|
15
|
-
if (error) {
|
|
16
|
-
console.error(error)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (!metadata?.assignees?.length) {
|
|
23
|
-
return {
|
|
24
|
-
label: 'Unassigned',
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const {assignees} = metadata ?? []
|
|
29
|
-
const hasMe = currentUser
|
|
30
|
-
? assignees.some((assignee) => assignee === currentUser.id)
|
|
31
|
-
: false
|
|
32
|
-
const assigneesCount = hasMe ? assignees.length - 1 : assignees.length
|
|
33
|
-
const assigneeUsers = userList.filter((user) => assignees.includes(user.id))
|
|
34
|
-
const title = assigneeUsers.map((user) => user.displayName).join(', ')
|
|
35
|
-
|
|
36
|
-
let label
|
|
37
|
-
|
|
38
|
-
if (hasMe && assigneesCount === 0) {
|
|
39
|
-
label = 'Assigned to Me'
|
|
40
|
-
} else if (hasMe && assigneesCount > 0) {
|
|
41
|
-
label = `Me and ${assigneesCount} ${
|
|
42
|
-
assigneesCount === 1 ? 'other' : 'others'
|
|
43
|
-
}`
|
|
44
|
-
} else {
|
|
45
|
-
label = `${assigneesCount} assigned`
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
label,
|
|
50
|
-
title,
|
|
51
|
-
color: 'primary',
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {DocumentBadgeDescription} from 'sanity'
|
|
2
|
-
|
|
3
|
-
import {useWorkflowContext} from '../components/WorkflowContext'
|
|
4
|
-
|
|
5
|
-
export function StateBadge(
|
|
6
|
-
documentId: string
|
|
7
|
-
): DocumentBadgeDescription | null {
|
|
8
|
-
const {metadata, loading, error, states} = useWorkflowContext(documentId)
|
|
9
|
-
const state = states.find((s) => s.id === metadata?.state)
|
|
10
|
-
|
|
11
|
-
if (loading || error) {
|
|
12
|
-
if (error) {
|
|
13
|
-
console.error(error)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (!state) {
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
label: state.title,
|
|
25
|
-
// title: state.title,
|
|
26
|
-
color: state?.color,
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {Box, Flex, Text} from '@sanity/ui'
|
|
3
|
-
import {useCurrentUser, UserAvatar} from 'sanity'
|
|
4
|
-
|
|
5
|
-
import {User} from '../../types'
|
|
6
|
-
|
|
7
|
-
type AvatarGroupProps = {
|
|
8
|
-
users: User[]
|
|
9
|
-
max?: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default function AvatarGroup(props: AvatarGroupProps) {
|
|
13
|
-
const currentUser = useCurrentUser()
|
|
14
|
-
const {users, max = 4} = props
|
|
15
|
-
|
|
16
|
-
const len = users?.length
|
|
17
|
-
const {me, visibleUsers} = React.useMemo(() => {
|
|
18
|
-
return {
|
|
19
|
-
me: currentUser?.id ? users.find((u) => u.id === currentUser.id) : undefined,
|
|
20
|
-
visibleUsers: users.filter((u) => u.id !== currentUser?.id).slice(0, max - 1),
|
|
21
|
-
}
|
|
22
|
-
}, [users, max, currentUser])
|
|
23
|
-
|
|
24
|
-
if (!users?.length) {
|
|
25
|
-
return null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<Flex align="center" gap={1}>
|
|
30
|
-
{me ? <UserAvatar user={me} /> : null}
|
|
31
|
-
{visibleUsers.map((user) => (
|
|
32
|
-
<Box key={user.id} style={{marginRight: -8}}>
|
|
33
|
-
<UserAvatar user={user} />
|
|
34
|
-
</Box>
|
|
35
|
-
))}
|
|
36
|
-
{len > max && (
|
|
37
|
-
<Box paddingLeft={2}>
|
|
38
|
-
<Text size={1}>+{len - max}</Text>
|
|
39
|
-
</Box>
|
|
40
|
-
)}
|
|
41
|
-
</Flex>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import {CheckmarkIcon} from '@sanity/icons'
|
|
2
|
-
import {Box, Button, Text, Tooltip, useToast} from '@sanity/ui'
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import {useClient} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import {handleDeleteMetadata} from '../../actions/CompleteWorkflow'
|
|
7
|
-
import {API_VERSION} from '../../constants'
|
|
8
|
-
|
|
9
|
-
type CompleteButtonProps = {
|
|
10
|
-
documentId: string
|
|
11
|
-
disabled: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default function CompleteButton(props: CompleteButtonProps) {
|
|
15
|
-
const {documentId, disabled = false} = props
|
|
16
|
-
const client = useClient({apiVersion: API_VERSION})
|
|
17
|
-
const toast = useToast()
|
|
18
|
-
|
|
19
|
-
const handleComplete: React.MouseEventHandler<HTMLButtonElement> =
|
|
20
|
-
React.useCallback(
|
|
21
|
-
(event) => {
|
|
22
|
-
const id = event.currentTarget.value
|
|
23
|
-
|
|
24
|
-
if (!id) {
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
handleDeleteMetadata(client, toast, id)
|
|
29
|
-
},
|
|
30
|
-
[client, toast]
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<Tooltip
|
|
35
|
-
portal
|
|
36
|
-
content={
|
|
37
|
-
<Box padding={2}>
|
|
38
|
-
<Text size={1}>Remove this document from Workflow</Text>
|
|
39
|
-
</Box>
|
|
40
|
-
}
|
|
41
|
-
>
|
|
42
|
-
<Button
|
|
43
|
-
value={documentId}
|
|
44
|
-
onClick={handleComplete}
|
|
45
|
-
text="Complete"
|
|
46
|
-
icon={CheckmarkIcon}
|
|
47
|
-
tone="positive"
|
|
48
|
-
mode="ghost"
|
|
49
|
-
fontSize={1}
|
|
50
|
-
padding={2}
|
|
51
|
-
tabIndex={-1}
|
|
52
|
-
disabled={disabled}
|
|
53
|
-
/>
|
|
54
|
-
</Tooltip>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {Button} from '@sanity/ui'
|
|
2
|
-
import {EditIcon} from '@sanity/icons'
|
|
3
|
-
import {useRouter} from 'sanity/router'
|
|
4
|
-
|
|
5
|
-
type EditButtonProps = {
|
|
6
|
-
id: string
|
|
7
|
-
type: string
|
|
8
|
-
disabled?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default function EditButton(props: EditButtonProps) {
|
|
12
|
-
const {id, type, disabled = false} = props
|
|
13
|
-
const {navigateIntent} = useRouter()
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<Button
|
|
17
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
18
|
-
onClick={() => navigateIntent('edit', {id, type})}
|
|
19
|
-
mode="ghost"
|
|
20
|
-
fontSize={1}
|
|
21
|
-
padding={2}
|
|
22
|
-
tabIndex={-1}
|
|
23
|
-
icon={EditIcon}
|
|
24
|
-
text="Edit"
|
|
25
|
-
disabled={disabled}
|
|
26
|
-
/>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import {Flex, Card, Spinner} from '@sanity/ui'
|
|
2
|
-
import {Preview, SanityDocument, StringInputProps, useSchema} from 'sanity'
|
|
3
|
-
import {useListeningQuery, Feedback} from 'sanity-plugin-utils'
|
|
4
|
-
|
|
5
|
-
import EditButton from './EditButton'
|
|
6
|
-
|
|
7
|
-
// TODO: Update this to use the same component as the Tool
|
|
8
|
-
export default function Field(props: StringInputProps) {
|
|
9
|
-
const schema = useSchema()
|
|
10
|
-
const {data, loading, error} = useListeningQuery<SanityDocument>(
|
|
11
|
-
`*[_id in [$id, $draftId]]|order(_updatedAt)[0]`,
|
|
12
|
-
{
|
|
13
|
-
params: {
|
|
14
|
-
id: String(props.value),
|
|
15
|
-
draftId: `drafts.${String(props.value)}`,
|
|
16
|
-
},
|
|
17
|
-
}
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
if (loading) {
|
|
21
|
-
return <Spinner />
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const schemaType = schema.get(data?._type ?? ``)
|
|
25
|
-
|
|
26
|
-
if (error || !data?._type || !schemaType) {
|
|
27
|
-
return <Feedback tone="critical" title="Error with query" />
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Card border padding={2}>
|
|
32
|
-
<Flex align="center" justify="space-between" gap={2}>
|
|
33
|
-
<Preview layout="default" value={data} schemaType={schemaType} />
|
|
34
|
-
<EditButton id={data._id} type={data._type} />
|
|
35
|
-
</Flex>
|
|
36
|
-
</Card>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {useEffect} from 'react'
|
|
2
|
-
import {useValidationStatus, ValidationStatus} from 'sanity'
|
|
3
|
-
|
|
4
|
-
type ValidateProps = {
|
|
5
|
-
documentId: string
|
|
6
|
-
type: string
|
|
7
|
-
onChange: (validation: ValidationStatus) => void
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Document validation is siloed into its own component
|
|
11
|
-
// Because it's not performant to run on a lot of documents
|
|
12
|
-
export default function Validate(props: ValidateProps) {
|
|
13
|
-
const {documentId, type, onChange} = props
|
|
14
|
-
const {isValidating, validation = []} = useValidationStatus(documentId, type)
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
onChange({isValidating, validation})
|
|
18
|
-
}, [onChange, isValidating, validation])
|
|
19
|
-
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {ErrorOutlineIcon, WarningOutlineIcon} from '@sanity/icons'
|
|
2
|
-
import {ValidationMarker} from '@sanity/types'
|
|
3
|
-
import {Box, Text, Tooltip} from '@sanity/ui'
|
|
4
|
-
import {TextWithTone} from 'sanity'
|
|
5
|
-
|
|
6
|
-
type ValidationStatusProps = {
|
|
7
|
-
validation: ValidationMarker[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function ValidationStatus(props: ValidationStatusProps) {
|
|
11
|
-
const {validation = []} = props
|
|
12
|
-
|
|
13
|
-
if (!validation.length) {
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const hasError = validation.some((item) => item.level === 'error')
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<Tooltip
|
|
21
|
-
portal
|
|
22
|
-
content={
|
|
23
|
-
<Box padding={2}>
|
|
24
|
-
<Text size={1}>
|
|
25
|
-
{validation.length === 1
|
|
26
|
-
? `1 validation issue`
|
|
27
|
-
: `${validation.length} validation issues`}
|
|
28
|
-
</Text>
|
|
29
|
-
</Box>
|
|
30
|
-
}
|
|
31
|
-
>
|
|
32
|
-
<TextWithTone tone={hasError ? `critical` : `caution`} size={1}>
|
|
33
|
-
{hasError ? <ErrorOutlineIcon /> : <WarningOutlineIcon />}
|
|
34
|
-
</TextWithTone>
|
|
35
|
-
</Tooltip>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {EditIcon} from '@sanity/icons'
|
|
2
|
-
import {PreviewValue, SanityDocument} from '@sanity/types'
|
|
3
|
-
import {Box, Text, Tooltip} from '@sanity/ui'
|
|
4
|
-
import {TextWithTone} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import {TimeAgo} from './TimeAgo'
|
|
7
|
-
|
|
8
|
-
export function DraftStatus(props: {document?: PreviewValue | Partial<SanityDocument> | null}) {
|
|
9
|
-
const {document} = props
|
|
10
|
-
const updatedAt = document && '_updatedAt' in document && document._updatedAt
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<Tooltip
|
|
14
|
-
portal
|
|
15
|
-
content={
|
|
16
|
-
<Box padding={2}>
|
|
17
|
-
<Text size={1}>
|
|
18
|
-
{document ? (
|
|
19
|
-
<>Edited {updatedAt && <TimeAgo time={updatedAt} />}</>
|
|
20
|
-
) : (
|
|
21
|
-
<>No unpublished edits</>
|
|
22
|
-
)}
|
|
23
|
-
</Text>
|
|
24
|
-
</Box>
|
|
25
|
-
}
|
|
26
|
-
>
|
|
27
|
-
<TextWithTone tone="caution" dimmed={!document} muted={!document} size={1}>
|
|
28
|
-
<EditIcon />
|
|
29
|
-
</TextWithTone>
|
|
30
|
-
</Tooltip>
|
|
31
|
-
)
|
|
32
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import {PublishIcon} from '@sanity/icons'
|
|
2
|
-
import {PreviewValue, SanityDocument} from '@sanity/types'
|
|
3
|
-
import {Box, Text, Tooltip} from '@sanity/ui'
|
|
4
|
-
import {TextWithTone} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import {TimeAgo} from './TimeAgo'
|
|
7
|
-
|
|
8
|
-
export function PublishedStatus(props: {
|
|
9
|
-
document?: PreviewValue | Partial<SanityDocument> | null
|
|
10
|
-
}) {
|
|
11
|
-
const {document} = props
|
|
12
|
-
const updatedAt = document && '_updatedAt' in document && document._updatedAt
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<Tooltip
|
|
16
|
-
portal
|
|
17
|
-
content={
|
|
18
|
-
<Box padding={2}>
|
|
19
|
-
<Text size={1}>
|
|
20
|
-
{document ? (
|
|
21
|
-
<>Published {updatedAt && <TimeAgo time={updatedAt} />}</>
|
|
22
|
-
) : (
|
|
23
|
-
<>Not published</>
|
|
24
|
-
)}
|
|
25
|
-
</Text>
|
|
26
|
-
</Box>
|
|
27
|
-
}
|
|
28
|
-
>
|
|
29
|
-
<TextWithTone
|
|
30
|
-
tone="positive"
|
|
31
|
-
dimmed={!document}
|
|
32
|
-
muted={!document}
|
|
33
|
-
size={1}
|
|
34
|
-
>
|
|
35
|
-
<PublishIcon />
|
|
36
|
-
</TextWithTone>
|
|
37
|
-
</Tooltip>
|
|
38
|
-
)
|
|
39
|
-
}
|