// @flow import type { Settings } from '../../models/settings'; import type { Response } from '../../models/response'; import type { OAuth2Token } from '../../models/o-auth-2-token'; import type { Workspace } from '../../models/workspace'; import type { Request, RequestAuthentication, RequestBody, RequestHeader, RequestParameter, } from '../../models/request'; import type { SidebarChildObjects } from './sidebar/sidebar-children'; import * as React from 'react'; import autobind from 'autobind-decorator'; import classnames from 'classnames'; import { registerModal, showModal } from './modals/index'; import AlertModal from './modals/alert-modal'; import WrapperModal from './modals/wrapper-modal'; import ErrorModal from './modals/error-modal'; import CookiesModal from './modals/cookies-modal'; import CookieModifyModal from '../components/modals/cookie-modify-modal'; import EnvironmentEditModal from './modals/environment-edit-modal'; import GenerateCodeModal from './modals/generate-code-modal'; import LoginModal from './modals/login-modal'; import ResponseDebugModal from './modals/response-debug-modal'; import PaymentNotificationModal from './modals/payment-notification-modal'; import NunjucksModal from './modals/nunjucks-modal'; import PromptModal from './modals/prompt-modal'; import AskModal from './modals/ask-modal'; import SelectModal from './modals/select-modal'; import RequestCreateModal from './modals/request-create-modal'; import RequestPane from './request-pane'; import RequestSwitcherModal from './modals/request-switcher-modal'; import SettingsModal from './modals/settings-modal'; import FilterHelpModal from './modals/filter-help-modal'; import ResponsePane from './response-pane'; import RequestSettingsModal from './modals/request-settings-modal'; import SetupSyncModal from './modals/setup-sync-modal'; import SyncStagingModal from './modals/sync-staging-modal'; import SyncMergeModal from './modals/sync-merge-modal'; import SyncHistoryModal from './modals/sync-history-modal'; import SyncShareModal from './modals/sync-share-modal'; import SyncBranchesModal from './modals/sync-branches-modal'; import RequestRenderErrorModal from './modals/request-render-error-modal'; import Sidebar from './sidebar/sidebar'; import WorkspaceEnvironmentsEditModal from './modals/workspace-environments-edit-modal'; 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'; import type { Environment } from '../../models/environment'; import ErrorBoundary from './error-boundary'; import type { ClientCertificate } from '../../models/client-certificate'; import MoveRequestGroupModal from './modals/move-request-group-modal'; import AddKeyCombinationModal from './modals/add-key-combination-modal'; import ExportRequestsModal from './modals/export-requests-modal'; import VCS from '../../sync/vcs'; import type { StatusCandidate } from '../../sync/types'; import type { RequestMeta } from '../../models/request-meta'; import type { RequestVersion } from '../../models/request-version'; type Props = { // Helper Functions handleActivateRequest: Function, handleSetSidebarFilter: Function, handleToggleMenuBar: Function, handleImportFileToWorkspace: Function, handleImportUriToWorkspace: Function, handleExportFile: Function, handleShowExportRequestsModal: Function, handleExportRequestsToFile: Function, handleSetActiveWorkspace: Function, handleSetActiveEnvironment: Function, handleMoveDoc: Function, handleCreateRequest: Function, handleDuplicateRequest: Function, handleDuplicateRequestGroup: Function, handleMoveRequestGroup: Function, handleDuplicateWorkspace: Function, handleCreateRequestGroup: Function, handleGenerateCodeForActiveRequest: Function, handleGenerateCode: Function, handleCopyAsCurl: Function, handleCreateRequestForWorkspace: Function, handleSetRequestPaneRef: Function, handleSetResponsePaneRef: Function, handleSetResponsePreviewMode: Function, handleRender: Function, handleGetRenderContext: Function, handleSetResponseFilter: Function, handleSetActiveResponse: Function, handleSetSidebarRef: Function, handleStartDragSidebar: Function, handleResetDragSidebar: Function, handleStartDragPaneHorizontal: Function, handleStartDragPaneVertical: Function, handleResetDragPaneHorizontal: Function, handleResetDragPaneVertical: Function, handleSetRequestGroupCollapsed: Function, handleSetRequestPinned: Function, handleSendRequestWithEnvironment: Function, handleSendAndDownloadRequestWithEnvironment: Function, handleUpdateRequestMimeType: Function, handleUpdateDownloadPath: Function, // Properties loadStartTime: number, isLoading: boolean, paneWidth: number, paneHeight: number, responsePreviewMode: string, responseFilter: string, responseFilterHistory: Array, responseDownloadPath: string | null, sidebarWidth: number, sidebarHidden: boolean, sidebarFilter: string, sidebarChildren: SidebarChildObjects, settings: Settings, workspaces: Array, requestMetas: Array, requests: Array, requestVersions: Array, unseenWorkspaces: Array, workspaceChildren: Array, environments: Array, activeRequestResponses: Array, activeWorkspace: Workspace, activeCookieJar: CookieJar, activeEnvironment: Environment | null, activeWorkspaceClientCertificates: Array, isVariableUncovered: boolean, headerEditorKey: string, vcs: VCS | null, syncItems: Array, // Optional oAuth2Token: ?OAuth2Token, activeRequest: ?Request, activeResponse: ?Response, }; type State = { forceRefreshKey: number, }; const rUpdate = (request, ...args) => { if (!request) { throw new Error('Tried to update null request'); } return models.request.update(request, ...args); }; const sUpdate = models.settings.update; @autobind class Wrapper extends React.PureComponent { constructor(props: any) { super(props); this.state = { forceRefreshKey: Date.now(), }; } // Request updaters async _handleForceUpdateRequest(r: Request, patch: Object): Promise { const newRequest = await rUpdate(r, patch); // Give it a second for the app to render first. If we don't wait, it will refresh // on the old request and won't catch the newest one. // TODO: Move this refresh key into redux store so we don't need timeout window.setTimeout(this._forceRequestPaneRefresh, 100); return newRequest; } _handleForceUpdateRequestHeaders(r: Request, headers: Array): Promise { return this._handleForceUpdateRequest(r, { headers }); } static _handleUpdateRequestBody(r: Request, body: RequestBody): Promise { return rUpdate(r, { body }); } static _handleUpdateRequestParameters( r: Request, parameters: Array, ): Promise { return rUpdate(r, { parameters }); } static _handleUpdateRequestAuthentication( r: Request, authentication: RequestAuthentication, ): Promise { return rUpdate(r, { authentication }); } static _handleUpdateRequestHeaders(r: Request, headers: Array): Promise { return rUpdate(r, { headers }); } static _handleUpdateRequestMethod(r: Request, method: string): Promise { return rUpdate(r, { method }); } static _handleUpdateRequestUrl(r: Request, url: string): Promise { // Don't update if we don't need to if (r.url === url) { return Promise.resolve(r); } return rUpdate(r, { url }); } // Special request updaters _handleStartDragSidebar(e: Event): void { e.preventDefault(); this.props.handleStartDragSidebar(); } async _handleImport(text: string): Promise { // Allow user to paste any import file into the url. If it results in // only one item, it will overwrite the current request. try { const { data } = await importers.convert(text); const { resources } = data; const r = resources[0]; if (r && r._type === 'request' && this.props.activeRequest) { // Only pull fields that we want to update return this._handleForceUpdateRequest(this.props.activeRequest, { url: r.url, method: r.method, headers: r.headers, body: r.body, authentication: r.authentication, parameters: r.parameters, }); } } catch (e) { // Import failed, that's alright } return null; } // Settings updaters _handleUpdateSettingsShowPasswords(showPasswords: boolean): Promise { return sUpdate(this.props.settings, { showPasswords }); } _handleUpdateSettingsUseBulkHeaderEditor(useBulkHeaderEditor: boolean): Promise { return sUpdate(this.props.settings, { useBulkHeaderEditor }); } // Other Helpers _handleImportFile(): void { this.props.handleImportFileToWorkspace(this.props.activeWorkspace._id); } _handleImportUri(uri: string): void { this.props.handleImportUriToWorkspace(this.props.activeWorkspace._id, uri); } _handleSetActiveResponse(responseId: string | null): void { if (!this.props.activeRequest) { console.warn('Tried to set active response when request not active'); return; } this.props.handleSetActiveResponse(this.props.activeRequest._id, responseId); } _handleShowEnvironmentsModal(): void { showModal(WorkspaceEnvironmentsEditModal, this.props.activeWorkspace); } _handleShowCookiesModal(): void { showModal(CookiesModal, this.props.activeWorkspace); } static _handleShowModifyCookieModal(cookie: Object): void { showModal(CookieModifyModal, cookie); } _handleShowRequestSettingsModal(): void { showModal(RequestSettingsModal, { request: this.props.activeRequest }); } async _handleDeleteResponses(): Promise { if (!this.props.activeRequest) { console.warn('Tried to delete responses when request not active'); return; } await models.response.removeForRequest(this.props.activeRequest._id); this._handleSetActiveResponse(null); } async _handleDeleteResponse(response: Response): Promise { if (response) { await models.response.remove(response); } // Also unset active response it's the one we're deleting if (this.props.activeResponse && this.props.activeResponse._id === response._id) { this._handleSetActiveResponse(null); } } async _handleRemoveActiveWorkspace(): Promise { const { workspaces, activeWorkspace } = this.props; if (workspaces.length <= 1) { showModal(AlertModal, { title: 'Deleting Last Workspace', message: 'Since you deleted your only workspace, a new one has been created for you.', }); models.workspace.create({ name: 'Insomnia' }); } 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'; const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : 'n/a'; handleSendRequestWithEnvironment(activeRequestId, activeEnvironmentId); } async _handleSendAndDownloadRequestWithActiveEnvironment(filename?: string): Promise { const { activeRequest, activeEnvironment, handleSendAndDownloadRequestWithEnvironment, } = this.props; const activeRequestId = activeRequest ? activeRequest._id : 'n/a'; const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : 'n/a'; await handleSendAndDownloadRequestWithEnvironment( activeRequestId, activeEnvironmentId, filename, ); } _handleSetPreviewMode(previewMode: string): void { const activeRequest = this.props.activeRequest; const activeRequestId = activeRequest ? activeRequest._id : 'n/a'; this.props.handleSetResponsePreviewMode(activeRequestId, previewMode); } _handleSetResponseFilter(filter: string): void { const activeRequest = this.props.activeRequest; const activeRequestId = activeRequest ? activeRequest._id : 'n/a'; this.props.handleSetResponseFilter(activeRequestId, filter); } _forceRequestPaneRefresh(): void { this.setState({ forceRefreshKey: Date.now() }); } render() { const { activeCookieJar, activeEnvironment, activeRequest, activeRequestResponses, activeResponse, activeWorkspace, activeWorkspaceClientCertificates, environments, handleActivateRequest, handleCopyAsCurl, handleCreateRequest, handleCreateRequestForWorkspace, handleCreateRequestGroup, handleDuplicateRequest, handleDuplicateRequestGroup, handleDuplicateWorkspace, handleExportFile, handleExportRequestsToFile, handleGenerateCode, handleGenerateCodeForActiveRequest, handleGetRenderContext, handleMoveDoc, handleMoveRequestGroup, handleRender, handleResetDragPaneHorizontal, handleResetDragPaneVertical, handleResetDragSidebar, handleSetActiveEnvironment, handleSetActiveWorkspace, handleSetRequestGroupCollapsed, handleSetRequestPaneRef, handleSetRequestPinned, handleSetResponsePaneRef, handleSetSidebarFilter, handleSetSidebarRef, handleShowExportRequestsModal, handleStartDragPaneHorizontal, handleStartDragPaneVertical, handleToggleMenuBar, handleUpdateRequestMimeType, handleUpdateDownloadPath, headerEditorKey, isLoading, isVariableUncovered, loadStartTime, oAuth2Token, paneHeight, paneWidth, requestMetas, requestVersions, responseFilter, responseFilterHistory, responsePreviewMode, responseDownloadPath, settings, sidebarChildren, sidebarFilter, sidebarHidden, sidebarWidth, syncItems, unseenWorkspaces, vcs, workspaceChildren, workspaces, } = this.props; const realSidebarWidth = sidebarHidden ? 0 : sidebarWidth; const columns = `${realSidebarWidth}rem 0 minmax(0, ${paneWidth}fr) 0 minmax(0, ${1 - paneWidth}fr)`; const rows = `minmax(0, ${paneHeight}fr) 0 minmax(0, ${1 - paneHeight}fr)`; return [
{/* TODO: Figure out why cookieJar is sometimes null */} {activeCookieJar ? ( ) : null} {vcs && ( )}
,
, ]; } } export default Wrapper;