synapse-react-client 4.0.30 → 4.0.32

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 (222) hide show
  1. package/dist/SWC.index.d.ts +4 -0
  2. package/dist/SWC.index.d.ts.map +1 -1
  3. package/dist/SWC.index.js +2 -1
  4. package/dist/SWC.index.js.map +1 -1
  5. package/dist/assets/illustrations/curie_avatar.svg +52 -0
  6. package/dist/assets/illustrations/curie_avatar_head.js +91 -0
  7. package/dist/assets/illustrations/curie_avatar_head.js.map +1 -0
  8. package/dist/assets/illustrations/curie_avatar_head.svg +21 -0
  9. package/dist/assets/illustrations/discussions_illustration2.js +96 -0
  10. package/dist/assets/illustrations/discussions_illustration2.js.map +1 -0
  11. package/dist/assets/illustrations/discussions_illustration2.svg +17 -0
  12. package/dist/assets/illustrations/index.d.ts +3 -0
  13. package/dist/assets/illustrations/index.d.ts.map +1 -1
  14. package/dist/assets/illustrations/index.js +34 -32
  15. package/dist/assets/illustrations/index.js.map +1 -1
  16. package/dist/assets/mui_components/CurieAvatarHead.d.ts +5 -0
  17. package/dist/assets/mui_components/CurieAvatarHead.d.ts.map +1 -0
  18. package/dist/assets/mui_components/CurieAvatarHead.js +17 -0
  19. package/dist/assets/mui_components/CurieAvatarHead.js.map +1 -0
  20. package/dist/assets/themed_icons/Model.d.ts +3 -0
  21. package/dist/assets/themed_icons/Model.d.ts.map +1 -0
  22. package/dist/assets/themed_icons/Model.js +31 -0
  23. package/dist/assets/themed_icons/Model.js.map +1 -0
  24. package/dist/assets/themed_icons/index.d.ts +2 -1
  25. package/dist/assets/themed_icons/index.d.ts.map +1 -1
  26. package/dist/assets/themed_icons/index.js +19 -18
  27. package/dist/components/ChallengeDataDownload/ChallengeDataDownload.d.ts.map +1 -1
  28. package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js +49 -39
  29. package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js.map +1 -1
  30. package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
  31. package/dist/components/DataGrid/SynapseGrid.js +46 -45
  32. package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
  33. package/dist/components/DataGrid/utils/DataGridUtils.js +1 -1
  34. package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
  35. package/dist/components/EntityFinder/EntityFinder.js +127 -127
  36. package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
  37. package/dist/components/EntityFinder/details/view/DetailsView.js +53 -53
  38. package/dist/components/EntitySidebar/EntitySidebar.css +1 -1
  39. package/dist/components/EntitySidebar/EntitySidebar.module.js +11 -11
  40. package/dist/components/EntitySidebar/EntitySidebar.module.js.map +1 -1
  41. package/dist/components/EntitySidebar/EntitySidebar.module.scss +2 -2
  42. package/dist/components/EntityTreeTable/EntityTreeTable.d.ts +7 -0
  43. package/dist/components/EntityTreeTable/EntityTreeTable.d.ts.map +1 -1
  44. package/dist/components/EntityTreeTable/EntityTreeTable.js +24 -20
  45. package/dist/components/EntityTreeTable/EntityTreeTable.js.map +1 -1
  46. package/dist/components/EntityTreeTable/components/CheckboxCell.d.ts +4 -0
  47. package/dist/components/EntityTreeTable/components/CheckboxCell.d.ts.map +1 -0
  48. package/dist/components/EntityTreeTable/components/CheckboxCell.js +43 -0
  49. package/dist/components/EntityTreeTable/components/CheckboxCell.js.map +1 -0
  50. package/dist/components/EntityTreeTable/components/EntityNameCell.d.ts.map +1 -1
  51. package/dist/components/EntityTreeTable/components/EntityNameCell.js +10 -9
  52. package/dist/components/EntityTreeTable/components/EntityNameCell.js.map +1 -1
  53. package/dist/components/EntityTreeTable/components/EntityTreeTableContext.d.ts +6 -0
  54. package/dist/components/EntityTreeTable/components/EntityTreeTableContext.d.ts.map +1 -1
  55. package/dist/components/EntityTreeTable/components/EntityTreeTableContext.js.map +1 -1
  56. package/dist/components/EntityTreeTable/hooks/useTableColumns.d.ts +1 -1
  57. package/dist/components/EntityTreeTable/hooks/useTableColumns.d.ts.map +1 -1
  58. package/dist/components/EntityTreeTable/hooks/useTableColumns.js +49 -39
  59. package/dist/components/EntityTreeTable/hooks/useTableColumns.js.map +1 -1
  60. package/dist/components/EntityUpload/EntityUpload.js +6 -6
  61. package/dist/components/Forum/DiscussionEmpty.css +1 -0
  62. package/dist/components/Forum/DiscussionEmpty.d.ts +6 -0
  63. package/dist/components/Forum/DiscussionEmpty.d.ts.map +1 -0
  64. package/dist/components/Forum/DiscussionEmpty.js +30 -0
  65. package/dist/components/Forum/DiscussionEmpty.js.map +1 -0
  66. package/dist/components/Forum/DiscussionEmpty.module.js +10 -0
  67. package/dist/components/Forum/DiscussionEmpty.module.js.map +1 -0
  68. package/dist/components/Forum/DiscussionEmpty.module.scss +37 -0
  69. package/dist/components/Icon/Icon.d.ts.map +1 -1
  70. package/dist/components/Icon/Icon.js +82 -80
  71. package/dist/components/Icon/Icon.js.map +1 -1
  72. package/dist/components/ProvenanceGraph/ProvenanceGraph.d.ts.map +1 -1
  73. package/dist/components/ProvenanceGraph/ProvenanceGraph.js +39 -41
  74. package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
  75. package/dist/components/SynapseChat/AccessLevelMenu.d.ts.map +1 -1
  76. package/dist/components/SynapseChat/AccessLevelMenu.js +1 -0
  77. package/dist/components/SynapseChat/AccessLevelMenu.js.map +1 -1
  78. package/dist/components/SynapseChat/GridAgentChat.d.ts.map +1 -1
  79. package/dist/components/SynapseChat/GridAgentChat.js +34 -25
  80. package/dist/components/SynapseChat/GridAgentChat.js.map +1 -1
  81. package/dist/components/SynapseChat/SynapseChat.d.ts +10 -12
  82. package/dist/components/SynapseChat/SynapseChat.d.ts.map +1 -1
  83. package/dist/components/SynapseChat/SynapseChat.js +106 -103
  84. package/dist/components/SynapseChat/SynapseChat.js.map +1 -1
  85. package/dist/components/SynapseChat/SynapseChatInteraction.css +1 -0
  86. package/dist/components/SynapseChat/SynapseChatInteraction.d.ts +22 -1
  87. package/dist/components/SynapseChat/SynapseChatInteraction.d.ts.map +1 -1
  88. package/dist/components/SynapseChat/SynapseChatInteraction.js +123 -94
  89. package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
  90. package/dist/components/SynapseChat/SynapseChatInteraction.module.js +8 -0
  91. package/dist/components/SynapseChat/SynapseChatInteraction.module.js.map +1 -0
  92. package/dist/components/SynapseChat/SynapseChatInteraction.module.scss +25 -0
  93. package/dist/components/SynapseChat/SynapseChatMessage.d.ts +16 -1
  94. package/dist/components/SynapseChat/SynapseChatMessage.d.ts.map +1 -1
  95. package/dist/components/SynapseChat/SynapseChatMessage.js +25 -11
  96. package/dist/components/SynapseChat/SynapseChatMessage.js.map +1 -1
  97. package/dist/components/SynapseChat/components/AddFilesDialog/AddFilesDialog.d.ts +27 -0
  98. package/dist/components/SynapseChat/components/AddFilesDialog/AddFilesDialog.d.ts.map +1 -0
  99. package/dist/components/SynapseChat/components/AddFilesDialog/AddFilesDialog.js +79 -0
  100. package/dist/components/SynapseChat/components/AddFilesDialog/AddFilesDialog.js.map +1 -0
  101. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.css +1 -0
  102. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.d.ts +33 -0
  103. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.d.ts.map +1 -0
  104. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.js +77 -0
  105. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.js.map +1 -0
  106. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.module.js +8 -0
  107. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.module.js.map +1 -0
  108. package/dist/components/SynapseChat/components/AttachmentChip/AttachmentChip.module.scss +16 -0
  109. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.css +1 -0
  110. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.d.ts +23 -0
  111. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.d.ts.map +1 -0
  112. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.js +24 -0
  113. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.js.map +1 -0
  114. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.module.js +9 -0
  115. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.module.js.map +1 -0
  116. package/dist/components/SynapseChat/components/ChatAttachmentStrip/ChatAttachmentStrip.module.scss +19 -0
  117. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.css +1 -0
  118. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.d.ts +22 -0
  119. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.d.ts.map +1 -0
  120. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.js +80 -0
  121. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.js.map +1 -0
  122. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.module.js +9 -0
  123. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.module.js.map +1 -0
  124. package/dist/components/SynapseChat/components/ChatInputArea/ChatInputArea.module.scss +39 -0
  125. package/dist/components/SynapseChat/useChatState.d.ts +12 -4
  126. package/dist/components/SynapseChat/useChatState.d.ts.map +1 -1
  127. package/dist/components/SynapseChat/useChatState.js +38 -20
  128. package/dist/components/SynapseChat/useChatState.js.map +1 -1
  129. package/dist/components/SynapseChat/utils/constants.d.ts +8 -0
  130. package/dist/components/SynapseChat/utils/constants.d.ts.map +1 -0
  131. package/dist/components/SynapseChat/utils/constants.js +12 -0
  132. package/dist/components/SynapseChat/utils/constants.js.map +1 -0
  133. package/dist/components/SynapseChat/utils/types.d.ts +13 -0
  134. package/dist/components/SynapseChat/utils/types.d.ts.map +1 -0
  135. package/dist/components/SynapseChat/utils/types.js +0 -0
  136. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js +101 -101
  137. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  138. package/dist/components/entity/page/action_menu/EntityActionMenu.d.ts +1 -0
  139. package/dist/components/entity/page/action_menu/EntityActionMenu.d.ts.map +1 -1
  140. package/dist/components/entity/page/action_menu/EntityActionMenu.js +8 -0
  141. package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
  142. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js +1 -1
  143. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js.map +1 -1
  144. package/dist/components/file/upload/BasicFileHandleUpload.d.ts +35 -4
  145. package/dist/components/file/upload/BasicFileHandleUpload.d.ts.map +1 -1
  146. package/dist/components/file/upload/BasicFileHandleUpload.js +22 -16
  147. package/dist/components/file/upload/BasicFileHandleUpload.js.map +1 -1
  148. package/dist/components/file/upload/MultiFileUploadProgress.js +6 -6
  149. package/dist/components/file/upload/UploadFilePanel.d.ts +32 -0
  150. package/dist/components/file/upload/UploadFilePanel.d.ts.map +1 -1
  151. package/dist/components/file/upload/UploadFilePanel.js +58 -42
  152. package/dist/components/file/upload/UploadFilePanel.js.map +1 -1
  153. package/dist/components/file/upload/validateFileSelection.d.ts +25 -0
  154. package/dist/components/file/upload/validateFileSelection.d.ts.map +1 -0
  155. package/dist/components/file/upload/validateFileSelection.js +18 -0
  156. package/dist/components/file/upload/validateFileSelection.js.map +1 -0
  157. package/dist/components/menu/DropdownMenu.d.ts +3 -0
  158. package/dist/components/menu/DropdownMenu.d.ts.map +1 -1
  159. package/dist/components/menu/DropdownMenu.js +108 -83
  160. package/dist/components/menu/DropdownMenu.js.map +1 -1
  161. package/dist/features/curator/dashboard/components/CurationTaskCard.css +1 -1
  162. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js +13 -13
  163. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js.map +1 -1
  164. package/dist/features/curator/dashboard/components/CurationTaskCard.module.scss +2 -1
  165. package/dist/features/curator/dashboard/components/CurationTaskCardLayout.d.ts.map +1 -1
  166. package/dist/features/curator/dashboard/components/CurationTaskCardLayout.js +35 -27
  167. package/dist/features/curator/dashboard/components/CurationTaskCardLayout.js.map +1 -1
  168. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -1
  169. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +131 -131
  170. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -1
  171. package/dist/features/entity/metadata-task/create-task/useCurationTaskFormState.d.ts.map +1 -1
  172. package/dist/features/entity/metadata-task/create-task/useCurationTaskFormState.js +21 -18
  173. package/dist/features/entity/metadata-task/create-task/useCurationTaskFormState.js.map +1 -1
  174. package/dist/features/entity/metadata-task/utils/dueDate.d.ts +1 -1
  175. package/dist/features/entity/metadata-task/utils/dueDate.js.map +1 -1
  176. package/dist/mocks/chat/mockChat.d.ts +13 -1
  177. package/dist/mocks/chat/mockChat.d.ts.map +1 -1
  178. package/dist/mocks/chat/mockChat.js +34 -9
  179. package/dist/mocks/chat/mockChat.js.map +1 -1
  180. package/dist/mocks/msw/handlers/chatHandlers.d.ts +1 -1
  181. package/dist/mocks/msw/handlers/chatHandlers.d.ts.map +1 -1
  182. package/dist/mocks/msw/handlers/chatHandlers.js +21 -7
  183. package/dist/mocks/msw/handlers/chatHandlers.js.map +1 -1
  184. package/dist/synapse-client/SynapseClient.d.ts +2 -2
  185. package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
  186. package/dist/synapse-client/SynapseClient.js.map +1 -1
  187. package/dist/synapse-queries/KeyFactory.d.ts +10 -1
  188. package/dist/synapse-queries/KeyFactory.d.ts.map +1 -1
  189. package/dist/synapse-queries/KeyFactory.js +29 -2
  190. package/dist/synapse-queries/KeyFactory.js.map +1 -1
  191. package/dist/synapse-queries/asynchronous/usePollAsynchronousJob.d.ts +2 -2
  192. package/dist/synapse-queries/asynchronous/usePollAsynchronousJob.d.ts.map +1 -1
  193. package/dist/synapse-queries/asynchronous/usePollAsynchronousJob.js +2 -1
  194. package/dist/synapse-queries/asynchronous/usePollAsynchronousJob.js.map +1 -1
  195. package/dist/synapse-queries/chat/useChat.d.ts +3 -2
  196. package/dist/synapse-queries/chat/useChat.d.ts.map +1 -1
  197. package/dist/synapse-queries/chat/useChat.js +7 -6
  198. package/dist/synapse-queries/chat/useChat.js.map +1 -1
  199. package/dist/synapse-queries/dataaccess/index.d.ts +1 -0
  200. package/dist/synapse-queries/dataaccess/index.d.ts.map +1 -1
  201. package/dist/synapse-queries/dataaccess/index.js +4 -3
  202. package/dist/synapse-queries/dataaccess/useEDuc.d.ts +44 -0
  203. package/dist/synapse-queries/dataaccess/useEDuc.d.ts.map +1 -0
  204. package/dist/synapse-queries/dataaccess/useEDuc.js +75 -0
  205. package/dist/synapse-queries/dataaccess/useEDuc.js.map +1 -0
  206. package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts.map +1 -1
  207. package/dist/synapse-queries/featureflags/useGetFeatureFlag.js +1 -1
  208. package/dist/synapse-queries/featureflags/useGetFeatureFlag.js.map +1 -1
  209. package/dist/synapse-queries/file/useDirectUploadToS3.js +6 -6
  210. package/dist/synapse-queries/index.js +181 -172
  211. package/dist/tsconfig.build.tsbuildinfo +1 -1
  212. package/dist/utils/SynapseConstants.d.ts +2 -0
  213. package/dist/utils/SynapseConstants.d.ts.map +1 -1
  214. package/dist/utils/SynapseConstants.js +122 -120
  215. package/dist/utils/SynapseConstants.js.map +1 -1
  216. package/dist/utils/featureflag/FeatureFlags.d.ts +3 -1
  217. package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -1
  218. package/dist/utils/featureflag/FeatureFlags.js +1 -1
  219. package/dist/utils/featureflag/FeatureFlags.js.map +1 -1
  220. package/dist/utils/hooks/useUploadFileEntity/useUploadFileEntities.js +5 -5
  221. package/dist/utils/hooks/useUploadFileEntity/useUploadFiles.js +14 -14
  222. package/package.json +4 -4
