diff --git a/README.md b/README.md index 68dfad2..c073113 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # ora +Work in progress. Come back soon for more 🚀 +
Icons made by Pixel perfect from www.flaticon.com
diff --git a/ROADMAP.md b/ROADMAP.md index b4e51d4..a9f1c73 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,14 +2,11 @@ ## Current -- Max time for website -> block. - ## Backlog - Dark mode support - Options - Dashboard -- Better icon - Add footer - Build With ♥️ - Github link diff --git a/manifest.json b/manifest.json index e410fb3..d9225c8 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Ora", - "version": "0.2", + "version": "0.3", "description": "See how much time you spend on each website and set limits", "icons": { diff --git a/package.json b/package.json index 7b2969d..0f04bd0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "homepage": "https://github.com/cupcakearmy/ora", "scripts": { - "clean": "rm -rf dist .cache", + "clean": "rm -rf dist .cache web-ext-artifacts node_modules", "dev": "parcel watch --no-hmr manifest.json src/dashboard/index.html", "build": "parcel build --no-content-hash --no-source-maps --no-minify manifest.json src/dashboard/index.html", "dist": "rm -rf dist && yarn run build && web-ext build -s dist --overwrite-dest" @@ -23,6 +23,8 @@ "dayjs": "^1.8.36", "dexie": "^3.0.2", "faker": "^5.1.0", + "file-saver": "^2.0.2", + "joi": "^17.2.1", "lodash": "^4.17.20", "spectre.css": "^0.5.9", "svelte-spa-router": "^2.2.0", diff --git a/src/background/index.js b/src/background/index.js index e647450..15961cf 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -1,14 +1,15 @@ import browser from 'webextension-polyfill' +import dayjs from 'dayjs' import { dashboard } from '../shared/utils' -import { insertLog, normalizeTimestamp, Limits } from '../shared/db' +import { insertLog, normalizeTimestamp, Limits, DB } from '../shared/db' import { getUsageForHost, percentagesToBool } from '../shared/lib' browser.browserAction.onClicked.addListener(() => browser.tabs.create({ url: dashboard, active: true })) const frequency = 1000 -async function getAllTabs() { +async function log() { try { const tabs = await browser.tabs.query({}) const windows = await browser.windows.getAll() @@ -35,9 +36,16 @@ async function getAllTabs() { } catch {} } -setInterval(() => { - getAllTabs() -}, frequency) +async function deleteOldLogs() { + const { retention } = await browser.storage.local.get() + const maxAge = dayjs().startOf('day').subtract(retention, 'days').toDate() + const toDelete = await DB.logs.where('timestamp').below(maxAge).toArray() + const ids = toDelete.map((log) => log.id) + await DB.logs.bulkDelete(ids) +} + +setInterval(deleteOldLogs, 5 * 60 * 1000) // Delete old logs every 5 minutes +setInterval(log, frequency) browser.runtime.onMessage.addListener((message, sender, sendResponse) => { return getUsageForHost(message).then((percentages) => percentagesToBool(percentages)) diff --git a/src/dashboard/App.svelte b/src/dashboard/App.svelte index fd1fe41..e50ccd6 100644 --- a/src/dashboard/App.svelte +++ b/src/dashboard/App.svelte @@ -5,6 +5,8 @@ import Dashboard from './pages/Dashboard.svelte' import Limits from './pages/Limits.svelte' + import { isDev } from '../shared/utils' + const routes = { '/': Dashboard, @@ -21,7 +23,9 @@ } - +{#if isDev} + +{/if}
diff --git a/src/dashboard/components/Chart.svelte b/src/dashboard/components/Chart.svelte index a3a1434..38fbb41 100644 --- a/src/dashboard/components/Chart.svelte +++ b/src/dashboard/components/Chart.svelte @@ -1,38 +1,24 @@ diff --git a/src/dashboard/components/Dev.svelte b/src/dashboard/components/Dev.svelte index 5ac236e..23de26c 100644 --- a/src/dashboard/components/Dev.svelte +++ b/src/dashboard/components/Dev.svelte @@ -3,14 +3,14 @@ import day from 'dayjs' import { range, random } from 'lodash' - import { insertLog, normalizeTimestamp, DB } from '../../shared/db' + import { insertLog, normalizeTimestamp, DB, clear as clearDB } from '../../shared/db' let loading = false async function fill() { try { loading = true - const start = day().subtract('7', 'days').valueOf() + const start = day().subtract(2, 'weeks').valueOf() const end = Date.now() for (const n of range(20)) { const host = faker.internet.domainName() @@ -29,8 +29,7 @@ async function clear() { try { loading = true - await DB.limits.clear() - await DB.logs.clear() + await clearDB() } finally { loading = false } diff --git a/src/dashboard/components/RangeChooser.svelte b/src/dashboard/components/RangeChooser.svelte index 6fa21ed..5dd46df 100644 --- a/src/dashboard/components/RangeChooser.svelte +++ b/src/dashboard/components/RangeChooser.svelte @@ -29,7 +29,6 @@ } -
diff --git a/src/dashboard/pages/Dashboard.svelte b/src/dashboard/pages/Dashboard.svelte index e509e05..f3a6c0d 100644 --- a/src/dashboard/pages/Dashboard.svelte +++ b/src/dashboard/pages/Dashboard.svelte @@ -7,10 +7,11 @@ import { data, countInGroup } from '../../shared/lib' let top = 15 - let full = 50 + let full = 100 let loading = true let counted = [] + let table = [] let timeout let start @@ -37,13 +38,37 @@ timeout = setTimeout(calculate, 5) } + $: { + let lastHuman = null + table = counted.map((entry) => { + const same = lastHuman === entry.human + if (!same) lastHuman = entry.human + return { + ...entry, + same, + } + }) + } + onMount(calculate) -
+

Dashboard

@@ -52,16 +77,16 @@ {:else if counted}

Top {top}

-

Top {full}

+

Top {full}

- {#each counted.slice(0, 100) as { host, total, human }} + {#each table.slice(0, full) as { host, total, human, same }} - - + + {/each}
Time Spent Host
{human}{human}
diff --git a/src/options/App.svelte b/src/options/App.svelte index eec6179..7b87790 100644 --- a/src/options/App.svelte +++ b/src/options/App.svelte @@ -1,43 +1,85 @@ -
- + -
+
+ + +

Settings

+
- - + +
+ + +
+

Your Data

+
+ + + + +
diff --git a/src/options/FileUpload.svelte b/src/options/FileUpload.svelte new file mode 100644 index 0000000..8274309 --- /dev/null +++ b/src/options/FileUpload.svelte @@ -0,0 +1,47 @@ + + + + + diff --git a/src/shared/db.js b/src/shared/db.js index 46010b1..b733d6e 100644 --- a/src/shared/db.js +++ b/src/shared/db.js @@ -2,6 +2,7 @@ import dj from 'dayjs' import Dexie from 'dexie' import RelativeTime from 'dayjs/plugin/relativeTime' import Duration from 'dayjs/plugin/duration' +import Joi from 'joi' dj.extend(Duration) dj.extend(RelativeTime) @@ -29,3 +30,56 @@ export async function insertLog({ timestamp, host, seconds }) { data.seconds += seconds await DB.logs.put(data) } + +export async function clear() { + await DB.limits.clear() + await DB.logs.clear() +} + +export async function dump() { + return { + limits: await DB.limits.toArray(), + logs: await DB.logs.toArray(), + } +} + +export function validate(data) { + const schema = Joi.object({ + limits: Joi.array().items( + Joi.object({ + host: Joi.string(), + id: Joi.number(), + rules: Joi.array().items( + Joi.object({ + limit: Joi.array().items(Joi.string(), Joi.number()), + every: Joi.array().items(Joi.string(), Joi.number()), + }) + ), + }) + ), + logs: Joi.array().items( + Joi.object({ + host: Joi.string(), + id: Joi.number(), + seconds: Joi.number(), + timestamp: Joi.string(), + }) + ), + }) + + const validated = schema.validate(data, { presence: 'required' }) + return !validated.error +} + +export async function load(data) { + if (!validate(data)) throw new Error('Invalid data') + + await clear() + await DB.limits.bulkAdd(data.limits) + await DB.logs.bulkAdd( + data.logs.map((log) => ({ + ...log, + timestamp: new Date(log.timestamp), + })) + ) +} diff --git a/src/shared/index.html b/src/shared/index.html index 5db7542..4809202 100644 --- a/src/shared/index.html +++ b/src/shared/index.html @@ -3,7 +3,7 @@ - +