Merge pull request #156 from wakatime/sebas-enable-disable-logging

chore: enable disable logging
This commit is contained in:
Juan Sebastian velez Posada
2023-01-18 07:18:24 -05:00
committed by GitHub
11 changed files with 121 additions and 113 deletions

95
package-lock.json generated
View File

@@ -20,7 +20,7 @@
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"react-transition-group": "^4.4.5", "react-transition-group": "^4.4.5",
"redux-logger": "^4.0.0", "redux-logger": "^4.0.0",
"webextension-polyfill-ts": "^0.26.0" "webextension-polyfill": "^0.10.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.8.7", "@babel/core": "^7.8.7",
@@ -44,7 +44,9 @@
"@types/redux-logger": "^3.0.9", "@types/redux-logger": "^3.0.9",
"@types/remote-redux-devtools": "^0.5.4", "@types/remote-redux-devtools": "^0.5.4",
"@types/shelljs": "^0.8.8", "@types/shelljs": "^0.8.8",
"@types/sinon-chrome": "^2.2.11",
"@types/wait-on": "^5.2.0", "@types/wait-on": "^5.2.0",
"@types/webextension-polyfill": "^0.10.0",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0", "@typescript-eslint/parser": "^4.33.0",
"@xarc/run": "^1.0.4", "@xarc/run": "^1.0.4",
@@ -3948,6 +3950,31 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/sinon": {
"version": "10.0.13",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
"integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==",
"dev": true,
"dependencies": {
"@types/sinonjs__fake-timers": "*"
}
},
"node_modules/@types/sinon-chrome": {
"version": "2.2.11",
"resolved": "https://registry.npmjs.org/@types/sinon-chrome/-/sinon-chrome-2.2.11.tgz",
"integrity": "sha512-hmpjlIDwIi8LLYdzZMh9+oj6k4mM7hD3dEC2a5vzYbNvIEIqDLxED8WhfroqLzLHLYV3ni5N1fLOEF0fmaFpqA==",
"dev": true,
"dependencies": {
"@types/chrome": "*",
"@types/sinon": "*"
}
},
"node_modules/@types/sinonjs__fake-timers": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz",
"integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==",
"dev": true
},
"node_modules/@types/sizzle": { "node_modules/@types/sizzle": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
@@ -3989,6 +4016,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/webextension-polyfill": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz",
"integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==",
"dev": true
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "17.0.19", "version": "17.0.19",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz",
@@ -22619,18 +22652,9 @@
} }
}, },
"node_modules/webextension-polyfill": { "node_modules/webextension-polyfill": {
"version": "0.8.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz",
"integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g=="
},
"node_modules/webextension-polyfill-ts": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/webextension-polyfill-ts/-/webextension-polyfill-ts-0.26.0.tgz",
"integrity": "sha512-XEFL+aYVEsm/d4RajVwP75g56c/w2aSHnPwgtUv8/nCzbLNSzRQIix6aj1xqFkA5yr7OIDkk3OD/QTnPp8ThYA==",
"deprecated": "This project has moved to @types/webextension-polyfill",
"dependencies": {
"webextension-polyfill": "^0.8.0"
}
}, },
"node_modules/webidl-conversions": { "node_modules/webidl-conversions": {
"version": "7.0.0", "version": "7.0.0",
@@ -26286,6 +26310,31 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/sinon": {
"version": "10.0.13",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
"integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==",
"dev": true,
"requires": {
"@types/sinonjs__fake-timers": "*"
}
},
"@types/sinon-chrome": {
"version": "2.2.11",
"resolved": "https://registry.npmjs.org/@types/sinon-chrome/-/sinon-chrome-2.2.11.tgz",
"integrity": "sha512-hmpjlIDwIi8LLYdzZMh9+oj6k4mM7hD3dEC2a5vzYbNvIEIqDLxED8WhfroqLzLHLYV3ni5N1fLOEF0fmaFpqA==",
"dev": true,
"requires": {
"@types/chrome": "*",
"@types/sinon": "*"
}
},
"@types/sinonjs__fake-timers": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz",
"integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==",
"dev": true
},
"@types/sizzle": { "@types/sizzle": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
@@ -26327,6 +26376,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/webextension-polyfill": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz",
"integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==",
"dev": true
},
"@types/yargs": { "@types/yargs": {
"version": "17.0.19", "version": "17.0.19",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz",
@@ -40480,17 +40535,9 @@
"dev": true "dev": true
}, },
"webextension-polyfill": { "webextension-polyfill": {
"version": "0.8.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz",
"integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g=="
},
"webextension-polyfill-ts": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/webextension-polyfill-ts/-/webextension-polyfill-ts-0.26.0.tgz",
"integrity": "sha512-XEFL+aYVEsm/d4RajVwP75g56c/w2aSHnPwgtUv8/nCzbLNSzRQIix6aj1xqFkA5yr7OIDkk3OD/QTnPp8ThYA==",
"requires": {
"webextension-polyfill": "^0.8.0"
}
}, },
"webidl-conversions": { "webidl-conversions": {
"version": "7.0.0", "version": "7.0.0",

View File

@@ -40,7 +40,7 @@
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"react-transition-group": "^4.4.5", "react-transition-group": "^4.4.5",
"redux-logger": "^4.0.0", "redux-logger": "^4.0.0",
"webextension-polyfill-ts": "^0.26.0" "webextension-polyfill": "^0.10.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.8.7", "@babel/core": "^7.8.7",
@@ -64,7 +64,9 @@
"@types/redux-logger": "^3.0.9", "@types/redux-logger": "^3.0.9",
"@types/remote-redux-devtools": "^0.5.4", "@types/remote-redux-devtools": "^0.5.4",
"@types/shelljs": "^0.8.8", "@types/shelljs": "^0.8.8",
"@types/sinon-chrome": "^2.2.11",
"@types/wait-on": "^5.2.0", "@types/wait-on": "^5.2.0",
"@types/webextension-polyfill": "^0.10.0",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0", "@typescript-eslint/parser": "^4.33.0",
"@xarc/run": "^1.0.4", "@xarc/run": "^1.0.4",

View File

@@ -1,4 +1,11 @@
import '@testing-library/jest-dom/extend-expect'; import '@testing-library/jest-dom/extend-expect';
import chrome from 'sinon-chrome';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
window.chrome = chrome;
chrome.runtime.id = 'testid'; // https://github.com/mozilla/webextension-polyfill/issues/218#issuecomment-584936358
class BrowserMock { class BrowserMock {
runtime = { runtime = {

View File

@@ -2,29 +2,16 @@ import React from 'react';
import { renderWithProviders } from '../utils/test-utils'; import { renderWithProviders } from '../utils/test-utils';
import MainList from './MainList'; import MainList from './MainList';
type onClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
describe('MainList', () => { describe('MainList', () => {
let disableLogging: onClick;
let enableLogging: onClick;
let loggingEnabled: boolean; let loggingEnabled: boolean;
let logoutUser: onClick;
let totalTimeLoggedToday: string; let totalTimeLoggedToday: string;
beforeEach(() => { beforeEach(() => {
disableLogging = jest.fn();
enableLogging = jest.fn();
loggingEnabled = false; loggingEnabled = false;
logoutUser = jest.fn();
totalTimeLoggedToday = '1/1/1999'; totalTimeLoggedToday = '1/1/1999';
}); });
it('should render properly', () => { it('should render properly', () => {
const { container } = renderWithProviders( const { container } = renderWithProviders(
<MainList <MainList loggingEnabled={loggingEnabled} totalTimeLoggedToday={totalTimeLoggedToday} />,
disableLogging={disableLogging}
enableLogging={enableLogging}
loggingEnabled={loggingEnabled}
logoutUser={logoutUser}
totalTimeLoggedToday={totalTimeLoggedToday}
/>,
); );
expect(container).toMatchInlineSnapshot(` expect(container).toMatchInlineSnapshot(`
<div> <div>

View File

@@ -1,13 +1,13 @@
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import changeExtensionState from '../utils/changeExtensionState';
import { configLogout, setLoggingEnabled } from '../reducers/configReducer';
import { userLogout } from '../reducers/currentUser';
import { ReduxSelector } from '../types/store'; import { ReduxSelector } from '../types/store';
import { User } from '../types/user'; import { User } from '../types/user';
export interface MainListProps { export interface MainListProps {
disableLogging: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
enableLogging: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
loggingEnabled: boolean; loggingEnabled: boolean;
logoutUser: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
totalTimeLoggedToday?: string; totalTimeLoggedToday?: string;
} }
const openOptionsPage = async (): Promise<void> => { const openOptionsPage = async (): Promise<void> => {
@@ -15,16 +15,34 @@ const openOptionsPage = async (): Promise<void> => {
}; };
export default function MainList({ export default function MainList({
disableLogging,
enableLogging,
loggingEnabled, loggingEnabled,
logoutUser,
totalTimeLoggedToday, totalTimeLoggedToday,
}: MainListProps): JSX.Element { }: MainListProps): JSX.Element {
const dispatch = useDispatch();
const user: User | undefined = useSelector( const user: User | undefined = useSelector(
(selector: ReduxSelector) => selector.currentUser.user, (selector: ReduxSelector) => selector.currentUser.user,
); );
const logoutUser = async (): Promise<void> => {
await browser.storage.sync.set({ apiKey: '' });
dispatch(configLogout());
dispatch(userLogout());
await changeExtensionState('notSignedIn');
};
const enableLogging = async (): Promise<void> => {
dispatch(setLoggingEnabled(true));
await browser.storage.sync.set({ loggingEnabled: true });
await changeExtensionState('allGood');
};
const disableLogging = async (): Promise<void> => {
dispatch(setLoggingEnabled(false));
await browser.storage.sync.set({ loggingEnabled: false });
await changeExtensionState('notLogging');
};
return ( return (
<div> <div>
{user && ( {user && (

View File

@@ -2,9 +2,8 @@ import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { configLogout, setApiKey } from '../reducers/configReducer'; import { configLogout, setApiKey } from '../reducers/configReducer';
import { userLogout } from '../reducers/currentUser'; import { userLogout } from '../reducers/currentUser';
import { ReduxSelector } from '../types/store'; import { ApiKeyReducer, ReduxSelector } from '../types/store';
import { User } from '../types/user'; import { User } from '../types/user';
import config from '../config/config';
import apiKeyInvalid from '../utils/apiKey'; import apiKeyInvalid from '../utils/apiKey';
import { fetchUserData } from '../utils/user'; import { fetchUserData } from '../utils/user';
@@ -14,20 +13,20 @@ export default function NavBar(): JSX.Element {
apiKeyError: '', apiKeyError: '',
loading: false, loading: false,
}); });
useEffect(() => {
const fetch = async () => {
const { apiKey } = await browser.storage.sync.get({ apiKey: config.apiKey });
setState({ ...state, apiKey });
};
fetch();
}, []);
const dispatch = useDispatch(); const dispatch = useDispatch();
const { apiKey: apiKeyFromRedux }: ApiKeyReducer = useSelector(
(selector: ReduxSelector) => selector.config,
);
const user: User | undefined = useSelector( const user: User | undefined = useSelector(
(selector: ReduxSelector) => selector.currentUser.user, (selector: ReduxSelector) => selector.currentUser.user,
); );
useEffect(() => {
setState({ ...state, apiKey: apiKeyFromRedux });
}, [apiKeyFromRedux]);
const signedInAs = () => { const signedInAs = () => {
if (user) { if (user) {
return ( return (

View File

@@ -1,20 +1,13 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { ApiKeyReducer, ReduxSelector } from '../types/store'; import { ApiKeyReducer, ReduxSelector } from '../types/store';
import config from '../config/config';
import { fetchUserData } from '../utils/user'; import { fetchUserData } from '../utils/user';
import changeExtensionState from '../utils/changeExtensionState';
import NavBar from './NavBar'; import NavBar from './NavBar';
import MainList from './MainList'; import MainList from './MainList';
export default function WakaTime(): JSX.Element { export default function WakaTime(): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
const defaultState = {
loggingEnabled: config.loggingEnabled,
totalTimeLoggedToday: '0 minutes',
};
const [state, setState] = useState(defaultState);
const { const {
apiKey: apiKeyFromRedux, apiKey: apiKeyFromRedux,
loggingEnabled, loggingEnabled,
@@ -25,53 +18,13 @@ export default function WakaTime(): JSX.Element {
fetchUserData(apiKeyFromRedux, dispatch); fetchUserData(apiKeyFromRedux, dispatch);
}, []); }, []);
const disableLogging = async () => {
setState({
...state,
loggingEnabled: false,
});
await changeExtensionState('notLogging');
await browser.storage.sync.set({
loggingEnabled: false,
});
};
const enableLogging = async () => {
setState({
...state,
loggingEnabled: true,
});
await changeExtensionState('allGood');
await browser.storage.sync.set({
loggingEnabled: true,
});
};
const logoutUser = async () => {
await browser.storage.sync.set({ apiKey: '' });
setState(defaultState);
await changeExtensionState('notSignedIn');
};
return ( return (
<div> <div>
<NavBar /> <NavBar />
<div className="container"> <div className="container">
<div className="row"> <div className="row">
<div className="col-md-12"> <div className="col-md-12">
<MainList <MainList loggingEnabled={loggingEnabled} totalTimeLoggedToday={totalTimeLoggedToday} />
disableLogging={disableLogging}
enableLogging={enableLogging}
loggingEnabled={loggingEnabled}
totalTimeLoggedToday={totalTimeLoggedToday}
logoutUser={logoutUser}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'; import axios, { AxiosResponse } from 'axios';
import moment from 'moment'; import moment from 'moment';
import { Tabs } from 'webextension-polyfill-ts'; import { Tabs } from 'webextension-polyfill';
import { AxiosUserResponse, User } from '../types/user'; import { AxiosUserResponse, User } from '../types/user';
import config from '../config/config'; import config from '../config/config';
import { SummariesPayload, GrandTotal } from '../types/summaries'; import { SummariesPayload, GrandTotal } from '../types/summaries';

View File

@@ -14,13 +14,8 @@ const root = createRoot(container!);
const store = createStore('WakaTime-Options'); const store = createStore('WakaTime-Options');
checkCurrentUser(store)(30 * 1000); checkCurrentUser(store)(30 * 1000);
const openOptions = async (): Promise<void> => {
await browser.runtime.openOptionsPage();
};
root.render( root.render(
<Provider store={store}> <Provider store={store}>
<WakaTime /> <WakaTime />
<div onClick={openOptions}>Open options</div>
</Provider>, </Provider>,
); );

View File

@@ -1,4 +1,4 @@
import { browser } from 'webextension-polyfill-ts'; import browser from 'webextension-polyfill';
import config from '../config/config'; import config from '../config/config';
type ColorIconTypes = 'gray' | 'red' | 'white' | ''; type ColorIconTypes = 'gray' | 'red' | 'white' | '';

View File

@@ -1,4 +1,4 @@
import { browser } from 'webextension-polyfill-ts'; import browser from 'webextension-polyfill';
import config from '../config/config'; import config from '../config/config';
/** /**