Merge branch 'develop' of github.com:getinsomnia/insomnia into develop

This commit is contained in:
Gregory Schier committed 2019-04-17 16:10:27 -07:00
commit 2e25cf22cd
71 files changed
+1802 -1420

No files matched your search

+10 -10
View File
@@ -1785,7 +1785,7 @@
},
"array-equal": {
"version": "1.0.0",
"resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
@@ -1916,7 +1916,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -1929,7 +1929,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
@@ -2036,7 +2036,7 @@
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true
},
@@ -2329,7 +2329,7 @@
},
"callsites": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
"dev": true
},
@@ -3291,7 +3291,7 @@
},
"expand-range": {
"version": "1.8.2",
"resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
"dev": true,
"requires": {
@@ -6129,7 +6129,7 @@
},
"jsesc": {
"version": "1.3.0",
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
"dev": true
},
@@ -6159,7 +6159,7 @@
},
"json5": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
},
@@ -8315,7 +8315,7 @@
},
"resolve": {
"version": "1.1.7",
"resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
"integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
"dev": true
},
@@ -9736,7 +9736,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
}
+1
View File
@@ -24,6 +24,7 @@
},
"mac": {
"category": "public.app-category.developer-tools",
"darkModeSupport": true,
"target": [
"dmg",
"zip"
+10 -3
View File
@@ -69,12 +69,19 @@ export const FLEXIBLE_URL_REGEX = /^(http|https):\/\/[\wàâäèéêëîïôóœ
export const CHECK_FOR_UPDATES_INTERVAL = 1000 * 60 * 60 * 3; // 3 hours
export const PLUGIN_PATH = path.join(getDataDirectory(), 'plugins');
// Available editor key maps
export const EDITOR_KEY_MAP_DEFAULT = 'default';
export const EDITOR_KEY_MAP_EMACS = 'emacs';
export const EDITOR_KEY_MAP_SUBLIME = 'sublime';
export const EDITOR_KEY_MAP_VIM = 'vim';
// Hotkeys
export const MNEMONIC_SYM = isMac() ? '' : '&';
export const MOD_SYM = isMac() ? '⌘' : 'Ctrl';
export const ALT_SYM = isMac() ? '⌃' : 'Alt';
export const SHIFT_SYM = isMac() ? '⇧' : 'Shift';
export const CTRL_SYM = isMac() ? '⌃' : 'Ctrl';
export const ALT_SYM = isMac() ? '⌥' : 'Alt';
export const SHIFT_SYM = isMac() ? '⇧' : 'Shift';
export const META_SYM = isMac() ? '⌘' : 'Super';
export function joinHotKeys(keys) {
return keys.join(isMac() ? '' : '+');
}
+1 -6
View File
@@ -339,12 +339,7 @@ export async function exportHarWithRenderedRequest(
// Set auth header if we have it
if (!misc.hasAuthHeader(renderedRequest.headers)) {
const header = await getAuthHeader(
renderedRequest._id,
url,
renderedRequest.method,
renderedRequest.authentication,
);
const header = await getAuthHeader(renderedRequest, url);
if (header) {
renderedRequest.headers.push({
name: header.name,
@@ -0,0 +1,72 @@
// @flow
import type { HotKeyDefinition, KeyBindings } from './hotkeys';
import { getPlatformKeyCombinations } from './hotkeys';
import * as models from '../models';
function _pressedHotKey(e: KeyboardEvent, bindings: KeyBindings): boolean {
const isCtrlPressed = e.ctrlKey;
const isAltPressed = e.altKey;
const isShiftPressed = e.shiftKey;
const isMetaPressed = e.metaKey;
const keyCombList = getPlatformKeyCombinations(bindings);
for (const keyComb of keyCombList) {
const { ctrl, alt, shift, meta, keyCode } = keyComb;
if ((ctrl && !isCtrlPressed) || (!ctrl && isCtrlPressed)) {
continue;
}
if ((alt && !isAltPressed) || (!alt && isAltPressed)) {
continue;
}
if ((shift && !isShiftPressed) || (!shift && isShiftPressed)) {
continue;
}
if ((meta && !isMetaPressed) || (!meta && isMetaPressed)) {
continue;
}
if (keyCode !== e.keyCode) {
continue;
}
return true;
}
return false;
}
/**
* Check whether a hotkey has been pressed.
* @param e the activated keyboard event.
* @param definition the hotkey definition being checked.
* @returns {Promise<boolean>}
*/
export async function pressedHotKey(
e: KeyboardEvent,
definition: HotKeyDefinition,
): Promise<boolean> {
const settings = await models.settings.getOrCreate();
return _pressedHotKey(e, settings.hotKeyRegistry[definition.id]);
}
/**
* Call callback if the hotkey has been pressed.
* @param e the activated keyboard event.
* @param definition the hotkey definition being checked.
* @param callback to be called if the hotkey has been activated.
* @returns {Promise<void>}
*/
export async function executeHotKey(
e: KeyboardEvent,
definition: HotKeyDefinition,
callback: Function,
): Promise<void> {
const settings = await models.settings.getOrCreate();
if (_pressedHotKey(e, settings.hotKeyRegistry[definition.id])) {
callback();
}
}
+348 -281
View File
@@ -2,304 +2,371 @@
import keycodes from './keycodes';
import { isMac } from './constants';
export type Hotkey = {
/**
* The readable definition of a hotkey.
* The {@code id} the hotkey's reference id.
*/
export type HotKeyDefinition = {
id: string,
description: string,
meta: boolean,
};
/**
* The combination of key presses that will activate a hotkey if pressed.
*/
export type KeyCombination = {
ctrl: boolean,
alt: boolean,
shift: boolean,
keycode: number | Array<number>,
metaIsCtrl?: boolean,
meta: boolean,
keyCode: number,
};
export const SHOW_WORKSPACE_SETTINGS: Hotkey = {
description: 'Show Workspace Settings',
meta: true,
alt: false,
shift: true,
keycode: keycodes.comma,
/**
* The collection of a hotkey's key combinations for each platforms.
*/
export type KeyBindings = {
macKeys: Array<KeyCombination>,
// The key combinations for both Windows and Linux.
winLinuxKeys: Array<KeyCombination>,
};
export const SHOW_REQUEST_SETTINGS: Hotkey = {
description: 'Show Request Settings',
meta: true,
alt: true,
shift: true,
keycode: keycodes.comma,
/**
* The collection of defined hotkeys.
* The registry maps a hotkey by its reference id to its key bindings.
*/
export type HotKeyRegistry = {
[refId: string]: KeyBindings,
};
export const SHOW_KEYBOARD_SHORTCUTS: Hotkey = {
description: 'Show Keyboard Shortcuts',
meta: true,
alt: false,
shift: true,
keycode: keycodes.forwardslash,
};
export const SHOW_SETTINGS: Hotkey = {
description: 'Show App Preferences',
meta: true,
alt: false,
shift: false,
keycode: keycodes.comma,
};
export const TOGGLE_MAIN_MENU: Hotkey = {
description: 'Toggle Main Menu',
meta: true,
alt: true,
shift: false,
keycode: keycodes.comma,
};
export const TOGGLE_SIDEBAR: Hotkey = {
description: 'Toggle Sidebar',
meta: true,
alt: false,
shift: false,
keycode: keycodes.backslash,
};
export const SHOW_QUICK_SWITCHER: Hotkey = {
description: 'Switch Requests',
meta: true,
alt: false,
shift: false,
keycode: keycodes.p,
};
export const RELOAD_PLUGINS: Hotkey = {
description: 'Reload Plugins',
meta: true,
alt: false,
shift: true,
keycode: keycodes.r,
};
export const SHOW_AUTOCOMPLETE: Hotkey = {
description: 'Show Autocomplete',
meta: true,
metaIsCtrl: true,
alt: false,
shift: false,
keycode: keycodes.space,
};
export const SEND_REQUEST: Hotkey = {
description: 'Send Request',
meta: true,
alt: false,
shift: false,
keycode: [keycodes.enter, keycodes.r],
};
export const SEND_REQUEST_F5: Hotkey = {
description: 'Send Request',
meta: false,
alt: false,
shift: false,
keycode: keycodes.f5,
};
export const SHOW_SEND_OPTIONS: Hotkey = {
description: 'Send Request (Options)',
meta: true,
alt: false,
shift: true,
keycode: keycodes.enter,
};
export const SHOW_ENVIRONMENTS: Hotkey = {
description: 'Show Environment Editor',
meta: true,
alt: false,
shift: false,
keycode: keycodes.e,
};
export const TOGGLE_ENVIRONMENTS_MENU: Hotkey = {
description: 'Switch Environments',
meta: true,
alt: false,
shift: true,
keycode: keycodes.e,
};
export const TOGGLE_METHOD_DROPDOWN: Hotkey = {
description: 'Change HTTP Method',
meta: true,
alt: false,
shift: true,
keycode: keycodes.l,
};
export const TOGGLE_HISTORY_DROPDOWN: Hotkey = {
description: 'Show Request History',
meta: true,
alt: false,
shift: true,
keycode: keycodes.h,
};
export const FOCUS_URL: Hotkey = {
description: 'Focus URL',
meta: true,
alt: false,
shift: false,
keycode: keycodes.l,
};
export const GENERATE_CODE: Hotkey = {
description: 'Generate Code',
meta: true,
alt: false,
shift: true,
keycode: keycodes.g,
};
export const FOCUS_FILTER: Hotkey = {
description: 'Filter Sidebar',
meta: true,
alt: false,
shift: true,
keycode: keycodes.f,
};
export const FOCUS_RESPONSE: Hotkey = {
description: 'Focus Response',
meta: true,
alt: false,
shift: false,
keycode: keycodes.singlequote,
};
export const SHOW_COOKIES: Hotkey = {
description: 'Edit Cookies',
meta: true,
alt: false,
shift: false,
keycode: keycodes.k,
};
export const CREATE_REQUEST: Hotkey = {
description: 'Create Request',
meta: true,
alt: false,
shift: false,
keycode: keycodes.n,
};
export const DELETE_REQUEST: Hotkey = {
description: 'Delete Request',
meta: true,
alt: false,
shift: true,
keycode: keycodes.delete,
};
export const CREATE_FOLDER: Hotkey = {
description: 'Create Folder',
meta: true,
alt: false,
shift: true,
keycode: keycodes.n,
};
export const DUPLICATE_REQUEST: Hotkey = {
description: 'Duplicate Request',
meta: true,
alt: false,
shift: false,
keycode: keycodes.d,
};
export const CLOSE_DROPDOWN: Hotkey = {
description: 'Close Dropdown',
meta: false,
alt: false,
shift: false,
keycode: keycodes.esc,
};
export const CLOSE_MODAL: Hotkey = {
description: 'Close Modal',
meta: false,
alt: false,
shift: false,
keycode: keycodes.esc,
};
export const UNCOVER_VARIABLES: Hotkey = {
description: 'Uncover Variables',
meta: false,
alt: true,
shift: true,
keycode: keycodes.u,
};
export function pressedHotKey(e: KeyboardEvent, definition: Hotkey): boolean {
const isMetaPressed = isMac() ? e.metaKey : e.ctrlKey;
const isAltPressed = isMac() ? e.ctrlKey : e.altKey;
const isShiftPressed = e.shiftKey;
const { meta, alt, shift, keycode } = definition;
const codes = Array.isArray(keycode) ? keycode : [keycode];
for (const code of codes) {
if ((alt && !isAltPressed) || (!alt && isAltPressed)) {
continue;
}
if ((meta && !isMetaPressed) || (!meta && isMetaPressed)) {
continue;
}
if ((shift && !isShiftPressed) || (!shift && isShiftPressed)) {
continue;
}
if (code !== e.keyCode) {
continue;
}
return true;
}
return false;
function defineHotKey(id: string, description: string): HotKeyDefinition {
return {
id: id,
description: description,
};
}
export function executeHotKey(e: KeyboardEvent, definition: Hotkey, callback: Function): void {
if (pressedHotKey(e, definition)) {
callback();
}
function keyComb(
ctrl: boolean,
alt: boolean,
shift: boolean,
meta: boolean,
keyCode: number,
): KeyCombination {
return {
ctrl: ctrl,
alt: alt,
shift: shift,
meta: meta,
keyCode: keyCode,
};
}
export function getChar(hotkey: Hotkey) {
const codes = Array.isArray(hotkey.keycode) ? hotkey.keycode : [hotkey.keycode];
const chars = [];
function keyBinds(
mac: KeyCombination | Array<KeyCombination>,
winLinux: KeyCombination | Array<KeyCombination>,
): KeyBindings {
if (!Array.isArray(mac)) {
mac = [mac];
}
for (const keycode of codes) {
const v = Object.keys(keycodes).find(k => keycodes[k] === keycode);
if (!Array.isArray(winLinux)) {
winLinux = [winLinux];
}
if (!v) {
console.error('Invalid hotkey', hotkey);
} else if (v.toUpperCase() === 'ENTER') {
chars.push('Enter');
} else if (v.toUpperCase() === 'DELETE') {
chars.push('Delete');
} else if (v.toUpperCase() === 'COMMA') {
chars.push(',');
} else if (v.toUpperCase() === 'BACKSLASH') {
chars.push('\\');
} else if (v.toUpperCase() === 'FORWARDSLASH') {
chars.push('/');
} else if (v.toUpperCase() === 'SINGLEQUOTE') {
chars.push("'");
} else if (v.toUpperCase() === 'SPACE') {
chars.push('Space');
return {
macKeys: mac,
winLinuxKeys: winLinux,
};
}
/**
* The collection of available hotkeys' and their definitions.
*/
// Not using dot, because NeDB prohibits field names to contain dots.
export const hotKeyRefs = {
WORKSPACE_SHOW_SETTINGS: defineHotKey('workspace_showSettings', 'Show Workspace Settings'),
REQUEST_SHOW_SETTINGS: defineHotKey('request_showSettings', 'Show Request Settings'),
PREFERENCES_SHOW_KEYBOARD_SHORTCUTS: defineHotKey(
'preferences_showKeyboardShortcuts',
'Show Keyboard Shortcuts',
),
PREFERENCES_SHOW_GENERAL: defineHotKey('preferences_showGeneral', 'Show App Preferences'),
TOGGLE_MAIN_MENU: defineHotKey('toggleMainMenu', 'Toggle Main Menu'),
SIDEBAR_TOGGLE: defineHotKey('sidebar_toggle', 'Toggle Sidebar'),
REQUEST_QUICK_SWITCH: defineHotKey('request_quickSwitch', 'Switch Requests'),
PLUGIN_RELOAD: defineHotKey('plugin_reload', 'Reload Plugins'),
SHOW_AUTOCOMPLETE: defineHotKey('showAutocomplete', 'Show Autocomplete'),
REQUEST_SEND: defineHotKey('request_send', 'Send Request'),
REQUEST_SHOW_OPTIONS: defineHotKey('request_showOptions', 'Send Request (Options)'),
ENVIRONMENT_SHOW_EDITOR: defineHotKey('environment_showEditor', 'Show Environment Editor'),
ENVIRONMENT_SHOW_SWITCH_MENU: defineHotKey('environment_showSwitchMenu', 'Switch Environments'),
REQUEST_TOGGLE_HTTP_METHOD_MENU: defineHotKey(
'request_toggleHttpMethodMenu',
'Change HTTP Method',
),
REQUEST_TOGGLE_HISTORY: defineHotKey('request_toggleHistory', 'Show Request History'),
REQUEST_FOCUS_URL: defineHotKey('request_focusUrl', 'Focus URL'),
REQUEST_SHOW_GENERATE_CODE_EDITOR: defineHotKey(
'request_showGenerateCodeEditor',
'Generate Code',
),
SIDEBAR_FOCUS_FILTER: defineHotKey('sidebar_focusFilter', 'Filter Sidebar'),
RESPONSE_FOCUS: defineHotKey('response_focus', 'Focus Response'),
SHOW_COOKIES_EDITOR: defineHotKey('showCookiesEditor', 'Edit Cookies'),
REQUEST_SHOW_CREATE: defineHotKey('request_showCreate', 'Create Request'),
REQUEST_SHOW_DELETE: defineHotKey('request_showDelete', 'Delete Request'),
REQUEST_SHOW_CREATE_FOLDER: defineHotKey('request_showCreateFolder', 'Create Folder'),
REQUEST_SHOW_DUPLICATE: defineHotKey('request_showDuplicate', 'Duplicate Request'),
CLOSE_DROPDOWN: defineHotKey('closeDropdown', 'Close Dropdown'),
CLOSE_MODAL: defineHotKey('closeModal', 'Close Modal'),
ENVIRONMENT_UNCOVER_VARIABLES: defineHotKey('environment_uncoverVariables', 'Uncover Variables'),
};
/**
* The default key bindings values of all available hotkeys.
*/
const defaultRegistry: HotKeyRegistry = {
[hotKeyRefs.WORKSPACE_SHOW_SETTINGS.id]: keyBinds(
keyComb(false, false, true, true, keycodes.comma),
keyComb(true, false, true, false, keycodes.comma),
),
[hotKeyRefs.REQUEST_SHOW_SETTINGS.id]: keyBinds(
keyComb(false, true, true, true, keycodes.comma),
keyComb(true, true, true, false, keycodes.comma),
),
[hotKeyRefs.PREFERENCES_SHOW_KEYBOARD_SHORTCUTS.id]: keyBinds(
keyComb(false, false, true, true, keycodes.forwardslash),
keyComb(true, false, true, false, keycodes.forwardslash),
),
[hotKeyRefs.PREFERENCES_SHOW_GENERAL.id]: keyBinds(
keyComb(false, false, false, true, keycodes.comma),
keyComb(true, false, false, false, keycodes.comma),
),
[hotKeyRefs.TOGGLE_MAIN_MENU.id]: keyBinds(
keyComb(false, true, false, true, keycodes.comma),
keyComb(true, true, false, false, keycodes.comma),
),
[hotKeyRefs.SIDEBAR_TOGGLE.id]: keyBinds(
keyComb(false, false, false, true, keycodes.backslash),
keyComb(true, false, false, false, keycodes.backslash),
),
[hotKeyRefs.REQUEST_QUICK_SWITCH.id]: keyBinds(
keyComb(false, false, false, true, keycodes.p),
keyComb(true, false, false, false, keycodes.p),
),
[hotKeyRefs.PLUGIN_RELOAD.id]: keyBinds(
keyComb(false, false, true, true, keycodes.r),
keyComb(true, false, true, false, keycodes.r),
),
[hotKeyRefs.SHOW_AUTOCOMPLETE.id]: keyBinds(
keyComb(true, false, false, false, keycodes.space),
keyComb(true, false, false, false, keycodes.space),
),
[hotKeyRefs.REQUEST_SEND.id]: keyBinds(
[
keyComb(false, false, false, true, keycodes.enter),
keyComb(false, false, false, true, keycodes.r),
keyComb(false, false, false, false, keycodes.f5),
],
[
keyComb(true, false, false, false, keycodes.enter),
keyComb(true, false, false, false, keycodes.r),
keyComb(false, false, false, false, keycodes.f5),
],
),
[hotKeyRefs.REQUEST_SHOW_OPTIONS.id]: keyBinds(
keyComb(false, false, true, true, keycodes.enter),
keyComb(true, false, true, false, keycodes.enter),
),
[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]: keyBinds(
keyComb(false, false, false, true, keycodes.e),
keyComb(true, false, false, false, keycodes.e),
),
[hotKeyRefs.ENVIRONMENT_SHOW_SWITCH_MENU.id]: keyBinds(
keyComb(false, false, true, true, keycodes.e),
keyComb(true, false, true, false, keycodes.e),
),
[hotKeyRefs.REQUEST_TOGGLE_HTTP_METHOD_MENU.id]: keyBinds(
keyComb(false, false, true, true, keycodes.l),
keyComb(true, false, true, false, keycodes.l),
),
[hotKeyRefs.REQUEST_TOGGLE_HISTORY.id]: keyBinds(
keyComb(false, false, true, true, keycodes.h),
keyComb(true, false, true, false, keycodes.h),
),
[hotKeyRefs.REQUEST_FOCUS_URL.id]: keyBinds(
keyComb(false, false, false, true, keycodes.l),
keyComb(true, false, false, false, keycodes.l),
),
[hotKeyRefs.REQUEST_SHOW_GENERATE_CODE_EDITOR.id]: keyBinds(
keyComb(false, false, true, true, keycodes.g),
keyComb(true, false, true, false, keycodes.g),
),
[hotKeyRefs.SIDEBAR_FOCUS_FILTER.id]: keyBinds(
keyComb(false, false, true, true, keycodes.f),
keyComb(true, false, true, false, keycodes.f),
),
[hotKeyRefs.RESPONSE_FOCUS.id]: keyBinds(
keyComb(false, false, false, true, keycodes.singlequote),
keyComb(true, false, false, false, keycodes.singlequote),
),
[hotKeyRefs.SHOW_COOKIES_EDITOR.id]: keyBinds(
keyComb(false, false, false, true, keycodes.k),
keyComb(true, false, false, false, keycodes.k),
),
[hotKeyRefs.REQUEST_SHOW_CREATE.id]: keyBinds(
keyComb(false, false, false, true, keycodes.n),
keyComb(true, false, false, false, keycodes.n),
),
[hotKeyRefs.REQUEST_SHOW_DELETE.id]: keyBinds(
keyComb(false, false, true, true, keycodes.delete),
keyComb(true, false, true, false, keycodes.delete),
),
[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]: keyBinds(
keyComb(false, false, true, true, keycodes.n),
keyComb(true, false, true, false, keycodes.n),
),
[hotKeyRefs.REQUEST_SHOW_DUPLICATE.id]: keyBinds(
keyComb(false, false, false, true, keycodes.d),
keyComb(true, false, false, false, keycodes.d),
),
[hotKeyRefs.CLOSE_DROPDOWN.id]: keyBinds(
keyComb(false, false, false, false, keycodes.esc),
keyComb(false, false, false, false, keycodes.esc),
),
[hotKeyRefs.CLOSE_MODAL.id]: keyBinds(
keyComb(false, false, false, false, keycodes.esc),
keyComb(false, false, false, false, keycodes.esc),
),
[hotKeyRefs.ENVIRONMENT_UNCOVER_VARIABLES.id]: keyBinds(
keyComb(false, true, true, false, keycodes.u),
keyComb(false, true, true, false, keycodes.u),
),
};
function copyKeyCombs(sources: Array<KeyCombination>): Array<KeyCombination> {
let targets: Array<KeyCombination> = [];
sources.forEach(keyComb => {
targets.push(Object.assign({}, keyComb));
});
return targets;
}
/**
* Get a new copy of hotkey registry with default values.
* @returns {HotKeyRegistry}
*/
export function newDefaultRegistry(): HotKeyRegistry {
let newDefaults: HotKeyRegistry = {};
for (const refId in defaultRegistry) {
if (!defaultRegistry.hasOwnProperty(refId)) {
continue;
}
const keyBindings: KeyBindings = defaultRegistry[refId];
newDefaults[refId] = {
macKeys: copyKeyCombs(keyBindings.macKeys),
winLinuxKeys: copyKeyCombs(keyBindings.winLinuxKeys),
};
}
return newDefaults;
}
/**
* Get the key combinations based on the current platform.
* @param bindings
* @returns {Array<KeyCombination>}
*/
export function getPlatformKeyCombinations(bindings: KeyBindings): Array<KeyCombination> {
if (isMac()) {
return bindings.macKeys;
}
return bindings.winLinuxKeys;
}
/**
* Gets the displayed text of a key code.
* @param keyCode
* @returns {string}
*/
export function getChar(keyCode: number): string {
let char;
const keyCodeStr = Object.keys(keycodes).find(k => keycodes[k] === keyCode);
if (!keyCodeStr) {
console.error('Invalid key code', keyCode);
} else {
const cap = keyCodeStr.toUpperCase();
if (cap === 'ENTER') {
char = 'Enter';
} else if (cap === 'DELETE') {
char = 'Delete';
} else if (cap === 'COMMA') {
char = ',';
} else if (cap === 'BACKSLASH') {
char = '\\';
} else if (cap === 'FORWARDSLASH') {
char = '/';
} else if (cap === 'SINGLEQUOTE') {
char = "'";
} else if (cap === 'SPACE') {
char = 'Space';
} else {
chars.push(v.toUpperCase());
char = cap;
}
}
return chars[0] || 'unknown';
return char || 'unknown';
}
@@ -2,6 +2,7 @@
import type { BaseModel } from './index';
import * as db from '../common/database';
import { UPDATE_CHANNEL_STABLE } from '../common/constants';
import * as hotkeys from '../common/hotkeys';
type BaseSettings = {
showPasswords: boolean,
@@ -34,6 +35,7 @@ type BaseSettings = {
fontInterface: string | null,
fontSize: number,
fontVariantLigatures: boolean,
hotKeyRegistry: hotkeys.HotKeyRegistry,
};
export type Settings = BaseModel & BaseSettings;
@@ -75,6 +77,7 @@ export function init(): BaseSettings {
fontInterface: null,
fontSize: 13,
fontVariantLigatures: false,
hotKeyRegistry: hotkeys.newDefaultRegistry(),
};
}
@@ -3,7 +3,7 @@ import { AUTH_OAUTH_1 } from '../../common/constants';
describe('OAuth 1.0', () => {
it('Does OAuth 1.0', async () => {
const header = await getAuthHeader('req_123', 'https://insomnia.rest/', 'GET', {
const authentication = {
type: AUTH_OAUTH_1,
consumerKey: 'consumerKey',
consumerSecret: 'consumerSecret',
@@ -13,7 +13,9 @@ describe('OAuth 1.0', () => {
signatureMethod: 'HMAC-SHA1',
nonce: 'nonce',
timestamp: '1234567890',
});
};
const request = { url: 'https://insomnia.rest/', method: 'GET', authentication };
const header = await getAuthHeader(request, 'https://insomnia.rest/');
expect(header).toEqual({
name: 'Authorization',
@@ -31,7 +33,7 @@ describe('OAuth 1.0', () => {
});
it('Does OAuth 1.0 with RSA-SHA1', async () => {
const header = await getAuthHeader('req_123', 'https://insomnia.rest/', 'GET', {
const authentication = {
type: AUTH_OAUTH_1,
consumerKey: 'consumerKey',
consumerSecret: 'consumerSecret',
@@ -57,7 +59,9 @@ describe('OAuth 1.0', () => {
'-----END RSA PRIVATE KEY-----',
nonce: 'nonce',
timestamp: '1234567890',
});
};
const request = { url: 'https://insomnia.rest/', method: 'GET', authentication };
const header = await getAuthHeader(request, 'https://insomnia.rest/');
expect(header).toEqual({
name: 'Authorization',
@@ -75,12 +79,14 @@ describe('OAuth 1.0', () => {
});
it('Does OAuth 1.0 with defaults', async () => {
const header = await getAuthHeader('req_123', 'https://insomnia.rest/', 'GET', {
const authentication = {
type: AUTH_OAUTH_1,
consumerKey: 'consumerKey',
consumerSecret: 'consumerSecret',
signatureMethod: 'HMAC-SHA1',
});
};
const request = { url: 'https://insomnia.rest/', method: 'GET', authentication };
const header = await getAuthHeader(request, 'https://insomnia.rest/');
expect(header.name).toBe('Authorization');
expect(header.value).toMatch(
@@ -11,7 +11,7 @@ import getOAuth2Token from './o-auth-2/get-token';
import getOAuth1Token from './o-auth-1/get-token';
import * as Hawk from 'hawk';
import jwtAuthentication from 'jwt-authentication';
import type { RequestAuthentication } from '../models/request';
import type { RenderedRequest } from '../common/render';
import { getBasicAuthHeader } from './basic-auth/get-header';
import { getBearerAuthHeader } from './bearer-auth/get-header';
@@ -21,11 +21,12 @@ type Header = {
};
export async function getAuthHeader(
requestId: string,
renderedRequest: RenderedRequest,
url: string,
method: string,
authentication: RequestAuthentication,
): Promise<Header | null> {
const { method, authentication } = renderedRequest;
const requestId = renderedRequest._id;
if (authentication.disabled) {
return null;
}
@@ -69,11 +70,21 @@ export async function getAuthHeader(
}
if (authentication.type === AUTH_HAWK) {
const { id, key, algorithm, ext } = authentication;
const header = Hawk.client.header(url, method, {
const { id, key, algorithm, ext, validatePayload } = authentication;
let headerOptions = {
credentials: { id, key, algorithm },
ext: ext,
});
};
if (validatePayload) {
const payloadValidationFields = {
payload: renderedRequest.body.text,
contentType: renderedRequest.body.mimeType,
};
headerOptions = Object.assign({}, payloadValidationFields, headerOptions);
}
const header = Hawk.client.header(url, method, headerOptions);
return {
name: 'Authorization',
value: header.field,
+1 -6
View File
@@ -594,12 +594,7 @@ export async function _actuallySend(
} else if (renderedRequest.authentication.type === AUTH_NETRC) {
setOpt(Curl.option.NETRC, Curl.netrc.REQUIRED);
} else {
const authHeader = await getAuthHeader(
renderedRequest._id,
finalUrl,
renderedRequest.method,
renderedRequest.authentication,
);
const authHeader = await getAuthHeader(renderedRequest, finalUrl);
if (authHeader) {
headers.push({
+13 -8
View File
@@ -78,11 +78,6 @@ async function _isInsomniaPlugin(lookupName: string): Promise<Object> {
},
},
(err, stdout, stderr) => {
if (err) {
reject(new Error(`${lookupName} npm error: ${err.message}`));
return;
}
if (stderr) {
reject(new Error(`Yarn error ${stderr.toString('utf8')}`));
return;
@@ -91,8 +86,15 @@ async function _isInsomniaPlugin(lookupName: string): Promise<Object> {
let yarnOutput;
try {
yarnOutput = JSON.parse(stdout.toString('utf8'));
} catch (err) {
reject(new Error(`Yarn response not JSON: ${err.message}`));
} catch (ex) {
// Output is not JSON. Check if yarn/electron terminated with non-zero exit code.
// In certain environments electron can exit with error even if output is OK.
// Parsing is attemted before checking exit code as workaround for false errors.
if (err) {
reject(new Error(`${lookupName} npm error: ${err.message}`));
} else {
reject(new Error(`Yarn response not JSON: ${ex.message}`));
}
return;
}
@@ -149,7 +151,10 @@ async function _installPluginToTmpDir(lookupName: string): Promise<{ tmpDir: str
},
},
(err, stdout, stderr) => {
if (err) {
// Check yarn/electron process exit code.
// In certain environments electron can exit with error even if the command was perfomed sucesfully.
// Checking for sucess message in output is a workaround for false errors.
if (err && !stdout.toString('utf8').includes('success')) {
reject(new Error(`${lookupName} install error: ${err.message}`));
return;
}
@@ -1,16 +1,16 @@
// @flow
import * as React from 'react';
import type { Hotkey as HotkeyType } from '../../../../common/hotkeys';
import Hotkey from '../../hotkey';
import type { KeyBindings } from '../../../../common/hotkeys';
type Props = {
hotkey: HotkeyType,
keyBindings: KeyBindings,
};
class DropdownHint extends React.PureComponent<Props> {
render() {
const { hotkey } = this.props;
return <Hotkey className="dropdown__hint" hotkey={hotkey} />;
const { keyBindings } = this.props;
return <Hotkey className="dropdown__hint" keyBindings={keyBindings} />;
}
}
@@ -8,7 +8,8 @@ import DropdownItem from './dropdown-item';
import DropdownDivider from './dropdown-divider';
import { fuzzyMatch } from '../../../../common/misc';
import KeydownBinder from '../../keydown-binder';
import * as hotkeys from '../../../../common/hotkeys';
import { executeHotKey } from '../../../../common/hotkeys-listener';
import { hotKeyRefs } from '../../../../common/hotkeys';
const dropdownsContainer = document.querySelector('#dropdowns-container');
@@ -115,7 +116,7 @@ class Dropdown extends PureComponent {
this._handleDropdownNavigation(e);
hotkeys.executeHotKey(e, hotkeys.CLOSE_DROPDOWN, () => {
executeHotKey(e, hotKeyRefs.CLOSE_DROPDOWN, () => {
this.hide();
});
}
@@ -3,7 +3,8 @@ import PropTypes from 'prop-types';
import autobind from 'autobind-decorator';
import classnames from 'classnames';
import KeydownBinder from '../keydown-binder';
import * as hotkeys from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
import { pressedHotKey } from '../../../common/hotkeys-listener';
// Keep global z-index reference so that every modal will
// appear over top of an existing one.
@@ -21,7 +22,7 @@ class Modal extends PureComponent {
};
}
_handleKeyDown(e) {
async _handleKeyDown(e) {
if (!this.state.open) {
return;
}
@@ -32,7 +33,7 @@ class Modal extends PureComponent {
}
const closeOnKeyCodes = this.props.closeOnKeyCodes || [];
const pressedEscape = hotkeys.pressedHotKey(e, hotkeys.CLOSE_MODAL);
const pressedEscape = await pressedHotKey(e, hotKeyRefs.CLOSE_MODAL);
const pressedCloseButton = closeOnKeyCodes.find(c => c === e.keyCode);
// Pressed escape
@@ -10,7 +10,8 @@ import { showModal } from '../modals/index';
import FilterHelpModal from '../modals/filter-help-modal';
import * as misc from '../../../common/misc';
import prettify from 'insomnia-prettify';
import { DEBOUNCE_MILLIS, isMac } from '../../../common/constants';
import { DEBOUNCE_MILLIS, EDITOR_KEY_MAP_VIM, isMac } from '../../../common/constants';
import keyCodes from '../../../common/keycodes';
import './base-imports';
import { getTagDefinitions } from '../../../templating/index';
import Dropdown from '../base/dropdown/dropdown';
@@ -287,6 +288,7 @@ class CodeEditor extends React.Component {
this.codeMirror.on('blur', this._codemirrorBlur);
this.codeMirror.on('paste', this._codemirrorPaste);
this.codeMirror.on('scroll', this._codemirrorScroll);
this.codeMirror.on('keyHandled', this._codemirrorKeyHandled);
// Prevent these things if we're type === "password"
this.codeMirror.on('copy', this._codemirrorPreventWhenTypePassword);
@@ -664,6 +666,18 @@ class CodeEditor extends React.Component {
this._persistState();
}
_codemirrorKeyHandled(codeMirror, keyName, event) {
const { keyMap } = this.props;
const { keyCode } = event;
const isVimKeyMap = keyMap === EDITOR_KEY_MAP_VIM;
const pressedEscape = keyCode === keyCodes.esc;
if (isVimKeyMap && pressedEscape) {
event.stopPropagation();
}
}
_codemirrorValueBeforeChange(doc, change) {
// If we're in single-line mode, merge all changed lines into one
if (this.props.singleLine && change.text && change.text.length > 1) {
@@ -11,17 +11,19 @@ import {
} from '../base/dropdown';
import { showModal } from '../modals/index';
import Tooltip from '../tooltip';
import * as hotkeys from '../../../common/hotkeys';
import KeydownBinder from '../keydown-binder';
import type { Workspace } from '../../../models/workspace';
import type { Environment } from '../../../models/environment';
import type { HotKeyRegistry } from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
import { executeHotKey } from '../../../common/hotkeys-listener';
type Props = {
workspace: Workspace,
handleChangeEnvironment: Function,
workspace: Workspace,
environments: Array<Environment>,
environmentHighlightColorStyle: String,
hotKeyRegistry: HotKeyRegistry,
// Optional
className?: string,
@@ -57,7 +59,7 @@ class EnvironmentsDropdown extends React.PureComponent<Props> {
}
_handleKeydown(e: KeyboardEvent) {
hotkeys.executeHotKey(e, hotkeys.TOGGLE_ENVIRONMENTS_MENU, () => {
executeHotKey(e, hotKeyRefs.ENVIRONMENT_SHOW_SWITCH_MENU, () => {
this._dropdown && this._dropdown.toggle(true);
});
}
@@ -69,6 +71,7 @@ class EnvironmentsDropdown extends React.PureComponent<Props> {
environments,
activeEnvironment,
environmentHighlightColorStyle,
hotKeyRegistry,
...other
} = this.props;
@@ -125,7 +128,7 @@ class EnvironmentsDropdown extends React.PureComponent<Props> {
<DropdownItem onClick={this._handleShowEnvironmentModal}>
<i className="fa fa-wrench" /> Manage Environments
<DropdownHint hotkey={hotkeys.SHOW_ENVIRONMENTS} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]} />
</DropdownItem>
</Dropdown>
</KeydownBinder>
@@ -10,7 +10,7 @@ import {
DropdownItem,
} from '../base/dropdown/index';
import * as models from '../../../models';
import * as hotkeys from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
@autobind
class RequestActionsDropdown extends PureComponent {
@@ -44,6 +44,7 @@ class RequestActionsDropdown extends PureComponent {
const {
request, // eslint-disable-line no-unused-vars
handleShowSettings,
hotKeyRegistry,
...other
} = this.props;
@@ -54,11 +55,13 @@ class RequestActionsDropdown extends PureComponent {
</DropdownButton>
<DropdownItem onClick={this._handleDuplicate}>
<i className="fa fa-copy" /> Duplicate
<DropdownHint hotkey={hotkeys.DUPLICATE_REQUEST} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_DUPLICATE.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleGenerateCode}>
<i className="fa fa-code" /> Generate Code
<DropdownHint hotkey={hotkeys.GENERATE_CODE} />
<DropdownHint
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_GENERATE_CODE_EDITOR.id]}
/>
</DropdownItem>
<DropdownItem onClick={this._handleCopyAsCurl}>
<i className="fa fa-copy" /> Copy as Curl
@@ -71,7 +74,7 @@ class RequestActionsDropdown extends PureComponent {
<DropdownItem onClick={handleShowSettings}>
<i className="fa fa-wrench" /> Settings
<DropdownHint hotkey={hotkeys.SHOW_REQUEST_SETTINGS} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_SETTINGS.id]} />
</DropdownItem>
</Dropdown>
);
@@ -84,6 +87,7 @@ RequestActionsDropdown.propTypes = {
handleCopyAsCurl: PropTypes.func.isRequired,
handleShowSettings: PropTypes.func.isRequired,
request: PropTypes.object.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
};
export default RequestActionsDropdown;
@@ -12,7 +12,7 @@ import {
import EnvironmentEditModal from '../modals/environment-edit-modal';
import * as models from '../../../models';
import { showPrompt, showModal } from '../modals/index';
import * as hotkeys from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
@autobind
class RequestGroupActionsDropdown extends PureComponent {
@@ -63,6 +63,7 @@ class RequestGroupActionsDropdown extends PureComponent {
render() {
const {
requestGroup, // eslint-disable-line no-unused-vars
hotKeyRegistry,
...other
} = this.props;
@@ -73,11 +74,11 @@ class RequestGroupActionsDropdown extends PureComponent {
</DropdownButton>
<DropdownItem onClick={this._handleRequestCreate}>
<i className="fa fa-plus-circle" /> New Request
<DropdownHint hotkey={hotkeys.CREATE_REQUEST} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleRequestGroupCreate}>
<i className="fa fa-folder" /> New Folder
<DropdownHint hotkey={hotkeys.CREATE_FOLDER} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]} />
</DropdownItem>
<DropdownDivider />
<DropdownItem onClick={this._handleRequestGroupDuplicate}>
@@ -102,6 +103,7 @@ class RequestGroupActionsDropdown extends PureComponent {
RequestGroupActionsDropdown.propTypes = {
workspace: PropTypes.object.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
handleCreateRequest: PropTypes.func.isRequired,
handleCreateRequestGroup: PropTypes.func.isRequired,
handleDuplicateRequestGroup: PropTypes.func.isRequired,
@@ -6,9 +6,10 @@ import StatusTag from '../tags/status-tag';
import URLTag from '../tags/url-tag';
import PromptButton from '../base/prompt-button';
import KeydownBinder from '../keydown-binder';
import * as hotkeys from '../../../common/hotkeys';
import TimeTag from '../tags/time-tag';
import SizeTag from '../tags/size-tag';
import { executeHotKey } from '../../../common/hotkeys-listener';
import { hotKeyRefs } from '../../../common/hotkeys';
@autobind
class ResponseHistoryDropdown extends PureComponent {
@@ -29,7 +30,7 @@ class ResponseHistoryDropdown extends PureComponent {
}
_handleKeydown(e) {
hotkeys.executeHotKey(e, hotkeys.TOGGLE_HISTORY_DROPDOWN, () => {
executeHotKey(e, hotKeyRefs.REQUEST_TOGGLE_HISTORY, () => {
this._dropdown && this._dropdown.toggle(true);
});
}
@@ -17,8 +17,9 @@ import WorkspaceShareSettingsModal from '../modals/workspace-share-settings-moda
import * as session from '../../../sync/session';
import LoginModal from '../modals/login-modal';
import Tooltip from '../tooltip';
import * as hotkeys from '../../../common/hotkeys';
import KeydownBinder from '../keydown-binder';
import { hotKeyRefs } from '../../../common/hotkeys';
import { executeHotKey } from '../../../common/hotkeys-listener';
@autobind
class WorkspaceDropdown extends PureComponent {
@@ -91,7 +92,7 @@ class WorkspaceDropdown extends PureComponent {
}
_handleKeydown(e) {
hotkeys.executeHotKey(e, hotkeys.TOGGLE_MAIN_MENU, () => {
executeHotKey(e, hotKeyRefs.TOGGLE_MAIN_MENU, () => {
this._dropdown && this._dropdown.toggle(true);
});
}
@@ -103,6 +104,7 @@ class WorkspaceDropdown extends PureComponent {
activeWorkspace,
unseenWorkspaces,
isLoading,
hotKeyRegistry,
...other
} = this.props;
@@ -145,7 +147,7 @@ class WorkspaceDropdown extends PureComponent {
<DropdownDivider>{activeWorkspace.name}</DropdownDivider>
<DropdownItem onClick={this._handleShowWorkspaceSettings}>
<i className="fa fa-wrench" /> Workspace Settings
<DropdownHint hotkey={hotkeys.SHOW_WORKSPACE_SETTINGS} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.WORKSPACE_SHOW_SETTINGS.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleShowShareSettings}>
@@ -176,7 +178,7 @@ class WorkspaceDropdown extends PureComponent {
<DropdownItem onClick={this._handleShowSettings}>
<i className="fa fa-cog" /> Preferences
<DropdownHint hotkey={hotkeys.SHOW_SETTINGS} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.PREFERENCES_SHOW_GENERAL.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleShowExport}>
<i className="fa fa-share" /> Import/Export
@@ -215,6 +217,7 @@ WorkspaceDropdown.propTypes = {
workspaces: PropTypes.arrayOf(PropTypes.object).isRequired,
unseenWorkspaces: PropTypes.arrayOf(PropTypes.object).isRequired,
activeWorkspace: PropTypes.object.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
// Optional
className: PropTypes.string,
@@ -49,6 +49,11 @@ class HawkAuth extends React.PureComponent<Props> {
this._handleChangeProperty('ext', value);
}
_handleChangePayloadValidation(): void {
const { request } = this.props;
this._handleChangeProperty('validatePayload', !request.authentication.validatePayload);
}
renderHawkAuthenticationFields(): React.Node {
const hawkAuthId = this.renderInputRow('Auth ID', 'id', this._handleChangeHawkAuthId);
@@ -66,7 +71,13 @@ class HawkAuth extends React.PureComponent<Props> {
const ext = this.renderInputRow('Ext', 'ext', this._handleChangeExt);
return [hawkAuthId, hawkAuthKey, algorithm, ext];
const payloadValidation = this.renderButtonRow(
'Validate Payload',
'validatePayload',
this._handleChangePayloadValidation,
);
return [hawkAuthId, hawkAuthKey, algorithm, ext, payloadValidation];
}
renderSelectRow(
@@ -115,7 +126,7 @@ class HawkAuth extends React.PureComponent<Props> {
isVariableUncovered,
} = this.props;
const {authentication} = request;
const { authentication } = request;
const id = label.replace(/ /g, '-');
return (
@@ -146,6 +157,44 @@ class HawkAuth extends React.PureComponent<Props> {
);
}
renderButtonRow(label: string, property: string, onChange: Function): React.Element<*> {
const { request } = this.props;
const { authentication } = request;
const id = label.replace(/ /g, '-');
return (
<tr key={id}>
<td className="pad-right no-wrap valign-middle">
<label htmlFor={id} className="label--small no-pad">
{label}
</label>
</td>
<td className="wide">
<div
className={classnames('form-control form-control--underlined no-margin', {
'form-control--inactive': authentication.disabled,
})}>
<Button
className="btn btn--super-duper-compact"
id={id}
onClick={this._handleChangePayloadValidation}
value={authentication.validatePayload}
title={
authentication.validatePayload
? 'Enable payload validation'
: 'Disable payload validation'
}>
{authentication.validatePayload ? (
<i className="fa fa-check-square-o" />
) : (
<i className="fa fa-square-o" />
)}
</Button>
</div>
</td>
</tr>
);
}
render() {
const fields = this.renderHawkAuthenticationFields();
const { authentication } = this.props.request;
@@ -1,12 +1,12 @@
// @flow
import * as React from 'react';
import classnames from 'classnames';
import type { Hotkey as HotkeyType } from '../../common/hotkeys';
import { ALT_SYM, CTRL_SYM, isMac, joinHotKeys, META_SYM, SHIFT_SYM } from '../../common/constants';
import type { KeyBindings } from '../../common/hotkeys';
import * as hotkeys from '../../common/hotkeys';
import { ALT_SYM, CTRL_SYM, isMac, joinHotKeys, MOD_SYM, SHIFT_SYM } from '../../common/constants';
type Props = {
hotkey: HotkeyType,
keyBindings: KeyBindings,
// Optional
className?: string,
@@ -14,22 +14,18 @@ type Props = {
class Hotkey extends React.PureComponent<Props> {
render() {
const { hotkey, className } = this.props;
const { alt, shift, meta, metaIsCtrl } = hotkey;
const { keyBindings, className } = this.props;
const keyComb = hotkeys.getPlatformKeyCombinations(keyBindings)[0];
const { ctrl, alt, shift, meta, keyCode } = keyComb;
const chars = [];
alt && chars.push(ALT_SYM);
shift && chars.push(SHIFT_SYM);
ctrl && chars.push(CTRL_SYM);
meta && chars.push(META_SYM);
if (meta) {
if (metaIsCtrl) {
chars.push(CTRL_SYM);
} else {
chars.push(isMac() ? MOD_SYM : CTRL_SYM);
}
}
chars.push(hotkeys.getChar(hotkey));
chars.push(hotkeys.getChar(keyCode));
return (
<span className={classnames(className, { 'font-normal': isMac() })}>
@@ -137,7 +137,7 @@ class SettingsModal extends PureComponent {
<Theme handleChangeTheme={this._handleChangeTheme} activeTheme={settings.theme} />
</TabPanel>
<TabPanel className="react-tabs__tab-panel pad scrollable">
<SettingsShortcuts />
<SettingsShortcuts hotKeyRegistry={settings.hotKeyRegistry} />
</TabPanel>
<TabPanel className="react-tabs__tab-panel pad scrollable">
<Account />
@@ -29,8 +29,8 @@ import { showModal } from './modals/index';
import RequestSettingsModal from './modals/request-settings-modal';
import MarkdownPreview from './markdown-preview';
import type { Settings } from '../../models/settings';
import * as hotkeys from '../../common/hotkeys';
import ErrorBoundary from './error-boundary';
import { hotKeyRefs } from '../../common/hotkeys';
type Props = {
// Functions
@@ -171,38 +171,42 @@ class RequestPane extends React.PureComponent<Props> {
const paneHeaderClasses = 'pane__header theme--pane__header';
const paneBodyClasses = 'pane__body theme--pane__body';
const hotKeyRegistry = settings.hotKeyRegistry;
if (!request) {
return (
<section className={paneClasses}>
<header className={paneHeaderClasses}/>
<header className={paneHeaderClasses} />
<div className={paneBodyClasses + ' pane__body--placeholder'}>
<div>
<table className="table--fancy">
<tbody>
<tr>
<td>New Request</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.CREATE_REQUEST}/>
</code>
</td>
</tr>
<tr>
<td>Switch Requests</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.SHOW_QUICK_SWITCHER}/>
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.SHOW_ENVIRONMENTS}/>
</code>
</td>
</tr>
<tr>
<td>New Request</td>
<td className="text-right">
<code>
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE.id]} />
</code>
</td>
</tr>
<tr>
<td>Switch Requests</td>
<td className="text-right">
<code>
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_QUICK_SWITCH.id]} />
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
/>
</code>
</td>
</tr>
</tbody>
</table>
@@ -251,6 +255,7 @@ class RequestPane extends React.PureComponent<Props> {
isVariableUncovered={isVariableUncovered}
handleGetRenderContext={handleGetRenderContext}
request={request}
hotKeyRegistry={settings.hotKeyRegistry}
/>
</ErrorBoundary>
</header>
@@ -266,7 +271,7 @@ class RequestPane extends React.PureComponent<Props> {
? getContentTypeName(request.body.mimeType)
: 'Body'}
{numBodyParams ? <span className="bubble space-left">{numBodyParams}</span> : null}
<i className="fa fa-caret-down space-left"/>
<i className="fa fa-caret-down space-left" />
</ContentTypeDropdown>
</Tab>
<Tab tabIndex="-1">
@@ -275,7 +280,7 @@ class RequestPane extends React.PureComponent<Props> {
request={request}
className="tall">
{getAuthTypeName(request.authentication.type) || 'Auth'}
<i className="fa fa-caret-down space-left"/>
<i className="fa fa-caret-down space-left" />
</AuthDropdown>
</Tab>
<Tab tabIndex="-1">
@@ -295,7 +300,7 @@ class RequestPane extends React.PureComponent<Props> {
Docs
{request.description && (
<span className="bubble space-left">
<i className="fa fa--skinny fa-check txt-xxs"/>
<i className="fa fa--skinny fa-check txt-xxs" />
</span>
)}
</button>
@@ -341,7 +346,7 @@ class RequestPane extends React.PureComponent<Props> {
<ErrorBoundary
key={uniqueKey}
errorClassName="tall wide vertically-align font-error pad text-center">
<RenderedQueryString handleRender={handleRender} request={request}/>
<RenderedQueryString handleRender={handleRender} request={request} />
</ErrorBoundary>
</code>
</div>
@@ -419,10 +424,10 @@ class RequestPane extends React.PureComponent<Props> {
<div className="overflow-hidden editor vertically-center text-center">
<p className="pad text-sm text-center">
<span className="super-faint">
<i className="fa fa-file-text-o" style={{ fontSize: '8rem', opacity: 0.3 }}/>
<i className="fa fa-file-text-o" style={{ fontSize: '8rem', opacity: 0.3 }} />
</span>
<br/>
<br/>
<br />
<br />
<button
className="btn btn--clicky faint"
onClick={this._handleEditDescriptionAdd}>
@@ -14,9 +14,11 @@ import { showPrompt } from './modals/index';
import MethodDropdown from './dropdowns/method-dropdown';
import PromptButton from './base/prompt-button';
import OneLineEditor from './codemirror/one-line-editor';
import * as hotkeys from '../../common/hotkeys';
import KeydownBinder from './keydown-binder';
import type { Request } from '../../models/request';
import type { HotKeyRegistry } from '../../common/hotkeys';
import { hotKeyRefs } from '../../common/hotkeys';
import { executeHotKey } from '../../common/hotkeys-listener';
type Props = {
handleAutocompleteUrls: Function,
@@ -32,6 +34,7 @@ type Props = {
onUrlChange: (r: Request, url: string) => Promise<Request>,
request: Request,
uniquenessKey: string,
hotKeyRegistry: HotKeyRegistry,
};
type State = {
@@ -142,21 +145,21 @@ class RequestUrlBar extends React.PureComponent<Props, State> {
this.setState({ downloadPath: null });
}
_handleKeyDown(e: KeyboardEvent) {
async _handleKeyDown(e: KeyboardEvent) {
if (!this._input) {
return;
}
hotkeys.executeHotKey(e, hotkeys.FOCUS_URL, () => {
executeHotKey(e, hotKeyRefs.REQUEST_FOCUS_URL, () => {
this._input && this._input.focus();
this._input && this._input.selectAll();
});
hotkeys.executeHotKey(e, hotkeys.TOGGLE_METHOD_DROPDOWN, () => {
executeHotKey(e, hotKeyRefs.REQUEST_TOGGLE_HTTP_METHOD_MENU, () => {
this._methodDropdown && this._methodDropdown.toggle();
});
hotkeys.executeHotKey(e, hotkeys.SHOW_SEND_OPTIONS, () => {
executeHotKey(e, hotKeyRefs.REQUEST_SHOW_OPTIONS, () => {
this._dropdown && this._dropdown.toggle(true);
});
}
@@ -248,6 +251,7 @@ class RequestUrlBar extends React.PureComponent<Props, State> {
}
renderSendButton() {
const { hotKeyRegistry } = this.props;
const { currentInterval, currentTimeout, downloadPath } = this.state;
let cancelButton = null;
@@ -287,7 +291,7 @@ class RequestUrlBar extends React.PureComponent<Props, State> {
<DropdownDivider>Basic</DropdownDivider>
<DropdownItem onClick={this._handleClickSend}>
<i className="fa fa-arrow-circle-o-right" /> Send Now
<DropdownHint hotkey={hotkeys.SEND_REQUEST} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SEND.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleGenerateCode}>
<i className="fa fa-code" /> Generate Client Code
@@ -24,8 +24,9 @@ import { PREVIEW_MODE_SOURCE } from '../../common/constants';
import { getSetCookieHeaders, nullFn } from '../../common/misc';
import { cancelCurrentRequest } from '../../network/network';
import Hotkey from './hotkey';
import * as hotkeys from '../../common/hotkeys';
import ErrorBoundary from './error-boundary';
import type { HotKeyRegistry } from '../../common/hotkeys';
import { hotKeyRefs } from '../../common/hotkeys';
type Props = {
// Functions
@@ -47,6 +48,7 @@ type Props = {
editorLineWrapping: boolean,
loadStartTime: number,
responses: Array<Response>,
hotKeyRegistry: HotKeyRegistry,
// Other
request: ?Request,
@@ -170,6 +172,7 @@ class ResponsePane extends React.PureComponent<Props> {
filter,
filterHistory,
showCookiesModal,
hotKeyRegistry,
} = this.props;
const paneClasses = 'response-pane theme--pane pane';
@@ -197,7 +200,7 @@ class ResponsePane extends React.PureComponent<Props> {
<td>Send Request</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.SEND_REQUEST} />
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SEND.id]} />
</code>
</td>
</tr>
@@ -205,7 +208,7 @@ class ResponsePane extends React.PureComponent<Props> {
<td>Focus Url Bar</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.FOCUS_URL} />
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_FOCUS_URL.id]} />
</code>
</td>
</tr>
@@ -213,7 +216,7 @@ class ResponsePane extends React.PureComponent<Props> {
<td>Manage Cookies</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.SHOW_COOKIES} />
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.SHOW_COOKIES_EDITOR.id]} />
</code>
</td>
</tr>
@@ -221,7 +224,9 @@ class ResponsePane extends React.PureComponent<Props> {
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkeys.SHOW_ENVIRONMENTS} />
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
/>
</code>
</td>
</tr>
@@ -9,6 +9,10 @@ import {
isWindows,
UPDATE_CHANNEL_BETA,
UPDATE_CHANNEL_STABLE,
EDITOR_KEY_MAP_DEFAULT,
EDITOR_KEY_MAP_EMACS,
EDITOR_KEY_MAP_SUBLIME,
EDITOR_KEY_MAP_VIM,
} from '../../../common/constants';
import type { Settings } from '../../../models/settings';
import CheckForUpdatesButton from '../check-for-updates-button';
@@ -331,10 +335,10 @@ class General extends React.PureComponent<Props, State> {
defaultValue={settings.editorKeyMap}
name="editorKeyMap"
onChange={this._handleUpdateSetting}>
<option value="default">Default</option>
<option value="vim">Vim</option>
<option value="emacs">Emacs</option>
<option value="sublime">Sublime</option>
<option value={EDITOR_KEY_MAP_DEFAULT}>Default</option>
<option value={EDITOR_KEY_MAP_VIM}>Vim</option>
<option value={EDITOR_KEY_MAP_EMACS}>Emacs</option>
<option value={EDITOR_KEY_MAP_SUBLIME}>Sublime</option>
</select>
</label>
</div>
@@ -1,17 +1,23 @@
// @flow
import React, { PureComponent } from 'react';
import autobind from 'autobind-decorator';
import Hotkey from '../hotkey';
import * as hotkeys from '../../../common/hotkeys';
import type { HotKeyDefinition, HotKeyRegistry } from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
type Props = {
hotKeyRegistry: HotKeyRegistry,
};
@autobind
class Shortcuts extends PureComponent {
renderHotkey(hotkey, i) {
class Shortcuts extends PureComponent<Props> {
renderHotKey(def: HotKeyDefinition, i: number) {
return (
<tr key={i}>
<td>{hotkey.description}</td>
<td>{def.description}</td>
<td className="text-right">
<code>
<Hotkey hotkey={hotkey} />
<Hotkey keyBindings={this.props.hotKeyRegistry[def.id]} />
</code>
</td>
</tr>
@@ -19,33 +25,38 @@ class Shortcuts extends PureComponent {
}
render() {
const hotKeyDefs: Array<HotKeyDefinition> = [
hotKeyRefs.PREFERENCES_SHOW_KEYBOARD_SHORTCUTS,
hotKeyRefs.REQUEST_QUICK_SWITCH,
hotKeyRefs.REQUEST_SEND,
hotKeyRefs.REQUEST_SHOW_OPTIONS,
hotKeyRefs.REQUEST_SHOW_CREATE,
hotKeyRefs.REQUEST_SHOW_DELETE,
hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER,
hotKeyRefs.REQUEST_SHOW_DUPLICATE,
hotKeyRefs.SHOW_COOKIES_EDITOR,
hotKeyRefs.ENVIRONMENT_SHOW_EDITOR,
hotKeyRefs.ENVIRONMENT_SHOW_SWITCH_MENU,
hotKeyRefs.REQUEST_FOCUS_URL,
hotKeyRefs.RESPONSE_FOCUS,
hotKeyRefs.REQUEST_TOGGLE_HTTP_METHOD_MENU,
hotKeyRefs.SIDEBAR_TOGGLE,
hotKeyRefs.REQUEST_TOGGLE_HISTORY,
hotKeyRefs.SHOW_AUTOCOMPLETE,
hotKeyRefs.PREFERENCES_SHOW_GENERAL,
hotKeyRefs.WORKSPACE_SHOW_SETTINGS,
hotKeyRefs.REQUEST_SHOW_SETTINGS,
hotKeyRefs.TOGGLE_MAIN_MENU,
hotKeyRefs.PLUGIN_RELOAD,
hotKeyRefs.ENVIRONMENT_UNCOVER_VARIABLES,
];
return (
<div>
<table className="table--fancy">
<tbody>
{this.renderHotkey(hotkeys.SHOW_KEYBOARD_SHORTCUTS)}
{this.renderHotkey(hotkeys.SHOW_QUICK_SWITCHER)}
{this.renderHotkey(hotkeys.SEND_REQUEST)}
{this.renderHotkey(hotkeys.SHOW_SEND_OPTIONS)}
{this.renderHotkey(hotkeys.CREATE_REQUEST)}
{this.renderHotkey(hotkeys.DELETE_REQUEST)}
{this.renderHotkey(hotkeys.CREATE_FOLDER)}
{this.renderHotkey(hotkeys.DUPLICATE_REQUEST)}
{this.renderHotkey(hotkeys.SHOW_COOKIES)}
{this.renderHotkey(hotkeys.SHOW_ENVIRONMENTS)}
{this.renderHotkey(hotkeys.TOGGLE_ENVIRONMENTS_MENU)}
{this.renderHotkey(hotkeys.FOCUS_URL)}
{this.renderHotkey(hotkeys.FOCUS_RESPONSE)}
{this.renderHotkey(hotkeys.TOGGLE_METHOD_DROPDOWN)}
{this.renderHotkey(hotkeys.TOGGLE_SIDEBAR)}
{this.renderHotkey(hotkeys.TOGGLE_HISTORY_DROPDOWN)}
{this.renderHotkey(hotkeys.SHOW_AUTOCOMPLETE)}
{this.renderHotkey(hotkeys.SHOW_SETTINGS)}
{this.renderHotkey(hotkeys.SHOW_WORKSPACE_SETTINGS)}
{this.renderHotkey(hotkeys.SHOW_REQUEST_SETTINGS)}
{this.renderHotkey(hotkeys.TOGGLE_MAIN_MENU)}
{this.renderHotkey(hotkeys.RELOAD_PLUGINS)}
{this.renderHotkey(hotkeys.UNCOVER_VARIABLES)}
{hotKeyDefs.map((def: HotKeyDefinition, idx: number) => {
return this.renderHotKey(def, idx);
})}
</tbody>
</table>
</div>
@@ -6,6 +6,7 @@ import * as models from '../../../models/index';
import type { RequestGroup } from '../../../models/request-group';
import type { Workspace } from '../../../models/workspace';
import type { Request } from '../../../models/request';
import type { HotKeyRegistry } from '../../../common/hotkeys';
type Child = {
doc: Request | RequestGroup,
@@ -29,6 +30,7 @@ type Props = {
childObjects: Array<Child>,
workspace: Workspace,
filter: string,
hotKeyRegistry: HotKeyRegistry,
// Optional
activeRequest?: Request,
@@ -50,6 +52,7 @@ class SidebarChildren extends React.PureComponent<Props> {
handleActivateRequest,
activeRequest,
workspace,
hotKeyRegistry,
} = this.props;
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
@@ -73,6 +76,7 @@ class SidebarChildren extends React.PureComponent<Props> {
isActive={child.doc._id === activeRequestId}
request={child.doc}
workspace={workspace}
hotKeyRegistry={hotKeyRegistry}
/>
);
}
@@ -113,6 +117,7 @@ class SidebarChildren extends React.PureComponent<Props> {
numChildren={child.children.length}
workspace={workspace}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry}
children={children}
/>
);
@@ -4,13 +4,16 @@ import autobind from 'autobind-decorator';
import { Dropdown, DropdownHint, DropdownButton, DropdownItem } from '../base/dropdown';
import { DEBOUNCE_MILLIS } from '../../../common/constants';
import KeydownBinder from '../keydown-binder';
import * as hotkeys from '../../../common/hotkeys';
import type { HotKeyRegistry } from '../../../common/hotkeys';
import { hotKeyRefs } from '../../../common/hotkeys';
import { executeHotKey } from '../../../common/hotkeys-listener';
type Props = {
onChange: string => void,
requestCreate: () => void,
requestGroupCreate: () => void,
filter: string,
hotKeyRegistry: HotKeyRegistry,
};
@autobind
@@ -48,13 +51,13 @@ class SidebarFilter extends React.PureComponent<Props> {
}
_handleKeydown(e: KeyboardEvent) {
hotkeys.executeHotKey(e, hotkeys.FOCUS_FILTER, () => {
executeHotKey(e, hotKeyRefs.SIDEBAR_FOCUS_FILTER, () => {
this._input && this._input.focus();
});
}
render() {
const { filter } = this.props;
const { filter, hotKeyRegistry } = this.props;
return (
<KeydownBinder onKeydown={this._handleKeydown}>
<div className="sidebar__filter">
@@ -79,11 +82,13 @@ class SidebarFilter extends React.PureComponent<Props> {
</DropdownButton>
<DropdownItem onClick={this._handleRequestCreate}>
<i className="fa fa-plus-circle" /> New Request
<DropdownHint hotkey={hotkeys.CREATE_REQUEST} />
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleRequestGroupCreate}>
<i className="fa fa-folder" /> New Folder
<DropdownHint hotkey={hotkeys.CREATE_FOLDER} />
<DropdownHint
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]}
/>
</DropdownItem>
</Dropdown>
</div>
@@ -55,6 +55,7 @@ class SidebarRequestGroupRow extends PureComponent {
isDragging,
isDraggingOver,
workspace,
hotKeyRegistry,
} = this.props;
const { dragDirection } = this.state;
@@ -98,6 +99,7 @@ class SidebarRequestGroupRow extends PureComponent {
handleMoveRequestGroup={handleMoveRequestGroup}
workspace={workspace}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry}
right
/>
</div>
@@ -122,6 +124,7 @@ class SidebarRequestGroupRow extends PureComponent {
workspace={workspace}
requestCreate={handleCreateRequest}
filter={filter}
hotKeyRegistry={hotKeyRegistry}
/>
)}
</ul>
@@ -146,6 +149,7 @@ SidebarRequestGroupRow.propTypes = {
isCollapsed: PropTypes.bool.isRequired,
workspace: PropTypes.object.isRequired,
requestGroup: PropTypes.object.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
// React DnD
isDragging: PropTypes.bool,
@@ -78,6 +78,7 @@ class SidebarRequestRow extends PureComponent {
request,
requestGroup,
isActive,
hotKeyRegistry,
} = this.props;
const { dragDirection } = this.state;
@@ -134,6 +135,7 @@ class SidebarRequestRow extends PureComponent {
handleShowSettings={this._handleShowRequestSettings}
request={request}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry}
/>
</div>
</div>
@@ -161,6 +163,7 @@ SidebarRequestRow.propTypes = {
// Other
filter: PropTypes.string.isRequired,
isActive: PropTypes.bool.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
// React DnD
isDragging: PropTypes.bool,
@@ -55,6 +55,7 @@ class Sidebar extends PureComponent {
handleActivateRequest,
activeRequest,
environmentHighlightColorStyle,
hotKeyRegistry,
} = this.props;
return (
@@ -77,6 +78,7 @@ class Sidebar extends PureComponent {
activeWorkspace={workspace}
workspaces={workspaces}
unseenWorkspaces={unseenWorkspaces}
hotKeyRegistry={hotKeyRegistry}
handleExportFile={handleExportFile}
handleImportFile={handleImportFile}
handleSetActiveWorkspace={handleSetActiveWorkspace}
@@ -90,6 +92,7 @@ class Sidebar extends PureComponent {
environments={environments}
workspace={workspace}
environmentHighlightColorStyle={environmentHighlightColorStyle}
hotKeyRegistry={hotKeyRegistry}
/>
<button className="btn btn--super-compact" onClick={showCookiesModal}>
<div className="sidebar__menu__thing">
@@ -104,6 +107,7 @@ class Sidebar extends PureComponent {
requestCreate={this._handleCreateRequestInWorkspace}
requestGroupCreate={this._handleCreateRequestGroupInWorkspace}
filter={filter || ''}
hotKeyRegistry={hotKeyRegistry}
/>
<SidebarChildren
@@ -121,6 +125,7 @@ class Sidebar extends PureComponent {
workspace={workspace}
activeRequest={activeRequest}
filter={filter || ''}
hotKeyRegistry={hotKeyRegistry}
/>
<SyncButton className="sidebar__footer" key={workspace._id} workspace={workspace} />
@@ -159,6 +164,7 @@ Sidebar.propTypes = {
unseenWorkspaces: PropTypes.arrayOf(PropTypes.object).isRequired,
environments: PropTypes.arrayOf(PropTypes.object).isRequired,
environmentHighlightColorStyle: PropTypes.string.isRequired,
hotKeyRegistry: PropTypes.object.isRequired,
// Optional
filter: PropTypes.string,
@@ -16,8 +16,9 @@ import {
PREVIEW_MODE_FRIENDLY,
PREVIEW_MODE_RAW,
} from '../../../common/constants';
import * as hotkeys from '../../../common/hotkeys';
import KeydownBinder from '../keydown-binder';
import { executeHotKey } from '../../../common/hotkeys-listener';
import { hotKeyRefs } from '../../../common/hotkeys';
let alwaysShowLargeResponses = false;
@@ -180,7 +181,7 @@ class ResponseViewer extends React.Component<Props, State> {
return;
}
hotkeys.executeHotKey(e, hotkeys.FOCUS_RESPONSE, () => {
executeHotKey(e, hotKeyRefs.RESPONSE_FOCUS, () => {
if (!this._isViewSelectable()) {
return;
}
@@ -633,6 +633,7 @@ class Wrapper extends React.PureComponent<Props, State> {
workspaces={workspaces}
environments={environments}
environmentHighlightColorStyle={settings.environmentHighlightColorStyle}
hotKeyRegistry={settings.hotKeyRegistry}
/>
</ErrorBoundary>
@@ -697,6 +698,7 @@ class Wrapper extends React.PureComponent<Props, State> {
editorIndentSize={settings.editorIndentSize}
editorKeyMap={settings.editorKeyMap}
editorLineWrapping={settings.editorLineWrapping}
hotKeyRegistry={settings.hotKeyRegistry}
previewMode={responsePreviewMode}
filter={responseFilter}
filterHistory={responseFilterHistory}
+16 -16
View File
@@ -58,7 +58,8 @@ import * as render from '../../common/render';
import { getKeys } from '../../templating/utils';
import { showAlert, showModal, showPrompt } from '../components/modals/index';
import { exportHarRequest } from '../../common/har';
import * as hotkeys from '../../common/hotkeys';
import { hotKeyRefs } from '../../common/hotkeys';
import { executeHotKey } from '../../common/hotkeys-listener';
import KeydownBinder from '../components/keydown-binder';
import ErrorBoundary from '../components/error-boundary';
import * as plugins from '../../plugins';
@@ -100,20 +101,20 @@ class App extends PureComponent {
_setGlobalKeyMap() {
this._globalKeyMap = [
[
hotkeys.SHOW_KEYBOARD_SHORTCUTS,
hotKeyRefs.PREFERENCES_SHOW_KEYBOARD_SHORTCUTS,
() => {
showModal(SettingsModal, TAB_INDEX_SHORTCUTS);
},
],
[
hotkeys.SHOW_WORKSPACE_SETTINGS,
hotKeyRefs.WORKSPACE_SHOW_SETTINGS,
() => {
const { activeWorkspace } = this.props;
showModal(WorkspaceSettingsModal, activeWorkspace);
},
],
[
hotkeys.SHOW_REQUEST_SETTINGS,
hotKeyRefs.REQUEST_SHOW_SETTINGS,
() => {
if (this.props.activeRequest) {
showModal(RequestSettingsModal, {
@@ -123,29 +124,28 @@ class App extends PureComponent {
},
],
[
hotkeys.SHOW_QUICK_SWITCHER,
hotKeyRefs.REQUEST_QUICK_SWITCH,
() => {
showModal(RequestSwitcherModal);
},
],
[hotkeys.SEND_REQUEST, this._handleSendShortcut],
[hotkeys.SEND_REQUEST_F5, this._handleSendShortcut],
[hotKeyRefs.REQUEST_SEND, this._handleSendShortcut],
[
hotkeys.SHOW_ENVIRONMENTS,
hotKeyRefs.ENVIRONMENT_SHOW_EDITOR,
() => {
const { activeWorkspace } = this.props;
showModal(WorkspaceEnvironmentsEditModal, activeWorkspace);
},
],
[
hotkeys.SHOW_COOKIES,
hotKeyRefs.SHOW_COOKIES_EDITOR,
() => {
const { activeWorkspace } = this.props;
showModal(CookiesModal, activeWorkspace);
},
],
[
hotkeys.CREATE_REQUEST,
hotKeyRefs.REQUEST_SHOW_CREATE,
() => {
const { activeRequest, activeWorkspace } = this.props;
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
@@ -153,7 +153,7 @@ class App extends PureComponent {
},
],
[
hotkeys.DELETE_REQUEST,
hotKeyRefs.REQUEST_SHOW_DELETE,
() => {
const { activeRequest } = this.props;
@@ -174,7 +174,7 @@ class App extends PureComponent {
},
],
[
hotkeys.CREATE_FOLDER,
hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER,
() => {
const { activeRequest, activeWorkspace } = this.props;
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
@@ -182,19 +182,19 @@ class App extends PureComponent {
},
],
[
hotkeys.GENERATE_CODE,
hotKeyRefs.REQUEST_SHOW_GENERATE_CODE_EDITOR,
async () => {
showModal(GenerateCodeModal, this.props.activeRequest);
},
],
[
hotkeys.DUPLICATE_REQUEST,
hotKeyRefs.REQUEST_SHOW_DUPLICATE,
async () => {
await this._requestDuplicate(this.props.activeRequest);
},
],
[
hotkeys.UNCOVER_VARIABLES,
hotKeyRefs.ENVIRONMENT_UNCOVER_VARIABLES,
async () => {
await this._updateIsVariableUncovered();
},
@@ -743,7 +743,7 @@ class App extends PureComponent {
_handleKeyDown(e) {
for (const [definition, callback] of this._globalKeyMap) {
hotkeys.executeHotKey(e, definition, callback);
executeHotKey(e, definition, callback);
}
}
+745 -919
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -180,9 +180,9 @@
"cross-env": "^2.0.0",
"css-loader": "^0.28.11",
"electron": "^3.0.4",
"electron-builder": "^20.20.4",
"electron-builder-lib": "^20.20.4",
"electron-builder-squirrel-windows": "^20.20.4",
"electron-builder": "^20.38.5",
"electron-builder-lib": "^20.23.1",
"electron-builder-squirrel-windows": "^20.38.5",
"electron-rebuild": "^1.8.2",
"eslint": "^4.19.1",
"eslint-config-semistandard": "^12.0.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-cookies",
"version": "0.0.11",
"version": "0.0.13",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-httpsnippet",
"version": "1.16.17",
"version": "1.16.19",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -0,0 +1,84 @@
/**
* @description
* HTTP code snippet generator for the browser Fetch API
*
* @author
* @peoplenarthax
*
* for any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
*/
'use strict';
var util = require('util');
var CodeBuilder = require('../../helpers/code-builder');
module.exports = function(source, options) {
var opts = util._extend(
{
indent: ' ',
},
options,
);
var code = new CodeBuilder(opts.indent);
var url = source.fullUrl;
var fetchOptions = {
mode: 'cors',
method: source.method,
headers: source.allHeaders,
};
switch (source.postData.mimeType) {
case 'application/x-www-form-urlencoded':
fetchOptions.body = source.postData.paramsObj
? source.postData.paramsObj
: source.postData.text;
break;
case 'application/json':
fetchOptions.body = source.postData.text;
break;
case 'multipart/form-data':
code.push('let form = new FormData();');
source.postData.params.forEach(function(param) {
code.push(
'form.append(%s, %s);',
JSON.stringify(param.name),
JSON.stringify(param.value || param.fileName || ''),
);
});
delete fetchOptions.headers;
fetchOptions.body = '[form]';
code.blank();
break;
default:
if (source.postData.text) {
fetchOptions.data = source.postData.text;
}
}
code
.push(
'const fetchOptions = ' +
JSON.stringify(fetchOptions, null, opts.indent).replace('"[form]"', 'form'),
)
.blank()
.push('fetch("' + url + '", fetchOptions)')
.push(1, '.then(response => response.json())')
.push(1, '.then(data => console.log(data));');
return code.join();
};
module.exports.info = {
key: 'fetch',
title: 'Fetch API',
link: 'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API',
description: 'Browser API that offers a simple interface for fetching resources',
};
@@ -9,5 +9,6 @@ module.exports = {
},
jquery: require('./jquery'),
fetch: require('./fetch'),
xhr: require('./xhr'),
};
@@ -1,6 +1,6 @@
/**
* @description
* HTTP code snippet generator for native XMLHttpRequest
* HTTP code snippet generator for jQuery
*
* @author
* @AhmadNassri
@@ -63,6 +63,12 @@
"link": "http://api.jquery.com/jquery.ajax/",
"description": "Perform an asynchronous HTTP (Ajax) requests with jQuery"
},
{
"key": "fetch",
"title": "Fetch API",
"link": "https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API",
"description": "Browser API that offers a simple interface for fetching resources"
},
{
"key": "xhr",
"title": "XMLHttpRequest",
@@ -137,7 +143,7 @@
"extname": ".m",
"default": "nsurlsession",
"clients": [
{
{
"key": "nsurlsession",
"title": "NSURLSession",
"link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html",
@@ -151,7 +157,7 @@
"extname": ".swift",
"default": "nsurlsession",
"clients": [
{
{
"key": "nsurlsession",
"title": "NSURLSession",
"link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html",
@@ -165,7 +171,7 @@
"extname": ".go",
"default": "native",
"clients": [
{
{
"key": "native",
"title": "NewRequest",
"link": "http://golang.org/pkg/net/http/#NewRequest",
@@ -0,0 +1,15 @@
const fetchOptions = {
mode: 'cors',
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: {
foo: 'bar',
hello: 'world',
},
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,13 @@
const fetchOptions = {
mode: 'cors',
method: 'POST',
headers: {
'content-type': 'application/json',
},
body:
'{"number":1,"string":"f\\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}',
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,11 @@
const fetchOptions = {
mode: 'cors',
method: 'POST',
headers: {
cookie: 'foo=bar; bar=baz',
},
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,9 @@
const fetchOptions = {
mode: 'cors',
method: 'PROPFIND',
headers: {},
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,16 @@
const fetchOptions = {
mode: 'cors',
method: 'POST',
headers: {
cookie: 'foo=bar; bar=baz',
accept: 'application/json',
'content-type': 'application/x-www-form-urlencoded',
},
body: {
foo: 'bar',
},
};
fetch('http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,12 @@
const fetchOptions = {
mode: 'cors',
method: 'GET',
headers: {
accept: 'application/json',
'x-foo': 'Bar',
},
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,9 @@
const fetchOptions = {
mode: 'cors',
method: 'GET',
headers: {},
};
fetch('https://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,12 @@
let form = new FormData();
form.append('foo', 'Hello World');
const fetchOptions = {
mode: 'cors',
method: 'POST',
body: form,
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,12 @@
let form = new FormData();
form.append('foo', 'test/fixtures/files/hello.txt');
const fetchOptions = {
mode: 'cors',
method: 'POST',
body: form,
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,12 @@
let form = new FormData();
form.append('foo', 'bar');
const fetchOptions = {
mode: 'cors',
method: 'POST',
body: form,
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,9 @@
const fetchOptions = {
mode: 'cors',
method: 'GET',
headers: {},
};
fetch('http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,9 @@
const fetchOptions = {
mode: 'cors',
method: 'GET',
headers: {},
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,12 @@
const fetchOptions = {
mode: 'cors',
method: 'POST',
headers: {
'content-type': 'text/plain',
},
data: 'Hello World',
};
fetch('http://mockbin.com/har', fetchOptions)
.then(response => response.json())
.then(data => console.log(data));
@@ -0,0 +1,3 @@
'use strict';
module.exports = function(snippet, fixtures) {};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-importers",
"version": "2.0.12",
"version": "2.0.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-libcurl",
"version": "0.0.22",
"version": "0.0.24",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-xpath",
"version": "1.0.8",
"version": "1.0.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -19,12 +19,19 @@ function assertTemplateFails(args, expected) {
}
describe('Base64EncodeExtension', () => {
it('encodes nothing', assertTemplate(['encode'], ''));
it('encodes something', assertTemplate(['encode', 'my string'], 'bXkgc3RyaW5n'));
it('decodes nothing', assertTemplate(['decode'], ''));
it('decodes something', assertTemplate(['decode', 'bXkgc3RyaW5n'], 'my string'));
it('encodes nothing', assertTemplate(['encode', 'normal', ''], ''));
it('encodes something', assertTemplate(['encode', 'normal', 'my string'], 'bXkgc3RyaW5n'));
it('urlencodes nothing', assertTemplate(['encode', 'url', ''], ''));
it('urlencodes something', assertTemplate(['encode', 'url', 'hello world'], 'aGVsbG8gd29ybGQ'));
it('decodes nothing', assertTemplate(['decode', 'normal', ''], ''));
it('decodes something', assertTemplate(['decode', 'normal', 'bXkgc3RyaW5n'], 'my string'));
it('urldecodes nothing', assertTemplate(['decode', 'url', ''], ''));
it('urldecodes something', assertTemplate(['decode', 'url', 'aGVsbG8gd29ybGQ'], 'hello world'));
it(
'fails on invalid op',
assertTemplateFails(['foo'], 'Unsupported operation "foo". Must be encode or decode.'),
'fails on invalid action',
assertTemplateFails(
['foo', 'normal', ''],
'Unsupported operation "foo". Must be encode or decode.',
),
);
});
+18 -5
View File
@@ -12,21 +12,34 @@ module.exports.templateTags = [
{ displayName: 'Decode', value: 'decode' },
],
},
{
displayName: 'Kind',
type: 'enum',
options: [{ displayName: 'Normal', value: 'normal' }, { displayName: 'URL', value: 'url' }],
},
{
displayName: 'Value',
type: 'string',
placeholder: 'My text',
},
],
run(context, op, text) {
run(context, action, kind, text) {
text = text || '';
if (op === 'encode') {
return Buffer.from(text, 'utf8').toString('base64');
} else if (op === 'decode') {
if (action === 'encode') {
if (kind === 'normal') {
return Buffer.from(text, 'utf8').toString('base64');
} else if (kind === 'url') {
return Buffer.from(text, 'utf8')
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
} else if (action === 'decode') {
return Buffer.from(text, 'base64').toString('utf8');
} else {
throw new Error('Unsupported operation "' + op + '". Must be encode or decode.');
throw new Error('Unsupported operation "' + action + '". Must be encode or decode.');
}
},
},
+1 -1
View File
@@ -14,6 +14,6 @@
"description": "Encode/Decode base64 strings"
},
"scripts": {
"test": "node --version"
"test": "jest --silent"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-cookie-jar",
"version": "1.0.7",
"version": "1.0.9",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-jsonpath",
"version": "1.0.11",
"version": "1.0.13",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-now",
"version": "1.0.10",
"version": "1.0.12",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-os",
"version": "1.0.12",
"version": "1.0.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -31,7 +31,7 @@ module.exports.templateTags = [
description: 'fully qualified URL',
},
{
displayName: 'Query Paramter',
displayName: 'Query Parameter',
value: 'parameter',
description: 'query parameter by name',
},
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-response",
"version": "1.0.15",
"version": "1.0.17",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "insomnia-plugin-uuid",
"version": "1.0.9",
"version": "1.0.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {