Es6 cmp migration (#113)

* migrate Alert component

* convert Mainlist component

* add webpack watch task

* update build script for different manifests

* add types for api responses

* convert changeExtensionIcon

* convert inArray, getDomainParts, contains to ts

* convert changeExtensionTooltip

* convert changeExtensionState to ts
This commit is contained in:
Vu Nguyen
2021-01-16 19:31:52 -06:00
committed by GitHub
parent 9ecc2144aa
commit d194bcfe60
21 changed files with 660 additions and 10 deletions

View File

@@ -13,6 +13,8 @@ module.exports = {
'kentcdodds/import', 'kentcdodds/import',
'kentcdodds/jest', 'kentcdodds/jest',
'kentcdodds/possible-errors', 'kentcdodds/possible-errors',
'plugin:jest-dom/recommended',
'plugin:testing-library/recommended',
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'plugin:import/errors', 'plugin:import/errors',
'plugin:import/typescript', 'plugin:import/typescript',

165
package-lock.json generated
View File

@@ -5897,6 +5897,144 @@
} }
} }
}, },
"@testing-library/jest-dom": {
"version": "5.11.9",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz",
"integrity": "sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.9.2",
"@types/testing-library__jest-dom": "^5.9.1",
"aria-query": "^4.2.2",
"chalk": "^3.0.0",
"css": "^3.0.0",
"css.escape": "^1.5.1",
"lodash": "^4.17.15",
"redent": "^3.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"css": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
"integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==",
"dev": true,
"requires": {
"inherits": "^2.0.4",
"source-map": "^0.6.1",
"source-map-resolve": "^0.6.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true
},
"redent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
"dev": true,
"requires": {
"indent-string": "^4.0.0",
"strip-indent": "^3.0.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-resolve": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
"integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
"dev": true,
"requires": {
"atob": "^2.1.2",
"decode-uri-component": "^0.2.0"
}
},
"strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"dev": true,
"requires": {
"min-indent": "^1.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"@testing-library/react": {
"version": "11.2.3",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.3.tgz",
"integrity": "sha512-BirBUGPkTW28ULuCwIbYo0y2+0aavHczBT6N9r3LrsswEW3pg25l1wgoE7I8QBIy1upXWkwKpYdWY7NYYP0Bxw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.12.5",
"@testing-library/dom": "^7.28.1"
}
},
"@testing-library/user-event": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.6.0.tgz",
"integrity": "sha512-FNEH/HLmOk5GO70I52tKjs7WvGYckeE/SrnLX/ip7z2IGbffyd5zOUM1tZ10vsTphqm+VbDFI0oaXu0wcfQsAQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.12.5"
}
},
"@types/anymatch": { "@types/anymatch": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
@@ -5960,6 +6098,12 @@
"@types/har-format": "*" "@types/har-format": "*"
} }
}, },
"@types/classnames": {
"version": "2.2.11",
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz",
"integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw==",
"dev": true
},
"@types/copy-webpack-plugin": { "@types/copy-webpack-plugin": {
"version": "6.4.0", "version": "6.4.0",
"resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-6.4.0.tgz", "resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-6.4.0.tgz",
@@ -6278,6 +6422,15 @@
"integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
"dev": true "dev": true
}, },
"@types/testing-library__jest-dom": {
"version": "5.9.5",
"resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz",
"integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==",
"dev": true,
"requires": {
"@types/jest": "*"
}
},
"@types/uglify-js": { "@types/uglify-js": {
"version": "3.11.1", "version": "3.11.1",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz",
@@ -10645,6 +10798,12 @@
} }
} }
}, },
"css.escape": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
"integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=",
"dev": true
},
"cssom": { "cssom": {
"version": "0.4.4", "version": "0.4.4",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
@@ -20413,6 +20572,12 @@
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true "dev": true
}, },
"min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true
},
"minimalistic-assert": { "minimalistic-assert": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",

View File

@@ -38,7 +38,12 @@
"webextension-polyfill-ts": "^0.22.0" "webextension-polyfill-ts": "^0.22.0"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/dom": "^7.29.4",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.3",
"@testing-library/user-event": "^12.6.0",
"@types/chrome": "0.0.128", "@types/chrome": "0.0.128",
"@types/classnames": "^2.2.11",
"@types/copy-webpack-plugin": "^6.4.0", "@types/copy-webpack-plugin": "^6.4.0",
"@types/firefox-webext-browser": "^82.0.0", "@types/firefox-webext-browser": "^82.0.0",
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",
@@ -60,9 +65,11 @@
"eslint-config-kentcdodds": "^17.3.0", "eslint-config-kentcdodds": "^17.3.0",
"eslint-config-prettier": "^7.1.0", "eslint-config-prettier": "^7.1.0",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest-dom": "^3.6.5",
"eslint-plugin-prettier": "^3.3.1", "eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-react": "^7.22.0", "eslint-plugin-react": "^7.22.0",
"eslint-plugin-sort-keys-fix": "^1.1.1", "eslint-plugin-sort-keys-fix": "^1.1.1",
"eslint-plugin-testing-library": "^3.10.1",
"eslint-plugin-typescript-sort-keys": "^1.5.0", "eslint-plugin-typescript-sort-keys": "^1.5.0",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"husky": "^4.3.7", "husky": "^4.3.7",

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import Alert from './Alert';
describe('Alert Component', () => {
it('should render with proper text on success type', () => {
const text = 'Test Text';
const { container } = render(<Alert text={text} type="success" />);
expect(screen.getByText(text)).toBeTruthy();
expect(container).toMatchInlineSnapshot(`
<div>
<div
class="alert alert-success"
>
Test Text
</div>
</div>
`);
});
it('should render wtih proper text on danger type', () => {
const text = 'Test Text';
const { container } = render(<Alert text={text} type="danger" />);
expect(screen.getByText(text)).toBeTruthy();
expect(container).toMatchInlineSnapshot(`
<div>
<div
class="alert alert-danger"
>
Test Text
</div>
</div>
`);
});
});

11
src/components/Alert.tsx Normal file
View File

@@ -0,0 +1,11 @@
import React from 'react';
import classNames from 'classnames';
import { SuccessOrFailType } from '../config';
interface AlertProps {
text: string;
type: SuccessOrFailType;
}
export default function Alert({ type, text }: AlertProps): JSX.Element {
return <div className={classNames('alert', `alert-${type}`)}>{text}</div>;
}

View File

@@ -0,0 +1,63 @@
import React from 'react';
import { render } from '@testing-library/react';
import MainList from './MainList';
type onClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
describe('MainList', () => {
let disableLogging: onClick;
let enableLogging: onClick;
let loggedIn: boolean;
let loggingEnabled: boolean;
let logoutUser: onClick;
let totalTimeLoggedToday: string;
beforeEach(() => {
disableLogging = jest.fn();
enableLogging = jest.fn();
loggingEnabled = false;
loggedIn = false;
logoutUser = jest.fn();
totalTimeLoggedToday = '1/1/1999';
});
it('should render properly', () => {
const { container } = render(
<MainList
disableLogging={disableLogging}
enableLogging={enableLogging}
loggingEnabled={loggingEnabled}
loggedIn={loggedIn}
logoutUser={logoutUser}
totalTimeLoggedToday={totalTimeLoggedToday}
/>,
);
expect(container).toMatchInlineSnapshot(`
<div>
<div>
<div
class="list-group"
>
<a
class="list-group-item"
href="#"
>
<i
class="fa fa-fw fa-cogs"
/>
Options
</a>
<a
class="list-group-item"
href="https://wakatime.com/login"
rel="noreferrer"
target="_blank"
>
<i
class="fa fa-fw fa-sign-in"
/>
Login
</a>
</div>
</div>
</div>
`);
});
});

View File

@@ -0,0 +1,87 @@
import React from 'react';
import { browser } from 'webextension-polyfill-ts';
export interface MainListProps {
disableLogging: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
enableLogging: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
loggedIn: boolean;
loggingEnabled: boolean;
logoutUser: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
totalTimeLoggedToday?: string;
}
const openOptionsPage = async (): Promise<void> => {
await browser.runtime.openOptionsPage();
};
export default function MainList({
disableLogging,
enableLogging,
loggedIn,
loggingEnabled,
logoutUser,
totalTimeLoggedToday,
}: MainListProps): JSX.Element {
return (
<div>
{loggedIn && (
<div className="row">
<div className="col-xs-12">
<blockquote>
<p>{totalTimeLoggedToday}</p>
<small>
<cite>TOTAL TIME LOGGED TODAY</cite>
</small>
</blockquote>
</div>
</div>
)}
{loggingEnabled && loggedIn && (
<div className="row">
<div className="col-xs-12">
<p>
<a href="#" onClick={disableLogging} className="btn btn-danger btn-block">
Disable logging
</a>
</p>
</div>
</div>
)}
{!loggingEnabled && loggedIn && (
<div className="row">
<div className="col-xs-12">
<p>
<a href="#" onClick={enableLogging} className="btn btn-success btn-block">
Enable logging
</a>
</p>
</div>
</div>
)}
<div className="list-group">
<a href="#" className="list-group-item" onClick={openOptionsPage}>
<i className="fa fa-fw fa-cogs"></i>
Options
</a>
{loggedIn && (
<div>
<a href="#" className="list-group-item" onClick={logoutUser}>
<i className="fa fa-fw fa-sign-out"></i>
Logout
</a>
</div>
)}
{!loggedIn && (
<a
target="_blank"
rel="noreferrer"
href="https://wakatime.com/login"
className="list-group-item"
>
<i className="fa fa-fw fa-sign-in"></i>
Login
</a>
)}
</div>
</div>
);
}

View File

@@ -3,16 +3,16 @@ import { browser } from 'webextension-polyfill-ts';
/** /**
* Logging * Logging
*/ */
type ApiStates = 'allGood' | 'notLogging' | 'notSignedIn' | 'blacklisted' | 'whitelisted'; export type ApiStates = 'allGood' | 'notLogging' | 'notSignedIn' | 'blacklisted' | 'whitelisted';
/** /**
* Supported logging style * Supported logging style
*/ */
type LoggingStyle = 'whitelist' | 'blacklist'; export type LoggingStyle = 'whitelist' | 'blacklist';
/** /**
* Logging type * Logging type
*/ */
type LoggingType = 'domain' | 'url'; export type LoggingType = 'domain' | 'url';
type SuccessOrFailType = 'success' | 'danger'; export type SuccessOrFailType = 'success' | 'danger';
/** /**
* Predefined alert type and text for success and failure. * Predefined alert type and text for success and failure.
*/ */
@@ -31,10 +31,10 @@ interface SuccessOrFailAlert {
* Different colors for different states of the extension * Different colors for different states of the extension
*/ */
interface Colors { interface Colors {
allGood: string; allGood: '';
lightTheme: string; lightTheme: 'white';
notLogging: string; notLogging: 'gray';
notSignedIn: string; notSignedIn: 'red';
} }
/** /**
* Tooltip messages * Tooltip messages

38
src/manifests/chrome.json Normal file
View File

@@ -0,0 +1,38 @@
{
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": {
"19": "graphics/wakatime-logo-19.png",
"38": "graphics/wakatime-logo-38.png"
},
"default_popup": "popup.html",
"default_title": "WakaTime"
},
"browser_specific_settings": {},
"description": "Automatic time tracking for Chrome.",
"devtools_page": "devtools.html",
"homepage_url": "https://wakatime.com",
"icons": {
"16": "graphics/wakatime-logo-16.png",
"48": "graphics/wakatime-logo-48.png",
"128": "graphics/wakatime-logo-128.png"
},
"manifest_version": 2,
"name": "WakaTime",
"options_ui": {
"chrome_style": false,
"page": "options.html"
},
"permissions": [
"https://api.wakatime.com/*",
"https://wakatime.com/*",
"alarms",
"tabs",
"storage",
"idle"
],
"version": "2.0.1"
}

28
src/types/heartbeats.d.ts vendored Normal file
View File

@@ -0,0 +1,28 @@
// Generated by https://quicktype.io
export interface HeartBeatsPayload {
data: Datum[];
end: string;
start: string;
timezone: string;
}
export interface Datum {
branch: string;
category: string;
created_at: string;
cursorpos: null;
dependencies: string;
entity: string;
id: string;
is_write: boolean;
language: string;
lineno: null;
lines: number;
machine_name_id: string;
project: string;
time: number;
type: string;
user_agent_id: string;
user_id: string;
}

47
src/types/summaries.d.ts vendored Normal file
View File

@@ -0,0 +1,47 @@
// Generated by https://quicktype.io
export interface SummariesPayload {
data: Datum[];
end: string;
start: string;
}
export interface Datum {
categories: Category[];
dependencies: Category[];
editors: Category[];
grand_total: GrandTotal;
languages: Category[];
machines: Category[];
operating_systems: Category[];
projects: Category[];
range: Range;
}
export interface Category {
digital: string;
hours: number;
machine_name_id?: string;
minutes: number;
name: string;
percent: number;
seconds: number;
text: string;
total_seconds: number;
}
export interface GrandTotal {
digital: string;
hours: number;
minutes: number;
text: string;
total_seconds: number;
}
export interface Range {
date: string;
end: string;
start: string;
text: string;
timezone: string;
}

44
src/types/user.d.ts vendored Normal file
View File

@@ -0,0 +1,44 @@
// Generated by https://quicktype.io
export interface UserPayload {
data: User;
}
export interface User {
bio: null;
color_scheme: string;
created_at: string;
date_format: string;
default_dashboard_range: string;
display_name: string;
email: string;
full_name: string;
has_premium_features: boolean;
human_readable_website: string;
id: string;
is_email_confirmed: boolean;
is_email_public: boolean;
is_hireable: boolean;
is_onboarding_finished: boolean;
languages_used_public: boolean;
last_heartbeat_at: string;
last_plugin: string;
last_plugin_name: string;
last_project: string;
location: string;
logged_time_public: boolean;
modified_at: string;
needs_payment_method: boolean;
photo: string;
photo_public: boolean;
plan: string;
public_email: string;
show_machine_name_ip: boolean;
time_format_24hr: boolean;
timeout: number;
timezone: string;
username: string;
website: string;
weekday_start: number;
writes_only: boolean;
}

View File

@@ -0,0 +1,28 @@
import { browser } from 'webextension-polyfill-ts';
import config from '../config';
type ColorIconTypes = 'gray' | 'red' | 'white' | '';
/**
* It changes the extension icon color.
*/
export default async function changeExtensionIcon(color?: ColorIconTypes): Promise<void> {
if (color) {
const path = `./graphics/wakatime-logo-38-${color}.png`;
await browser.browserAction.setIcon({
path: path,
});
} else {
const { theme } = await browser.storage.sync.get({
theme: config.theme,
});
const path =
theme === config.theme
? './graphics/wakatime-logo-38.png'
: './graphics/wakatime-logo-38-white.png';
await browser.browserAction.setIcon({
path: path,
});
}
}

View File

@@ -0,0 +1,34 @@
import config, { ApiStates } from '../config';
import changeExtensionIcon from './changeExtensionIcon';
import changeExtensionTooltip from './changeExtensionTooltip';
/**
* Sets the current state of the extension.
*/
export default async function changeExtensionState(state: ApiStates): Promise<void> {
switch (state) {
case 'allGood':
await changeExtensionIcon(config.colors.allGood);
await changeExtensionTooltip(config.tooltips.allGood);
break;
case 'notLogging':
await changeExtensionIcon(config.colors.notLogging);
await changeExtensionTooltip(config.tooltips.notLogging);
break;
case 'notSignedIn':
await changeExtensionIcon(config.colors.notSignedIn);
await changeExtensionTooltip(config.tooltips.notSignedIn);
break;
case 'blacklisted':
await changeExtensionIcon(config.colors.notLogging);
await changeExtensionTooltip(config.tooltips.blacklisted);
break;
case 'whitelisted':
await changeExtensionIcon(config.colors.notLogging);
await changeExtensionTooltip(config.tooltips.whitelisted);
break;
default:
break;
}
}

View File

@@ -0,0 +1,16 @@
import { browser } from 'webextension-polyfill-ts';
import config from '../config';
/**
* It changes the extension title
*
*/
export default async function changeExtensionTooltip(text: string): Promise<void> {
if (text === '') {
text = config.name;
} else {
text = `${config.name} - ${text}`;
}
await browser.browserAction.setTitle({ title: text });
}

24
src/utils/contains.ts Normal file
View File

@@ -0,0 +1,24 @@
/**
* Creates an array from list using \n as delimiter
* and checks if any element in list is contained in the url.
*/
export default function contains(url: string, list: string): boolean {
const lines = list.split('\n');
for (let i = 0; i < lines.length; i++) {
// Trim all lines from the list one by one
const cleanLine = lines[i].trim();
// If by any chance one line in the list is empty, ignore it
if (cleanLine === '') continue;
const lineRe = new RegExp(cleanLine.replace('.', '.').replace('*', '.*'));
// If url matches the current line return true
if (lineRe.test(url)) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,8 @@
/**
* Returns domain from given URL.
*/
export function getDomainFromUrl(url: string): string {
const parts = url.split('/');
return parts[0] + '//' + parts[2];
}

12
src/utils/inArray.ts Normal file
View File

@@ -0,0 +1,12 @@
/**
* Returns boolean if needle is found in haystack or not.
*/
export function in_array<T>(needle: T, haystack: T[]): boolean {
for (let i = 0; i < haystack.length; i++) {
if (needle == haystack[i]) {
return true;
}
}
return false;
}

View File

@@ -12,7 +12,7 @@ const fontFolder = join(publicFolder, 'fonts');
const graphicsFolder = join(__dirname, 'graphics'); const graphicsFolder = join(__dirname, 'graphics');
const srcFolder = join(__dirname, 'src'); const srcFolder = join(__dirname, 'src');
const htmlFolder = join(srcFolder, 'html'); const htmlFolder = join(srcFolder, 'html');
const manifestFile = join(__dirname, 'manifest.json'); const manifestFolder = join(srcFolder, 'manifests');
const getConfigByBrowser = (isProd: boolean, browser: BrowserTypes): webpack.Configuration => { const getConfigByBrowser = (isProd: boolean, browser: BrowserTypes): webpack.Configuration => {
const cfg: webpack.Configuration = { const cfg: webpack.Configuration = {
@@ -43,7 +43,7 @@ const getConfigByBrowser = (isProd: boolean, browser: BrowserTypes): webpack.Con
{ from: graphicsFolder, to: 'graphics' }, { from: graphicsFolder, to: 'graphics' },
{ from: htmlFolder }, { from: htmlFolder },
// TODO: Create a mechanism to have a firefox manifest vs chrome // TODO: Create a mechanism to have a firefox manifest vs chrome
{ from: manifestFile }, { from: join(manifestFolder, `${browser}.json`), to: 'manifest.json' },
], ],
}), }),
], ],

View File

@@ -41,6 +41,8 @@ load({
'test-jest': [exec('jest --clearCache'), exec('jest --verbose --coverage')], 'test-jest': [exec('jest --clearCache'), exec('jest --verbose --coverage')],
'test-jest-update': exec('jest -u'), 'test-jest-update': exec('jest -u'),
'test-js': 'phantomjs tests/run.js', 'test-js': 'phantomjs tests/run.js',
'watch-jest': exec('jest --watch'),
webpack: [exec('webpack --mode production')], webpack: [exec('webpack --mode production')],
'webpack:dev': [exec('webpack --mode development')], 'webpack:dev': [exec('webpack --mode development')],
'webpack:watch': exec('webpack --mode development --watch'),
}); });