server.cljs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. (ns frontend.components.server
  2. (:require
  3. [clojure.string :as string]
  4. [rum.core :as rum]
  5. [electron.ipc :as ipc]
  6. [medley.core :as medley]
  7. [promesa.core :as p]
  8. [frontend.state :as state]
  9. [frontend.util :as util]
  10. [frontend.handler.notification :as notification]
  11. [frontend.ui :as ui]))
  12. (rum/defcs panel-of-tokens
  13. < rum/reactive
  14. (rum/local nil ::tokens)
  15. {:will-mount
  16. (fn [s]
  17. (let [*tokens (s ::tokens)]
  18. (reset! *tokens (get-in @state/state [:electron/server :tokens])) s))}
  19. [_state close-panel]
  20. (let [server-state (state/sub :electron/server)
  21. *tokens (::tokens _state)
  22. changed? (not= @*tokens (:tokens server-state))]
  23. [:div.cp__server-tokens-panel.-mx-2
  24. [:h2.text-3xl.-translate-y-4 "Authorization tokens"]
  25. ;; items
  26. (let [update-value! (fn [idx k v] (swap! *tokens assoc-in [idx k] v))]
  27. (for [[idx {:keys [value name]}] (medley/indexed @*tokens)]
  28. [:div.item.py-2.flex.space-x-2.items-center
  29. {:key idx}
  30. [:input.form-input.basis-36
  31. {:auto-focus true
  32. :placeholder "name"
  33. :value name
  34. :on-change #(let [value (.-value (.-target %))]
  35. (update-value! idx :name value))}]
  36. [:input.form-input
  37. {:placeholder "value"
  38. :value value
  39. :on-change #(let [value (.-value (.-target %))]
  40. (update-value! idx :value value))}]
  41. [:button.px-2.opacity-50.hover:opacity-90.active:opacity-100
  42. {:on-click #(reset! *tokens (into [] (medley/remove-nth idx @*tokens)))}
  43. [:span.flex.items-center (ui/icon "trash-x")]]]))
  44. [:p.flex.justify-end.pt-6.space-x-3
  45. (ui/button "+ Add new token"
  46. :on-click #(swap! *tokens conj {})
  47. :intent "logseq")
  48. (ui/button "Save"
  49. :on-click (fn [] (-> (ipc/ipc :server/set-config {:tokens @*tokens})
  50. (p/then #(notification/show! "Update tokens successfully!" :success))
  51. (p/catch #(js/console.error %))
  52. (p/finally #(close-panel))))
  53. :disabled (not changed?))]]))
  54. (rum/defcs panel-of-configs
  55. < rum/reactive
  56. (rum/local nil ::configs)
  57. {:will-mount
  58. (fn [s]
  59. (let [*configs (s ::configs)]
  60. (reset! *configs (:electron/server @state/state)) s))}
  61. [_state close-panel]
  62. (let [server-state (state/sub :electron/server)
  63. *configs (::configs _state)
  64. {:keys [host port autostart]} @*configs
  65. hp-changed? (or (not= host (:host server-state))
  66. (not= (util/safe-parse-int (or port 0))
  67. (util/safe-parse-int (or (:port server-state) 0))))
  68. changed? (or hp-changed? (->> [autostart (:autostart server-state)]
  69. (mapv #(cond-> % (nil? %) not))
  70. (apply not=)))]
  71. [:div.cp__server-configs-panel.-mx-2
  72. [:h2.text-3xl.-translate-y-4 "Server configurations"]
  73. [:div.item.flex.items-center.space-x-3
  74. [:label.basis-96
  75. [:strong "Host"]
  76. [:input.form-input
  77. {:value host
  78. :on-change #(let [value (.-value (.-target %))]
  79. (swap! *configs assoc :host value))}]]
  80. [:label
  81. [:strong "Port (1 ~ 65535)"]
  82. [:input.form-input
  83. {:auto-focus true
  84. :value port
  85. :min "1"
  86. :max "65535"
  87. :type "number"
  88. :on-change #(let [value (.-value (.-target %))]
  89. (swap! *configs assoc :port value))}]]]
  90. [:p.py-3.px-1
  91. [:label.flex.space-x-2.items-center
  92. [:input.form-checkbox
  93. {:type "checkbox"
  94. :on-change #(let [checked (.-checked (.-target %))]
  95. (swap! *configs assoc :autostart checked))
  96. :checked (not (false? autostart))}]
  97. [:strong.select-none "Auto start server with the app launched"]]]
  98. [:p.flex.justify-end.pt-6.space-x-3
  99. (ui/button "Reset" :intent "logseq"
  100. :on-click #(reset! *configs (select-keys server-state [:host :port :autostart])))
  101. (ui/button "Save & Apply"
  102. :disabled (not changed?)
  103. :on-click (fn []
  104. (let [configs (select-keys @*configs [:host :port :autostart])]
  105. (-> (ipc/ipc :server/set-config configs)
  106. (p/then #(p/let [_ (close-panel)
  107. _ (p/delay 1000)]
  108. (when hp-changed?
  109. (ipc/ipc :server/do :restart))))
  110. (p/catch #(notification/show! (str %) :error))))))]]))
  111. (rum/defc server-indicator
  112. [server-state]
  113. (rum/use-effect!
  114. (fn []
  115. (p/let [_ (p/delay 1000)
  116. _ (ipc/ipc :server/load-state)]
  117. (let [t (js/setTimeout #(when (state/sub [:electron/server :autostart])
  118. (ipc/ipc :server/do :restart)) 1000)]
  119. #(js/clearTimeout t))))
  120. [])
  121. (let [{:keys [status error]} server-state
  122. status (keyword (util/safe-lower-case status))
  123. running? (= :running status)
  124. href (and running? (str "http://" (:host server-state) ":" (:port server-state)))]
  125. (rum/use-effect!
  126. #(when error
  127. (notification/show! (str "[Server] " error) :error))
  128. [error])
  129. [:div.cp__server-indicator
  130. ;; settings menus
  131. (ui/dropdown-with-links
  132. (fn [{:keys [toggle-fn]}]
  133. [:button.button.icon
  134. {:on-click #(toggle-fn)}
  135. (ui/icon (if running? "api" "api-off") {:size 22})])
  136. ;; items
  137. (->> [{:hr true}
  138. (cond
  139. running?
  140. {:title "Stop server"
  141. :options {:on-click #(ipc/ipc :server/do :stop)}
  142. :icon [:span.text-red-500.flex.items-center (ui/icon "player-stop")]}
  143. :else
  144. {:title "Start server"
  145. :options {:on-click #(ipc/ipc :server/do :restart)}
  146. :icon [:span.text-green-500.flex.items-center (ui/icon "player-play")]})
  147. {:title "Authorization tokens"
  148. :options {:on-click #(state/set-modal!
  149. (fn [close]
  150. (panel-of-tokens close))
  151. {:center? true})}
  152. :icon (ui/icon "key")}
  153. {:title "Server configurations"
  154. :options {:on-click #(state/set-modal!
  155. (fn [close]
  156. (panel-of-configs close))
  157. {:center? true})}
  158. :icon (ui/icon "server-cog")}])
  159. {:links-header
  160. [:div.links-header.flex.justify-center.py-2
  161. [:span.ml-1.text-sm
  162. (if-not running?
  163. (string/upper-case (or (:status server-state) "stopped"))
  164. [:a.hover:underline {:href href} href])]]})]))