@dxos/plugin-thread 0.8.4-main.67995b8 → 0.8.4-main.dedc0f3

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 (248) hide show
  1. package/dist/lib/browser/ChannelContainer-4PYFOIDK.mjs +16 -0
  2. package/dist/lib/browser/{ChatContainer-AIGIWAUG.mjs → ChatContainer-EXNNREYB.mjs} +4 -4
  3. package/dist/lib/browser/{app-graph-builder-N7BE5TYW.mjs → app-graph-builder-FHAOPO57.mjs} +5 -5
  4. package/dist/lib/browser/app-graph-builder-FHAOPO57.mjs.map +7 -0
  5. package/dist/lib/browser/{call-manager-NIPDYUVD.mjs → call-manager-RMPTWSTF.mjs} +4 -4
  6. package/dist/lib/browser/call-manager-RMPTWSTF.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-LGSDKXPF.mjs → chunk-4APCDRSH.mjs} +1 -1
  8. package/dist/lib/browser/{chunk-LGSDKXPF.mjs.map → chunk-4APCDRSH.mjs.map} +1 -1
  9. package/dist/lib/browser/{chunk-KWPRNHTK.mjs → chunk-7W7QK5ZP.mjs} +232 -230
  10. package/dist/lib/browser/chunk-7W7QK5ZP.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-G4CNILRR.mjs +23 -0
  12. package/dist/lib/browser/{chunk-FR7KJPNY.mjs.map → chunk-G4CNILRR.mjs.map} +3 -3
  13. package/dist/lib/browser/{chunk-GCLD5ESP.mjs → chunk-KTWYVC5X.mjs} +22 -12
  14. package/dist/lib/browser/chunk-KTWYVC5X.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-PBMNFG3B.mjs +376 -0
  16. package/dist/lib/browser/chunk-PBMNFG3B.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-ERWASUQK.mjs → chunk-RI3Z6MK3.mjs} +38 -6
  18. package/dist/lib/{node-esm/chunk-25ABSYP2.mjs.map → browser/chunk-RI3Z6MK3.mjs.map} +4 -4
  19. package/dist/lib/browser/{chunk-6NSMBO3B.mjs → chunk-XYUJXHYV.mjs} +55 -5
  20. package/dist/lib/browser/chunk-XYUJXHYV.mjs.map +7 -0
  21. package/dist/lib/browser/{chunk-ZE7KWN36.mjs → chunk-ZCEU5K23.mjs} +461 -240
  22. package/dist/lib/browser/chunk-ZCEU5K23.mjs.map +7 -0
  23. package/dist/lib/browser/chunk-ZH2WPTNP.mjs +618 -0
  24. package/dist/lib/browser/chunk-ZH2WPTNP.mjs.map +7 -0
  25. package/dist/lib/browser/index.mjs +20 -9
  26. package/dist/lib/browser/index.mjs.map +3 -3
  27. package/dist/lib/browser/{intent-resolver-JFGLZ6VI.mjs → intent-resolver-J7OCP2P6.mjs} +67 -9
  28. package/dist/lib/browser/intent-resolver-J7OCP2P6.mjs.map +7 -0
  29. package/dist/lib/browser/{markdown-M3FMR7OD.mjs → markdown-Z677YORA.mjs} +4 -4
  30. package/dist/lib/browser/markdown-Z677YORA.mjs.map +7 -0
  31. package/dist/lib/browser/meta.json +1 -1
  32. package/dist/lib/browser/{react-root-JEUSQXI6.mjs → react-root-XKOD4KRB.mjs} +9 -9
  33. package/dist/lib/browser/{react-surface-XWS6GIZY.mjs → react-surface-GVGZRBDK.mjs} +9 -9
  34. package/dist/lib/browser/react-surface-GVGZRBDK.mjs.map +7 -0
  35. package/dist/lib/browser/{settings-E32MTL7A.mjs → settings-GRKEID73.mjs} +2 -2
  36. package/dist/lib/browser/{state-H6CYONWE.mjs → state-2T4KDWBX.mjs} +2 -2
  37. package/dist/lib/browser/{state-H6CYONWE.mjs.map → state-2T4KDWBX.mjs.map} +2 -2
  38. package/dist/lib/browser/toolkit-KUPIIFC6.mjs +80 -0
  39. package/dist/lib/browser/toolkit-KUPIIFC6.mjs.map +7 -0
  40. package/dist/lib/browser/types/index.mjs +1 -1
  41. package/dist/lib/node-esm/{ChannelContainer-7FXCKO7X.mjs → ChannelContainer-KQQEZWUN.mjs} +7 -7
  42. package/dist/lib/node-esm/{ChatContainer-IQUWU426.mjs → ChatContainer-QVQKFBWA.mjs} +4 -4
  43. package/dist/lib/node-esm/{app-graph-builder-VCW76Z6V.mjs → app-graph-builder-XEYWX5FC.mjs} +5 -5
  44. package/dist/lib/node-esm/app-graph-builder-XEYWX5FC.mjs.map +7 -0
  45. package/dist/lib/node-esm/{call-manager-D6O5ZJJ4.mjs → call-manager-QAREJFVX.mjs} +4 -4
  46. package/dist/lib/node-esm/call-manager-QAREJFVX.mjs.map +7 -0
  47. package/dist/lib/node-esm/{chunk-OU5BYIDO.mjs → chunk-2V3WSLUZ.mjs} +55 -5
  48. package/dist/lib/node-esm/chunk-2V3WSLUZ.mjs.map +7 -0
  49. package/dist/lib/node-esm/chunk-4T45PCKP.mjs +25 -0
  50. package/dist/lib/node-esm/{chunk-2CXOK2TD.mjs.map → chunk-4T45PCKP.mjs.map} +3 -3
  51. package/dist/lib/node-esm/chunk-DKCQCENK.mjs +377 -0
  52. package/dist/lib/node-esm/chunk-DKCQCENK.mjs.map +7 -0
  53. package/dist/lib/node-esm/{chunk-25ABSYP2.mjs → chunk-JNPKMT7O.mjs} +38 -6
  54. package/dist/lib/node-esm/chunk-JNPKMT7O.mjs.map +7 -0
  55. package/dist/lib/node-esm/chunk-LE2LIYGX.mjs +619 -0
  56. package/dist/lib/node-esm/chunk-LE2LIYGX.mjs.map +7 -0
  57. package/dist/lib/node-esm/{chunk-TDFHTCZZ.mjs → chunk-P6E247RF.mjs} +22 -12
  58. package/dist/lib/node-esm/chunk-P6E247RF.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-75RJ5DJI.mjs → chunk-PYTVBN5J.mjs} +1 -1
  60. package/dist/lib/node-esm/{chunk-75RJ5DJI.mjs.map → chunk-PYTVBN5J.mjs.map} +1 -1
  61. package/dist/lib/node-esm/{chunk-C3XFMUAY.mjs → chunk-SNKFZQST.mjs} +232 -230
  62. package/dist/lib/node-esm/chunk-SNKFZQST.mjs.map +7 -0
  63. package/dist/lib/node-esm/{chunk-IHDNQLLR.mjs → chunk-TIPIOH2J.mjs} +461 -240
  64. package/dist/lib/node-esm/chunk-TIPIOH2J.mjs.map +7 -0
  65. package/dist/lib/node-esm/index.mjs +20 -9
  66. package/dist/lib/node-esm/index.mjs.map +3 -3
  67. package/dist/lib/node-esm/{intent-resolver-OXGNQ44Y.mjs → intent-resolver-SR2LW4HF.mjs} +67 -9
  68. package/dist/lib/node-esm/intent-resolver-SR2LW4HF.mjs.map +7 -0
  69. package/dist/lib/node-esm/{markdown-INKTE4MH.mjs → markdown-FL4IXLRP.mjs} +4 -4
  70. package/dist/lib/node-esm/markdown-FL4IXLRP.mjs.map +7 -0
  71. package/dist/lib/node-esm/meta.json +1 -1
  72. package/dist/lib/node-esm/{react-root-XYYY2JXZ.mjs → react-root-4JWDRIQB.mjs} +9 -9
  73. package/dist/lib/node-esm/{react-surface-MJ33KPYE.mjs → react-surface-WLQUVRAX.mjs} +9 -9
  74. package/dist/lib/node-esm/react-surface-WLQUVRAX.mjs.map +7 -0
  75. package/dist/lib/node-esm/{settings-SJ24YG7M.mjs → settings-F2ODVNNW.mjs} +2 -2
  76. package/dist/lib/node-esm/{state-D7WNDT3N.mjs → state-62TQKQVB.mjs} +2 -2
  77. package/dist/lib/node-esm/{state-D7WNDT3N.mjs.map → state-62TQKQVB.mjs.map} +2 -2
  78. package/dist/lib/node-esm/toolkit-KZIS7G36.mjs +81 -0
  79. package/dist/lib/node-esm/toolkit-KZIS7G36.mjs.map +7 -0
  80. package/dist/lib/node-esm/types/index.mjs +1 -1
  81. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  82. package/dist/types/src/calls/call-manager.d.ts.map +1 -1
  83. package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -1
  84. package/dist/types/src/calls/media-manager.d.ts +1 -1
  85. package/dist/types/src/calls/media-manager.d.ts.map +1 -1
  86. package/dist/types/src/calls/types.d.ts +1 -1
  87. package/dist/types/src/calls/types.d.ts.map +1 -1
  88. package/dist/types/src/calls/util/calls-service.d.ts +4 -2
  89. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
  90. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
  91. package/dist/types/src/calls-service.stories.d.ts +10 -8
  92. package/dist/types/src/calls-service.stories.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  94. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  95. package/dist/types/src/capabilities/call-manager.d.ts +1 -1
  96. package/dist/types/src/capabilities/call-manager.d.ts.map +1 -1
  97. package/dist/types/src/capabilities/capabilities.d.ts +2 -2
  98. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  99. package/dist/types/src/capabilities/index.d.ts +11 -10
  100. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  101. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  102. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  103. package/dist/types/src/capabilities/markdown.d.ts +1 -1
  104. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  105. package/dist/types/src/capabilities/react-root.d.ts +2 -2
  106. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  107. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  108. package/dist/types/src/capabilities/settings.d.ts +1 -1
  109. package/dist/types/src/capabilities/state.d.ts +2 -2
  110. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  111. package/dist/types/src/capabilities/toolkit.d.ts +5 -0
  112. package/dist/types/src/capabilities/toolkit.d.ts.map +1 -0
  113. package/dist/types/src/components/Call/Call.d.ts.map +1 -1
  114. package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
  115. package/dist/types/src/components/CallDebugPanel.d.ts +7 -0
  116. package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -1
  117. package/dist/types/src/components/CallSidebar.d.ts.map +1 -1
  118. package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
  119. package/dist/types/src/components/ChannelContainer.stories.d.ts +88 -3
  120. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
  121. package/dist/types/src/components/Chat.stories.d.ts +90 -4
  122. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  123. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  124. package/dist/types/src/components/Comments.stories.d.ts +156 -3
  125. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  126. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  127. package/dist/types/src/components/CommentsThreadContainer.d.ts +2 -2
  128. package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -1
  129. package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -1
  130. package/dist/types/src/components/Media/VideoObject.d.ts +1 -1
  131. package/dist/types/src/components/Media/VideoObject.stories.d.ts +15 -3
  132. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
  133. package/dist/types/src/components/MessageContainer.d.ts +4 -1
  134. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  135. package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
  136. package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -1
  137. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +154 -2
  138. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
  139. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +156 -3
  140. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
  141. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -1
  142. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
  143. package/dist/types/src/components/command-extension.d.ts.map +1 -1
  144. package/dist/types/src/components/testing.d.ts +1 -0
  145. package/dist/types/src/components/testing.d.ts.map +1 -1
  146. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  147. package/dist/types/src/hooks/index.d.ts +1 -0
  148. package/dist/types/src/hooks/index.d.ts.map +1 -1
  149. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +2 -0
  150. package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +1 -0
  151. package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -1
  152. package/dist/types/src/translations.d.ts +3 -1
  153. package/dist/types/src/translations.d.ts.map +1 -1
  154. package/dist/types/src/types/schema.d.ts +123 -108
  155. package/dist/types/src/types/schema.d.ts.map +1 -1
  156. package/dist/types/src/types/types.d.ts +255 -170
  157. package/dist/types/src/types/types.d.ts.map +1 -1
  158. package/dist/types/tsconfig.tsbuildinfo +1 -1
  159. package/package.json +56 -54
  160. package/src/ThreadPlugin.tsx +9 -2
  161. package/src/calls/call-manager.ts +2 -2
  162. package/src/calls/call-swarm-synchronizer.ts +1 -1
  163. package/src/calls/media-manager.ts +60 -34
  164. package/src/calls/types.ts +8 -4
  165. package/src/calls/util/calls-service.ts +65 -14
  166. package/src/calls/util/stub-media-streams.ts +62 -5
  167. package/src/calls-service.stories.tsx +76 -60
  168. package/src/capabilities/app-graph-builder.ts +8 -5
  169. package/src/capabilities/call-manager.ts +3 -2
  170. package/src/capabilities/capabilities.ts +2 -2
  171. package/src/capabilities/index.ts +1 -0
  172. package/src/capabilities/intent-resolver.ts +38 -4
  173. package/src/capabilities/markdown.ts +4 -3
  174. package/src/capabilities/react-surface.tsx +5 -4
  175. package/src/capabilities/state.ts +2 -1
  176. package/src/capabilities/toolkit.ts +78 -0
  177. package/src/components/Call/Call.tsx +3 -2
  178. package/src/components/Call/Toolbar.tsx +5 -5
  179. package/src/components/CallDebugPanel.tsx +108 -49
  180. package/src/components/CallSidebar.tsx +2 -1
  181. package/src/components/ChannelContainer.stories.tsx +6 -5
  182. package/src/components/ChannelContainer.tsx +7 -6
  183. package/src/components/Chat.stories.tsx +28 -26
  184. package/src/components/ChatContainer.tsx +8 -4
  185. package/src/components/Comments.stories.tsx +33 -29
  186. package/src/components/CommentsContainer.tsx +2 -1
  187. package/src/components/CommentsThreadContainer.tsx +9 -7
  188. package/src/components/Lobby/Lobby.tsx +1 -1
  189. package/src/components/Media/VideoObject.stories.tsx +30 -27
  190. package/src/components/MessageContainer.tsx +43 -9
  191. package/src/components/Participant/Participant.tsx +13 -7
  192. package/src/components/Participant/ParticipantGrid.tsx +2 -1
  193. package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +6 -5
  194. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +42 -39
  195. package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +1 -1
  196. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +2 -2
  197. package/src/components/ThreadComplementary.tsx +38 -8
  198. package/src/components/ThreadSettings.tsx +2 -2
  199. package/src/components/command-extension.ts +5 -2
  200. package/src/components/testing.ts +22 -0
  201. package/src/extensions/threads.ts +3 -3
  202. package/src/hooks/index.ts +1 -0
  203. package/src/hooks/useBlackCanvasStreamTrack.tsx +27 -0
  204. package/src/hooks/useDebugMode.ts +1 -1
  205. package/src/hooks/useVideoStreamTrack.tsx +5 -2
  206. package/src/testing/stories.ts +2 -2
  207. package/src/translations.ts +3 -1
  208. package/src/types/types.ts +21 -12
  209. package/src/typings/peermetrics-webrtc-stats.d.ts +17 -1
  210. package/src/typings.d.ts +8 -0
  211. package/dist/lib/browser/ChannelContainer-3GIE7ASU.mjs +0 -16
  212. package/dist/lib/browser/app-graph-builder-N7BE5TYW.mjs.map +0 -7
  213. package/dist/lib/browser/call-manager-NIPDYUVD.mjs.map +0 -7
  214. package/dist/lib/browser/chunk-3SGRT4NM.mjs +0 -367
  215. package/dist/lib/browser/chunk-3SGRT4NM.mjs.map +0 -7
  216. package/dist/lib/browser/chunk-6NSMBO3B.mjs.map +0 -7
  217. package/dist/lib/browser/chunk-ERWASUQK.mjs.map +0 -7
  218. package/dist/lib/browser/chunk-FR7KJPNY.mjs +0 -21
  219. package/dist/lib/browser/chunk-GCLD5ESP.mjs.map +0 -7
  220. package/dist/lib/browser/chunk-KWPRNHTK.mjs.map +0 -7
  221. package/dist/lib/browser/chunk-VUWC4IJM.mjs +0 -479
  222. package/dist/lib/browser/chunk-VUWC4IJM.mjs.map +0 -7
  223. package/dist/lib/browser/chunk-ZE7KWN36.mjs.map +0 -7
  224. package/dist/lib/browser/intent-resolver-JFGLZ6VI.mjs.map +0 -7
  225. package/dist/lib/browser/markdown-M3FMR7OD.mjs.map +0 -7
  226. package/dist/lib/browser/react-surface-XWS6GIZY.mjs.map +0 -7
  227. package/dist/lib/node-esm/app-graph-builder-VCW76Z6V.mjs.map +0 -7
  228. package/dist/lib/node-esm/call-manager-D6O5ZJJ4.mjs.map +0 -7
  229. package/dist/lib/node-esm/chunk-2CXOK2TD.mjs +0 -23
  230. package/dist/lib/node-esm/chunk-2MFNK53T.mjs +0 -480
  231. package/dist/lib/node-esm/chunk-2MFNK53T.mjs.map +0 -7
  232. package/dist/lib/node-esm/chunk-C3XFMUAY.mjs.map +0 -7
  233. package/dist/lib/node-esm/chunk-FLBFYGBK.mjs +0 -368
  234. package/dist/lib/node-esm/chunk-FLBFYGBK.mjs.map +0 -7
  235. package/dist/lib/node-esm/chunk-IHDNQLLR.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-OU5BYIDO.mjs.map +0 -7
  237. package/dist/lib/node-esm/chunk-TDFHTCZZ.mjs.map +0 -7
  238. package/dist/lib/node-esm/intent-resolver-OXGNQ44Y.mjs.map +0 -7
  239. package/dist/lib/node-esm/markdown-INKTE4MH.mjs.map +0 -7
  240. package/dist/lib/node-esm/react-surface-MJ33KPYE.mjs.map +0 -7
  241. /package/dist/lib/browser/{ChannelContainer-3GIE7ASU.mjs.map → ChannelContainer-4PYFOIDK.mjs.map} +0 -0
  242. /package/dist/lib/browser/{ChatContainer-AIGIWAUG.mjs.map → ChatContainer-EXNNREYB.mjs.map} +0 -0
  243. /package/dist/lib/browser/{react-root-JEUSQXI6.mjs.map → react-root-XKOD4KRB.mjs.map} +0 -0
  244. /package/dist/lib/browser/{settings-E32MTL7A.mjs.map → settings-GRKEID73.mjs.map} +0 -0
  245. /package/dist/lib/node-esm/{ChannelContainer-7FXCKO7X.mjs.map → ChannelContainer-KQQEZWUN.mjs.map} +0 -0
  246. /package/dist/lib/node-esm/{ChatContainer-IQUWU426.mjs.map → ChatContainer-QVQKFBWA.mjs.map} +0 -0
  247. /package/dist/lib/node-esm/{react-root-XYYY2JXZ.mjs.map → react-root-4JWDRIQB.mjs.map} +0 -0
  248. /package/dist/lib/node-esm/{settings-SJ24YG7M.mjs.map → settings-F2ODVNNW.mjs.map} +0 -0
