diff --git a/README.md b/README.md index f58190116a..3f3bad5e8d 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ the following tools: Here is a list of plugins available for installation via NPM. - [Chance](https://www.npmjs.com/package/insomnia-plugin-chance) – Generates a random value using Chance.JS +- [Cuid](https://www.npmjs.com/package/insomnia-plugin-cuid) – Generate random cuids - [Custom Timestamp](https://www.npmjs.com/package/insomnia-plugin-customtimestamp) – Advanced timestamp creator - [Default Headers](https://www.npmjs.com/package/insomnia-plugin-default-headers) – Set default headers on requests - [Defaults](https://www.npmjs.com/package/insomnia-plugin-defaults) - Set request defaults through your environment diff --git a/packages/insomnia-app/app/models/settings.js b/packages/insomnia-app/app/models/settings.js index f146bea1f7..9310f99461 100644 --- a/packages/insomnia-app/app/models/settings.js +++ b/packages/insomnia-app/app/models/settings.js @@ -29,6 +29,7 @@ type BaseSettings = { updateAutomatically: boolean, disableUpdateNotification: boolean, environmentHighlightColorStyle: string, + autocompleteDelay: number, fontMonospace: string | null, fontInterface: string | null, fontSize: number, @@ -69,6 +70,7 @@ export function init(): BaseSettings { updateAutomatically: true, disableUpdateNotification: false, environmentHighlightColorStyle: 'sidebar-indicator', + autocompleteDelay: 700, fontMonospace: null, fontInterface: null, fontSize: 13, diff --git a/packages/insomnia-app/app/network/o-auth-2/get-token.js b/packages/insomnia-app/app/network/o-auth-2/get-token.js index 6a0d039cf8..a6824780d2 100644 --- a/packages/insomnia-app/app/network/o-auth-2/get-token.js +++ b/packages/insomnia-app/app/network/o-auth-2/get-token.js @@ -190,6 +190,12 @@ async function _getAccessToken( authentication.scope, ); + // If we didn't receive an access token it means the refresh token didn't succeed, + // so we tell caller to fetch brand new access and refresh tokens. + if (!refreshResults.access_token) { + return null; + } + // ~~~~~~~~~~~~~ // // Update the DB // // ~~~~~~~~~~~~~ // diff --git a/packages/insomnia-app/app/network/o-auth-2/refresh-token.js b/packages/insomnia-app/app/network/o-auth-2/refresh-token.js index 4c6bdfd415..465ae46de2 100644 --- a/packages/insomnia-app/app/network/o-auth-2/refresh-token.js +++ b/packages/insomnia-app/app/network/o-auth-2/refresh-token.js @@ -48,7 +48,14 @@ export default async function( }); const statusCode = response.statusCode || 0; - if (statusCode < 200 || statusCode >= 300) { + + if (statusCode === 401) { + // If the refresh token was rejected due an unauthorized request, we will + // return a null access_token to trigger an authentication request to fetch + // brand new refresh and access tokens. + + return responseToObject(null, [c.P_ACCESS_TOKEN]); + } else if (statusCode < 200 || statusCode >= 300) { throw new Error(`[oauth2] Failed to refresh token url=${url} status=${statusCode}`); } diff --git a/packages/insomnia-app/app/ui/components/codemirror/extensions/autocomplete.js b/packages/insomnia-app/app/ui/components/codemirror/extensions/autocomplete.js index 310013fcc8..280cde7d0b 100644 --- a/packages/insomnia-app/app/ui/components/codemirror/extensions/autocomplete.js +++ b/packages/insomnia-app/app/ui/components/codemirror/extensions/autocomplete.js @@ -1,5 +1,6 @@ import CodeMirror from 'codemirror'; import 'codemirror/addon/mode/overlay'; +import * as models from '../../../../models'; import { getDefaultFill } from '../../../../templating/utils'; import { escapeHTML, escapeRegex } from '../../../../common/misc'; @@ -11,7 +12,6 @@ const COMPLETE_AFTER_WORD = /[\w.\][-]+/; const COMPLETE_AFTER_CURLIES = /[^{]*{[{%]\s*/; const COMPLETION_CLOSE_KEYS = /[}|-]/; const MAX_HINT_LOOK_BACK = 100; -const HINT_DELAY_MILLIS = 700; const TYPE_VARIABLE = 'variable'; const TYPE_TAG = 'tag'; const TYPE_CONSTANT = 'constant'; @@ -126,7 +126,7 @@ CodeMirror.defineOption('environmentAutocomplete', null, (cm, options) => { let keydownDebounce = null; - cm.on('keydown', (cm, e) => { + cm.on('keydown', async (cm, e) => { // Close autocomplete on Escape if it's open if (cm.isHintDropdownActive() && e.key === 'Escape') { if (!cm.state.completionActive) { @@ -146,9 +146,14 @@ CodeMirror.defineOption('environmentAutocomplete', null, (cm, options) => { } clearTimeout(keydownDebounce); - keydownDebounce = setTimeout(() => { - completeIfInVariableName(cm); - }, HINT_DELAY_MILLIS); + + const { autocompleteDelay } = await models.settings.getOrCreate(); + + if (autocompleteDelay > 0) { + keydownDebounce = setTimeout(() => { + completeIfInVariableName(cm); + }, autocompleteDelay); + } }); // Clear timeout if we already closed the completion diff --git a/packages/insomnia-app/app/ui/components/modals/workspace-settings-modal.js b/packages/insomnia-app/app/ui/components/modals/workspace-settings-modal.js index c0c5c64a3d..72e873c22a 100644 --- a/packages/insomnia-app/app/ui/components/modals/workspace-settings-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/workspace-settings-modal.js @@ -27,6 +27,7 @@ type Props = { handleGetRenderContext: Function, handleRemoveWorkspace: Function, handleDuplicateWorkspace: Function, + handleClearAllResponses: Function, }; type State = { @@ -78,6 +79,11 @@ class WorkspaceSettingsModal extends React.PureComponent { this.hide(); } + _handleClearAllResponses() { + this.props.handleClearAllResponses(); + this.hide(); + } + _handleDuplicateWorkspace() { this.props.handleDuplicateWorkspace(() => { this.hide(); @@ -331,6 +337,12 @@ class WorkspaceSettingsModal extends React.PureComponent { className="width-auto btn btn--clicky inline-block space-left"> Duplicate + + Clear All Responses + diff --git a/packages/insomnia-app/app/ui/components/settings/general.js b/packages/insomnia-app/app/ui/components/settings/general.js index 3eaad45d7e..393284913d 100644 --- a/packages/insomnia-app/app/ui/components/settings/general.js +++ b/packages/insomnia-app/app/ui/components/settings/general.js @@ -209,22 +209,40 @@ class General extends React.PureComponent { -
- +
+
+ +
+
+ +
diff --git a/packages/insomnia-app/app/ui/components/wrapper.js b/packages/insomnia-app/app/ui/components/wrapper.js index c77a5c2738..ee82539892 100644 --- a/packages/insomnia-app/app/ui/components/wrapper.js +++ b/packages/insomnia-app/app/ui/components/wrapper.js @@ -43,6 +43,7 @@ import WorkspaceEnvironmentsEditModal from './modals/workspace-environments-edit import WorkspaceSettingsModal from './modals/workspace-settings-modal'; import WorkspaceShareSettingsModal from './modals/workspace-share-settings-modal'; import CodePromptModal from './modals/code-prompt-modal'; +import * as db from '../../common/database'; import * as models from '../../models/index'; import * as importers from 'insomnia-importers'; import type { CookieJar } from '../../models/cookie-jar'; @@ -304,6 +305,14 @@ class Wrapper extends React.PureComponent { await models.workspace.remove(activeWorkspace); } + async _handleActiveWorkspaceClearAllResponses(): Promise { + const docs = await db.withDescendants(this.props.activeWorkspace, models.request.type); + const requests = docs.filter(doc => doc.type === models.request.type); + for (const req of requests) { + await models.response.removeForRequest(req._id); + } + } + _handleSendRequestWithActiveEnvironment(): void { const { activeRequest, activeEnvironment, handleSendRequestWithEnvironment } = this.props; const activeRequestId = activeRequest ? activeRequest._id : 'n/a'; @@ -320,7 +329,11 @@ class Wrapper extends React.PureComponent { const activeRequestId = activeRequest ? activeRequest._id : 'n/a'; const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : 'n/a'; - await handleSendAndDownloadRequestWithEnvironment(activeRequestId, activeEnvironmentId, filename); + await handleSendAndDownloadRequestWithEnvironment( + activeRequestId, + activeEnvironmentId, + filename, + ); } _handleSetPreviewMode(previewMode: string): void { @@ -400,24 +413,24 @@ class Wrapper extends React.PureComponent { const realSidebarWidth = sidebarHidden ? 0 : sidebarWidth; const columns = `${realSidebarWidth}rem 0 minmax(0, ${paneWidth}fr) 0 minmax(0, ${1 - - paneWidth}fr)`; + paneWidth}fr)`; const rows = `minmax(0, ${paneHeight}fr) 0 minmax(0, ${1 - paneHeight}fr)`; return [
- - - + + + - - - - - - - - + + + + + + + + { workspace={activeWorkspace} /> - + { nunjucksPowerUserMode={settings.nunjucksPowerUserMode} handleRemoveWorkspace={this._handleRemoveActiveWorkspace} handleDuplicateWorkspace={handleDuplicateWorkspace} + handleClearAllResponses={this._handleActiveWorkspaceClearAllResponses} isVariableUncovered={isVariableUncovered} /> - + { settings={settings} /> - + { isVariableUncovered={isVariableUncovered} /> - + {
-
+