diff --git a/packages/insomnia-app/app/ui/components/modals/cookie-modify-modal.tsx b/packages/insomnia-app/app/ui/components/modals/cookie-modify-modal.tsx index ef62e1429..4a5da777b 100644 --- a/packages/insomnia-app/app/ui/components/modals/cookie-modify-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/cookie-modify-modal.tsx @@ -2,22 +2,24 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import clone from 'clone'; import { cookieToString } from 'insomnia-cookies'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import * as toughCookie from 'tough-cookie'; import { AUTOBIND_CFG, DEBOUNCE_MILLIS } from '../../../common/constants'; import * as models from '../../../models'; import type { Cookie, CookieJar } from '../../../models/cookie-jar'; -import type { Workspace } from '../../../models/workspace'; -import { Modal, ModalProps } from '../base/modal'; +import { RootState } from '../../redux/modules'; +import { selectActiveCookieJar } from '../../redux/selectors'; +import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; import { ModalFooter } from '../base/modal-footer'; import { ModalHeader } from '../base/modal-header'; import { OneLineEditor } from '../codemirror/one-line-editor'; -interface Props extends ModalProps { - workspace: Workspace; - cookieJar: CookieJar; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { } interface State { @@ -26,7 +28,7 @@ interface State { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class CookieModifyModal extends PureComponent { +export class UnconnectedCookieModifyModal extends PureComponent { modal: Modal | null = null; _rawTimeout: NodeJS.Timeout | null = null; _cookieUpdateTimeout: NodeJS.Timeout | null = null; @@ -43,17 +45,15 @@ export class CookieModifyModal extends PureComponent { async show(cookie: Cookie) { // Dunno why this is sent as an array cookie = cookie[0] || cookie; - const { cookieJar } = this.props; - const oldCookie = cookieJar.cookies.find(c => c.id === cookie.id); + const { activeCookeJar } = this.props; + const prevCookie = activeCookeJar?.cookies.find(c => c.id === cookie.id); - if (!oldCookie) { + if (!prevCookie) { // Cookie not found in jar return; } - this.setState({ - cookie, - }); + this.setState({ cookie }); this.modal?.show(); } @@ -65,13 +65,13 @@ export class CookieModifyModal extends PureComponent { await models.cookieJar.update(cookieJar); } - _handleChangeRawValue(e: React.SyntheticEvent) { - const value = e.currentTarget.value; + _handleChangeRawValue(event: React.SyntheticEvent) { + const value = event.currentTarget.value; if (this._rawTimeout !== null) { clearTimeout(this._rawTimeout); } this._rawTimeout = setTimeout(async () => { - const oldCookie = this.state.cookie; + const prevCookie = this.state.cookie; let cookie; try { @@ -83,25 +83,26 @@ export class CookieModifyModal extends PureComponent { return; } - if (!this.state.cookie || !oldCookie) { + if (!this.state.cookie || !prevCookie) { return; } // Make sure cookie has an id - cookie.id = oldCookie.id; + cookie.id = prevCookie.id; await this._handleCookieUpdate(cookie); }, DEBOUNCE_MILLIS * 2); } - async _handleCookieUpdate(newCookie: Cookie) { - const oldCookie = this.state.cookie; + async _handleCookieUpdate(nextCookie: Cookie) { + const prevCookie = this.state.cookie; + const { activeCookeJar: prevCookieJar } = this.props; - if (!oldCookie) { + if (!prevCookie || !prevCookieJar) { // We don't have a cookie to edit return; } - const cookie = clone(newCookie); + const cookie = clone(nextCookie); // Sanitize expires field const expires = new Date(cookie.expires || '').getTime(); @@ -112,7 +113,7 @@ export class CookieModifyModal extends PureComponent { } // Clone so we don't modify the original - const cookieJar = clone(this.props.cookieJar); + const cookieJar = clone(prevCookieJar); const { cookies } = cookieJar; const index = cookies.findIndex(c => c.id === cookie.id); @@ -122,9 +123,7 @@ export class CookieModifyModal extends PureComponent { } cookieJar.cookies = [...cookies.slice(0, index), cookie, ...cookies.slice(index + 1)]; - this.setState({ - cookie, - }); + this.setState({ cookie }); await CookieModifyModal._saveChanges(cookieJar); return cookie; } @@ -153,9 +152,7 @@ export class CookieModifyModal extends PureComponent { } this._cookieUpdateTimeout = setTimeout(async () => { await this._handleCookieUpdate(newCookie); - this.setState({ - cookie: newCookie, - }); + this.setState({ cookie: newCookie }); }, DEBOUNCE_MILLIS * 2); } @@ -202,14 +199,14 @@ export class CookieModifyModal extends PureComponent { } render() { - const { cookieJar } = this.props; + const { activeCookeJar } = this.props; const { cookie } = this.state; const checkFields = ['secure', 'httpOnly']; return ( Edit Cookie - {cookieJar && cookie && ( + {activeCookeJar && cookie && ( @@ -276,3 +273,14 @@ export class CookieModifyModal extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + activeCookeJar: selectActiveCookieJar(state), +}); + +export const CookieModifyModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedCookieModifyModal); diff --git a/packages/insomnia-app/app/ui/components/modals/cookies-modal.tsx b/packages/insomnia-app/app/ui/components/modals/cookies-modal.tsx index f9e352c42..7ec78ec32 100644 --- a/packages/insomnia-app/app/ui/components/modals/cookies-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/cookies-modal.tsx @@ -1,14 +1,15 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import deepEqual from 'deep-equal'; import React, { ChangeEvent, forwardRef, ForwardRefRenderFunction, PureComponent } from 'react'; +import { useSelector } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { fuzzyMatch } from '../../../common/misc'; import { HandleRender } from '../../../common/render'; import * as models from '../../../models'; import type { Cookie, CookieJar } from '../../../models/cookie-jar'; -import type { Workspace } from '../../../models/workspace'; import { useNunjucks } from '../../context/nunjucks/use-nunjucks'; +import { selectActiveCookieJar } from '../../redux/selectors'; import { Modal, ModalProps } from '../base/modal'; import { ModalBody } from '../base/modal-body'; import { ModalFooter } from '../base/modal-footer'; @@ -19,8 +20,7 @@ import { showModal } from '.'; interface Props extends ModalProps { handleShowModifyCookieModal: CookieListProps['handleShowModifyCookieModal']; handleRender: HandleRender; - cookieJar: CookieJar; - workspace: Workspace; + activeCookieJar: CookieJar | null; } interface State { @@ -47,28 +47,40 @@ class CookiesModal extends PureComponent { } async _saveChanges() { - const { cookieJar } = this.props; - await models.cookieJar.update(cookieJar); + const { activeCookieJar } = this.props; + if (!activeCookieJar) { + return; + } + await models.cookieJar.update(activeCookieJar); } async _handleCookieAdd(cookie: Cookie) { - const { cookieJar } = this.props; - const { cookies } = cookieJar; - cookieJar.cookies = [cookie, ...cookies]; + const { activeCookieJar } = this.props; + if (!activeCookieJar) { + return; + } + const { cookies } = activeCookieJar; + activeCookieJar.cookies = [cookie, ...cookies]; await this._saveChanges(); } async _handleDeleteAllCookies() { - const { cookieJar } = this.props; - cookieJar.cookies = []; + const { activeCookieJar } = this.props; + if (!activeCookieJar) { + return; + } + activeCookieJar.cookies = []; await this._saveChanges(); } async _handleCookieDelete(cookie: Cookie) { - const { cookieJar } = this.props; - const { cookies } = cookieJar; + const { activeCookieJar } = this.props; + if (!activeCookieJar) { + return; + } + const { cookies } = activeCookieJar; // NOTE: This is sketchy because it relies on the same reference - cookieJar.cookies = cookies.filter(c => c.id !== cookie.id); + activeCookieJar.cookies = cookies.filter(c => c.id !== cookie.id); await this._saveChanges(); } @@ -76,20 +88,28 @@ class CookiesModal extends PureComponent { if (!(e.target instanceof HTMLInputElement)) { return; } + const { activeCookieJar } = this.props; + if (!activeCookieJar) { + return; + } const filter = e.target.value; - this._applyFilter(filter, this.props.cookieJar.cookies); + this._applyFilter(filter, activeCookieJar.cookies); } // eslint-disable-next-line camelcase UNSAFE_componentWillReceiveProps(nextProps: Props) { + const { activeCookieJar } = this.props; + if (!activeCookieJar || !nextProps.activeCookieJar) { + return; + } // Re-filter if we received new cookies // Compare cookies with Dates cast to strings - const sameCookies = deepEqual(this.props.cookieJar.cookies, nextProps.cookieJar.cookies); + const sameCookies = deepEqual(activeCookieJar.cookies, nextProps.activeCookieJar.cookies); if (!sameCookies) { - this._applyFilter(this.state.filter, nextProps.cookieJar.cookies); + this._applyFilter(this.state.filter, nextProps.activeCookieJar.cookies); } } @@ -132,22 +152,29 @@ class CookiesModal extends PureComponent { } _getVisibleCookies(): Cookie[] { - const { cookieJar } = this.props; + const { activeCookieJar } = this.props; const { visibleCookieIndexes } = this.state; - if (visibleCookieIndexes === null) { - return cookieJar.cookies; + if (!activeCookieJar) { + return []; } - return cookieJar.cookies.filter((_, i) => visibleCookieIndexes.includes(i)); + if (visibleCookieIndexes === null) { + return activeCookieJar.cookies; + } + + return activeCookieJar.cookies.filter((_, i) => visibleCookieIndexes.includes(i)); } async show() { + const { activeCookieJar } = this.props; + setTimeout(() => { this.filterInput?.focus(); }, 100); + // make sure the filter is up to date - await this._applyFilter(this.state.filter, this.props.cookieJar.cookies); + await this._applyFilter(this.state.filter, activeCookieJar?.cookies || []); this.modal?.show(); } @@ -156,7 +183,7 @@ class CookiesModal extends PureComponent { } render() { - const { handleShowModifyCookieModal, cookieJar } = this.props; + const { handleShowModifyCookieModal, activeCookieJar } = this.props; const { filter } = this.state; const cookies = this._getVisibleCookies(); @@ -165,7 +192,7 @@ class CookiesModal extends PureComponent { Manage Cookies - {cookieJar && ( + {activeCookieJar && (
@@ -207,9 +234,18 @@ class CookiesModal extends PureComponent { } } -const CookiesModalFCRF: ForwardRefRenderFunction> = (props, ref) => { +const CookiesModalFCRF: ForwardRefRenderFunction> = (props, ref) => { const { handleRender } = useNunjucks(); - return ; + const activeCookieJar = useSelector(selectActiveCookieJar); + + return ( + + ); }; diff --git a/packages/insomnia-app/app/ui/components/modals/project-settings-modal.tsx b/packages/insomnia-app/app/ui/components/modals/project-settings-modal.tsx index 655ef3ef1..c165a3bba 100644 --- a/packages/insomnia-app/app/ui/components/modals/project-settings-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/project-settings-modal.tsx @@ -101,10 +101,9 @@ class ProjectSettingsModal extends PureComponent { } } -const mapStateToProps = (state: RootState) => { - const project = selectActiveProject(state); - return { project }; -}; +const mapStateToProps = (state: RootState) => ({ + project: selectActiveProject(state), +}); const mapDispatchToProps = dispatch => { const boundProjectActions = bindActionCreators(projectActions, dispatch); diff --git a/packages/insomnia-app/app/ui/components/modals/request-group-settings-modal.tsx b/packages/insomnia-app/app/ui/components/modals/request-group-settings-modal.tsx index f899173c1..d2793943b 100644 --- a/packages/insomnia-app/app/ui/components/modals/request-group-settings-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/request-group-settings-modal.tsx @@ -1,11 +1,14 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import * as React from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { database as db } from '../../../common/database'; import * as models from '../../../models'; import type { RequestGroup } from '../../../models/request-group'; import type { Workspace } from '../../../models/workspace'; +import { RootState } from '../../redux/modules'; +import { selectWorkspacesForActiveProject } from '../../redux/selectors'; import { DebouncedInput } from '../base/debounced-input'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -13,8 +16,9 @@ import { ModalHeader } from '../base/modal-header'; import { HelpTooltip } from '../help-tooltip'; import { MarkdownEditor } from '../markdown-editor'; -interface Props { - workspacesForActiveProject: Workspace[]; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { } interface State { @@ -34,7 +38,7 @@ interface RequestGroupSettingsModalOptions { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class RequestGroupSettingsModal extends React.PureComponent { +export class UnconnectedRequestGroupSettingsModal extends React.PureComponent { modal: Modal | null = null; _editor: MarkdownEditor | null = null; @@ -326,3 +330,14 @@ export class RequestGroupSettingsModal extends React.PureComponent ); } } + +const mapStateToProps = (state: RootState) => ({ + workspacesForActiveProject: selectWorkspacesForActiveProject(state), +}); + +export const RequestGroupSettingsModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedRequestGroupSettingsModal); diff --git a/packages/insomnia-app/app/ui/components/modals/request-settings-modal.tsx b/packages/insomnia-app/app/ui/components/modals/request-settings-modal.tsx index 7b41f749c..82838da21 100644 --- a/packages/insomnia-app/app/ui/components/modals/request-settings-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/request-settings-modal.tsx @@ -1,5 +1,6 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { database as db } from '../../../common/database'; @@ -8,6 +9,8 @@ import { GrpcRequest, isGrpcRequest } from '../../../models/grpc-request'; import * as requestOperations from '../../../models/helpers/request-operations'; import type { BaseRequest, Request } from '../../../models/request'; import { isWorkspace, Workspace } from '../../../models/workspace'; +import { RootState } from '../../redux/modules'; +import { selectWorkspacesForActiveProject } from '../../redux/selectors'; import { DebouncedInput } from '../base/debounced-input'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -15,8 +18,9 @@ import { ModalHeader } from '../base/modal-header'; import { HelpTooltip } from '../help-tooltip'; import { MarkdownEditor } from '../markdown-editor'; -interface Props { - workspacesForActiveProject: Workspace[]; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { } interface State { @@ -36,7 +40,7 @@ interface RequestSettingsModalOptions { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class RequestSettingsModal extends PureComponent { +export class UnconnectedRequestSettingsModal extends PureComponent { modal: Modal | null = null; _editor: MarkdownEditor | null = null; @@ -463,3 +467,14 @@ export class RequestSettingsModal extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + workspacesForActiveProject: selectWorkspacesForActiveProject(state), +}); + +export const RequestSettingsModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedRequestSettingsModal); diff --git a/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.tsx b/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.tsx index 4c977b5d9..f923b0f7c 100644 --- a/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.tsx @@ -29,18 +29,14 @@ import { MethodTag } from '../tags/method-tag'; type ReduxProps = ReturnType & ReturnType; -const mapStateToProps = (state: RootState) => { - const activeRequest = selectActiveRequest(state); - - return { - activeRequest, - workspace: selectActiveWorkspace(state), - workspacesForActiveProject: selectWorkspacesForActiveProject(state), - requestMetas: selectRequestMetas(state), - grpcRequestMetas: selectGrpcRequestMetas(state), - workspaceRequestsAndRequestGroups: selectWorkspaceRequestsAndRequestGroups(state), - }; -}; +const mapStateToProps = (state: RootState) => ({ + activeRequest: selectActiveRequest(state), + workspace: selectActiveWorkspace(state), + workspacesForActiveProject: selectWorkspacesForActiveProject(state), + requestMetas: selectRequestMetas(state), + grpcRequestMetas: selectGrpcRequestMetas(state), + workspaceRequestsAndRequestGroups: selectWorkspaceRequestsAndRequestGroups(state), +}); const mapDispatchToProps = dispatch => { const bound = bindActionCreators({ activateWorkspace }, dispatch); diff --git a/packages/insomnia-app/app/ui/components/modals/settings-modal.tsx b/packages/insomnia-app/app/ui/components/modals/settings-modal.tsx index 0bfb91bdb..bd8ea6d62 100644 --- a/packages/insomnia-app/app/ui/components/modals/settings-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/settings-modal.tsx @@ -2,12 +2,14 @@ import { Curl } from '@getinsomnia/node-libcurl'; import { autoBindMethodsForReact } from 'class-autobind-decorator'; import { HotKeyRegistry } from 'insomnia-common'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import * as session from '../../../account/session'; import { AUTOBIND_CFG, getAppName, getAppVersion } from '../../../common/constants'; import * as models from '../../../models/index'; -import { Settings } from '../../../models/settings'; +import { RootState } from '../../redux/modules'; +import { selectSettings } from '../../redux/selectors'; import { Button } from '../base/button'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -26,8 +28,9 @@ export const TAB_INDEX_SHORTCUTS = 3; export const TAB_INDEX_THEMES = 2; export const TAB_INDEX_PLUGINS = 5; -interface Props { - settings: Settings; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { } interface State { @@ -35,7 +38,7 @@ interface State { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class SettingsModal extends PureComponent { +export class UnconnectedSettingsModal extends PureComponent { state: State = { currentTabIndex: null, }; @@ -136,3 +139,14 @@ export class SettingsModal extends PureComponent { } export const showSettingsModal = () => showModal(SettingsModal); + +const mapStateToProps = (state: RootState) => ({ + settings: selectSettings(state), +}); + +export const SettingsModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSettingsModal); diff --git a/packages/insomnia-app/app/ui/components/modals/sync-branches-modal.tsx b/packages/insomnia-app/app/ui/components/modals/sync-branches-modal.tsx index a76bed6c9..51ea2f751 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-branches-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/sync-branches-modal.tsx @@ -1,24 +1,23 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import classnames from 'classnames'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { database as db } from '../../../common/database'; -import { Project } from '../../../models/project'; -import type { Workspace } from '../../../models/workspace'; -import type { StatusCandidate } from '../../../sync/types'; import { interceptAccessError } from '../../../sync/vcs/util'; import { VCS } from '../../../sync/vcs/vcs'; +import { RootState } from '../../redux/modules'; +import { selectSyncItems } from '../../redux/selectors'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; import { ModalHeader } from '../base/modal-header'; import { PromptButton } from '../base/prompt-button'; import { SyncPullButton } from '../sync-pull-button'; -interface Props { - workspace: Workspace; - project: Project; - syncItems: StatusCandidate[]; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { vcs: VCS; } @@ -31,7 +30,7 @@ interface State { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class SyncBranchesModal extends PureComponent { +export class UnconnectedSyncBranchesModal extends PureComponent { modal: Modal | null = null; state: State = { @@ -181,7 +180,7 @@ export class SyncBranchesModal extends PureComponent { } render() { - const { vcs, project } = this.props; + const { vcs } = this.props; const { branches, remoteBranches, currentBranch, newBranchName, error } = this.state; return ( @@ -301,7 +300,6 @@ export class SyncBranchesModal extends PureComponent { { ); } } + +const mapStateToProps = (state: RootState) => ({ + syncItems: selectSyncItems(state), +}); + +export const SyncBranchesModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSyncBranchesModal); diff --git a/packages/insomnia-app/app/ui/components/modals/sync-delete-modal.tsx b/packages/insomnia-app/app/ui/components/modals/sync-delete-modal.tsx index 77abc194c..b7a95a37c 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-delete-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/sync-delete-modal.tsx @@ -1,18 +1,21 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import { Button } from 'insomnia-components'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { strings } from '../../../common/strings'; -import type { Workspace } from '../../../models/workspace'; import { interceptAccessError } from '../../../sync/vcs/util'; import { VCS } from '../../../sync/vcs/vcs'; +import { RootState } from '../../redux/modules'; +import { selectActiveWorkspace } from '../../redux/selectors'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; import { ModalHeader } from '../base/modal-header'; -interface Props { - workspace: Workspace; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { vcs: VCS; } @@ -27,7 +30,7 @@ const INITIAL_STATE: State = { }; @autoBindMethodsForReact(AUTOBIND_CFG) -export class SyncDeleteModal extends PureComponent { +export class UnconnectedSyncDeleteModal extends PureComponent { modal: Modal | null = null; input: HTMLInputElement | null = null; @@ -89,14 +92,14 @@ export class SyncDeleteModal extends PureComponent { render() { const { error, workspaceName } = this.state; - const { workspace } = this.props; + const { activeWorkspace } = this.props; const workspaceNameElement = ( - {workspace.name} + {activeWorkspace?.name} ); return ( @@ -118,7 +121,7 @@ export class SyncDeleteModal extends PureComponent { onChange={this._updateWorkspaceName} value={workspaceName} /> -
@@ -128,3 +131,14 @@ export class SyncDeleteModal extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + activeWorkspace: selectActiveWorkspace(state), +}); + +export const SyncDeleteModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSyncDeleteModal); diff --git a/packages/insomnia-app/app/ui/components/modals/sync-history-modal.tsx b/packages/insomnia-app/app/ui/components/modals/sync-history-modal.tsx index ef7cdc6e3..5a22ac84a 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-history-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/sync-history-modal.tsx @@ -3,7 +3,6 @@ import React, { Fragment, PureComponent } from 'react'; import * as session from '../../../account/session'; import { AUTOBIND_CFG } from '../../../common/constants'; -import type { Workspace } from '../../../models/workspace'; import type { Snapshot } from '../../../sync/types'; import { VCS } from '../../../sync/vcs/vcs'; import { Modal } from '../base/modal'; @@ -15,7 +14,6 @@ import { TimeFromNow } from '../time-from-now'; import { Tooltip } from '../tooltip'; interface Props { - workspace: Workspace; vcs: VCS; } diff --git a/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.tsx b/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.tsx index 652640a30..fb43a4398 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.tsx @@ -1,19 +1,21 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; -import type { Workspace } from '../../../models/workspace'; -import type { DocumentKey, MergeConflict, StatusCandidate } from '../../../sync/types'; +import type { DocumentKey, MergeConflict } from '../../../sync/types'; import { VCS } from '../../../sync/vcs/vcs'; +import { RootState } from '../../redux/modules'; +import { selectSyncItems } from '../../redux/selectors'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; import { ModalFooter } from '../base/modal-footer'; import { ModalHeader } from '../base/modal-header'; -interface Props { - workspace: Workspace; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { vcs: VCS; - syncItems: StatusCandidate[]; } interface State { @@ -21,7 +23,7 @@ interface State { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class SyncMergeModal extends PureComponent { +export class UnconnectedSyncMergeModal extends PureComponent { modal: Modal | null = null; _handleDone: (arg0: MergeConflict[]) => void; @@ -126,3 +128,14 @@ export class SyncMergeModal extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + syncItems: selectSyncItems(state), +}); + +export const SyncMergeModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSyncMergeModal); diff --git a/packages/insomnia-app/app/ui/components/modals/sync-staging-modal.tsx b/packages/insomnia-app/app/ui/components/modals/sync-staging-modal.tsx index 496b88da8..de9cd6a1c 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-staging-modal.tsx +++ b/packages/insomnia-app/app/ui/components/modals/sync-staging-modal.tsx @@ -1,14 +1,16 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import React, { Fragment, PureComponent, ReactNode } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../../common/constants'; import { strings } from '../../../common/strings'; import * as models from '../../../models'; import { BaseModel } from '../../../models'; -import type { Workspace } from '../../../models/workspace'; -import type { DocumentKey, Stage, StageEntry, Status, StatusCandidate } from '../../../sync/types'; +import type { DocumentKey, Stage, StageEntry, Status } from '../../../sync/types'; import { describeChanges } from '../../../sync/vcs/util'; import { VCS } from '../../../sync/vcs/vcs'; +import { RootState } from '../../redux/modules'; +import { selectSyncItems } from '../../redux/selectors'; import { IndeterminateCheckbox } from '../base/indeterminate-checkbox'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -16,9 +18,9 @@ import { ModalFooter } from '../base/modal-footer'; import { ModalHeader } from '../base/modal-header'; import { Tooltip } from '../tooltip'; -interface Props { - workspace: Workspace; - syncItems: StatusCandidate[]; +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { vcs: VCS; } @@ -51,7 +53,7 @@ const _initialState: State = { }; @autoBindMethodsForReact(AUTOBIND_CFG) -export class SyncStagingModal extends PureComponent { +export class UnconnectedSyncStagingModal extends PureComponent { modal: Modal | null = null; _onSnapshot: (() => void) | null = null; _handlePush: (() => Promise) | null = null; @@ -398,3 +400,14 @@ export class SyncStagingModal extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + syncItems: selectSyncItems(state), +}); + +export const SyncStagingModal = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSyncStagingModal); diff --git a/packages/insomnia-app/app/ui/components/sync-pull-button.tsx b/packages/insomnia-app/app/ui/components/sync-pull-button.tsx index 3ec64222e..3d9b1c32b 100644 --- a/packages/insomnia-app/app/ui/components/sync-pull-button.tsx +++ b/packages/insomnia-app/app/ui/components/sync-pull-button.tsx @@ -1,15 +1,18 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import React, { PureComponent, ReactNode } from 'react'; +import { connect } from 'react-redux'; import { AUTOBIND_CFG } from '../../common/constants'; -import { Project } from '../../models/project'; import { VCS } from '../../sync/vcs/vcs'; +import { RootState } from '../redux/modules'; +import { selectActiveProject } from '../redux/selectors'; import { showError } from './modals'; -interface Props { +type ReduxProps = ReturnType; + +interface Props extends ReduxProps { vcs: VCS; branch: string; - project: Project; onPull: (...args: any[]) => any; disabled?: boolean; className?: string; @@ -21,7 +24,7 @@ interface State { } @autoBindMethodsForReact(AUTOBIND_CFG) -export class SyncPullButton extends PureComponent { +export class UnconnectedSyncPullButton extends PureComponent { _timeout: NodeJS.Timeout | null = null; state: State = { @@ -84,3 +87,14 @@ export class SyncPullButton extends PureComponent { ); } } + +const mapStateToProps = (state: RootState) => ({ + project: selectActiveProject(state), +}); + +export const SyncPullButton = connect( + mapStateToProps, + null, + null, + { forwardRef: true }, +)(UnconnectedSyncPullButton); diff --git a/packages/insomnia-app/app/ui/components/wrapper.tsx b/packages/insomnia-app/app/ui/components/wrapper.tsx index fcd6c65ea..1aefec3ce 100644 --- a/packages/insomnia-app/app/ui/components/wrapper.tsx +++ b/packages/insomnia-app/app/ui/components/wrapper.tsx @@ -442,7 +442,6 @@ export class Wrapper extends PureComponent { activeEnvironment, activeGitRepository, activeWorkspace, - activeProject, activeApiSpec, activeWorkspaceClientCertificates, activeActivity, @@ -451,11 +450,8 @@ export class Wrapper extends PureComponent { handleExportRequestsToFile, handleInitializeEntities, handleSidebarSort, - settings, sidebarChildren, - syncItems, vcs, - workspacesForActiveProject, } = this.props; // Setup git sync dropdown for use in Design/Debug pages @@ -487,7 +483,6 @@ export class Wrapper extends PureComponent { - @@ -499,20 +494,9 @@ export class Wrapper extends PureComponent { - - - - - - + + + {activeWorkspace ? <> {/* TODO: Figure out why cookieJar is sometimes null */} @@ -520,14 +504,8 @@ export class Wrapper extends PureComponent { - + : null} { environmentId={activeEnvironment ? activeEnvironment._id : 'n/a'} /> - - + { {activeWorkspace && vcs ? ( - - - - - + + + + + ) : null} @@ -673,9 +631,7 @@ export class Wrapper extends PureComponent { handleImport={this._handleImport} handleRequestCreate={this._handleCreateRequestInWorkspace} handleRequestGroupCreate={this._handleCreateRequestGroupInWorkspace} - handleSendAndDownloadRequestWithActiveEnvironment={ - this._handleSendAndDownloadRequestWithActiveEnvironment - } + handleSendAndDownloadRequestWithActiveEnvironment={this._handleSendAndDownloadRequestWithActiveEnvironment} handleSendRequestWithActiveEnvironment={this._handleSendRequestWithActiveEnvironment} handleSetActiveResponse={this._handleSetActiveResponse} handleSetPreviewMode={this._handleSetPreviewMode} @@ -688,12 +644,8 @@ export class Wrapper extends PureComponent { handleUpdateRequestMethod={Wrapper._handleUpdateRequestMethod} handleUpdateRequestParameters={Wrapper._handleUpdateRequestParameters} handleUpdateRequestUrl={Wrapper._handleUpdateRequestUrl} - handleUpdateSettingsUseBulkHeaderEditor={ - this._handleUpdateSettingsUseBulkHeaderEditor - } - handleUpdateSettingsUseBulkParametersEditor={ - this._handleUpdateSettingsUseBulkParametersEditor - } + handleUpdateSettingsUseBulkHeaderEditor={this._handleUpdateSettingsUseBulkHeaderEditor} + handleUpdateSettingsUseBulkParametersEditor={this._handleUpdateSettingsUseBulkParametersEditor} wrapperProps={this.props} /> )} diff --git a/packages/insomnia-app/app/ui/containers/app.tsx b/packages/insomnia-app/app/ui/containers/app.tsx index 6e1668cdc..06c67d28c 100644 --- a/packages/insomnia-app/app/ui/containers/app.tsx +++ b/packages/insomnia-app/app/ui/containers/app.tsx @@ -134,6 +134,19 @@ import { import { selectPaneHeight, selectPaneWidth, selectSidebarChildren, selectSidebarFilter, selectSidebarHidden, selectSidebarWidth } from '../redux/sidebar-selectors'; import { AppHooks } from './app-hooks'; +const updateRequestMetaByParentId = async ( + requestId: string, + patch: Partial | Partial +) => { + const isGrpc = isGrpcRequestId(requestId); + + if (isGrpc) { + return models.grpcRequestMeta.updateOrCreateByParentId(requestId, patch); + } else { + return models.requestMeta.updateOrCreateByParentId(requestId, patch); + } +}; + export type AppProps = ReturnType & ReturnType; interface State { @@ -528,16 +541,6 @@ class App extends PureComponent { } } - static async _updateRequestMetaByParentId(requestId, patch) { - const isGrpc = isGrpcRequestId(requestId); - - if (isGrpc) { - return models.grpcRequestMeta.updateOrCreateByParentId(requestId, patch); - } else { - return models.requestMeta.updateOrCreateByParentId(requestId, patch); - } - } - async _updateShowVariableSourceAndValue() { const { settings } = this.props; await models.settings.update(settings, { showVariableSourceAndValue: !settings.showVariableSourceAndValue }); @@ -563,7 +566,7 @@ class App extends PureComponent { await this._updateActiveWorkspaceMeta({ activeRequestId, }); - await App._updateRequestMetaByParentId(activeRequestId, { + await updateRequestMetaByParentId(activeRequestId, { lastActive: Date.now(), }); } @@ -605,25 +608,25 @@ class App extends PureComponent { } async _handleSetRequestPinned(request, pinned) { - App._updateRequestMetaByParentId(request._id, { + updateRequestMetaByParentId(request._id, { pinned, }); } _handleSetResponsePreviewMode(requestId, previewMode) { - App._updateRequestMetaByParentId(requestId, { + updateRequestMetaByParentId(requestId, { previewMode, }); } _handleUpdateDownloadPath(requestId, downloadPath) { - App._updateRequestMetaByParentId(requestId, { + updateRequestMetaByParentId(requestId, { downloadPath, }); } async _handleSetResponseFilter(requestId, responseFilter) { - await App._updateRequestMetaByParentId(requestId, { + await updateRequestMetaByParentId(requestId, { responseFilter, }); @@ -646,7 +649,7 @@ class App extends PureComponent { } responseFilterHistory.unshift(responseFilter); - await App._updateRequestMetaByParentId(requestId, { + await updateRequestMetaByParentId(requestId, { responseFilterHistory, }); }, 2000); @@ -779,7 +782,7 @@ class App extends PureComponent { }); } finally { // Unset active response because we just made a new one - await App._updateRequestMetaByParentId(requestId, { + await updateRequestMetaByParentId(requestId, { activeResponseId: null, }); // Stop loading @@ -825,7 +828,7 @@ class App extends PureComponent { } // Unset active response because we just made a new one - await App._updateRequestMetaByParentId(requestId, { + await updateRequestMetaByParentId(requestId, { activeResponseId: null, }); // Stop loading @@ -835,7 +838,7 @@ class App extends PureComponent { async _handleSetActiveResponse(requestId: string, activeResponse: Response | null = null) { const { activeEnvironment } = this.props; const activeResponseId = activeResponse ? activeResponse._id : null; - await App._updateRequestMetaByParentId(requestId, { + await updateRequestMetaByParentId(requestId, { activeResponseId, }); diff --git a/packages/insomnia-app/app/ui/redux/selectors.ts b/packages/insomnia-app/app/ui/redux/selectors.ts index b23a9a43f..2cd768d8c 100644 --- a/packages/insomnia-app/app/ui/redux/selectors.ts +++ b/packages/insomnia-app/app/ui/redux/selectors.ts @@ -142,7 +142,7 @@ export const selectActiveWorkspaceMeta = createSelector( selectEntitiesLists, (activeWorkspace, entities) => { const id = activeWorkspace ? activeWorkspace._id : 'n/a'; - return entities.workspaceMetas.find(m => m.parentId === id); + return entities.workspaceMetas.find(workspaceMeta => workspaceMeta.parentId === id); }, ); diff --git a/packages/insomnia-app/package-lock.json b/packages/insomnia-app/package-lock.json index 89216dba9..19d3941dc 100644 --- a/packages/insomnia-app/package-lock.json +++ b/packages/insomnia-app/package-lock.json @@ -6123,6 +6123,18 @@ "@types/react": "*" } }, + "@types/react-redux": { + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", + "dev": true, + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "@types/react-tabs": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/react-tabs/-/react-tabs-2.3.2.tgz", diff --git a/packages/insomnia-app/package.json b/packages/insomnia-app/package.json index c44604de6..826c5037f 100644 --- a/packages/insomnia-app/package.json +++ b/packages/insomnia-app/package.json @@ -217,6 +217,7 @@ "@types/react": "^16.14.5", "@types/react-dom": "^16.9.12", "@types/react-tabs": "^2.3.2", + "@types/react-redux": "^7.1.22", "@types/redux-mock-store": "^1.0.2", "@types/styled-components": "^4.4.3", "@types/swagger-ui-react": "^3.35.0",