@burdenoff/microfe-brainyrich 2026.819.1 → 2026.827.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (514) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +1 -1
  2. package/dist/brainyrich/BrainyRichRoot.d.ts +0 -1
  3. package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
  4. package/dist/brainyrich/BrainyRichRoutes.js.map +1 -1
  5. package/dist/brainyrich/components/ActorName.js.map +1 -1
  6. package/dist/brainyrich/components/ConfirmDialog.d.ts +0 -1
  7. package/dist/brainyrich/components/ConfirmDialog.js.map +1 -1
  8. package/dist/brainyrich/components/LoadMore.js.map +1 -1
  9. package/dist/brainyrich/components/notify.js.map +1 -1
  10. package/dist/brainyrich/components/pickers.js.map +1 -1
  11. package/dist/brainyrich/components/reuse/CommentThread.js.map +1 -1
  12. package/dist/brainyrich/components/reuse/DocumentsPanel.d.ts +4 -0
  13. package/dist/brainyrich/components/reuse/DocumentsPanel.d.ts.map +1 -1
  14. package/dist/brainyrich/components/reuse/DocumentsPanel.js +150 -99
  15. package/dist/brainyrich/components/reuse/DocumentsPanel.js.map +1 -1
  16. package/dist/brainyrich/components/reuse/TagField.js.map +1 -1
  17. package/dist/brainyrich/components/reuse/transport.js.map +1 -1
  18. package/dist/brainyrich/components/viz.d.ts +0 -1
  19. package/dist/brainyrich/components/viz.js.map +1 -1
  20. package/dist/brainyrich/hooks/useBrainyRichAnalytics.js.map +1 -1
  21. package/dist/brainyrich/hooks/useBrainyRichApi.d.ts +176 -1
  22. package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
  23. package/dist/brainyrich/hooks/useBrainyRichApi.js +96 -82
  24. package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
  25. package/dist/brainyrich/pages/AccountsPage.d.ts.map +1 -1
  26. package/dist/brainyrich/pages/AccountsPage.js +367 -363
  27. package/dist/brainyrich/pages/AccountsPage.js.map +1 -1
  28. package/dist/brainyrich/pages/AdminFirmPage.d.ts.map +1 -1
  29. package/dist/brainyrich/pages/AdminFirmPage.js +115 -83
  30. package/dist/brainyrich/pages/AdminFirmPage.js.map +1 -1
  31. package/dist/brainyrich/pages/AiAssistantPage.d.ts.map +1 -1
  32. package/dist/brainyrich/pages/AiAssistantPage.js +251 -230
  33. package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
  34. package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
  35. package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
  36. package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
  37. package/dist/brainyrich/pages/FirmPage.d.ts.map +1 -1
  38. package/dist/brainyrich/pages/FirmPage.js +148 -116
  39. package/dist/brainyrich/pages/FirmPage.js.map +1 -1
  40. package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
  41. package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
  42. package/dist/brainyrich/pages/PortfoliosPage.d.ts +14 -0
  43. package/dist/brainyrich/pages/PortfoliosPage.d.ts.map +1 -1
  44. package/dist/brainyrich/pages/PortfoliosPage.js +530 -353
  45. package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
  46. package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
  47. package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
  48. package/dist/brainyrich/pages/RiskPage.js +381 -396
  49. package/dist/brainyrich/pages/RiskPage.js.map +1 -1
  50. package/dist/brainyrich/pages/TaxPage.js.map +1 -1
  51. package/dist/brainyrich/pages/_shared.d.ts +21 -1
  52. package/dist/brainyrich/pages/_shared.d.ts.map +1 -1
  53. package/dist/brainyrich/pages/_shared.js +66 -31
  54. package/dist/brainyrich/pages/_shared.js.map +1 -1
  55. package/dist/brainyrich/providers/BrainyRichProvider.d.ts +0 -1
  56. package/dist/brainyrich/providers/BrainyRichProvider.js.map +1 -1
  57. package/dist/brainyrich/services/createSandboxAssistantTransport.js.map +1 -1
  58. package/dist/brainyrich/types/bra.d.ts.map +1 -1
  59. package/dist/brainyrich/types/index.d.ts +0 -1
  60. package/dist/brainyrich/utils/cn.d.ts +0 -1
  61. package/dist/brainyrich/utils/i18n.d.ts +0 -1
  62. package/dist/brainyrich/utils/i18n.js.map +1 -1
  63. package/dist/brainyrich/utils/nativeControls.d.ts +0 -1
  64. package/dist/brainyrich/utils/nativeControls.js.map +1 -1
  65. package/dist/brainyrich/utils/navigation.js.map +1 -1
  66. package/dist/brainyrich/utils/pageContext.js.map +1 -1
  67. package/dist/dev/main.d.ts +0 -1
  68. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  69. package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
  70. package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
  71. package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
  72. package/dist/node_modules/d3-array/src/descending.js.map +1 -1
  73. package/dist/node_modules/d3-array/src/max.js.map +1 -1
  74. package/dist/node_modules/d3-array/src/min.js.map +1 -1
  75. package/dist/node_modules/d3-array/src/number.js.map +1 -1
  76. package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
  77. package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
  78. package/dist/node_modules/d3-array/src/range.js.map +1 -1
  79. package/dist/node_modules/d3-array/src/sort.js.map +1 -1
  80. package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
  81. package/dist/node_modules/d3-color/src/color.js.map +1 -1
  82. package/dist/node_modules/d3-color/src/define.js.map +1 -1
  83. package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
  84. package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
  85. package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
  86. package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
  87. package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
  88. package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
  89. package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
  90. package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
  91. package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
  92. package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
  93. package/dist/node_modules/d3-format/src/identity.js.map +1 -1
  94. package/dist/node_modules/d3-format/src/locale.js.map +1 -1
  95. package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
  96. package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
  97. package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
  98. package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
  99. package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
  100. package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
  101. package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
  102. package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
  103. package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
  104. package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
  105. package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
  106. package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
  107. package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
  108. package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
  109. package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
  110. package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
  111. package/dist/node_modules/d3-path/src/path.js.map +1 -1
  112. package/dist/node_modules/d3-scale/src/band.js.map +1 -1
  113. package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
  114. package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
  115. package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
  116. package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
  117. package/dist/node_modules/d3-scale/src/init.js.map +1 -1
  118. package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
  119. package/dist/node_modules/d3-scale/src/log.js.map +1 -1
  120. package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
  121. package/dist/node_modules/d3-scale/src/number.js.map +1 -1
  122. package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
  123. package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
  124. package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
  125. package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
  126. package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
  127. package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
  128. package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
  129. package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
  130. package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
  131. package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
  132. package/dist/node_modules/d3-scale/src/time.js.map +1 -1
  133. package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
  134. package/dist/node_modules/d3-shape/src/area.js.map +1 -1
  135. package/dist/node_modules/d3-shape/src/array.js.map +1 -1
  136. package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
  137. package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
  138. package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
  139. package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
  140. package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
  141. package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
  142. package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
  143. package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
  144. package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
  145. package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
  146. package/dist/node_modules/d3-shape/src/line.js.map +1 -1
  147. package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
  148. package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
  149. package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
  150. package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
  151. package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
  152. package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
  153. package/dist/node_modules/d3-shape/src/path.js.map +1 -1
  154. package/dist/node_modules/d3-shape/src/point.js.map +1 -1
  155. package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
  156. package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
  157. package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
  158. package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
  159. package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
  160. package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
  161. package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
  162. package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
  163. package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
  164. package/dist/node_modules/d3-time/src/day.js.map +1 -1
  165. package/dist/node_modules/d3-time/src/hour.js.map +1 -1
  166. package/dist/node_modules/d3-time/src/interval.js.map +1 -1
  167. package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
  168. package/dist/node_modules/d3-time/src/minute.js.map +1 -1
  169. package/dist/node_modules/d3-time/src/month.js.map +1 -1
  170. package/dist/node_modules/d3-time/src/second.js.map +1 -1
  171. package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
  172. package/dist/node_modules/d3-time/src/week.js.map +1 -1
  173. package/dist/node_modules/d3-time/src/year.js.map +1 -1
  174. package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
  175. package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
  176. package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
  177. package/dist/node_modules/eventemitter3/index.js.map +1 -1
  178. package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
  179. package/dist/node_modules/internmap/src/index.js.map +1 -1
  180. package/dist/node_modules/lodash/_DataView.js.map +1 -1
  181. package/dist/node_modules/lodash/_Hash.js.map +1 -1
  182. package/dist/node_modules/lodash/_ListCache.js.map +1 -1
  183. package/dist/node_modules/lodash/_Map.js.map +1 -1
  184. package/dist/node_modules/lodash/_MapCache.js.map +1 -1
  185. package/dist/node_modules/lodash/_Promise.js.map +1 -1
  186. package/dist/node_modules/lodash/_Set.js.map +1 -1
  187. package/dist/node_modules/lodash/_SetCache.js.map +1 -1
  188. package/dist/node_modules/lodash/_Stack.js +2 -1
  189. package/dist/node_modules/lodash/_Stack.js.map +1 -1
  190. package/dist/node_modules/lodash/_Symbol.js.map +1 -1
  191. package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
  192. package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
  193. package/dist/node_modules/lodash/_apply.js.map +1 -1
  194. package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
  195. package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
  196. package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
  197. package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
  198. package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
  199. package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
  200. package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
  201. package/dist/node_modules/lodash/_arraySome.js.map +1 -1
  202. package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
  203. package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
  204. package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
  205. package/dist/node_modules/lodash/_baseEach.js.map +1 -1
  206. package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
  207. package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
  208. package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
  209. package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
  210. package/dist/node_modules/lodash/_baseFor.js.map +1 -1
  211. package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
  212. package/dist/node_modules/lodash/_baseGet.js.map +1 -1
  213. package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
  214. package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
  215. package/dist/node_modules/lodash/_baseGt.js.map +1 -1
  216. package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
  217. package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
  218. package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
  219. package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
  220. package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
  221. package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
  222. package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
  223. package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
  224. package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
  225. package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
  226. package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
  227. package/dist/node_modules/lodash/_baseLt.js.map +1 -1
  228. package/dist/node_modules/lodash/_baseMap.js.map +1 -1
  229. package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
  230. package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
  231. package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
  232. package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
  233. package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
  234. package/dist/node_modules/lodash/_baseRange.js.map +1 -1
  235. package/dist/node_modules/lodash/_baseRest.js.map +1 -1
  236. package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
  237. package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
  238. package/dist/node_modules/lodash/_baseSome.js.map +1 -1
  239. package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
  240. package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
  241. package/dist/node_modules/lodash/_baseToString.js.map +1 -1
  242. package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
  243. package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
  244. package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
  245. package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
  246. package/dist/node_modules/lodash/_castPath.js.map +1 -1
  247. package/dist/node_modules/lodash/_castSlice.js.map +1 -1
  248. package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
  249. package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
  250. package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
  251. package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
  252. package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
  253. package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
  254. package/dist/node_modules/lodash/_createFind.js.map +1 -1
  255. package/dist/node_modules/lodash/_createRange.js.map +1 -1
  256. package/dist/node_modules/lodash/_createSet.js.map +1 -1
  257. package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
  258. package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
  259. package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
  260. package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
  261. package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
  262. package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
  263. package/dist/node_modules/lodash/_getMapData.js.map +1 -1
  264. package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
  265. package/dist/node_modules/lodash/_getNative.js.map +1 -1
  266. package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
  267. package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
  268. package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
  269. package/dist/node_modules/lodash/_getTag.js.map +1 -1
  270. package/dist/node_modules/lodash/_getValue.js.map +1 -1
  271. package/dist/node_modules/lodash/_hasPath.js.map +1 -1
  272. package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
  273. package/dist/node_modules/lodash/_hashClear.js.map +1 -1
  274. package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
  275. package/dist/node_modules/lodash/_hashGet.js.map +1 -1
  276. package/dist/node_modules/lodash/_hashHas.js.map +1 -1
  277. package/dist/node_modules/lodash/_hashSet.js.map +1 -1
  278. package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
  279. package/dist/node_modules/lodash/_isIndex.js.map +1 -1
  280. package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
  281. package/dist/node_modules/lodash/_isKey.js.map +1 -1
  282. package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
  283. package/dist/node_modules/lodash/_isMasked.js.map +1 -1
  284. package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
  285. package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
  286. package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
  287. package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
  288. package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
  289. package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
  290. package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
  291. package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
  292. package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
  293. package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
  294. package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
  295. package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
  296. package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
  297. package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
  298. package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
  299. package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
  300. package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
  301. package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
  302. package/dist/node_modules/lodash/_objectToString.js.map +1 -1
  303. package/dist/node_modules/lodash/_overArg.js.map +1 -1
  304. package/dist/node_modules/lodash/_overRest.js.map +1 -1
  305. package/dist/node_modules/lodash/_root.js.map +1 -1
  306. package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
  307. package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
  308. package/dist/node_modules/lodash/_setToArray.js.map +1 -1
  309. package/dist/node_modules/lodash/_setToString.js.map +1 -1
  310. package/dist/node_modules/lodash/_shortOut.js.map +1 -1
  311. package/dist/node_modules/lodash/_stackClear.js.map +1 -1
  312. package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
  313. package/dist/node_modules/lodash/_stackGet.js.map +1 -1
  314. package/dist/node_modules/lodash/_stackHas.js.map +1 -1
  315. package/dist/node_modules/lodash/_stackSet.js.map +1 -1
  316. package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
  317. package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
  318. package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
  319. package/dist/node_modules/lodash/_toKey.js.map +1 -1
  320. package/dist/node_modules/lodash/_toSource.js.map +1 -1
  321. package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
  322. package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
  323. package/dist/node_modules/lodash/constant.js.map +1 -1
  324. package/dist/node_modules/lodash/debounce.js.map +1 -1
  325. package/dist/node_modules/lodash/eq.js.map +1 -1
  326. package/dist/node_modules/lodash/every.js.map +1 -1
  327. package/dist/node_modules/lodash/find.js.map +1 -1
  328. package/dist/node_modules/lodash/findIndex.js.map +1 -1
  329. package/dist/node_modules/lodash/flatMap.js.map +1 -1
  330. package/dist/node_modules/lodash/get.js.map +1 -1
  331. package/dist/node_modules/lodash/hasIn.js.map +1 -1
  332. package/dist/node_modules/lodash/identity.js.map +1 -1
  333. package/dist/node_modules/lodash/isArguments.js.map +1 -1
  334. package/dist/node_modules/lodash/isArray.js.map +1 -1
  335. package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
  336. package/dist/node_modules/lodash/isBoolean.js.map +1 -1
  337. package/dist/node_modules/lodash/isBuffer.js.map +1 -1
  338. package/dist/node_modules/lodash/isEqual.js.map +1 -1
  339. package/dist/node_modules/lodash/isFunction.js.map +1 -1
  340. package/dist/node_modules/lodash/isLength.js.map +1 -1
  341. package/dist/node_modules/lodash/isNaN.js.map +1 -1
  342. package/dist/node_modules/lodash/isNil.js.map +1 -1
  343. package/dist/node_modules/lodash/isNumber.js.map +1 -1
  344. package/dist/node_modules/lodash/isObject.js.map +1 -1
  345. package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
  346. package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
  347. package/dist/node_modules/lodash/isString.js.map +1 -1
  348. package/dist/node_modules/lodash/isSymbol.js.map +1 -1
  349. package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
  350. package/dist/node_modules/lodash/keys.js.map +1 -1
  351. package/dist/node_modules/lodash/last.js.map +1 -1
  352. package/dist/node_modules/lodash/map.js.map +1 -1
  353. package/dist/node_modules/lodash/mapValues.js.map +1 -1
  354. package/dist/node_modules/lodash/max.js.map +1 -1
  355. package/dist/node_modules/lodash/maxBy.js.map +1 -1
  356. package/dist/node_modules/lodash/memoize.js.map +1 -1
  357. package/dist/node_modules/lodash/min.js.map +1 -1
  358. package/dist/node_modules/lodash/minBy.js.map +1 -1
  359. package/dist/node_modules/lodash/noop.js.map +1 -1
  360. package/dist/node_modules/lodash/now.js.map +1 -1
  361. package/dist/node_modules/lodash/property.js.map +1 -1
  362. package/dist/node_modules/lodash/range.js.map +1 -1
  363. package/dist/node_modules/lodash/some.js.map +1 -1
  364. package/dist/node_modules/lodash/sortBy.js.map +1 -1
  365. package/dist/node_modules/lodash/stubArray.js.map +1 -1
  366. package/dist/node_modules/lodash/stubFalse.js.map +1 -1
  367. package/dist/node_modules/lodash/throttle.js.map +1 -1
  368. package/dist/node_modules/lodash/toFinite.js.map +1 -1
  369. package/dist/node_modules/lodash/toInteger.js.map +1 -1
  370. package/dist/node_modules/lodash/toNumber.js.map +1 -1
  371. package/dist/node_modules/lodash/toString.js.map +1 -1
  372. package/dist/node_modules/lodash/uniqBy.js.map +1 -1
  373. package/dist/node_modules/lodash/upperFirst.js.map +1 -1
  374. package/dist/node_modules/object-assign/index.js.map +1 -1
  375. package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
  376. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
  377. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
  378. package/dist/node_modules/prop-types/index.js.map +1 -1
  379. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
  380. package/dist/node_modules/prop-types/lib/has.js.map +1 -1
  381. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  382. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  383. package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
  384. package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  385. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  386. package/dist/node_modules/react-is/index.js.map +1 -1
  387. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  388. package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
  389. package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
  390. package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
  391. package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
  392. package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
  393. package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
  394. package/dist/node_modules/recharts/es6/cartesian/Area.js +13 -13
  395. package/dist/node_modules/recharts/es6/cartesian/Area.js.map +1 -1
  396. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  397. package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
  398. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  399. package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
  400. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  401. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
  402. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  403. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
  404. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  405. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
  406. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  407. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
  408. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  409. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
  410. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  411. package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
  412. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  413. package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
  414. package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
  415. package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
  416. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  417. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
  418. package/dist/node_modules/recharts/es6/chart/AreaChart.js.map +1 -1
  419. package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
  420. package/dist/node_modules/recharts/es6/chart/PieChart.js.map +1 -1
  421. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  422. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
  423. package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
  424. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  425. package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
  426. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  427. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
  428. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  429. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
  430. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  431. package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
  432. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  433. package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
  434. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  435. package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
  436. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  437. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
  438. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  439. package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
  440. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  441. package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
  442. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  443. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
  444. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  445. package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
  446. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  447. package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
  448. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  449. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
  450. package/dist/node_modules/recharts/es6/polar/Pie.js +13 -13
  451. package/dist/node_modules/recharts/es6/polar/Pie.js.map +1 -1
  452. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
  453. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js.map +1 -1
  454. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
  455. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js.map +1 -1
  456. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  457. package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
  458. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  459. package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
  460. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  461. package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
  462. package/dist/node_modules/recharts/es6/shape/Polygon.js +4 -4
  463. package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -1
  464. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  465. package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
  466. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  467. package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
  468. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  469. package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
  470. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  471. package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
  472. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  473. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
  474. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  475. package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
  476. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  477. package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
  478. package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
  479. package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
  480. package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
  481. package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
  482. package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
  483. package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
  484. package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
  485. package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
  486. package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
  487. package/dist/node_modules/recharts/es6/util/PolarUtils.js +1 -1
  488. package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
  489. package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
  490. package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
  491. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  492. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
  493. package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
  494. package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
  495. package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
  496. package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
  497. package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
  498. package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
  499. package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
  500. package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
  501. package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
  502. package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
  503. package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
  504. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  505. package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
  506. package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
  507. package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
  508. package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
  509. package/dist/node_modules/sonner/dist/index.js.map +1 -1
  510. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
  511. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  512. package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
  513. package/dist/stories/LoadMore.stories.d.ts +0 -1
  514. package/package.json +15 -7