@@ -8,6 +8,7 @@ type EntityActionMenuDropdownMenuConfiguration = {
8
8
  visible: boolean;
9
9
  tooltipText?: string;
10
10
  disabled?: boolean;
11
+ showFileAccessRequestNotice?: boolean;
11
12
  };
12
13
  export type ActionConfiguration = {
13
14
  visible: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"EntityActionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAEhE,OAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAK/C,KAAK,gCAAgC,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9D,KAAK,yCAAyC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;AAExE,MAAM,MAAM,oBAAoB,GAAG,MAAM,CACvC,gCAAgC,EAChC,yCAAyC,CAC1C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,eAAe,EAAE,CAAA;IAChC,mBAAmB,EAAE,eAAe,EAAE,EAAE,CAAA;IACxC,kBAAkB,EAAE,eAAe,EAAE,EAAE,CAAA;IACvC,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,QAAQ,CAAA;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,YAAY,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC5C,kBAAkB,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAElC,mBAAmB,EAAE,sBAAsB,CAAA;IAE3C,iBAAiB,EAAE,oBAAoB,CAAA;IAEvC,MAAM,EAAE,sBAAsB,CAAA;CAC/B,CAAA;AAMD,iBAAS,kBAAkB,CACzB,mBAAmB,EAAE,sBAAsB,EAC3C,MAAM,EAAE,sBAAsB,GAC7B,sBAAsB,CAmBxB;AAED;;;;;GAKG;AACH,iBAAS,4BAA4B,CACnC,KAAK,EAAE,eAAe,EAAE,EACxB,mBAAmB,EAAE,sBAAsB,GAC1C,gBAAgB,EAAE,CAqBpB;AAED;;;;;;GAMG;AACH,iBAAS,sBAAsB,CAC7B,WAAW,EAAE,eAAe,EAAE,EAAE,EAChC,mBAAmB,EAAE,sBAAsB,GAC1C,gBAAgB,EAAE,EAAE,CAYtB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,2CAoIpE;AAED,eAAO,MAAM,yBAAyB;;;;CAIrC,CAAA"}
1
+ {"version":3,"file":"EntityActionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAEhE,OAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAK/C,KAAK,gCAAgC,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9D,KAAK,yCAAyC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2BAA2B,CAAC,EAAE,OAAO,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;AAExE,MAAM,MAAM,oBAAoB,GAAG,MAAM,CACvC,gCAAgC,EAChC,yCAAyC,CAC1C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,eAAe,EAAE,CAAA;IAChC,mBAAmB,EAAE,eAAe,EAAE,EAAE,CAAA;IACxC,kBAAkB,EAAE,eAAe,EAAE,EAAE,CAAA;IACvC,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,QAAQ,CAAA;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,YAAY,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC5C,kBAAkB,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAElC,mBAAmB,EAAE,sBAAsB,CAAA;IAE3C,iBAAiB,EAAE,oBAAoB,CAAA;IAEvC,MAAM,EAAE,sBAAsB,CAAA;CAC/B,CAAA;AAMD,iBAAS,kBAAkB,CACzB,mBAAmB,EAAE,sBAAsB,EAC3C,MAAM,EAAE,sBAAsB,GAC7B,sBAAsB,CAmBxB;AAED;;;;;GAKG;AACH,iBAAS,4BAA4B,CACnC,KAAK,EAAE,eAAe,EAAE,EACxB,mBAAmB,EAAE,sBAAsB,GAC1C,gBAAgB,EAAE,CAqBpB;AAED;;;;;;GAMG;AACH,iBAAS,sBAAsB,CAC7B,WAAW,EAAE,eAAe,EAAE,EAAE,EAChC,mBAAmB,EAAE,sBAAsB,GAC1C,gBAAgB,EAAE,EAAE,CAYtB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,2CA6IpE;AAED,eAAO,MAAM,yBAAyB;;;;CAIrC,CAAA"}
@@ -58,6 +58,14 @@ function c(o) {
58
58
  convertSingleItemToButton: !0,
59
59
  renderMenuIfNoItems: !1,
60
60
  variant: u.downloadMenuVariant,
61
+ showFileAccessRequestNotice: l.DOWNLOAD.showFileAccessRequestNotice ?? !1,
62
+ paperSx: {
63
+ borderRadius: "5px",
64
+ border: "1px solid #E2E4EA",
65
+ width: "279px",
66
+ padding: "12px 16px"
67
+ },
68
+ elevation: 3,
61
69
  buttonTooltip: l.DOWNLOAD.tooltipText,
62
70
  buttonProps: {
63
71
  disabled: l.DOWNLOAD.disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"EntityActionMenu.js","names":[],"sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"sourcesContent":["import { Box, ButtonProps, SxProps, Theme } from '@mui/material'\nimport { ComplexMenu, ComplexMenuButtonProps } from '../../../menu/ComplexMenu'\nimport IconSvg, { IconName } from '../../../IconSvg/IconSvg'\nimport { DropdownMenuItem, DropdownMenuProps } from '../../../menu/DropdownMenu'\nimport { MouseEvent } from 'react'\nimport { SystemStyleObject } from '@mui/system'\n\nconst outlinedButtonHoverBackgroundColor = 'rgba(0, 0, 0, 0.01)'\n\n// Represents the two types of dropdown menus that will be displayed on the entity page\ntype EntityActionMenuDropdownMenuType = 'DOWNLOAD' | 'PRIMARY'\n\ntype EntityActionMenuDropdownMenuConfiguration = {\n visible: boolean\n tooltipText?: string\n disabled?: boolean\n}\n\nexport type ActionConfiguration = {\n visible: boolean\n text: string\n disabled?: boolean\n tooltipText?: string\n onClick?: (e: MouseEvent) => void\n href?: string\n}\n\nexport type ActionConfigurationMap = Record<string, ActionConfiguration>\n\nexport type MenuConfigurationMap = Record<\n EntityActionMenuDropdownMenuType,\n EntityActionMenuDropdownMenuConfiguration\n>\n\nexport type ActionViewProps = {\n action: string\n icon?: IconName\n textSx?: SxProps\n iconSx?: SxProps\n variant?: ButtonProps['variant']\n}\n\nexport type EntityActionMenuLayout = {\n buttonActions: ActionViewProps[]\n downloadMenuActions: ActionViewProps[][]\n primaryMenuActions: ActionViewProps[][]\n primaryMenuText: string\n primaryMenuEndIcon: IconName\n primaryMenuEndIconSx?: SxProps\n menuButtonSx?: SystemStyleObject<Theme>\n downloadMenuVariant?: ButtonProps['variant']\n primaryMenuVariant?: ButtonProps['variant']\n}\n\nexport type EntityActionMenuProps = {\n /* Maps a unique action string to a dynamic configuration for that particular action */\n actionConfiguration: ActionConfigurationMap\n /* Maps each dropdown menu to a dynamic configuration for that particular menu */\n menuConfiguration: MenuConfigurationMap\n /* Defines the layout of the actions. Typically depends on just the entity type and area. */\n layout: EntityActionMenuLayout\n}\n\n/*\n * All visible actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\nfunction getUnmappedActions(\n actionConfiguration: ActionConfigurationMap,\n layout: EntityActionMenuLayout,\n): ActionConfigurationMap {\n return Object.fromEntries(\n Object.entries(actionConfiguration).filter(([action, config]) => {\n // We don't care about actions that are not configured or should not be visible\n if (!config || !config.visible) {\n return false\n }\n\n const allLayoutActions: ActionViewProps[] = [\n ...layout.buttonActions,\n ...layout.primaryMenuActions.flat(),\n ...layout.downloadMenuActions.flat(),\n ]\n // Action is unmapped if it's visible and the layout doesn't have it\n return !allLayoutActions.some(\n layoutAction => layoutAction.action === action,\n )\n }),\n )\n}\n\n/**\n * Given a group of dropdown menu items and an action configuration,\n * return a list of dropdown menu items with non-visible and non-configured actions removed.\n * @param group\n * @param actionConfiguration\n */\nfunction mapAndFilterItemsInMenuGroup(\n group: ActionViewProps[],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[] {\n return group.reduce(\n (itemAcc: DropdownMenuItem[], actionViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[actionViewProps.action]\n // Only show the item if it's configured + visible\n if (configForAction && configForAction.visible) {\n itemAcc.push({\n text: configForAction.text ?? actionViewProps.action,\n onClick: configForAction.onClick,\n href: configForAction.href,\n tooltipText: configForAction.tooltipText,\n disabled: configForAction.disabled,\n icon: actionViewProps.icon,\n textSx: actionViewProps.textSx,\n iconSx: actionViewProps.iconSx,\n })\n }\n return itemAcc\n },\n [],\n )\n}\n\n/**\n * Given a list of groups of dropdown menu actions, returns a list of dropdown menu item\n * groups where non-visible actions have been removed, and groups with no visible actions\n * have been removed.\n * @param menuActions\n * @param actionConfiguration\n */\nfunction mapAndFilterMenuGroups(\n menuActions: ActionViewProps[][],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[][] {\n return menuActions.reduce(\n (groupAcc: DropdownMenuItem[][], group: ActionViewProps[]) => {\n const itemGroup = mapAndFilterItemsInMenuGroup(group, actionConfiguration)\n // Only show the group if it contains visible items\n if (itemGroup.length > 0) {\n groupAcc.push(itemGroup)\n }\n return groupAcc\n },\n [],\n )\n}\n\n/**\n * The EntityActionMenu renders a menu that displays the actions that can be invoked on an Entity page.\n */\nexport default function EntityActionMenu(props: EntityActionMenuProps) {\n const { actionConfiguration, menuConfiguration, layout } = props\n\n /*\n * All actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\n const unmappedActions = getUnmappedActions(actionConfiguration, layout)\n // Warn if unmapped actions were found and push them on to the layout.\n if (Object.entries(unmappedActions).length > 0) {\n console.warn(\n 'Actions are visible but have not been configured in the layout:',\n Object.entries(unmappedActions).map(entry => entry[0]),\n )\n // Modify the layout: put the unmapped actions in their own group at the top of the menu\n layout.primaryMenuActions.unshift(\n Object.entries(unmappedActions).map(\n (entry): ActionViewProps => ({\n action: entry[0],\n }),\n ),\n )\n }\n\n // Map button actions to a button configuration and omit non-visible actions\n const iconButtonConfigs: ComplexMenuButtonProps[] =\n layout.buttonActions.reduce(\n (acc: ComplexMenuButtonProps[], buttonViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[buttonViewProps.action]\n if (configForAction && configForAction.visible) {\n let onClick = configForAction.onClick\n if (onClick == null && !configForAction.href) {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n onClick = () => {\n console.warn(\n `No handler registered for ${buttonViewProps.action}`,\n )\n }\n }\n acc.push({\n icon: buttonViewProps.icon as IconName,\n onClick: onClick,\n tooltipText: configForAction.text,\n text: configForAction.text,\n variant: buttonViewProps.variant,\n iconSx: buttonViewProps.iconSx,\n disabled: configForAction.disabled,\n href: configForAction.href,\n })\n }\n return acc\n },\n [],\n )\n\n const downloadMenuConfig: DropdownMenuProps = {\n dropdownButtonText: 'Download Options',\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n variant: layout.downloadMenuVariant,\n buttonTooltip: menuConfiguration.DOWNLOAD.tooltipText,\n buttonProps: {\n disabled: menuConfiguration.DOWNLOAD.disabled,\n endIcon: <IconSvg icon={'expandMore'} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.downloadMenuActions,\n actionConfiguration,\n ),\n }\n\n const primaryMenuConfig: DropdownMenuProps = {\n dropdownButtonText: layout.primaryMenuText,\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n variant: layout.primaryMenuVariant,\n buttonProps: {\n endIcon: (\n <IconSvg\n icon={layout.primaryMenuEndIcon}\n wrap={false}\n sx={layout.primaryMenuEndIconSx}\n />\n ),\n },\n items: mapAndFilterMenuGroups(\n layout.primaryMenuActions,\n actionConfiguration,\n ),\n }\n\n const menuButtonSx = layout.menuButtonSx ?? {}\n\n return (\n <Box\n sx={{\n '& .MuiButton-root': {\n borderRadius: '6px',\n fontWeight: 540,\n padding: '10px 12px',\n },\n // Optional per-layout overrides (e.g. background/border color for entity\n // menu buttons).\n '& .MuiButton-outlined': {\n ...menuButtonSx,\n\n '&:hover': {\n ...menuButtonSx,\n backgroundColor: outlinedButtonHoverBackgroundColor,\n },\n },\n '& .MuiButton-text': {\n ...menuButtonSx,\n backgroundColor: 'transparent',\n\n '&:hover': {\n ...menuButtonSx,\n backgroundColor: outlinedButtonHoverBackgroundColor,\n textDecoration: 'none',\n },\n },\n '& .MuiButton-root .MuiTypography-root': {\n fontWeight: 540,\n },\n }}\n >\n <ComplexMenu\n iconButtons={iconButtonConfigs}\n dropdownMenus={[primaryMenuConfig, downloadMenuConfig]}\n />\n </Box>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n getUnmappedActions,\n mapAndFilterItemsInMenuGroup,\n mapAndFilterMenuGroups,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EntityActionMenu.js","names":[],"sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"sourcesContent":["import { Box, ButtonProps, SxProps, Theme } from '@mui/material'\nimport { ComplexMenu, ComplexMenuButtonProps } from '../../../menu/ComplexMenu'\nimport IconSvg, { IconName } from '../../../IconSvg/IconSvg'\nimport { DropdownMenuItem, DropdownMenuProps } from '../../../menu/DropdownMenu'\nimport { MouseEvent } from 'react'\nimport { SystemStyleObject } from '@mui/system'\n\nconst outlinedButtonHoverBackgroundColor = 'rgba(0, 0, 0, 0.01)'\n\n// Represents the two types of dropdown menus that will be displayed on the entity page\ntype EntityActionMenuDropdownMenuType = 'DOWNLOAD' | 'PRIMARY'\n\ntype EntityActionMenuDropdownMenuConfiguration = {\n visible: boolean\n tooltipText?: string\n disabled?: boolean\n showFileAccessRequestNotice?: boolean\n}\n\nexport type ActionConfiguration = {\n visible: boolean\n text: string\n disabled?: boolean\n tooltipText?: string\n onClick?: (e: MouseEvent) => void\n href?: string\n}\n\nexport type ActionConfigurationMap = Record<string, ActionConfiguration>\n\nexport type MenuConfigurationMap = Record<\n EntityActionMenuDropdownMenuType,\n EntityActionMenuDropdownMenuConfiguration\n>\n\nexport type ActionViewProps = {\n action: string\n icon?: IconName\n textSx?: SxProps\n iconSx?: SxProps\n variant?: ButtonProps['variant']\n}\n\nexport type EntityActionMenuLayout = {\n buttonActions: ActionViewProps[]\n downloadMenuActions: ActionViewProps[][]\n primaryMenuActions: ActionViewProps[][]\n primaryMenuText: string\n primaryMenuEndIcon: IconName\n primaryMenuEndIconSx?: SxProps\n menuButtonSx?: SystemStyleObject<Theme>\n downloadMenuVariant?: ButtonProps['variant']\n primaryMenuVariant?: ButtonProps['variant']\n}\n\nexport type EntityActionMenuProps = {\n /* Maps a unique action string to a dynamic configuration for that particular action */\n actionConfiguration: ActionConfigurationMap\n /* Maps each dropdown menu to a dynamic configuration for that particular menu */\n menuConfiguration: MenuConfigurationMap\n /* Defines the layout of the actions. Typically depends on just the entity type and area. */\n layout: EntityActionMenuLayout\n}\n\n/*\n * All visible actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\nfunction getUnmappedActions(\n actionConfiguration: ActionConfigurationMap,\n layout: EntityActionMenuLayout,\n): ActionConfigurationMap {\n return Object.fromEntries(\n Object.entries(actionConfiguration).filter(([action, config]) => {\n // We don't care about actions that are not configured or should not be visible\n if (!config || !config.visible) {\n return false\n }\n\n const allLayoutActions: ActionViewProps[] = [\n ...layout.buttonActions,\n ...layout.primaryMenuActions.flat(),\n ...layout.downloadMenuActions.flat(),\n ]\n // Action is unmapped if it's visible and the layout doesn't have it\n return !allLayoutActions.some(\n layoutAction => layoutAction.action === action,\n )\n }),\n )\n}\n\n/**\n * Given a group of dropdown menu items and an action configuration,\n * return a list of dropdown menu items with non-visible and non-configured actions removed.\n * @param group\n * @param actionConfiguration\n */\nfunction mapAndFilterItemsInMenuGroup(\n group: ActionViewProps[],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[] {\n return group.reduce(\n (itemAcc: DropdownMenuItem[], actionViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[actionViewProps.action]\n // Only show the item if it's configured + visible\n if (configForAction && configForAction.visible) {\n itemAcc.push({\n text: configForAction.text ?? actionViewProps.action,\n onClick: configForAction.onClick,\n href: configForAction.href,\n tooltipText: configForAction.tooltipText,\n disabled: configForAction.disabled,\n icon: actionViewProps.icon,\n textSx: actionViewProps.textSx,\n iconSx: actionViewProps.iconSx,\n })\n }\n return itemAcc\n },\n [],\n )\n}\n\n/**\n * Given a list of groups of dropdown menu actions, returns a list of dropdown menu item\n * groups where non-visible actions have been removed, and groups with no visible actions\n * have been removed.\n * @param menuActions\n * @param actionConfiguration\n */\nfunction mapAndFilterMenuGroups(\n menuActions: ActionViewProps[][],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[][] {\n return menuActions.reduce(\n (groupAcc: DropdownMenuItem[][], group: ActionViewProps[]) => {\n const itemGroup = mapAndFilterItemsInMenuGroup(group, actionConfiguration)\n // Only show the group if it contains visible items\n if (itemGroup.length > 0) {\n groupAcc.push(itemGroup)\n }\n return groupAcc\n },\n [],\n )\n}\n\n/**\n * The EntityActionMenu renders a menu that displays the actions that can be invoked on an Entity page.\n */\nexport default function EntityActionMenu(props: EntityActionMenuProps) {\n const { actionConfiguration, menuConfiguration, layout } = props\n\n /*\n * All actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\n const unmappedActions = getUnmappedActions(actionConfiguration, layout)\n // Warn if unmapped actions were found and push them on to the layout.\n if (Object.entries(unmappedActions).length > 0) {\n console.warn(\n 'Actions are visible but have not been configured in the layout:',\n Object.entries(unmappedActions).map(entry => entry[0]),\n )\n // Modify the layout: put the unmapped actions in their own group at the top of the menu\n layout.primaryMenuActions.unshift(\n Object.entries(unmappedActions).map(\n (entry): ActionViewProps => ({\n action: entry[0],\n }),\n ),\n )\n }\n\n // Map button actions to a button configuration and omit non-visible actions\n const iconButtonConfigs: ComplexMenuButtonProps[] =\n layout.buttonActions.reduce(\n (acc: ComplexMenuButtonProps[], buttonViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[buttonViewProps.action]\n if (configForAction && configForAction.visible) {\n let onClick = configForAction.onClick\n if (onClick == null && !configForAction.href) {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n onClick = () => {\n console.warn(\n `No handler registered for ${buttonViewProps.action}`,\n )\n }\n }\n acc.push({\n icon: buttonViewProps.icon as IconName,\n onClick: onClick,\n tooltipText: configForAction.text,\n text: configForAction.text,\n variant: buttonViewProps.variant,\n iconSx: buttonViewProps.iconSx,\n disabled: configForAction.disabled,\n href: configForAction.href,\n })\n }\n return acc\n },\n [],\n )\n\n const downloadMenuConfig: DropdownMenuProps = {\n dropdownButtonText: 'Download Options',\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n variant: layout.downloadMenuVariant,\n showFileAccessRequestNotice:\n menuConfiguration.DOWNLOAD.showFileAccessRequestNotice ?? false,\n paperSx: {\n borderRadius: '5px',\n border: '1px solid #E2E4EA',\n width: '279px',\n padding: '12px 16px',\n },\n elevation: 3,\n buttonTooltip: menuConfiguration.DOWNLOAD.tooltipText,\n buttonProps: {\n disabled: menuConfiguration.DOWNLOAD.disabled,\n endIcon: <IconSvg icon={'expandMore'} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.downloadMenuActions,\n actionConfiguration,\n ),\n }\n\n const primaryMenuConfig: DropdownMenuProps = {\n dropdownButtonText: layout.primaryMenuText,\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n variant: layout.primaryMenuVariant,\n buttonProps: {\n endIcon: (\n <IconSvg\n icon={layout.primaryMenuEndIcon}\n wrap={false}\n sx={layout.primaryMenuEndIconSx}\n />\n ),\n },\n items: mapAndFilterMenuGroups(\n layout.primaryMenuActions,\n actionConfiguration,\n ),\n }\n\n const menuButtonSx = layout.menuButtonSx ?? {}\n\n return (\n <Box\n sx={{\n '& .MuiButton-root': {\n borderRadius: '6px',\n fontWeight: 540,\n padding: '10px 12px',\n },\n // Optional per-layout overrides (e.g. background/border color for entity\n // menu buttons).\n '& .MuiButton-outlined': {\n ...menuButtonSx,\n\n '&:hover': {\n ...menuButtonSx,\n backgroundColor: outlinedButtonHoverBackgroundColor,\n },\n },\n '& .MuiButton-text': {\n ...menuButtonSx,\n backgroundColor: 'transparent',\n\n '&:hover': {\n ...menuButtonSx,\n backgroundColor: outlinedButtonHoverBackgroundColor,\n textDecoration: 'none',\n },\n },\n '& .MuiButton-root .MuiTypography-root': {\n fontWeight: 540,\n },\n }}\n >\n <ComplexMenu\n iconButtons={iconButtonConfigs}\n dropdownMenus={[primaryMenuConfig, downloadMenuConfig]}\n />\n </Box>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n getUnmappedActions,\n mapAndFilterItemsInMenuGroup,\n mapAndFilterMenuGroups,\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { jsx as t } from "react/jsx-runtime";
3
3
  //#region src/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.tsx
4
4
  var n = 32, r = "#4D535A", i = {
5
5
  marginTop: "0px",
6
- padding: "10px 32px",
6
+ padding: "20px 32px",
7
7
  "& .MuiTypography-root": {
8
8
  fontWeight: 440,
9
9
  lineHeight: "20px",
@@ -1 +1 @@
1
- {"version":3,"file":"EntityPageBreadcrumbs.js","names":[],"sources":["../../../../../src/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.tsx"],"sourcesContent":["import {\n Breadcrumbs,\n BreadcrumbItem,\n} from '@/components/Breadcrumbs/Breadcrumbs'\nimport { SxProps } from '@mui/material'\n\ntype EntityPageBreadcrumbsProps = {\n items: BreadcrumbItem[]\n sx?: SxProps\n}\n\nconst ENTITY_PAGE_MAX_BREADCRUMB_LENGTH = 32\nconst ENTITY_PAGE_TEXT_COLOR = '#4D535A'\n\nconst breadcrumbTextStyle: SxProps = {\n fontWeight: 440,\n lineHeight: '20px',\n color: ENTITY_PAGE_TEXT_COLOR,\n}\n\nconst entityPageBreadcrumbStyle: SxProps = {\n marginTop: '0px',\n padding: '10px 32px',\n ['& .MuiTypography-root']: breadcrumbTextStyle,\n ['& .MuiLink-root']: {\n '&:visited': {\n color: ENTITY_PAGE_TEXT_COLOR,\n },\n },\n ['& .MuiSvgIcon-root']: {\n fontWeight: '300',\n color: ENTITY_PAGE_TEXT_COLOR,\n },\n}\n\nexport default function EntityPageBreadcrumbs(\n props: EntityPageBreadcrumbsProps,\n) {\n const { items } = props\n return (\n <Breadcrumbs\n items={items}\n sx={entityPageBreadcrumbStyle}\n maxBreadcrumbLength={ENTITY_PAGE_MAX_BREADCRUMB_LENGTH}\n iconVariant=\"outlined\"\n />\n )\n}\n"],"mappings":";;;AAWA,IAAM,IAAoC,IACpC,IAAyB,WAQzB,IAAqC;CACzC,WAAW;CACX,SAAS;CACR,yBAA0B;EAR3B,YAAY;EACZ,YAAY;EACZ,OAAO;CAMoB;CAC1B,mBAAoB,EACnB,aAAa,EACX,OAAO,EACT,EACF;CACC,sBAAuB;EACtB,YAAY;EACZ,OAAO;CACT;AACF;AAEA,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,aAAU;CAClB,OACE,kBAAC,GAAD;EACS;EACP,IAAI;EACJ,qBAAqB;EACrB,aAAY;CACb,CAAA;AAEL"}
1
+ {"version":3,"file":"EntityPageBreadcrumbs.js","names":[],"sources":["../../../../../src/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.tsx"],"sourcesContent":["import {\n Breadcrumbs,\n BreadcrumbItem,\n} from '@/components/Breadcrumbs/Breadcrumbs'\nimport { SxProps } from '@mui/material'\n\ntype EntityPageBreadcrumbsProps = {\n items: BreadcrumbItem[]\n sx?: SxProps\n}\n\nconst ENTITY_PAGE_MAX_BREADCRUMB_LENGTH = 32\nconst ENTITY_PAGE_TEXT_COLOR = '#4D535A'\n\nconst breadcrumbTextStyle: SxProps = {\n fontWeight: 440,\n lineHeight: '20px',\n color: ENTITY_PAGE_TEXT_COLOR,\n}\n\nconst entityPageBreadcrumbStyle: SxProps = {\n marginTop: '0px',\n padding: '20px 32px',\n ['& .MuiTypography-root']: breadcrumbTextStyle,\n ['& .MuiLink-root']: {\n '&:visited': {\n color: ENTITY_PAGE_TEXT_COLOR,\n },\n },\n ['& .MuiSvgIcon-root']: {\n fontWeight: '300',\n color: ENTITY_PAGE_TEXT_COLOR,\n },\n}\n\nexport default function EntityPageBreadcrumbs(\n props: EntityPageBreadcrumbsProps,\n) {\n const { items } = props\n return (\n <Breadcrumbs\n items={items}\n sx={entityPageBreadcrumbStyle}\n maxBreadcrumbLength={ENTITY_PAGE_MAX_BREADCRUMB_LENGTH}\n iconVariant=\"outlined\"\n />\n )\n}\n"],"mappings":";;;AAWA,IAAM,IAAoC,IACpC,IAAyB,WAQzB,IAAqC;CACzC,WAAW;CACX,SAAS;CACR,yBAA0B;EAR3B,YAAY;EACZ,YAAY;EACZ,OAAO;CAMoB;CAC1B,mBAAoB,EACnB,aAAa,EACX,OAAO,EACT,EACF;CACC,sBAAuB;EACtB,YAAY;EACZ,OAAO;CACT;AACF;AAEA,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,aAAU;CAClB,OACE,kBAAC,GAAD;EACS;EACP,IAAI;EACJ,qBAAqB;EACrB,aAAY;CACb,CAAA;AAEL"}
@@ -1,10 +1,17 @@
1
+ import { FileSelectionConstraints } from '@/components/file/upload/validateFileSelection';
1
2
  import { UploaderState } from '@/utils/hooks/useUploadFileEntity/useUploadFiles';
2
3
  export type BasicFileHandleUploadProps = {
3
4
  /**
4
- * Whether to allow uploading multiple files.
5
- * Currently, only single file upload is supported by this UI component.
5
+ * Whether to allow uploading multiple files at once.
6
6
  */
7
- allowMultipleUpload: false;
7
+ allowMultipleUpload: boolean;
8
+ /**
9
+ * When `allowMultipleUpload` is true, whether to skip the Files/Folder menu and open the
10
+ * (multi-select) file browser directly, rather than offering a folder upload option.
11
+ * Has no effect when `allowMultipleUpload` is false.
12
+ * @default false
13
+ */
14
+ disableFolderUpload?: boolean;
8
15
  /**
9
16
  * Whether to disable "drag-and-drop to upload" functionality.
10
17
  * Currently, drag-and-drop cannot be enabled.
@@ -15,7 +22,31 @@ export type BasicFileHandleUploadProps = {
15
22
  /** Callback that is invoked when component is ready to upload */
16
23
  onUploadReady?: () => void;
17
24
  /** Callback that is invoked when an individual upload is complete */
18
- onFileUploadComplete?: (fileHandleIds: string) => void;
25
+ onFileUploadComplete?: (fileHandleId: string, file: File) => void;
26
+ /**
27
+ * If provided, files whose type is not included in this list are rejected before upload.
28
+ */
29
+ acceptedContentTypes?: FileSelectionConstraints['acceptedContentTypes'];
30
+ /**
31
+ * If provided, files larger than this are rejected before upload.
32
+ */
33
+ maxFileSizeBytes?: FileSelectionConstraints['maxFileSizeBytes'];
34
+ /**
35
+ * If provided, a selection that would bring the total file count (see `currentFileCount`)
36
+ * above this value is rejected before upload.
37
+ */
38
+ maxFiles?: FileSelectionConstraints['maxFiles'];
39
+ /**
40
+ * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.
41
+ * @default 0
42
+ */
43
+ currentFileCount?: FileSelectionConstraints['currentFileCount'];
44
+ /**
45
+ * Invoked when a file selection is rejected due to `acceptedContentTypes`, `maxFileSizeBytes`,
46
+ * or `maxFiles`. Invoked with `null` when a subsequent selection is valid, so the caller can
47
+ * clear a previously displayed error.
48
+ */
49
+ onValidationError?: (message: string | null) => void;
19
50
  };
20
51
  export type FileUploadHandle = {
21
52
  /** Programmatically add files to the upload (e.g. on drag & drop) */
@@ -1 +1 @@
1
- {"version":3,"file":"BasicFileHandleUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EAEd,MAAM,kDAAkD,CAAA;AAIzD,MAAM,MAAM,0BAA0B,GAAG;IACvC;;;OAGG;IACH,mBAAmB,EAAE,KAAK,CAAA;IAC1B;;;OAGG;IACH,kBAAkB,EAAE,IAAI,CAAA;IACxB,sEAAsE;IACtE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC9C,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAA;CACvD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qEAAqE;IACrE,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;CACnD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,yHAoDhC,CAAA"}
1
+ {"version":3,"file":"BasicFileHandleUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAA;AACzF,OAAO,EACL,aAAa,EAEd,MAAM,kDAAkD,CAAA;AAIzD,MAAM,MAAM,0BAA0B,GAAG;IACvC;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAA;IAC5B;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;OAGG;IACH,kBAAkB,EAAE,IAAI,CAAA;IACxB,sEAAsE;IACtE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC9C,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IACjE;;OAEG;IACH,oBAAoB,CAAC,EAAE,wBAAwB,CAAC,sBAAsB,CAAC,CAAA;IACvE;;OAEG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAA;IAC/D;;;OAGG;IACH,QAAQ,CAAC,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAA;IAC/C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAA;IAC/D;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CACrD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qEAAqE;IACrE,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;CACnD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,yHAgEhC,CAAA"}
@@ -1,27 +1,33 @@
1
- import { useUploadFiles as e } from "../../../utils/hooks/useUploadFileEntity/useUploadFiles.js";
2
- import t from "./MultiFileUploadProgress.js";
3
- import n from "./UploadFilePanel.js";
1
+ import e from "./MultiFileUploadProgress.js";
2
+ import t from "./UploadFilePanel.js";
3
+ import { useUploadFiles as n } from "../../../utils/hooks/useUploadFileEntity/useUploadFiles.js";
4
4
  import { forwardRef as r, useEffect as i, useImperativeHandle as a } from "react";
5
5
  import { noop as o } from "lodash-es";
6
6
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
7
  //#region src/components/file/upload/BasicFileHandleUpload.tsx
8
8
  var l = r(function(r, l) {
9
- let { allowMultipleUpload: u, onStateChange: d = o, onUploadReady: f = o, onFileUploadComplete: p = o } = r, { startUpload: m, state: h, uploadProgress: g } = e({ onUploadComplete: (e, t) => (p(t), Promise.resolve()) });
9
+ let { allowMultipleUpload: u, disableFolderUpload: d = !1, onStateChange: f = o, onUploadReady: p = o, onFileUploadComplete: m = o, acceptedContentTypes: h, maxFileSizeBytes: g, maxFiles: _, currentFileCount: v, onValidationError: y } = r, { startUpload: b, state: x, uploadProgress: S } = n({ onUploadComplete: (e, t) => (m(t, e.file), Promise.resolve()) });
10
10
  i(() => {
11
- d(h);
12
- }, [h, d]), i(() => {
13
- f();
14
- }, [f]);
15
- function _(e) {
16
- m(...Array.from(e).map((e) => ({ file: e })));
11
+ f(x);
12
+ }, [x, f]), i(() => {
13
+ p();
14
+ }, [p]);
15
+ function C(e) {
16
+ b(...Array.from(e).map((e) => ({ file: e })));
17
17
  }
18
- return a(l, () => ({ handleUploads: _ })), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s(n, {
19
- onUploadFileList: _,
18
+ return a(l, () => ({ handleUploads: C })), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s(t, {
19
+ onUploadFileList: C,
20
20
  allowMultipleFiles: u,
21
- disableDragAndDrop: !0
22
- }), /* @__PURE__ */ s(t, {
23
- uploaderState: h,
24
- uploadProgress: g
21
+ hideFolderOption: d,
22
+ disableDragAndDrop: !0,
23
+ acceptedContentTypes: h,
24
+ maxFileSizeBytes: g,
25
+ maxFiles: _,
26
+ currentFileCount: v,
27
+ onValidationError: y
28
+ }), /* @__PURE__ */ s(e, {
29
+ uploaderState: x,
30
+ uploadProgress: S
25
31
  })] });
26
32
  });
27
33
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"BasicFileHandleUpload.js","names":[],"sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport {\n UploaderState,\n useUploadFiles,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFiles'\nimport { noop } from 'lodash-es'\nimport { ForwardedRef, forwardRef, useEffect, useImperativeHandle } from 'react'\n\nexport type BasicFileHandleUploadProps = {\n /**\n * Whether to allow uploading multiple files.\n * Currently, only single file upload is supported by this UI component.\n */\n allowMultipleUpload: false\n /**\n * Whether to disable \"drag-and-drop to upload\" functionality.\n * Currently, drag-and-drop cannot be enabled.\n */\n disableDragAndDrop: true\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: UploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n /** Callback that is invoked when an individual upload is complete */\n onFileUploadComplete?: (fileHandleIds: string) => void\n}\n\nexport type FileUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\n/**\n * BasicFileHandleUpload is a component that supports uploading a file to the default Synapse S3 bucket and creating a\n * file handle, which can only be accessed the system itself and the user uploading the file.\n */\nexport const BasicFileHandleUpload = forwardRef(function FileHandleUpload(\n props: BasicFileHandleUploadProps,\n ref: ForwardedRef<FileUploadHandle>,\n) {\n const {\n allowMultipleUpload,\n onStateChange = noop,\n onUploadReady = noop,\n onFileUploadComplete = noop,\n } = props\n\n const { startUpload, state, uploadProgress } = useUploadFiles({\n onUploadComplete: (_, fileHandleId) => {\n onFileUploadComplete(fileHandleId)\n return Promise.resolve()\n },\n })\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n onUploadReady()\n }, [onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n const args = Array.from(fileList).map(file => {\n return {\n file,\n }\n })\n startUpload(...args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n return (\n <div>\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={allowMultipleUpload}\n disableDragAndDrop={true}\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;AAqCA,IAAa,IAAwB,EAAW,SAC9C,GACA,GACA;CACA,IAAM,EACJ,wBACA,mBAAgB,GAChB,mBAAgB,GAChB,0BAAuB,MACrB,GAEE,EAAE,gBAAa,UAAO,sBAAmB,EAAe,EAC5D,mBAAmB,GAAG,OACpB,EAAqB,CAAY,GAC1B,QAAQ,QAAQ,GAE3B,CAAC;CAMD,AAJA,QAAgB;EACd,EAAc,CAAK;CACrB,GAAG,CAAC,GAAO,CAAa,CAAC,GAEzB,QAAgB;EACd,EAAc;CAChB,GAAG,CAAC,CAAa,CAAC;CAElB,SAAS,EAAe,GAA2B;EAMjD,EAAY,GALC,MAAM,KAAK,CAAQ,EAAE,KAAI,OAC7B,EACL,QACF,EAEa,CAAI;CACrB;CAMA,OAJA,EAAoB,UAAY,EAC9B,eAAe,EACjB,EAAE,GAGA,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,kBAAkB;EAClB,oBAAoB;EACpB,oBAAoB;CACrB,CAAA,GACD,kBAAC,GAAD;EACE,eAAe;EACC;CACjB,CAAA,CACE,EAAA,CAAA;AAET,CAAC"}
1
+ {"version":3,"file":"BasicFileHandleUpload.js","names":[],"sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport { FileSelectionConstraints } from '@/components/file/upload/validateFileSelection'\nimport {\n UploaderState,\n useUploadFiles,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFiles'\nimport { noop } from 'lodash-es'\nimport { ForwardedRef, forwardRef, useEffect, useImperativeHandle } from 'react'\n\nexport type BasicFileHandleUploadProps = {\n /**\n * Whether to allow uploading multiple files at once.\n */\n allowMultipleUpload: boolean\n /**\n * When `allowMultipleUpload` is true, whether to skip the Files/Folder menu and open the\n * (multi-select) file browser directly, rather than offering a folder upload option.\n * Has no effect when `allowMultipleUpload` is false.\n * @default false\n */\n disableFolderUpload?: boolean\n /**\n * Whether to disable \"drag-and-drop to upload\" functionality.\n * Currently, drag-and-drop cannot be enabled.\n */\n disableDragAndDrop: true\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: UploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n /** Callback that is invoked when an individual upload is complete */\n onFileUploadComplete?: (fileHandleId: string, file: File) => void\n /**\n * If provided, files whose type is not included in this list are rejected before upload.\n */\n acceptedContentTypes?: FileSelectionConstraints['acceptedContentTypes']\n /**\n * If provided, files larger than this are rejected before upload.\n */\n maxFileSizeBytes?: FileSelectionConstraints['maxFileSizeBytes']\n /**\n * If provided, a selection that would bring the total file count (see `currentFileCount`)\n * above this value is rejected before upload.\n */\n maxFiles?: FileSelectionConstraints['maxFiles']\n /**\n * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.\n * @default 0\n */\n currentFileCount?: FileSelectionConstraints['currentFileCount']\n /**\n * Invoked when a file selection is rejected due to `acceptedContentTypes`, `maxFileSizeBytes`,\n * or `maxFiles`. Invoked with `null` when a subsequent selection is valid, so the caller can\n * clear a previously displayed error.\n */\n onValidationError?: (message: string | null) => void\n}\n\nexport type FileUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\n/**\n * BasicFileHandleUpload is a component that supports uploading a file to the default Synapse S3 bucket and creating a\n * file handle, which can only be accessed the system itself and the user uploading the file.\n */\nexport const BasicFileHandleUpload = forwardRef(function FileHandleUpload(\n props: BasicFileHandleUploadProps,\n ref: ForwardedRef<FileUploadHandle>,\n) {\n const {\n allowMultipleUpload,\n disableFolderUpload = false,\n onStateChange = noop,\n onUploadReady = noop,\n onFileUploadComplete = noop,\n acceptedContentTypes,\n maxFileSizeBytes,\n maxFiles,\n currentFileCount,\n onValidationError,\n } = props\n\n const { startUpload, state, uploadProgress } = useUploadFiles({\n onUploadComplete: (preparedFile, fileHandleId) => {\n onFileUploadComplete(fileHandleId, preparedFile.file)\n return Promise.resolve()\n },\n })\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n onUploadReady()\n }, [onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n const args = Array.from(fileList).map(file => {\n return {\n file,\n }\n })\n startUpload(...args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n return (\n <div>\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={allowMultipleUpload}\n hideFolderOption={disableFolderUpload}\n disableDragAndDrop={true}\n acceptedContentTypes={acceptedContentTypes}\n maxFileSizeBytes={maxFileSizeBytes}\n maxFiles={maxFiles}\n currentFileCount={currentFileCount}\n onValidationError={onValidationError}\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;AAoEA,IAAa,IAAwB,EAAW,SAC9C,GACA,GACA;CACA,IAAM,EACJ,wBACA,yBAAsB,IACtB,mBAAgB,GAChB,mBAAgB,GAChB,0BAAuB,GACvB,yBACA,qBACA,aACA,qBACA,yBACE,GAEE,EAAE,gBAAa,UAAO,sBAAmB,EAAe,EAC5D,mBAAmB,GAAc,OAC/B,EAAqB,GAAc,EAAa,IAAI,GAC7C,QAAQ,QAAQ,GAE3B,CAAC;CAMD,AAJA,QAAgB;EACd,EAAc,CAAK;CACrB,GAAG,CAAC,GAAO,CAAa,CAAC,GAEzB,QAAgB;EACd,EAAc;CAChB,GAAG,CAAC,CAAa,CAAC;CAElB,SAAS,EAAe,GAA2B;EAMjD,EAAY,GALC,MAAM,KAAK,CAAQ,EAAE,KAAI,OAC7B,EACL,QACF,EAEa,CAAI;CACrB;CAMA,OAJA,EAAoB,UAAY,EAC9B,eAAe,EACjB,EAAE,GAGA,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,kBAAkB;EAClB,oBAAoB;EACpB,kBAAkB;EAClB,oBAAoB;EACE;EACJ;EACR;EACQ;EACC;CACpB,CAAA,GACD,kBAAC,GAAD;EACE,eAAe;EACC;CACjB,CAAA,CACE,EAAA,CAAA;AAET,CAAC"}
@@ -1,5 +1,5 @@
1
- import e from "../../../utils/hooks/useUploadFileEntity/getActiveUploadCount.js";
2
- import { FileUploadProgress as t } from "../../EntityUpload/FileUploadProgress.js";
1
+ import { FileUploadProgress as e } from "../../EntityUpload/FileUploadProgress.js";
2
+ import t from "../../../utils/hooks/useUploadFileEntity/getActiveUploadCount.js";
3
3
  import { Fragment as n, jsx as r, jsxs as i } from "react/jsx-runtime";
4
4
  import a from "@mui/material/Typography";
5
5
  import o from "pluralize";
@@ -11,7 +11,7 @@ var u = 24;
11
11
  function d(d) {
12
12
  let { uploaderState: f, uploadProgress: p } = d;
13
13
  if (p.length === 0) return null;
14
- let m = e(p.map((e) => e.status)), h = p.filter((e) => e.status === "COMPLETE").length;
14
+ let m = t(p.map((e) => e.status)), h = p.filter((e) => e.status === "COMPLETE").length;
15
15
  return /* @__PURE__ */ i(c, {
16
16
  sx: {
17
17
  px: `${u}px`,
@@ -49,15 +49,15 @@ function d(d) {
49
49
  height: 205,
50
50
  itemCount: p.length,
51
51
  width: "100%",
52
- children: ({ index: e, style: n }) => {
53
- let i = p[e], a = i.file.webkitRelativePath || i.file.name, o = i.file.size, s = o * (i.progress.value / i.progress.total);
52
+ children: ({ index: t, style: n }) => {
53
+ let i = p[t], a = i.file.webkitRelativePath || i.file.name, o = i.file.size, s = o * (i.progress.value / i.progress.total);
54
54
  return /* @__PURE__ */ r("div", {
55
55
  style: {
56
56
  ...n,
57
57
  width: `calc(100% - ${u * 2}px)`,
58
58
  margin: `0px ${u}px`
59
59
  },
60
- children: /* @__PURE__ */ r(t, {
60
+ children: /* @__PURE__ */ r(e, {
61
61
  fileName: a,
62
62
  status: i.status,
63
63
  totalSizeInBytes: o,
@@ -1,4 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
+ import { FileSelectionConstraints } from './validateFileSelection';
2
3
  export type UploadFilePanelProps = {
3
4
  /**
4
5
  * An optional message that appears in the upload panel (e.g. to describe the upload destination).
@@ -32,6 +33,37 @@ export type UploadFilePanelProps = {
32
33
  * @default false
33
34
  */
34
35
  disableDragAndDrop?: boolean;
36
+ /**
37
+ * When `allowMultipleFiles` is true, whether to skip the Files/Folder menu and open the
38
+ * (multi-select) file browser directly. Has no effect when `allowMultipleFiles` is false.
39
+ * @default false
40
+ */
41
+ hideFolderOption?: boolean;
42
+ /**
43
+ * If provided, files whose `type` is not included in this list are rejected before upload,
44
+ * and used to constrain the file picker via the input's `accept` attribute.
45
+ */
46
+ acceptedContentTypes?: FileSelectionConstraints['acceptedContentTypes'];
47
+ /**
48
+ * If provided, files larger than this are rejected before upload.
49
+ */
50
+ maxFileSizeBytes?: FileSelectionConstraints['maxFileSizeBytes'];
51
+ /**
52
+ * If provided, a selection that would bring the total file count (see `currentFileCount`)
53
+ * above this value is rejected before upload.
54
+ */
55
+ maxFiles?: FileSelectionConstraints['maxFiles'];
56
+ /**
57
+ * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.
58
+ * @default 0
59
+ */
60
+ currentFileCount?: FileSelectionConstraints['currentFileCount'];
61
+ /**
62
+ * Invoked when a file selection is rejected due to `acceptedContentTypes`, `maxFileSizeBytes`,
63
+ * or `maxFiles`, with a human-readable description of the violation. Invoked with `null` when
64
+ * a subsequent selection is valid, so the caller can clear a previously displayed error.
65
+ */
66
+ onValidationError?: (message: string | null) => void;
35
67
  };
36
68
  /**
37
69
  * Provides a generic UI component to upload one or more files.
@@ -1 +1 @@
1
- {"version":3,"file":"UploadFilePanel.d.ts","sourceRoot":"","sources":["../../../../src/components/file/upload/UploadFilePanel.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,SAAS,EAAoB,MAAM,OAAO,CAAA;AAW/D,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;OAGG;IACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IAClD;;OAEG;IACH,kBAAkB,EAAE,OAAO,CAAA;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAuIlE"}
1
+ {"version":3,"file":"UploadFilePanel.d.ts","sourceRoot":"","sources":["../../../../src/components/file/upload/UploadFilePanel.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAc,SAAS,EAAoB,MAAM,OAAO,CAAA;AAE/D,OAAO,EACL,wBAAwB,EAEzB,MAAM,yBAAyB,CAAA;AAOhC,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;OAGG;IACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IAClD;;OAEG;IACH,kBAAkB,EAAE,OAAO,CAAA;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,wBAAwB,CAAC,sBAAsB,CAAC,CAAA;IACvE;;OAEG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAA;IAC/D;;;OAGG;IACH,QAAQ,CAAC,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAA;IAC/C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAA;IAC/D;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CACrD,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAiKlE"}
@@ -1,24 +1,39 @@
1
1
  import { SynapseSpinner as e } from "../../LoadingScreen/LoadingScreen.js";
2
- import { useRef as t, useState as n } from "react";
3
- import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
4
- import o from "@mui/material/Link";
5
- import s from "@mui/material/Typography";
6
- import c from "@mui/material/Stack";
7
- import l from "@mui/material/Menu";
8
- import u from "@mui/material/Fade";
9
- import d from "@mui/material/MenuItem";
2
+ import { validateFileSelection as t } from "./validateFileSelection.js";
3
+ import { useRef as n, useState as r } from "react";
4
+ import { noop as i } from "lodash-es";
5
+ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ import c from "@mui/material/Link";
7
+ import l from "@mui/material/Typography";
8
+ import u from "@mui/material/Stack";
9
+ import d from "@mui/material/Fade";
10
+ import f from "@mui/material/Menu";
11
+ import p from "@mui/material/MenuItem";
10
12
  //#region src/components/file/upload/UploadFilePanel.tsx
11
- var f = {
13
+ var m = {
12
14
  pointerEvents: "none",
13
15
  filter: "opacity(33%)"
14
16
  };
15
- function p(p) {
16
- let { onUploadFileList: m, allowMultipleFiles: h, isLoading: g = !1, loadingText: _ = "Loading...", disabled: v = !1, message: y, disableDragAndDrop: b = !1 } = p, x = t(null), S = t(null), [C, w] = n(null), T = !!C, E = (e) => {
17
- h ? w(e.currentTarget) : x.current.click();
18
- }, D = () => {
19
- w(null);
17
+ function h(h) {
18
+ let { onUploadFileList: g, allowMultipleFiles: _, isLoading: v = !1, loadingText: y = "Loading...", disabled: b = !1, message: x, disableDragAndDrop: S = !1, hideFolderOption: C = !1, acceptedContentTypes: w, maxFileSizeBytes: T, maxFiles: E, currentFileCount: D = 0, onValidationError: O = i } = h, k = n(null), A = n(null), [j, M] = r(null), N = !!j, P = (e) => {
19
+ !_ || C ? k.current.click() : M(e.currentTarget);
20
+ }, F = () => {
21
+ M(null);
20
22
  };
21
- return /* @__PURE__ */ a(c, {
23
+ function I(e) {
24
+ let n = t(Array.from(e), {
25
+ acceptedContentTypes: w,
26
+ maxFileSizeBytes: T,
27
+ maxFiles: E,
28
+ currentFileCount: D
29
+ });
30
+ if (n) {
31
+ O(n);
32
+ return;
33
+ }
34
+ O(null), g(e);
35
+ }
36
+ return /* @__PURE__ */ s(u, {
22
37
  sx: {
23
38
  py: 3,
24
39
  gap: 1,
@@ -28,50 +43,51 @@ function p(p) {
28
43
  border: "1px dashed #D9D9D9",
29
44
  backgroundColor: "grey.100",
30
45
  textAlign: "center",
31
- ...v ? f : {}
46
+ ...b ? m : {}
32
47
  },
33
- children: [g && /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("div", { children: /* @__PURE__ */ i(e, { size: 40 }) }), /* @__PURE__ */ i(s, {
48
+ children: [v && /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o("div", { children: /* @__PURE__ */ o(e, { size: 40 }) }), /* @__PURE__ */ o(l, {
34
49
  variant: "smallText1",
35
50
  sx: { my: 2 },
36
- children: _
37
- })] }), !g && /* @__PURE__ */ a(r, { children: [
38
- /* @__PURE__ */ i("img", { src: "https://s3.us-east-1.amazonaws.com/static.synapse.org/images/upload_illustration.svg" }),
39
- /* @__PURE__ */ i("input", {
51
+ children: y
52
+ })] }), !v && /* @__PURE__ */ s(a, { children: [
53
+ /* @__PURE__ */ o("img", { src: "https://s3.us-east-1.amazonaws.com/static.synapse.org/images/upload_illustration.svg" }),
54
+ /* @__PURE__ */ o("input", {
40
55
  type: "file",
41
56
  id: "filesToUpload",
42
57
  name: "file upload",
43
58
  style: { display: "none" },
44
59
  "aria-hidden": "true",
45
- multiple: h,
46
- ref: x,
60
+ multiple: _,
61
+ accept: w?.join(","),
62
+ ref: k,
47
63
  onChange: (e) => {
48
- e.target.files != null && m(e.target.files);
64
+ e.target.files != null && (I(e.target.files), e.target.value = "");
49
65
  }
50
66
  }),
51
- /* @__PURE__ */ i("input", {
67
+ /* @__PURE__ */ o("input", {
52
68
  type: "file",
53
69
  id: "folderToUpload",
54
70
  name: "folder upload",
55
71
  style: { display: "none" },
56
72
  "aria-hidden": "true",
57
- ref: S,
73
+ ref: A,
58
74
  onChange: (e) => {
59
- e.target.files != null && m(e.target.files);
75
+ e.target.files != null && (I(e.target.files), e.target.value = "");
60
76
  },
61
77
  webkitdirectory: "true"
62
78
  }),
63
- /* @__PURE__ */ a(s, {
79
+ /* @__PURE__ */ s(l, {
64
80
  variant: "body1",
65
81
  sx: { my: 2 },
66
- children: [/* @__PURE__ */ i(o, {
67
- onClick: E,
82
+ children: [/* @__PURE__ */ o(c, {
83
+ onClick: P,
68
84
  children: "Click to upload"
69
- }), !b && " or drag and drop"]
85
+ }), !S && " or drag and drop"]
70
86
  }),
71
- /* @__PURE__ */ a(l, {
72
- anchorEl: C,
73
- open: T,
74
- onClose: D,
87
+ /* @__PURE__ */ s(f, {
88
+ anchorEl: j,
89
+ open: N,
90
+ onClose: F,
75
91
  anchorOrigin: {
76
92
  vertical: "bottom",
77
93
  horizontal: "left"
@@ -80,24 +96,24 @@ function p(p) {
80
96
  vertical: "top",
81
97
  horizontal: "left"
82
98
  },
83
- slots: { transition: u },
84
- children: [/* @__PURE__ */ i(d, {
99
+ slots: { transition: d },
100
+ children: [/* @__PURE__ */ o(p, {
85
101
  onClick: () => {
86
- D(), x.current.click();
102
+ F(), k.current.click();
87
103
  },
88
104
  children: "Files"
89
- }), /* @__PURE__ */ i(d, {
105
+ }), /* @__PURE__ */ o(p, {
90
106
  onClick: () => {
91
- D(), S.current.click();
107
+ F(), A.current.click();
92
108
  },
93
109
  children: "Folder"
94
110
  })]
95
111
  }),
96
- y
112
+ x
97
113
  ] })]
98
114
  });
99
115
  }
100
116
  //#endregion
101
- export { p as default };
117
+ export { h as default };
102
118
 
103
119
  //# sourceMappingURL=UploadFilePanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"UploadFilePanel.js","names":[],"sources":["../../../../src/components/file/upload/UploadFilePanel.tsx"],"sourcesContent":["import Link from '@mui/material/Link'\nimport Stack from '@mui/material/Stack'\nimport { SxProps } from '@mui/material/styles'\nimport Typography from '@mui/material/Typography'\nimport { MouseEvent, ReactNode, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../../LoadingScreen/LoadingScreen'\nimport Menu from '@mui/material/Menu'\nimport Fade from '@mui/material/Fade'\nimport MenuItem from '@mui/material/MenuItem'\n\nconst disabledUploadPaneSx: SxProps = {\n pointerEvents: 'none',\n filter: 'opacity(33%)',\n}\n\nexport type UploadFilePanelProps = {\n /**\n * An optional message that appears in the upload panel (e.g. to describe the upload destination).\n */\n message?: ReactNode\n /**\n * Called when upload is invoked.\n * @param files\n */\n onUploadFileList: (files: ArrayLike<File>) => void\n /**\n * If true, allow uploading multiple files. Otherwise, only one file may be uploaded.\n */\n allowMultipleFiles: boolean\n /** Whether the component should show a loader.\n * @default false\n */\n isLoading?: boolean\n /**\n * Text to show when `isLoading` is true.\n * @default 'Loading...'\n */\n loadingText?: string\n /**\n * Whether to disable the upload panel (e.g. when the project storage is full).\n * @default false\n */\n disabled?: boolean\n /**\n * Whether to enable drag-and-drop to upload functionality.\n * @default false\n */\n disableDragAndDrop?: boolean\n}\n\n/**\n * Provides a generic UI component to upload one or more files.\n * @param props\n * @constructor\n */\nexport default function UploadFilePanel(props: UploadFilePanelProps) {\n const {\n onUploadFileList,\n allowMultipleFiles,\n isLoading = false,\n loadingText = 'Loading...',\n disabled = false,\n message,\n disableDragAndDrop = false,\n } = props\n const fileInputRef = useRef<HTMLInputElement>(null)\n const folderInputRef = useRef<HTMLInputElement>(null)\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)\n const open = Boolean(anchorEl)\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n if (!allowMultipleFiles) {\n fileInputRef.current!.click()\n } else {\n setAnchorEl(event.currentTarget)\n }\n }\n const handleClose = () => {\n setAnchorEl(null)\n }\n\n return (\n <Stack\n sx={{\n py: 3,\n gap: 1,\n justifyContent: 'center',\n alignItems: 'center',\n width: '100%',\n border: '1px dashed #D9D9D9',\n backgroundColor: 'grey.100',\n textAlign: 'center',\n ...(disabled ? disabledUploadPaneSx : {}),\n }}\n >\n {isLoading && (\n <>\n <div>\n <SynapseSpinner size={40} />\n </div>\n <Typography\n variant={'smallText1'}\n sx={{\n my: 2,\n }}\n >\n {loadingText}\n </Typography>\n </>\n )}\n {!isLoading && (\n <>\n <img\n src={\n 'https://s3.us-east-1.amazonaws.com/static.synapse.org/images/upload_illustration.svg'\n }\n />\n {/* File input */}\n <input\n type=\"file\"\n id=\"filesToUpload\"\n name=\"file upload\"\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n multiple={allowMultipleFiles}\n ref={fileInputRef}\n onChange={e => {\n if (e.target.files != null) {\n onUploadFileList(e.target.files)\n }\n }}\n />\n {/* Folder input */}\n <input\n type=\"file\"\n id=\"folderToUpload\"\n name=\"folder upload\"\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n ref={folderInputRef}\n onChange={e => {\n if (e.target.files != null) {\n onUploadFileList(e.target.files)\n }\n }}\n // @ts-expect-error - webkitdirectory is not included in the InputHTMLAttributes type\n webkitdirectory=\"true\"\n />\n\n <Typography\n variant={'body1'}\n sx={{\n my: 2,\n }}\n >\n <Link onClick={handleClick}>Click to upload</Link>\n {!disableDragAndDrop && ' or drag and drop'}\n </Typography>\n <Menu\n anchorEl={anchorEl}\n open={open}\n onClose={handleClose}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n transformOrigin={{ vertical: 'top', horizontal: 'left' }}\n slots={{\n transition: Fade,\n }}\n >\n <MenuItem\n onClick={() => {\n handleClose()\n fileInputRef.current!.click()\n }}\n >\n Files\n </MenuItem>\n <MenuItem\n onClick={() => {\n handleClose()\n folderInputRef.current!.click()\n }}\n >\n Folder\n </MenuItem>\n </Menu>\n {message}\n </>\n )}\n </Stack>\n )\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAM,IAAgC;CACpC,eAAe;CACf,QAAQ;AACV;AA0CA,SAAwB,EAAgB,GAA6B;CACnE,IAAM,EACJ,qBACA,uBACA,eAAY,IACZ,iBAAc,cACd,cAAW,IACX,YACA,wBAAqB,OACnB,GACE,IAAe,EAAyB,IAAI,GAC5C,IAAiB,EAAyB,IAAI,GAC9C,CAAC,GAAU,KAAe,EAA6B,IAAI,GAC3D,IAAO,EAAQ,GAEf,KAAe,MAAmC;EACtD,AAAK,IAGH,EAAY,EAAM,aAAa,IAF/B,EAAa,QAAS,MAAM;CAIhC,GACM,UAAoB;EACxB,EAAY,IAAI;CAClB;CAEA,OACE,kBAAC,GAAD;EACE,IAAI;GACF,IAAI;GACJ,KAAK;GACL,gBAAgB;GAChB,YAAY;GACZ,OAAO;GACP,QAAQ;GACR,iBAAiB;GACjB,WAAW;GACX,GAAI,IAAW,IAAuB,CAAC;EACzC;YAXF,CAaG,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAA,UACE,kBAAC,GAAD,EAAgB,MAAM,GAAK,CAAA,EACxB,CAAA,GACL,kBAAC,GAAD;GACE,SAAS;GACT,IAAI,EACF,IAAI,EACN;aAEC;EACS,CAAA,CACZ,EAAA,CAAA,GAEH,CAAC,KACA,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,OAAD,EACE,KACE,uFAEH,CAAA;GAED,kBAAC,SAAD;IACE,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO,EAAE,SAAS,OAAO;IACzB,eAAY;IACZ,UAAU;IACV,KAAK;IACL,WAAU,MAAK;KACb,AAAI,EAAE,OAAO,SAAS,QACpB,EAAiB,EAAE,OAAO,KAAK;IAEnC;GACD,CAAA;GAED,kBAAC,SAAD;IACE,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO,EAAE,SAAS,OAAO;IACzB,eAAY;IACZ,KAAK;IACL,WAAU,MAAK;KACb,AAAI,EAAE,OAAO,SAAS,QACpB,EAAiB,EAAE,OAAO,KAAK;IAEnC;IAEA,iBAAgB;GACjB,CAAA;GAED,kBAAC,GAAD;IACE,SAAS;IACT,IAAI,EACF,IAAI,EACN;cAJF,CAME,kBAAC,GAAD;KAAM,SAAS;eAAa;IAAqB,CAAA,GAChD,CAAC,KAAsB,mBACd;;GACZ,kBAAC,GAAD;IACY;IACJ;IACN,SAAS;IACT,cAAc;KAAE,UAAU;KAAU,YAAY;IAAO;IACvD,iBAAiB;KAAE,UAAU;KAAO,YAAY;IAAO;IACvD,OAAO,EACL,YAAY,EACd;cARF,CAUE,kBAAC,GAAD;KACE,eAAe;MAEb,AADA,EAAY,GACZ,EAAa,QAAS,MAAM;KAC9B;eACD;IAES,CAAA,GACV,kBAAC,GAAD;KACE,eAAe;MAEb,AADA,EAAY,GACZ,EAAe,QAAS,MAAM;KAChC;eACD;IAES,CAAA,CACN;;GACL;EACD,EAAA,CAAA,CAEC;;AAEX"}
1
+ {"version":3,"file":"UploadFilePanel.js","names":[],"sources":["../../../../src/components/file/upload/UploadFilePanel.tsx"],"sourcesContent":["import Fade from '@mui/material/Fade'\nimport Link from '@mui/material/Link'\nimport Menu from '@mui/material/Menu'\nimport MenuItem from '@mui/material/MenuItem'\nimport Stack from '@mui/material/Stack'\nimport { SxProps } from '@mui/material/styles'\nimport Typography from '@mui/material/Typography'\nimport { noop } from 'lodash-es'\nimport { MouseEvent, ReactNode, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../../LoadingScreen/LoadingScreen'\nimport {\n FileSelectionConstraints,\n validateFileSelection,\n} from './validateFileSelection'\n\nconst disabledUploadPaneSx: SxProps = {\n pointerEvents: 'none',\n filter: 'opacity(33%)',\n}\n\nexport type UploadFilePanelProps = {\n /**\n * An optional message that appears in the upload panel (e.g. to describe the upload destination).\n */\n message?: ReactNode\n /**\n * Called when upload is invoked.\n * @param files\n */\n onUploadFileList: (files: ArrayLike<File>) => void\n /**\n * If true, allow uploading multiple files. Otherwise, only one file may be uploaded.\n */\n allowMultipleFiles: boolean\n /** Whether the component should show a loader.\n * @default false\n */\n isLoading?: boolean\n /**\n * Text to show when `isLoading` is true.\n * @default 'Loading...'\n */\n loadingText?: string\n /**\n * Whether to disable the upload panel (e.g. when the project storage is full).\n * @default false\n */\n disabled?: boolean\n /**\n * Whether to enable drag-and-drop to upload functionality.\n * @default false\n */\n disableDragAndDrop?: boolean\n /**\n * When `allowMultipleFiles` is true, whether to skip the Files/Folder menu and open the\n * (multi-select) file browser directly. Has no effect when `allowMultipleFiles` is false.\n * @default false\n */\n hideFolderOption?: boolean\n /**\n * If provided, files whose `type` is not included in this list are rejected before upload,\n * and used to constrain the file picker via the input's `accept` attribute.\n */\n acceptedContentTypes?: FileSelectionConstraints['acceptedContentTypes']\n /**\n * If provided, files larger than this are rejected before upload.\n */\n maxFileSizeBytes?: FileSelectionConstraints['maxFileSizeBytes']\n /**\n * If provided, a selection that would bring the total file count (see `currentFileCount`)\n * above this value is rejected before upload.\n */\n maxFiles?: FileSelectionConstraints['maxFiles']\n /**\n * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.\n * @default 0\n */\n currentFileCount?: FileSelectionConstraints['currentFileCount']\n /**\n * Invoked when a file selection is rejected due to `acceptedContentTypes`, `maxFileSizeBytes`,\n * or `maxFiles`, with a human-readable description of the violation. Invoked with `null` when\n * a subsequent selection is valid, so the caller can clear a previously displayed error.\n */\n onValidationError?: (message: string | null) => void\n}\n\n/**\n * Provides a generic UI component to upload one or more files.\n * @param props\n * @constructor\n */\nexport default function UploadFilePanel(props: UploadFilePanelProps) {\n const {\n onUploadFileList,\n allowMultipleFiles,\n isLoading = false,\n loadingText = 'Loading...',\n disabled = false,\n message,\n disableDragAndDrop = false,\n hideFolderOption = false,\n acceptedContentTypes,\n maxFileSizeBytes,\n maxFiles,\n currentFileCount = 0,\n onValidationError = noop,\n } = props\n const fileInputRef = useRef<HTMLInputElement>(null)\n const folderInputRef = useRef<HTMLInputElement>(null)\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)\n const open = Boolean(anchorEl)\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n if (!allowMultipleFiles || hideFolderOption) {\n fileInputRef.current!.click()\n } else {\n setAnchorEl(event.currentTarget)\n }\n }\n const handleClose = () => {\n setAnchorEl(null)\n }\n\n function handleFileListSelected(fileList: FileList) {\n const files = Array.from(fileList)\n const validationError = validateFileSelection(files, {\n acceptedContentTypes,\n maxFileSizeBytes,\n maxFiles,\n currentFileCount,\n })\n if (validationError) {\n onValidationError(validationError)\n return\n }\n onValidationError(null)\n onUploadFileList(fileList)\n }\n\n return (\n <Stack\n sx={{\n py: 3,\n gap: 1,\n justifyContent: 'center',\n alignItems: 'center',\n width: '100%',\n border: '1px dashed #D9D9D9',\n backgroundColor: 'grey.100',\n textAlign: 'center',\n ...(disabled ? disabledUploadPaneSx : {}),\n }}\n >\n {isLoading && (\n <>\n <div>\n <SynapseSpinner size={40} />\n </div>\n <Typography\n variant={'smallText1'}\n sx={{\n my: 2,\n }}\n >\n {loadingText}\n </Typography>\n </>\n )}\n {!isLoading && (\n <>\n <img\n src={\n 'https://s3.us-east-1.amazonaws.com/static.synapse.org/images/upload_illustration.svg'\n }\n />\n {/* File input */}\n <input\n type=\"file\"\n id=\"filesToUpload\"\n name=\"file upload\"\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n multiple={allowMultipleFiles}\n accept={acceptedContentTypes?.join(',')}\n ref={fileInputRef}\n onChange={e => {\n if (e.target.files != null) {\n handleFileListSelected(e.target.files)\n // Reset so the same file(s) can be reselected after fixing a validation error.\n e.target.value = ''\n }\n }}\n />\n {/* Folder input */}\n <input\n type=\"file\"\n id=\"folderToUpload\"\n name=\"folder upload\"\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n ref={folderInputRef}\n onChange={e => {\n if (e.target.files != null) {\n handleFileListSelected(e.target.files)\n e.target.value = ''\n }\n }}\n // @ts-expect-error - webkitdirectory is not included in the InputHTMLAttributes type\n webkitdirectory=\"true\"\n />\n\n <Typography\n variant={'body1'}\n sx={{\n my: 2,\n }}\n >\n <Link onClick={handleClick}>Click to upload</Link>\n {!disableDragAndDrop && ' or drag and drop'}\n </Typography>\n <Menu\n anchorEl={anchorEl}\n open={open}\n onClose={handleClose}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n transformOrigin={{ vertical: 'top', horizontal: 'left' }}\n slots={{\n transition: Fade,\n }}\n >\n <MenuItem\n onClick={() => {\n handleClose()\n fileInputRef.current!.click()\n }}\n >\n Files\n </MenuItem>\n <MenuItem\n onClick={() => {\n handleClose()\n folderInputRef.current!.click()\n }}\n >\n Folder\n </MenuItem>\n </Menu>\n {message}\n </>\n )}\n </Stack>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,IAAM,IAAgC;CACpC,eAAe;CACf,QAAQ;AACV;AAyEA,SAAwB,EAAgB,GAA6B;CACnE,IAAM,EACJ,qBACA,uBACA,eAAY,IACZ,iBAAc,cACd,cAAW,IACX,YACA,wBAAqB,IACrB,sBAAmB,IACnB,yBACA,qBACA,aACA,sBAAmB,GACnB,uBAAoB,MAClB,GACE,IAAe,EAAyB,IAAI,GAC5C,IAAiB,EAAyB,IAAI,GAC9C,CAAC,GAAU,KAAe,EAA6B,IAAI,GAC3D,IAAO,EAAQ,GAEf,KAAe,MAAmC;EACtD,AAAI,CAAC,KAAsB,IACzB,EAAa,QAAS,MAAM,IAE5B,EAAY,EAAM,aAAa;CAEnC,GACM,UAAoB;EACxB,EAAY,IAAI;CAClB;CAEA,SAAS,EAAuB,GAAoB;EAElD,IAAM,IAAkB,EADV,MAAM,KAAK,CACqB,GAAO;GACnD;GACA;GACA;GACA;EACF,CAAC;EACD,IAAI,GAAiB;GACnB,EAAkB,CAAe;GACjC;EACF;EAEA,AADA,EAAkB,IAAI,GACtB,EAAiB,CAAQ;CAC3B;CAEA,OACE,kBAAC,GAAD;EACE,IAAI;GACF,IAAI;GACJ,KAAK;GACL,gBAAgB;GAChB,YAAY;GACZ,OAAO;GACP,QAAQ;GACR,iBAAiB;GACjB,WAAW;GACX,GAAI,IAAW,IAAuB,CAAC;EACzC;YAXF,CAaG,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAA,UACE,kBAAC,GAAD,EAAgB,MAAM,GAAK,CAAA,EACxB,CAAA,GACL,kBAAC,GAAD;GACE,SAAS;GACT,IAAI,EACF,IAAI,EACN;aAEC;EACS,CAAA,CACZ,EAAA,CAAA,GAEH,CAAC,KACA,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,OAAD,EACE,KACE,uFAEH,CAAA;GAED,kBAAC,SAAD;IACE,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO,EAAE,SAAS,OAAO;IACzB,eAAY;IACZ,UAAU;IACV,QAAQ,GAAsB,KAAK,GAAG;IACtC,KAAK;IACL,WAAU,MAAK;KACb,AAAI,EAAE,OAAO,SAAS,SACpB,EAAuB,EAAE,OAAO,KAAK,GAErC,EAAE,OAAO,QAAQ;IAErB;GACD,CAAA;GAED,kBAAC,SAAD;IACE,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO,EAAE,SAAS,OAAO;IACzB,eAAY;IACZ,KAAK;IACL,WAAU,MAAK;KACb,AAAI,EAAE,OAAO,SAAS,SACpB,EAAuB,EAAE,OAAO,KAAK,GACrC,EAAE,OAAO,QAAQ;IAErB;IAEA,iBAAgB;GACjB,CAAA;GAED,kBAAC,GAAD;IACE,SAAS;IACT,IAAI,EACF,IAAI,EACN;cAJF,CAME,kBAAC,GAAD;KAAM,SAAS;eAAa;IAAqB,CAAA,GAChD,CAAC,KAAsB,mBACd;;GACZ,kBAAC,GAAD;IACY;IACJ;IACN,SAAS;IACT,cAAc;KAAE,UAAU;KAAU,YAAY;IAAO;IACvD,iBAAiB;KAAE,UAAU;KAAO,YAAY;IAAO;IACvD,OAAO,EACL,YAAY,EACd;cARF,CAUE,kBAAC,GAAD;KACE,eAAe;MAEb,AADA,EAAY,GACZ,EAAa,QAAS,MAAM;KAC9B;eACD;IAES,CAAA,GACV,kBAAC,GAAD;KACE,eAAe;MAEb,AADA,EAAY,GACZ,EAAe,QAAS,MAAM;KAChC;eACD;IAES,CAAA,CACN;;GACL;EACD,EAAA,CAAA,CAEC;;AAEX"}
@@ -0,0 +1,25 @@
1
+ export type FileSelectionConstraints = {
2
+ /**
3
+ * If provided, files whose `type` is not included in this list will be rejected.
4
+ */
5
+ acceptedContentTypes?: readonly string[];
6
+ /**
7
+ * If provided, files larger than this will be rejected.
8
+ */
9
+ maxFileSizeBytes?: number;
10
+ /**
11
+ * If provided, the total number of files (this selection plus `currentFileCount`) may not exceed this value.
12
+ */
13
+ maxFiles?: number;
14
+ /**
15
+ * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.
16
+ * @default 0
17
+ */
18
+ currentFileCount?: number;
19
+ };
20
+ /**
21
+ * Validates a file selection against the given constraints, returning a human-readable error
22
+ * message describing the first violation encountered, or null if the selection is valid.
23
+ */
24
+ export declare function validateFileSelection(files: File[], constraints: FileSelectionConstraints): string | null;
25
+ //# sourceMappingURL=validateFileSelection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateFileSelection.d.ts","sourceRoot":"","sources":["../../../../src/components/file/upload/validateFileSelection.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,IAAI,EAAE,EACb,WAAW,EAAE,wBAAwB,GACpC,MAAM,GAAG,IAAI,CA+Bf"}
@@ -0,0 +1,18 @@
1
+ //#region src/components/file/upload/validateFileSelection.ts
2
+ function e(e) {
3
+ return `${Math.round(e / (1024 * 1024))} MB`;
4
+ }
5
+ function t(t, n) {
6
+ let { acceptedContentTypes: r, maxFileSizeBytes: i, maxFiles: a, currentFileCount: o = 0 } = n;
7
+ if (a != null && o + t.length > a) return `You can attach up to ${a} files.`;
8
+ if (i != null && t.some((e) => e.size > i)) return `Each file must be ${e(i)} or less.`;
9
+ if (r != null) {
10
+ let e = t.filter((e) => !r.includes(e.type));
11
+ if (e.length > 0) return `Unsupported file type: ${e.map((e) => e.name).join(", ")}.`;
12
+ }
13
+ return null;
14
+ }
15
+ //#endregion
16
+ export { t as validateFileSelection };
17
+
18
+ //# sourceMappingURL=validateFileSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateFileSelection.js","names":[],"sources":["../../../../src/components/file/upload/validateFileSelection.ts"],"sourcesContent":["export type FileSelectionConstraints = {\n /**\n * If provided, files whose `type` is not included in this list will be rejected.\n */\n acceptedContentTypes?: readonly string[]\n /**\n * If provided, files larger than this will be rejected.\n */\n maxFileSizeBytes?: number\n /**\n * If provided, the total number of files (this selection plus `currentFileCount`) may not exceed this value.\n */\n maxFiles?: number\n /**\n * The number of files already selected/uploaded prior to this selection. Used with `maxFiles`.\n * @default 0\n */\n currentFileCount?: number\n}\n\nfunction formatMegabytes(bytes: number): string {\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n\n/**\n * Validates a file selection against the given constraints, returning a human-readable error\n * message describing the first violation encountered, or null if the selection is valid.\n */\nexport function validateFileSelection(\n files: File[],\n constraints: FileSelectionConstraints,\n): string | null {\n const {\n acceptedContentTypes,\n maxFileSizeBytes,\n maxFiles,\n currentFileCount = 0,\n } = constraints\n\n if (maxFiles != null && currentFileCount + files.length > maxFiles) {\n return `You can attach up to ${maxFiles} files.`\n }\n\n if (\n maxFileSizeBytes != null &&\n files.some(file => file.size > maxFileSizeBytes)\n ) {\n return `Each file must be ${formatMegabytes(maxFileSizeBytes)} or less.`\n }\n\n if (acceptedContentTypes != null) {\n const unsupportedFiles = files.filter(\n file => !acceptedContentTypes.includes(file.type),\n )\n if (unsupportedFiles.length > 0) {\n return `Unsupported file type: ${unsupportedFiles\n .map(file => file.name)\n .join(', ')}.`\n }\n }\n\n return null\n}\n"],"mappings":";AAoBA,SAAS,EAAgB,GAAuB;CAC9C,OAAO,GAAG,KAAK,MAAM,KAAS,OAAO,KAAK,EAAE;AAC9C;AAMA,SAAgB,EACd,GACA,GACe;CACf,IAAM,EACJ,yBACA,qBACA,aACA,sBAAmB,MACjB;CAEJ,IAAI,KAAY,QAAQ,IAAmB,EAAM,SAAS,GACxD,OAAO,wBAAwB,EAAS;CAG1C,IACE,KAAoB,QACpB,EAAM,MAAK,MAAQ,EAAK,OAAO,CAAgB,GAE/C,OAAO,qBAAqB,EAAgB,CAAgB,EAAE;CAGhE,IAAI,KAAwB,MAAM;EAChC,IAAM,IAAmB,EAAM,QAC7B,MAAQ,CAAC,EAAqB,SAAS,EAAK,IAAI,CAClD;EACA,IAAI,EAAiB,SAAS,GAC5B,OAAO,0BAA0B,EAC9B,KAAI,MAAQ,EAAK,IAAI,EACrB,KAAK,IAAI,EAAE;CAElB;CAEA,OAAO;AACT"}