sanity-plugin-workflow 1.0.0-beta.1 → 1.0.0-beta.3
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/LICENSE +1 -1
- package/README.md +71 -12
- package/lib/{src/index.d.ts → index.d.ts} +3 -3
- package/lib/index.esm.js +1691 -1
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +1704 -1
- package/lib/index.js.map +1 -1
- package/package.json +48 -38
- package/src/actions/AssignWorkflow.tsx +48 -0
- package/src/actions/BeginWorkflow.tsx +68 -0
- package/src/actions/CompleteWorkflow.tsx +41 -0
- package/src/actions/RequestReviewAction.js +1 -7
- package/src/actions/UpdateWorkflow.tsx +142 -0
- package/src/badges/AssigneesBadge.tsx +52 -0
- package/src/badges/{index.tsx → StateBadge.tsx} +4 -8
- package/src/components/DocumentCard/AvatarGroup.tsx +12 -8
- package/src/components/DocumentCard/CompleteButton.tsx +53 -0
- package/src/components/DocumentCard/EditButton.tsx +3 -2
- package/src/components/DocumentCard/Field.tsx +38 -0
- package/src/components/DocumentCard/ValidationStatus.tsx +37 -0
- package/src/components/DocumentCard/core/DraftStatus.tsx +32 -0
- package/src/components/DocumentCard/core/PublishedStatus.tsx +32 -0
- package/src/components/DocumentCard/core/TimeAgo.tsx +11 -0
- package/src/components/DocumentCard/index.tsx +156 -50
- package/src/components/Filters.tsx +168 -0
- package/src/components/FloatingCard.tsx +29 -0
- package/src/components/StateTitle/Status.tsx +27 -0
- package/src/components/StateTitle/index.tsx +73 -0
- package/src/components/UserAssignment.tsx +57 -75
- package/src/components/UserAssignmentInput.tsx +27 -0
- package/src/components/UserDisplay.tsx +57 -0
- package/src/components/Validators.tsx +196 -0
- package/src/components/WorkflowTool.tsx +301 -160
- package/src/constants/index.ts +31 -0
- package/src/helpers/arraysContainMatchingString.ts +6 -0
- package/src/helpers/filterItemsAndSort.ts +39 -0
- package/src/helpers/initialRank.ts +13 -0
- package/src/hooks/useWorkflowDocuments.tsx +62 -70
- package/src/hooks/useWorkflowMetadata.tsx +0 -1
- package/src/index.ts +38 -58
- package/src/schema/workflow/workflow.metadata.ts +68 -0
- package/src/tools/index.ts +15 -0
- package/src/types/index.ts +27 -6
- package/src/actions/DemoteAction.tsx +0 -62
- package/src/actions/PromoteAction.tsx +0 -62
- package/src/components/Mutate.tsx +0 -54
- package/src/components/StateTimeline.tsx +0 -98
- package/src/components/UserSelectInput.tsx +0 -43
- package/src/schema/workflow/metadata.ts +0 -38
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import {AddIcon} from '@sanity/icons'
|
|
2
|
+
import {useToast} from '@sanity/ui'
|
|
4
3
|
import {UserSelectMenu} from 'sanity-plugin-utils'
|
|
5
4
|
import {useClient} from 'sanity'
|
|
6
5
|
|
|
7
|
-
import AvatarGroup from './DocumentCard/AvatarGroup'
|
|
8
6
|
import {User} from '../types'
|
|
7
|
+
import {API_VERSION} from '../constants'
|
|
9
8
|
|
|
10
9
|
type UserAssignmentProps = {
|
|
11
10
|
userList: User[]
|
|
@@ -15,28 +14,28 @@ type UserAssignmentProps = {
|
|
|
15
14
|
|
|
16
15
|
export default function UserAssignment(props: UserAssignmentProps) {
|
|
17
16
|
const {assignees, userList, documentId} = props
|
|
18
|
-
const client = useClient()
|
|
17
|
+
const client = useClient({apiVersion: API_VERSION})
|
|
19
18
|
const toast = useToast()
|
|
20
|
-
const [openId, setOpenId] = React.useState<string>(``)
|
|
21
19
|
|
|
22
20
|
const addAssignee = React.useCallback(
|
|
23
21
|
(userId: string) => {
|
|
24
|
-
|
|
22
|
+
const user = userList.find((u) => u.id === userId)
|
|
23
|
+
|
|
24
|
+
if (!userId || !user) {
|
|
25
25
|
return toast.push({
|
|
26
26
|
status: 'error',
|
|
27
|
-
title: '
|
|
27
|
+
title: 'Could not find User',
|
|
28
28
|
})
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
client
|
|
31
|
+
return client
|
|
32
32
|
.patch(`workflow-metadata.${documentId}`)
|
|
33
33
|
.setIfMissing({assignees: []})
|
|
34
34
|
.insert(`after`, `assignees[-1]`, [userId])
|
|
35
35
|
.commit()
|
|
36
36
|
.then(() => {
|
|
37
37
|
return toast.push({
|
|
38
|
-
title: `
|
|
39
|
-
description: userId,
|
|
38
|
+
title: `Added ${user.displayName} to assignees`,
|
|
40
39
|
status: 'success',
|
|
41
40
|
})
|
|
42
41
|
})
|
|
@@ -50,90 +49,73 @@ export default function UserAssignment(props: UserAssignmentProps) {
|
|
|
50
49
|
})
|
|
51
50
|
})
|
|
52
51
|
},
|
|
53
|
-
[documentId, client, toast]
|
|
52
|
+
[documentId, client, toast, userList]
|
|
54
53
|
)
|
|
55
54
|
|
|
56
55
|
const removeAssignee = React.useCallback(
|
|
57
|
-
(
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
(userId: string) => {
|
|
57
|
+
const user = userList.find((u) => u.id === userId)
|
|
58
|
+
|
|
59
|
+
if (!userId || !user) {
|
|
60
|
+
return toast.push({
|
|
61
|
+
status: 'error',
|
|
62
|
+
title: 'Could not find User',
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return client
|
|
67
|
+
.patch(`workflow-metadata.${documentId}`)
|
|
60
68
|
.unset([`assignees[@ == "${userId}"]`])
|
|
61
69
|
.commit()
|
|
62
|
-
.then((
|
|
70
|
+
.then(() => {
|
|
71
|
+
return toast.push({
|
|
72
|
+
title: `Removed ${user.displayName} from assignees`,
|
|
73
|
+
status: 'success',
|
|
74
|
+
})
|
|
75
|
+
})
|
|
63
76
|
.catch((err) => {
|
|
64
77
|
console.error(err)
|
|
65
78
|
|
|
66
79
|
return toast.push({
|
|
67
80
|
title: `Failed to remove assignee`,
|
|
68
|
-
description:
|
|
81
|
+
description: documentId,
|
|
69
82
|
status: 'error',
|
|
70
83
|
})
|
|
71
84
|
})
|
|
72
85
|
},
|
|
73
|
-
[client, toast]
|
|
86
|
+
[client, toast, documentId, userList]
|
|
74
87
|
)
|
|
75
88
|
|
|
76
|
-
const clearAssignees = React.useCallback(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
const clearAssignees = React.useCallback(() => {
|
|
90
|
+
return client
|
|
91
|
+
.patch(`workflow-metadata.${documentId}`)
|
|
92
|
+
.unset([`assignees`])
|
|
93
|
+
.commit()
|
|
94
|
+
.then(() => {
|
|
95
|
+
return toast.push({
|
|
96
|
+
title: `Cleared assignees`,
|
|
97
|
+
status: 'success',
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
.catch((err) => {
|
|
101
|
+
console.error(err)
|
|
85
102
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
})
|
|
103
|
+
return toast.push({
|
|
104
|
+
title: `Failed to clear assignees`,
|
|
105
|
+
description: documentId,
|
|
106
|
+
status: 'error',
|
|
91
107
|
})
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
108
|
+
})
|
|
109
|
+
}, [client, toast, documentId])
|
|
95
110
|
|
|
96
111
|
return (
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
userList={userList}
|
|
106
|
-
onAdd={addAssignee}
|
|
107
|
-
onClear={clearAssignees}
|
|
108
|
-
onRemove={removeAssignee}
|
|
109
|
-
open={openId === documentId}
|
|
110
|
-
/>
|
|
111
|
-
}
|
|
112
|
-
portal
|
|
113
|
-
open={openId === documentId}
|
|
114
|
-
>
|
|
115
|
-
{!assignees || assignees.length === 0 ? (
|
|
116
|
-
<Button
|
|
117
|
-
onClick={() => setOpenId(documentId)}
|
|
118
|
-
fontSize={1}
|
|
119
|
-
padding={2}
|
|
120
|
-
tabIndex={-1}
|
|
121
|
-
icon={AddIcon}
|
|
122
|
-
text="Assign"
|
|
123
|
-
tone="positive"
|
|
124
|
-
/>
|
|
125
|
-
) : (
|
|
126
|
-
<Button
|
|
127
|
-
onClick={() => setOpenId(documentId)}
|
|
128
|
-
padding={0}
|
|
129
|
-
mode="bleed"
|
|
130
|
-
style={{width: `100%`}}
|
|
131
|
-
>
|
|
132
|
-
<AvatarGroup
|
|
133
|
-
users={userList.filter((u) => assignees.includes(u.id))}
|
|
134
|
-
/>
|
|
135
|
-
</Button>
|
|
136
|
-
)}
|
|
137
|
-
</Popover>
|
|
112
|
+
<UserSelectMenu
|
|
113
|
+
style={{maxHeight: 300}}
|
|
114
|
+
value={assignees || []}
|
|
115
|
+
userList={userList}
|
|
116
|
+
onAdd={addAssignee}
|
|
117
|
+
onClear={clearAssignees}
|
|
118
|
+
onRemove={removeAssignee}
|
|
119
|
+
/>
|
|
138
120
|
)
|
|
139
121
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Card} from '@sanity/ui'
|
|
2
|
+
import {FunctionComponent} from 'react'
|
|
3
|
+
import {ArraySchemaType, ArrayOfPrimitivesInputProps, useFormValue} from 'sanity'
|
|
4
|
+
import {useProjectUsers} from 'sanity-plugin-utils'
|
|
5
|
+
|
|
6
|
+
import {API_VERSION} from '../constants'
|
|
7
|
+
import UserAssignment from './UserAssignment'
|
|
8
|
+
|
|
9
|
+
const UserAssignmentInput: FunctionComponent<
|
|
10
|
+
ArrayOfPrimitivesInputProps<string | number | boolean, ArraySchemaType>
|
|
11
|
+
> = (props) => {
|
|
12
|
+
const documentId = useFormValue([`documentId`])
|
|
13
|
+
const userList = useProjectUsers({apiVersion: API_VERSION})
|
|
14
|
+
|
|
15
|
+
const stringValue =
|
|
16
|
+
Array.isArray(props?.value) && props?.value?.length
|
|
17
|
+
? props.value.map((item) => String(item))
|
|
18
|
+
: []
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Card border padding={1}>
|
|
22
|
+
<UserAssignment userList={userList} assignees={stringValue} documentId={String(documentId)} />
|
|
23
|
+
</Card>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default UserAssignmentInput
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {Button, Grid, Popover, useClickOutside} from '@sanity/ui'
|
|
3
|
+
import {AddIcon} from '@sanity/icons'
|
|
4
|
+
|
|
5
|
+
import AvatarGroup from './DocumentCard/AvatarGroup'
|
|
6
|
+
import {User} from '../types'
|
|
7
|
+
import UserAssignment from './UserAssignment'
|
|
8
|
+
|
|
9
|
+
type UserDisplayProps = {
|
|
10
|
+
userList: User[]
|
|
11
|
+
assignees: string[]
|
|
12
|
+
documentId: string
|
|
13
|
+
disabled?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function UserDisplay(props: UserDisplayProps) {
|
|
17
|
+
const {assignees, userList, documentId, disabled = false} = props
|
|
18
|
+
|
|
19
|
+
const [button] = React.useState(null)
|
|
20
|
+
const [popover, setPopover] = React.useState(null)
|
|
21
|
+
const [isOpen, setIsOpen] = React.useState(false)
|
|
22
|
+
|
|
23
|
+
const close = React.useCallback(() => setIsOpen(false), [])
|
|
24
|
+
const open = React.useCallback(() => setIsOpen(true), [])
|
|
25
|
+
|
|
26
|
+
useClickOutside(close, [button, popover])
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Popover
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
ref={setPopover}
|
|
32
|
+
content={<UserAssignment userList={userList} assignees={assignees} documentId={documentId} />}
|
|
33
|
+
portal
|
|
34
|
+
open={isOpen}
|
|
35
|
+
>
|
|
36
|
+
{!assignees || assignees.length === 0 ? (
|
|
37
|
+
<Button
|
|
38
|
+
onClick={open}
|
|
39
|
+
fontSize={1}
|
|
40
|
+
padding={2}
|
|
41
|
+
tabIndex={-1}
|
|
42
|
+
icon={AddIcon}
|
|
43
|
+
text="Assign"
|
|
44
|
+
tone="positive"
|
|
45
|
+
mode="ghost"
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
/>
|
|
48
|
+
) : (
|
|
49
|
+
<Grid>
|
|
50
|
+
<Button onClick={open} padding={0} mode="bleed" disabled={disabled}>
|
|
51
|
+
<AvatarGroup users={userList.filter((u) => assignees.includes(u.id))} />
|
|
52
|
+
</Button>
|
|
53
|
+
</Grid>
|
|
54
|
+
)}
|
|
55
|
+
</Popover>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {useToast, Button} from '@sanity/ui'
|
|
3
|
+
import {useClient} from 'sanity'
|
|
4
|
+
import {UserExtended} from 'sanity-plugin-utils'
|
|
5
|
+
import {LexoRank} from 'lexorank'
|
|
6
|
+
|
|
7
|
+
import FloatingCard from './FloatingCard'
|
|
8
|
+
import {API_VERSION} from '../constants'
|
|
9
|
+
import {SanityDocumentWithMetadata, State} from '../types'
|
|
10
|
+
|
|
11
|
+
type ValidatorsProps = {
|
|
12
|
+
data: SanityDocumentWithMetadata[]
|
|
13
|
+
userList: UserExtended[]
|
|
14
|
+
states: State[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function Validators({data, userList, states}: ValidatorsProps) {
|
|
18
|
+
const client = useClient({apiVersion: API_VERSION})
|
|
19
|
+
const toast = useToast()
|
|
20
|
+
|
|
21
|
+
// A lot of error-checking
|
|
22
|
+
const documentsWithoutValidMetadataIds = data?.length
|
|
23
|
+
? data.reduce((acc, cur) => {
|
|
24
|
+
const {documentId, state} = cur._metadata ?? {}
|
|
25
|
+
const stateExists = states.find((s) => s.id === state)
|
|
26
|
+
|
|
27
|
+
return !stateExists && documentId ? [...acc, documentId] : acc
|
|
28
|
+
}, [] as string[])
|
|
29
|
+
: []
|
|
30
|
+
|
|
31
|
+
const documentsWithInvalidUserIds = data?.length
|
|
32
|
+
? data.reduce((acc, cur) => {
|
|
33
|
+
const {documentId, assignees} = cur._metadata ?? {}
|
|
34
|
+
const allAssigneesExist = assignees?.length
|
|
35
|
+
? assignees?.every((a) => userList.find((u) => u.id === a))
|
|
36
|
+
: true
|
|
37
|
+
|
|
38
|
+
return !allAssigneesExist && documentId ? [...acc, documentId] : acc
|
|
39
|
+
}, [] as string[])
|
|
40
|
+
: []
|
|
41
|
+
|
|
42
|
+
const documentsWithoutOrderIds = data?.length
|
|
43
|
+
? data.reduce((acc, cur) => {
|
|
44
|
+
const {documentId, orderRank} = cur._metadata ?? {}
|
|
45
|
+
|
|
46
|
+
return !orderRank && documentId ? [...acc, documentId] : acc
|
|
47
|
+
}, [] as string[])
|
|
48
|
+
: []
|
|
49
|
+
|
|
50
|
+
// Updates metadata documents to a valid, existing state
|
|
51
|
+
const correctDocuments = React.useCallback(
|
|
52
|
+
async (ids: string[]) => {
|
|
53
|
+
toast.push({
|
|
54
|
+
title: 'Correcting...',
|
|
55
|
+
status: 'info',
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const tx = ids.reduce((item, documentId) => {
|
|
59
|
+
return item.patch(`workflow-metadata.${documentId}`, {
|
|
60
|
+
set: {state: states[0].id},
|
|
61
|
+
})
|
|
62
|
+
}, client.transaction())
|
|
63
|
+
|
|
64
|
+
await tx.commit()
|
|
65
|
+
|
|
66
|
+
toast.push({
|
|
67
|
+
title: `Corrected ${
|
|
68
|
+
ids.length === 1 ? `1 Document` : `${ids.length} Documents`
|
|
69
|
+
}`,
|
|
70
|
+
status: 'success',
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
[client, states, toast]
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
// Remove users that are no longer in the project from documents
|
|
77
|
+
const removeUsersFromDocuments = React.useCallback(
|
|
78
|
+
async (ids: string[]) => {
|
|
79
|
+
toast.push({
|
|
80
|
+
title: 'Removing users...',
|
|
81
|
+
status: 'info',
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const tx = ids.reduce((item, documentId) => {
|
|
85
|
+
const {assignees} =
|
|
86
|
+
data.find((d) => d._id === documentId)?._metadata ?? {}
|
|
87
|
+
const validAssignees = assignees?.length
|
|
88
|
+
? // eslint-disable-next-line max-nested-callbacks
|
|
89
|
+
assignees.filter((a) => userList.find((u) => u.id === a)?.id)
|
|
90
|
+
: []
|
|
91
|
+
|
|
92
|
+
return item.patch(`workflow-metadata.${documentId}`, {
|
|
93
|
+
set: {assignees: validAssignees},
|
|
94
|
+
})
|
|
95
|
+
}, client.transaction())
|
|
96
|
+
|
|
97
|
+
await tx.commit()
|
|
98
|
+
|
|
99
|
+
toast.push({
|
|
100
|
+
title: `Corrected ${
|
|
101
|
+
ids.length === 1 ? `1 Document` : `${ids.length} Documents`
|
|
102
|
+
}`,
|
|
103
|
+
status: 'success',
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
[client, data, toast, userList]
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
// Add order value to metadata documents
|
|
110
|
+
const addOrderToDocuments = React.useCallback(
|
|
111
|
+
async (ids: string[]) => {
|
|
112
|
+
toast.push({
|
|
113
|
+
title: 'Adding ordering...',
|
|
114
|
+
status: 'info',
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Get first order value
|
|
118
|
+
const firstOrder = data[0]?._metadata?.orderRank
|
|
119
|
+
let newLexo =
|
|
120
|
+
firstOrder && data.length !== ids.length
|
|
121
|
+
? LexoRank.parse(firstOrder)
|
|
122
|
+
: LexoRank.min()
|
|
123
|
+
|
|
124
|
+
const tx = client.transaction()
|
|
125
|
+
|
|
126
|
+
for (let index = 0; index < ids.length; index += 1) {
|
|
127
|
+
newLexo = newLexo.genNext().genNext()
|
|
128
|
+
|
|
129
|
+
tx.patch(`workflow-metadata.${ids[index]}`, {
|
|
130
|
+
set: {orderRank: newLexo.toString()},
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await tx.commit()
|
|
135
|
+
|
|
136
|
+
toast.push({
|
|
137
|
+
title: `Added order to ${
|
|
138
|
+
ids.length === 1 ? `1 Document` : `${ids.length} Documents`
|
|
139
|
+
}`,
|
|
140
|
+
status: 'success',
|
|
141
|
+
})
|
|
142
|
+
},
|
|
143
|
+
[data, client, toast]
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<FloatingCard>
|
|
148
|
+
{documentsWithoutValidMetadataIds.length > 0 ? (
|
|
149
|
+
<Button
|
|
150
|
+
tone="caution"
|
|
151
|
+
onClick={() => correctDocuments(documentsWithoutValidMetadataIds)}
|
|
152
|
+
text={
|
|
153
|
+
documentsWithoutValidMetadataIds.length === 1
|
|
154
|
+
? `Correct 1 Document State`
|
|
155
|
+
: `Correct ${documentsWithoutValidMetadataIds.length} Document States`
|
|
156
|
+
}
|
|
157
|
+
/>
|
|
158
|
+
) : null}
|
|
159
|
+
{documentsWithInvalidUserIds.length > 0 ? (
|
|
160
|
+
<Button
|
|
161
|
+
tone="caution"
|
|
162
|
+
onClick={() => removeUsersFromDocuments(documentsWithInvalidUserIds)}
|
|
163
|
+
text={
|
|
164
|
+
documentsWithInvalidUserIds.length === 1
|
|
165
|
+
? `Remove Invalid Users from 1 Document`
|
|
166
|
+
: `Remove Invalid Users from ${documentsWithInvalidUserIds.length} Documents`
|
|
167
|
+
}
|
|
168
|
+
/>
|
|
169
|
+
) : null}
|
|
170
|
+
{documentsWithoutOrderIds.length > 0 ? (
|
|
171
|
+
<Button
|
|
172
|
+
tone="caution"
|
|
173
|
+
onClick={() => addOrderToDocuments(documentsWithoutOrderIds)}
|
|
174
|
+
text={
|
|
175
|
+
documentsWithoutOrderIds.length === 1
|
|
176
|
+
? `Set Order for 1 Document`
|
|
177
|
+
: `Set Order for ${documentsWithoutOrderIds.length} Documents`
|
|
178
|
+
}
|
|
179
|
+
/>
|
|
180
|
+
) : null}
|
|
181
|
+
{/* <Button
|
|
182
|
+
tone="caution"
|
|
183
|
+
onClick={() =>
|
|
184
|
+
addOrderToDocuments(
|
|
185
|
+
data.map((doc) => String(doc._metadata?.documentId))
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
text={
|
|
189
|
+
data.length === 1
|
|
190
|
+
? `Reset Order for 1 Document`
|
|
191
|
+
: `Reset Order for all ${data.length} Documents`
|
|
192
|
+
}
|
|
193
|
+
/> */}
|
|
194
|
+
</FloatingCard>
|
|
195
|
+
)
|
|
196
|
+
}
|