sanity-plugin-workflow 1.0.0-beta.7 → 1.0.0-beta.8
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/lib/index.esm.js +82 -15
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +82 -15
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/DocumentList.tsx +2 -1
- package/src/components/Verify.tsx +76 -44
- package/src/helpers/generateMultipleOrderRanks.ts +80 -0
- package/src/hooks/useWorkflowDocuments.tsx +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-workflow",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.8",
|
|
4
4
|
"description": "A demonstration of a custom content publishing workflow using Sanity.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"rimraf": "^4.1.2",
|
|
88
88
|
"sanity": "^3.3.1",
|
|
89
89
|
"semantic-release": "^20.1.0",
|
|
90
|
-
"typescript": "^
|
|
90
|
+
"typescript": "^5.0.0"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
93
|
"@sanity/ui": "^1.2.2",
|
|
@@ -94,7 +94,8 @@ export default function DocumentList(props: DocumentListProps) {
|
|
|
94
94
|
return (
|
|
95
95
|
<Draggable
|
|
96
96
|
// The metadata's documentId is always the published one to avoid rerendering
|
|
97
|
-
key={documentId}
|
|
97
|
+
// key={documentId}
|
|
98
|
+
key={virtualItem.key}
|
|
98
99
|
draggableId={documentId}
|
|
99
100
|
index={virtualItem.index}
|
|
100
101
|
isDragDisabled={isDragDisabled}
|
|
@@ -5,6 +5,7 @@ import {useClient} from 'sanity'
|
|
|
5
5
|
import {UserExtended} from 'sanity-plugin-utils'
|
|
6
6
|
|
|
7
7
|
import {API_VERSION} from '../constants'
|
|
8
|
+
import {generateMultipleOrderRanks} from '../helpers/generateMultipleOrderRanks'
|
|
8
9
|
import {SanityDocumentWithMetadata, State} from '../types'
|
|
9
10
|
import FloatingCard from './FloatingCard'
|
|
10
11
|
|
|
@@ -32,16 +33,17 @@ export default function Verify(props: VerifyProps) {
|
|
|
32
33
|
}, [] as string[])
|
|
33
34
|
: []
|
|
34
35
|
|
|
35
|
-
const documentsWithInvalidUserIds =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const documentsWithInvalidUserIds =
|
|
37
|
+
data?.length && userList?.length
|
|
38
|
+
? data.reduce((acc, cur) => {
|
|
39
|
+
const {documentId, assignees} = cur._metadata ?? {}
|
|
40
|
+
const allAssigneesExist = assignees?.length
|
|
41
|
+
? assignees?.every((a) => userList.find((u) => u.id === a))
|
|
42
|
+
: true
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
return !allAssigneesExist && documentId ? [...acc, documentId] : acc
|
|
45
|
+
}, [] as string[])
|
|
46
|
+
: []
|
|
45
47
|
|
|
46
48
|
const documentsWithoutOrderIds = data?.length
|
|
47
49
|
? data.reduce((acc, cur) => {
|
|
@@ -130,29 +132,51 @@ export default function Verify(props: VerifyProps) {
|
|
|
130
132
|
status: 'info',
|
|
131
133
|
})
|
|
132
134
|
|
|
133
|
-
// Get first and second order values
|
|
135
|
+
// Get first and second order values, if they exist
|
|
134
136
|
const [firstOrder, secondOrder] = [...data]
|
|
135
137
|
.slice(0, 2)
|
|
136
138
|
.map((d) => d._metadata?.orderRank)
|
|
137
|
-
const minLexo =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
: LexoRank.min()
|
|
141
|
-
const maxLexo =
|
|
142
|
-
secondOrder && data.length !== ids.length
|
|
143
|
-
? LexoRank.parse(secondOrder)
|
|
144
|
-
: LexoRank.max()
|
|
145
|
-
let newLexo = minLexo.between(maxLexo)
|
|
146
|
-
const lastLexo = maxLexo
|
|
139
|
+
const minLexo = firstOrder ? LexoRank.parse(firstOrder) : undefined
|
|
140
|
+
const maxLexo = secondOrder ? LexoRank.parse(secondOrder) : undefined
|
|
141
|
+
const ranks = generateMultipleOrderRanks(ids.length, minLexo, maxLexo)
|
|
147
142
|
|
|
148
143
|
const tx = client.transaction()
|
|
149
144
|
|
|
150
145
|
// Create a new in-between value for each document
|
|
151
146
|
for (let index = 0; index < ids.length; index += 1) {
|
|
152
|
-
|
|
147
|
+
tx.patch(`workflow-metadata.${ids[index]}`, {
|
|
148
|
+
set: {orderRank: ranks[index].toString()},
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await tx.commit()
|
|
153
153
|
|
|
154
|
+
toast.push({
|
|
155
|
+
title: `Added order to ${
|
|
156
|
+
ids.length === 1 ? `1 Document` : `${ids.length} Documents`
|
|
157
|
+
}`,
|
|
158
|
+
status: 'success',
|
|
159
|
+
})
|
|
160
|
+
},
|
|
161
|
+
[data, client, toast]
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
// Reset order value on all metadata documents
|
|
165
|
+
const resetOrderOfAllDocuments = React.useCallback(
|
|
166
|
+
async (ids: string[]) => {
|
|
167
|
+
toast.push({
|
|
168
|
+
title: 'Adding ordering...',
|
|
169
|
+
status: 'info',
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const ranks = generateMultipleOrderRanks(ids.length)
|
|
173
|
+
|
|
174
|
+
const tx = client.transaction()
|
|
175
|
+
|
|
176
|
+
// Create a new in-between value for each document
|
|
177
|
+
for (let index = 0; index < ids.length; index += 1) {
|
|
154
178
|
tx.patch(`workflow-metadata.${ids[index]}`, {
|
|
155
|
-
set: {orderRank:
|
|
179
|
+
set: {orderRank: ranks[index].toString()},
|
|
156
180
|
})
|
|
157
181
|
}
|
|
158
182
|
|
|
@@ -199,6 +223,7 @@ export default function Verify(props: VerifyProps) {
|
|
|
199
223
|
{documentsWithoutValidMetadataIds.length > 0 ? (
|
|
200
224
|
<Button
|
|
201
225
|
tone="caution"
|
|
226
|
+
mode="ghost"
|
|
202
227
|
onClick={() => correctDocuments(documentsWithoutValidMetadataIds)}
|
|
203
228
|
text={
|
|
204
229
|
documentsWithoutValidMetadataIds.length === 1
|
|
@@ -210,6 +235,7 @@ export default function Verify(props: VerifyProps) {
|
|
|
210
235
|
{documentsWithInvalidUserIds.length > 0 ? (
|
|
211
236
|
<Button
|
|
212
237
|
tone="caution"
|
|
238
|
+
mode="ghost"
|
|
213
239
|
onClick={() => removeUsersFromDocuments(documentsWithInvalidUserIds)}
|
|
214
240
|
text={
|
|
215
241
|
documentsWithInvalidUserIds.length === 1
|
|
@@ -221,6 +247,7 @@ export default function Verify(props: VerifyProps) {
|
|
|
221
247
|
{documentsWithoutOrderIds.length > 0 ? (
|
|
222
248
|
<Button
|
|
223
249
|
tone="caution"
|
|
250
|
+
mode="ghost"
|
|
224
251
|
onClick={() => addOrderToDocuments(documentsWithoutOrderIds)}
|
|
225
252
|
text={
|
|
226
253
|
documentsWithoutOrderIds.length === 1
|
|
@@ -230,36 +257,41 @@ export default function Verify(props: VerifyProps) {
|
|
|
230
257
|
/>
|
|
231
258
|
) : null}
|
|
232
259
|
{documentsWithDuplicatedOrderIds.length > 0 ? (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
260
|
+
<>
|
|
261
|
+
<Button
|
|
262
|
+
tone="caution"
|
|
263
|
+
mode="ghost"
|
|
264
|
+
onClick={() => addOrderToDocuments(documentsWithDuplicatedOrderIds)}
|
|
265
|
+
text={
|
|
266
|
+
documentsWithDuplicatedOrderIds.length === 1
|
|
267
|
+
? `Set Unique Order for 1 Document`
|
|
268
|
+
: `Set Unique Order for ${documentsWithDuplicatedOrderIds.length} Documents`
|
|
269
|
+
}
|
|
270
|
+
/>
|
|
271
|
+
<Button
|
|
272
|
+
tone="caution"
|
|
273
|
+
mode="ghost"
|
|
274
|
+
onClick={() =>
|
|
275
|
+
resetOrderOfAllDocuments(
|
|
276
|
+
data.map((doc) => String(doc._metadata?.documentId))
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
text={
|
|
280
|
+
data.length === 1
|
|
281
|
+
? `Reset Order for 1 Document`
|
|
282
|
+
: `Reset Order for all ${data.length} Documents`
|
|
283
|
+
}
|
|
284
|
+
/>
|
|
285
|
+
</>
|
|
242
286
|
) : null}
|
|
243
287
|
{orphanedMetadataDocumentIds.length > 0 ? (
|
|
244
288
|
<Button
|
|
245
289
|
text="Cleanup orphaned metadata"
|
|
246
290
|
onClick={handleOrphans}
|
|
247
291
|
tone="caution"
|
|
292
|
+
mode="ghost"
|
|
248
293
|
/>
|
|
249
294
|
) : null}
|
|
250
|
-
{/* <Button
|
|
251
|
-
tone="caution"
|
|
252
|
-
onClick={() =>
|
|
253
|
-
addOrderToDocuments(
|
|
254
|
-
data.map((doc) => String(doc._metadata?.documentId))
|
|
255
|
-
)
|
|
256
|
-
}
|
|
257
|
-
text={
|
|
258
|
-
data.length === 1
|
|
259
|
-
? `Reset Order for 1 Document`
|
|
260
|
-
: `Reset Order for all ${data.length} Documents`
|
|
261
|
-
}
|
|
262
|
-
/> */}
|
|
263
295
|
</FloatingCard>
|
|
264
296
|
)
|
|
265
297
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {LexoRank} from 'lexorank'
|
|
2
|
+
|
|
3
|
+
function generateMiddleValue(ranks: (LexoRank | undefined)[]) {
|
|
4
|
+
// Has no undefined values
|
|
5
|
+
if (!ranks.some((rank) => !rank)) {
|
|
6
|
+
return ranks
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Find the first undefined value
|
|
10
|
+
const firstUndefined = ranks.findIndex((rank) => !rank)
|
|
11
|
+
|
|
12
|
+
// Find the first defined value after the undefined value
|
|
13
|
+
const firstDefinedAfter = ranks.findIndex(
|
|
14
|
+
(rank, index) => rank && index > firstUndefined
|
|
15
|
+
)
|
|
16
|
+
// Find the first defined value before the undefined value
|
|
17
|
+
const firstDefinedBefore = ranks.findLastIndex(
|
|
18
|
+
(rank, index) => rank && index < firstUndefined
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if (firstDefinedAfter === -1 || firstDefinedBefore === -1) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Unable to generate middle value between indexes ${firstDefinedBefore} and ${firstDefinedAfter}`
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const beforeRank = ranks[firstDefinedBefore]
|
|
28
|
+
const afterRank = ranks[firstDefinedAfter]
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
!beforeRank ||
|
|
32
|
+
typeof beforeRank === 'undefined' ||
|
|
33
|
+
!afterRank ||
|
|
34
|
+
typeof afterRank === 'undefined'
|
|
35
|
+
) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Unable to generate middle value between indexes ${firstDefinedBefore} and ${firstDefinedAfter}`
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Generate a new value between the two
|
|
42
|
+
const between = beforeRank.between(afterRank)
|
|
43
|
+
|
|
44
|
+
// Calculate the middle index between the defined values
|
|
45
|
+
const middle = Math.floor((firstDefinedAfter + firstDefinedBefore) / 2)
|
|
46
|
+
|
|
47
|
+
if (ranks[middle]) {
|
|
48
|
+
throw new Error(`Should not have overwritten value at index ${middle}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Insert the new value into the array
|
|
52
|
+
ranks[middle] = between
|
|
53
|
+
|
|
54
|
+
// Return as a new array
|
|
55
|
+
return ranks
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Generates an array of LexoRanks between two values
|
|
59
|
+
export function generateMultipleOrderRanks(
|
|
60
|
+
count: number,
|
|
61
|
+
start?: LexoRank,
|
|
62
|
+
end?: LexoRank
|
|
63
|
+
): LexoRank[] {
|
|
64
|
+
// Begin array with correct size
|
|
65
|
+
let ranks = [...Array(count)]
|
|
66
|
+
|
|
67
|
+
// Use or create default values
|
|
68
|
+
const rankStart = start ?? LexoRank.min().genNext().genNext()
|
|
69
|
+
const rankEnd = end ?? LexoRank.max().genPrev().genPrev()
|
|
70
|
+
|
|
71
|
+
ranks[0] = rankStart
|
|
72
|
+
ranks[count - 1] = rankEnd
|
|
73
|
+
|
|
74
|
+
// Keep processing the array until every value between undefined values is defined
|
|
75
|
+
for (let i = 0; i < count; i++) {
|
|
76
|
+
ranks = generateMiddleValue(ranks)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return ranks.sort((a, b) => a.toString().localeCompare(b.toString()))
|
|
80
|
+
}
|
|
@@ -131,7 +131,10 @@ export function useWorkflowDocuments(schemaTypes: string[]): WorkflowDocuments {
|
|
|
131
131
|
.commit()
|
|
132
132
|
.then((res) => {
|
|
133
133
|
toast.push({
|
|
134
|
-
title:
|
|
134
|
+
title:
|
|
135
|
+
newState.id === document._metadata.state
|
|
136
|
+
? `Reordered in "${newState?.title ?? newStateId}"`
|
|
137
|
+
: `Moved to "${newState?.title ?? newStateId}"`,
|
|
135
138
|
status: 'success',
|
|
136
139
|
})
|
|
137
140
|
return res
|