debug_ui.cljs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. (ns frontend.db.rtc.debug-ui
  2. "Debug UI for rtc module"
  3. (:require [fipp.edn :as fipp]
  4. [frontend.common.missionary :as c.m]
  5. [frontend.db :as db]
  6. [frontend.handler.db-based.rtc-flows :as rtc-flows]
  7. [frontend.handler.user :as user]
  8. [frontend.state :as state]
  9. [frontend.ui :as ui]
  10. [frontend.util :as util]
  11. [logseq.db.frontend.schema :as db-schema]
  12. [logseq.shui.ui :as shui]
  13. [missionary.core :as m]
  14. [promesa.core :as p]
  15. [rum.core :as rum]))
  16. (defonce debug-state (:rtc/state @state/state))
  17. (defn- stop
  18. []
  19. (p/do!
  20. (state/<invoke-db-worker :thread-api/rtc-stop)
  21. (reset! debug-state nil)))
  22. (rum/defcs ^:large-vars/cleanup-todo rtc-debug-ui < rum/reactive
  23. (rum/local nil ::logs)
  24. (rum/local nil ::sub-log-canceler)
  25. (rum/local nil ::keys-state)
  26. {:will-mount (fn [state]
  27. (let [canceler
  28. (c.m/run-task
  29. (m/reduce
  30. (fn [logs log]
  31. (let [logs* (if log
  32. (take 10 (conj logs log))
  33. logs)]
  34. (reset! (get state ::logs) logs*)
  35. logs*))
  36. nil rtc-flows/rtc-log-flow)
  37. ::sub-logs)]
  38. (reset! (get state ::sub-log-canceler) canceler)
  39. state))
  40. :will-unmount (fn [state]
  41. (when-let [canceler (some-> (get state ::sub-log-canceler) deref)]
  42. (canceler))
  43. state)}
  44. [state]
  45. (let [debug-state* (rum/react debug-state)
  46. rtc-logs @(get state ::logs)
  47. rtc-state (:rtc-state debug-state*)
  48. rtc-lock (:rtc-lock debug-state*)]
  49. [:div
  50. {:on-click (fn [^js e]
  51. (when-let [^js btn (.closest (.-target e) ".ui__button")]
  52. (.setAttribute btn "disabled" "true")
  53. (js/setTimeout #(.removeAttribute btn "disabled") 2000)))}
  54. [:div.flex.gap-2.flex-wrap.items-center.pb-3
  55. (shui/button
  56. {:size :sm
  57. :on-click (fn [_]
  58. (p/let [new-state (state/<invoke-db-worker :thread-api/rtc-get-debug-state)]
  59. (swap! debug-state (fn [old] (merge old new-state)))))}
  60. (shui/tabler-icon "refresh") "state")
  61. (shui/button
  62. {:size :sm
  63. :on-click
  64. (fn [_]
  65. (let [token (state/get-auth-id-token)]
  66. (p/let [graph-list (state/<invoke-db-worker :thread-api/rtc-get-graphs token)]
  67. (swap! debug-state assoc
  68. :remote-graphs
  69. (map
  70. #(into {}
  71. (filter second
  72. (select-keys % [:graph-uuid
  73. :graph-schema-version
  74. :graph-name
  75. :graph-status
  76. :graph<->user-user-type
  77. :graph<->user-grant-by-user])))
  78. graph-list)))))}
  79. (shui/tabler-icon "download") "graph-list")
  80. (shui/button
  81. {:size :sm
  82. :on-click #(c.m/run-task
  83. (user/new-task--upload-user-avatar "TEST_AVATAR")
  84. :upload-test-avatar)}
  85. (shui/tabler-icon "upload") "upload-test-avatar")]
  86. [:div.pb-4
  87. [:pre.select-text
  88. (-> {:user-uuid (user/user-uuid)
  89. :graph (:graph-uuid debug-state*)
  90. :rtc-state rtc-state
  91. :rtc-logs rtc-logs
  92. :local-tx (:local-tx debug-state*)
  93. :pending-block-update-count (:unpushed-block-update-count debug-state*)
  94. :remote-graphs (:remote-graphs debug-state*)
  95. :online-users (:online-users debug-state*)
  96. :auto-push? (:auto-push? debug-state*)
  97. :remote-profile? (:remote-profile? debug-state*)
  98. :current-page (state/get-current-page)
  99. :blocks-count (when-let [page (state/get-current-page)]
  100. (count (:block/_page (db/get-page page))))
  101. :schema-version {:app (db-schema/schema-version->string db-schema/version)
  102. :local-graph (:local-graph-schema-version debug-state*)
  103. :remote-graph (str (:remote-graph-schema-version debug-state*))}}
  104. (fipp/pprint {:width 20})
  105. with-out-str)]]
  106. (if (nil? rtc-lock)
  107. (shui/button
  108. {:variant :outline
  109. :class "text-green-rx-09 border-green-rx-10 hover:text-green-rx-10"
  110. :on-click (fn []
  111. (let [token (state/get-auth-id-token)]
  112. (state/<invoke-db-worker :thread-api/rtc-start (state/get-current-repo) token)))}
  113. (shui/tabler-icon "player-play") "start")
  114. [:div.my-2.flex
  115. [:div.mr-2 (ui/button (str "Toggle auto push updates("
  116. (if (:auto-push? debug-state*)
  117. "ON" "OFF")
  118. ")")
  119. {:on-click
  120. (fn []
  121. (state/<invoke-db-worker :thread-api/rtc-toggle-auto-push))})]
  122. [:div.mr-2 (ui/button (str "Toggle remote profile("
  123. (if (:remote-profile? debug-state*)
  124. "ON" "OFF")
  125. ")")
  126. {:on-click
  127. (fn []
  128. (state/<invoke-db-worker :thread-api/rtc-toggle-remote-profile))})]
  129. [:div (shui/button
  130. {:variant :outline
  131. :class "text-red-rx-09 border-red-rx-08 hover:text-red-rx-10"
  132. :size :sm
  133. :on-click (fn [] (stop))}
  134. (shui/tabler-icon "player-stop") "stop")]])
  135. (when (some? debug-state*)
  136. [:hr]
  137. [:div.flex.flex-row.items-center.gap-2
  138. (ui/button "grant graph access to"
  139. {:icon "award"
  140. :on-click (fn []
  141. (let [token (state/get-auth-id-token)
  142. user-uuid (some-> (:grant-access-to-user debug-state*) parse-uuid)
  143. user-email (when-not user-uuid (:grant-access-to-user debug-state*))]
  144. (when-let [graph-uuid (:graph-uuid debug-state*)]
  145. (state/<invoke-db-worker :thread-api/rtc-grant-graph-access
  146. token graph-uuid
  147. (some-> user-uuid vector)
  148. (some-> user-email vector)))))})
  149. [:b "➡️"]
  150. [:input.form-input.my-2.py-1
  151. {:on-change (fn [e] (swap! debug-state assoc :grant-access-to-user (util/evalue e)))
  152. :on-focus (fn [e] (let [v (.-value (.-target e))]
  153. (when (= v "input email or user-uuid here")
  154. (set! (.-value (.-target e)) ""))))
  155. :placeholder "input email or user-uuid here"}]])
  156. [:hr.my-2]
  157. [:div.flex.flex-row.items-center.gap-2
  158. (ui/button (str "download graph to")
  159. {:icon "download"
  160. :class "mr-2"
  161. :on-click (fn []
  162. (when-let [graph-name (:download-graph-to-repo debug-state*)]
  163. (when-let [{:keys [graph-uuid graph-schema-version]}
  164. (:graph-uuid-to-download debug-state*)]
  165. (prn :download-graph graph-uuid graph-schema-version :to graph-name)
  166. (p/let [token (state/get-auth-id-token)
  167. download-info-uuid (state/<invoke-db-worker
  168. :thread-api/rtc-request-download-graph
  169. token graph-uuid graph-schema-version)
  170. {:keys [_download-info-uuid
  171. download-info-s3-url
  172. _download-info-tx-instant
  173. _download-info-t
  174. _download-info-created-at]
  175. :as result}
  176. (state/<invoke-db-worker :thread-api/rtc-wait-download-graph-info-ready
  177. token download-info-uuid graph-uuid graph-schema-version 60000)]
  178. (when (not= result :timeout)
  179. (assert (some? download-info-s3-url) result)
  180. (state/<invoke-db-worker :thread-api/rtc-download-graph-from-s3
  181. graph-uuid graph-name download-info-s3-url))))))})
  182. [:b "➡"]
  183. [:div.flex.flex-row.items-center.gap-2
  184. (shui/select
  185. {:on-value-change (fn [[graph-uuid graph-schema-version]]
  186. (when (and (parse-uuid graph-uuid) graph-schema-version)
  187. (swap! debug-state assoc
  188. :graph-uuid-to-download
  189. {:graph-uuid graph-uuid
  190. :graph-schema-version graph-schema-version})))}
  191. (shui/select-trigger
  192. {:class "!px-2 !py-0 !h-8 border-gray-04"}
  193. (shui/select-value
  194. {:placeholder "Select a graph-uuid"}))
  195. (shui/select-content
  196. (shui/select-group
  197. (for [{:keys [graph-uuid graph-schema-version graph-status]} (sort-by :graph-uuid (:remote-graphs debug-state*))]
  198. (shui/select-item {:value [graph-uuid graph-schema-version] :disabled (some? graph-status)} graph-uuid)))))
  199. [:b "+"]
  200. [:input.form-input.my-2.py-1
  201. {:on-change (fn [e] (swap! debug-state assoc :download-graph-to-repo (util/evalue e)))
  202. :on-focus (fn [e] (let [v (.-value (.-target e))]
  203. (when (= v "repo name here")
  204. (set! (.-value (.-target e)) ""))))
  205. :placeholder "repo name here"}]]]
  206. [:div.flex.my-2.items-center.gap-2
  207. (ui/button (str "upload current repo")
  208. {:icon "upload"
  209. :on-click (fn []
  210. (let [repo (state/get-current-repo)
  211. token (state/get-auth-id-token)
  212. remote-graph-name (:upload-as-graph-name debug-state*)]
  213. (state/<invoke-db-worker :thread-api/rtc-async-upload-graph
  214. repo token remote-graph-name)))})
  215. [:b "➡️"]
  216. [:input.form-input.my-2.py-1.w-32
  217. {:on-change (fn [e] (swap! debug-state assoc :upload-as-graph-name (util/evalue e)))
  218. :on-focus (fn [e] (let [v (.-value (.-target e))]
  219. (when (= v "remote graph name here")
  220. (set! (.-value (.-target e)) ""))))
  221. :placeholder "remote graph name here"}]]
  222. [:div.pb-2.flex.flex-row.items-center.gap-2
  223. (ui/button (str "delete graph")
  224. {:icon "trash"
  225. :on-click (fn []
  226. (when-let [{:keys [graph-uuid graph-schema-version]} (:graph-uuid-to-delete debug-state*)]
  227. (let [token (state/get-auth-id-token)]
  228. (prn ::delete-graph graph-uuid graph-schema-version)
  229. (state/<invoke-db-worker :thread-api/rtc-delete-graph
  230. token graph-uuid graph-schema-version))))})
  231. (shui/select
  232. {:on-value-change (fn [[graph-uuid graph-schema-version]]
  233. (when (and (parse-uuid graph-uuid) graph-schema-version)
  234. (swap! debug-state assoc
  235. :graph-uuid-to-delete
  236. {:graph-uuid graph-uuid
  237. :graph-schema-version graph-schema-version})))}
  238. (shui/select-trigger
  239. {:class "!px-2 !py-0 !h-8"}
  240. (shui/select-value
  241. {:placeholder "Select a graph-uuid"}))
  242. (shui/select-content
  243. (shui/select-group
  244. (for [{:keys [graph-uuid graph-schema-version graph-status]} (:remote-graphs debug-state*)]
  245. (shui/select-item {:value [graph-uuid graph-schema-version] :disabled (some? graph-status)} graph-uuid)))))]
  246. [:div.pb-2.flex.flex-row.items-center.gap-2
  247. (ui/button "Run server-migrations"
  248. {:on-click (fn []
  249. (let [repo (state/get-current-repo)]
  250. (when-let [server-schema-version (:server-schema-version debug-state*)]
  251. (state/<invoke-db-worker :thread-api/rtc-add-migration-client-ops
  252. repo server-schema-version))))})
  253. [:input.form-input.my-2.py-1.w-32
  254. {:on-change (fn [e] (swap! debug-state assoc :server-schema-version (util/evalue e)))
  255. :on-focus (fn [e] (let [v (.-value (.-target e))]
  256. (when (= v "server migration start version here(e.g. \"64.2\")")
  257. (set! (.-value (.-target e)) ""))))
  258. :placeholder "server migration start version here(e.g. \"64.2\")"}]]
  259. [:hr.my-2]
  260. (let [*keys-state (get state ::keys-state)
  261. keys-state @*keys-state]
  262. [:div
  263. [:div.pb-2.flex.flex-row.items-center.gap-2
  264. (shui/button
  265. {:size :sm
  266. :on-click (fn [_]
  267. (p/let [graph-keys (state/<invoke-db-worker :thread-api/rtc-get-graph-keys (state/get-current-repo))
  268. devices (some->> (state/get-auth-id-token)
  269. (state/<invoke-db-worker :thread-api/list-devices))]
  270. (swap! (get state ::keys-state) #(merge % graph-keys {:devices devices}))))}
  271. (shui/tabler-icon "refresh") "keys-state")]
  272. [:div.pb-4
  273. [:pre.select-text
  274. (-> {:devices (:devices keys-state)
  275. :graph-aes-key-jwk (:aes-key-jwk keys-state)}
  276. (fipp/pprint {:width 20})
  277. with-out-str)]]
  278. (shui/button
  279. {:size :sm
  280. :on-click (fn [_]
  281. (when-let [device-uuid (not-empty (:remove-device-device-uuid keys-state))]
  282. (when-let [token (state/get-auth-id-token)]
  283. (state/<invoke-db-worker :thread-api/remove-device token device-uuid))))}
  284. "Remove device:")
  285. [:input.form-input.my-2.py-1.w-32
  286. {:on-change (fn [e] (swap! *keys-state assoc :remove-device-device-uuid (util/evalue e)))
  287. :on-focus (fn [e] (let [v (.-value (.-target e))]
  288. (when (= v "device-uuid here")
  289. (set! (.-value (.-target e)) ""))))
  290. :placeholder "device-uuid here"}]
  291. (shui/button
  292. {:size :sm
  293. :on-click (fn [_]
  294. (when-let [device-uuid (not-empty (:remove-public-key-device-uuid keys-state))]
  295. (when-let [key-name (not-empty (:remove-public-key-key-name keys-state))]
  296. (when-let [token (state/get-auth-id-token)]
  297. (state/<invoke-db-worker :thread-api/remove-device-public-key token device-uuid key-name)))))}
  298. "Remove public-key:")
  299. [:input.form-input.my-2.py-1.w-32
  300. {:on-change (fn [e] (swap! *keys-state assoc :remove-public-key-device-uuid (util/evalue e)))
  301. :on-focus (fn [e] (let [v (.-value (.-target e))]
  302. (when (= v "device-uuid here")
  303. (set! (.-value (.-target e)) ""))))
  304. :placeholder "device-uuid here"}]
  305. [:input.form-input.my-2.py-1.w-32
  306. {:on-change (fn [e] (swap! *keys-state assoc :remove-public-key-key-name (util/evalue e)))
  307. :on-focus (fn [e] (let [v (.-value (.-target e))]
  308. (when (= v "key-name here")
  309. (set! (.-value (.-target e)) ""))))
  310. :placeholder "key-name here"}]
  311. (shui/button
  312. {:size :sm
  313. :on-click (fn [_]
  314. (when-let [token (state/get-auth-id-token)]
  315. (when-let [device-uuid (not-empty (:sync-private-key-device-uuid keys-state))]
  316. (state/<invoke-db-worker :thread-api/rtc-sync-current-graph-encrypted-aes-key
  317. token [(parse-uuid device-uuid)]))))}
  318. "Sync CurrentGraph EncryptedAesKey")
  319. [:input.form-input.my-2.py-1.w-32
  320. {:on-change (fn [e] (swap! *keys-state assoc :sync-private-key-device-uuid (util/evalue e)))
  321. :on-focus (fn [e] (let [v (.-value (.-target e))]
  322. (when (= v "device-uuid here")
  323. (set! (.-value (.-target e)) ""))))
  324. :placeholder "device-uuid here"}]])]))