Commit 9596d91a authored by Ricardo J. Mendez's avatar Ricardo J. Mendez

Implemented settings UI

Decided that I'd keep the settings and the data separate, so I'm now
saving two transit-encoded data blocks.

- io/save and io/get now expect a key to retrieve
- io/save can now receive a callback as well
- Having the background script reload data when we save new settings
parent d328936b
......@@ -4,6 +4,7 @@
[ :as io]
[relevance.migrations :as migrations]
[relevance.utils :refer [on-channel url-key host-key hostname is-http? ms-day]]
[relevance.settings :refer [default-settings]]
[khroma.alarms :as alarms]
[khroma.context-menus :as menus]
[khroma.idle :as idle]
......@@ -29,8 +30,6 @@
(def relevant-tab-keys [:windowId :id :active :url :start-time :title :favIconUrl])
(def select-tab-keys #(select-keys % relevant-tab-keys))
(def default-ignore-set #{"localhost" "newtab"})
(defn now [] (.now js/Date))
......@@ -119,7 +118,7 @@
(fn [_]
(dispatch [:data-load (<! (io/load))])
(dispatch [:data-load (<! (io/load :data)) (or (<! (io/load :settings)) default-settings)])
(dispatch [::window-focus {:windowId (:id (<! (windows/get-last-focused {:populate false})))}])
;; We should only hook to the channels once, so we do it during the :initialize handler
......@@ -137,10 +136,10 @@
(fn [app-state [_ loaded]]
(let [migrated (migrations/migrate-to-latest loaded)
(fn [app-state [_ data settings]]
(let [migrated (migrations/migrate-to-latest data)
t (now)
ignore-set (or (:ignore-set migrated) default-ignore-set)
ignore-set (:ignore-set settings)
new-urls (->
(:url-times migrated)
(data/clean-up-by-time (- t (* 7 ms-day)) 30)
......@@ -156,10 +155,13 @@
(assoc (val %) :icon (get-in site-data [(key %) :icon]))))
(into {}))
new-data (assoc migrated :url-times new-urls :site-times new-sites :ignore-set ignore-set)]
; (console/trace "Data load" loaded "migrated" new-data)
new-data (assoc migrated :url-times new-urls :site-times new-sites)]
; (console/trace "Data load" data "migrated" new-data)
; (console/trace "Settings" settings)
;; Save the migrated data we just received
(io/save new-data)
;; We don't save the settings, since the background script does not really change them.
;; That's the UI's domain.
(io/save :data new-data)
;; Process the suspend info
(let [suspend-info (:suspend-info new-data)
old-tab (:active-tab suspend-info)
......@@ -170,15 +172,16 @@
(if is-same?
(dispatch [:handle-activation old-tab (:start-time old-tab)])
(dispatch [:handle-deactivation old-tab (:time suspend-info)])))
(-> app-state
(assoc :data (dissoc new-data :suspend-info))))))
(assoc app-state :data (dissoc new-data :suspend-info)
:settings settings)
(fn [app-state [_ key item]]
(let [new-state (assoc-in app-state [:data key] item)]
(io/save (:data new-state))
(io/save :data (:data new-state))
......@@ -265,7 +268,7 @@
(fn [app-state [_ {:keys [message sender]}]]
; (console/log "GOT INTERNAL MESSAGE" message "from" sender)
(condp = (keyword message)
:reload-data (go (dispatch [:data-load (<! (io/load))])))
:reload-data (go (dispatch [:data-load (<! (io/load :data)) (<! (io/load :settings))])))
......@@ -339,7 +342,7 @@
site-times (data/track-site-time (or (:site-times data) {}) tab (quot time 1000) (now))
new-data (assoc data :url-times url-times :site-times site-times)]
; (console/trace time " milliseconds spent at " tab)
(io/save new-data)
(io/save :data new-data)
(assoc app-state :data new-data)
(:require [relevance.utils :refer [url-key host-key hostname]]))
(:require [relevance.utils :refer [url-key host-key hostname]]
[khroma.log :as console]))
(defn accumulate-site-times
......@@ -10,19 +10,21 @@
(defn save-raw
"Saves the data raw, without converting it to transit first."
[data callback]
(storage/set {:data data} storage/local callback))
[id data callback]
(storage/set {id data} storage/local callback))
(defn save
"Saves our data on the extension's storage after converting it to transit."
(save-raw (to-transit data) nil))
([id data]
(save id data nil))
([id data callback]
(save-raw id (to-transit data) callback)))
(defn load
"Returns a channel where we'll put the entire data block read from the
extension's storage"
(let [raw (:data (<! (storage/get)))]
(let [raw (id (<! (storage/get)))]
(from-transit raw))))
(ns relevance.settings)
(def default-settings
{:ignore-set #{"localhost" "newtab" "" ""}})
\ No newline at end of file
......@@ -87,7 +87,7 @@
"Split a string into a string set using commas, semi-colons or new lines, and returns it as a set"
(string/split (or s "") #",|\n|;")
(string/split (or s "") #",|\n|;| ")
(map string/trim)
(remove empty?)
(map string/lower-case)
......@@ -104,6 +104,5 @@
(< seconds 60) (str seconds "s")
(< seconds 3600) (time-label (quot seconds 60) "min" (rem seconds 60) "s")
(< seconds 86400) (time-label (quot seconds 3600) "h" (quot (rem seconds 3600) 60) "min")
:else (time-label (quot seconds 86400) "d" (quot (rem seconds 86400) 3600) "h"))
:else (time-label (quot seconds 86400) "d" (quot (rem seconds 86400) 3600) "h")))
\ No newline at end of file
......@@ -41,7 +41,7 @@
(defn do-transformations! []
(let [data (<! (io/load))
(let [data (<! (io/load :data))
nodes (sel :.result_url_heading)
base (sel1 :.web_regular_results)]
(doseq [node nodes]
......@@ -4,13 +4,17 @@
[cljs.core.async :refer [>! <!]]
[cljs.core :refer [random-uuid]]
[clojure.string :as string]
[khroma.idle :as idle]
[khroma.log :as console]
[khroma.runtime :as runtime]
[ :as storage]
[reagent.core :as reagent]
[re-frame.core :refer [dispatch register-sub register-handler subscribe dispatch-sync]]
[ :as io])
[ :as io]
[relevance.utils :as utils]
[relevance.settings :refer [default-settings]]
(:require-macros [cljs.core :refer [goog-define]]
[cljs.core.async.macros :refer [go go-loop]]
[reagent.ratom :refer [reaction]]))
......@@ -26,6 +30,7 @@
;; Application data, will be saved
(register-sub :data general-query)
(register-sub :settings general-query)
(register-sub :raw-data general-query)
;; Transient data items
(register-sub :ui-state general-query)
......@@ -62,7 +67,7 @@
(fn [app-state [_ transit-data]]
;; We actually just need to save it, since ::storage-changed takes care
;; of loading it and importing it.
(io/save-raw transit-data #(runtime/send-message :reload-data))
(io/save-raw :data transit-data #(runtime/send-message :reload-data))
(-> app-state
(assoc-in [:ui-state :section] :url-times)
(assoc-in [:app-state :import] nil))
......@@ -72,9 +77,13 @@
(fn [_]
;; Fake a ::storage-changed message to load the data from storage
(go (dispatch [::storage-changed {:changes {:data {:newValue (:data (<! (storage/get)))}}}]))
(dispatch [:settings-set (or (<! (io/load :settings))
;; Fake a ::storage-changed message to load the data from storage
(dispatch [::storage-changed {:changes {:data {:newValue (:data (<! (storage/get)))}}}]))
{:app-state {}
:settings default-settings
:ui-state {:section :intro}}))
......@@ -83,6 +92,23 @@
(fn [app-state [_ info]]
(assoc-in app-state [:ui-state :modal-info] info)))
(fn [app-state [_ settings]]
(let [ignore-set (utils/to-string-set (:ignore-set settings))]
(dispatch [:settings-set {:ignore-set ignore-set} true])
(fn [app-state [_ settings save?]]
; (console/log "Saving" settings save?)
(when save?
;; We tell the backend to reload the data after saving the settings, since
;; they can have an effect on behavior.
(io/save :settings settings #(runtime/send-message :reload-data)))
(assoc app-state :settings settings)))
......@@ -126,6 +152,7 @@
(nav-left-item "Introduction" "pe-7s-home" :intro @section)
(nav-left-item "Page times" "pe-7s-note2" :url-times @section)
(nav-left-item "Site times" "pe-7s-note2" :site-times @section)
(nav-left-item "Settings" "pe-7s-config" :settings @section)
(nav-left-item "Export data" "pe-7s-box1" :export @section)
(nav-left-item "Import data" "pe-7s-attention" :import @section)]))
......@@ -140,6 +167,7 @@
:url-times "Time reading a page"
:site-times "Time visiting a site"
:export "Export your Relevance data"
:settings "Settings"
:import "Import a Relevance backup"
......@@ -190,7 +218,7 @@
(< age-ms (* 14 ms-day)) "#cc6600"
:else "#994c00"
^{:key i}
[:td {:class "col-sm-2"}
......@@ -320,6 +348,7 @@
(defn data-import []
(let [import-data (reagent/atom "")]
(fn []
......@@ -332,14 +361,39 @@
:rows 30
:value @import-data
:on-change #(reset! import-data (-> % .-target .-value))}]
[:a {:class "btn btn-danger btn-sm"
[:a {:class "btn btn-primary btn-sm"
:on-click #(dispatch [:data-import @import-data])} "Import"]
(defn div-settings []
(let [ignore-set (subscribe [:settings :ignore-set])
our-ignore (reagent/atom (string/join "\n" (sort @ignore-set)))
(fn []
[:div {:class "col-sm-12"}
[:div {:class "row"}
[:div {:class "col-sm-6"}
[:h3 "Ignore domains"]
[:p "Type on the left domains that you want ignore, one per line."]
[:p {:class "alert alert-info"} [:strong "Heads up! "] "Adding a domain to the ignore list will remove the data Relevance currently has for it."]
[:div {:class "col-sm-6"}
[:textarea {:class "form-control"
:value @our-ignore
:rows 10
:on-change #(reset! our-ignore (-> % .-target .-value))}
[:div {:class "row"}
[:a {:class "btn btn-danger btn-sm"
:on-click #(dispatch [:settings-parse {:ignore-set @our-ignore}])} "Save settings"]]
(def component-dir {:export data-export
:import data-import
:intro div-intro
:settings div-settings
:url-times div-urltimes
:site-times div-sitetimes})
......@@ -131,5 +131,6 @@
"alpha\nbeta " #{"alpha" "beta"}
"a\nbeta,c" #{"a" "beta" "c"}
"a\nbeta,C;d;" #{"a" "beta" "c" "d"}
"a b,c" #{"a" "b" "c"}
"a,b,,c,;d;e;; f,e\n\n" #{"a" "b" "c" "d" "e" "f"}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment