('#files', 'mouseover', setCurrentViewFileCheckbox);
16 |
17 | await elementReady('[data-hotkey="v"]');
18 |
19 | const vHotKeyEl = document.querySelector('[data-hotkey="v"]');
20 |
21 | if (vHotKeyEl) {
22 | vHotKeyEl.removeAttribute('data-hotkey');
23 | console.debug('Removed V key binding from "Review Changes" box');
24 | }
25 | }
26 |
27 | function isVKeyPressedInBody(event: KeyboardEvent): boolean {
28 | const isKeypressInBody = event.target['tagName'] === 'BODY';
29 | const isKeypressV = event.code === 'KeyV';
30 |
31 | console.debug({isKeypressInBody, isKeypressV});
32 |
33 | return isKeypressV && isKeypressInBody;
34 | }
35 |
36 | function setCurrentViewFileCheckbox(event: MouseEvent): void {
37 | const viewFileForm = (event.target as HTMLDivElement)
38 | .closest('.file')
39 | ?.querySelector('form.js-toggle-user-reviewed-file-form');
40 |
41 | currentViewFileCheckbox = viewFileForm?.querySelector('input[type=checkbox]');
42 | console.debug('currentViewFileCheckbox', currentViewFileCheckbox);
43 | }
44 |
--------------------------------------------------------------------------------
/src/icons/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladholubiev/quickreview-for-github/0decfd24bab27e1f7034deccbd2c21cf5fd33918/src/icons/128.png
--------------------------------------------------------------------------------
/src/icons/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladholubiev/quickreview-for-github/0decfd24bab27e1f7034deccbd2c21cf5fd33918/src/icons/16.png
--------------------------------------------------------------------------------
/src/icons/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladholubiev/quickreview-for-github/0decfd24bab27e1f7034deccbd2c21cf5fd33918/src/icons/256.png
--------------------------------------------------------------------------------
/src/icons/48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladholubiev/quickreview-for-github/0decfd24bab27e1f7034deccbd2c21cf5fd33918/src/icons/48.png
--------------------------------------------------------------------------------
/src/icons/icon.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladholubiev/quickreview-for-github/0decfd24bab27e1f7034deccbd2c21cf5fd33918/src/icons/icon.psd
--------------------------------------------------------------------------------
/src/index.test.ts:
--------------------------------------------------------------------------------
1 | import {getFoo} from './index';
2 |
3 | it('should return bar', () => {
4 | expect(getFoo()).toEqual('bar');
5 | });
6 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import {enableViewingFilesOnVPress} from './features/pull-requests/press-v-to-view';
2 | import {enableApproveMergeShortcuts} from './features/pull-requests/press-a-approve-m-merge';
3 |
4 | async function init() {
5 | const {host} = window.location;
6 |
7 | if (host.includes('github.com')) {
8 | enableViewingFilesOnVPress();
9 | enableApproveMergeShortcuts();
10 | }
11 | }
12 |
13 | init();
14 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Quick Review for GitHub",
3 | "description": "Hotkeys for faster code review of Pull Requests on GitHub",
4 | "version": "0.3.2",
5 | "manifest_version": 2,
6 | "permissions": [
7 | "tabs",
8 | "storage",
9 | "contextMenus",
10 | "https://circleci.com/api/*"
11 | ],
12 | "background": {
13 | "scripts": [
14 | "background.js"
15 | ]
16 | },
17 | "icons": {
18 | "16": "icons/16.png",
19 | "48": "icons/48.png",
20 | "128": "icons/128.png",
21 | "256": "icons/256.png"
22 | },
23 | "options_ui": {
24 | "chrome_style": true,
25 | "page": "options.html"
26 | },
27 | "content_scripts": [
28 | {
29 | "run_at": "document_start",
30 | "matches": [
31 | "https://github.com/*/*/pull/*/files",
32 | "https://app.circleci.com/pipelines/*"
33 | ],
34 | "js": [
35 | "content-script.js"
36 | ]
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/options.ts:
--------------------------------------------------------------------------------
1 | import OptionsSync from 'webext-options-sync';
2 |
3 | function init() {
4 | const optionsStorage = new OptionsSync();
5 | optionsStorage.syncForm(document.querySelector('form'));
6 | }
7 |
8 | init();
9 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Options {
2 | ghToken?: string;
3 | circleToken?: string;
4 | [key: string]: string | number | boolean;
5 | }
6 |
7 | export type AnyAction = ApprovePRAction | MergePRAction;
8 |
9 | export interface ApprovePRAction {
10 | action: 'approve-pr';
11 | params: {
12 | org: string;
13 | repo: string;
14 | prNumber: string;
15 | username: string;
16 | };
17 | }
18 |
19 | export interface MergePRAction {
20 | action: 'merge-pr';
21 | params: {
22 | org: string;
23 | repo: string;
24 | prNumber: string;
25 | username: string;
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "esModuleInterop": true,
5 | "module": "commonjs",
6 | "skipLibCheck": true,
7 | "sourceMap": false,
8 | "target": "esnext",
9 | "jsx": "react"
10 | },
11 | "exclude": ["node_modules"],
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/wallaby.config.js:
--------------------------------------------------------------------------------
1 | module.exports = () => {
2 | return {
3 | autoDetect: true,
4 | files: ['package.json', 'src/**/*.ts', '!src/**/*.test.ts'],
5 | tests: ['src/**/*.test.ts'],
6 | env: {
7 | params: {
8 | env: 'TZ=UTC'
9 | }
10 | }
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const CopyWebpackPlugin = require('copy-webpack-plugin');
3 | const ExtensionReloader = require('webpack-extension-reloader');
4 |
5 | module.exports = {
6 | mode: 'production',
7 | entry: {
8 | 'content-script': './src/index.tsx',
9 | options: './src/options.ts',
10 | background: './src/background/background.ts'
11 | },
12 | output: {
13 | filename: '[name].js',
14 | path: path.resolve(__dirname, 'lib')
15 | },
16 | optimization: {
17 | minimize: false
18 | },
19 | devtool: 'cheap-module-source-map',
20 | module: {
21 | rules: [
22 | {
23 | test: /\.(ts|js)x?$/,
24 | use: {
25 | loader: 'babel-loader',
26 | options: {
27 | cacheDirectory: true
28 | }
29 | }
30 | }
31 | ]
32 | },
33 | plugins: [
34 | process.env.NODE_ENV === 'development' &&
35 | new ExtensionReloader({
36 | manifest: path.resolve(__dirname, 'src/manifest.json')
37 | }),
38 | new CopyWebpackPlugin([{from: 'src/manifest.json'}]),
39 | new CopyWebpackPlugin([{from: 'src/options.html'}]),
40 | new CopyWebpackPlugin([{from: 'src/icons/*.png', to: 'icons/[name].[ext]'}])
41 | ].filter(e => e),
42 | resolve: {
43 | modules: [path.resolve(__dirname, 'node_modules')],
44 | extensions: ['.ts', '.tsx', '.json', '.js']
45 | }
46 | };
47 |
--------------------------------------------------------------------------------