2018-06-25 17:42:50 +00:00
|
|
|
|
import React, { PureComponent } from 'react';
|
2017-08-10 01:56:27 +00:00
|
|
|
|
import PropTypes from 'prop-types';
|
2017-03-03 01:44:07 +00:00
|
|
|
|
import autobind from 'autobind-decorator';
|
2017-02-01 20:21:14 +00:00
|
|
|
|
import fs from 'fs';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import { clipboard, ipcRenderer, remote } from 'electron';
|
|
|
|
|
import { parse as urlParse } from 'url';
|
2019-04-26 05:47:42 +00:00
|
|
|
|
import HTTPSnippet from 'httpsnippet';
|
2016-07-19 16:15:03 +00:00
|
|
|
|
import ReactDOM from 'react-dom';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
|
import { bindActionCreators } from 'redux';
|
2017-03-08 05:52:17 +00:00
|
|
|
|
import Wrapper from '../components/wrapper';
|
|
|
|
|
import WorkspaceEnvironmentsEditModal from '../components/modals/workspace-environments-edit-modal';
|
|
|
|
|
import Toast from '../components/toast';
|
|
|
|
|
import CookiesModal from '../components/modals/cookies-modal';
|
|
|
|
|
import RequestSwitcherModal from '../components/modals/request-switcher-modal';
|
2018-10-17 16:42:33 +00:00
|
|
|
|
import SettingsModal, { TAB_INDEX_SHORTCUTS } from '../components/modals/settings-modal';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import {
|
|
|
|
|
COLLAPSE_SIDEBAR_REMS,
|
|
|
|
|
DEFAULT_PANE_HEIGHT,
|
|
|
|
|
DEFAULT_PANE_WIDTH,
|
|
|
|
|
DEFAULT_SIDEBAR_WIDTH,
|
|
|
|
|
MAX_PANE_HEIGHT,
|
|
|
|
|
MAX_PANE_WIDTH,
|
|
|
|
|
MAX_SIDEBAR_REMS,
|
|
|
|
|
MIN_PANE_HEIGHT,
|
|
|
|
|
MIN_PANE_WIDTH,
|
|
|
|
|
MIN_SIDEBAR_REMS,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
PREVIEW_MODE_SOURCE,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
} from '../../common/constants';
|
2016-11-16 17:18:39 +00:00
|
|
|
|
import * as globalActions from '../redux/modules/global';
|
2016-11-10 05:56:23 +00:00
|
|
|
|
import * as db from '../../common/database';
|
|
|
|
|
import * as models from '../../models';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import {
|
|
|
|
|
selectActiveCookieJar,
|
|
|
|
|
selectActiveOAuth2Token,
|
|
|
|
|
selectActiveRequest,
|
|
|
|
|
selectActiveRequestMeta,
|
|
|
|
|
selectActiveRequestResponses,
|
|
|
|
|
selectActiveResponse,
|
|
|
|
|
selectActiveWorkspace,
|
|
|
|
|
selectActiveWorkspaceClientCertificates,
|
|
|
|
|
selectActiveWorkspaceMeta,
|
|
|
|
|
selectEntitiesLists,
|
|
|
|
|
selectSidebarChildren,
|
2019-04-18 00:50:03 +00:00
|
|
|
|
selectSyncItems,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
selectUnseenWorkspaces,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
selectWorkspaceRequestsAndRequestGroups,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
} from '../redux/selectors';
|
2017-03-08 05:52:17 +00:00
|
|
|
|
import RequestCreateModal from '../components/modals/request-create-modal';
|
|
|
|
|
import GenerateCodeModal from '../components/modals/generate-code-modal';
|
|
|
|
|
import WorkspaceSettingsModal from '../components/modals/workspace-settings-modal';
|
2017-03-28 22:45:23 +00:00
|
|
|
|
import RequestSettingsModal from '../components/modals/request-settings-modal';
|
|
|
|
|
import RequestRenderErrorModal from '../components/modals/request-render-error-modal';
|
2017-03-16 17:51:56 +00:00
|
|
|
|
import * as network from '../../network/network';
|
2019-04-18 00:50:03 +00:00
|
|
|
|
import { debounce, getContentDispositionHeader, getDataDirectory } from '../../common/misc';
|
2017-02-01 20:21:14 +00:00
|
|
|
|
import * as mime from 'mime-types';
|
|
|
|
|
import * as path from 'path';
|
2017-02-13 08:12:02 +00:00
|
|
|
|
import * as render from '../../common/render';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import { getKeys } from '../../templating/utils';
|
|
|
|
|
import { showAlert, showModal, showPrompt } from '../components/modals/index';
|
|
|
|
|
import { exportHarRequest } from '../../common/har';
|
2019-03-12 16:38:30 +00:00
|
|
|
|
import { hotKeyRefs } from '../../common/hotkeys';
|
|
|
|
|
import { executeHotKey } from '../../common/hotkeys-listener';
|
2017-11-01 14:13:51 +00:00
|
|
|
|
import KeydownBinder from '../components/keydown-binder';
|
2017-10-13 13:01:27 +00:00
|
|
|
|
import ErrorBoundary from '../components/error-boundary';
|
2017-11-01 14:54:57 +00:00
|
|
|
|
import * as plugins from '../../plugins';
|
|
|
|
|
import * as templating from '../../templating/index';
|
2017-11-10 14:13:03 +00:00
|
|
|
|
import AskModal from '../components/modals/ask-modal';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
import { updateMimeType } from '../../models/request';
|
2018-03-29 13:57:24 +00:00
|
|
|
|
import MoveRequestGroupModal from '../components/modals/move-request-group-modal';
|
2018-07-17 23:34:28 +00:00
|
|
|
|
import * as themes from '../../plugins/misc';
|
2019-02-27 15:01:51 +00:00
|
|
|
|
import ExportRequestsModal from '../components/modals/export-requests-modal';
|
2019-04-18 00:50:03 +00:00
|
|
|
|
import FileSystemDriver from '../../sync/store/drivers/file-system-driver';
|
|
|
|
|
import VCS from '../../sync/vcs';
|
|
|
|
|
import SyncMergeModal from '../components/modals/sync-merge-modal';
|
2016-03-20 04:47:43 +00:00
|
|
|
|
|
2017-03-03 01:44:07 +00:00
|
|
|
|
@autobind
|
2017-02-28 21:32:23 +00:00
|
|
|
|
class App extends PureComponent {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
constructor(props) {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
super(props);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this.state = {
|
2017-03-28 22:45:23 +00:00
|
|
|
|
showDragOverlay: false,
|
2016-12-01 01:50:59 +00:00
|
|
|
|
draggingSidebar: false,
|
2017-03-28 22:45:23 +00:00
|
|
|
|
draggingPaneHorizontal: false,
|
|
|
|
|
draggingPaneVertical: false,
|
2016-12-01 01:50:59 +00:00
|
|
|
|
sidebarWidth: props.sidebarWidth || DEFAULT_SIDEBAR_WIDTH,
|
2017-03-28 22:45:23 +00:00
|
|
|
|
paneWidth: props.paneWidth || DEFAULT_PANE_WIDTH,
|
2018-11-30 05:50:30 +00:00
|
|
|
|
paneHeight: props.paneHeight || DEFAULT_PANE_HEIGHT,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
isVariableUncovered: props.isVariableUncovered || false,
|
2019-04-18 00:50:03 +00:00
|
|
|
|
vcs: null,
|
|
|
|
|
forceRefreshCounter: 0,
|
2019-05-08 20:31:54 +00:00
|
|
|
|
forceRefreshHeaderCounter: 0,
|
2019-12-10 16:29:48 +00:00
|
|
|
|
isMigratingChildren: false,
|
2016-12-01 01:50:59 +00:00
|
|
|
|
};
|
2016-11-25 20:55:15 +00:00
|
|
|
|
|
2017-03-12 00:31:23 +00:00
|
|
|
|
this._getRenderContextPromiseCache = {};
|
2017-02-27 21:00:13 +00:00
|
|
|
|
|
2018-10-17 16:42:33 +00:00
|
|
|
|
this._savePaneWidth = debounce(paneWidth => this._updateActiveWorkspaceMeta({ paneWidth }));
|
|
|
|
|
this._savePaneHeight = debounce(paneHeight => this._updateActiveWorkspaceMeta({ paneHeight }));
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this._saveSidebarWidth = debounce(sidebarWidth =>
|
2018-12-12 17:36:11 +00:00
|
|
|
|
this._updateActiveWorkspaceMeta({ sidebarWidth }),
|
2018-06-25 17:42:50 +00:00
|
|
|
|
);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
|
2017-03-03 21:10:35 +00:00
|
|
|
|
this._globalKeyMap = null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_setGlobalKeyMap() {
|
2017-01-27 01:00:27 +00:00
|
|
|
|
this._globalKeyMap = [
|
2019-02-08 18:20:24 +00:00
|
|
|
|
[
|
|
|
|
|
hotKeyRefs.PREFERENCES_SHOW_GENERAL,
|
|
|
|
|
() => {
|
|
|
|
|
showModal(SettingsModal);
|
|
|
|
|
},
|
|
|
|
|
],
|
2018-12-11 23:11:54 +00:00
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.PREFERENCES_SHOW_KEYBOARD_SHORTCUTS,
|
2018-12-11 23:11:54 +00:00
|
|
|
|
() => {
|
|
|
|
|
showModal(SettingsModal, TAB_INDEX_SHORTCUTS);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-12-11 23:11:54 +00:00
|
|
|
|
],
|
2019-05-10 01:18:34 +00:00
|
|
|
|
[
|
|
|
|
|
hotKeyRefs.SHOW_RECENT_REQUESTS,
|
|
|
|
|
() => {
|
|
|
|
|
showModal(RequestSwitcherModal, {
|
|
|
|
|
disableInput: true,
|
|
|
|
|
maxRequests: 10,
|
|
|
|
|
maxWorkspaces: 0,
|
|
|
|
|
selectOnKeyup: true,
|
|
|
|
|
title: 'Recent Requests',
|
2019-05-10 19:19:47 +00:00
|
|
|
|
hideNeverActiveRequests: true,
|
2019-05-10 14:42:08 +00:00
|
|
|
|
|
|
|
|
|
// Add an open delay so the dialog won't show for quick presses
|
|
|
|
|
openDelay: 150,
|
2019-05-10 01:18:34 +00:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
],
|
2018-06-25 17:42:50 +00:00
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.WORKSPACE_SHOW_SETTINGS,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeWorkspace } = this.props;
|
|
|
|
|
showModal(WorkspaceSettingsModal, activeWorkspace);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_SETTINGS,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
if (this.props.activeRequest) {
|
|
|
|
|
showModal(RequestSettingsModal, {
|
2018-12-12 17:36:11 +00:00
|
|
|
|
request: this.props.activeRequest,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_QUICK_SWITCH,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
showModal(RequestSwitcherModal);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
2019-03-12 16:38:30 +00:00
|
|
|
|
[hotKeyRefs.REQUEST_SEND, this._handleSendShortcut],
|
2018-06-25 17:42:50 +00:00
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.ENVIRONMENT_SHOW_EDITOR,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeWorkspace } = this.props;
|
|
|
|
|
showModal(WorkspaceEnvironmentsEditModal, activeWorkspace);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.SHOW_COOKIES_EDITOR,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeWorkspace } = this.props;
|
|
|
|
|
showModal(CookiesModal, activeWorkspace);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
2019-04-26 20:58:05 +00:00
|
|
|
|
[
|
|
|
|
|
hotKeyRefs.REQUEST_QUICK_CREATE,
|
|
|
|
|
async () => {
|
|
|
|
|
const { activeRequest, activeWorkspace } = this.props;
|
|
|
|
|
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
|
|
|
|
|
const request = await models.request.create({ parentId, name: 'New Request' });
|
|
|
|
|
await this._handleSetActiveRequest(request._id);
|
|
|
|
|
},
|
|
|
|
|
],
|
2018-06-25 17:42:50 +00:00
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_CREATE,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeRequest, activeWorkspace } = this.props;
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this._requestCreate(parentId);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_DELETE,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeRequest } = this.props;
|
|
|
|
|
|
|
|
|
|
if (!activeRequest) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-11-10 17:03:36 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
showModal(AskModal, {
|
|
|
|
|
title: 'Delete Request?',
|
|
|
|
|
message: `Really delete ${activeRequest.name}?`,
|
|
|
|
|
onDone: confirmed => {
|
|
|
|
|
if (!confirmed) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
models.request.remove(activeRequest);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
() => {
|
|
|
|
|
const { activeRequest, activeWorkspace } = this.props;
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this._requestGroupCreate(parentId);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_GENERATE_CODE_EDITOR,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async () => {
|
|
|
|
|
showModal(GenerateCodeModal, this.props.activeRequest);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-06-25 17:42:50 +00:00
|
|
|
|
],
|
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.REQUEST_SHOW_DUPLICATE,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async () => {
|
|
|
|
|
await this._requestDuplicate(this.props.activeRequest);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2018-11-30 05:50:30 +00:00
|
|
|
|
],
|
2019-05-07 14:46:35 +00:00
|
|
|
|
[
|
|
|
|
|
hotKeyRefs.REQUEST_TOGGLE_PIN,
|
|
|
|
|
async () => {
|
|
|
|
|
if (!this.props.activeRequest) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const metas = Object.values(this.props.entities.requestMetas).find(
|
|
|
|
|
m => m.parentId === this.props.activeRequest._id,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await this._handleSetRequestPinned(this.props.activeRequest, !(metas && metas.pinned));
|
|
|
|
|
},
|
|
|
|
|
],
|
2019-02-08 18:20:24 +00:00
|
|
|
|
[hotKeyRefs.PLUGIN_RELOAD, this._handleReloadPlugins],
|
2018-11-30 05:50:30 +00:00
|
|
|
|
[
|
2019-03-12 16:38:30 +00:00
|
|
|
|
hotKeyRefs.ENVIRONMENT_UNCOVER_VARIABLES,
|
2018-11-30 05:50:30 +00:00
|
|
|
|
async () => {
|
|
|
|
|
await this._updateIsVariableUncovered();
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
|
|
|
|
],
|
2019-12-14 04:11:13 +00:00
|
|
|
|
[
|
|
|
|
|
hotKeyRefs.SIDEBAR_TOGGLE,
|
|
|
|
|
() => {
|
|
|
|
|
this._handleToggleSidebar();
|
|
|
|
|
},
|
|
|
|
|
],
|
2017-01-27 01:00:27 +00:00
|
|
|
|
];
|
|
|
|
|
}
|
2016-07-19 16:59:26 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSendShortcut() {
|
|
|
|
|
const { activeRequest, activeEnvironment } = this.props;
|
2017-06-07 21:51:24 +00:00
|
|
|
|
await this._handleSendRequestWithEnvironment(
|
|
|
|
|
activeRequest ? activeRequest._id : 'n/a',
|
2018-12-12 17:36:11 +00:00
|
|
|
|
activeEnvironment ? activeEnvironment._id : 'n/a',
|
2017-06-07 21:51:24 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_setRequestPaneRef(n) {
|
2017-03-03 01:44:07 +00:00
|
|
|
|
this._requestPane = n;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_setResponsePaneRef(n) {
|
2017-03-03 01:44:07 +00:00
|
|
|
|
this._responsePane = n;
|
|
|
|
|
}
|
2016-11-25 20:55:15 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_setSidebarRef(n) {
|
2017-03-03 01:44:07 +00:00
|
|
|
|
this._sidebar = n;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_requestGroupCreate(parentId) {
|
2017-06-01 02:04:27 +00:00
|
|
|
|
showPrompt({
|
2017-07-20 01:55:40 +00:00
|
|
|
|
title: 'New Folder',
|
2016-08-15 17:04:36 +00:00
|
|
|
|
defaultValue: 'My Folder',
|
2016-11-23 20:44:46 +00:00
|
|
|
|
submitName: 'Create',
|
2016-11-29 20:55:31 +00:00
|
|
|
|
label: 'Name',
|
2017-06-01 02:04:27 +00:00
|
|
|
|
selectText: true,
|
2018-05-25 01:40:36 +00:00
|
|
|
|
onComplete: async name => {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const requestGroup = await models.requestGroup.create({
|
|
|
|
|
parentId,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
name,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
|
|
|
|
await models.requestGroupMeta.create({
|
|
|
|
|
parentId: requestGroup._id,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
collapsed: false,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2016-08-15 17:04:36 +00:00
|
|
|
|
});
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-08-15 17:04:36 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_requestCreate(parentId) {
|
2017-06-09 21:42:19 +00:00
|
|
|
|
showModal(RequestCreateModal, {
|
|
|
|
|
parentId,
|
|
|
|
|
onComplete: request => {
|
|
|
|
|
this._handleSetActiveRequest(request._id);
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2017-06-09 21:42:19 +00:00
|
|
|
|
});
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-04-17 20:35:35 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
static async _requestGroupDuplicate(requestGroup) {
|
2019-12-11 17:48:56 +00:00
|
|
|
|
showPrompt({
|
|
|
|
|
title: 'Duplicate Folder',
|
|
|
|
|
defaultValue: requestGroup.name,
|
|
|
|
|
submitName: 'Create',
|
|
|
|
|
label: 'New Name',
|
|
|
|
|
selectText: true,
|
|
|
|
|
onComplete: async name => {
|
|
|
|
|
await models.requestGroup.duplicate(requestGroup, { name });
|
|
|
|
|
},
|
|
|
|
|
});
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-11-28 07:12:17 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
static async _requestGroupMove(requestGroup) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
showModal(MoveRequestGroupModal, { requestGroup });
|
2018-03-29 13:57:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 17:48:56 +00:00
|
|
|
|
_requestDuplicate(request) {
|
2016-11-27 21:42:38 +00:00
|
|
|
|
if (!request) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 17:48:56 +00:00
|
|
|
|
showPrompt({
|
|
|
|
|
title: 'Duplicate Request',
|
|
|
|
|
defaultValue: request.name,
|
|
|
|
|
submitName: 'Create',
|
|
|
|
|
label: 'New Name',
|
|
|
|
|
selectText: true,
|
|
|
|
|
onComplete: async name => {
|
|
|
|
|
const newRequest = await models.request.duplicate(request, { name });
|
|
|
|
|
await this._handleSetActiveRequest(newRequest._id);
|
|
|
|
|
},
|
|
|
|
|
});
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2017-02-13 08:12:02 +00:00
|
|
|
|
|
2019-12-11 17:48:56 +00:00
|
|
|
|
_workspaceDuplicate(callback) {
|
2017-06-07 00:07:09 +00:00
|
|
|
|
const workspace = this.props.activeWorkspace;
|
|
|
|
|
showPrompt({
|
2017-07-20 01:55:40 +00:00
|
|
|
|
title: 'Duplicate Workspace',
|
2019-12-11 17:48:56 +00:00
|
|
|
|
defaultValue: workspace.name,
|
|
|
|
|
submitName: 'Create',
|
2017-06-07 00:07:09 +00:00
|
|
|
|
selectText: true,
|
2019-12-11 17:48:56 +00:00
|
|
|
|
label: 'New Name',
|
2017-06-07 00:07:09 +00:00
|
|
|
|
onComplete: async name => {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const newWorkspace = await db.duplicate(workspace, { name });
|
2017-06-07 00:07:09 +00:00
|
|
|
|
await this.props.handleSetActiveWorkspace(newWorkspace._id);
|
|
|
|
|
callback();
|
2018-12-12 17:36:11 +00:00
|
|
|
|
},
|
2017-06-07 00:07:09 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _fetchRenderContext() {
|
2018-06-25 19:58:03 +00:00
|
|
|
|
const { activeEnvironment, activeRequest, activeWorkspace } = this.props;
|
2017-03-12 00:31:23 +00:00
|
|
|
|
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
2018-06-25 20:10:12 +00:00
|
|
|
|
|
|
|
|
|
const ancestors = await db.withAncestors(activeRequest || activeWorkspace, [
|
|
|
|
|
models.request.type,
|
|
|
|
|
models.requestGroup.type,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
models.workspace.type,
|
2018-06-25 20:10:12 +00:00
|
|
|
|
]);
|
2018-06-25 19:58:03 +00:00
|
|
|
|
|
|
|
|
|
return render.getRenderContext(activeRequest, environmentId, ancestors);
|
2017-03-12 00:31:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleGetRenderContext() {
|
2017-03-12 00:31:23 +00:00
|
|
|
|
const context = await this._fetchRenderContext();
|
|
|
|
|
const keys = getKeys(context);
|
2018-06-25 17:42:50 +00:00
|
|
|
|
return { context, keys };
|
2017-03-12 00:31:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-27 21:00:13 +00:00
|
|
|
|
/**
|
|
|
|
|
* Heavily optimized render function
|
|
|
|
|
*
|
|
|
|
|
* @param text - template to render
|
|
|
|
|
* @param contextCacheKey - if rendering multiple times in parallel, set this
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleRenderText(text, contextCacheKey = null) {
|
2018-10-17 16:42:33 +00:00
|
|
|
|
if (!contextCacheKey || !this._getRenderContextPromiseCache[contextCacheKey]) {
|
2017-02-27 21:00:13 +00:00
|
|
|
|
// NOTE: We're caching promises here to avoid race conditions
|
2019-04-18 00:50:03 +00:00
|
|
|
|
this._getRenderContextPromiseCache[contextCacheKey] = this._fetchRenderContext();
|
2017-02-27 21:00:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set timeout to delete the key eventually
|
2018-10-17 16:42:33 +00:00
|
|
|
|
setTimeout(() => delete this._getRenderContextPromiseCache[contextCacheKey], 5000);
|
2017-02-27 21:00:13 +00:00
|
|
|
|
|
2017-03-12 00:31:23 +00:00
|
|
|
|
const context = await this._getRenderContextPromiseCache[contextCacheKey];
|
2017-04-11 21:20:01 +00:00
|
|
|
|
return render.render(text, context);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-11-27 21:42:38 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleGenerateCodeForActiveRequest() {
|
2019-04-18 00:50:03 +00:00
|
|
|
|
App._handleGenerateCode(this.props.activeRequest);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2017-02-01 20:21:14 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
static _handleGenerateCode(request) {
|
2017-02-01 20:21:14 +00:00
|
|
|
|
showModal(GenerateCodeModal, request);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-11-28 07:12:17 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleCopyAsCurl(request) {
|
|
|
|
|
const { activeEnvironment } = this.props;
|
2017-06-29 18:27:29 +00:00
|
|
|
|
const environmentId = activeEnvironment ? activeEnvironment._id : 'n/a';
|
2017-11-01 11:23:22 +00:00
|
|
|
|
const har = await exportHarRequest(request._id, environmentId);
|
2017-06-29 18:27:29 +00:00
|
|
|
|
const snippet = new HTTPSnippet(har);
|
|
|
|
|
const cmd = snippet.convert('shell', 'curl');
|
|
|
|
|
clipboard.writeText(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
static async _updateRequestGroupMetaByParentId(requestGroupId, patch) {
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const requestGroupMeta = await models.requestGroupMeta.getByParentId(requestGroupId);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
if (requestGroupMeta) {
|
|
|
|
|
await models.requestGroupMeta.update(requestGroupMeta, patch);
|
|
|
|
|
} else {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const newPatch = Object.assign({ parentId: requestGroupId }, patch);
|
2016-12-01 03:54:26 +00:00
|
|
|
|
await models.requestGroupMeta.create(newPatch);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-11-25 23:09:17 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _updateActiveWorkspaceMeta(patch) {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const workspaceId = this.props.activeWorkspace._id;
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const workspaceMeta = await models.workspaceMeta.getOrCreateByParentId(workspaceId);
|
2017-07-27 22:59:07 +00:00
|
|
|
|
if (workspaceMeta) {
|
|
|
|
|
return models.workspaceMeta.update(workspaceMeta, patch);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
} else {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const newPatch = Object.assign({ parentId: workspaceId }, patch);
|
2017-06-08 02:42:16 +00:00
|
|
|
|
return models.workspaceMeta.create(newPatch);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
static async _updateRequestMetaByParentId(requestId, patch) {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const requestMeta = await models.requestMeta.getByParentId(requestId);
|
|
|
|
|
if (requestMeta) {
|
2017-06-08 02:42:16 +00:00
|
|
|
|
return models.requestMeta.update(requestMeta, patch);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
} else {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const newPatch = Object.assign({ parentId: requestId }, patch);
|
2017-06-08 02:42:16 +00:00
|
|
|
|
return models.requestMeta.create(newPatch);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
_updateIsVariableUncovered() {
|
2018-11-30 05:50:30 +00:00
|
|
|
|
this.setState({ isVariableUncovered: !this.state.isVariableUncovered });
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleSetPaneWidth(paneWidth) {
|
|
|
|
|
this.setState({ paneWidth });
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this._savePaneWidth(paneWidth);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleSetPaneHeight(paneHeight) {
|
|
|
|
|
this.setState({ paneHeight });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
this._savePaneHeight(paneHeight);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetActiveRequest(activeRequestId) {
|
|
|
|
|
await this._updateActiveWorkspaceMeta({ activeRequestId });
|
2019-05-10 01:18:34 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(activeRequestId, { lastActive: Date.now() });
|
2017-03-03 20:09:08 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetActiveEnvironment(activeEnvironmentId) {
|
|
|
|
|
await this._updateActiveWorkspaceMeta({ activeEnvironmentId });
|
2017-03-29 02:21:49 +00:00
|
|
|
|
|
|
|
|
|
// Give it time to update and re-render
|
2019-11-26 21:17:55 +00:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this._wrapper && this._wrapper._forceRequestPaneRefresh();
|
|
|
|
|
}, 300);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleSetSidebarWidth(sidebarWidth) {
|
|
|
|
|
this.setState({ sidebarWidth });
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this._saveSidebarWidth(sidebarWidth);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetSidebarHidden(sidebarHidden) {
|
|
|
|
|
await this._updateActiveWorkspaceMeta({ sidebarHidden });
|
2017-03-03 20:09:08 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetSidebarFilter(sidebarFilter) {
|
|
|
|
|
await this._updateActiveWorkspaceMeta({ sidebarFilter });
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleSetRequestGroupCollapsed(requestGroupId, collapsed) {
|
2019-04-18 00:50:03 +00:00
|
|
|
|
App._updateRequestGroupMetaByParentId(requestGroupId, { collapsed });
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2019-05-07 14:46:35 +00:00
|
|
|
|
async _handleSetRequestPinned(request, pinned) {
|
|
|
|
|
App._updateRequestMetaByParentId(request._id, { pinned });
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleSetResponsePreviewMode(requestId, previewMode) {
|
2019-04-18 00:50:03 +00:00
|
|
|
|
App._updateRequestMetaByParentId(requestId, { previewMode });
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2019-06-03 18:45:22 +00:00
|
|
|
|
_handleUpdateDownloadPath(requestId, downloadPath) {
|
|
|
|
|
App._updateRequestMetaByParentId(requestId, { downloadPath });
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetResponseFilter(requestId, responseFilter) {
|
2019-04-18 00:50:03 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(requestId, { responseFilter });
|
2017-06-08 02:42:16 +00:00
|
|
|
|
|
|
|
|
|
clearTimeout(this._responseFilterHistorySaveTimeout);
|
|
|
|
|
this._responseFilterHistorySaveTimeout = setTimeout(async () => {
|
|
|
|
|
const meta = await models.requestMeta.getByParentId(requestId);
|
|
|
|
|
const responseFilterHistory = meta.responseFilterHistory.slice(0, 10);
|
|
|
|
|
|
|
|
|
|
// Already in history?
|
|
|
|
|
if (responseFilterHistory.includes(responseFilter)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-08 02:53:46 +00:00
|
|
|
|
// Blank?
|
|
|
|
|
if (!responseFilter) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-08 02:42:16 +00:00
|
|
|
|
responseFilterHistory.unshift(responseFilter);
|
2019-04-18 00:50:03 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(requestId, {
|
2018-12-12 17:36:11 +00:00
|
|
|
|
responseFilterHistory,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2017-06-08 02:42:16 +00:00
|
|
|
|
}, 2000);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleUpdateRequestMimeType(mimeType) {
|
2018-02-16 16:24:54 +00:00
|
|
|
|
if (!this.props.activeRequest) {
|
|
|
|
|
console.warn('Tried to update request mime-type when no active request');
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-02 09:49:10 +00:00
|
|
|
|
const requestMeta = await models.requestMeta.getOrCreateByParentId(
|
2018-12-12 17:36:11 +00:00
|
|
|
|
this.props.activeRequest._id,
|
2018-03-02 09:49:10 +00:00
|
|
|
|
);
|
2018-02-16 16:24:54 +00:00
|
|
|
|
const savedBody = requestMeta.savedRequestBody;
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const saveValue =
|
|
|
|
|
typeof mimeType !== 'string' // Switched to No body
|
|
|
|
|
? this.props.activeRequest.body
|
|
|
|
|
: {}; // Clear saved value in requestMeta
|
2018-02-16 16:24:54 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
await models.requestMeta.update(requestMeta, {
|
2018-12-12 17:36:11 +00:00
|
|
|
|
savedRequestBody: saveValue,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2018-02-16 16:24:54 +00:00
|
|
|
|
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const newRequest = await updateMimeType(this.props.activeRequest, mimeType, false, savedBody);
|
2018-02-16 16:24:54 +00:00
|
|
|
|
|
|
|
|
|
// Force it to update, because other editor components (header editor)
|
|
|
|
|
// needs to change. Need to wait a delay so the next render can finish
|
2019-05-08 20:31:54 +00:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.setState({ forceRefreshHeaderCounter: this.state.forceRefreshHeaderCounter + 1 });
|
|
|
|
|
}, 500);
|
2018-02-16 16:24:54 +00:00
|
|
|
|
|
|
|
|
|
return newRequest;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 20:15:25 +00:00
|
|
|
|
async _getDownloadLocation() {
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
|
const options = {
|
|
|
|
|
title: 'Select Download Location',
|
|
|
|
|
buttonLabel: 'Send and Save',
|
2018-12-12 17:36:11 +00:00
|
|
|
|
defaultPath: window.localStorage.getItem('insomnia.sendAndDownloadLocation'),
|
2018-10-17 20:15:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
remote.dialog.showSaveDialog(options, filename => {
|
|
|
|
|
window.localStorage.setItem('insomnia.sendAndDownloadLocation', filename);
|
|
|
|
|
resolve(filename);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 16:42:33 +00:00
|
|
|
|
async _handleSendAndDownloadRequestWithEnvironment(requestId, environmentId, dir) {
|
2019-04-18 04:58:09 +00:00
|
|
|
|
const { settings, handleStartLoading, handleStopLoading } = this.props;
|
|
|
|
|
|
2017-02-01 20:21:14 +00:00
|
|
|
|
const request = await models.request.getById(requestId);
|
|
|
|
|
if (!request) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: Since request is by far the most popular event, we will throttle
|
|
|
|
|
// it so that we only track it if the request has changed since the last one
|
|
|
|
|
const key = request._id;
|
|
|
|
|
if (this._sendRequestTrackingKey !== key) {
|
|
|
|
|
this._sendRequestTrackingKey = key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start loading
|
2019-04-18 04:58:09 +00:00
|
|
|
|
handleStartLoading(requestId);
|
2017-02-01 20:21:14 +00:00
|
|
|
|
|
|
|
|
|
try {
|
2017-11-23 21:57:08 +00:00
|
|
|
|
const responsePatch = await network.send(requestId, environmentId);
|
2017-09-18 18:19:04 +00:00
|
|
|
|
const headers = responsePatch.headers || [];
|
|
|
|
|
const header = getContentDispositionHeader(headers);
|
|
|
|
|
const nameFromHeader = header ? header.value : null;
|
|
|
|
|
|
2019-04-26 22:38:35 +00:00
|
|
|
|
if (
|
|
|
|
|
responsePatch.bodyPath &&
|
|
|
|
|
responsePatch.statusCode >= 200 &&
|
|
|
|
|
responsePatch.statusCode < 300
|
|
|
|
|
) {
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const extension = mime.extension(responsePatch.contentType) || 'unknown';
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const name =
|
2018-10-17 16:42:33 +00:00
|
|
|
|
nameFromHeader || `${request.name.replace(/\s/g, '-').toLowerCase()}.${extension}`;
|
2017-11-21 17:49:17 +00:00
|
|
|
|
|
2018-10-17 20:15:25 +00:00
|
|
|
|
let filename;
|
|
|
|
|
if (dir) {
|
|
|
|
|
filename = path.join(dir, name);
|
|
|
|
|
} else {
|
|
|
|
|
filename = await this._getDownloadLocation();
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-21 17:49:17 +00:00
|
|
|
|
const to = fs.createWriteStream(filename);
|
2017-11-23 21:57:08 +00:00
|
|
|
|
const readStream = models.response.getBodyStream(responsePatch);
|
2017-11-21 17:49:17 +00:00
|
|
|
|
|
2017-11-23 21:57:08 +00:00
|
|
|
|
if (!readStream) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readStream.pipe(to);
|
|
|
|
|
|
|
|
|
|
readStream.on('end', async () => {
|
|
|
|
|
responsePatch.error = `Saved to ${filename}`;
|
2019-04-18 04:58:09 +00:00
|
|
|
|
await models.response.create(responsePatch, settings.maxHistoryResponses);
|
2017-11-21 17:49:17 +00:00
|
|
|
|
});
|
|
|
|
|
|
2017-11-23 21:57:08 +00:00
|
|
|
|
readStream.on('error', async err => {
|
2018-10-17 16:42:33 +00:00
|
|
|
|
console.warn('Failed to download request after sending', responsePatch.bodyPath, err);
|
2019-04-18 04:58:09 +00:00
|
|
|
|
await models.response.create(responsePatch, settings.maxHistoryResponses);
|
2017-02-01 20:21:14 +00:00
|
|
|
|
});
|
2019-04-26 22:38:35 +00:00
|
|
|
|
} else {
|
|
|
|
|
// Save the bad responses so failures are shown still
|
|
|
|
|
await models.response.create(responsePatch, settings.maxHistoryResponses);
|
2017-02-01 20:21:14 +00:00
|
|
|
|
}
|
2017-07-17 22:37:24 +00:00
|
|
|
|
} catch (err) {
|
|
|
|
|
showAlert({
|
|
|
|
|
title: 'Unexpected Request Failure',
|
|
|
|
|
message: (
|
|
|
|
|
<div>
|
|
|
|
|
<p>The request failed due to an unhandled error:</p>
|
|
|
|
|
<code className="wide selectable">
|
|
|
|
|
<pre>{err.message}</pre>
|
|
|
|
|
</code>
|
|
|
|
|
</div>
|
2018-12-12 17:36:11 +00:00
|
|
|
|
),
|
2017-07-17 22:37:24 +00:00
|
|
|
|
});
|
2017-02-01 20:21:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unset active response because we just made a new one
|
2019-04-18 00:50:03 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(requestId, {
|
2018-12-12 17:36:11 +00:00
|
|
|
|
activeResponseId: null,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2017-02-01 20:21:14 +00:00
|
|
|
|
|
|
|
|
|
// Stop loading
|
2019-04-18 04:58:09 +00:00
|
|
|
|
handleStopLoading(requestId);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2017-02-01 20:21:14 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSendRequestWithEnvironment(requestId, environmentId) {
|
2019-04-18 04:58:09 +00:00
|
|
|
|
const { handleStartLoading, handleStopLoading, settings } = this.props;
|
2016-12-05 22:42:40 +00:00
|
|
|
|
const request = await models.request.getById(requestId);
|
|
|
|
|
if (!request) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2016-12-05 22:42:40 +00:00
|
|
|
|
// NOTE: Since request is by far the most popular event, we will throttle
|
|
|
|
|
// it so that we only track it if the request has changed since the last noe
|
|
|
|
|
const key = `${request._id}::${request.modified}`;
|
|
|
|
|
if (this._sendRequestTrackingKey !== key) {
|
|
|
|
|
this._sendRequestTrackingKey = key;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-18 04:58:09 +00:00
|
|
|
|
handleStartLoading(requestId);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
|
|
|
|
try {
|
2017-11-21 17:49:17 +00:00
|
|
|
|
const responsePatch = await network.send(requestId, environmentId);
|
2019-04-18 04:58:09 +00:00
|
|
|
|
await models.response.create(responsePatch, settings.maxHistoryResponses);
|
2017-03-28 22:45:23 +00:00
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err.type === 'render') {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
showModal(RequestRenderErrorModal, { request, error: err });
|
2017-07-17 22:37:24 +00:00
|
|
|
|
} else {
|
|
|
|
|
showAlert({
|
|
|
|
|
title: 'Unexpected Request Failure',
|
|
|
|
|
message: (
|
|
|
|
|
<div>
|
|
|
|
|
<p>The request failed due to an unhandled error:</p>
|
|
|
|
|
<code className="wide selectable">
|
|
|
|
|
<pre>{err.message}</pre>
|
|
|
|
|
</code>
|
|
|
|
|
</div>
|
2018-12-12 17:36:11 +00:00
|
|
|
|
),
|
2017-07-17 22:37:24 +00:00
|
|
|
|
});
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unset active response because we just made a new one
|
2019-04-18 00:50:03 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(requestId, {
|
2018-12-12 17:36:11 +00:00
|
|
|
|
activeResponseId: null,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
|
|
|
|
// Stop loading
|
2019-04-18 04:58:09 +00:00
|
|
|
|
handleStopLoading(requestId);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleSetActiveResponse(requestId, activeResponse = null) {
|
2020-01-22 19:23:19 +00:00
|
|
|
|
const { activeEnvironment } = this.props;
|
2017-07-17 18:20:38 +00:00
|
|
|
|
const activeResponseId = activeResponse ? activeResponse._id : null;
|
2019-04-18 00:50:03 +00:00
|
|
|
|
await App._updateRequestMetaByParentId(requestId, { activeResponseId });
|
2017-06-12 21:49:46 +00:00
|
|
|
|
|
|
|
|
|
let response;
|
|
|
|
|
if (activeResponseId) {
|
|
|
|
|
response = await models.response.getById(activeResponseId);
|
|
|
|
|
} else {
|
2020-01-22 19:23:19 +00:00
|
|
|
|
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
|
|
|
|
response = await models.response.getLatestForRequest(requestId, environmentId);
|
2017-06-12 21:49:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const requestVersionId = response ? response.requestVersionId : 'n/a';
|
|
|
|
|
const request = await models.requestVersion.restore(requestVersionId);
|
|
|
|
|
|
|
|
|
|
if (request) {
|
|
|
|
|
// Refresh app to reflect changes. Using timeout because we need to
|
|
|
|
|
// wait for the request update to propagate.
|
|
|
|
|
setTimeout(() => this._wrapper._forceRequestPaneRefresh(), 500);
|
|
|
|
|
} else {
|
|
|
|
|
// Couldn't restore request. That's okay
|
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-12-01 01:50:59 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_requestCreateForWorkspace() {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this._requestCreate(this.props.activeWorkspace._id);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-11-25 23:09:17 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_startDragSidebar() {
|
|
|
|
|
this.setState({ draggingSidebar: true });
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-06-19 00:08:14 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_resetDragSidebar() {
|
2016-07-06 22:11:37 +00:00
|
|
|
|
// TODO: Remove setTimeout need be not triggering drag on double click
|
2016-12-01 01:50:59 +00:00
|
|
|
|
setTimeout(() => this._handleSetSidebarWidth(DEFAULT_SIDEBAR_WIDTH), 50);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-06-19 00:08:14 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_startDragPaneHorizontal() {
|
|
|
|
|
this.setState({ draggingPaneHorizontal: true });
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-06-19 00:08:14 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_startDragPaneVertical() {
|
|
|
|
|
this.setState({ draggingPaneVertical: true });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_resetDragPaneHorizontal() {
|
2016-07-06 22:11:37 +00:00
|
|
|
|
// TODO: Remove setTimeout need be not triggering drag on double click
|
2016-12-01 01:50:59 +00:00
|
|
|
|
setTimeout(() => this._handleSetPaneWidth(DEFAULT_PANE_WIDTH), 50);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-07-06 22:11:37 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_resetDragPaneVertical() {
|
2017-03-28 22:45:23 +00:00
|
|
|
|
// TODO: Remove setTimeout need be not triggering drag on double click
|
|
|
|
|
setTimeout(() => this._handleSetPaneHeight(DEFAULT_PANE_HEIGHT), 50);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleMouseMove(e) {
|
2017-03-28 22:45:23 +00:00
|
|
|
|
if (this.state.draggingPaneHorizontal) {
|
|
|
|
|
// Only pop the overlay after we've moved it a bit (so we don't block doubleclick);
|
|
|
|
|
const distance = this.props.paneWidth - this.state.paneWidth;
|
|
|
|
|
if (!this.state.showDragOverlay && Math.abs(distance) > 0.02 /* % */) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ showDragOverlay: true });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-03 04:32:45 +00:00
|
|
|
|
const requestPane = ReactDOM.findDOMNode(this._requestPane);
|
|
|
|
|
const responsePane = ReactDOM.findDOMNode(this._responsePane);
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
|
|
|
|
const requestPaneWidth = requestPane.offsetWidth;
|
|
|
|
|
const responsePaneWidth = responsePane.offsetWidth;
|
2017-03-12 00:31:23 +00:00
|
|
|
|
|
2016-07-06 20:18:26 +00:00
|
|
|
|
const pixelOffset = e.clientX - requestPane.offsetLeft;
|
|
|
|
|
let paneWidth = pixelOffset / (requestPaneWidth + responsePaneWidth);
|
|
|
|
|
paneWidth = Math.min(Math.max(paneWidth, MIN_PANE_WIDTH), MAX_PANE_WIDTH);
|
2017-03-12 00:31:23 +00:00
|
|
|
|
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this._handleSetPaneWidth(paneWidth);
|
2017-03-28 22:45:23 +00:00
|
|
|
|
} else if (this.state.draggingPaneVertical) {
|
|
|
|
|
// Only pop the overlay after we've moved it a bit (so we don't block doubleclick);
|
|
|
|
|
const distance = this.props.paneHeight - this.state.paneHeight;
|
|
|
|
|
if (!this.state.showDragOverlay && Math.abs(distance) > 0.02 /* % */) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ showDragOverlay: true });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const requestPane = ReactDOM.findDOMNode(this._requestPane);
|
|
|
|
|
const responsePane = ReactDOM.findDOMNode(this._responsePane);
|
|
|
|
|
|
|
|
|
|
const requestPaneHeight = requestPane.offsetHeight;
|
|
|
|
|
const responsePaneHeight = responsePane.offsetHeight;
|
|
|
|
|
|
|
|
|
|
const pixelOffset = e.clientY - requestPane.offsetTop;
|
|
|
|
|
let paneHeight = pixelOffset / (requestPaneHeight + responsePaneHeight);
|
2018-10-17 16:42:33 +00:00
|
|
|
|
paneHeight = Math.min(Math.max(paneHeight, MIN_PANE_HEIGHT), MAX_PANE_HEIGHT);
|
2017-03-28 22:45:23 +00:00
|
|
|
|
|
|
|
|
|
this._handleSetPaneHeight(paneHeight);
|
2016-07-06 20:18:26 +00:00
|
|
|
|
} else if (this.state.draggingSidebar) {
|
2017-03-28 22:45:23 +00:00
|
|
|
|
// Only pop the overlay after we've moved it a bit (so we don't block doubleclick);
|
|
|
|
|
const distance = this.props.sidebarWidth - this.state.sidebarWidth;
|
|
|
|
|
if (!this.state.showDragOverlay && Math.abs(distance) > 2 /* ems */) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ showDragOverlay: true });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-09 15:09:48 +00:00
|
|
|
|
const sidebar = ReactDOM.findDOMNode(this._sidebar);
|
|
|
|
|
const currentPixelWidth = sidebar.offsetWidth;
|
|
|
|
|
const ratio = (e.clientX - sidebar.offsetLeft) / currentPixelWidth;
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const width = this.state.sidebarWidth * ratio;
|
2017-03-12 00:31:23 +00:00
|
|
|
|
|
2017-04-21 04:30:52 +00:00
|
|
|
|
let sidebarWidth = Math.min(width, MAX_SIDEBAR_REMS);
|
|
|
|
|
|
|
|
|
|
if (sidebarWidth < COLLAPSE_SIDEBAR_REMS) {
|
|
|
|
|
sidebarWidth = MIN_SIDEBAR_REMS;
|
|
|
|
|
}
|
2017-03-12 00:31:23 +00:00
|
|
|
|
|
2016-12-01 01:50:59 +00:00
|
|
|
|
this._handleSetSidebarWidth(sidebarWidth);
|
2016-07-06 20:18:26 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleMouseUp() {
|
2016-07-06 20:18:26 +00:00
|
|
|
|
if (this.state.draggingSidebar) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ draggingSidebar: false, showDragOverlay: false });
|
2016-07-06 20:18:26 +00:00
|
|
|
|
}
|
2016-03-22 05:01:58 +00:00
|
|
|
|
|
2017-03-28 22:45:23 +00:00
|
|
|
|
if (this.state.draggingPaneHorizontal) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ draggingPaneHorizontal: false, showDragOverlay: false });
|
2017-03-28 22:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.state.draggingPaneVertical) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
this.setState({ draggingPaneVertical: false, showDragOverlay: false });
|
2016-06-19 07:21:43 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleKeyDown(e) {
|
2017-09-17 14:04:56 +00:00
|
|
|
|
for (const [definition, callback] of this._globalKeyMap) {
|
2019-03-12 16:38:30 +00:00
|
|
|
|
executeHotKey(e, definition, callback);
|
2017-01-27 01:00:27 +00:00
|
|
|
|
}
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2017-01-27 01:00:27 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_handleToggleMenuBar(hide) {
|
2017-05-24 16:25:22 +00:00
|
|
|
|
for (const win of remote.BrowserWindow.getAllWindows()) {
|
2017-05-24 16:46:18 +00:00
|
|
|
|
if (win.isMenuBarAutoHide() !== hide) {
|
2017-05-24 16:25:22 +00:00
|
|
|
|
win.setAutoHideMenuBar(hide);
|
|
|
|
|
win.setMenuBarVisibility(!hide);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async _handleToggleSidebar() {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const sidebarHidden = !this.props.sidebarHidden;
|
2017-02-27 21:00:13 +00:00
|
|
|
|
await this._handleSetSidebarHidden(sidebarHidden);
|
2017-03-03 01:44:07 +00:00
|
|
|
|
}
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
2019-03-05 06:53:45 +00:00
|
|
|
|
_handleShowExportRequestsModal() {
|
2019-02-27 15:01:51 +00:00
|
|
|
|
showModal(ExportRequestsModal);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_setWrapperRef(n) {
|
2017-03-03 01:44:07 +00:00
|
|
|
|
this._wrapper = n;
|
|
|
|
|
}
|
2016-11-09 04:16:38 +00:00
|
|
|
|
|
2019-02-08 18:20:24 +00:00
|
|
|
|
async _handleReloadPlugins() {
|
|
|
|
|
const { settings } = this.props;
|
2020-03-11 19:23:52 +00:00
|
|
|
|
await plugins.reloadPlugins();
|
2019-02-08 18:20:24 +00:00
|
|
|
|
templating.reload();
|
|
|
|
|
themes.setTheme(settings.theme);
|
|
|
|
|
console.log('[plugins] reloaded');
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-12 09:03:57 +00:00
|
|
|
|
/**
|
|
|
|
|
* Update document.title to be "Workspace (Environment) – Request"
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2018-06-25 17:42:50 +00:00
|
|
|
|
_updateDocumentTitle() {
|
|
|
|
|
const { activeWorkspace, activeEnvironment, activeRequest } = this.props;
|
2017-03-12 09:03:57 +00:00
|
|
|
|
|
|
|
|
|
let title = activeWorkspace.name;
|
|
|
|
|
|
|
|
|
|
if (activeEnvironment) {
|
|
|
|
|
title += ` (${activeEnvironment.name})`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (activeRequest) {
|
|
|
|
|
title += ` – ${activeRequest.name}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.title = title;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
componentDidUpdate(prevProps) {
|
2017-03-12 09:03:57 +00:00
|
|
|
|
this._updateDocumentTitle();
|
2019-04-18 00:50:03 +00:00
|
|
|
|
|
|
|
|
|
// Force app refresh if login state changes
|
|
|
|
|
if (prevProps.isLoggedIn !== this.props.isLoggedIn) {
|
|
|
|
|
this.setState(state => ({
|
|
|
|
|
forceRefreshCounter: state.forceRefreshCounter + 1,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _updateVCS(activeWorkspace) {
|
|
|
|
|
// Get the vcs and set it to null in the state while we update it
|
|
|
|
|
let vcs = this.state.vcs;
|
|
|
|
|
this.setState({ vcs: null });
|
|
|
|
|
|
|
|
|
|
if (!vcs) {
|
|
|
|
|
const directory = path.join(getDataDirectory(), 'version-control');
|
|
|
|
|
const driver = new FileSystemDriver({ directory });
|
|
|
|
|
vcs = new VCS(driver, async conflicts => {
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
|
showModal(SyncMergeModal, {
|
|
|
|
|
conflicts,
|
|
|
|
|
handleDone: conflicts => resolve(conflicts),
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-10 16:02:38 +00:00
|
|
|
|
await vcs.switchProject(activeWorkspace._id);
|
2019-04-18 00:50:03 +00:00
|
|
|
|
|
|
|
|
|
this.setState({ vcs });
|
2017-03-12 09:03:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async componentDidMount() {
|
2017-01-27 01:00:27 +00:00
|
|
|
|
// Bind mouse and key handlers
|
2016-07-06 20:18:26 +00:00
|
|
|
|
document.addEventListener('mouseup', this._handleMouseUp);
|
|
|
|
|
document.addEventListener('mousemove', this._handleMouseMove);
|
2017-03-03 21:10:35 +00:00
|
|
|
|
this._setGlobalKeyMap();
|
2016-07-25 22:27:29 +00:00
|
|
|
|
|
2017-03-12 09:03:57 +00:00
|
|
|
|
// Update title
|
|
|
|
|
this._updateDocumentTitle();
|
2016-07-25 22:27:29 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
// Update VCS
|
2019-04-18 22:47:11 +00:00
|
|
|
|
await this._updateVCS(this.props.activeWorkspace);
|
2019-04-18 00:50:03 +00:00
|
|
|
|
|
2017-02-13 08:12:02 +00:00
|
|
|
|
db.onChange(async changes => {
|
2018-06-08 20:47:49 +00:00
|
|
|
|
let needsRefresh = false;
|
|
|
|
|
|
2016-10-24 23:30:37 +00:00
|
|
|
|
for (const change of changes) {
|
2019-04-18 22:47:11 +00:00
|
|
|
|
const [type, doc, fromSync] = change;
|
2017-03-12 09:03:57 +00:00
|
|
|
|
|
2019-04-18 22:47:11 +00:00
|
|
|
|
const { vcs } = this.state;
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const { activeRequest } = this.props;
|
2016-11-07 20:24:38 +00:00
|
|
|
|
|
2016-12-03 05:15:38 +00:00
|
|
|
|
// Force refresh if environment changes
|
2017-01-13 19:21:03 +00:00
|
|
|
|
// TODO: Only do this for environments in this workspace (not easy because they're nested)
|
2016-12-03 05:15:38 +00:00
|
|
|
|
if (doc.type === models.environment.type) {
|
2017-01-11 21:59:35 +00:00
|
|
|
|
console.log('[App] Forcing update from environment change', change);
|
2018-06-08 20:47:49 +00:00
|
|
|
|
needsRefresh = true;
|
2016-10-24 23:30:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-03 05:15:38 +00:00
|
|
|
|
// Force refresh if sync changes the active request
|
2019-04-18 22:47:11 +00:00
|
|
|
|
if (fromSync && activeRequest && doc._id === activeRequest._id) {
|
2018-06-08 20:47:49 +00:00
|
|
|
|
needsRefresh = true;
|
2017-01-11 21:59:35 +00:00
|
|
|
|
console.log('[App] Forcing update from request change', change);
|
2016-12-03 05:15:38 +00:00
|
|
|
|
}
|
2019-04-18 22:47:11 +00:00
|
|
|
|
|
|
|
|
|
// Delete VCS project if workspace deleted
|
|
|
|
|
if (vcs && doc.type === models.workspace.type && type === db.CHANGE_REMOVE) {
|
|
|
|
|
await vcs.removeProjectsForRoot(doc._id);
|
|
|
|
|
}
|
2016-10-24 23:30:37 +00:00
|
|
|
|
}
|
2018-06-08 20:47:49 +00:00
|
|
|
|
|
|
|
|
|
if (needsRefresh) {
|
2019-11-26 21:17:55 +00:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this._wrapper && this._wrapper._forceRequestPaneRefresh();
|
|
|
|
|
}, 300);
|
2018-06-08 20:47:49 +00:00
|
|
|
|
}
|
2016-10-24 23:30:37 +00:00
|
|
|
|
});
|
|
|
|
|
|
2016-08-22 20:05:42 +00:00
|
|
|
|
ipcRenderer.on('toggle-preferences', () => {
|
2017-03-28 22:45:23 +00:00
|
|
|
|
showModal(SettingsModal);
|
2016-09-12 20:04:15 +00:00
|
|
|
|
});
|
|
|
|
|
|
2019-02-08 18:20:24 +00:00
|
|
|
|
ipcRenderer.on('reload-plugins', this._handleReloadPlugins);
|
2017-11-01 14:54:57 +00:00
|
|
|
|
|
2017-08-04 16:54:11 +00:00
|
|
|
|
ipcRenderer.on('toggle-preferences-shortcuts', () => {
|
|
|
|
|
showModal(SettingsModal, TAB_INDEX_SHORTCUTS);
|
|
|
|
|
});
|
|
|
|
|
|
2017-05-03 17:48:23 +00:00
|
|
|
|
ipcRenderer.on('run-command', (e, commandUri) => {
|
|
|
|
|
const parsed = urlParse(commandUri, true);
|
|
|
|
|
|
|
|
|
|
const command = `${parsed.hostname}${parsed.pathname}`;
|
|
|
|
|
const args = JSON.parse(JSON.stringify(parsed.query));
|
|
|
|
|
args.workspaceId = args.workspaceId || this.props.activeWorkspace._id;
|
|
|
|
|
|
|
|
|
|
this.props.handleCommand(command, args);
|
|
|
|
|
});
|
|
|
|
|
|
2017-11-01 14:13:51 +00:00
|
|
|
|
// NOTE: This is required for "drop" event to trigger.
|
2018-06-25 17:42:50 +00:00
|
|
|
|
document.addEventListener(
|
|
|
|
|
'dragover',
|
|
|
|
|
e => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
},
|
2018-12-12 17:36:11 +00:00
|
|
|
|
false,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
);
|
2017-11-01 14:13:51 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
document.addEventListener(
|
|
|
|
|
'drop',
|
|
|
|
|
async e => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const { activeWorkspace, handleImportUriToWorkspace } = this.props;
|
|
|
|
|
if (!activeWorkspace) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.dataTransfer.files.length === 0) {
|
|
|
|
|
console.log('[drag] Ignored drop event because no files present');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-11-01 14:13:51 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const file = e.dataTransfer.files[0];
|
|
|
|
|
const { path } = file;
|
|
|
|
|
const uri = `file://${path}`;
|
2017-11-01 14:13:51 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
await showAlert({
|
|
|
|
|
title: 'Confirm Data Import',
|
|
|
|
|
message: (
|
|
|
|
|
<span>
|
|
|
|
|
Import <code>{path}</code>?
|
|
|
|
|
</span>
|
|
|
|
|
),
|
2018-12-12 17:36:11 +00:00
|
|
|
|
addCancel: true,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
});
|
2017-11-01 14:13:51 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
handleImportUriToWorkspace(activeWorkspace._id, uri);
|
|
|
|
|
},
|
2018-12-12 17:36:11 +00:00
|
|
|
|
false,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
);
|
2017-11-01 14:13:51 +00:00
|
|
|
|
|
2016-11-25 20:55:15 +00:00
|
|
|
|
ipcRenderer.on('toggle-sidebar', this._handleToggleSidebar);
|
2017-05-03 17:48:23 +00:00
|
|
|
|
|
2017-05-24 16:25:22 +00:00
|
|
|
|
// handle this
|
|
|
|
|
this._handleToggleMenuBar(this.props.settings.autoHideMenuBar);
|
2017-11-22 21:10:34 +00:00
|
|
|
|
|
|
|
|
|
// Give it a bit before letting the backend know it's ready
|
|
|
|
|
setTimeout(() => ipcRenderer.send('window-ready'), 500);
|
2016-07-06 20:18:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-18 17:44:08 +00:00
|
|
|
|
componentWillUnmount() {
|
2017-01-27 01:00:27 +00:00
|
|
|
|
// Remove mouse and key handlers
|
2016-07-06 20:18:26 +00:00
|
|
|
|
document.removeEventListener('mouseup', this._handleMouseUp);
|
|
|
|
|
document.removeEventListener('mousemove', this._handleMouseMove);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 16:29:48 +00:00
|
|
|
|
_ensureWorkspaceChildren(props) {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const { activeWorkspace, activeCookieJar, environments } = props;
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const baseEnvironments = environments.filter(e => e.parentId === activeWorkspace._id);
|
2017-11-22 14:00:12 +00:00
|
|
|
|
|
|
|
|
|
// Nothing to do
|
|
|
|
|
if (baseEnvironments.length && activeCookieJar) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We already started migrating. Let it finish.
|
2019-12-10 16:29:48 +00:00
|
|
|
|
if (this.state.isMigratingChildren) {
|
2017-11-22 14:00:12 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prevent rendering of everything
|
2019-12-10 16:29:48 +00:00
|
|
|
|
this.setState({ isMigratingChildren: true }, async () => {
|
|
|
|
|
const flushId = await db.bufferChanges();
|
|
|
|
|
await models.environment.getOrCreateForWorkspace(activeWorkspace);
|
|
|
|
|
await models.cookieJar.getOrCreateForParentId(activeWorkspace._id);
|
|
|
|
|
await db.flushChanges(flushId);
|
|
|
|
|
|
|
|
|
|
this.setState({ isMigratingChildren: false });
|
|
|
|
|
});
|
2017-11-22 14:00:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-06 20:51:52 +00:00
|
|
|
|
// eslint-disable-next-line camelcase
|
|
|
|
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
2017-11-22 14:00:12 +00:00
|
|
|
|
this._ensureWorkspaceChildren(nextProps);
|
2019-04-18 00:50:03 +00:00
|
|
|
|
|
|
|
|
|
// Update VCS if needed
|
|
|
|
|
const { activeWorkspace } = this.props;
|
|
|
|
|
if (nextProps.activeWorkspace._id !== activeWorkspace._id) {
|
|
|
|
|
this._updateVCS(nextProps.activeWorkspace);
|
|
|
|
|
}
|
2017-11-22 14:00:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-06 20:51:52 +00:00
|
|
|
|
// eslint-disable-next-line camelcase
|
|
|
|
|
UNSAFE_componentWillMount() {
|
2017-11-22 14:00:12 +00:00
|
|
|
|
this._ensureWorkspaceChildren(this.props);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
render() {
|
2019-12-10 16:29:48 +00:00
|
|
|
|
if (this.state.isMigratingChildren) {
|
2017-11-22 14:00:12 +00:00
|
|
|
|
console.log('[app] Waiting for migration to complete');
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
const { activeWorkspace } = this.props;
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
paneWidth,
|
|
|
|
|
paneHeight,
|
|
|
|
|
sidebarWidth,
|
|
|
|
|
isVariableUncovered,
|
|
|
|
|
vcs,
|
|
|
|
|
forceRefreshCounter,
|
2019-05-08 20:31:54 +00:00
|
|
|
|
forceRefreshHeaderCounter,
|
2019-04-18 00:50:03 +00:00
|
|
|
|
} = this.state;
|
|
|
|
|
|
|
|
|
|
const uniquenessKey = `${forceRefreshCounter}::${activeWorkspace._id}`;
|
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
return (
|
2019-04-18 00:50:03 +00:00
|
|
|
|
<KeydownBinder onKeydown={this._handleKeyDown}>
|
|
|
|
|
<div className="app" key={uniquenessKey}>
|
2017-10-13 13:01:27 +00:00
|
|
|
|
<ErrorBoundary showAlert>
|
|
|
|
|
<Wrapper
|
|
|
|
|
{...this.props}
|
|
|
|
|
ref={this._setWrapperRef}
|
2019-04-18 00:50:03 +00:00
|
|
|
|
paneWidth={paneWidth}
|
|
|
|
|
paneHeight={paneHeight}
|
|
|
|
|
sidebarWidth={sidebarWidth}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
handleCreateRequestForWorkspace={this._requestCreateForWorkspace}
|
2019-05-07 14:46:35 +00:00
|
|
|
|
handleSetRequestPinned={this._handleSetRequestPinned}
|
2018-10-17 16:42:33 +00:00
|
|
|
|
handleSetRequestGroupCollapsed={this._handleSetRequestGroupCollapsed}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
handleActivateRequest={this._handleSetActiveRequest}
|
|
|
|
|
handleSetRequestPaneRef={this._setRequestPaneRef}
|
|
|
|
|
handleSetResponsePaneRef={this._setResponsePaneRef}
|
|
|
|
|
handleSetSidebarRef={this._setSidebarRef}
|
|
|
|
|
handleStartDragSidebar={this._startDragSidebar}
|
|
|
|
|
handleResetDragSidebar={this._resetDragSidebar}
|
|
|
|
|
handleStartDragPaneHorizontal={this._startDragPaneHorizontal}
|
|
|
|
|
handleStartDragPaneVertical={this._startDragPaneVertical}
|
|
|
|
|
handleResetDragPaneHorizontal={this._resetDragPaneHorizontal}
|
|
|
|
|
handleResetDragPaneVertical={this._resetDragPaneVertical}
|
|
|
|
|
handleCreateRequest={this._requestCreate}
|
|
|
|
|
handleRender={this._handleRenderText}
|
|
|
|
|
handleGetRenderContext={this._handleGetRenderContext}
|
|
|
|
|
handleDuplicateRequest={this._requestDuplicate}
|
2019-04-18 00:50:03 +00:00
|
|
|
|
handleDuplicateRequestGroup={App._requestGroupDuplicate}
|
|
|
|
|
handleMoveRequestGroup={App._requestGroupMove}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
handleDuplicateWorkspace={this._workspaceDuplicate}
|
|
|
|
|
handleCreateRequestGroup={this._requestGroupCreate}
|
2019-04-18 00:50:03 +00:00
|
|
|
|
handleGenerateCode={App._handleGenerateCode}
|
2018-10-17 16:42:33 +00:00
|
|
|
|
handleGenerateCodeForActiveRequest={this._handleGenerateCodeForActiveRequest}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
handleCopyAsCurl={this._handleCopyAsCurl}
|
|
|
|
|
handleSetResponsePreviewMode={this._handleSetResponsePreviewMode}
|
|
|
|
|
handleSetResponseFilter={this._handleSetResponseFilter}
|
2018-10-17 16:42:33 +00:00
|
|
|
|
handleSendRequestWithEnvironment={this._handleSendRequestWithEnvironment}
|
2018-06-25 17:42:50 +00:00
|
|
|
|
handleSendAndDownloadRequestWithEnvironment={
|
|
|
|
|
this._handleSendAndDownloadRequestWithEnvironment
|
|
|
|
|
}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
handleSetActiveResponse={this._handleSetActiveResponse}
|
|
|
|
|
handleSetActiveRequest={this._handleSetActiveRequest}
|
|
|
|
|
handleSetActiveEnvironment={this._handleSetActiveEnvironment}
|
|
|
|
|
handleSetSidebarFilter={this._handleSetSidebarFilter}
|
|
|
|
|
handleToggleMenuBar={this._handleToggleMenuBar}
|
2018-02-16 16:24:54 +00:00
|
|
|
|
handleUpdateRequestMimeType={this._handleUpdateRequestMimeType}
|
2019-03-05 06:53:45 +00:00
|
|
|
|
handleShowExportRequestsModal={this._handleShowExportRequestsModal}
|
2019-06-03 18:45:22 +00:00
|
|
|
|
handleUpdateDownloadPath={this._handleUpdateDownloadPath}
|
2019-04-18 00:50:03 +00:00
|
|
|
|
isVariableUncovered={isVariableUncovered}
|
2019-05-08 20:31:54 +00:00
|
|
|
|
headerEditorKey={forceRefreshHeaderCounter + ''}
|
2019-04-18 00:50:03 +00:00
|
|
|
|
vcs={vcs}
|
2017-10-13 13:01:27 +00:00
|
|
|
|
/>
|
|
|
|
|
</ErrorBoundary>
|
|
|
|
|
|
|
|
|
|
<ErrorBoundary showAlert>
|
2018-06-25 17:42:50 +00:00
|
|
|
|
<Toast />
|
2017-10-13 13:01:27 +00:00
|
|
|
|
</ErrorBoundary>
|
2017-09-17 14:04:56 +00:00
|
|
|
|
|
|
|
|
|
{/* Block all mouse activity by showing an overlay while dragging */}
|
2018-10-17 16:42:33 +00:00
|
|
|
|
{this.state.showDragOverlay ? <div className="blocker-overlay" /> : null}
|
2017-09-17 14:04:56 +00:00
|
|
|
|
</div>
|
|
|
|
|
</KeydownBinder>
|
2017-03-03 20:09:08 +00:00
|
|
|
|
);
|
2016-11-16 17:18:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
2017-03-08 05:52:17 +00:00
|
|
|
|
App.propTypes = {
|
|
|
|
|
// Required
|
|
|
|
|
sidebarWidth: PropTypes.number.isRequired,
|
|
|
|
|
paneWidth: PropTypes.number.isRequired,
|
2017-03-28 22:45:23 +00:00
|
|
|
|
paneHeight: PropTypes.number.isRequired,
|
2017-05-03 17:48:23 +00:00
|
|
|
|
handleCommand: PropTypes.func.isRequired,
|
2017-05-24 16:25:22 +00:00
|
|
|
|
settings: PropTypes.object.isRequired,
|
2019-04-18 00:50:03 +00:00
|
|
|
|
isLoggedIn: PropTypes.bool.isRequired,
|
2017-03-08 05:52:17 +00:00
|
|
|
|
activeWorkspace: PropTypes.shape({
|
2018-12-12 17:36:11 +00:00
|
|
|
|
_id: PropTypes.string.isRequired,
|
2017-03-08 05:52:17 +00:00
|
|
|
|
}).isRequired,
|
2017-06-07 00:07:09 +00:00
|
|
|
|
handleSetActiveWorkspace: PropTypes.func.isRequired,
|
2017-03-08 05:52:17 +00:00
|
|
|
|
|
|
|
|
|
// Optional
|
2017-03-12 00:31:23 +00:00
|
|
|
|
activeRequest: PropTypes.object,
|
|
|
|
|
activeEnvironment: PropTypes.shape({
|
2018-12-12 17:36:11 +00:00
|
|
|
|
_id: PropTypes.string.isRequired,
|
|
|
|
|
}),
|
2017-03-08 05:52:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
function mapStateToProps(state, props) {
|
|
|
|
|
const { entities, global } = state;
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
const { isLoading, loadingRequestIds, isLoggedIn } = global;
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
|
|
|
|
// Entities
|
2016-11-25 23:09:17 +00:00
|
|
|
|
const entitiesLists = selectEntitiesLists(state, props);
|
2019-06-07 15:25:02 +00:00
|
|
|
|
const {
|
|
|
|
|
workspaces,
|
|
|
|
|
environments,
|
|
|
|
|
requests,
|
|
|
|
|
requestGroups,
|
|
|
|
|
requestMetas,
|
|
|
|
|
requestVersions,
|
|
|
|
|
} = entitiesLists;
|
2016-11-25 23:09:17 +00:00
|
|
|
|
|
|
|
|
|
const settings = entitiesLists.settings[0];
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
|
|
|
|
// Workspace stuff
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const workspaceMeta = selectActiveWorkspaceMeta(state, props) || {};
|
2016-11-25 23:09:17 +00:00
|
|
|
|
const activeWorkspace = selectActiveWorkspace(state, props);
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const activeWorkspaceClientCertificates = selectActiveWorkspaceClientCertificates(state, props);
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const sidebarHidden = workspaceMeta.sidebarHidden || false;
|
|
|
|
|
const sidebarFilter = workspaceMeta.sidebarFilter || '';
|
|
|
|
|
const sidebarWidth = workspaceMeta.sidebarWidth || DEFAULT_SIDEBAR_WIDTH;
|
|
|
|
|
const paneWidth = workspaceMeta.paneWidth || DEFAULT_PANE_WIDTH;
|
2017-03-28 22:45:23 +00:00
|
|
|
|
const paneHeight = workspaceMeta.paneHeight || DEFAULT_PANE_HEIGHT;
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
|
|
|
|
// Request stuff
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const requestMeta = selectActiveRequestMeta(state, props) || {};
|
|
|
|
|
const activeRequest = selectActiveRequest(state, props);
|
|
|
|
|
const responsePreviewMode = requestMeta.previewMode || PREVIEW_MODE_SOURCE;
|
|
|
|
|
const responseFilter = requestMeta.responseFilter || '';
|
2017-06-08 02:42:16 +00:00
|
|
|
|
const responseFilterHistory = requestMeta.responseFilterHistory || [];
|
2019-06-03 18:45:22 +00:00
|
|
|
|
const responseDownloadPath = requestMeta.downloadPath || null;
|
2017-07-17 18:20:38 +00:00
|
|
|
|
|
2017-08-22 23:54:31 +00:00
|
|
|
|
// Cookie Jar
|
|
|
|
|
const activeCookieJar = selectActiveCookieJar(state, props);
|
|
|
|
|
|
2017-07-17 18:20:38 +00:00
|
|
|
|
// Response stuff
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const activeRequestResponses = selectActiveRequestResponses(state, props) || [];
|
2017-07-17 18:20:38 +00:00
|
|
|
|
const activeResponse = selectActiveResponse(state, props) || null;
|
2016-11-27 21:42:38 +00:00
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
// Environment stuff
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const activeEnvironmentId = workspaceMeta.activeEnvironmentId;
|
2016-11-16 17:18:39 +00:00
|
|
|
|
const activeEnvironment = entities.environments[activeEnvironmentId];
|
|
|
|
|
|
2017-03-23 22:10:42 +00:00
|
|
|
|
// OAuth2Token stuff
|
|
|
|
|
const oAuth2Token = selectActiveOAuth2Token(state, props);
|
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
// Find other meta things
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const loadStartTime = loadingRequestIds[activeRequest ? activeRequest._id : 'n/a'] || -1;
|
2016-11-25 23:09:17 +00:00
|
|
|
|
const sidebarChildren = selectSidebarChildren(state, props);
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const workspaceChildren = selectWorkspaceRequestsAndRequestGroups(state, props);
|
2017-07-27 22:59:07 +00:00
|
|
|
|
const unseenWorkspaces = selectUnseenWorkspaces(state, props);
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
2019-04-18 00:50:03 +00:00
|
|
|
|
// Sync stuff
|
|
|
|
|
const syncItems = selectSyncItems(state, props);
|
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
return Object.assign({}, state, {
|
2019-06-07 15:25:02 +00:00
|
|
|
|
activeCookieJar,
|
|
|
|
|
activeEnvironment,
|
2017-03-03 20:09:08 +00:00
|
|
|
|
activeRequest,
|
2017-07-17 18:20:38 +00:00
|
|
|
|
activeRequestResponses,
|
|
|
|
|
activeResponse,
|
2019-06-07 15:25:02 +00:00
|
|
|
|
activeWorkspace,
|
|
|
|
|
activeWorkspaceClientCertificates,
|
|
|
|
|
environments,
|
|
|
|
|
isLoading,
|
|
|
|
|
isLoggedIn,
|
|
|
|
|
loadStartTime,
|
|
|
|
|
oAuth2Token,
|
2017-03-28 22:45:23 +00:00
|
|
|
|
paneHeight,
|
2019-06-07 15:25:02 +00:00
|
|
|
|
paneWidth,
|
|
|
|
|
requestGroups,
|
|
|
|
|
requestMetas,
|
|
|
|
|
requestVersions,
|
|
|
|
|
requests,
|
|
|
|
|
responseDownloadPath,
|
2017-03-03 20:09:08 +00:00
|
|
|
|
responseFilter,
|
2017-06-08 02:42:16 +00:00
|
|
|
|
responseFilterHistory,
|
2019-06-07 15:25:02 +00:00
|
|
|
|
responsePreviewMode,
|
|
|
|
|
settings,
|
2017-03-03 20:09:08 +00:00
|
|
|
|
sidebarChildren,
|
2019-06-07 15:25:02 +00:00
|
|
|
|
sidebarFilter,
|
|
|
|
|
sidebarHidden,
|
|
|
|
|
sidebarWidth,
|
2019-04-18 00:50:03 +00:00
|
|
|
|
syncItems,
|
2019-06-07 15:25:02 +00:00
|
|
|
|
unseenWorkspaces,
|
|
|
|
|
workspaceChildren,
|
|
|
|
|
workspaces,
|
2017-03-03 21:10:35 +00:00
|
|
|
|
});
|
2016-11-16 17:18:39 +00:00
|
|
|
|
}
|
2016-07-06 20:18:26 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
function mapDispatchToProps(dispatch) {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
const global = bindActionCreators(globalActions, dispatch);
|
2016-04-26 07:29:24 +00:00
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
return {
|
2016-12-01 01:50:59 +00:00
|
|
|
|
handleStartLoading: global.loadRequestStart,
|
|
|
|
|
handleStopLoading: global.loadRequestStop,
|
|
|
|
|
|
|
|
|
|
handleSetActiveWorkspace: global.setActiveWorkspace,
|
|
|
|
|
handleImportFileToWorkspace: global.importFile,
|
2019-11-22 15:46:54 +00:00
|
|
|
|
handleImportClipBoardToWorkspace: global.importClipBoard,
|
2017-05-03 17:48:23 +00:00
|
|
|
|
handleImportUriToWorkspace: global.importUri,
|
|
|
|
|
handleCommand: global.newCommand,
|
2019-03-05 06:53:45 +00:00
|
|
|
|
handleExportFile: global.exportWorkspacesToFile,
|
|
|
|
|
handleExportRequestsToFile: global.exportRequestsToFile,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
handleMoveDoc: _moveDoc,
|
2016-11-16 17:18:39 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
2016-03-22 03:22:45 +00:00
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
async function _moveDoc(docToMove, parentId, targetId, targetOffset) {
|
2017-11-09 23:36:09 +00:00
|
|
|
|
// Nothing to do. We are in the same spot as we started
|
2017-06-13 20:45:15 +00:00
|
|
|
|
if (docToMove._id === targetId) {
|
2016-11-16 17:18:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-26 07:29:24 +00:00
|
|
|
|
|
2017-11-09 23:36:09 +00:00
|
|
|
|
// Don't allow dragging things into itself or children. This will disconnect
|
|
|
|
|
// the node from the tree and cause the item to no longer show in the UI.
|
|
|
|
|
const descendents = await db.withDescendants(docToMove);
|
|
|
|
|
for (const doc of descendents) {
|
|
|
|
|
if (doc._id === parentId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
function __updateDoc(doc, patch) {
|
2017-06-13 20:45:15 +00:00
|
|
|
|
models.getModel(docToMove.type).update(doc, patch);
|
2016-11-16 17:18:39 +00:00
|
|
|
|
}
|
2016-03-20 04:47:43 +00:00
|
|
|
|
|
2016-11-16 17:18:39 +00:00
|
|
|
|
if (targetId === null) {
|
|
|
|
|
// We are moving to an empty area. No sorting required
|
2018-06-25 17:42:50 +00:00
|
|
|
|
await __updateDoc(docToMove, { parentId });
|
2016-11-16 17:18:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: using requestToTarget's parentId so we can switch parents!
|
2017-06-13 20:45:15 +00:00
|
|
|
|
let docs = [
|
2018-06-25 17:42:50 +00:00
|
|
|
|
...(await models.request.findByParentId(parentId)),
|
2018-12-12 17:36:11 +00:00
|
|
|
|
...(await models.requestGroup.findByParentId(parentId)),
|
2018-06-25 17:42:50 +00:00
|
|
|
|
].sort((a, b) => (a.metaSortKey < b.metaSortKey ? -1 : 1));
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
2017-06-13 20:45:15 +00:00
|
|
|
|
// Find the index of doc B so we can re-order and save everything
|
|
|
|
|
for (let i = 0; i < docs.length; i++) {
|
|
|
|
|
const doc = docs[i];
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
2017-06-13 20:45:15 +00:00
|
|
|
|
if (doc._id === targetId) {
|
2016-11-16 17:18:39 +00:00
|
|
|
|
let before, after;
|
|
|
|
|
if (targetOffset < 0) {
|
|
|
|
|
// We're moving to below
|
2017-06-13 20:45:15 +00:00
|
|
|
|
before = docs[i];
|
|
|
|
|
after = docs[i + 1];
|
2016-11-16 17:18:39 +00:00
|
|
|
|
} else {
|
|
|
|
|
// We're moving to above
|
2017-06-13 20:45:15 +00:00
|
|
|
|
before = docs[i - 1];
|
|
|
|
|
after = docs[i];
|
2016-11-16 17:18:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 20:45:15 +00:00
|
|
|
|
const beforeKey = before ? before.metaSortKey : docs[0].metaSortKey - 100;
|
2018-10-17 16:42:33 +00:00
|
|
|
|
const afterKey = after ? after.metaSortKey : docs[docs.length - 1].metaSortKey + 100;
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
|
|
|
|
if (Math.abs(afterKey - beforeKey) < 0.000001) {
|
|
|
|
|
// If sort keys get too close together, we need to redistribute the list. This is
|
|
|
|
|
// not performant at all (need to update all siblings in DB), but it is extremely rare
|
|
|
|
|
// anyway
|
2017-11-22 00:07:28 +00:00
|
|
|
|
console.log(`[app] Recreating Sort Keys ${beforeKey} ${afterKey}`);
|
2016-11-16 17:18:39 +00:00
|
|
|
|
|
2017-11-22 14:00:12 +00:00
|
|
|
|
await db.bufferChanges(300);
|
2018-06-25 17:42:50 +00:00
|
|
|
|
docs.map((r, i) => __updateDoc(r, { metaSortKey: i * 100, parentId }));
|
2016-11-16 17:18:39 +00:00
|
|
|
|
} else {
|
2018-06-25 17:42:50 +00:00
|
|
|
|
const metaSortKey = afterKey - (afterKey - beforeKey) / 2;
|
|
|
|
|
__updateDoc(docToMove, { metaSortKey, parentId });
|
2016-11-16 17:18:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2016-04-16 23:24:57 +00:00
|
|
|
|
}
|
2016-03-20 04:47:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
|
export default connect(
|
|
|
|
|
mapStateToProps,
|
2018-12-12 17:36:11 +00:00
|
|
|
|
mapDispatchToProps,
|
2018-06-25 17:42:50 +00:00
|
|
|
|
)(App);
|