@@ -2,15 +2,15 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { WebRTCStats } from '@peermetrics/webrtc-stats';
5
+ import { WebRTCStats, type WebRTCStatsEvent } from '@peermetrics/webrtc-stats';
6
6
  import React, { useEffect, useMemo, useState } from 'react';
7
7
 
8
- import { Panel } from '@dxos/devtools';
8
+ import { truncateKey } from '@dxos/debug';
9
+ import { JsonView, Panel } from '@dxos/devtools';
9
10
  import { log } from '@dxos/log';
10
- import { Input, useTranslation, type ThemedClassName } from '@dxos/react-ui';
11
- import { Json } from '@dxos/react-ui-syntax-highlighter';
11
+ import { IconButton, Input, type ThemedClassName, useTranslation } from '@dxos/react-ui';
12
12
 
13
- import { type GlobalState } from '../calls';
13
+ import { type EncodedTrackName, type GlobalState } from '../calls';
14
14
  import { meta } from '../meta';
15
15
 
16
16
  export type CallDebugPanelProps = ThemedClassName<{
@@ -19,11 +19,16 @@ export type CallDebugPanelProps = ThemedClassName<{
19
19
 
20
20
  export const CallDebugPanel = ({ state }: CallDebugPanelProps) => {
21
21
  const { t } = useTranslation(meta.id);
22
- const users = state?.call?.users;
23
- const self = state?.call?.self;
24
22
 
25
23
  const [open, setOpen] = useState(false);
26
24
  const handleToggle = () => setOpen(!open);
25
+ const [showServiceHistory, setShowServiceHistory] = useState(false);
26
+ const handleToggleServiceHistory = () => setShowServiceHistory(!showServiceHistory);
27
+
28
+ const handleCopyRaw = async () => {
29
+ await navigator.clipboard.writeText(JSON.stringify({ users: state?.call?.users, stats }, null, 2));
30
+ };
31
+
27
32
  const [showDetailedWebRTCStats, setShowDetailedWebRTCStats] = useState(false);
28
33
  const handleShowDetailedWebRTCStats = () => setShowDetailedWebRTCStats(!showDetailedWebRTCStats);
29
34
 
@@ -34,22 +39,24 @@ export const CallDebugPanel = ({ state }: CallDebugPanelProps) => {
34
39
  }),
35
40
  [],
36
41
  );
42
+ const [stats, setStats] = useState<WebRTCStatsEvent['data']>();
37
43
 
38
- const [stats, setStats] = useState<Record<string, any>>({});
39
44
  useEffect(() => {
40
45
  const pc = state?.media.peer?.session?.peerConnection;
41
- const handleStats = (stats: Record<string, any>) => setStats(stats.data);
46
+ const handleStats = (stats: WebRTCStatsEvent) => {
47
+ setStats(stats.data);
48
+ };
42
49
  let added = false;
43
50
  if (pc && showDetailedWebRTCStats) {
44
51
  webrtcStats.addConnection({ pc, peerId: 1, connectionId: '1' });
45
- webrtcStats.on('stats', handleStats);
52
+ webrtcStats.on('stats', handleStats as never);
46
53
  added = true;
47
54
  }
48
55
  return () => {
49
56
  try {
50
57
  if (pc && added) {
51
58
  webrtcStats.removeConnection({ pc });
52
- webrtcStats.removeListener('stats', handleStats);
59
+ webrtcStats.removeListener('stats', handleStats as never);
53
60
  }
54
61
  } catch (error) {
55
62
  log.error('error removing webrtc stats', { error, pc, peerId: 1, connectionId: '1' });
@@ -57,6 +64,8 @@ export const CallDebugPanel = ({ state }: CallDebugPanelProps) => {
57
64
  };
58
65
  }, [state?.media.peer?.session?.peerConnection, showDetailedWebRTCStats]);
59
66
 
67
+ const rows = useMemo(() => getCallStatusTable(state), [state?.call.users, state?.media.pulledAudioTracks]);
68
+
60
69
  return (
61
70
  <Panel
62
71
  id='meeting-status'
@@ -65,51 +74,101 @@ export const CallDebugPanel = ({ state }: CallDebugPanelProps) => {
65
74
  onToggle={handleToggle}
66
75
  title={t('meeting status title')}
67
76
  maxHeight={false}
68
- info={
69
- <div className='flex items-center gap-2'>
70
- <span title='Joined'>{self?.joined ? 'Active' : 'Inactive'}</span>
71
- {users?.length !== undefined && <span title='Users'>{users?.length ?? 0} User(s)</span>}
72
- </div>
73
- }
77
+ info={<div className='flex items-center gap-2'> {state?.call.joined ? 'Active' : 'Inactive'}</div>}
74
78
  >
75
- <div className='flex flex-col gap-2 overflow-y-auto'>
76
- <div className='flex items-row gap-2'>
79
+ <div className='flex flex-col w-full gap-2 text-xs'>
80
+ <div className='flex items-center gap-2'>
77
81
  <Input.Root>
78
82
  <Input.Label classNames={'text-sm'}>{t('show webrtc stats title')}</Input.Label>
79
83
  <Input.Checkbox checked={showDetailedWebRTCStats} onCheckedChange={handleShowDetailedWebRTCStats} />
80
84
  </Input.Root>
81
85
  </div>
82
- <Json
83
- classNames='text-sm'
84
- data={{
85
- users,
86
- activities: state?.call?.activities,
87
- ...(showDetailedWebRTCStats
88
- ? {
89
- webrtc: {
90
- connectionState: state?.media.peer?.session?.peerConnection.connectionState,
91
- iceConnectionState: state?.media.peer?.session?.peerConnection.iceConnectionState,
92
- stats,
93
- },
94
- }
95
- : {}),
96
- tracks: state?.media.peer?.session?.peerConnection.getTransceivers().map((transceiver) => {
97
- const track =
98
- transceiver.direction === 'recvonly' ? transceiver.receiver.track : transceiver.sender.track;
99
- return {
100
- id: track?.id,
101
- kind: track?.kind,
102
- direction: transceiver.direction,
103
- enabled: track?.enabled,
104
- muted: track?.muted,
105
- readyState: track?.readyState,
106
- settings: track?.getSettings(),
107
- };
108
- }),
109
- callsServiceHistory: state?.media.peer?.history.get(),
110
- }}
111
- />
86
+ <div className='flex items-center gap-2'>
87
+ <Input.Root>
88
+ <Input.Label classNames={'text-sm'}>{t('show calls history title')}</Input.Label>
89
+ <Input.Checkbox checked={showServiceHistory} onCheckedChange={handleToggleServiceHistory} />
90
+ </Input.Root>
91
+ </div>
92
+ <div className='flex items-center gap-2'>
93
+ <IconButton classNames={'text-sm'} icon='ph--copy--regular' label={'copy raw'} onClick={handleCopyRaw} />
94
+ </div>
95
+ <Table rows={rows} />
96
+ {showDetailedWebRTCStats && <JsonView data={{ stats }} />}
97
+ {showServiceHistory && <JsonView data={{ history: state?.media.peer?.history.get() }} />}
112
98
  </div>
113
99
  </Panel>
114
100
  );
115
101
  };
102
+
103
+ const getCallStatusTable = (state?: GlobalState): TableProps['rows'] => {
104
+ if (!state || !state.call?.users) {
105
+ return [];
106
+ }
107
+
108
+ const self = state.call.self;
109
+ const users = state.call.users
110
+ .filter((user) => user.id !== self!.id)
111
+ .map((user) => {
112
+ const isOk = {
113
+ audio:
114
+ user.tracks?.audio &&
115
+ state.media.pulledAudioTracks[user.tracks?.audio as EncodedTrackName]?.ctx.disposed === false,
116
+ video:
117
+ user.tracks?.video &&
118
+ state.media.pulledVideoStreams[user.tracks?.video as EncodedTrackName]?.ctx.disposed === false,
119
+ screenshare:
120
+ user.tracks?.screenshare &&
121
+ state.media.pulledVideoStreams[user.tracks?.screenshare as EncodedTrackName]?.ctx.disposed === false,
122
+ };
123
+
124
+ return {
125
+ ...user,
126
+ isOk,
127
+ };
128
+ });
129
+
130
+ return [
131
+ ['users', state.call.users.length ?? 0],
132
+ [
133
+ '*self* ' + (self?.name ?? truncateKey(self!.id, 8)),
134
+ self?.tracks?.audio && state.media.pushedAudioTrack ? 'AUD ✅' : 'AUD ❌',
135
+ self?.tracks?.video && state.media.pushedVideoTrack ? 'VID ✅' : 'VID ❌',
136
+ self?.tracks?.screenshareEnabled
137
+ ? self.tracks.screenshareEnabled && state.media.pushedScreenshareTrack
138
+ ? 'SCR ✅'
139
+ : 'SCR ❌'
140
+ : undefined,
141
+ ],
142
+
143
+ ...users.map((user) => [
144
+ user.name ?? truncateKey(user.id, 8),
145
+ user.isOk.audio ? 'AUD ✅' : 'AUD ❌',
146
+ user.isOk.video ? 'VID ✅' : 'VID ❌',
147
+ user.tracks?.screenshareEnabled ? (user.isOk.screenshare ? 'SCR ✅' : 'SCR ❌') : undefined,
148
+ ]),
149
+ ['ICE', state.media.peer?.session?.peerConnection.iceConnectionState ?? 'no connection'],
150
+ ];
151
+ };
152
+
153
+ export namespace Unit {
154
+ export const KB = (n?: number) => ((n ?? 0) / 1_000).toFixed(2);
155
+ }
156
+
157
+ export type TableProps = {
158
+ rows: (string | number | undefined)[][];
159
+ };
160
+
161
+ export const Table = ({ rows }: TableProps) => {
162
+ return (
163
+ <div className='w-full text-xs font-mono'>
164
+ {rows.map(([prefix, label, value, unit], i) => (
165
+ <div key={i} className='grid grid-cols-[3fr_1fr_1fr_1fr]'>
166
+ <div className='p-1'>{prefix}</div>
167
+ <div className='p-1'>{label}</div>
168
+ <div className='p-1'>{value}</div>
169
+ <div className='p-1'>{unit}</div>
170
+ </div>
171
+ ))}
172
+ </div>
173
+ );
174
+ };
@@ -6,9 +6,10 @@ import React from 'react';
6
6
 
7
7
  import { useCapability } from '@dxos/app-framework';
8
8
 
9
- import { ChannelContainer } from './ChannelContainer';
10
9
  import { ThreadCapabilities } from '../capabilities';
11
10
 
11
+ import { ChannelContainer } from './ChannelContainer';
12
+
12
13
  export const CallSidebar = () => {
13
14
  const call = useCapability(ThreadCapabilities.CallManager);
14
15
  return <ChannelContainer roomId={call.roomId} />;
@@ -12,13 +12,14 @@ import { withPluginManager } from '@dxos/app-framework/testing';
12
12
  import { ClientCapabilities } from '@dxos/plugin-client';
13
13
  import { Query, useQuery, useSpace } from '@dxos/react-client/echo';
14
14
  import { DataType } from '@dxos/schema';
15
- import { withLayout, ColumnContainer } from '@dxos/storybook-utils';
15
+ import { ColumnContainer, withLayout } from '@dxos/storybook-utils';
16
16
 
17
- import { ChannelContainer, type ChannelContainerProps } from './ChannelContainer';
18
17
  import { createThreadPlugins } from '../testing';
19
18
  import { translations } from '../translations';
20
19
  import { ChannelType, ThreadType } from '../types';
21
20
 
21
+ import { ChannelContainer, type ChannelContainerProps } from './ChannelContainer';
22
+
22
23
  // TODO(wittjosiah): Channel doesn't render full height.
23
24
  const Story = ({ roomId }: ChannelContainerProps) => {
24
25
  const space = useSpace();
@@ -30,7 +31,7 @@ const Story = ({ roomId }: ChannelContainerProps) => {
30
31
  return <ChannelContainer channel={channel} roomId={roomId} />;
31
32
  };
32
33
 
33
- const meta: Meta<ChannelContainerProps> = {
34
+ const meta = {
34
35
  title: 'plugins/plugin-thread/ChannelContainer',
35
36
  component: ChannelContainer,
36
37
  render: (args) => <Story {...args} />,
@@ -44,11 +45,11 @@ const meta: Meta<ChannelContainerProps> = {
44
45
  parameters: {
45
46
  translations,
46
47
  },
47
- };
48
+ } satisfies Meta<typeof ChannelContainer>;
48
49
 
49
50
  export default meta;
50
51
 
51
- type Story = StoryObj<ChannelContainerProps>;
52
+ type Story = StoryObj<typeof meta>;
52
53
 
53
54
  export const Default: Story = {
54
55
  args: {
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Rx } from '@effect-rx/rx-react';
6
- import React, { useCallback, useEffect, useMemo, useState, type ChangeEvent } from 'react';
6
+ import React, { type ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';
7
7
 
8
8
  import { useCapabilities, useCapability } from '@dxos/app-framework';
9
9
  import { Context } from '@dxos/context';
@@ -12,18 +12,19 @@ import { log } from '@dxos/log';
12
12
  import { useClient } from '@dxos/react-client';
13
13
  import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
14
14
  import { useIdentity } from '@dxos/react-client/halo';
15
- import { useTranslation, Input, ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
16
- import { ControlGroup, ControlItemInput, ControlGroupButton } from '@dxos/react-ui-form';
17
- import { ToolbarMenu, MenuProvider, createMenuAction, useMenuActions, createMenuItemGroup } from '@dxos/react-ui-menu';
15
+ import { ElevationProvider, Input, type ThemedClassName, useTranslation } from '@dxos/react-ui';
16
+ import { ControlGroup, ControlGroupButton, ControlItemInput } from '@dxos/react-ui-form';
17
+ import { MenuProvider, ToolbarMenu, createMenuAction, createMenuItemGroup, useMenuActions } from '@dxos/react-ui-menu';
18
18
  import { useSoundEffect } from '@dxos/react-ui-sfx';
19
19
  import { StackItem } from '@dxos/react-ui-stack';
20
20
 
21
- import { Call } from './Call';
22
- import ChatContainer from './ChatContainer';
23
21
  import { ThreadCapabilities } from '../capabilities';
24
22
  import { meta } from '../meta';
25
23
  import { type ChannelType } from '../types';
26
24
 
25
+ import { Call } from './Call';
26
+ import ChatContainer from './ChatContainer';
27
+
27
28
  export type ChannelContainerProps = {
28
29
  channel?: ChannelType;
29
30
  roomId?: string;
@@ -4,10 +4,10 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type Meta } from '@storybook/react-vite';
8
- import React, { useEffect, useState } from 'react';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
+ import React, { useState } from 'react';
9
9
 
10
- import { Capabilities, contributes, createSurface, IntentPlugin } from '@dxos/app-framework';
10
+ import { Capabilities, IntentPlugin, contributes, createSurface } from '@dxos/app-framework';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
12
12
  import { Obj, Ref } from '@dxos/echo';
13
13
  import { faker } from '@dxos/random';
@@ -15,35 +15,35 @@ import { useClient } from '@dxos/react-client';
15
15
  import { type Space } from '@dxos/react-client/echo';
16
16
  import { useIdentity } from '@dxos/react-client/halo';
17
17
  import { withClientProvider } from '@dxos/react-client/testing';
18
+ import { useAsyncEffect } from '@dxos/react-ui';
18
19
  import { Thread } from '@dxos/react-ui-thread';
19
20
  import { DataType } from '@dxos/schema';
20
- import { withLayout, withTheme } from '@dxos/storybook-utils';
21
+ import { render, withLayout, withTheme } from '@dxos/storybook-utils';
21
22
 
22
- import { ChatContainer } from './ChatContainer';
23
23
  import { translations } from '../translations';
24
24
  import { ChannelType, ThreadType } from '../types';
25
25
 
26
+ import { ChatContainer } from './ChatContainer';
27
+
26
28
  faker.seed(1);
27
29
 
28
- const Story = () => {
30
+ const DefaultStory = () => {
29
31
  const client = useClient();
30
32
  const identity = useIdentity();
31
33
  const [space, setSpace] = useState<Space>();
32
34
  const [channel, setChannel] = useState<ChannelType | null>();
33
35
 
34
- useEffect(() => {
36
+ useAsyncEffect(async () => {
35
37
  if (identity) {
36
- setTimeout(async () => {
37
- const space = await client.spaces.create();
38
- const channel = space.db.add(
39
- Obj.make(ChannelType, {
40
- defaultThread: Ref.make(Obj.make(ThreadType, { messages: [], status: 'active' })),
41
- threads: [],
42
- }),
43
- );
44
- setSpace(space);
45
- setChannel(channel);
46
- });
38
+ const space = await client.spaces.create();
39
+ const channel = space.db.add(
40
+ Obj.make(ChannelType, {
41
+ defaultThread: Ref.make(Obj.make(ThreadType, { messages: [], status: 'active' })),
42
+ threads: [],
43
+ }),
44
+ );
45
+ setSpace(space);
46
+ setChannel(channel);
47
47
  }
48
48
  }, [identity]);
49
49
 
@@ -52,18 +52,16 @@ const Story = () => {
52
52
  }
53
53
 
54
54
  return (
55
- <main className='max-is-prose mli-auto bs-dvh overflow-hidden'>
55
+ <main className='is-full max-is-prose mli-auto bs-dvh overflow-hidden'>
56
56
  <ChatContainer space={space} thread={channel.defaultThread.target} />
57
57
  </main>
58
58
  );
59
59
  };
60
60
 
61
- export const Default = {};
62
-
63
- const meta: Meta<typeof Thread.Root> = {
61
+ const meta = {
64
62
  title: 'plugins/plugin-thread/Chat',
65
- component: Thread.Root,
66
- render: () => <Story />,
63
+ component: Thread.Root as any,
64
+ render: render(DefaultStory),
67
65
  decorators: [
68
66
  withPluginManager({
69
67
  plugins: [IntentPlugin()],
@@ -80,9 +78,13 @@ const meta: Meta<typeof Thread.Root> = {
80
78
  }),
81
79
  withTheme,
82
80
  withLayout({ fullscreen: true }),
83
- withClientProvider({ createSpace: true, types: [ThreadType, DataType.Message] }),
81
+ withClientProvider({ createSpace: true, types: [ThreadType, ChannelType, DataType.Message] }),
84
82
  ],
85
83
  parameters: { translations },
86
- };
84
+ } satisfies Meta<typeof DefaultStory>;
87
85
 
88
86
  export default meta;
87
+
88
+ type Story = StoryObj<typeof meta>;
89
+
90
+ export const Default: Story = {};
@@ -5,7 +5,7 @@
5
5
  import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
6
6
 
7
7
  import { Obj, Ref } from '@dxos/echo';
8
- import { fullyQualifiedId, type Space, useMembers } from '@dxos/react-client/echo';
8
+ import { type Space, fullyQualifiedId, useMembers } from '@dxos/react-client/echo';
9
9
  import { useIdentity } from '@dxos/react-client/halo';
10
10
  import { Icon, ScrollArea, useThemeContext, useTranslation } from '@dxos/react-ui';
11
11
  import { createBasicExtensions, createThemeExtensions, listener } from '@dxos/react-ui-editor';
@@ -21,13 +21,14 @@ import {
21
21
  import { DataType } from '@dxos/schema';
22
22
  import { isNonNullable } from '@dxos/util';
23
23
 
24
- import { MessageContainer } from './MessageContainer';
25
- import { command } from './command-extension';
26
24
  import { useStatus } from '../hooks';
27
25
  import { meta } from '../meta';
28
26
  import { type ThreadType } from '../types';
29
27
  import { getMessageMetadata } from '../util';
30
28
 
29
+ import { command } from './command-extension';
30
+ import { MessageContainer } from './MessageContainer';
31
+
31
32
  export const ChatHeading = ({ attendableId }: { attendableId?: string }) => {
32
33
  const { t } = useTranslation(meta.id);
33
34
  return (
@@ -111,7 +112,10 @@ export const ChatContainer = ({ space, thread, context, current, autoFocusTextbo
111
112
  <Thread.Root
112
113
  current={current}
113
114
  id={id}
114
- classNames='bs-full grid-rows-[1fr_min-content_min-content] overflow-hidden transition-[padding-block-end] [[data-sidebar-inline-start-state=open]_&]:lg:pbe-0'
115
+ classNames={[
116
+ 'bs-full is-full max-is-prose mli-auto grid-rows-[1fr_min-content_min-content] overflow-hidden',
117
+ 'transition-[padding-block-end] [[data-sidebar-inline-start-state=open]_&]:lg:pbe-0',
118
+ ]}
115
119
  >
116
120
  <ScrollArea.Root classNames='col-span-2'>
117
121
  <ScrollArea.Viewport classNames='overflow-anchored after:overflow-anchor after:block after:bs-px after:-mbs-px [&>div]:min-bs-full [&>div]:!grid [&>div]:grid-rows-[1fr_0]'>
@@ -4,8 +4,8 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type Meta } from '@storybook/react-vite';
8
- import React, { useEffect } from 'react';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
+ import React from 'react';
9
9
 
10
10
  import { IntentPlugin } from '@dxos/app-framework';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
@@ -14,14 +14,16 @@ import { ClientPlugin } from '@dxos/plugin-client';
14
14
  import { faker } from '@dxos/random';
15
15
  import { useQuery, useSpace } from '@dxos/react-client/echo';
16
16
  import { useIdentity } from '@dxos/react-client/halo';
17
+ import { useAsyncEffect } from '@dxos/react-ui';
17
18
  import { AnchoredTo, DataType } from '@dxos/schema';
18
19
  import { layoutCentered, render, withLayout, withTheme } from '@dxos/storybook-utils';
19
20
 
20
- import { CommentsContainer } from './CommentsContainer';
21
- import { createCommentThread } from './testing';
22
21
  import { translations } from '../translations';
23
22
  import { ThreadType } from '../types';
24
23
 
24
+ import { CommentsContainer } from './CommentsContainer';
25
+ import { createCommentThread, createProposalThread } from './testing';
26
+
25
27
  faker.seed(1);
26
28
 
27
29
  const DefaultStory = () => {
@@ -29,27 +31,25 @@ const DefaultStory = () => {
29
31
  const space = useSpace();
30
32
  const anchors = useQuery(space, Query.type(AnchoredTo));
31
33
 
32
- useEffect(() => {
34
+ useAsyncEffect(async () => {
33
35
  if (identity && space) {
34
- const t = setTimeout(async () => {
35
- const object = space.db.add(Obj.make(Type.Expando, {}));
36
- const thread1 = space.db.add(createCommentThread(identity));
37
- const thread2 = space.db.add(createCommentThread(identity));
38
- space.db.add(
39
- Relation.make(AnchoredTo, {
40
- [Relation.Source]: thread1,
41
- [Relation.Target]: object,
42
- }),
43
- );
44
- space.db.add(
45
- Relation.make(AnchoredTo, {
46
- [Relation.Source]: thread2,
47
- [Relation.Target]: object,
48
- }),
49
- );
50
- });
51
-
52
- return () => clearTimeout(t);
36
+ const object = space.db.add(Obj.make(Type.Expando, {}));
37
+ const thread1 = space.db.add(createCommentThread(identity));
38
+ const thread2 = space.db.add(createProposalThread(identity));
39
+ space.db.add(
40
+ Relation.make(AnchoredTo, {
41
+ [Relation.Source]: thread1,
42
+ [Relation.Target]: object,
43
+ anchor: 'test',
44
+ }),
45
+ );
46
+ space.db.add(
47
+ Relation.make(AnchoredTo, {
48
+ [Relation.Source]: thread2,
49
+ [Relation.Target]: object,
50
+ anchor: 'test',
51
+ }),
52
+ );
53
53
  }
54
54
  }, [identity, space]);
55
55
 
@@ -59,23 +59,25 @@ const DefaultStory = () => {
59
59
 
60
60
  return (
61
61
  <div className='w-[30rem] overflow-y-auto bg-baseSurface'>
62
- <CommentsContainer anchors={anchors} onThreadDelete={console.log} />
62
+ <CommentsContainer anchors={anchors} onThreadDelete={console.log} onAcceptProposal={console.log} />
63
63
  </div>
64
64
  );
65
65
  };
66
66
 
67
- const meta: Meta = {
67
+ const meta = {
68
68
  title: 'plugins/plugin-thread/Comments',
69
69
  render: render(DefaultStory),
70
70
  decorators: [
71
71
  withTheme,
72
72
  withLayout({ fullscreen: true, classNames: layoutCentered }),
73
+ // TODO(wittjosiah): This shouldn't depend on app framework. Should use withClientProvider instead.
74
+ // Currently this is required due to useOnEditAnalytics.
73
75
  withPluginManager({
74
76
  plugins: [
75
77
  IntentPlugin(),
76
78
  ClientPlugin({
77
79
  types: [DataType.Message, ThreadType, AnchoredTo],
78
- onClientInitialized: async (_, client) => {
80
+ onClientInitialized: async ({ client }) => {
79
81
  await client.halo.createIdentity();
80
82
  },
81
83
  }),
@@ -85,8 +87,10 @@ const meta: Meta = {
85
87
  parameters: {
86
88
  translations,
87
89
  },
88
- };
90
+ } satisfies Meta<typeof DefaultStory>;
89
91
 
90
92
  export default meta;
91
93
 
92
- export const Default = {};
94
+ type Story = StoryObj<typeof meta>;
95
+
96
+ export const Default: Story = {};
@@ -9,10 +9,11 @@ import { fullyQualifiedId } from '@dxos/react-client/echo';
9
9
  import { Callout, Icon, Trans, useTranslation } from '@dxos/react-ui';
10
10
  import { type AnchoredTo } from '@dxos/schema';
11
11
 
12
- import { CommentsThreadContainer, type CommentsThreadContainerProps } from './CommentsThreadContainer';
13
12
  import { meta } from '../meta';
14
13
  import { type ThreadType } from '../types';
15
14
 
15
+ import { CommentsThreadContainer, type CommentsThreadContainerProps } from './CommentsThreadContainer';
16
+
16
17
  export type CommentsContainerProps = Omit<CommentsThreadContainerProps, 'anchor' | 'current'> & {
17
18
  anchors: AnchoredTo[];
18
19
  currentId?: string;
@@ -14,15 +14,13 @@ import { MessageTextbox, type MessageTextboxProps, Thread, type ThreadRootProps
14
14
  import { type AnchoredTo } from '@dxos/schema';
15
15
  import { isNonNullable } from '@dxos/util';
16
16
 
17
- import { MessageContainer } from './MessageContainer';
18
- import { command } from './command-extension';
19
17
  import { useStatus } from '../hooks';
20
18
  import { meta } from '../meta';
21
19
  import { type ThreadType } from '../types';
22
20
  import { getMessageMetadata } from '../util';
23
21
 
24
- // TODO(burdon): Remove need for p-1.
25
- export const commentControlClassNames = '!p-1 transition-opacity';
22
+ import { command } from './command-extension';
23
+ import { MessageContainer, buttonClassNames, buttonGroupClassNames } from './MessageContainer';
26
24
 
27
25
  export type CommentsThreadContainerProps = {
28
26
  anchor: AnchoredTo;
@@ -31,6 +29,7 @@ export type CommentsThreadContainerProps = {
31
29
  onResolve?: (anchor: AnchoredTo) => void;
32
30
  onMessageDelete?: (anchor: AnchoredTo, messageId: string) => void;
33
31
  onThreadDelete?: (anchor: AnchoredTo) => void;
32
+ onAcceptProposal?: (anchor: AnchoredTo, messageId: string) => void;
34
33
  } & Pick<ThreadRootProps, 'current'>;
35
34
 
36
35
  export const CommentsThreadContainer = ({
@@ -41,6 +40,7 @@ export const CommentsThreadContainer = ({
41
40
  onResolve,
42
41
  onMessageDelete,
43
42
  onThreadDelete,
43
+ onAcceptProposal,
44
44
  }: CommentsThreadContainerProps) => {
45
45
  const { t } = useTranslation(meta.id);
46
46
  const identity = useIdentity()!;
@@ -75,6 +75,7 @@ export const CommentsThreadContainer = ({
75
75
  const handleResolve = useCallback(() => onResolve?.(anchor), [onResolve, anchor]);
76
76
  const handleMessageDelete = useCallback((id: string) => onMessageDelete?.(anchor, id), [onMessageDelete, anchor]);
77
77
  const handleThreadDelete = useCallback(() => onThreadDelete?.(anchor), [onThreadDelete, anchor]);
78
+ const handleAcceptProposal = useCallback((id: string) => onAcceptProposal?.(anchor, id), [onAcceptProposal, anchor]);
78
79
 
79
80
  const handleComment: MessageTextboxProps['onSend'] = useCallback(() => {
80
81
  if (!messageRef.current) {
@@ -112,7 +113,7 @@ export const CommentsThreadContainer = ({
112
113
  ) : (
113
114
  <Thread.Header>{thread.name}</Thread.Header>
114
115
  )}
115
- <div className='flex flex-row items-center gap-0.5'>
116
+ <div role='none' className={buttonGroupClassNames}>
116
117
  {thread.status === 'staged' && <Tag palette='neutral'>{t('draft button')}</Tag>}
117
118
  {onResolve && !(thread?.status === 'staged') && (
118
119
  <IconButton
@@ -121,7 +122,7 @@ export const CommentsThreadContainer = ({
121
122
  icon={thread?.status === 'resolved' ? 'ph--check--fill' : 'ph--check--regular'}
122
123
  iconOnly
123
124
  label={t('resolve thread label')}
124
- classNames={[commentControlClassNames, thread?.status !== 'resolved' && hoverableControlItem]}
125
+ classNames={[buttonClassNames, thread?.status !== 'resolved' && hoverableControlItem]}
125
126
  onClick={handleResolve}
126
127
  />
127
128
  )}
@@ -132,7 +133,7 @@ export const CommentsThreadContainer = ({
132
133
  icon='ph--x--regular'
133
134
  iconOnly
134
135
  label={t('delete thread label')}
135
- classNames={[commentControlClassNames, hoverableControlItem]}
136
+ classNames={[buttonClassNames, hoverableControlItem]}
136
137
  onClick={handleThreadDelete}
137
138
  />
138
139
  )}
@@ -147,6 +148,7 @@ export const CommentsThreadContainer = ({
147
148
  message={message}
148
149
  members={members}
149
150
  onDelete={handleMessageDelete}
151
+ onAcceptProposal={handleAcceptProposal}
150
152
  />
151
153
  ))}
152
154
 
@@ -5,7 +5,7 @@
5
5
  import React, { type FC, type PropsWithChildren, useEffect, useState } from 'react';
6
6
 
7
7
  import { useCapability } from '@dxos/app-framework';
8
- import { useTranslation, type ThemedClassName } from '@dxos/react-ui';
8
+ import { type ThemedClassName, useTranslation } from '@dxos/react-ui';
9
9
  import { mx } from '@dxos/react-ui-theme';
10
10
 
11
11
  import { ThreadCapabilities } from '../../capabilities';