@peers-app/peers-ui 0.0.14

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 (404) hide show
  1. package/.github/README.md +52 -0
  2. package/.github/workflows/publish.yml +45 -0
  3. package/babel.config.js +7 -0
  4. package/dist/app.d.ts +9 -0
  5. package/dist/app.js +54 -0
  6. package/dist/command-palette/command-palette-ui.d.ts +2 -0
  7. package/dist/command-palette/command-palette-ui.js +192 -0
  8. package/dist/command-palette/command-palette.d.ts +23 -0
  9. package/dist/command-palette/command-palette.js +371 -0
  10. package/dist/components/checkbox.d.ts +7 -0
  11. package/dist/components/checkbox.js +20 -0
  12. package/dist/components/group-switcher.d.ts +6 -0
  13. package/dist/components/group-switcher.js +301 -0
  14. package/dist/components/input-date.d.ts +7 -0
  15. package/dist/components/input-date.js +19 -0
  16. package/dist/components/input-datetime.d.ts +7 -0
  17. package/dist/components/input-datetime.js +35 -0
  18. package/dist/components/input-number.d.ts +9 -0
  19. package/dist/components/input-number.js +87 -0
  20. package/dist/components/input.d.ts +7 -0
  21. package/dist/components/input.js +20 -0
  22. package/dist/components/io-schema-values.d.ts +15 -0
  23. package/dist/components/io-schema-values.js +105 -0
  24. package/dist/components/io-schema.d.ts +13 -0
  25. package/dist/components/io-schema.js +163 -0
  26. package/dist/components/lazy-list.d.ts +13 -0
  27. package/dist/components/lazy-list.js +91 -0
  28. package/dist/components/lazy-sortable-list.d.ts +29 -0
  29. package/dist/components/lazy-sortable-list.js +12 -0
  30. package/dist/components/left-bar.d.ts +3 -0
  31. package/dist/components/left-bar.js +130 -0
  32. package/dist/components/list-screen.d.ts +16 -0
  33. package/dist/components/list-screen.js +100 -0
  34. package/dist/components/loading-indicator.d.ts +2 -0
  35. package/dist/components/loading-indicator.js +12 -0
  36. package/dist/components/main-content-container.d.ts +2 -0
  37. package/dist/components/main-content-container.js +90 -0
  38. package/dist/components/markdown-editor/autolink-plugin.d.ts +2 -0
  39. package/dist/components/markdown-editor/autolink-plugin.js +29 -0
  40. package/dist/components/markdown-editor/editor-inline.d.ts +3 -0
  41. package/dist/components/markdown-editor/editor-inline.js +13 -0
  42. package/dist/components/markdown-editor/editor.d.ts +18 -0
  43. package/dist/components/markdown-editor/editor.js +143 -0
  44. package/dist/components/markdown-editor/markdown-plugin.d.ts +9 -0
  45. package/dist/components/markdown-editor/markdown-plugin.js +194 -0
  46. package/dist/components/markdown-editor/mention-node.d.ts +21 -0
  47. package/dist/components/markdown-editor/mention-node.js +160 -0
  48. package/dist/components/markdown-editor/mentions-plugin.d.ts +7 -0
  49. package/dist/components/markdown-editor/mentions-plugin.js +268 -0
  50. package/dist/components/markdown-editor/theme.d.ts +46 -0
  51. package/dist/components/markdown-editor/theme.js +48 -0
  52. package/dist/components/markdown-editor/toolbar.d.ts +10 -0
  53. package/dist/components/markdown-editor/toolbar.js +112 -0
  54. package/dist/components/markdown-with-mentions.d.ts +4 -0
  55. package/dist/components/markdown-with-mentions.js +140 -0
  56. package/dist/components/message-logs/message-logs.d.ts +6 -0
  57. package/dist/components/message-logs/message-logs.js +307 -0
  58. package/dist/components/messages/avatar.d.ts +10 -0
  59. package/dist/components/messages/avatar.js +65 -0
  60. package/dist/components/messages/channel-message-list.d.ts +14 -0
  61. package/dist/components/messages/channel-message-list.js +158 -0
  62. package/dist/components/messages/channel-view.d.ts +6 -0
  63. package/dist/components/messages/channel-view.js +82 -0
  64. package/dist/components/messages/message-compose.d.ts +11 -0
  65. package/dist/components/messages/message-compose.js +152 -0
  66. package/dist/components/messages/message-display.d.ts +10 -0
  67. package/dist/components/messages/message-display.js +152 -0
  68. package/dist/components/messages/thread-message-list.d.ts +11 -0
  69. package/dist/components/messages/thread-message-list.js +122 -0
  70. package/dist/components/messages/thread-view.d.ts +6 -0
  71. package/dist/components/messages/thread-view.js +174 -0
  72. package/dist/components/off-canvas.d.ts +13 -0
  73. package/dist/components/off-canvas.js +89 -0
  74. package/dist/components/router.d.ts +6 -0
  75. package/dist/components/router.js +240 -0
  76. package/dist/components/save-button.d.ts +13 -0
  77. package/dist/components/save-button.js +75 -0
  78. package/dist/components/sortable-list.d.ts +36 -0
  79. package/dist/components/sortable-list.js +77 -0
  80. package/dist/components/tabs.d.ts +11 -0
  81. package/dist/components/tabs.js +69 -0
  82. package/dist/components/text-list-editor.tsx/text-list-editor.d.ts +6 -0
  83. package/dist/components/text-list-editor.tsx/text-list-editor.js +13 -0
  84. package/dist/components/tooltip.d.ts +11 -0
  85. package/dist/components/tooltip.js +20 -0
  86. package/dist/components/top-bar.d.ts +2 -0
  87. package/dist/components/top-bar.js +51 -0
  88. package/dist/components/typeahead/mentions-plugin.d.ts +7 -0
  89. package/dist/components/typeahead/mentions-plugin.js +203 -0
  90. package/dist/components/typeahead/typeahead-editor.d.ts +15 -0
  91. package/dist/components/typeahead/typeahead-editor.js +134 -0
  92. package/dist/components/typeahead/typeahead.d.ts +12 -0
  93. package/dist/components/typeahead/typeahead.js +94 -0
  94. package/dist/components/typeahead.d.ts +22 -0
  95. package/dist/components/typeahead.js +270 -0
  96. package/dist/globals.d.ts +29 -0
  97. package/dist/globals.js +148 -0
  98. package/dist/hooks.d.ts +34 -0
  99. package/dist/hooks.js +137 -0
  100. package/dist/index.d.ts +4 -0
  101. package/dist/index.js +20 -0
  102. package/dist/layout-vars.d.ts +6 -0
  103. package/dist/layout-vars.js +10 -0
  104. package/dist/mention-configs.d.ts +18 -0
  105. package/dist/mention-configs.js +149 -0
  106. package/dist/screens/assistants/assistant-config.d.ts +5 -0
  107. package/dist/screens/assistants/assistant-config.js +52 -0
  108. package/dist/screens/assistants/assistant-details.d.ts +4 -0
  109. package/dist/screens/assistants/assistant-details.js +85 -0
  110. package/dist/screens/assistants/assistant-info.d.ts +6 -0
  111. package/dist/screens/assistants/assistant-info.js +28 -0
  112. package/dist/screens/assistants/assistant-list.d.ts +2 -0
  113. package/dist/screens/assistants/assistant-list.js +114 -0
  114. package/dist/screens/assistants/assistant-tools.d.ts +5 -0
  115. package/dist/screens/assistants/assistant-tools.js +38 -0
  116. package/dist/screens/contacts/contact-details.d.ts +6 -0
  117. package/dist/screens/contacts/contact-details.js +100 -0
  118. package/dist/screens/contacts/contact-list.d.ts +2 -0
  119. package/dist/screens/contacts/contact-list.js +213 -0
  120. package/dist/screens/contacts/index.d.ts +4 -0
  121. package/dist/screens/contacts/index.js +21 -0
  122. package/dist/screens/events/cron.d.ts +3 -0
  123. package/dist/screens/events/cron.js +77 -0
  124. package/dist/screens/events/event-details.d.ts +6 -0
  125. package/dist/screens/events/event-details.js +112 -0
  126. package/dist/screens/events/event-handlers.d.ts +7 -0
  127. package/dist/screens/events/event-handlers.js +84 -0
  128. package/dist/screens/events/event-info.d.ts +5 -0
  129. package/dist/screens/events/event-info.js +19 -0
  130. package/dist/screens/events/event-list.d.ts +2 -0
  131. package/dist/screens/events/event-list.js +107 -0
  132. package/dist/screens/events/event-schedule.d.ts +5 -0
  133. package/dist/screens/events/event-schedule.js +124 -0
  134. package/dist/screens/groups/group-details.d.ts +6 -0
  135. package/dist/screens/groups/group-details.js +218 -0
  136. package/dist/screens/groups/group-list.d.ts +2 -0
  137. package/dist/screens/groups/group-list.js +275 -0
  138. package/dist/screens/groups/group-members.d.ts +8 -0
  139. package/dist/screens/groups/group-members.js +315 -0
  140. package/dist/screens/groups/index.d.ts +6 -0
  141. package/dist/screens/groups/index.js +23 -0
  142. package/dist/screens/knowledge/knowledge-frame-details.bk.d.ts +6 -0
  143. package/dist/screens/knowledge/knowledge-frame-details.bk.js +84 -0
  144. package/dist/screens/knowledge/knowledge-frame-details.d.ts +8 -0
  145. package/dist/screens/knowledge/knowledge-frame-details.js +143 -0
  146. package/dist/screens/knowledge/knowledge-frame-list.d.ts +2 -0
  147. package/dist/screens/knowledge/knowledge-frame-list.js +45 -0
  148. package/dist/screens/knowledge/knowledge-value-details.d.ts +6 -0
  149. package/dist/screens/knowledge/knowledge-value-details.js +150 -0
  150. package/dist/screens/knowledge/knowledge-value-list-item.d.ts +5 -0
  151. package/dist/screens/knowledge/knowledge-value-list-item.js +39 -0
  152. package/dist/screens/knowledge/knowledge-value-list.d.ts +3 -0
  153. package/dist/screens/knowledge/knowledge-value-list.js +123 -0
  154. package/dist/screens/packages/package-details.d.ts +6 -0
  155. package/dist/screens/packages/package-details.js +82 -0
  156. package/dist/screens/packages/package-info.d.ts +5 -0
  157. package/dist/screens/packages/package-info.js +42 -0
  158. package/dist/screens/packages/package-list.d.ts +2 -0
  159. package/dist/screens/packages/package-list.js +182 -0
  160. package/dist/screens/packages/package-new-local.d.ts +2 -0
  161. package/dist/screens/packages/package-new-local.js +82 -0
  162. package/dist/screens/peer-types/peer-type-details.d.ts +10 -0
  163. package/dist/screens/peer-types/peer-type-details.js +126 -0
  164. package/dist/screens/peer-types/peer-type-list.d.ts +2 -0
  165. package/dist/screens/peer-types/peer-type-list.js +57 -0
  166. package/dist/screens/predicates/predicate-details.d.ts +6 -0
  167. package/dist/screens/predicates/predicate-details.js +103 -0
  168. package/dist/screens/predicates/predicate-list.d.ts +2 -0
  169. package/dist/screens/predicates/predicate-list.js +46 -0
  170. package/dist/screens/profile.d.ts +2 -0
  171. package/dist/screens/profile.js +66 -0
  172. package/dist/screens/search/global-search.d.ts +2 -0
  173. package/dist/screens/search/global-search.js +186 -0
  174. package/dist/screens/settings/color-mode-dropdown.d.ts +6 -0
  175. package/dist/screens/settings/color-mode-dropdown.js +63 -0
  176. package/dist/screens/settings/settings-page.d.ts +2 -0
  177. package/dist/screens/settings/settings-page.js +49 -0
  178. package/dist/screens/setup-user.d.ts +2 -0
  179. package/dist/screens/setup-user.js +270 -0
  180. package/dist/screens/tools/tool-code.d.ts +5 -0
  181. package/dist/screens/tools/tool-code.js +32 -0
  182. package/dist/screens/tools/tool-details.d.ts +6 -0
  183. package/dist/screens/tools/tool-details.js +68 -0
  184. package/dist/screens/tools/tool-info.d.ts +5 -0
  185. package/dist/screens/tools/tool-info.js +74 -0
  186. package/dist/screens/tools/tool-list.d.ts +2 -0
  187. package/dist/screens/tools/tool-list.js +123 -0
  188. package/dist/screens/tools/tool-schema.d.ts +5 -0
  189. package/dist/screens/tools/tool-schema.js +30 -0
  190. package/dist/screens/tools/tool-test-details.d.ts +4 -0
  191. package/dist/screens/tools/tool-test-details.js +54 -0
  192. package/dist/screens/tools/tool-test-list.d.ts +4 -0
  193. package/dist/screens/tools/tool-test-list.js +82 -0
  194. package/dist/screens/variables/variable-details.d.ts +6 -0
  195. package/dist/screens/variables/variable-details.js +140 -0
  196. package/dist/screens/variables/variable-list.d.ts +2 -0
  197. package/dist/screens/variables/variable-list.js +58 -0
  198. package/dist/screens/workflows/workflow-details.d.ts +6 -0
  199. package/dist/screens/workflows/workflow-details.js +122 -0
  200. package/dist/screens/workflows/workflow-info.d.ts +5 -0
  201. package/dist/screens/workflows/workflow-info.js +18 -0
  202. package/dist/screens/workflows/workflow-instructions.d.ts +5 -0
  203. package/dist/screens/workflows/workflow-instructions.js +118 -0
  204. package/dist/screens/workflows/workflow-list.d.ts +2 -0
  205. package/dist/screens/workflows/workflow-list.js +109 -0
  206. package/dist/screens/workflows/workflow-subscriptions.d.ts +6 -0
  207. package/dist/screens/workflows/workflow-subscriptions.js +81 -0
  208. package/dist/setupTests.d.ts +1 -0
  209. package/dist/setupTests.js +31 -0
  210. package/dist/system-apps/assistants.app.d.ts +2 -0
  211. package/dist/system-apps/assistants.app.js +8 -0
  212. package/dist/system-apps/contacts.app.d.ts +2 -0
  213. package/dist/system-apps/contacts.app.js +9 -0
  214. package/dist/system-apps/events.app.d.ts +2 -0
  215. package/dist/system-apps/events.app.js +8 -0
  216. package/dist/system-apps/groups.app.d.ts +2 -0
  217. package/dist/system-apps/groups.app.js +9 -0
  218. package/dist/system-apps/index.d.ts +19 -0
  219. package/dist/system-apps/index.js +90 -0
  220. package/dist/system-apps/knowledge-frames.app.d.ts +2 -0
  221. package/dist/system-apps/knowledge-frames.app.js +9 -0
  222. package/dist/system-apps/knowledge-values.app.d.ts +2 -0
  223. package/dist/system-apps/knowledge-values.app.js +9 -0
  224. package/dist/system-apps/packages.app.d.ts +2 -0
  225. package/dist/system-apps/packages.app.js +8 -0
  226. package/dist/system-apps/predicates.app.d.ts +2 -0
  227. package/dist/system-apps/predicates.app.js +8 -0
  228. package/dist/system-apps/profile.app.d.ts +2 -0
  229. package/dist/system-apps/profile.app.js +8 -0
  230. package/dist/system-apps/search.app.d.ts +2 -0
  231. package/dist/system-apps/search.app.js +9 -0
  232. package/dist/system-apps/settings.app.d.ts +2 -0
  233. package/dist/system-apps/settings.app.js +8 -0
  234. package/dist/system-apps/threads.app.d.ts +2 -0
  235. package/dist/system-apps/threads.app.js +8 -0
  236. package/dist/system-apps/tools.app.d.ts +2 -0
  237. package/dist/system-apps/tools.app.js +8 -0
  238. package/dist/system-apps/types.app.d.ts +2 -0
  239. package/dist/system-apps/types.app.js +8 -0
  240. package/dist/system-apps/variables.app.d.ts +2 -0
  241. package/dist/system-apps/variables.app.js +8 -0
  242. package/dist/system-apps/workflows.app.d.ts +2 -0
  243. package/dist/system-apps/workflows.app.js +8 -0
  244. package/dist/tabs-layout/tabs-layout.d.ts +5 -0
  245. package/dist/tabs-layout/tabs-layout.js +374 -0
  246. package/dist/tabs-layout/tabs-state.d.ts +26 -0
  247. package/dist/tabs-layout/tabs-state.js +239 -0
  248. package/dist/three-bar-layout/left-bar-content.d.ts +7 -0
  249. package/dist/three-bar-layout/left-bar-content.js +151 -0
  250. package/dist/three-bar-layout/right-bar-content.d.ts +2 -0
  251. package/dist/three-bar-layout/right-bar-content.js +64 -0
  252. package/dist/three-bar-layout/three-bar-layout.d.ts +5 -0
  253. package/dist/three-bar-layout/three-bar-layout.js +218 -0
  254. package/dist/ui-defaults/index.d.ts +2 -0
  255. package/dist/ui-defaults/index.js +4 -0
  256. package/dist/ui-defaults/list-screen.d.ts +6 -0
  257. package/dist/ui-defaults/list-screen.js +74 -0
  258. package/dist/ui-defaults/notes-editor.d.ts +7 -0
  259. package/dist/ui-defaults/notes-editor.js +41 -0
  260. package/dist/ui-router/routes-loader.d.ts +25 -0
  261. package/dist/ui-router/routes-loader.js +97 -0
  262. package/dist/ui-router/ui-loader.d.ts +18 -0
  263. package/dist/ui-router/ui-loader.js +481 -0
  264. package/dist/utils.d.ts +9 -0
  265. package/dist/utils.js +250 -0
  266. package/docs/conversation-tab.md +201 -0
  267. package/docs/getting-started.md +284 -0
  268. package/docs/knowledge.md +187 -0
  269. package/docs/tabs-ui.md +696 -0
  270. package/docs/user-contacts-ui.md +384 -0
  271. package/jest.config.js +25 -0
  272. package/package.json +109 -0
  273. package/src/app.tsx +59 -0
  274. package/src/command-palette/command-palette-ui.tsx +264 -0
  275. package/src/command-palette/command-palette.ts +364 -0
  276. package/src/components/checkbox.tsx +22 -0
  277. package/src/components/group-switcher.tsx +469 -0
  278. package/src/components/input-date.tsx +28 -0
  279. package/src/components/input-datetime.tsx +41 -0
  280. package/src/components/input-number.tsx +67 -0
  281. package/src/components/input.tsx +22 -0
  282. package/src/components/io-schema-values.tsx +122 -0
  283. package/src/components/io-schema.tsx +234 -0
  284. package/src/components/lazy-list.tsx +98 -0
  285. package/src/components/lazy-sortable-list.tsx +51 -0
  286. package/src/components/left-bar.tsx +264 -0
  287. package/src/components/list-screen.tsx +105 -0
  288. package/src/components/loading-indicator.tsx +9 -0
  289. package/src/components/main-content-container.tsx +76 -0
  290. package/src/components/markdown-editor/autolink-plugin.tsx +36 -0
  291. package/src/components/markdown-editor/editor-inline.tsx +10 -0
  292. package/src/components/markdown-editor/editor.tsx +152 -0
  293. package/src/components/markdown-editor/markdown-plugin.tsx +224 -0
  294. package/src/components/markdown-editor/mention-node.ts +199 -0
  295. package/src/components/markdown-editor/mentions-plugin.tsx +356 -0
  296. package/src/components/markdown-editor/theme.ts +47 -0
  297. package/src/components/markdown-editor/toolbar.tsx +263 -0
  298. package/src/components/markdown-with-mentions.tsx +183 -0
  299. package/src/components/message-logs/message-logs.tsx +406 -0
  300. package/src/components/messages/avatar.tsx +95 -0
  301. package/src/components/messages/channel-message-list.tsx +177 -0
  302. package/src/components/messages/channel-view.tsx +74 -0
  303. package/src/components/messages/message-compose.tsx +162 -0
  304. package/src/components/messages/message-display.tsx +217 -0
  305. package/src/components/messages/thread-message-list.tsx +126 -0
  306. package/src/components/messages/thread-view.tsx +214 -0
  307. package/src/components/off-canvas.tsx +83 -0
  308. package/src/components/router.tsx +224 -0
  309. package/src/components/save-button.tsx +109 -0
  310. package/src/components/sortable-list.tsx +102 -0
  311. package/src/components/tabs.tsx +70 -0
  312. package/src/components/text-list-editor.tsx/text-list-editor.tsx +13 -0
  313. package/src/components/tooltip.tsx +50 -0
  314. package/src/components/top-bar.tsx +119 -0
  315. package/src/components/typeahead/mentions-plugin.tsx +265 -0
  316. package/src/components/typeahead/typeahead-editor.tsx +140 -0
  317. package/src/components/typeahead/typeahead.tsx +77 -0
  318. package/src/components/typeahead.tsx +359 -0
  319. package/src/globals.tsx +162 -0
  320. package/src/hooks.ts +144 -0
  321. package/src/index.tsx +8 -0
  322. package/src/layout-vars.ts +8 -0
  323. package/src/mention-configs.ts +166 -0
  324. package/src/screens/assistants/assistant-config.tsx +80 -0
  325. package/src/screens/assistants/assistant-details.tsx +77 -0
  326. package/src/screens/assistants/assistant-info.tsx +45 -0
  327. package/src/screens/assistants/assistant-list.tsx +115 -0
  328. package/src/screens/assistants/assistant-tools.tsx +61 -0
  329. package/src/screens/contacts/contact-details.tsx +175 -0
  330. package/src/screens/contacts/contact-list.tsx +251 -0
  331. package/src/screens/contacts/index.ts +6 -0
  332. package/src/screens/events/cron.ts +74 -0
  333. package/src/screens/events/event-details.tsx +117 -0
  334. package/src/screens/events/event-handlers.tsx +61 -0
  335. package/src/screens/events/event-info.tsx +29 -0
  336. package/src/screens/events/event-list.tsx +104 -0
  337. package/src/screens/events/event-schedule.tsx +130 -0
  338. package/src/screens/groups/group-details.tsx +306 -0
  339. package/src/screens/groups/group-list.tsx +366 -0
  340. package/src/screens/groups/group-members.tsx +455 -0
  341. package/src/screens/groups/index.ts +9 -0
  342. package/src/screens/knowledge/knowledge-frame-details.bk.tsx +160 -0
  343. package/src/screens/knowledge/knowledge-frame-details.tsx +176 -0
  344. package/src/screens/knowledge/knowledge-frame-list.tsx +49 -0
  345. package/src/screens/knowledge/knowledge-value-details.tsx +181 -0
  346. package/src/screens/knowledge/knowledge-value-list-item.tsx +48 -0
  347. package/src/screens/knowledge/knowledge-value-list.tsx +131 -0
  348. package/src/screens/packages/package-details.tsx +117 -0
  349. package/src/screens/packages/package-info.tsx +83 -0
  350. package/src/screens/packages/package-list.tsx +191 -0
  351. package/src/screens/packages/package-new-local.tsx +93 -0
  352. package/src/screens/peer-types/peer-type-details.tsx +162 -0
  353. package/src/screens/peer-types/peer-type-list.tsx +74 -0
  354. package/src/screens/predicates/predicate-details.tsx +125 -0
  355. package/src/screens/predicates/predicate-list.tsx +50 -0
  356. package/src/screens/profile.tsx +68 -0
  357. package/src/screens/search/global-search.tsx +274 -0
  358. package/src/screens/settings/color-mode-dropdown.tsx +57 -0
  359. package/src/screens/settings/settings-page.tsx +76 -0
  360. package/src/screens/setup-user.tsx +367 -0
  361. package/src/screens/tools/tool-code.tsx +35 -0
  362. package/src/screens/tools/tool-details.tsx +101 -0
  363. package/src/screens/tools/tool-info.tsx +60 -0
  364. package/src/screens/tools/tool-list.tsx +121 -0
  365. package/src/screens/tools/tool-schema.tsx +42 -0
  366. package/src/screens/tools/tool-test-details.tsx +100 -0
  367. package/src/screens/tools/tool-test-list.tsx +74 -0
  368. package/src/screens/variables/variable-details.tsx +183 -0
  369. package/src/screens/variables/variable-list.tsx +74 -0
  370. package/src/screens/workflows/workflow-details.tsx +130 -0
  371. package/src/screens/workflows/workflow-info.tsx +29 -0
  372. package/src/screens/workflows/workflow-instructions.tsx +127 -0
  373. package/src/screens/workflows/workflow-list.tsx +107 -0
  374. package/src/screens/workflows/workflow-subscriptions.tsx +58 -0
  375. package/src/setupTests.ts +32 -0
  376. package/src/system-apps/assistants.app.ts +7 -0
  377. package/src/system-apps/contacts.app.ts +8 -0
  378. package/src/system-apps/events.app.ts +7 -0
  379. package/src/system-apps/groups.app.ts +8 -0
  380. package/src/system-apps/index.ts +79 -0
  381. package/src/system-apps/knowledge-frames.app.ts +8 -0
  382. package/src/system-apps/knowledge-values.app.ts +8 -0
  383. package/src/system-apps/packages.app.ts +7 -0
  384. package/src/system-apps/predicates.app.ts +7 -0
  385. package/src/system-apps/profile.app.ts +7 -0
  386. package/src/system-apps/search.app.ts +8 -0
  387. package/src/system-apps/settings.app.ts +7 -0
  388. package/src/system-apps/threads.app.ts +7 -0
  389. package/src/system-apps/tools.app.ts +7 -0
  390. package/src/system-apps/types.app.ts +7 -0
  391. package/src/system-apps/variables.app.ts +7 -0
  392. package/src/system-apps/workflows.app.ts +7 -0
  393. package/src/tabs-layout/tabs-layout.tsx +672 -0
  394. package/src/tabs-layout/tabs-state.ts +269 -0
  395. package/src/three-bar-layout/left-bar-content.tsx +202 -0
  396. package/src/three-bar-layout/right-bar-content.tsx +67 -0
  397. package/src/three-bar-layout/three-bar-layout.tsx +297 -0
  398. package/src/ui-defaults/index.ts +3 -0
  399. package/src/ui-defaults/list-screen.tsx +92 -0
  400. package/src/ui-defaults/notes-editor.tsx +51 -0
  401. package/src/ui-router/routes-loader.ts +98 -0
  402. package/src/ui-router/ui-loader.tsx +497 -0
  403. package/src/utils.ts +266 -0
  404. package/tsconfig.json +24 -0
