sanity-plugin-workflow 1.0.0-beta.5 → 1.0.0-beta.7

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 CHANGED
@@ -12,6 +12,8 @@ With Sanity Studio you can [customize your content tools to support arbitrary wo
12
12
 
13
13
  This plugin is distributed as a **reference implementation** of these customization APIs and is not considered to be a feature-complete implementation of what workflow management requires in production. It is a starting point intended to be forked and customized to the needs of your organization and content creators.
14
14
 
15
+ A key intention of this plugin is that it **does not influence or modify whether a document is in draft or published**. It only tracks the values of a separate "metadata" document. In this implementation, an "Approved" document could be a draft but will still need publishing. "Approving" the document simply removes it from the Workflow process. You will decide if Publishing the document happens in the Studio like normal, using the [Scheduled Publishing plugin](https://www.sanity.io/plugins/scheduled-publishing) or the [Scheduling API](https://www.sanity.io/docs/scheduling-api#fa3bb95f83ed).
16
+
15
17
  ![Screenshot 2023-03-21 at 12 11 24](https://user-images.githubusercontent.com/9684022/226602179-5bd3d91a-9c27-431e-be18-3c70f06c6ccb.png)
16
18
 
17
19
  ## Features
@@ -51,7 +53,7 @@ Add it as a plugin in sanity.config.ts (or .js):
51
53
  // schemaTypes: ['article', 'product'],
52
54
  schemaTypes: [],
53
55
  // Optional, see below
54
- states: [],
56
+ // states: [],
55
57
  })
56
58
  ]
57
59
  })
@@ -101,10 +103,12 @@ Once the Workflow is complete, the metadata can be removed by using the "Complet
101
103
 
102
104
  This plugin is largely based on the original Workflow Demo built into a Sanity Studio v2 project. The major differences are:
103
105
 
104
- * This plugin can be more easily installed and configured, not just code examples built into a Studio project
105
- * Documents must "opt-in" to and removed from the Workflow, in the previous version all documents were in the workflow which would fill up the interface
106
- * User Roles and Assignments can affect the Workflow. Set rules to enforce which States documents can move between and if being assigned to a document is required to move it to a new State
107
- * Ability to filter Schema types and assigned Users
106
+ * This plugin is not concerned with nor will modify whether a document is in draft or published.
107
+ * This plugin can be more easily installed and configured, not just code examples built into a Studio project.
108
+ * Documents must "opt-in" to and be removed from the Workflow. In the previous version, all documents were in the workflow which would fill up the interface and negatively affect performance.
109
+ * Document validation status can be used as a way to prevent movement through the workflow.
110
+ * User Roles and Assignments can affect the Workflow. Set rules to enforce which States documents can move between and if being assigned to a document is required to move it to a new State.
111
+ * This plugin can filter Schema types and assigned Users.
108
112
 
109
113
  ## License
110
114
 
package/lib/index.esm.js CHANGED
@@ -633,7 +633,7 @@ function useWorkflowDocuments(schemaTypes) {
633
633
  setLocalDocuments(data);
634
634
  }
635
635
  }, [data]);