@@ -1,39 +1,40 @@
1
1
  import { useBrainyRich as e } from "../../providers/BrainyRichProvider.js";
2
- import { formatDate as t } from "../../pages/_shared.js";
3
- import { wspaceFetch as n, wspaceMutate as r } from "./transport.js";
4
- import { useCallback as i, useRef as a, useState as o } from "react";
5
- import { Download as s, FileText as c, Upload as l } from "lucide-react";
6
- import { useMutation as u, useQuery as d, useQueryClient as f } from "@tanstack/react-query";
7
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
8
- import { Button as h, Card as g, CardContent as _, Skeleton as v } from "@burdenoff/fe-libs/ui";
2
+ import { ConfirmDialog as t } from "../ConfirmDialog.js";
3
+ import { formatDate as n } from "../../pages/_shared.js";
4
+ import { wspaceFetch as r, wspaceMutate as i } from "./transport.js";
5
+ import { useCallback as a, useRef as o, useState as s } from "react";
6
+ import { Download as c, FileText as l, Trash2 as u, Upload as d, UploadCloud as f } from "lucide-react";
7
+ import { useMutation as p, useQuery as m, useQueryClient as h } from "@tanstack/react-query";
8
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
9
+ import { Button as v, Card as y, CardContent as b, Skeleton as x } from "@burdenoff/fe-libs/ui";
9
10
  //#region src/brainyrich/components/reuse/DocumentsPanel.tsx