@@ -0,0 +1,175 @@
1
+ import { getUserContext, IDoc, IUser, TrustLevel, Users } from "@peers-app/peers-sdk";
2
+ import React from "react";
3
+ import { Input } from "../../components/input";
4
+ import { LoadingIndicator } from "../../components/loading-indicator";
5
+ import { SaveButton } from "../../components/save-button";
6
+ import { ScreenTabBody, Tabs } from "../../components/tabs";
7
+ import { usePromise } from "../../hooks";
8
+ import { updateActiveTabTitle } from "../../tabs-layout/tabs-state";
9
+ import { registerInternalPeersUI } from "../../ui-router/ui-loader";
10
+
11
+ interface IProps {
12
+ userId: string;
13
+ }
14
+
15
+ export const ContactDetails = (props: IProps) => {
16
+
17
+ const contact = usePromise(async () => {
18
+ const userContext = await getUserContext();
19
+ const contact = await Users(userContext.userDataContext).get(props.userId);
20
+ if (!contact) {
21
+ throw new Error('Contact not found');
22
+ }
23
+ updateActiveTabTitle(contact.name || "Contact");
24
+ return Users(userContext.userDataContext).initDoc(contact);
25
+ }, undefined, [props.userId]);
26
+
27
+ if (!contact) {
28
+ return <LoadingIndicator />;
29
+ }
30
+
31
+ return (
32
+ <div className="container-fluid p-3">
33
+
34
+ <div className="d-flex">
35
+ <div>
36
+ <h4>
37
+ <i className="bi-person-fill-check me-2"></i>
38
+ </h4>
39
+ </div>
40
+ <div className="flex-grow-1">
41
+ <h4>
42
+ <Input
43
+ key={contact.userId}
44
+ className='border border-0'
45
+ style={{ width: '100%', outline: 'none', backgroundColor: 'transparent' }}
46
+ value={contact.qs.name}
47
+ />
48
+ </h4>
49
+ </div>
50
+ <div>
51
+ <SaveButton
52
+ key={contact.userId}
53
+ doc={contact}
54
+ />
55
+ </div>
56
+ </div>
57
+
58
+ <Tabs
59
+ key={contact.userId}
60
+ tabs={[
61
+ {
62
+ name: 'Info', content:
63
+ <ScreenTabBody>
64
+ <ContactInfo contact={contact} />
65
+ </ScreenTabBody>
66
+ },
67
+ ]}
68
+ />
69
+ </div>
70
+ )
71
+ }
72
+
73
+ const ContactInfo = (props: { contact: IDoc<IUser> }) => {
74
+ const { contact } = props;
75
+
76
+ return (
77
+ <div>
78
+ <div className="mb-3">
79
+ <small>Name:</small>
80
+ <Input
81
+ value={contact.qs.name}
82
+ className="form-control mb-3 p-0 ps-2"
83
+ placeholder="Contact name"
84
+ title="Contact name"
85
+ />
86
+ </div>
87
+
88
+ <div className="mb-3">
89
+ <small>User ID:</small>
90
+ <div className="form-control-plaintext text-muted small">
91
+ {contact.userId}
92
+ </div>
93
+ </div>
94
+
95
+ <div className="mb-3">
96
+ <small>Public Key:</small>
97
+ <Input
98
+ value={contact.qs.publicKey}
99
+ className="form-control mb-3 p-0 ps-2"
100
+ placeholder="Public key"
101
+ title="Public key"
102
+ />
103
+ </div>
104
+
105
+ <div className="mb-3">
106
+ <small>Public Box Key:</small>
107
+ <Input
108
+ value={contact.qs.publicBoxKey}
109
+ className="form-control mb-3 p-0 ps-2"
110
+ placeholder="Public box key"
111
+ title="Public box key"
112
+ />
113
+ </div>
114
+
115
+ <div className="mb-3">
116
+ <small>Trust Level:</small>
117
+ <div className="mt-2">
118
+ <TrustLevelSelector contact={contact} />
119
+ </div>
120
+ </div>
121
+ </div>
122
+ );
123
+ };
124
+
125
+ const TrustLevelSelector = (props: { contact: IDoc<IUser> }) => {
126
+ const { contact } = props;
127
+
128
+ const trustLevels = [
129
+ { value: TrustLevel.Self, label: 'Self', color: 'success' },
130
+ { value: TrustLevel.Trusted, label: 'Trusted', color: 'success' },
131
+ { value: TrustLevel.Known, label: 'Known', color: 'info' },
132
+ { value: TrustLevel.NewDevice, label: 'New Device', color: 'primary' },
133
+ { value: TrustLevel.NewUser, label: 'New User', color: 'primary' },
134
+ { value: TrustLevel.Unknown, label: 'Unknown', color: 'warning' },
135
+ { value: TrustLevel.Untrusted, label: 'Untrusted', color: 'danger' },
136
+ { value: TrustLevel.Malicious, label: 'Malicious', color: 'danger' },
137
+ ];
138
+
139
+ return (
140
+ <div className="d-flex flex-wrap gap-2">
141
+ {trustLevels.map(level => (
142
+ <button
143
+ key={level.value}
144
+ className={`btn btn-sm ${
145
+ contact.trustLevel === level.value
146
+ ? `btn-${level.color}`
147
+ : `btn-outline-${level.color}`
148
+ }`}
149
+ onClick={() => contact.trustLevel = level.value}
150
+ >
151
+ {level.label}
152
+ </button>
153
+ ))}
154
+ </div>
155
+ );
156
+ };
157
+
158
+ registerInternalPeersUI({
159
+ peersUIId: '00contact00details00component',
160
+ component: ContactDetails,
161
+ routes: [
162
+ {
163
+ isMatch: (props, context) => {
164
+ const match = context.path.match(/^contacts\/([a-zA-Z0-9]+)$/);
165
+ if (match) {
166
+ props.userId = match[1];
167
+ return true;
168
+ }
169
+ return false;
170
+ },
171
+ uiCategory: 'screen',
172
+ priority: 2
173
+ }
174
+ ]
175
+ });
@@ -0,0 +1,251 @@
1
+ import { getUserContext, ICursorIterable, IUserWithSource, observable, TrustLevel, Users, usersCursor } from "@peers-app/peers-sdk";
2
+ import React, { useEffect, useState } from 'react';
3
+ import { Input } from '../../components/input';
4
+ import { LazyList } from '../../components/lazy-list';
5
+ import { LoadingIndicator } from '../../components/loading-indicator';
6
+ import { mainContentPath } from '../../globals';
7
+ import { useObservable } from '../../hooks';
8
+ import { registerInternalPeersUI } from '../../ui-router/ui-loader';
9
+
10
+ export function ContactList() {
11
+ const [searchTextObs] = useState(() => observable(''));
12
+ const [searchText] = useObservable(searchTextObs);
13
+ const [cursorObs] = useState(() => observable<ICursorIterable<IUserWithSource>>());
14
+ const [existingContacts, setExistingContacts] = useState<IUserWithSource[]>([]);
15
+
16
+ async function newCursor() {
17
+ const cursor = await usersCursor({ name: { $matchWords: searchText } });
18
+ cursorObs(cursor);
19
+ return cursor;
20
+ }
21
+
22
+ useEffect(() => {
23
+ newCursor();
24
+ setExistingContacts([]); // Reset existing contacts when search changes
25
+ }, [searchText]);
26
+
27
+ async function loadMore(existing: IUserWithSource[]): Promise<IUserWithSource[]> {
28
+ let moreMatches: IUserWithSource[] = [];
29
+ let cursor = cursorObs() || await newCursor();
30
+ for await (const nextContact of cursor) {
31
+ if (existing.find(e => e.userId === nextContact.userId)) continue;
32
+ moreMatches.push(nextContact);
33
+ if (searchText.length && moreMatches.length > 5) break;
34
+ if (moreMatches.length >= 10) break;
35
+ }
36
+ if (moreMatches.length === 0) {
37
+ cursorObs(undefined);
38
+ }
39
+ setExistingContacts(existing.concat(moreMatches)); // Track all loaded contacts
40
+ return moreMatches;
41
+ }
42
+
43
+ function isValidUserId(id: string): boolean {
44
+ // Check if it's a valid ID format (alphanumeric, typically 25 characters)
45
+ return /^[a-zA-Z0-9]{20,30}$/.test(id);
46
+ }
47
+
48
+ async function createContact(userId: string) {
49
+ try {
50
+ const userContext = await getUserContext();
51
+ const usersTable = Users(userContext.userDataContext);
52
+
53
+ const newContact = await usersTable.initRecord({
54
+ userId: userId.trim(),
55
+ name: 'New User',
56
+ publicKey: '',
57
+ publicBoxKey: '',
58
+ trustLevel: TrustLevel.NewUser
59
+ });
60
+
61
+ await usersTable.save(newContact);
62
+
63
+ // Navigate to the details screen for the new contact
64
+ mainContentPath(`contacts/${userId.trim()}`);
65
+ } catch (error) {
66
+ console.error('Error creating contact:', error);
67
+ }
68
+ }
69
+
70
+ async function handleSearchSubmit(evt: React.KeyboardEvent<HTMLInputElement>) {
71
+ if (evt.key !== 'Enter') return;
72
+
73
+ const input = searchText.trim();
74
+ if (!input) return;
75
+
76
+ // Check if there are any existing results
77
+ if (existingContacts.length === 0) {
78
+ // No results found, check if it's a valid user ID
79
+ if (isValidUserId(input)) {
80
+ // Clear search and create new contact with the ID
81
+ searchTextObs('');
82
+ await createContact(input);
83
+ }
84
+ }
85
+ }
86
+
87
+ function renderItems(contacts: IUserWithSource[]): JSX.Element[] {
88
+ const elements: JSX.Element[] = [];
89
+ let lastSource: string | null = null;
90
+
91
+ contacts.forEach((contact, index) => {
92
+ // Add horizontal separator when source changes
93
+ if (lastSource && lastSource !== contact.source) {
94
+ elements.push(
95
+ <div key={`separator-${index}`} className="my-3">
96
+ <hr className="border-secondary opacity-50" />
97
+ </div>
98
+ );
99
+ }
100
+
101
+ elements.push(
102
+ <ContactCard key={contact.userId} contact={contact} />
103
+ );
104
+
105
+ lastSource = contact.source;
106
+ });
107
+
108
+ return elements;
109
+ }
110
+
111
+ return (
112
+ <div className="container-fluid p-3">
113
+ <div className="d-flex justify-content-between align-items-center mb-3">
114
+ <h4>
115
+ <i className="bi-person-fill-check me-2" />
116
+ Contacts
117
+ </h4>
118
+ </div>
119
+
120
+ <div className="input-group mb-3">
121
+ <Input
122
+ value={searchTextObs}
123
+ className="form-control"
124
+ placeholder="Search or create contacts"
125
+ autoFocus={true}
126
+ onKeyUp={handleSearchSubmit}
127
+ />
128
+ </div>
129
+
130
+ <div className="peers-list-container">
131
+ <LazyList
132
+ resetTrigger={searchText}
133
+ loadMore={loadMore}
134
+ scrollThreshold={0.6}
135
+ renderItems={renderItems}
136
+ loadingIndicator={
137
+ <div className="d-flex justify-content-center" style={{ height: 200 }}>
138
+ <LoadingIndicator />
139
+ </div>
140
+ }
141
+ endOfList={
142
+ <div className="d-flex justify-content-center" style={{ height: 200 }}>
143
+ {/* End of contacts */}
144
+ </div>
145
+ }
146
+ />
147
+ </div>
148
+ </div>
149
+ );
150
+ }
151
+
152
+ interface ContactCardProps {
153
+ contact: IUserWithSource;
154
+ }
155
+
156
+ const ContactCard = ({ contact }: ContactCardProps) => {
157
+ const getSourceLabel = (source: string) => {
158
+ switch (source) {
159
+ case 'userDataContext': return 'Personal';
160
+ case 'currentDataContext': return 'Current Context';
161
+ case 'otherDataContexts': return 'Groups';
162
+ default: return source;
163
+ }
164
+ };
165
+
166
+ const getSourceIcon = (source: string) => {
167
+ switch (source) {
168
+ case 'userDataContext': return 'bi-person-fill';
169
+ case 'currentDataContext': return 'bi-house-fill';
170
+ case 'otherDataContexts': return 'bi-people-fill';
171
+ default: return 'bi-question-circle';
172
+ }
173
+ };
174
+
175
+ return (
176
+ <div className="list-group-item d-flex align-items-center justify-content-between py-2">
177
+ <div className="d-flex align-items-center">
178
+ <i className="bi-person-circle me-3" style={{ fontSize: '32px', color: '#6c757d' }} />
179
+ <div>
180
+ <strong>{contact.name}</strong>
181
+ <div className="d-flex align-items-center">
182
+ <small className="text-muted">{contact.userId}</small>
183
+ <span className="mx-1 text-muted">•</span>
184
+ <small className="text-info d-flex align-items-center">
185
+ <i className={`${getSourceIcon(contact.source)} me-1`} />
186
+ {getSourceLabel(contact.source)}
187
+ </small>
188
+ </div>
189
+ </div>
190
+ </div>
191
+
192
+ <div className="d-flex align-items-center">
193
+ {<TrustLevelBadge level={contact.trustLevel || TrustLevel.Unknown} />}
194
+ <a href={`#contacts/${contact.userId}`} className="btn btn-outline-primary btn-sm ms-2">
195
+ <i className="bi-eye me-1" />
196
+ View
197
+ </a>
198
+ </div>
199
+ </div>
200
+ );
201
+ };
202
+
203
+ interface TrustLevelBadgeProps {
204
+ level: TrustLevel;
205
+ }
206
+
207
+ const TrustLevelBadge = ({ level }: TrustLevelBadgeProps) => {
208
+ // Define trust level configurations with their numeric values
209
+ const trustLevelConfigs = [
210
+ { value: TrustLevel.Self, color: 'success', icon: 'bi-shield-fill-check', text: 'Self' },
211
+ { value: TrustLevel.Trusted, color: 'success', icon: 'bi-shield-check', text: 'Trusted' },
212
+ { value: TrustLevel.Known, color: 'info', icon: 'bi-shield-check', text: 'Known' },
213
+ { value: TrustLevel.NewDevice, color: 'primary', icon: 'bi-shield-plus', text: 'New Device' },
214
+ { value: TrustLevel.NewUser, color: 'primary', icon: 'bi-shield-plus', text: 'New User' },
215
+ { value: TrustLevel.Unknown, color: 'warning', icon: 'bi-shield-exclamation', text: 'Unknown' },
216
+ { value: TrustLevel.Untrusted, color: 'danger', icon: 'bi-shield-x', text: 'Untrusted' },
217
+ { value: TrustLevel.Malicious, color: 'danger', icon: 'bi-shield-x', text: 'Malicious' }
218
+ ];
219
+
220
+ // Sort by trust level value (ascending, so lowest first)
221
+ const sortedConfigs = trustLevelConfigs.sort((a, b) => a.value - b.value);
222
+
223
+ // Find the highest trust level that is at or below the current level
224
+ let config = { color: 'secondary', icon: 'bi-shield', text: 'Unknown' };
225
+ for (const trustConfig of sortedConfigs) {
226
+ if (level >= trustConfig.value) {
227
+ config = trustConfig;
228
+ } else {
229
+ break;
230
+ }
231
+ }
232
+
233
+ return (
234
+ <span className={`badge bg-${config.color} d-flex align-items-center gap-1`}>
235
+ <i className={config.icon} />
236
+ {config.text}
237
+ </span>
238
+ );
239
+ };
240
+
241
+ registerInternalPeersUI({
242
+ peersUIId: '00mfc4ql0lgqmjxrpvcd4ufk0',
243
+ component: ContactList,
244
+ routes: [
245
+ {
246
+ isMatch: (props, context) => context.path === 'contacts',
247
+ uiCategory: 'screen',
248
+ priority: 2
249
+ }
250
+ ]
251
+ });
@@ -0,0 +1,6 @@
1
+ // Import all contact screen components to ensure they register their routes
2
+ import './contact-list';
3
+ import './contact-details';
4
+
5
+ export * from "./contact-list";
6
+ export * from "./contact-details";
@@ -0,0 +1,74 @@
1
+ import cronValidate from "cron-validate";
2
+ import moment from "moment-timezone";
3
+ import { parseExpression } from 'cron-parser';
4
+
5
+
6
+ export function getCronErrors(cronExpression: string): string | false {
7
+ const validationResult = cronValidate(cronExpression);
8
+
9
+ if (validationResult.isError()) {
10
+ const errors = validationResult.getError();
11
+ const errorMarkdown = ['Validation errors:', ...errors].join('\n- ');
12
+ return errorMarkdown;
13
+ }
14
+
15
+ let parseError = '';
16
+ try {
17
+ parseExpression(cronExpression);
18
+ } catch (e: any) {
19
+ parseError = e.message;
20
+ }
21
+ if (parseError) {
22
+ return 'Validation error: ' + parseError;
23
+ }
24
+ return false;
25
+ }
26
+
27
+ export function getCronExplanation(cronExpression: string) {
28
+ if (!cronExpression) {
29
+ return '';
30
+ }
31
+ function formatDate(date: Date) {
32
+ // let dtStr = moment
33
+ return moment(date).calendar(null, {
34
+ sameDay: '[Today at] LT',
35
+ nextDay: '[Tomorrow at] LT',
36
+ nextWeek: 'dddd [at] LT',
37
+ lastDay: '[Yesterday at] LT',
38
+ lastWeek: '[Last] dddd [at] LT',
39
+ sameElse: 'L [at] LT'
40
+ }) + `\n - \`${date.toISOString().replace(':00.000Z', 'Z')}\``;
41
+ }
42
+ let parsed = parseExpression(cronExpression);
43
+
44
+ const strDates: string[] = [];
45
+ let i = 1;
46
+ while (true) {
47
+ const dt = parsed.prev().toString();
48
+ strDates.push(`- ${formatDate(new Date(dt))}`);
49
+ i++;
50
+ if (i > 3) break;
51
+ }
52
+ strDates.push('Prior three dates:');
53
+ strDates.reverse();
54
+ strDates.push('\nNext three dates:');
55
+ i = 1;
56
+ parsed = parseExpression(cronExpression);
57
+ while (true) {
58
+ const dt = parsed.next().toString();
59
+ strDates.push(`- ${formatDate(new Date(dt))}`);
60
+ i++;
61
+ if (i > 3) break;
62
+ }
63
+
64
+ return strDates.join('\n');
65
+ }
66
+
67
+ export function getNextCronDate(cronExpression: string): Date {
68
+ const errors = getCronErrors(cronExpression);
69
+ if (errors) {
70
+ throw new Error(errors);
71
+ }
72
+ const parsed = parseExpression(cronExpression);
73
+ return new Date(parsed.next().toString());
74
+ }
@@ -0,0 +1,117 @@
1
+ import { IPeerEventHandler, observable, PeerEventHandlers, PeerEventTypes } from "@peers-app/peers-sdk";
2
+ import React, { useState } from "react";
3
+ import { Input } from "../../components/input";
4
+ import { IOSchemaEditor } from "../../components/io-schema";
5
+ import { LoadingIndicator } from "../../components/loading-indicator";
6
+ import { SaveButton } from "../../components/save-button";
7
+ import { ScreenTabBody, Tabs } from "../../components/tabs";
8
+ import { usePromise } from "../../hooks";
9
+ import { updateActiveTabTitle } from "../../tabs-layout/tabs-state";
10
+ import { PeerEventHandlersUI } from "./event-handlers";
11
+ import { PeerEventInfo } from "./event-info";
12
+ import { PeerEventSchedule } from "./event-schedule";
13
+
14
+ interface IProps {
15
+ peerEventTypeId: string;
16
+ }
17
+
18
+ export const PeerEventDetails = (props: IProps) => {
19
+
20
+ const peerEventType = usePromise(async () => {
21
+ const peerEvent = await PeerEventTypes().get(props.peerEventTypeId);
22
+ if (!peerEvent) {
23
+ throw new Error('Workflow not found');
24
+ }
25
+ const doc = PeerEventTypes().initDoc(peerEvent);
26
+ updateActiveTabTitle(doc.name || "Event");
27
+ return doc;
28
+ }, undefined, [props.peerEventTypeId]);
29
+
30
+ const [handlers] = useState(() => observable([] as IPeerEventHandler[]));
31
+
32
+ const handlersLoaded = usePromise(async () => {
33
+ if (!peerEventType) return false;
34
+ const _handlers = await PeerEventHandlers().list({ peerEventTypeId: peerEventType?.peerEventTypeId });
35
+ handlers(_handlers);
36
+ return true;
37
+ }, false, [peerEventType]);
38
+
39
+ const allLoaded = !!(peerEventType && handlersLoaded);
40
+
41
+ if (!allLoaded) {
42
+ return <LoadingIndicator />;
43
+ }
44
+
45
+ async function saveChanges() {
46
+ if (!peerEventType) return;
47
+ await peerEventType.save();
48
+ const oldHandlers = await PeerEventHandlers().list({ peerEventTypeId: peerEventType.peerEventTypeId });
49
+ for (const oldHandler of oldHandlers) {
50
+ await PeerEventHandlers().delete(oldHandler.peerEventHandlerId);
51
+ }
52
+ for (const handler of handlers()) {
53
+ PeerEventHandlers().save(handler, { restoreIfDeleted: true });
54
+ }
55
+ }
56
+
57
+ return (
58
+ <div className="container-fluid p-3">
59
+
60
+ <div className="d-flex">
61
+ <div>
62
+ <h4>
63
+ <i className="bi bi-lightning-charge-fill me-2"></i>
64
+ </h4>
65
+ </div>
66
+ <div className="flex-grow-1">
67
+ <h4>
68
+ <Input
69
+ key={peerEventType.peerEventTypeId}
70
+ className='border border-0'
71
+ style={{ width: '100%', outline: 'none', backgroundColor: 'transparent' }}
72
+ value={peerEventType.qs.name}
73
+ />
74
+ </h4>
75
+ </div>
76
+ <div>
77
+ <SaveButton
78
+ key={peerEventType.peerEventTypeId}
79
+ onClick={saveChanges}
80
+ doc={peerEventType}
81
+ />
82
+ </div>
83
+ </div>
84
+
85
+ <Tabs
86
+ key={peerEventType.peerEventTypeId}
87
+ tabs={[
88
+ {
89
+ name: 'Info', content:
90
+ <ScreenTabBody>
91
+ <PeerEventInfo peerEventType={peerEventType} />
92
+ </ScreenTabBody>
93
+ },
94
+ {
95
+ name: 'Schema', content:
96
+ <ScreenTabBody>
97
+ <IOSchemaEditor ioSchema={peerEventType.qs.schema} simpleValueName="Event" />
98
+ </ScreenTabBody>
99
+ },
100
+ {
101
+ name: 'Triggers', content:
102
+ <ScreenTabBody>
103
+ <PeerEventSchedule peerEventType={peerEventType} />
104
+ </ScreenTabBody>
105
+ },
106
+ {
107
+ name: 'Handlers', content:
108
+ <ScreenTabBody>
109
+ <PeerEventHandlersUI peerEventType={peerEventType} handlers={handlers} />
110
+ </ScreenTabBody>
111
+ },
112
+
113
+ ]}
114
+ />
115
+ </div>
116
+ )
117
+ }
@@ -0,0 +1,61 @@
1
+ import { observable, Observable } from "@peers-app/peers-sdk";
2
+ import { isEqual } from "lodash";
3
+ import React, { useState } from "react";
4
+ import { newid, IDoc, IPeerEventHandler, IPeerEventType, Workflows } from "@peers-app/peers-sdk";
5
+ import { Tooltip } from "../../components/tooltip";
6
+ import { MarkdownEditorInline } from "../../components/markdown-editor/editor-inline";
7
+ import { LoadingIndicator } from "../../components/loading-indicator";
8
+ import { formatMention, getAllMentions } from "@peers-app/peers-sdk";
9
+ import { usePromise, useSubscription } from "../../hooks";
10
+
11
+ export const PeerEventHandlersUI = (props: { peerEventType: IDoc<IPeerEventType>, handlers: Observable<IPeerEventHandler[]> }) => {
12
+ const { peerEventType, handlers } = props;
13
+
14
+ const [handlersMarkdown] = useState(() => observable(''));
15
+
16
+ const markdownInitialized = usePromise(async () => {
17
+ const workflowIds = handlers().map(h => h.handlerWorkflowId);
18
+ const handlerWorkflows = await Workflows().list({ workflowId: { $in: workflowIds } });
19
+ const workflowTitles = handlerWorkflows.reduce((acc, wf) => ({ ...acc, [wf.workflowId]: wf.name }), {} as Record<string, string>);
20
+ const mentions = workflowIds.map(workflowId => '- ' + formatMention({ kind: 'workflow', id: workflowId, name: workflowTitles[workflowId] ?? workflowId }));
21
+ const markdown = `${mentions.join('\n') || '- '}`;
22
+ handlersMarkdown(markdown);
23
+ return true;
24
+ });
25
+
26
+ useSubscription(handlersMarkdown, () => {
27
+ if (!markdownInitialized) return;
28
+ const startWorkflowIds = handlers().map(h => h.handlerWorkflowId);
29
+ const workflowIds = getAllMentions(handlersMarkdown()).filter(m => m.kind === 'workflow').map(m => m.id);
30
+ if (isEqual(startWorkflowIds, workflowIds)) return;
31
+ const newHandlers: IPeerEventHandler[] = workflowIds.map(workflowId => ({
32
+ peerEventHandlerId: newid(),
33
+ peerEventTypeId: peerEventType.peerEventTypeId,
34
+ handlerWorkflowId: workflowId,
35
+ }));
36
+ handlers(newHandlers);
37
+ peerEventType.q(peerEventType.q() + 1);
38
+ console.log('new handlers', newHandlers.map(h => h.handlerWorkflowId));
39
+ });
40
+
41
+ if (!markdownInitialized) {
42
+ return <LoadingIndicator />;
43
+ }
44
+
45
+ return (
46
+ <div>
47
+
48
+ <div className='mt-2'>
49
+ <small>Mention workflows this event should trigger:</small>
50
+ <small>
51
+ <Tooltip markdownContent={`The mentions will be reformatted as a bulleted list regardless of how they are entered. All other content except for workflow mentions will be discarded.`} />
52
+ </small>
53
+
54
+ <MarkdownEditorInline
55
+ value={handlersMarkdown}
56
+ />
57
+ </div>
58
+
59
+ </div>
60
+ );
61
+ };