diff --git a/README.md b/README.md index 338e5af9..c47ff1ce 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,11 @@ Note: Activity from this Chrome extension will not display on leaderboards, so i 1. Install the extension: -[![Chrome Web Store](https://wakatime.com/static/img/chrome-web-store.png)](https://chrome.google.com/webstore/detail/wakatime/jnbbnacmeggbgdjgaoojpmhdlkkpblgi) +[![Chrome](https://wakatime.com/static/img/chrome-web-store.png)](https://chrome.google.com/webstore/detail/wakatime/jnbbnacmeggbgdjgaoojpmhdlkkpblgi) + +[![Firefox](https://wakatime.com/static/img/firefox-addon.png)](https://addons.mozilla.org/en-US/firefox/addon/wakatime/) + +[![Edge](https://wakatime.com/static/img/microsoft-extension.png)](https://microsoftedge.microsoft.com/addons/detail/wakatime/cdnpfnaadjmaplhghnlonephmabegadl) 2. Login to [WakaTime](https://wakatime.com/). diff --git a/src/background.ts b/src/background.ts index f652d34d..0eb455a7 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,5 +1,6 @@ import browser from 'webextension-polyfill'; import WakaTimeCore from './core/WakaTimeCore'; +import { PostHeartbeatMessage } from './types/heartbeats'; // Add a listener to resolve alarms browser.alarms.onAlarm.addListener(async (alarm) => { @@ -22,7 +23,7 @@ browser.alarms.create('heartbeatAlarm', { periodInMinutes: 2 }); * Whenever a active tab is changed it records a heartbeat with that tab url. */ browser.tabs.onActivated.addListener(async () => { - console.log('recording a heartbeat - active tab changed '); + console.log('recording a heartbeat - active tab changed'); await WakaTimeCore.recordHeartbeat(); }); @@ -62,6 +63,12 @@ self.addEventListener('activate', async () => { await WakaTimeCore.createDB(); }); +browser.runtime.onMessage.addListener(async (request: PostHeartbeatMessage) => { + if (request.recordHeartbeat === true) { + await WakaTimeCore.recordHeartbeat(request.projectDetails); + } +}); + /** * "Persistent" service worker via bug exploit * https://stackoverflow.com/questions/66618136/persistent-service-worker-in-chrome-extension diff --git a/src/components/Options.tsx b/src/components/Options.tsx index ec3c0312..e2d7e6fb 100644 --- a/src/components/Options.tsx +++ b/src/components/Options.tsx @@ -308,9 +308,9 @@ export default function Options(): JSX.Element { className="form-control" value={state.apiUrl} onChange={(e) => setState({ ...state, apiUrl: e.target.value })} - placeholder="https://wakatime.com/api/v1" + placeholder="https://api.wakatime.com/api/v1" /> - https://wakatime.com/api/v1 + https://api.wakatime.com/api/v1 diff --git a/src/config/config.test.ts b/src/config/config.test.ts index 7987e4b0..7d357eb5 100644 --- a/src/config/config.test.ts +++ b/src/config/config.test.ts @@ -25,7 +25,7 @@ describe('wakatime config', () => { }, }, "apiKey": "", - "apiUrl": "https://wakatime.com/api/v1", + "apiUrl": "https://api.wakatime.com/api/v1", "colors": { "allGood": "", "lightTheme": "white", diff --git a/src/config/config.ts b/src/config/config.ts index 1f24c91a..f10f19c5 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -120,7 +120,7 @@ const config: Config = { apiKey: '', - apiUrl: process.env.API_URL ?? 'https://wakatime.com/api/v1', + apiUrl: process.env.API_URL ?? 'https://api.wakatime.com/api/v1', colors: { allGood: '', diff --git a/src/core/WakaTimeCore.ts b/src/core/WakaTimeCore.ts index 321ad46a..1d699316 100644 --- a/src/core/WakaTimeCore.ts +++ b/src/core/WakaTimeCore.ts @@ -354,6 +354,7 @@ class WakaTimeCore { }; payload.project = heartbeat.project ?? '<>'; + payload.branch = heartbeat.branch ?? '<>'; return payload; } diff --git a/src/manifests/chrome.json b/src/manifests/chrome.json index 3d7d131b..58aad161 100644 --- a/src/manifests/chrome.json +++ b/src/manifests/chrome.json @@ -33,5 +33,5 @@ "page": "options.html" }, "permissions": ["alarms", "tabs", "storage", "idle"], - "version": "3.0.17" + "version": "3.0.21" } diff --git a/src/manifests/edge.json b/src/manifests/edge.json new file mode 100644 index 00000000..34ad2d9f --- /dev/null +++ b/src/manifests/edge.json @@ -0,0 +1,37 @@ +{ + "action": { + "default_icon": { + "19": "graphics/wakatime-logo-19.png", + "38": "graphics/wakatime-logo-38.png" + }, + "default_popup": "popup.html", + "default_title": "WakaTime" + }, + "background": { + "service_worker": "background.js", + "type": "module" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["wakatimeScript.js"], + "run_at": "document_end" + } + ], + "description": "Automatic time tracking for Edge.", + "devtools_page": "devtools.html", + "homepage_url": "https://wakatime.com", + "host_permissions": ["https://api.wakatime.com/*", "https://wakatime.com/*"], + "icons": { + "16": "graphics/wakatime-logo-16.png", + "48": "graphics/wakatime-logo-48.png", + "128": "graphics/wakatime-logo-128.png" + }, + "manifest_version": 3, + "name": "WakaTime", + "options_ui": { + "page": "options.html" + }, + "permissions": ["alarms", "tabs", "storage", "idle"], + "version": "3.0.21" +} diff --git a/src/manifests/firefox.json b/src/manifests/firefox.json index f3170357..30a57bb3 100644 --- a/src/manifests/firefox.json +++ b/src/manifests/firefox.json @@ -39,5 +39,5 @@ "page": "options.html" }, "permissions": ["", "alarms", "tabs", "storage", "idle"], - "version": "3.0.17" + "version": "3.0.21" } diff --git a/src/types/heartbeats.ts b/src/types/heartbeats.ts index f418e0d2..69734144 100644 --- a/src/types/heartbeats.ts +++ b/src/types/heartbeats.ts @@ -28,7 +28,20 @@ export interface Datum { } export interface SendHeartbeat { + branch: string | null; hostname: string; project: string | null; url: string; } + +export interface ProjectDetails { + category: string; + editor: string; + language: string; + project: string; +} + +export interface PostHeartbeatMessage { + projectDetails?: ProjectDetails; + recordHeartbeat: boolean; +} diff --git a/src/types/user.ts b/src/types/user.ts index c5edc51c..860e899e 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -25,10 +25,11 @@ export interface User { is_hireable: boolean; is_onboarding_finished: boolean; languages_used_public: boolean; + last_branch?: string; last_heartbeat_at: string; last_plugin: string; last_plugin_name: string; - last_project: string; + last_project?: string; location: string; logged_time_public: boolean; modified_at: string; diff --git a/src/wakatimeScript.ts b/src/wakatimeScript.ts index 028fec21..63649fbc 100644 --- a/src/wakatimeScript.ts +++ b/src/wakatimeScript.ts @@ -1,5 +1,3 @@ -import WakaTimeCore from './core/WakaTimeCore'; - const twoMinutes = 120000; interface DesignProject { @@ -10,13 +8,18 @@ interface DesignProject { } const parseCanva = (): DesignProject | undefined => { - const canvaProject = document.getElementsByClassName('rF765A'); - if (canvaProject.length === 0) return; - const projectName = (document.head.querySelector('meta[property="og:title"]') as HTMLMetaElement) .content; + if (!projectName) return; + + // make sure the page title matches the design input element's value, meaning this is a design file + const canvaProjectInput = Array.from( + document.querySelector('nav')?.querySelectorAll('input') ?? [], + ).find((inp) => inp.value === projectName); + if (!canvaProjectInput) return; + return { - category: 'Designing', + category: 'designing', editor: 'Canva', language: 'Canva Design', project: projectName, @@ -30,7 +33,7 @@ const parseFigma = (): DesignProject | undefined => { const projectName = (document.querySelector('span[data-testid="filename"]') as HTMLElement) .innerText; return { - category: 'Designing', + category: 'designing', editor: 'Figma', language: 'Figma Design', project: projectName, @@ -50,9 +53,8 @@ const init = async () => { const { hostname } = document.location; const projectDetails = getParser[hostname]?.(); - if (projectDetails) { - await WakaTimeCore.recordHeartbeat(projectDetails); + chrome.runtime.sendMessage({ projectDetails, recordHeartbeat: true }); } }; diff --git a/webpack.config.ts b/webpack.config.ts index 42f180dc..51a99e07 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -4,7 +4,7 @@ import * as webpack from 'webpack'; // eslint-disable-next-line import CopyPlugin from 'copy-webpack-plugin'; -type BrowserTypes = 'chrome' | 'firefox'; +type BrowserTypes = 'chrome' | 'firefox' | 'edge'; const publicFolder = join(__dirname, 'public'); const cssFolder = join(publicFolder, 'css'); @@ -75,5 +75,9 @@ export default ( arv: Record, ): webpack.Configuration[] => { const isProd = arv.mode !== 'development'; - return [getConfigByBrowser(isProd, 'chrome'), getConfigByBrowser(isProd, 'firefox')]; + return [ + getConfigByBrowser(isProd, 'chrome'), + getConfigByBrowser(isProd, 'firefox'), + getConfigByBrowser(isProd, 'edge'), + ]; };