636
- const move = React.useCallback((draggedId, destination, states, newOrder) => {
636
+ const move = React.useCallback(async (draggedId, destination, states, newOrder) => {
637
637
  const currentLocalData = localDocuments;
638
638
  const newLocalDocuments = localDocuments.map(item => {
639
639
  var _a;
@@ -680,25 +680,28 @@ function useWorkflowDocuments(schemaTypes) {
680
680
  _type
681
681
  } = document;
682
682
  const {
683
- _rev,
684
- documentId
683
+ documentId,
684
+ _rev
685
685
  } = document._metadata || {};
686
- client.patch("workflow-metadata.".concat(documentId)).ifRevisionId(_rev).set({
686
+ await client.patch("workflow-metadata.".concat(documentId)).ifRevisionId(_rev).set({
687
687
  state: newStateId,
688
688
  orderRank: newOrder
689
- }).commit().then(() => {
689
+ }).commit().then(res => {
690
690
  var _a;
691
- return toast.push({
691
+ toast.push({
692
692
  title: "Moved to \"".concat((_a = newState == null ? void 0 : newState.title) != null ? _a : newStateId, "\""),
693
693
  status: "success"
694
694
  });
695
- }).catch(() => {
695
+ return res;
696
+ }).catch(err => {
696
697
  var _a;
697
698
  setLocalDocuments(currentLocalData);
698
- return toast.push({
699
+ toast.push({
699
700
  title: "Failed to move to \"".concat((_a = newState == null ? void 0 : newState.title) != null ? _a : newStateId, "\""),
701
+ description: err.message,
700
702
  status: "error"
701
703
  });
704
+ return null;
702
705
  });
703
706
  return {
704
707
  _id,
@@ -812,31 +815,44 @@ function CompleteButton(props) {
812
815
  apiVersion: API_VERSION
813
816
  });
814
817
  const toast = useToast();
815
- const handleComplete = React.useCallback(id => {
818
+ const handleComplete = React.useCallback(event => {
819
+ const id = event.currentTarget.value;
820
+ if (!id) {
821
+ return;
822
+ }
816
823
  client.delete("workflow-metadata.".concat(id)).then(() => {
817
824
  toast.push({
818
825
  status: "success",
819
- title: "Workflow completed",
820
- description: id
826
+ title: "Workflow completed"
821
827
  });
822
828
  }).catch(() => {
823
829
  toast.push({
824
830
  status: "error",
825
- title: "Could not complete Workflow",
826
- description: id
831
+ title: "Could not complete Workflow"
827
832
  });
828
833
  });
829
834
  }, [client, toast]);
830
- return /* @__PURE__ */jsx(Button, {
831
- onClick: () => handleComplete(documentId),
832
- text: "Complete",
833
- icon: CheckmarkIcon,
834
- tone: "positive",
835
- mode: "ghost",
836
- fontSize: 1,
837
- padding: 2,
838
- tabIndex: -1,
839
- disabled
835
+ return /* @__PURE__ */jsx(Tooltip, {
836
+ portal: true,
837
+ content: /* @__PURE__ */jsx(Box, {
838
+ padding: 2,
839
+ children: /* @__PURE__ */jsx(Text, {
840
+ size: 1,
841
+ children: "Remove this document from Workflow"
842
+ })
843
+ }),
844
+ children: /* @__PURE__ */jsx(Button, {
845
+ value: documentId,
846
+ onClick: handleComplete,
847
+ text: "Complete",
848
+ icon: CheckmarkIcon,
849
+ tone: "positive",
850
+ mode: "ghost",
851
+ fontSize: 1,
852
+ padding: 2,
853
+ tabIndex: -1,
854
+ disabled
855
+ })
840
856
  });
841
857
  }
842
858
  function TimeAgo(_ref2) {
@@ -953,6 +969,7 @@ function DocumentCard(props) {
953
969
  var _a, _b;
954
970
  const {
955
971
  isDragDisabled,
972
+ isPatching,
956
973
  userRoleCanDrop,
957
974
  isDragging,
958
975
  item,
@@ -986,6 +1003,7 @@ function DocumentCard(props) {
986
1003
  let tone = defaultCardTone;
987
1004
  if (!userRoleCanDrop) return isDarkMode ? "default" : "transparent";
988
1005
  if (!documentId) return tone;
1006
+ if (isPatching) tone = isDarkMode ? "default" : "transparent";
989
1007
  if (isDragging) tone = "positive";
990
1008
  if ((state == null ? void 0 : state.requireValidation) && !isValidating && validation.length > 0) {
991
1009
  if (validation.some(v => v.level === "error")) {
@@ -995,7 +1013,7 @@ function DocumentCard(props) {
995
1013
  }
996
1014
  }
997
1015
  return tone;
998
- }, [defaultCardTone, userRoleCanDrop, isDarkMode, documentId, isDragging, isValidating, validation, state == null ? void 0 : state.requireValidation]);
1016
+ }, [defaultCardTone, userRoleCanDrop, isPatching, isDarkMode, documentId, isDragging, isValidating, validation, state == null ? void 0 : state.requireValidation]);
999
1017
  useEffect(() => {
1000
1018
  if (!isValidating && validation.length > 0) {
1001
1019
  if (validation.some(v => v.level === "error")) {
@@ -1041,7 +1059,7 @@ function DocumentCard(props) {
1041
1059
  children: [/* @__PURE__ */jsx(Box, {
1042
1060
  flex: 1,
1043
1061
  children: /* @__PURE__ */jsx(Preview, {
1044
- layout: "default",
1062
+ layout: "block",
1045
1063
  value: item,
1046
1064
  schemaType: schema.get(item._type)
1047
1065
  })
@@ -1049,14 +1067,14 @@ function DocumentCard(props) {
1049
1067
  style: {
1050
1068
  flexShrink: 0
1051
1069
  },
1052
- children: hasError || isDragDisabled ? null : /* @__PURE__ */jsx(DragHandleIcon, {})
1070
+ children: hasError || isDragDisabled || isPatching ? null : /* @__PURE__ */jsx(DragHandleIcon, {})
1053
1071
  })]
1054
1072
  })
1055
- }), /* @__PURE__ */jsx(Card, {
1073
+ }), /* @__PURE__ */jsxs(Card, {
1056
1074
  padding: 2,
1057
1075
  radius: 2,
1058
1076
  tone: "inherit",
1059
- children: /* @__PURE__ */jsxs(Flex, {
1077
+ children: [/* @__PURE__ */jsxs(Flex, {
1060
1078
  align: "center",
1061
1079
  justify: "space-between",
1062
1080
  gap: 3,
@@ -1078,11 +1096,17 @@ function DocumentCard(props) {
1078
1096
  id: item._id,
1079
1097
  type: item._type,
1080
1098
  disabled: !userRoleCanDrop
1081
- }), isLastState ? /* @__PURE__ */jsx(CompleteButton, {
1099
+ }), isLastState && states.length <= 3 ? /* @__PURE__ */jsx(CompleteButton, {
1082
1100
  documentId,
1083
1101
  disabled: !userRoleCanDrop
1084
1102
  }) : null]
1085
- })
1103
+ }), isLastState && states.length > 3 ? /* @__PURE__ */jsx(Stack, {
1104
+ paddingTop: 2,
1105
+ children: /* @__PURE__ */jsx(CompleteButton, {
1106
+ documentId,
1107
+ disabled: !userRoleCanDrop
1108
+ })
1109
+ }) : null]
1086
1110
  })]
1087
1111
  })
1088
1112
  })
@@ -1093,6 +1117,7 @@ function DocumentList(props) {
1093
1117
  const {
1094
1118
  data = [],
1095
1119
  invalidDocumentIds,
1120
+ patchingIds,
1096
1121
  selectedSchemaTypes,
1097
1122
  selectedUserIds,
1098
1123
  state,
@@ -1114,7 +1139,7 @@ function DocumentList(props) {
1114
1139
  return (_c = (_b = (_a = dataFiltered[index]) == null ? void 0 : _a._metadata) == null ? void 0 : _b.documentId) != null ? _c : index;
1115
1140
  },
1116
1141
  estimateSize: () => 113,
1117
- overscan: 5
1142
+ overscan: 10
1118
1143
  });
1119
1144
  if (!data.length) {
1120
1145
  return null;
@@ -1141,7 +1166,7 @@ function DocumentList(props) {
1141
1166
  }
1142
1167
  const isInvalid = invalidDocumentIds.includes(documentId);
1143
1168
  const meInAssignees = (user == null ? void 0 : user.id) ? assignees == null ? void 0 : assignees.includes(user.id) : false;
1144
- const isDragDisabled = !userRoleCanDrop || isInvalid || !(state.requireAssignment ? state.requireAssignment && meInAssignees : true);
1169
+ const isDragDisabled = patchingIds.includes(documentId) || !userRoleCanDrop || isInvalid || !(state.requireAssignment ? state.requireAssignment && meInAssignees : true);
1145
1170
  return /* @__PURE__ */jsx(Draggable, {
1146
1171
  draggableId: documentId,
1147
1172
  index: virtualItem.index,
@@ -1153,6 +1178,7 @@ function DocumentList(props) {
1153
1178
  children: /* @__PURE__ */jsx(DocumentCard, {
1154
1179
  userRoleCanDrop,
1155
1180
  isDragDisabled,
1181
+ isPatching: patchingIds.includes(documentId),
1156
1182
  isDragging: draggableSnapshot.isDragging,
1157
1183
  item,
1158
1184
  toggleInvalidDocumentId,
@@ -1278,7 +1304,7 @@ function Filters(props) {
1278
1304
  icon: ResetIcon
1279
1305
  }) : null]
1280
1306
  })
1281
- }), schemaTypes.length > 0 ? /* @__PURE__ */jsx(Flex, {
1307
+ }), schemaTypes.length > 1 ? /* @__PURE__ */jsx(Flex, {
1282
1308
  align: "center",
1283
1309
  gap: 1,
1284
1310
  children: schemaTypes.map(typeName => {
@@ -1326,7 +1352,8 @@ function StateTitle(props) {
1326
1352
  requireAssignment,
1327
1353
  userRoleCanDrop,
1328
1354
  isDropDisabled,
1329
- draggingFrom
1355
+ draggingFrom,
1356
+ documentCount
1330
1357
  } = props;
1331
1358
  let tone = "default";
1332
1359
  const isSource = draggingFrom === state.id;
@@ -1351,7 +1378,15 @@ function StateTitle(props) {
1351
1378
  }), requireAssignment ? /* @__PURE__ */jsx(Status, {
1352
1379
  text: "You must be assigned to the document to move documents to this State",
1353
1380
  icon: UserIcon
1354
- }) : null]
1381
+ }) : null, /* @__PURE__ */jsx(Box, {
1382
+ flex: 1,
1383
+ children: documentCount > 0 ? /* @__PURE__ */jsx(Text, {
1384
+ weight: "semibold",
1385
+ align: "right",
1386
+ size: 1,
1387
+ children: documentCount
1388
+ }) : null
1389
+ })]
1355
1390
  })
1356
1391
  });
1357
1392
  }
@@ -1421,6 +1456,17 @@ function Verify(props) {
1421
1456
  } = (_a = cur._metadata) != null ? _a : {};
1422
1457
  return !orderRank && documentId ? [...acc, documentId] : acc;
1423
1458
  }, []) : [];
1459
+ const documentsWithDuplicatedOrderIds = (data == null ? void 0 : data.length) ? data.reduce((acc, cur) => {
1460
+ var _a;
1461
+ const {
1462
+ documentId,
1463
+ orderRank
1464
+ } = (_a = cur._metadata) != null ? _a : {};
1465
+ return orderRank && data.filter(d => {
1466
+ var _a2;
1467
+ return ((_a2 = d._metadata) == null ? void 0 : _a2.orderRank) === orderRank;
1468
+ }).length > 1 && documentId ? [...acc, documentId] : acc;
1469
+ }, []) : [];
1424
1470
  const correctDocuments = React.useCallback(async ids => {
1425
1471
  toast.push({
1426
1472
  title: "Correcting...",
@@ -1468,16 +1514,21 @@ function Verify(props) {
1468
1514
  });
1469
1515
  }, [client, data, toast, userList]);
1470
1516
  const addOrderToDocuments = React.useCallback(async ids => {
1471
- var _a, _b;
1472
1517
  toast.push({
1473
1518
  title: "Adding ordering...",
1474
1519
  status: "info"
1475
1520
  });
1476
- const firstOrder = (_b = (_a = data[0]) == null ? void 0 : _a._metadata) == null ? void 0 : _b.orderRank;
1477
- let newLexo = firstOrder && data.length !== ids.length ? LexoRank.parse(firstOrder) : LexoRank.min();
1521
+ const [firstOrder, secondOrder] = [...data].slice(0, 2).map(d => {
1522
+ var _a;
1523
+ return (_a = d._metadata) == null ? void 0 : _a.orderRank;
1524
+ });
1525
+ const minLexo = firstOrder && data.length !== ids.length ? LexoRank.parse(firstOrder) : LexoRank.min();
1526
+ const maxLexo = secondOrder && data.length !== ids.length ? LexoRank.parse(secondOrder) : LexoRank.max();
1527
+ let newLexo = minLexo.between(maxLexo);
1528
+ const lastLexo = maxLexo;
1478
1529
  const tx = client.transaction();
1479
1530
  for (let index = 0; index < ids.length; index += 1) {
1480
- newLexo = newLexo.genNext().genNext();
1531
+ newLexo = newLexo.between(lastLexo);
1481
1532
  tx.patch("workflow-metadata.".concat(ids[index]), {
1482
1533
  set: {
1483
1534
  orderRank: newLexo.toString()
@@ -1521,6 +1572,10 @@ function Verify(props) {
1521
1572
  tone: "caution",
1522
1573
  onClick: () => addOrderToDocuments(documentsWithoutOrderIds),
1523
1574
  text: documentsWithoutOrderIds.length === 1 ? "Set Order for 1 Document" : "Set Order for ".concat(documentsWithoutOrderIds.length, " Documents")
1575
+ }) : null, documentsWithDuplicatedOrderIds.length > 0 ? /* @__PURE__ */jsx(Button, {
1576
+ tone: "caution",
1577
+ onClick: () => addOrderToDocuments(documentsWithDuplicatedOrderIds),
1578
+ text: documentsWithDuplicatedOrderIds.length === 1 ? "Set Unique Order for 1 Document" : "Set Unique Order for ".concat(documentsWithDuplicatedOrderIds.length, " Documents")
1524
1579
  }) : null, orphanedMetadataDocumentIds.length > 0 ? /* @__PURE__ */jsx(Button, {
1525
1580
  text: "Cleanup orphaned metadata",
1526
1581
  onClick: handleOrphans,
@@ -1536,6 +1591,7 @@ function WorkflowTool(props) {
1536
1591
  } = (_b = (_a = props == null ? void 0 : props.tool) == null ? void 0 : _a.options) != null ? _b : {};
1537
1592
  const isDarkMode = useTheme().sanity.color.dark;
1538
1593
  const defaultCardTone = isDarkMode ? "default" : "transparent";
1594
+ const toast = useToast();
1539
1595
  const userList = useProjectUsers({
1540
1596
  apiVersion: API_VERSION
1541
1597
  });
@@ -1545,6 +1601,7 @@ function WorkflowTool(props) {
1545
1601
  workflowData,
1546
1602
  operations
1547
1603
  } = useWorkflowDocuments(schemaTypes);
1604
+ const [patchingIds, setPatchingIds] = React.useState([]);
1548
1605
  const {
1549
1606
  data,
1550
1607
  loading,
@@ -1592,7 +1649,7 @@ function WorkflowTool(props) {
1592
1649
  setUndroppableStates(undroppableExceptSelf);
1593
1650
  }
1594
1651
  }, [data, states, user]);
1595
- const handleDragEnd = React.useCallback(result => {
1652
+ const handleDragEnd = React.useCallback(async result => {
1596
1653
  var _a2, _b2, _c2, _d, _e, _f;
1597
1654
  setUndroppableStates([]);
1598
1655
  setDraggingFrom("");
@@ -1609,26 +1666,65 @@ function WorkflowTool(props) {
1609
1666
  return;
1610
1667
  }
1611
1668
  const destinationStateItems = [...filterItemsAndSort(data, destination.droppableId, [], null)];
1669
+ const destinationStateIndex = states.findIndex(s => s.id === destination.droppableId);
1670
+ const globalStateMinimumRank = data[0]._metadata.orderRank;
1671
+ const globalStateMaximumRank = data[data.length - 1]._metadata.orderRank;
1612
1672
  let newOrder;
1613
1673
  if (!destinationStateItems.length) {
1614
- newOrder = LexoRank.min().toString();
1674
+ if (destinationStateIndex === 0) {
1675
+ newOrder = LexoRank.min().toString();
1676
+ } else {
1677
+ newOrder = LexoRank.parse(globalStateMinimumRank).between(LexoRank.min()).toString();
1678
+ }
1615
1679
  } else if (destination.index === 0) {
1616
1680
  const firstItemOrderRank = (_b2 = (_a2 = [...destinationStateItems].shift()) == null ? void 0 : _a2._metadata) == null ? void 0 : _b2.orderRank;
1617
- newOrder = firstItemOrderRank && typeof firstItemOrderRank === "string" ? LexoRank.parse(firstItemOrderRank).genPrev().toString() : LexoRank.min().toString();
1681
+ if (firstItemOrderRank && typeof firstItemOrderRank === "string") {
1682
+ newOrder = LexoRank.parse(firstItemOrderRank).genPrev().toString();
1683
+ } else if (destinationStateIndex === 0) {
1684
+ newOrder = LexoRank.min().toString();
1685
+ } else {
1686
+ newOrder = LexoRank.parse(globalStateMinimumRank).between(LexoRank.min()).toString();
1687
+ }
1618
1688
  } else if (destination.index + 1 === destinationStateItems.length) {
1619
1689
  const lastItemOrderRank = (_d = (_c2 = [...destinationStateItems].pop()) == null ? void 0 : _c2._metadata) == null ? void 0 : _d.orderRank;
1620
- newOrder = lastItemOrderRank && typeof lastItemOrderRank === "string" ? LexoRank.parse(lastItemOrderRank).genNext().toString() : LexoRank.min().toString();
1690
+ if (lastItemOrderRank && typeof lastItemOrderRank === "string") {
1691
+ newOrder = LexoRank.parse(lastItemOrderRank).genNext().toString();
1692
+ } else if (destinationStateIndex === states.length - 1) {
1693
+ newOrder = LexoRank.max().toString();
1694
+ } else {
1695
+ newOrder = LexoRank.parse(globalStateMaximumRank).between(LexoRank.min()).toString();
1696
+ }
1621
1697
  } else {
1622
1698
  const itemBefore = destinationStateItems[destination.index - 1];
1623
1699
  const itemBeforeRank = (_e = itemBefore == null ? void 0 : itemBefore._metadata) == null ? void 0 : _e.orderRank;
1624
- const itemBeforeRankParsed = itemBeforeRank ? LexoRank.parse(itemBeforeRank) : LexoRank.min();
1700
+ let itemBeforeRankParsed;
1701
+ if (itemBeforeRank) {
1702
+ itemBeforeRankParsed = LexoRank.parse(itemBeforeRank);
1703
+ } else if (destinationStateIndex === 0) {
1704
+ itemBeforeRankParsed = LexoRank.min();
1705
+ } else {
1706
+ itemBeforeRankParsed = LexoRank.parse(globalStateMinimumRank);
1707
+ }
1625
1708
  const itemAfter = destinationStateItems[destination.index];
1626
1709
  const itemAfterRank = (_f = itemAfter == null ? void 0 : itemAfter._metadata) == null ? void 0 : _f.orderRank;
1627
- const itemAfterRankParsed = itemAfterRank ? LexoRank.parse(itemAfterRank) : LexoRank.max();
1710
+ let itemAfterRankParsed;
1711
+ if (itemAfterRank) {
1712
+ itemAfterRankParsed = LexoRank.parse(itemAfterRank);
1713
+ } else if (destinationStateIndex === states.length - 1) {
1714
+ itemAfterRankParsed = LexoRank.max();
1715
+ } else {
1716
+ itemAfterRankParsed = LexoRank.parse(globalStateMaximumRank);
1717
+ }
1628
1718
  newOrder = itemBeforeRankParsed.between(itemAfterRankParsed).toString();
1629
1719
  }
1630
- move(draggableId, destination, states, newOrder);
1631
- }, [data, move, states]);
1720
+ setPatchingIds([...patchingIds, draggableId]);
1721
+ toast.push({
1722
+ status: "info",
1723
+ title: "Updating document state..."
1724
+ });
1725
+ await move(draggableId, destination, states, newOrder);
1726
+ setPatchingIds(ids => ids.filter(id => id !== draggableId));
1727
+ }, [data, patchingIds, toast, move, states]);
1632
1728
  const uniqueAssignedUsers = React.useMemo(() => {
1633
1729
  const uniqueUserIds = data.reduce((acc, item) => {
1634
1730
  var _a2;
@@ -1655,6 +1751,30 @@ function WorkflowTool(props) {
1655
1751
  const toggleInvalidDocumentId = React.useCallback((docId, action) => {
1656
1752
  setInvalidDocumentIds(prev => action === "ADD" ? [...prev, docId] : prev.filter(id => id !== docId));
1657
1753
  }, []);
1754
+ const Clone = React.useCallback((provided, snapshot, rubric) => {
1755
+ const item = data.find(doc => {
1756
+ var _a2;
1757
+ return ((_a2 = doc == null ? void 0 : doc._metadata) == null ? void 0 : _a2.documentId) === rubric.draggableId;
1758
+ });
1759
+ return /* @__PURE__ */jsx("div", {
1760
+ ...provided.draggableProps,
1761
+ ...provided.dragHandleProps,
1762
+ ref: provided.innerRef,
1763
+ children: item ? /* @__PURE__ */jsx(DocumentCard, {
1764
+ isDragDisabled: false,
1765
+ isPatching: false,
1766
+ userRoleCanDrop: true,
1767
+ isDragging: snapshot.isDragging,
1768
+ item,
1769
+ states,
1770
+ toggleInvalidDocumentId,
1771
+ userList
1772
+ }) : /* @__PURE__ */jsx(Feedback, {
1773
+ title: "Item not found",
1774
+ tone: "caution"
1775
+ })
1776
+ });
1777
+ }, [data, states, toggleInvalidDocumentId, userList]);
1658
1778
  if (!(states == null ? void 0 : states.length)) {
1659
1779
  return /* @__PURE__ */jsx(Container, {
1660
1780
  width: 1,
@@ -1713,36 +1833,15 @@ function WorkflowTool(props) {
1713
1833
  requireAssignment: (_b2 = state.requireAssignment) != null ? _b2 : false,
1714
1834
  userRoleCanDrop,
1715
1835
  isDropDisabled,
1716
- draggingFrom
1836
+ draggingFrom,
1837
+ documentCount: filterItemsAndSort(data, state.id, selectedUserIds, selectedSchemaTypes).length
1717
1838
  }), /* @__PURE__ */jsx(Box, {
1718
1839
  flex: 1,
1719
1840
  children: /* @__PURE__ */jsx(Droppable, {
1720
1841
  droppableId: state.id,
1721
1842
  isDropDisabled,
1722
1843
  mode: "virtual",
1723
- renderClone: (provided, snapshot, rubric) => {
1724
- const item = data.find(doc => {
1725
- var _a3;
1726
- return ((_a3 = doc == null ? void 0 : doc._metadata) == null ? void 0 : _a3.documentId) === rubric.draggableId;
1727
- });
1728
- return /* @__PURE__ */jsx("div", {
1729
- ...provided.draggableProps,
1730
- ...provided.dragHandleProps,
1731
- ref: provided.innerRef,
1732
- children: item ? /* @__PURE__ */jsx(DocumentCard, {
1733
- isDragDisabled: false,
1734
- userRoleCanDrop,
1735
- isDragging: snapshot.isDragging,
1736
- item,
1737
- states,
1738
- toggleInvalidDocumentId,
1739
- userList
1740
- }) : /* @__PURE__ */jsx(Feedback, {
1741
- title: "Item not found",
1742
- tone: "caution"
1743
- })
1744
- });
1745
- },
1844
+ renderClone: Clone,
1746
1845
  children: (provided, snapshot) => /* @__PURE__ */jsxs(Card, {
1747
1846
  ref: provided.innerRef,
1748
1847
  tone: snapshot.isDraggingOver ? "primary" : defaultCardTone,
@@ -1758,6 +1857,7 @@ function WorkflowTool(props) {
1758
1857
  }) : null, /* @__PURE__ */jsx(DocumentList, {
1759
1858
  data,
1760
1859
  invalidDocumentIds,
1860
+ patchingIds,
1761
1861
  selectedSchemaTypes,
1762
1862
  selectedUserIds,
1763
1863
  state,