Commit 2711e0f5 authored by Ricardo J. Mendez's avatar Ricardo J. Mendez

Merge branch 'release/1.0.0'

parents acdcb3c5 03f447ed
(defproject relevance-chrome "0.9.0"
(defproject relevance-chrome "1.0.0"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
......@@ -43,9 +43,7 @@
:optimizations :whitespace
:pretty-print true}}
}
}
:chromebuild {:resource-paths ["resources/js"
"resources/dashboard"
"resources/images"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -15,6 +15,7 @@
<!-- Light Bootstrap Table core CSS -->
<link href="light-bootstrap-dashboard.css" rel="stylesheet"/>
<link href="relevance.css" rel="stylesheet"/>
<!-- Fonts and icons -->
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
......
......@@ -2,9 +2,7 @@
font-family: 'Pe-icon-7-stroke';
src:url('Pe-icon-7-stroke.eot?d7yf1v');
src:url('Pe-icon-7-stroke.eot?#iefixd7yf1v') format('embedded-opentype'),
url('Pe-icon-7-stroke.woff?d7yf1v') format('woff'),
url('Pe-icon-7-stroke.ttf?d7yf1v') format('truetype'),
url('Pe-icon-7-stroke.svg?d7yf1v#Pe-icon-7-stroke') format('svg');
url('Pe-icon-7-stroke.ttf?d7yf1v') format('truetype');
font-weight: normal;
font-style: normal;
}
......
.has_on_hover span.show_on_hover {
visibility: hidden;
}
.has_on_hover:hover span.show_on_hover {
visibility: visible;
}
\ No newline at end of file
{
"name": "Relevance - Smart tab organizer",
"name": "Relevance - Smart Tab Organizer",
"short_name": "Relevance",
"version": "0.9.0",
"version": "1.0.0",
"browser_action": {
"default_title": "Organize tabs",
"default_icon": {
......
(ns relevance.background
(:require [cljs.core.async :refer [>! <!]]
[clojure.walk :refer [keywordize-keys]]
[relevance.data :as data]
[relevance.io :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]
......@@ -32,11 +34,20 @@
(defn now [] (.now js/Date))
;;;;-------------------------------------
;;;; Functions
;;;;-------------------------------------
(defn accumulate-preserve-icons
"Accumulates all site times from url-times while preserving the
icons stored on site-data"
[url-times site-data]
(->>
;; Accumulate site times but preserve the icons we had before
(data/accumulate-site-times url-times)
(map #(vector (key %)
(assoc (val %) :icon (get-in site-data [(key %) :icon]))))
(into {})))
(defn check-window-status
"Checks if we have any focused window, and compares it against the
......@@ -84,7 +95,6 @@
(tabs/create {:url ext-url})))))
(defn time-score [tab url-times site-times]
(let [url (:url tab)
idx (:index tab)
......@@ -118,7 +128,7 @@
::initialize
(fn [_]
(go
(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
(hook-to-channels)
......@@ -136,27 +146,27 @@
(register-handler
:data-load
(fn [app-state [_ loaded]]
(let [migrated (migrations/migrate-to-latest loaded)
t (now)
new-urls (->
(:url-times migrated)
(data/time-clean-up (- t (* 7 ms-day)) 30)
(data/time-clean-up (- t (* 14 ms-day)) 90)
(data/time-clean-up (- t (* 30 ms-day)) 300))
site-data (:site-times migrated)
new-sites (if (not= new-urls (:url-times migrated))
(->>
;; Accumulate site times but preserve the icons we had before
(data/accumulate-site-times new-urls)
(map #(vector (key %)
(assoc (val %) :icon (get-in site-data [(key %) :icon]))))
(into {}))
site-data)
new-data (assoc migrated :url-times new-urls :site-times new-sites)]
; (console/trace "Data load" loaded "migrated" new-data)
(fn [app-state [_ data settings]]
(let [migrated (migrations/migrate-to-latest data)
t (now)
ignore-set (:ignore-set settings)
new-urls (->
(:url-times migrated)
(data/clean-up-by-time (- t (* 7 ms-day)) 30)
(data/clean-up-by-time (- t (* 14 ms-day)) 300)
(data/clean-up-by-time (- t (* 30 ms-day)) 1800)
(data/clean-up-ignored ignore-set))
site-data (:site-times migrated)
new-sites (if (not= new-urls (:url-times migrated))
(accumulate-preserve-icons new-urls site-data)
site-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)
......@@ -167,18 +177,36 @@
(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)
)))
(register-handler
:data-set
(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))
new-state)
))
(register-handler
:delete-url
(fn [app-state [_ url]]
(let [data (:data app-state)
old-times (:url-times data)
new-times (dissoc old-times (url-key url))
changed? (not= old-times new-times)
new-data (if changed?
(assoc data :url-times new-times
:site-times (accumulate-preserve-icons new-times (:site-times data)))
data)
]
(when changed?
(io/save :data new-data))
(assoc app-state :data new-data)
)))
(register-handler
:handle-activation
(fn [app-state [_ tab start-time]]
......@@ -259,10 +287,16 @@
(register-handler
::on-message
(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))])))
(fn [app-state [_ payload]]
(let [{:keys [message sender]} (keywordize-keys payload)
{:keys [action data]} message]
; (console/log "GOT INTERNAL MESSAGE" message "from" sender)
(condp = (keyword action)
:reload-data (go (dispatch [:data-load (<! (io/load :data)) (<! (io/load :settings))]))
:delete-url (dispatch [:delete-url data])
(console/error "Nothing matched" message)
)
)
app-state
))
......@@ -336,7 +370,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)
)))
......
(ns relevance.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
......@@ -18,7 +19,7 @@
)
(defn time-clean-up
(defn clean-up-by-time
"Removes from url-times all the items that are older than cut-off-ts
and which were viewed for less than min-seconds"
[url-times cut-off-ts min-seconds]
......@@ -27,11 +28,19 @@
(< (:time (val %)) min-seconds))
url-times)))
(defn clean-up-ignored
"Removes from url-times all the items for which the domain
matches an ignore set"
[url-times ignore-set]
(into {} (remove #(contains? ignore-set (hostname (:url (val %))))
url-times))
)
(defn track-url-time
"Receives a url time database, a tab record and a time to track, and returns
new time database which is the result of adding the time to the URL. It also
timestamps the record with the timestamp received."
[url-times tab time timestamp]
[url-times tab time timestamp & {:keys [ignore-set]}]
(let [url (or (:url tab) "")
id (url-key url)
url-item (or (get url-times id)
......@@ -39,6 +48,7 @@
:time 0
:ts 0})
track? (and (not= 0 id)
(not (contains? ignore-set (hostname url)))
(< 0 time))
new-item (assoc url-item :time (+ (:time url-item) time)
:title (:title tab)
......@@ -53,7 +63,7 @@
new time database which is the result of adding the time to the site. It also
timestamps the record with the timestamp received, and adds the favIconUrl of
the tab as the one for the entire site."
[site-times tab time timestamp]
[site-times tab time timestamp & {:keys [ignore-set]}]
(let [host (hostname (or (:url tab) ""))
id (host-key host)
site-item (or (get site-times id)
......@@ -61,6 +71,7 @@
:time 0
:ts 0})
track? (and (not= 0 id)
(not (contains? ignore-set host))
(< 0 time))
new-item (assoc site-item :time (+ (:time site-item) time)
:icon (:favIconUrl tab)
......
......@@ -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."
[data]
(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"
[]
[id]
(go
(let [raw (:data (<! (storage/get)))]
(let [raw (id (<! (storage/get)))]
(from-transit raw))))
(ns relevance.settings)
(def default-settings
{:ignore-set #{"localhost" "newtab" "t.co" "buff.ly"}})
\ No newline at end of file
......@@ -2,7 +2,8 @@
(:require [cljs.core.async :refer [<!]]
[clojure.string :refer [lower-case trim]]
[dommy.core :as dommy]
[cognitect.transit :as transit])
[cognitect.transit :as transit]
[clojure.string :as string])
(:require-macros [cljs.core.async.macros :refer [go go-loop]]))
......@@ -82,9 +83,18 @@
(hash-string shortened))
0))
(defn to-string-set
"Split a string into a string set using commas, semi-colons or new lines, and returns it as a set"
[s]
(->>
(string/split (or s "") #",|\n|;| ")
(map string/trim)
(remove empty?)
(map string/lower-case)
(into #{})))
(defn time-display
"Returns a display string for a number of milliseconds"
"Returns a display string for a number of seconds"
[seconds]
(letfn [(time-label [major major-label minor minor-label]
(apply str (concat [major major-label]
......@@ -92,8 +102,7 @@
(cond
(< seconds 1) "< 1s"
(< 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"))
)
(< seconds 3600) (time-label (quot seconds 60) "m" (rem seconds 60) "s")
(< seconds 86400) (time-label (quot seconds 3600) "h" (quot (rem seconds 3600) 60) "m")
: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! []
(go
(let [data (<! (io/load))
(let [data (<! (io/load :data))
nodes (sel :.result_url_heading)
base (sel1 :.web_regular_results)]
(doseq [node nodes]
......
This diff is collapsed.
......@@ -185,6 +185,26 @@
result (data/track-url-time (:url-times test-db) tab 9 ts)]
(is (= result (:url-times test-db)))
))
(testing "Attempting to add time to an ignored URL causes no changes"
;; Repeating almost the exact same test as when we tracked the time for
;; Numergent, only passing it as an ignore domain now.
(let [tab {:url "http://numergent.com/"
:title "Numergent limited"
:favIconUrl "http://numergent.com/favicon.png"}
ts 1445964037799
with-ignore (data/track-url-time (:url-times test-db) tab 9 ts
:ignore-set #{"localhost" "somedomain.com" "numergent.com"})
no-ignore (data/track-url-time (:url-times test-db) tab 9 ts
:ignore-set #{"localhost" "somedomain.com"})
tab-key (utils/url-key "http://numergent.com/")
item (get with-ignore tab-key)]
(is with-ignore)
(is (nil? item))
(is (= with-ignore (:url-times test-db)) "URL times should not have been altered")
(is (not= with-ignore no-ignore) "Removing the domain from the ignore list should result on the element being added")
(is (= (count no-ignore) (inc (count with-ignore))) "Result without ignoring the element should have one more value")
)
)
)
......@@ -207,7 +227,11 @@
(:favIconUrl tab) (:icon item)
"numergent.com" (:host item)
ts (:ts item)
1234 (:time item)))
1234 (:time item))
;; Let's make sure we did not break anything while adding an ignore parameter
(is (= result (data/track-site-time {} tab 1234 ts :ignore-set #{"localhost" "newtab"}))
"The result should be the same even if we pass an ignore-set")
)
)
(testing "Add time to an existing database for an existing site"
(let [tab {:url "http://numergent.com/opensource/index.html"
......@@ -230,7 +254,12 @@
147 (:time item))
(doseq [other (dissoc result id)]
(is (= (val other) (get (:site-times test-db) (key other))) "Other items should have remained untouched")
)))
)
;; Let's make sure we did not break anything while adding an ignore parameter
(is (= result (data/track-site-time (:site-times test-db) tab 3 ts
:ignore-set #{"localhost" "newtab"}))
"The result should be the same even if we pass an ignore-set")
))
(testing "Add time to an existing database for a new site"
(let [tab {:url "https://twitter.com/ArgesRic"
:title "ArgesRic"
......@@ -252,7 +281,13 @@
9 (:time item))
(doseq [other (dissoc result id)]
(is (= (val other) (get (:site-times test-db) (key other))) "Other items should have remained untouched")
))
)
;; Then, let's make sure we did not break anything while adding an ignore parameter
(is (= result
(data/track-site-time (:site-times test-db) tab 9 ts
:ignore-set #{"localhost" "somedomain.com"})))
)
)
(testing "Add zero time should not result on any changes"
(let [tab {:url "https://twitter.com/ArgesRic"
......@@ -278,13 +313,35 @@
ts)]
(is result)
(is (= result (:site-times test-db)))))
(testing "Add time to an ignored site does not change the database"
;; Repeating almost the exact same test as when we tracked the time for
;; Numergent, only passing it as an ignore domain now.
(let [tab {:url "http://numergent.com/opensource/index.html"
:title "Further open source project details"
:favIconUrl "http://numergent.com/newfavicon.png"}
ts 1445964037900
with-ignore (data/track-site-time (:site-times test-db) tab 3 ts
:ignore-set #{"localhost" "somedomain.com" "numergent.com"})
no-ignore (data/track-site-time (:site-times test-db) tab 3 ts
:ignore-set #{"localhost" "somedomain.com"})
id (utils/host-key (utils/hostname "http://numergent.com/opensource/"))
item (get no-ignore id)]
(is with-ignore)
(is (= with-ignore (:site-times test-db)))
(is (not= with-ignore no-ignore))
;; Then let's verify the values on the one we actually added
(are [expected result] (= expected result)
(:favIconUrl tab) (:icon item)
"numergent.com" (:host item)
ts (:ts item)
147 (:time item))))
)
(deftest test-time-clean-up
(deftest test-clean-up-by-time
(testing "Clean up date and minimum time are respected"
(let [min-date 1446028215913
pruned (data/time-clean-up (:url-times test-db) min-date 30)]
pruned (data/clean-up-by-time (:url-times test-db) min-date 30)]
(is pruned)
(is (= 5 (count pruned)))
;; We removed the right elements
......@@ -295,7 +352,7 @@
))
(testing "Timestamp filtering is only on strictly greater than"
(let [min-date 1446114615912
pruned (data/time-clean-up (:url-times test-db) min-date 30)]
pruned (data/clean-up-by-time (:url-times test-db) min-date 30)]
(is pruned)
(is (= 3 (count pruned)))
;; getprismatic is still there
......@@ -306,7 +363,7 @@
))
(testing "Cut-off seconds are respected when filtering"
(let [min-date 1446114615912
pruned (data/time-clean-up (:url-times test-db) min-date 28)]
pruned (data/clean-up-by-time (:url-times test-db) min-date 28)]
(is pruned)
(is (= 4 (count pruned)))
;; getprismatic is still there
......@@ -314,13 +371,34 @@
;; ... and we didn' lose splunk
(is (get pruned (utils/url-key "http://splunk.com/"))))
(let [min-date 1446114615913
pruned (data/time-clean-up (:url-times test-db) min-date 50)]
pruned (data/clean-up-by-time (:url-times test-db) min-date 50)]
(is pruned)
(is (= 2 (count pruned)))
(is (= #{-327774960 -327358142}
(into #{} (keys pruned)))))
))
(deftest test-clean-up-ignored
(let [url-times (:url-times test-db)]
(is (= url-times
(data/clean-up-ignored url-times #{}))
"Passing an empty set should not change things")
(is (= url-times
(data/clean-up-ignored url-times #{"localhost" "somedomain.com"}))
"Passing a set of not-matching domain does not change things")
;; Test removing a domain
(let [result (data/clean-up-ignored url-times #{"localhost" "numergent.com"})]
(is (= result (dissoc url-times -327774960 -526558523))
"We should have removed the numergent-associated urls")
(is (= 5 (count result))))
;; Test removing multiple domains
(let [result (data/clean-up-ignored url-times #{"localhost" "getprismatic.com" "numergent.com"})]
(is (= result (dissoc url-times -327774960 -526558523 1609181525))
"We should have removed the numergent-associated urls")
(is (= 4 (count result))))
))
(deftest test-accumulate-site-times
(testing "Accumulate site times creates a total but doesn't add favicons"
(is (= (into {} (map #(vector (key %) (assoc (val %) :icon nil))
......@@ -362,7 +440,7 @@
(deftest test-accumulate-after-clean-up
(testing "We get a value accumulation per site time after clean up"
(let [min-date 1446114615912
pruned (data/time-clean-up (:url-times test-db) min-date 30)
pruned (data/clean-up-by-time (:url-times test-db) min-date 30)
site-times (data/accumulate-site-times pruned)]
(is pruned)
(is (= {971841386 {:icon nil
......
......@@ -59,16 +59,16 @@
1 "1s"
3 "3s"
49 "49s"
60 "1min"
61 "1min 1s"
119 "1min 59s"
120 "2min"
124 "2min 4s"
762 "12min 42s"
60 "1m"
61 "1m 1s"
119 "1m 59s"
120 "2m"
124 "2m 4s"
762 "12m 42s"
3600 "1h"
3610 "1h"
3660 "1h 1min"
8659 "2h 24min"
3660 "1h 1m"
8659 "2h 24m"
86592 "1d"
124076 "1d 10h"
248996 "2d 21h"
......@@ -87,6 +87,7 @@
"chrome://extensions/?id=okhigbflgnbihoiokilagelkalkcigfp" "extensions"
"chrome-extension://okhigbflgnbihoiokilagelkalkcigfp/index.html" "okhigbflgnbihoiokilagelkalkcigfp"
"file:///Users/ricardo/Sources/user.html" ""
"view-source:http://localhost:4000/opensource/" ""
"" ""
nil nil
))
......@@ -115,7 +116,21 @@
"http://localhost" true
"https://numergent.com/" true
"chrome://extensions/?id=okhigbflgnbihoiokilagelkalkcigfp" false
"view-source:http://localhost:4000/opensource/" false
"http" false
"" false
nil false
))
\ No newline at end of file
))
(deftest test-to-string-set
(are [s result] (= result (utils/to-string-set s))
"alpha" #{"alpha"}
"alpha\nbeta" #{"alpha" "beta"}
"ALPHA\nBETA" #{"alpha" "beta"}
"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