10
- var y = 21600, b = "id name extension mimeType size createdAt", x = (e, t) => `BrainyRich · ${e} · ${t}`, S = (e, t) => [
11
+ var S = 21600, C = "id name extension mimeType size createdAt", w = (e, t) => `BrainyRich · ${e} · ${t}`, T = (e, t) => [
11
12
  "brainyrich",
12
13
  "entity-folder",
13
14
  e,
14
15
  t
15
- ], C = (e) => [
16
+ ], E = (e) => [
16
17
  "brainyrich",
17
18
  "folder-files",
18
19
  e ?? "none"
19
- ], w = (t, r) => {
20
- let { apiGatewayUrl: i } = e(), a = r ? x(t, r) : "";
21
- return d({
22
- queryKey: S(t, r ?? ""),
23
- enabled: !!r,
24
- queryFn: async () => (await n("query BraGetFolders($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }", { pagination: {
20
+ ], D = (t, n) => {
21
+ let { apiGatewayUrl: i } = e(), a = n ? w(t, n) : "";
22
+ return m({
23
+ queryKey: T(t, n ?? ""),
24
+ enabled: !!n,
25
+ queryFn: async () => (await r("query BraGetFolders($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }", { pagination: {
25
26
  limit: 200,
26
27
  offset: 0
27
28
  } }, i)).getFolders.folders.find((e) => e.name === a) ?? null
28
29
  });
29
- }, T = (t) => {
30
- let { apiGatewayUrl: r } = e();
31
- return d({
32
- queryKey: C(t),
30
+ }, O = (t) => {
31
+ let { apiGatewayUrl: n } = e();
32
+ return m({
33
+ queryKey: E(t),
33
34
  enabled: !!t,
34
- queryFn: async () => (await n(`query BraGetFilesInFolder($folderId: ID, $pagination: PaginationInput) {
35
+ queryFn: async () => (await r(`query BraGetFilesInFolder($folderId: ID, $pagination: PaginationInput) {
35
36
  getFilesInFolder(folderId: $folderId, pagination: $pagination) {
36
- files { ${b} }
37
+ files { ${C} }
37
38
  }
38
39
  }`, {
39
40
  folderId: t,
@@ -41,10 +42,10 @@ var y = 21600, b = "id name extension mimeType size createdAt", x = (e, t) => `B
41
42
  limit: 100,
42
43
  offset: 0
43
44
  }
44
- }, r)).getFilesInFolder.files
45
+ }, n)).getFilesInFolder.files
45
46
  });
46
47
  };
47
- function E(e, t, n, r) {
48
+ function k(e, t, n, r) {
48
49
  return new Promise((i, a) => {
49
50
  let o = new XMLHttpRequest();
50
51
  o.open("PUT", e), o.setRequestHeader("Content-Type", n), o.upload.onprogress = (e) => {
@@ -52,22 +53,22 @@ function E(e, t, n, r) {
52
53
  }, o.onload = () => o.status >= 200 && o.status < 300 ? i() : a(/* @__PURE__ */ Error(`File storage rejected the upload (HTTP ${o.status}).`)), o.onerror = () => a(/* @__PURE__ */ Error("Network error while uploading the file.")), o.onabort = () => a(/* @__PURE__ */ Error("The upload was cancelled.")), o.send(t);
53
54
  });
54
55
  }
55
- var D = (t, i) => {
56
- let { apiGatewayUrl: a } = e(), s = f(), [c, l] = o(0);
56
+ var A = (t, n) => {
57
+ let { apiGatewayUrl: a } = e(), o = h(), [c, l] = s(0);
57
58
  return {
58
- ...u({
59
+ ...p({
59
60
  mutationFn: async (e) => {
60
61
  l(0);
61
- let o = await n("query BraResolveFolder($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }", { pagination: {
62
+ let o = await r("query BraResolveFolder($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }", { pagination: {
62
63
  limit: 200,
63
64
  offset: 0
64
- } }, a).then((e) => e.getFolders.folders.find((e) => e.name === x(t, i)));
65
- o ||= (await r("mutation BraCreateFolder($input: CreateFolderInput!) {\n createFolder(input: $input) { id name }\n }", { input: {
66
- name: x(t, i),
67
- description: `Documents attached to ${t} ${i}.`,
65
+ } }, a).then((e) => e.getFolders.folders.find((e) => e.name === w(t, n)));
66
+ o ||= (await i("mutation BraCreateFolder($input: CreateFolderInput!) {\n createFolder(input: $input) { id name }\n }", { input: {
67
+ name: w(t, n),
68
+ description: `Documents attached to ${t} ${n}.`,
68
69
  visibility: "WORKSPACE"
69
70
  } }, a)).createFolder;
70
- let s = o.id, c = e.name.lastIndexOf("."), u = c > -1 ? e.name.slice(c + 1) : "", d = e.type || "application/octet-stream", f = String(e.size), p = await r("mutation BraInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) { uploadUrl session { id } }\n }", { input: {
71
+ let s = o.id, c = e.name.lastIndexOf("."), u = c > -1 ? e.name.slice(c + 1) : "", d = e.type || "application/octet-stream", f = String(e.size), p = await i("mutation BraInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) { uploadUrl session { id } }\n }", { input: {
71
72
  fileName: e.name,
72
73
  extension: u,
73
74
  mimeType: d,
@@ -76,147 +77,182 @@ var D = (t, i) => {
76
77
  visibility: "WORKSPACE"
77
78
  } }, a), { uploadUrl: m } = p.initiateUpload, h = p.initiateUpload.session.id;
78
79
  if (!m) throw Error("The file service did not return an upload URL.");
79
- return await E(m, e, d, l), await r("mutation BraCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) { fileId }\n }", { input: {
80
+ return await k(m, e, d, l), await i("mutation BraCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) { fileId }\n }", { input: {
80
81
  sessionId: h,
81
82
  fileSize: f,
82
83
  folderId: s
83
84
  } }, a), l(100), s;
84
85
  },
85
86
  onSuccess: (e) => {
86
- s.invalidateQueries({ queryKey: S(t, i) }), s.invalidateQueries({ queryKey: C(e) });
87
+ o.invalidateQueries({ queryKey: T(t, n) }), o.invalidateQueries({ queryKey: E(e) });
87
88
  }
88
89
  }),
89
90
  progress: c
90
91
  };
91
- }, O = () => {
92
+ }, j = () => {
92
93
  let { apiGatewayUrl: t } = e();
93
- return u({ mutationFn: async (e) => (await n("query BraGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }", {
94
+ return p({ mutationFn: async (e) => (await r("query BraGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }", {
94
95
  id: e,
95
- expiresIn: y
96
+ expiresIn: S
96
97
  }, t)).getFileDownloadUrl });
97
- }, k = (e) => {
98
+ }, M = (t) => {
99
+ let { apiGatewayUrl: n } = e(), r = h();
100
+ return p({
101
+ mutationFn: async (e) => (await i("mutation BraDeleteFile($id: ID!) { deleteFile(id: $id) }", { id: e }, n)).deleteFile,
102
+ onSuccess: () => r.invalidateQueries({ queryKey: E(t) })
103
+ });
104
+ }, N = (e) => {
98
105
  let t = Number(e);
99
106
  return !Number.isFinite(t) || t <= 0 ? "—" : t < 1024 ? `${t} B` : t < 1024 * 1024 ? `${(t / 1024).toFixed(0)} KB` : `${(t / (1024 * 1024)).toFixed(1)} MB`;
100
107
  };
101
- function A({ entityType: e, entityId: n, heading: r = "Documents", hideHeading: o = !1 }) {
102
- let u = a(null), d = w(e, n), f = T(d.data?.id), y = D(e, n), b = O(), x = i((e) => {
108
+ function P({ entityType: e, entityId: r, heading: i = "Documents", hideHeading: p = !1 }) {
109
+ let m = o(null), h = D(e, r), S = O(h.data?.id), C = A(e, r), w = j(), T = M(h.data?.id), [E, k] = s(!1), [P, F] = s(null), I = a((e) => {
103
110
  let t = e.target.files?.[0];
104
- t && y.mutate(t), e.target.value = "";
105
- }, [y]), S = async (e) => {
106
- let t = await b.mutateAsync(e);
111
+ t && C.mutate(t), e.target.value = "";
112
+ }, [C]), L = a((e) => {
113
+ if (e.preventDefault(), k(!1), C.isPending) return;
114
+ let t = e.dataTransfer.files?.[0];
115
+ t && C.mutate(t);
116
+ }, [C]), R = async (e) => {
117
+ let t = await w.mutateAsync(e);
107
118
  t && window.open(t, "_blank", "noopener,noreferrer");
108
- }, C = d.isLoading || !!d.data && f.isLoading, E = f.data ?? [];
109
- return /* @__PURE__ */ m("div", {
119
+ }, z = h.isLoading || !!h.data && S.isLoading, B = S.data ?? [];
120
+ return /* @__PURE__ */ _("div", {
110
121
  className: "space-y-3",
111
122
  children: [
112
- /* @__PURE__ */ m("div", {
123
+ /* @__PURE__ */ _("div", {
113
124
  className: "flex items-center justify-between",
114
- children: [!o && /* @__PURE__ */ m("h3", {
125
+ children: [!p && /* @__PURE__ */ _("h3", {
115
126
  className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
116
- children: [/* @__PURE__ */ p(c, {
127
+ children: [/* @__PURE__ */ g(l, {
117
128
  className: "size-4",
118
129
  "aria-hidden": "true"
119
- }), r]
120
- }), /* @__PURE__ */ m("div", {
130
+ }), i]
131
+ }), /* @__PURE__ */ _("div", {
121
132
  className: "ml-auto",
122
- children: [/* @__PURE__ */ p("input", {
123
- ref: u,
133
+ children: [/* @__PURE__ */ g("input", {
134
+ ref: m,
124
135
  type: "file",
125
136
  className: "sr-only",
126
137
  "aria-hidden": "true",
127
138
  tabIndex: -1,
128
- onChange: x
129
- }), /* @__PURE__ */ m(h, {
139
+ onChange: I
140
+ }), /* @__PURE__ */ _(v, {
130
141
  type: "button",
131
142
  size: "sm",
132
143
  variant: "outline",
133
- onClick: () => u.current?.click(),
134
- disabled: y.isPending,
135
- children: [/* @__PURE__ */ p(l, {
144
+ onClick: () => m.current?.click(),
145
+ disabled: C.isPending,
146
+ children: [/* @__PURE__ */ g(d, {
136
147
  className: "size-4",
137
148
  "aria-hidden": "true"
138
- }), y.isPending ? `Uploading ${y.progress}%` : "Upload"]
149
+ }), C.isPending ? `Uploading ${C.progress}%` : "Upload"]
139
150
  })]
140
151
  })]
141
152
  }),
142
- y.isPending && /* @__PURE__ */ p("div", {
153
+ C.isPending && /* @__PURE__ */ g("div", {
143
154
  className: "h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken",
144
155
  role: "progressbar",
145
156
  "aria-label": "Upload progress",
146
- "aria-valuenow": y.progress,
157
+ "aria-valuenow": C.progress,
147
158
  "aria-valuemin": 0,
148
159
  "aria-valuemax": 100,
149
- children: /* @__PURE__ */ p("div", {
160
+ children: /* @__PURE__ */ g("div", {
150
161
  className: "h-full rounded-full bg-primary motion-safe:transition-[width] motion-safe:duration-200",
151
- style: { width: `${y.progress}%` }
162
+ style: { width: `${C.progress}%` }
152
163
  })
153
164
  }),
154
- C ? /* @__PURE__ */ m("div", {
165
+ /* @__PURE__ */ _("button", {
166
+ type: "button",
167
+ onClick: () => m.current?.click(),
168
+ disabled: C.isPending,
169
+ onDragOver: (e) => {
170
+ e.preventDefault(), C.isPending || k(!0);
171
+ },
172
+ onDragLeave: () => k(!1),
173
+ onDrop: L,
174
+ className: `w-full rounded-lg border border-dashed px-4 py-8 text-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-action-primary-border)] disabled:cursor-not-allowed disabled:opacity-60 ${E ? "border-[var(--color-action-primary-border)] bg-bg-elevated" : "border-border-subtle bg-bg-surface hover:border-[var(--color-action-primary-border)]"}`,
175
+ children: [
176
+ /* @__PURE__ */ g(f, {
177
+ className: "mx-auto mb-2 size-6 text-text-secondary",
178
+ "aria-hidden": "true"
179
+ }),
180
+ /* @__PURE__ */ g("span", {
181
+ className: "block text-sm text-text-primary",
182
+ children: "Drop a statement, KYC or tax document here"
183
+ }),
184
+ /* @__PURE__ */ g("span", {
185
+ className: "mt-0.5 block text-xs text-text-secondary",
186
+ children: "or click to choose one file"
187
+ })
188
+ ]
189
+ }),
190
+ z ? /* @__PURE__ */ _("div", {
155
191
  className: "space-y-2",
156
192
  "aria-busy": "true",
157
- children: [/* @__PURE__ */ p(v, { className: "h-12 w-full rounded-md" }), /* @__PURE__ */ p(v, { className: "h-12 w-full rounded-md" })]
158
- }) : f.isError ? /* @__PURE__ */ m("p", {
193
+ children: [/* @__PURE__ */ g(x, { className: "h-12 w-full rounded-md" }), /* @__PURE__ */ g(x, { className: "h-12 w-full rounded-md" })]
194
+ }) : S.isError ? /* @__PURE__ */ _("p", {
159
195
  className: "text-sm text-status-error-text",
160
196
  children: [
161
197
  "Could not load documents.",
162
198
  " ",
163
- /* @__PURE__ */ p("button", {
199
+ /* @__PURE__ */ g("button", {
164
200
  type: "button",
165
201
  className: "underline underline-offset-2",
166
- onClick: () => f.refetch(),
202
+ onClick: () => S.refetch(),
167
203
  children: "Retry"
168
204
  })
169
205
  ]
170
- }) : E.length === 0 ? /* @__PURE__ */ m("div", {
171
- className: "rounded-lg border border-dashed border-border-subtle bg-bg-surface px-4 py-8 text-center",
172
- children: [
173
- /* @__PURE__ */ p(c, {
174
- className: "mx-auto mb-2 size-6 text-text-secondary",
175
- "aria-hidden": "true"
176
- }),
177
- /* @__PURE__ */ p("p", {
178
- className: "text-sm text-text-primary",
179
- children: "No documents yet"
180
- }),
181
- /* @__PURE__ */ p("p", {
182
- className: "mt-0.5 text-xs text-text-secondary",
183
- children: "Upload statements, KYC or tax documents for this record."
184
- })
185
- ]
186
- }) : /* @__PURE__ */ p("ul", {
206
+ }) : B.length === 0 ? /* @__PURE__ */ g("p", {
207
+ className: "text-center text-xs text-text-secondary",
208
+ children: "No documents attached to this record yet."
209
+ }) : /* @__PURE__ */ g("ul", {
187
210
  className: "space-y-2",
188
- children: E.map((e) => /* @__PURE__ */ p("li", { children: /* @__PURE__ */ p(g, { children: /* @__PURE__ */ m(_, {
211
+ children: B.map((e) => /* @__PURE__ */ g("li", { children: /* @__PURE__ */ g(y, { children: /* @__PURE__ */ _(b, {
189
212
  className: "flex items-center gap-3 p-3",
190
213
  children: [
191
- /* @__PURE__ */ p("div", {
214
+ /* @__PURE__ */ g("div", {
192
215
  className: "flex size-9 shrink-0 items-center justify-center rounded-md bg-bg-sunken text-text-secondary",
193
- children: /* @__PURE__ */ p(c, {
216
+ children: /* @__PURE__ */ g(l, {
194
217
  className: "size-4",
195
218
  "aria-hidden": "true"
196
219
  })
197
220
  }),
198
- /* @__PURE__ */ m("div", {
221
+ /* @__PURE__ */ _("div", {
199
222
  className: "min-w-0 flex-1",
200
- children: [/* @__PURE__ */ p("p", {
223
+ children: [/* @__PURE__ */ g("p", {
201
224
  className: "truncate text-sm font-medium text-text-primary",
202
225
  children: e.name
203
- }), /* @__PURE__ */ m("p", {
226
+ }), /* @__PURE__ */ _("p", {
204
227
  className: "text-xs text-text-secondary",
205
228
  children: [
206
- k(e.size),
229
+ N(e.size),
207
230
  " · ",
208
- t(e.createdAt)
231
+ n(e.createdAt)
209
232
  ]
210
233
  })]
211
234
  }),
212
- /* @__PURE__ */ p(h, {
235
+ /* @__PURE__ */ g(v, {
213
236
  type: "button",
214
237
  size: "sm",
215
238
  variant: "ghost",
216
239
  "aria-label": `Download ${e.name}`,
217
- disabled: b.isPending,
218
- onClick: () => S(e.id),
219
- children: /* @__PURE__ */ p(s, {
240
+ disabled: w.isPending,
241
+ onClick: () => R(e.id),
242
+ children: /* @__PURE__ */ g(c, {
243
+ className: "size-4",
244
+ "aria-hidden": "true"
245
+ })
246
+ }),
247
+ /* @__PURE__ */ g(v, {
248
+ type: "button",
249
+ size: "sm",
250
+ variant: "ghost",
251
+ className: "text-status-error-text hover:text-status-error-text",
252
+ "aria-label": `Delete ${e.name}`,
253
+ disabled: T.isPending,
254
+ onClick: () => F(e),
255
+ children: /* @__PURE__ */ g(u, {
220
256
  className: "size-4",
221
257
  "aria-hidden": "true"
222
258
  })
@@ -224,14 +260,29 @@ function A({ entityType: e, entityId: n, heading: r = "Documents", hideHeading:
224
260
  ]
225
261
  }) }) }, e.id))
226
262
  }),
227
- (y.isError || b.isError) && /* @__PURE__ */ p("p", {
263
+ (C.isError || w.isError || T.isError) && /* @__PURE__ */ g("p", {
228
264
  className: "text-sm text-status-error-text",
229
- children: y.error instanceof Error ? y.error.message : b.error instanceof Error ? "Could not open the document. Please try again." : "Something went wrong. Please try again."
265
+ children: C.error instanceof Error ? C.error.message : T.error instanceof Error ? `Could not delete the document. ${T.error.message}` : w.error instanceof Error ? "Could not open the document. Please try again." : "Something went wrong. Please try again."
266
+ }),
267
+ /* @__PURE__ */ g(t, {
268
+ open: P !== null,
269
+ onOpenChange: (e) => {
270
+ e || F(null);
271
+ },
272
+ title: "Delete this document?",
273
+ description: P ? `“${P.name}” will be removed from this record. This cannot be undone.` : void 0,
274
+ confirmLabel: "Delete",
275
+ pendingLabel: "Deleting…",
276
+ destructive: !0,
277
+ pending: T.isPending,
278
+ onConfirm: () => {
279
+ P && T.mutate(P.id, { onSuccess: () => F(null) });
280
+ }
230
281
  })
231
282
  ]
232
283
  });
233
284
  }
234
285
  //#endregion
235
- export { A as DocumentsPanel };
286
+ export { P as DocumentsPanel };
236
287
 
237
288
  //# sourceMappingURL=DocumentsPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentsPanel.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/DocumentsPanel.tsx"],"sourcesContent":["/**\n * DocumentsPanel — REUSE of `wspace-files-svc` for statement / KYC / tax-doc\n * attachments on Accounts + Households.\n * @module brainyrich/components/reuse/DocumentsPanel\n *\n * A wealth product needs to attach documents (statements, KYC, tax packs) to\n * accounts and households. `wspace-files-svc` has no native entity-owned link on\n * `File`, so we scope documents to an entity via a dedicated, stably-named\n * FOLDER per `(entityType, entityId)` and list its contents. All ops route\n * through the workspace supergraph the MFE already uses.\n *\n * Flow:\n * - resolve folder → `getFolders(filter)` matched by name (created lazily on\n * first upload via `createFolder`); no side-effects on read.\n * - list → `getFilesInFolder(folderId, pagination)`\n * - upload (3-step) → `initiateUpload` → S3 `PUT` (byte-progress) → `completeUpload`\n * - download → `getFileDownloadUrl(id, expiresIn)` capped at 21600s to\n * avoid the >604800 fleet bug (S3 7-day cap → 500).\n *\n * Presentational + self-contained: owns its hooks, reads the gateway base URL\n * from `useBrainyRich()`, uses fe-libs/ui primitives + semantic tokens.\n */\n\nimport { useCallback, useRef, useState } from 'react';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { Download, FileText, Upload } from 'lucide-react';\nimport { Button, Card, CardContent, Skeleton } from '@burdenoff/fe-libs/ui';\n\nimport { useBrainyRich } from '../../providers/BrainyRichProvider';\nimport { formatDate } from '../../pages/_shared';\nimport { wspaceFetch, wspaceMutate } from './transport';\n\n// Presigned-URL TTL: cap at 21600s (6h). >604800 (S3 7-day) → INTERNAL_SERVER_ERROR.\nconst DOWNLOAD_URL_TTL_SECONDS = 21600;\n\ninterface FilesFolder {\n id: string;\n name: string;\n}\n\ninterface FilesFile {\n id: string;\n name: string;\n extension: string;\n mimeType: string;\n size: string;\n createdAt: string;\n}\n\nconst FILE_FIELDS = 'id name extension mimeType size createdAt';\n\nconst folderName = (entityType: string, entityId: string) =>\n `BrainyRich · ${entityType} · ${entityId}`;\n\nconst folderKey = (entityType: string, entityId: string) =>\n ['brainyrich', 'entity-folder', entityType, entityId] as const;\n\nconst filesKey = (folderId: string | null | undefined) =>\n ['brainyrich', 'folder-files', folderId ?? 'none'] as const;\n\n// ============================================================================\n// Folder resolution (read-only — no lazy creation here)\n// ============================================================================\n\nconst useEntityFolder = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n const wanted = entityId ? folderName(entityType, entityId) : '';\n return useQuery({\n queryKey: folderKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFolders: { folders: FilesFolder[] } }>(\n `query BraGetFolders($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n );\n return data.getFolders.folders.find((f) => f.name === wanted) ?? null;\n },\n });\n};\n\nconst useFolderFiles = (folderId: string | null | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: filesKey(folderId),\n enabled: Boolean(folderId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFilesInFolder: { files: FilesFile[] } }>(\n `query BraGetFilesInFolder($folderId: ID, $pagination: PaginationInput) {\n getFilesInFolder(folderId: $folderId, pagination: $pagination) {\n files { ${FILE_FIELDS} }\n }\n }`,\n { folderId, pagination: { limit: 100, offset: 0 } },\n apiGatewayUrl\n );\n return data.getFilesInFolder.files;\n },\n });\n};\n\n// ============================================================================\n// Upload (3-step platform flow, with lazy folder creation)\n// ============================================================================\n\nfunction putWithProgress(\n url: string,\n file: File,\n contentType: string,\n onProgress: (percent: number) => void\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', contentType);\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n xhr.onload = () =>\n xhr.status >= 200 && xhr.status < 300\n ? resolve()\n : reject(new Error(`File storage rejected the upload (HTTP ${xhr.status}).`));\n xhr.onerror = () => reject(new Error('Network error while uploading the file.'));\n xhr.onabort = () => reject(new Error('The upload was cancelled.'));\n xhr.send(file);\n });\n}\n\nconst useDocumentUpload = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n const [progress, setProgress] = useState(0);\n\n const mutation = useMutation({\n mutationFn: async (file: File) => {\n setProgress(0);\n\n // 0. resolve or create the entity folder\n let folder = await wspaceFetch<{ getFolders: { folders: FilesFolder[] } }>(\n `query BraResolveFolder($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n ).then((d) => d.getFolders.folders.find((f) => f.name === folderName(entityType, entityId)));\n\n if (!folder) {\n const created = await wspaceMutate<{ createFolder: FilesFolder }>(\n `mutation BraCreateFolder($input: CreateFolderInput!) {\n createFolder(input: $input) { id name }\n }`,\n {\n input: {\n name: folderName(entityType, entityId),\n description: `Documents attached to ${entityType} ${entityId}.`,\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n folder = created.createFolder;\n }\n const folderId = folder.id;\n\n const dotIndex = file.name.lastIndexOf('.');\n const extension = dotIndex > -1 ? file.name.slice(dotIndex + 1) : '';\n const mimeType = file.type || 'application/octet-stream';\n const fileSize = String(file.size);\n\n // 1. initiate\n const initiated = await wspaceMutate<{\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n }>(\n `mutation BraInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) { uploadUrl session { id } }\n }`,\n {\n input: {\n fileName: file.name,\n extension,\n mimeType,\n fileSize,\n folderId,\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n const { uploadUrl } = initiated.initiateUpload;\n const sessionId = initiated.initiateUpload.session.id;\n if (!uploadUrl) throw new Error('The file service did not return an upload URL.');\n\n // 2. PUT the bytes\n await putWithProgress(uploadUrl, file, mimeType, setProgress);\n\n // 3. complete\n await wspaceMutate<{ completeUpload: { fileId: string } }>(\n `mutation BraCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) { fileId }\n }`,\n { input: { sessionId, fileSize, folderId } },\n apiGatewayUrl\n );\n setProgress(100);\n return folderId;\n },\n onSuccess: (folderId) => {\n qc.invalidateQueries({ queryKey: folderKey(entityType, entityId) });\n qc.invalidateQueries({ queryKey: filesKey(folderId) });\n },\n });\n\n return { ...mutation, progress };\n};\n\nconst useDownloadFile = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await wspaceFetch<{ getFileDownloadUrl: string }>(\n `query BraGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }`,\n { id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n apiGatewayUrl\n );\n return data.getFileDownloadUrl;\n },\n });\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nconst formatSize = (bytes: string): string => {\n const n = Number(bytes);\n if (!Number.isFinite(n) || n <= 0) return '—';\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n};\n\nexport interface DocumentsPanelProps {\n /** Polymorphic entity type, e.g. \"brainyrich-account\" | \"brainyrich-household\". */\n entityType: string;\n /** The bra entity's id (an ID scalar). */\n entityId: string;\n /** Optional heading; hide with `hideHeading`. */\n heading?: string;\n hideHeading?: boolean;\n}\n\nexport function DocumentsPanel({\n entityType,\n entityId,\n heading = 'Documents',\n hideHeading = false,\n}: DocumentsPanelProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const folder = useEntityFolder(entityType, entityId);\n const files = useFolderFiles(folder.data?.id);\n const upload = useDocumentUpload(entityType, entityId);\n const download = useDownloadFile();\n\n const onPick = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) upload.mutate(file);\n e.target.value = '';\n },\n [upload]\n );\n\n const onDownload = async (id: string) => {\n const url = await download.mutateAsync(id);\n if (url) window.open(url, '_blank', 'noopener,noreferrer');\n };\n\n const loading = folder.isLoading || (Boolean(folder.data) && files.isLoading);\n const list = files.data ?? [];\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n {!hideHeading && (\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n {heading}\n </h3>\n )}\n <div className=\"ml-auto\">\n <input\n ref={inputRef}\n type=\"file\"\n className=\"sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onChange={onPick}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => inputRef.current?.click()}\n disabled={upload.isPending}\n >\n <Upload className=\"size-4\" aria-hidden=\"true\" />\n {upload.isPending ? `Uploading ${upload.progress}%` : 'Upload'}\n </Button>\n </div>\n </div>\n\n {upload.isPending && (\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-label=\"Upload progress\"\n aria-valuenow={upload.progress}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full bg-primary motion-safe:transition-[width] motion-safe:duration-200\"\n style={{ width: `${upload.progress}%` }}\n />\n </div>\n )}\n\n {loading ? (\n <div className=\"space-y-2\" aria-busy=\"true\">\n <Skeleton className=\"h-12 w-full rounded-md\" />\n <Skeleton className=\"h-12 w-full rounded-md\" />\n </div>\n ) : files.isError ? (\n <p className=\"text-sm text-status-error-text\">\n Could not load documents.{' '}\n <button\n type=\"button\"\n className=\"underline underline-offset-2\"\n onClick={() => files.refetch()}\n >\n Retry\n </button>\n </p>\n ) : list.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border-subtle bg-bg-surface px-4 py-8 text-center\">\n <FileText className=\"mx-auto mb-2 size-6 text-text-secondary\" aria-hidden=\"true\" />\n <p className=\"text-sm text-text-primary\">No documents yet</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n Upload statements, KYC or tax documents for this record.\n </p>\n </div>\n ) : (\n <ul className=\"space-y-2\">\n {list.map((file) => (\n <li key={file.id}>\n <Card>\n <CardContent className=\"flex items-center gap-3 p-3\">\n <div className=\"flex size-9 shrink-0 items-center justify-center rounded-md bg-bg-sunken text-text-secondary\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{file.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatSize(file.size)} · {formatDate(file.createdAt)}\n </p>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Download ${file.name}`}\n disabled={download.isPending}\n onClick={() => onDownload(file.id)}\n >\n <Download className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </CardContent>\n </Card>\n </li>\n ))}\n </ul>\n )}\n\n {(upload.isError || download.isError) && (\n <p className=\"text-sm text-status-error-text\">\n {upload.error instanceof Error\n ? upload.error.message\n : download.error instanceof Error\n ? 'Could not open the document. Please try again.'\n : 'Something went wrong. Please try again.'}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DocumentsPanel.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/DocumentsPanel.tsx"],"sourcesContent":["/**\n * DocumentsPanel — REUSE of `wspace-files-svc` for statement / KYC / tax-doc\n * attachments on Accounts + Households.\n * @module brainyrich/components/reuse/DocumentsPanel\n *\n * A wealth product needs to attach documents (statements, KYC, tax packs) to\n * accounts and households. `wspace-files-svc` has no native entity-owned link on\n * `File`, so we scope documents to an entity via a dedicated, stably-named\n * FOLDER per `(entityType, entityId)` and list its contents. All ops route\n * through the workspace supergraph the MFE already uses.\n *\n * Flow:\n * - resolve folder → `getFolders(filter)` matched by name (created lazily on\n * first upload via `createFolder`); no side-effects on read.\n * - list → `getFilesInFolder(folderId, pagination)`\n * - upload (3-step) → `initiateUpload` → S3 `PUT` (byte-progress) → `completeUpload`\n * reachable by click OR by dropping a file on the zone; both take one file,\n * which is exactly what the single-file upload mutation supports.\n * - download → `getFileDownloadUrl(id, expiresIn)` capped at 21600s to\n * avoid the >604800 fleet bug (S3 7-day cap → 500).\n * - delete → `deleteFile(id)` (RBAC `delete`/`file`, enforced at the\n * gateway) behind a confirm step.\n *\n * Presentational + self-contained: owns its hooks, reads the gateway base URL\n * from `useBrainyRich()`, uses fe-libs/ui primitives + semantic tokens.\n */\n\nimport { useCallback, useRef, useState } from 'react';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { Download, FileText, Trash2, Upload, UploadCloud } from 'lucide-react';\nimport { Button, Card, CardContent, Skeleton } from '@burdenoff/fe-libs/ui';\n\nimport { useBrainyRich } from '../../providers/BrainyRichProvider';\nimport { formatDate } from '../../pages/_shared';\nimport { ConfirmDialog } from '../ConfirmDialog';\nimport { wspaceFetch, wspaceMutate } from './transport';\n\n// Presigned-URL TTL: cap at 21600s (6h). >604800 (S3 7-day) → INTERNAL_SERVER_ERROR.\nconst DOWNLOAD_URL_TTL_SECONDS = 21600;\n\ninterface FilesFolder {\n id: string;\n name: string;\n}\n\ninterface FilesFile {\n id: string;\n name: string;\n extension: string;\n mimeType: string;\n size: string;\n createdAt: string;\n}\n\nconst FILE_FIELDS = 'id name extension mimeType size createdAt';\n\nconst folderName = (entityType: string, entityId: string) =>\n `BrainyRich · ${entityType} · ${entityId}`;\n\nconst folderKey = (entityType: string, entityId: string) =>\n ['brainyrich', 'entity-folder', entityType, entityId] as const;\n\nconst filesKey = (folderId: string | null | undefined) =>\n ['brainyrich', 'folder-files', folderId ?? 'none'] as const;\n\n// ============================================================================\n// Folder resolution (read-only — no lazy creation here)\n// ============================================================================\n\nconst useEntityFolder = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n const wanted = entityId ? folderName(entityType, entityId) : '';\n return useQuery({\n queryKey: folderKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFolders: { folders: FilesFolder[] } }>(\n `query BraGetFolders($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n );\n return data.getFolders.folders.find((f) => f.name === wanted) ?? null;\n },\n });\n};\n\nconst useFolderFiles = (folderId: string | null | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: filesKey(folderId),\n enabled: Boolean(folderId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getFilesInFolder: { files: FilesFile[] } }>(\n `query BraGetFilesInFolder($folderId: ID, $pagination: PaginationInput) {\n getFilesInFolder(folderId: $folderId, pagination: $pagination) {\n files { ${FILE_FIELDS} }\n }\n }`,\n { folderId, pagination: { limit: 100, offset: 0 } },\n apiGatewayUrl\n );\n return data.getFilesInFolder.files;\n },\n });\n};\n\n// ============================================================================\n// Upload (3-step platform flow, with lazy folder creation)\n// ============================================================================\n\nfunction putWithProgress(\n url: string,\n file: File,\n contentType: string,\n onProgress: (percent: number) => void\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', contentType);\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n xhr.onload = () =>\n xhr.status >= 200 && xhr.status < 300\n ? resolve()\n : reject(new Error(`File storage rejected the upload (HTTP ${xhr.status}).`));\n xhr.onerror = () => reject(new Error('Network error while uploading the file.'));\n xhr.onabort = () => reject(new Error('The upload was cancelled.'));\n xhr.send(file);\n });\n}\n\nconst useDocumentUpload = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n const [progress, setProgress] = useState(0);\n\n const mutation = useMutation({\n mutationFn: async (file: File) => {\n setProgress(0);\n\n // 0. resolve or create the entity folder\n let folder = await wspaceFetch<{ getFolders: { folders: FilesFolder[] } }>(\n `query BraResolveFolder($pagination: PaginationInput) {\n getFolders(pagination: $pagination) { folders { id name } }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n ).then((d) => d.getFolders.folders.find((f) => f.name === folderName(entityType, entityId)));\n\n if (!folder) {\n const created = await wspaceMutate<{ createFolder: FilesFolder }>(\n `mutation BraCreateFolder($input: CreateFolderInput!) {\n createFolder(input: $input) { id name }\n }`,\n {\n input: {\n name: folderName(entityType, entityId),\n description: `Documents attached to ${entityType} ${entityId}.`,\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n folder = created.createFolder;\n }\n const folderId = folder.id;\n\n const dotIndex = file.name.lastIndexOf('.');\n const extension = dotIndex > -1 ? file.name.slice(dotIndex + 1) : '';\n const mimeType = file.type || 'application/octet-stream';\n const fileSize = String(file.size);\n\n // 1. initiate\n const initiated = await wspaceMutate<{\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n }>(\n `mutation BraInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) { uploadUrl session { id } }\n }`,\n {\n input: {\n fileName: file.name,\n extension,\n mimeType,\n fileSize,\n folderId,\n visibility: 'WORKSPACE',\n },\n },\n apiGatewayUrl\n );\n const { uploadUrl } = initiated.initiateUpload;\n const sessionId = initiated.initiateUpload.session.id;\n if (!uploadUrl) throw new Error('The file service did not return an upload URL.');\n\n // 2. PUT the bytes\n await putWithProgress(uploadUrl, file, mimeType, setProgress);\n\n // 3. complete\n await wspaceMutate<{ completeUpload: { fileId: string } }>(\n `mutation BraCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) { fileId }\n }`,\n { input: { sessionId, fileSize, folderId } },\n apiGatewayUrl\n );\n setProgress(100);\n return folderId;\n },\n onSuccess: (folderId) => {\n qc.invalidateQueries({ queryKey: folderKey(entityType, entityId) });\n qc.invalidateQueries({ queryKey: filesKey(folderId) });\n },\n });\n\n return { ...mutation, progress };\n};\n\nconst useDownloadFile = () => {\n const { apiGatewayUrl } = useBrainyRich();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await wspaceFetch<{ getFileDownloadUrl: string }>(\n `query BraGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }`,\n { id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n apiGatewayUrl\n );\n return data.getFileDownloadUrl;\n },\n });\n};\n\n/**\n * Remove one document. `deleteFile(id: ID!): Boolean!` is a real mutation on the\n * files subgraph of the same workspace supergraph; the gateway enforces its\n * `delete`/`file` @rbac directive, so a caller without the right gets a GraphQL\n * error surfaced below rather than a silently ignored click.\n */\nconst useDeleteFile = (folderId: string | null | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await wspaceMutate<{ deleteFile: boolean }>(\n `mutation BraDeleteFile($id: ID!) { deleteFile(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return data.deleteFile;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: filesKey(folderId) }),\n });\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nconst formatSize = (bytes: string): string => {\n const n = Number(bytes);\n if (!Number.isFinite(n) || n <= 0) return '—';\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n};\n\nexport interface DocumentsPanelProps {\n /** Polymorphic entity type, e.g. \"brainyrich-account\" | \"brainyrich-household\". */\n entityType: string;\n /** The bra entity's id (an ID scalar). */\n entityId: string;\n /** Optional heading; hide with `hideHeading`. */\n heading?: string;\n hideHeading?: boolean;\n}\n\nexport function DocumentsPanel({\n entityType,\n entityId,\n heading = 'Documents',\n hideHeading = false,\n}: DocumentsPanelProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const folder = useEntityFolder(entityType, entityId);\n const files = useFolderFiles(folder.data?.id);\n const upload = useDocumentUpload(entityType, entityId);\n const download = useDownloadFile();\n const remove = useDeleteFile(folder.data?.id);\n\n const [dragActive, setDragActive] = useState(false);\n const [fileToDelete, setFileToDelete] = useState<FilesFile | null>(null);\n\n const onPick = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) upload.mutate(file);\n e.target.value = '';\n },\n [upload]\n );\n\n // The upload mutation handles one file per call, so the drop zone accepts one\n // — matching the picker, which is deliberately not `multiple`.\n const onDrop = useCallback(\n (e: React.DragEvent<HTMLElement>) => {\n e.preventDefault();\n setDragActive(false);\n if (upload.isPending) return;\n const file = e.dataTransfer.files?.[0];\n if (file) upload.mutate(file);\n },\n [upload]\n );\n\n const onDownload = async (id: string) => {\n const url = await download.mutateAsync(id);\n if (url) window.open(url, '_blank', 'noopener,noreferrer');\n };\n\n const loading = folder.isLoading || (Boolean(folder.data) && files.isLoading);\n const list = files.data ?? [];\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n {!hideHeading && (\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n {heading}\n </h3>\n )}\n <div className=\"ml-auto\">\n <input\n ref={inputRef}\n type=\"file\"\n className=\"sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onChange={onPick}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => inputRef.current?.click()}\n disabled={upload.isPending}\n >\n <Upload className=\"size-4\" aria-hidden=\"true\" />\n {upload.isPending ? `Uploading ${upload.progress}%` : 'Upload'}\n </Button>\n </div>\n </div>\n\n {upload.isPending && (\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-label=\"Upload progress\"\n aria-valuenow={upload.progress}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full bg-primary motion-safe:transition-[width] motion-safe:duration-200\"\n style={{ width: `${upload.progress}%` }}\n />\n </div>\n )}\n\n {/* Drop target — same single-file upload path as the picker button */}\n <button\n type=\"button\"\n onClick={() => inputRef.current?.click()}\n disabled={upload.isPending}\n onDragOver={(e) => {\n e.preventDefault();\n if (!upload.isPending) setDragActive(true);\n }}\n onDragLeave={() => setDragActive(false)}\n onDrop={onDrop}\n className={`w-full rounded-lg border border-dashed px-4 py-8 text-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-action-primary-border)] disabled:cursor-not-allowed disabled:opacity-60 ${\n dragActive\n ? 'border-[var(--color-action-primary-border)] bg-bg-elevated'\n : 'border-border-subtle bg-bg-surface hover:border-[var(--color-action-primary-border)]'\n }`}\n >\n <UploadCloud className=\"mx-auto mb-2 size-6 text-text-secondary\" aria-hidden=\"true\" />\n <span className=\"block text-sm text-text-primary\">\n Drop a statement, KYC or tax document here\n </span>\n <span className=\"mt-0.5 block text-xs text-text-secondary\">\n or click to choose one file\n </span>\n </button>\n\n {loading ? (\n <div className=\"space-y-2\" aria-busy=\"true\">\n <Skeleton className=\"h-12 w-full rounded-md\" />\n <Skeleton className=\"h-12 w-full rounded-md\" />\n </div>\n ) : files.isError ? (\n <p className=\"text-sm text-status-error-text\">\n Could not load documents.{' '}\n <button\n type=\"button\"\n className=\"underline underline-offset-2\"\n onClick={() => files.refetch()}\n >\n Retry\n </button>\n </p>\n ) : list.length === 0 ? (\n <p className=\"text-center text-xs text-text-secondary\">\n No documents attached to this record yet.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {list.map((file) => (\n <li key={file.id}>\n <Card>\n <CardContent className=\"flex items-center gap-3 p-3\">\n <div className=\"flex size-9 shrink-0 items-center justify-center rounded-md bg-bg-sunken text-text-secondary\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{file.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatSize(file.size)} · {formatDate(file.createdAt)}\n </p>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Download ${file.name}`}\n disabled={download.isPending}\n onClick={() => onDownload(file.id)}\n >\n <Download className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"text-status-error-text hover:text-status-error-text\"\n aria-label={`Delete ${file.name}`}\n disabled={remove.isPending}\n onClick={() => setFileToDelete(file)}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </CardContent>\n </Card>\n </li>\n ))}\n </ul>\n )}\n\n {(upload.isError || download.isError || remove.isError) && (\n <p className=\"text-sm text-status-error-text\">\n {upload.error instanceof Error\n ? upload.error.message\n : remove.error instanceof Error\n ? `Could not delete the document. ${remove.error.message}`\n : download.error instanceof Error\n ? 'Could not open the document. Please try again.'\n : 'Something went wrong. Please try again.'}\n </p>\n )}\n\n <ConfirmDialog\n open={fileToDelete !== null}\n onOpenChange={(open) => {\n if (!open) setFileToDelete(null);\n }}\n title=\"Delete this document?\"\n description={\n fileToDelete\n ? `“${fileToDelete.name}” will be removed from this record. This cannot be undone.`\n : undefined\n }\n confirmLabel=\"Delete\"\n pendingLabel=\"Deleting…\"\n destructive\n pending={remove.isPending}\n onConfirm={() => {\n if (!fileToDelete) return;\n remove.mutate(fileToDelete.id, { onSuccess: () => setFileToDelete(null) });\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TagField.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/TagField.tsx"],"sourcesContent":["/**\n * TagField — REUSE of `wspace-tags-svc` UniversalTag (polymorphic-by-entity).\n * @module brainyrich/components/reuse/TagField\n *\n * Drop-in replacement for the free-text tag string inputs on Households /\n * Portfolios / Goals. Instead of writing a `tags` scalar on the bra entity,\n * this manages REAL `UniversalTag` assignments keyed by `(entityType, entityId)`\n * against the platform tag store — no bra-svc change required. The bra `tags`\n * scalar stays as legacy; this component is the canonical tag surface.\n *\n * Ops (all on the workspace supergraph):\n * - `getEntityTags(entityType, entityId)` → current assignments (chips)\n * - `searchTags(query, limit)` → typeahead over existing tags\n * - `assignTag(input)` → link an existing tag\n * - `createTag(input)` + `assignTag(...)` → create-from-label then link\n * - `removeTagAssignment(id)` → unlink a chip\n *\n * `createTag` needs a `vocabularyId`; we resolve a stable, workspace-scoped\n * \"brainyrich\" vocabulary via `getVocabularyByKey` (creating it on first use).\n *\n * Presentational + self-contained: owns its react-query hooks, reads the gateway\n * base URL from `useBrainyRich()`, uses fe-libs/ui primitives + semantic tokens.\n */\n\nimport { useState, type KeyboardEvent } from 'react';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { Plus, Tag as TagIcon, X } from 'lucide-react';\nimport { Badge, Button, Input, Label, Skeleton } from '@burdenoff/fe-libs/ui';\n\nimport { useBrainyRich } from '../../providers/BrainyRichProvider';\nimport { wspaceFetch, wspaceMutate } from './transport';\n\n// ============================================================================\n// Types (mirror the UniversalTag SDL fields we select)\n// ============================================================================\n\ninterface UniversalTag {\n id: string;\n label: string;\n color: string | null;\n key: string;\n}\n\ninterface UniversalTagAssignment {\n id: string;\n tag: UniversalTag;\n}\n\nconst TAG_FIELDS = 'id label color key';\nconst BRAINYRICH_VOCABULARY_KEY = 'brainyrich';\n\nconst entityTagsKey = (entityType: string, entityId: string) =>\n ['brainyrich', 'entity-tags', entityType, entityId] as const;\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48) || 'tag';\n\n// ============================================================================\n// Hooks (co-located; reuse the shared workspace transport)\n// ============================================================================\n\nconst useEntityTags = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: entityTagsKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getEntityTags: UniversalTagAssignment[] }>(\n `query BraGetEntityTags($entityType: String!, $entityId: ID!) {\n getEntityTags(entityType: $entityType, entityId: $entityId) {\n id\n tag { ${TAG_FIELDS} }\n }\n }`,\n { entityType, entityId },\n apiGatewayUrl\n );\n return data.getEntityTags;\n },\n });\n};\n\nconst useTagSearch = (query: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const trimmed = query.trim();\n return useQuery({\n queryKey: ['brainyrich', 'tag-search', trimmed],\n enabled: trimmed.length > 0,\n queryFn: async () => {\n const data = await wspaceFetch<{ searchTags: UniversalTag[] }>(\n `query BraSearchTags($query: String!, $limit: Int) {\n searchTags(query: $query, limit: $limit) { ${TAG_FIELDS} }\n }`,\n { query: trimmed, limit: 8 },\n apiGatewayUrl\n );\n return data.searchTags;\n },\n });\n};\n\n/** Resolve (creating on first use) the workspace-scoped \"brainyrich\" vocabulary. */\nconst resolveVocabularyId = async (baseUrl?: string): Promise<string> => {\n const existing = await wspaceFetch<{ getVocabularyByKey: { id: string } | null }>(\n `query BraGetVocabulary($key: String!) {\n getVocabularyByKey(key: $key) { id }\n }`,\n { key: BRAINYRICH_VOCABULARY_KEY },\n baseUrl\n );\n if (existing.getVocabularyByKey?.id) return existing.getVocabularyByKey.id;\n\n const created = await wspaceMutate<{ createVocabulary: { id: string } }>(\n `mutation BraCreateVocabulary($input: CreateVocabularyInput!) {\n createVocabulary(input: $input) { id }\n }`,\n {\n input: {\n key: BRAINYRICH_VOCABULARY_KEY,\n name: 'BrainyRich',\n description: 'Tags for BrainyRich households, portfolios and goals.',\n allowCustomTags: true,\n },\n },\n baseUrl\n );\n return created.createVocabulary.id;\n};\n\nconst useAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (tagId: string) => {\n const data = await wspaceMutate<{ assignTag: { id: string } }>(\n `mutation BraAssignTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId } },\n apiGatewayUrl\n );\n return data.assignTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\nconst useCreateAndAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (label: string) => {\n const trimmed = label.trim();\n if (!trimmed) throw new Error('A tag label is required.');\n const vocabularyId = await resolveVocabularyId(apiGatewayUrl);\n // Unique key avoids collisions inside the vocabulary; the label is the display text.\n const key = `${slugify(trimmed)}-${Math.random().toString(36).slice(2, 6)}`;\n const created = await wspaceMutate<{ createTag: { id: string } }>(\n `mutation BraCreateTag($input: CreateTagInput!) {\n createTag(input: $input) { id }\n }`,\n { input: { vocabularyId, key, label: trimmed } },\n apiGatewayUrl\n );\n await wspaceMutate<{ assignTag: { id: string } }>(\n `mutation BraAssignCreatedTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId: created.createTag.id } },\n apiGatewayUrl\n );\n return created.createTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\nconst useRemoveTagAssignment = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (assignmentId: string) => {\n const data = await wspaceMutate<{ removeTagAssignment: boolean }>(\n `mutation BraRemoveTagAssignment($id: ID!) { removeTagAssignment(id: $id) }`,\n { id: assignmentId },\n apiGatewayUrl\n );\n return data.removeTagAssignment;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface TagFieldProps {\n /** Polymorphic entity type, e.g. \"brainyrich-household\". */\n entityType: string;\n /** The bra entity's id (an ID scalar). */\n entityId: string;\n /** Optional field label (hidden visually when `hideLabel`). */\n label?: string;\n hideLabel?: boolean;\n}\n\nexport function TagField({\n entityType,\n entityId,\n label = 'Tags',\n hideLabel = false,\n}: TagFieldProps) {\n const [draft, setDraft] = useState('');\n const assignments = useEntityTags(entityType, entityId);\n const search = useTagSearch(draft);\n const assign = useAssignTag(entityType, entityId);\n const createAndAssign = useCreateAndAssignTag(entityType, entityId);\n const remove = useRemoveTagAssignment(entityType, entityId);\n\n const busy = assign.isPending || createAndAssign.isPending;\n const assigned = assignments.data ?? [];\n const assignedTagIds = new Set(assigned.map((a) => a.tag.id));\n const suggestions = (search.data ?? []).filter((t) => !assignedTagIds.has(t.id));\n const trimmed = draft.trim();\n const exactExists = suggestions.some((t) => t.label.toLowerCase() === trimmed.toLowerCase());\n\n const inputId = `tagfield-${entityType}-${entityId}`;\n\n const commitCreate = async () => {\n if (!trimmed || busy) return;\n await createAndAssign.mutateAsync(trimmed);\n setDraft('');\n };\n\n const commitAssign = async (tagId: string) => {\n if (busy) return;\n await assign.mutateAsync(tagId);\n setDraft('');\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n void commitCreate();\n }\n };\n\n return (\n <div className=\"space-y-2\">\n {!hideLabel && (\n <Label htmlFor={inputId} className=\"text-text-primary\">\n {label}\n </Label>\n )}\n\n {/* Current assignments */}\n {assignments.isLoading ? (\n <div className=\"flex flex-wrap gap-2\" aria-busy=\"true\">\n <Skeleton className=\"h-6 w-16 rounded-full\" />\n <Skeleton className=\"h-6 w-20 rounded-full\" />\n <Skeleton className=\"h-6 w-12 rounded-full\" />\n </div>\n ) : assignments.isError ? (\n <p className=\"text-sm text-status-error-text\">\n Could not load tags.{' '}\n <button\n type=\"button\"\n className=\"underline underline-offset-2\"\n onClick={() => assignments.refetch()}\n >\n Retry\n </button>\n </p>\n ) : assigned.length === 0 ? (\n <p className=\"flex items-center gap-1.5 text-sm text-text-secondary\">\n <TagIcon className=\"size-3.5\" aria-hidden=\"true\" />\n No tags yet — add one below.\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-2\">\n {assigned.map((a) => (\n <Badge key={a.id} variant=\"secondary\" className=\"gap-1 pr-1\">\n <span>{a.tag.label}</span>\n <button\n type=\"button\"\n aria-label={`Remove tag ${a.tag.label}`}\n className=\"rounded-full p-0.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-border-focus disabled:opacity-50\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(a.id)}\n >\n <X className=\"size-3\" aria-hidden=\"true\" />\n </button>\n </Badge>\n ))}\n </div>\n )}\n\n {/* Add control */}\n <div className=\"relative\">\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n placeholder=\"Search or create a tag…\"\n aria-label=\"Search or create a tag\"\n autoComplete=\"off\"\n disabled={busy}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={commitCreate}\n disabled={!trimmed || busy || exactExists}\n >\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n Create\n </Button>\n </div>\n\n {/* Typeahead suggestions */}\n {trimmed.length > 0 && (suggestions.length > 0 || search.isFetching) && (\n <ul\n className=\"absolute z-10 mt-1 w-full overflow-hidden rounded-md border border-border-subtle bg-bg-surface shadow-md\"\n role=\"listbox\"\n aria-label=\"Tag suggestions\"\n >\n {search.isFetching && suggestions.length === 0 ? (\n <li className=\"px-3 py-2 text-sm text-text-secondary\">Searching…</li>\n ) : (\n suggestions.map((t) => (\n <li key={t.id} role=\"option\" aria-selected=\"false\">\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-text-primary hover:bg-bg-sunken focus-visible:bg-bg-sunken focus-visible:outline-none disabled:opacity-50\"\n disabled={busy}\n onClick={() => commitAssign(t.id)}\n >\n <TagIcon className=\"size-3.5 text-text-secondary\" aria-hidden=\"true\" />\n {t.label}\n </button>\n </li>\n ))\n )}\n </ul>\n )}\n </div>\n\n {(assign.isError || createAndAssign.isError || remove.isError) && (\n <p className=\"text-sm text-status-error-text\">Could not update tags. Please try again.</p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TagField.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/TagField.tsx"],"sourcesContent":["/**\n * TagField — REUSE of `wspace-tags-svc` UniversalTag (polymorphic-by-entity).\n * @module brainyrich/components/reuse/TagField\n *\n * Drop-in replacement for the free-text tag string inputs on Households /\n * Portfolios / Goals. Instead of writing a `tags` scalar on the bra entity,\n * this manages REAL `UniversalTag` assignments keyed by `(entityType, entityId)`\n * against the platform tag store — no bra-svc change required. The bra `tags`\n * scalar stays as legacy; this component is the canonical tag surface.\n *\n * Ops (all on the workspace supergraph):\n * - `getEntityTags(entityType, entityId)` → current assignments (chips)\n * - `searchTags(query, limit)` → typeahead over existing tags\n * - `assignTag(input)` → link an existing tag\n * - `createTag(input)` + `assignTag(...)` → create-from-label then link\n * - `removeTagAssignment(id)` → unlink a chip\n *\n * `createTag` needs a `vocabularyId`; we resolve a stable, workspace-scoped\n * \"brainyrich\" vocabulary via `getVocabularyByKey` (creating it on first use).\n *\n * Presentational + self-contained: owns its react-query hooks, reads the gateway\n * base URL from `useBrainyRich()`, uses fe-libs/ui primitives + semantic tokens.\n */\n\nimport { useState, type KeyboardEvent } from 'react';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { Plus, Tag as TagIcon, X } from 'lucide-react';\nimport { Badge, Button, Input, Label, Skeleton } from '@burdenoff/fe-libs/ui';\n\nimport { useBrainyRich } from '../../providers/BrainyRichProvider';\nimport { wspaceFetch, wspaceMutate } from './transport';\n\n// ============================================================================\n// Types (mirror the UniversalTag SDL fields we select)\n// ============================================================================\n\ninterface UniversalTag {\n id: string;\n label: string;\n color: string | null;\n key: string;\n}\n\ninterface UniversalTagAssignment {\n id: string;\n tag: UniversalTag;\n}\n\nconst TAG_FIELDS = 'id label color key';\nconst BRAINYRICH_VOCABULARY_KEY = 'brainyrich';\n\nconst entityTagsKey = (entityType: string, entityId: string) =>\n ['brainyrich', 'entity-tags', entityType, entityId] as const;\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48) || 'tag';\n\n// ============================================================================\n// Hooks (co-located; reuse the shared workspace transport)\n// ============================================================================\n\nconst useEntityTags = (entityType: string, entityId: string | undefined) => {\n const { apiGatewayUrl } = useBrainyRich();\n return useQuery({\n queryKey: entityTagsKey(entityType, entityId ?? ''),\n enabled: Boolean(entityId),\n queryFn: async () => {\n const data = await wspaceFetch<{ getEntityTags: UniversalTagAssignment[] }>(\n `query BraGetEntityTags($entityType: String!, $entityId: ID!) {\n getEntityTags(entityType: $entityType, entityId: $entityId) {\n id\n tag { ${TAG_FIELDS} }\n }\n }`,\n { entityType, entityId },\n apiGatewayUrl\n );\n return data.getEntityTags;\n },\n });\n};\n\nconst useTagSearch = (query: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const trimmed = query.trim();\n return useQuery({\n queryKey: ['brainyrich', 'tag-search', trimmed],\n enabled: trimmed.length > 0,\n queryFn: async () => {\n const data = await wspaceFetch<{ searchTags: UniversalTag[] }>(\n `query BraSearchTags($query: String!, $limit: Int) {\n searchTags(query: $query, limit: $limit) { ${TAG_FIELDS} }\n }`,\n { query: trimmed, limit: 8 },\n apiGatewayUrl\n );\n return data.searchTags;\n },\n });\n};\n\n/** Resolve (creating on first use) the workspace-scoped \"brainyrich\" vocabulary. */\nconst resolveVocabularyId = async (baseUrl?: string): Promise<string> => {\n const existing = await wspaceFetch<{ getVocabularyByKey: { id: string } | null }>(\n `query BraGetVocabulary($key: String!) {\n getVocabularyByKey(key: $key) { id }\n }`,\n { key: BRAINYRICH_VOCABULARY_KEY },\n baseUrl\n );\n if (existing.getVocabularyByKey?.id) return existing.getVocabularyByKey.id;\n\n const created = await wspaceMutate<{ createVocabulary: { id: string } }>(\n `mutation BraCreateVocabulary($input: CreateVocabularyInput!) {\n createVocabulary(input: $input) { id }\n }`,\n {\n input: {\n key: BRAINYRICH_VOCABULARY_KEY,\n name: 'BrainyRich',\n description: 'Tags for BrainyRich households, portfolios and goals.',\n allowCustomTags: true,\n },\n },\n baseUrl\n );\n return created.createVocabulary.id;\n};\n\nconst useAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (tagId: string) => {\n const data = await wspaceMutate<{ assignTag: { id: string } }>(\n `mutation BraAssignTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId } },\n apiGatewayUrl\n );\n return data.assignTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\nconst useCreateAndAssignTag = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (label: string) => {\n const trimmed = label.trim();\n if (!trimmed) throw new Error('A tag label is required.');\n const vocabularyId = await resolveVocabularyId(apiGatewayUrl);\n // Unique key avoids collisions inside the vocabulary; the label is the display text.\n const key = `${slugify(trimmed)}-${Math.random().toString(36).slice(2, 6)}`;\n const created = await wspaceMutate<{ createTag: { id: string } }>(\n `mutation BraCreateTag($input: CreateTagInput!) {\n createTag(input: $input) { id }\n }`,\n { input: { vocabularyId, key, label: trimmed } },\n apiGatewayUrl\n );\n await wspaceMutate<{ assignTag: { id: string } }>(\n `mutation BraAssignCreatedTag($input: AssignTagInput!) {\n assignTag(input: $input) { id }\n }`,\n { input: { entityType, entityId, tagId: created.createTag.id } },\n apiGatewayUrl\n );\n return created.createTag;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\nconst useRemoveTagAssignment = (entityType: string, entityId: string) => {\n const { apiGatewayUrl } = useBrainyRich();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (assignmentId: string) => {\n const data = await wspaceMutate<{ removeTagAssignment: boolean }>(\n `mutation BraRemoveTagAssignment($id: ID!) { removeTagAssignment(id: $id) }`,\n { id: assignmentId },\n apiGatewayUrl\n );\n return data.removeTagAssignment;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: entityTagsKey(entityType, entityId) }),\n });\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport interface TagFieldProps {\n /** Polymorphic entity type, e.g. \"brainyrich-household\". */\n entityType: string;\n /** The bra entity's id (an ID scalar). */\n entityId: string;\n /** Optional field label (hidden visually when `hideLabel`). */\n label?: string;\n hideLabel?: boolean;\n}\n\nexport function TagField({\n entityType,\n entityId,\n label = 'Tags',\n hideLabel = false,\n}: TagFieldProps) {\n const [draft, setDraft] = useState('');\n const assignments = useEntityTags(entityType, entityId);\n const search = useTagSearch(draft);\n const assign = useAssignTag(entityType, entityId);\n const createAndAssign = useCreateAndAssignTag(entityType, entityId);\n const remove = useRemoveTagAssignment(entityType, entityId);\n\n const busy = assign.isPending || createAndAssign.isPending;\n const assigned = assignments.data ?? [];\n const assignedTagIds = new Set(assigned.map((a) => a.tag.id));\n const suggestions = (search.data ?? []).filter((t) => !assignedTagIds.has(t.id));\n const trimmed = draft.trim();\n const exactExists = suggestions.some((t) => t.label.toLowerCase() === trimmed.toLowerCase());\n\n const inputId = `tagfield-${entityType}-${entityId}`;\n\n const commitCreate = async () => {\n if (!trimmed || busy) return;\n await createAndAssign.mutateAsync(trimmed);\n setDraft('');\n };\n\n const commitAssign = async (tagId: string) => {\n if (busy) return;\n await assign.mutateAsync(tagId);\n setDraft('');\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n void commitCreate();\n }\n };\n\n return (\n <div className=\"space-y-2\">\n {!hideLabel && (\n <Label htmlFor={inputId} className=\"text-text-primary\">\n {label}\n </Label>\n )}\n\n {/* Current assignments */}\n {assignments.isLoading ? (\n <div className=\"flex flex-wrap gap-2\" aria-busy=\"true\">\n <Skeleton className=\"h-6 w-16 rounded-full\" />\n <Skeleton className=\"h-6 w-20 rounded-full\" />\n <Skeleton className=\"h-6 w-12 rounded-full\" />\n </div>\n ) : assignments.isError ? (\n <p className=\"text-sm text-status-error-text\">\n Could not load tags.{' '}\n <button\n type=\"button\"\n className=\"underline underline-offset-2\"\n onClick={() => assignments.refetch()}\n >\n Retry\n </button>\n </p>\n ) : assigned.length === 0 ? (\n <p className=\"flex items-center gap-1.5 text-sm text-text-secondary\">\n <TagIcon className=\"size-3.5\" aria-hidden=\"true\" />\n No tags yet — add one below.\n </p>\n ) : (\n <div className=\"flex flex-wrap gap-2\">\n {assigned.map((a) => (\n <Badge key={a.id} variant=\"secondary\" className=\"gap-1 pr-1\">\n <span>{a.tag.label}</span>\n <button\n type=\"button\"\n aria-label={`Remove tag ${a.tag.label}`}\n className=\"rounded-full p-0.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-border-focus disabled:opacity-50\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(a.id)}\n >\n <X className=\"size-3\" aria-hidden=\"true\" />\n </button>\n </Badge>\n ))}\n </div>\n )}\n\n {/* Add control */}\n <div className=\"relative\">\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n placeholder=\"Search or create a tag…\"\n aria-label=\"Search or create a tag\"\n autoComplete=\"off\"\n disabled={busy}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={commitCreate}\n disabled={!trimmed || busy || exactExists}\n >\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n Create\n </Button>\n </div>\n\n {/* Typeahead suggestions */}\n {trimmed.length > 0 && (suggestions.length > 0 || search.isFetching) && (\n <ul\n className=\"absolute z-10 mt-1 w-full overflow-hidden rounded-md border border-border-subtle bg-bg-surface shadow-md\"\n role=\"listbox\"\n aria-label=\"Tag suggestions\"\n >\n {search.isFetching && suggestions.length === 0 ? (\n <li className=\"px-3 py-2 text-sm text-text-secondary\">Searching…</li>\n ) : (\n suggestions.map((t) => (\n <li key={t.id} role=\"option\" aria-selected=\"false\">\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-text-primary hover:bg-bg-sunken focus-visible:bg-bg-sunken focus-visible:outline-none disabled:opacity-50\"\n disabled={busy}\n onClick={() => commitAssign(t.id)}\n >\n <TagIcon className=\"size-3.5 text-text-secondary\" aria-hidden=\"true\" />\n {t.label}\n </button>\n </li>\n ))\n )}\n </ul>\n )}\n </div>\n\n {(assign.isError || createAndAssign.isError || remove.isError) && (\n <p className=\"text-sm text-status-error-text\">Could not update tags. Please try again.</p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/transport.ts"],"sourcesContent":["/**\n * Shared workspace-gateway transport for the BrainyRich REUSE components.\n * @module brainyrich/components/reuse/transport\n *\n * The four reuse components (TagField, DocumentsPanel, CommentThread,\n * ReviewReminders) consume PLATFORM subgraphs — `wspace-tags-svc`,\n * `wspace-files-svc`, `wspace-conversations-svc`, `wspace-calendar-svc` —\n * that are composed into the SAME workspace supergraph the BrainyRich MFE\n * already talks to. So every call routes through the identical transport the\n * `bra*` hooks use: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })`.\n *\n * This file only contains the transport primitive; each component owns its own\n * react-query hooks (kept co-located so a page can drop one component into a\n * Sheet/tab without pulling in the others).\n */\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in a short-lived in-memory\n * cache keyed by operationName+variables (~15s); mutations are never cached. A\n * read issued right after a write (the react-query refetch our `invalidateQueries`\n * triggers) would otherwise return the PRE-mutation response until the TTL lapses,\n * hiding just-created rows. fe-libs' documented remedy is that write-performing\n * callers clear those caches — we do exactly that after every reuse mutation.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\n/** Execute a workspace-gateway GraphQL operation with the workspace token. */\nexport const wspaceFetch = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n/** Mutation transport — identical to `wspaceFetch` but clears read caches after. */\nexport const wspaceMutate = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const data = await wspaceFetch<TData>(query, variables, baseUrl);\n clearGraphqlReadCaches();\n return data;\n};\n"],"mappings":";;AAgCA,IAAM,UAAqC;CACzC,IAAM,IAAI;AAGV,CAFA,EAAE,6BAA6B,OAAO,EACtC,EAAE,gCAAgC,OAAO,EACzC,EAAE,4BAA4B,OAAO;GAI1B,IAAc,OACzB,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;EACjB,CAAC;AAEF,KAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,yBAAyB;AAE1E,KAAI,CAAC,EAAS,KACZ,OAAU,MAAM,wCAAwC;AAE1D,QAAO,EAAS;GAIL,IAAe,OAC1B,GACA,GACA,MACmB;CACnB,IAAM,IAAO,MAAM,EAAmB,GAAO,GAAW,EAAQ;AAEhE,QADA,GAAwB,EACjB"}
1
+ {"version":3,"file":"transport.js","names":[],"sources":["../../../../src/brainyrich/components/reuse/transport.ts"],"sourcesContent":["/**\n * Shared workspace-gateway transport for the BrainyRich REUSE components.\n * @module brainyrich/components/reuse/transport\n *\n * The four reuse components (TagField, DocumentsPanel, CommentThread,\n * ReviewReminders) consume PLATFORM subgraphs — `wspace-tags-svc`,\n * `wspace-files-svc`, `wspace-conversations-svc`, `wspace-calendar-svc` —\n * that are composed into the SAME workspace supergraph the BrainyRich MFE\n * already talks to. So every call routes through the identical transport the\n * `bra*` hooks use: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })`.\n *\n * This file only contains the transport primitive; each component owns its own\n * react-query hooks (kept co-located so a page can drop one component into a\n * Sheet/tab without pulling in the others).\n */\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in a short-lived in-memory\n * cache keyed by operationName+variables (~15s); mutations are never cached. A\n * read issued right after a write (the react-query refetch our `invalidateQueries`\n * triggers) would otherwise return the PRE-mutation response until the TTL lapses,\n * hiding just-created rows. fe-libs' documented remedy is that write-performing\n * callers clear those caches — we do exactly that after every reuse mutation.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\n/** Execute a workspace-gateway GraphQL operation with the workspace token. */\nexport const wspaceFetch = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n return response.data;\n};\n\n/** Mutation transport — identical to `wspaceFetch` but clears read caches after. */\nexport const wspaceMutate = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const data = await wspaceFetch<TData>(query, variables, baseUrl);\n clearGraphqlReadCaches();\n return data;\n};\n"],"mappings":";;AAgCA,IAAM,UAAqC;CACzC,IAAM,IAAI;CAGV,AAFA,EAAE,6BAA6B,MAAM,GACrC,EAAE,gCAAgC,MAAM,GACxC,EAAE,4BAA4B,MAAM;AACtC,GAGa,IAAc,OACzB,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;CAClB,CAAC;CAED,IAAI,EAAS,QAAQ,QACnB,MAAU,MAAM,EAAS,OAAO,IAAI,WAAW,wBAAwB;CAEzE,IAAI,CAAC,EAAS,MACZ,MAAU,MAAM,uCAAuC;CAEzD,OAAO,EAAS;AAClB,GAGa,IAAe,OAC1B,GACA,GACA,MACmB;CACnB,IAAM,IAAO,MAAM,EAAmB,GAAO,GAAW,CAAO;CAE/D,OADA,EAAuB,GAChB;AACT"}
@@ -1,5 +1,4 @@
1
1
  import { ReactNode } from 'react';
2
-
3
2
  export declare function useReducedMotion(): boolean;
4
3
  declare const CORE_TOKENS: {
5
4
  readonly brand: "--color-action-primary-bg";