mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Verify Before Syncing (#98)
* Added an UNSET sync mode * Fixed tests * Remove sync logs and adjusted dropdown * Fixed duplication kve bug * Added sync config modal * AUtobind * Autobind working * Hot loading works again * Remove express * Fixed tests * Fix one thing * Fixed some hmr-related bugs
This commit is contained in:
parent
c1e9e718e9
commit
314daf155e
25
.babelrc
Normal file
25
.babelrc
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"presets": [
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"transform-decorators-legacy"
|
||||
],
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": [
|
||||
"react-hot-loader/babel"
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"presets": [
|
||||
"es2015"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-regenerator",
|
||||
"transform-runtime"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -5,6 +5,10 @@ build/*
|
||||
.DS_Store
|
||||
coverage
|
||||
|
||||
# Generated
|
||||
*.tmp.js
|
||||
*.map
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
@ -1,4 +1,4 @@
|
||||
export default {
|
||||
module.exports = {
|
||||
remote: {
|
||||
app: {
|
||||
getPath (name) {
|
||||
@ -11,4 +11,4 @@ export default {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,14 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
// HOT RELOADING IN DEV
|
||||
(function () {
|
||||
const script = document.createElement('script');
|
||||
script.src = (process.env.HOT) ? 'http://localhost:3333/bundle.js' : './bundle.js';
|
||||
document.write(script.outerHTML);
|
||||
}());
|
||||
</script>
|
||||
<script src="static/raven.min.js"></script>
|
||||
<script>
|
||||
// UPDATE HANDLERS
|
||||
@ -109,14 +117,6 @@
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
<script>
|
||||
// HOT RELOADING IN DEV
|
||||
(function () {
|
||||
const script = document.createElement('script');
|
||||
script.src = (process.env.HOT) ? 'http://localhost:3333/build/bundle.js' : './bundle.js';
|
||||
document.write(script.outerHTML);
|
||||
}());
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// SOME HELPERS
|
||||
|
@ -39,7 +39,7 @@ describe('Test push/pull behaviour', () => {
|
||||
|
||||
// Set up sync modes
|
||||
await sync.createOrUpdateConfig(resourceRequest.resourceGroupId, syncStorage.SYNC_MODE_ON);
|
||||
await sync.createOrUpdateConfig(resourceRequest2.resourceGroupId, syncStorage.SYNC_MODE_OFF);
|
||||
await sync.createOrUpdateConfig(resourceRequest2.resourceGroupId, syncStorage.SYNC_MODE_UNSET);
|
||||
|
||||
await sync.push(); // Push only active configs
|
||||
await sync.push(resourceRequest.resourceGroupId); // Force push rg_1
|
||||
@ -268,8 +268,19 @@ describe('Integration tests for creating Resources and pushing', () => {
|
||||
expect((await syncStorage.allConfigs()).length).toBe(2);
|
||||
expect((await syncStorage.allResources()).length).toBe(7);
|
||||
|
||||
// Mark all configs as auto sync
|
||||
const configs = await syncStorage.allConfigs();
|
||||
for (const config of configs) {
|
||||
await syncStorage.updateConfig(config, {
|
||||
syncMode: syncStorage.SYNC_MODE_ON
|
||||
});
|
||||
}
|
||||
|
||||
// Do initial push
|
||||
await sync.push();
|
||||
|
||||
// Reset mocks once again before tests
|
||||
await _setupSessionMocks();
|
||||
});
|
||||
|
||||
it('Resources created on DB change', async () => {
|
||||
@ -294,15 +305,10 @@ describe('Integration tests for creating Resources and pushing', () => {
|
||||
expect(_decryptResource(resource).url).toBe('https://google.com');
|
||||
expect(resource.removed).toBe(false);
|
||||
|
||||
expect(session.syncPush.mock.calls.length).toBe(2);
|
||||
expect(session.syncPush.mock.calls[0][0].length).toBe(7);
|
||||
// NOTE: This would be 1 if we were mocking the "push" response properly
|
||||
// and telling the client to set the created docs to dirty=false
|
||||
expect(session.syncPush.mock.calls[1][0].length).toBe(8);
|
||||
expect(session.syncPush.mock.calls.length).toBe(1);
|
||||
expect(session.syncPush.mock.calls[0][0].length).toBe(8);
|
||||
|
||||
expect(session.syncPull.mock.calls.length).toBe(1);
|
||||
expect(session.syncPull.mock.calls[0][0].blacklist.length).toBe(0);
|
||||
expect(session.syncPull.mock.calls[0][0].resources.length).toEqual(7);
|
||||
expect(session.syncPull.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('Resources revived on DB change', async () => {
|
||||
@ -358,13 +364,10 @@ describe('Integration tests for creating Resources and pushing', () => {
|
||||
expect(_decryptResource(updatedResource).name).toBe('New Name');
|
||||
expect(resource.removed).toBe(false);
|
||||
|
||||
expect(session.syncPush.mock.calls.length).toBe(2);
|
||||
expect(session.syncPush.mock.calls.length).toBe(1);
|
||||
expect(session.syncPush.mock.calls[0][0].length).toBe(7);
|
||||
expect(session.syncPush.mock.calls[1][0].length).toBe(7);
|
||||
|
||||
expect(session.syncPull.mock.calls.length).toBe(1);
|
||||
expect(session.syncPull.mock.calls[0][0].blacklist.length).toBe(0);
|
||||
expect(session.syncPull.mock.calls[0][0].resources.length).toEqual(7);
|
||||
expect(session.syncPull.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('Resources removed on DB change', async () => {
|
||||
@ -384,13 +387,10 @@ describe('Integration tests for creating Resources and pushing', () => {
|
||||
expect(resource.removed).toBe(false);
|
||||
expect(updatedResource.removed).toBe(true);
|
||||
|
||||
expect(session.syncPush.mock.calls.length).toBe(2);
|
||||
expect(session.syncPush.mock.calls.length).toBe(1);
|
||||
expect(session.syncPush.mock.calls[0][0].length).toBe(7);
|
||||
expect(session.syncPush.mock.calls[1][0].length).toBe(7);
|
||||
|
||||
expect(session.syncPull.mock.calls.length).toBe(1);
|
||||
expect(session.syncPull.mock.calls[0][0].blacklist.length).toBe(0);
|
||||
expect(session.syncPull.mock.calls[0][0].resources.length).toEqual(7);
|
||||
expect(session.syncPull.mock.calls).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -544,11 +544,8 @@ export async function fetchResourceGroup (resourceGroupId, invalidateCache = fal
|
||||
}
|
||||
|
||||
// Also make sure a config exists when we first fetch it.
|
||||
// TODO: This exists in multiple places, so move it to one place.
|
||||
const config = await getOrCreateConfig(resourceGroupId);
|
||||
const syncMode = config ? config.syncMode : store.SYNC_MODE_OFF;
|
||||
|
||||
await createOrUpdateConfig(resourceGroupId, syncMode);
|
||||
// (This may not be needed but we'll do it just in case)
|
||||
await ensureConfigExists(resourceGroupId);
|
||||
}
|
||||
|
||||
// Bust cached promise because we're done with it.
|
||||
@ -648,7 +645,7 @@ export async function createResourceGroup (parentId, name) {
|
||||
}
|
||||
|
||||
// Create a config for it
|
||||
await ensureConfigExists(resourceGroup.id, store.SYNC_MODE_ON);
|
||||
await ensureConfigExists(resourceGroup.id, store.SYNC_MODE_UNSET);
|
||||
|
||||
logger.debug(`Created ResourceGroup ${resourceGroup.id}`);
|
||||
return resourceGroup;
|
||||
@ -684,7 +681,6 @@ export async function createResourceForDoc (doc) {
|
||||
|
||||
if (!workspaceResource) {
|
||||
const workspaceResourceGroup = await createResourceGroup(workspace._id, workspace.name);
|
||||
await ensureConfigExists(workspaceResourceGroup.id, store.SYNC_MODE_OFF);
|
||||
workspaceResource = await createResource(workspace, workspaceResourceGroup.id);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ const TYPE_CONFIG = 'Config';
|
||||
|
||||
export const SYNC_MODE_OFF = 'paused';
|
||||
export const SYNC_MODE_ON = 'active';
|
||||
export const SYNC_MODE_NEVER = 'never';
|
||||
export const SYNC_MODE_UNSET = 'unset';
|
||||
|
||||
export function allActiveResources (resourceGroupId = null) {
|
||||
if (resourceGroupId) {
|
||||
@ -26,7 +28,7 @@ export function allResources () {
|
||||
return findResources({});
|
||||
}
|
||||
|
||||
export async function findResources (query) {
|
||||
export async function findResources (query = {}) {
|
||||
return _execDB(TYPE_RESOURCE, 'find', query);
|
||||
}
|
||||
|
||||
@ -118,12 +120,9 @@ export function allConfigs () {
|
||||
|
||||
export function findInactiveConfigs (excludedResourceGroupId = null) {
|
||||
if (excludedResourceGroupId) {
|
||||
return findConfigs({
|
||||
syncMode: SYNC_MODE_OFF,
|
||||
$not: {excludedResourceGroupId}
|
||||
})
|
||||
return findConfigs({$not: {syncMode: SYNC_MODE_ON, excludedResourceGroupId}})
|
||||
} else {
|
||||
return findConfigs({syncMode: SYNC_MODE_OFF})
|
||||
return findConfigs({$not: {syncMode: SYNC_MODE_ON}})
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +158,7 @@ export async function insertConfig (config) {
|
||||
function _initConfig (data) {
|
||||
return Object.assign({
|
||||
_id: util.generateId('scf'),
|
||||
syncMode: SYNC_MODE_ON,
|
||||
syncMode: SYNC_MODE_UNSET,
|
||||
resourceGroupId: null
|
||||
}, data);
|
||||
}
|
||||
|
@ -1,15 +1,27 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Cookie} from 'tough-cookie';
|
||||
|
||||
|
||||
@autobind
|
||||
class CookieInput extends PureComponent {
|
||||
state = {isValid: true};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_handleChange () {
|
||||
this.state = {
|
||||
isValid: true,
|
||||
};
|
||||
}
|
||||
|
||||
_setInputRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
_handleChange (e) {
|
||||
const isValid = this._isValid();
|
||||
|
||||
if (isValid) {
|
||||
this.props.onChange(this._input.value);
|
||||
const value = e.target.value;
|
||||
this.props.onChange(value);
|
||||
}
|
||||
|
||||
this.setState({isValid})
|
||||
@ -31,10 +43,10 @@ class CookieInput extends PureComponent {
|
||||
return (
|
||||
<input
|
||||
className={isValid ? '' : 'input--error'}
|
||||
ref={n => this._input = n}
|
||||
ref={this._setInputRef}
|
||||
type="text"
|
||||
defaultValue={defaultValue}
|
||||
onChange={e => this._handleChange(e.target.value)}
|
||||
onChange={this._handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import * as querystring from '../../common/querystring';
|
||||
import * as util from '../../common/misc';
|
||||
|
||||
@autobind
|
||||
class RenderedQueryString extends PureComponent {
|
||||
state = {string: ''};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
string: ''
|
||||
};
|
||||
}
|
||||
|
||||
_update (props, delay = false) {
|
||||
clearTimeout(this._triggerTimeout);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import {parse as urlParse} from 'url';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
import Lazy from './base/Lazy';
|
||||
import KeyValueEditor from './keyvalueeditor/Editor';
|
||||
@ -14,29 +14,43 @@ import {debounce} from '../../common/misc';
|
||||
import {trackEvent} from '../../analytics/index';
|
||||
import * as querystring from '../../common/querystring';
|
||||
|
||||
@autobind
|
||||
class RequestPane extends PureComponent {
|
||||
_handleHidePasswords = () => this.props.updateSettingsShowPasswords(false);
|
||||
_handleShowPasswords = () => this.props.updateSettingsShowPasswords(true);
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_handleUpdateSettingsUseBulkHeaderEditor = () => {
|
||||
this._handleUpdateRequestUrl = debounce(this._handleUpdateRequestUrl);
|
||||
}
|
||||
|
||||
_handleHidePasswords () {
|
||||
this.props.updateSettingsShowPasswords(false);
|
||||
}
|
||||
|
||||
_handleShowPasswords () {
|
||||
this.props.updateSettingsShowPasswords(true);
|
||||
}
|
||||
|
||||
_handleUpdateSettingsUseBulkHeaderEditor () {
|
||||
const {useBulkHeaderEditor, updateSettingsUseBulkHeaderEditor} = this.props;
|
||||
updateSettingsUseBulkHeaderEditor(!useBulkHeaderEditor);
|
||||
trackEvent('Headers', 'Toggle Bulk', !useBulkHeaderEditor ? 'On' : 'Off');
|
||||
};
|
||||
}
|
||||
|
||||
_handleImportFile = () => {
|
||||
_handleImportFile () {
|
||||
this.props.handleImportFile();
|
||||
trackEvent('Request Pane', 'CTA', 'Import');
|
||||
};
|
||||
}
|
||||
|
||||
_handleCreateRequest = () => {
|
||||
_handleCreateRequest () {
|
||||
this.props.handleCreateRequest(this.props.request);
|
||||
trackEvent('Request Pane', 'CTA', 'New Request');
|
||||
}
|
||||
|
||||
_handleUpdateRequestUrl (url) {
|
||||
this.props.updateRequestUrl(url)
|
||||
};
|
||||
|
||||
_handleUpdateRequestUrl = debounce(url => this.props.updateRequestUrl(url));
|
||||
|
||||
_handleImportQueryFromUrl = () => {
|
||||
_handleImportQueryFromUrl () {
|
||||
const {request} = this.props;
|
||||
|
||||
let query;
|
||||
@ -58,20 +72,39 @@ class RequestPane extends PureComponent {
|
||||
if (url !== request.url) {
|
||||
this.props.forceUpdateRequest({url, parameters});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_trackQueryToggle = pair => trackEvent('Query', 'Toggle', pair.disabled ? 'Disable' : 'Enable');
|
||||
_trackQueryCreate = () => trackEvent('Query', 'Create');
|
||||
_trackQueryDelete = () => trackEvent('Query', 'Delete');
|
||||
_trackTabBody = () => trackEvent('Request Pane', 'View', 'Body');
|
||||
_trackTabHeaders = () => trackEvent('Request Pane', 'View', 'Headers');
|
||||
_trackTabAuthentication = () => trackEvent('Request Pane', 'View', 'Authentication');
|
||||
_trackTabQuery = () => trackEvent('Request Pane', 'View', 'Query');
|
||||
_trackQueryToggle (pair) {
|
||||
trackEvent('Query', 'Toggle', pair.disabled ? 'Disable' : 'Enable');
|
||||
}
|
||||
|
||||
_trackQueryCreate () {
|
||||
trackEvent('Query', 'Create');
|
||||
}
|
||||
|
||||
_trackQueryDelete () {
|
||||
trackEvent('Query', 'Delete');
|
||||
}
|
||||
|
||||
_trackTabBody () {
|
||||
trackEvent('Request Pane', 'View', 'Body');
|
||||
}
|
||||
|
||||
_trackTabHeaders () {
|
||||
trackEvent('Request Pane', 'View', 'Headers');
|
||||
}
|
||||
|
||||
_trackTabAuthentication () {
|
||||
trackEvent('Request Pane', 'View', 'Authentication');
|
||||
}
|
||||
|
||||
_trackTabQuery () {
|
||||
trackEvent('Request Pane', 'View', 'Query');
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
request,
|
||||
environmentId,
|
||||
showPasswords,
|
||||
editorFontSize,
|
||||
editorKeyMap,
|
||||
@ -317,7 +350,6 @@ RequestPane.propTypes = {
|
||||
editorKeyMap: PropTypes.string.isRequired,
|
||||
editorLineWrapping: PropTypes.bool.isRequired,
|
||||
workspace: PropTypes.object.isRequired,
|
||||
environmentId: PropTypes.string.isRequired,
|
||||
forceRefreshCounter: PropTypes.number.isRequired,
|
||||
|
||||
// Optional
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {remote} from 'electron';
|
||||
import {DEBOUNCE_MILLIS, isMac} from '../../common/constants';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider, DropdownHint} from './base/dropdown';
|
||||
@ -9,39 +10,49 @@ import PromptModal from './modals/PromptModal';
|
||||
import PromptButton from './base/PromptButton';
|
||||
import OneLineEditor from './codemirror/OneLineEditor';
|
||||
|
||||
@autobind
|
||||
class RequestUrlBar extends PureComponent {
|
||||
state = {
|
||||
currentInterval: null,
|
||||
currentTimeout: null,
|
||||
downloadPath: null
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentInterval: null,
|
||||
currentTimeout: null,
|
||||
downloadPath: null
|
||||
};
|
||||
|
||||
_urlChangeDebounceTimeout = null;
|
||||
_lastPastedText = null;
|
||||
this._urlChangeDebounceTimeout = null;
|
||||
this._lastPastedText = null;
|
||||
}
|
||||
|
||||
_setDropdownRef = n => this._dropdown = n;
|
||||
_setInputRef = n => this._input = n;
|
||||
_setDropdownRef (n) {
|
||||
this._dropdown = n;
|
||||
}
|
||||
|
||||
_handleMetaClickSend = e => {
|
||||
_setInputRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
_handleMetaClickSend (e) {
|
||||
e.preventDefault();
|
||||
this._dropdown.show();
|
||||
};
|
||||
}
|
||||
|
||||
_handleFormSubmit = e => {
|
||||
_handleFormSubmit (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this._handleSend();
|
||||
};
|
||||
}
|
||||
|
||||
_handleMethodChange = method => {
|
||||
_handleMethodChange (method) {
|
||||
this.props.onMethodChange(method);
|
||||
trackEvent('Request', 'Method Change', method);
|
||||
};
|
||||
}
|
||||
|
||||
_handleUrlChange = url => {
|
||||
_handleUrlChange (url) {
|
||||
clearTimeout(this._urlChangeDebounceTimeout);
|
||||
this._urlChangeDebounceTimeout = setTimeout(async () => {
|
||||
const pastedText = this._lastPastedText;
|
||||
|
||||
// If no pasted text in the queue, just fire the regular change handler
|
||||
if (!pastedText) {
|
||||
@ -49,7 +60,6 @@ class RequestUrlBar extends PureComponent {
|
||||
}
|
||||
|
||||
// Reset pasted text cache
|
||||
const pastedText = this._lastPastedText;
|
||||
this._lastPastedText = null;
|
||||
|
||||
// Attempt to import the pasted text
|
||||
@ -63,19 +73,19 @@ class RequestUrlBar extends PureComponent {
|
||||
}
|
||||
|
||||
}, DEBOUNCE_MILLIS);
|
||||
};
|
||||
}
|
||||
|
||||
_handleUrlPaste = e => {
|
||||
_handleUrlPaste (e) {
|
||||
// NOTE: We're not actually doing the import here to avoid races with onChange
|
||||
this._lastPastedText = e.clipboardData.getData('text/plain');
|
||||
};
|
||||
}
|
||||
|
||||
_handleGenerateCode = () => {
|
||||
_handleGenerateCode () {
|
||||
this.props.handleGenerateCode();
|
||||
trackEvent('Request', 'Generate Code', 'Send Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetDownloadLocation = () => {
|
||||
_handleSetDownloadLocation () {
|
||||
const options = {
|
||||
title: 'Select Download Location',
|
||||
buttonLabel: 'Select',
|
||||
@ -90,13 +100,13 @@ class RequestUrlBar extends PureComponent {
|
||||
|
||||
this.setState({downloadPath: paths[0]});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
_handleClearDownloadLocation = () => {
|
||||
_handleClearDownloadLocation () {
|
||||
this.setState({downloadPath: null});
|
||||
};
|
||||
}
|
||||
|
||||
_handleKeyDown = e => {
|
||||
_handleKeyDown (e) {
|
||||
if (!this._input) {
|
||||
return;
|
||||
}
|
||||
@ -108,9 +118,9 @@ class RequestUrlBar extends PureComponent {
|
||||
this._input.focus();
|
||||
this._input.select();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleSend = () => {
|
||||
_handleSend () {
|
||||
// Don't stop interval because duh, it needs to keep going!
|
||||
// XXX this._handleStopInterval(); XXX
|
||||
|
||||
@ -122,9 +132,9 @@ class RequestUrlBar extends PureComponent {
|
||||
} else {
|
||||
this.props.handleSend();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleSendAfterDelay = async () => {
|
||||
async _handleSendAfterDelay () {
|
||||
const seconds = await showModal(PromptModal, {
|
||||
inputType: 'decimal',
|
||||
headerName: 'Send After Delay',
|
||||
@ -140,7 +150,7 @@ class RequestUrlBar extends PureComponent {
|
||||
trackEvent('Request', 'Send on Delay', 'Send Action', seconds);
|
||||
};
|
||||
|
||||
_handleSendOnInterval = async () => {
|
||||
async _handleSendOnInterval () {
|
||||
const seconds = await showModal(PromptModal, {
|
||||
inputType: 'decimal',
|
||||
headerName: 'Send on Interval',
|
||||
@ -154,17 +164,17 @@ class RequestUrlBar extends PureComponent {
|
||||
this.setState({currentInterval: seconds});
|
||||
|
||||
trackEvent('Request', 'Send on Interval', 'Send Action', seconds);
|
||||
};
|
||||
}
|
||||
|
||||
_handleStopInterval = () => {
|
||||
_handleStopInterval () {
|
||||
clearTimeout(this._sendInterval);
|
||||
if (this.state.currentInterval) {
|
||||
this.setState({currentInterval: null});
|
||||
trackEvent('Request', 'Stop Send Interval');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleStopTimeout = () => {
|
||||
_handleStopTimeout () {
|
||||
clearTimeout(this._sendTimeout);
|
||||
if (this.state.currentTimeout) {
|
||||
this.setState({currentTimeout: null});
|
||||
@ -172,7 +182,7 @@ class RequestUrlBar extends PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
_handleClickSend = e => {
|
||||
_handleClickSend (e) {
|
||||
const metaPressed = isMac() ? e.metaKey : e.ctrlKey;
|
||||
|
||||
// If we're pressing a meta key, let the dropdown open
|
||||
@ -184,7 +194,7 @@ class RequestUrlBar extends PureComponent {
|
||||
// If we're not pressing a meta key, cancel dropdown and send the request
|
||||
e.stopPropagation(); // Don't trigger the dropdown
|
||||
this._handleFormSubmit(e);
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
document.body.addEventListener('keydown', this._handleKeyDown);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import fs from 'fs';
|
||||
import mime from 'mime-types';
|
||||
import {remote} from 'electron';
|
||||
@ -19,10 +20,18 @@ import {getSetCookieHeaders, nullFn} from '../../common/misc';
|
||||
import {cancelCurrentRequest} from '../../common/network';
|
||||
import {trackEvent} from '../../analytics';
|
||||
|
||||
@autobind
|
||||
class ResponsePane extends PureComponent {
|
||||
state = {response: null};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
response: null
|
||||
};
|
||||
}
|
||||
|
||||
_trackTab = name => trackEvent('Response Pane', 'View', name);
|
||||
_trackTab (name) {
|
||||
trackEvent('Response Pane', 'View', name);
|
||||
}
|
||||
|
||||
async _getResponse (requestId, responseId) {
|
||||
let response = await models.response.getById(responseId);
|
||||
@ -34,7 +43,7 @@ class ResponsePane extends PureComponent {
|
||||
this.setState({response});
|
||||
}
|
||||
|
||||
_handleDownloadResponseBody = async () => {
|
||||
async _handleDownloadResponseBody () {
|
||||
if (!this.state.response) {
|
||||
// Should never happen
|
||||
console.warn('No response to download');
|
||||
@ -69,7 +78,7 @@ class ResponsePane extends PureComponent {
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const activeRequestId = nextProps.request ? nextProps.request._id : null;
|
||||
@ -167,27 +176,27 @@ class ResponsePane extends PureComponent {
|
||||
loadStartTime={loadStartTime}
|
||||
/>
|
||||
{!response ? null : (
|
||||
<header className="pane__header row-spaced">
|
||||
<div className="no-wrap scrollable scrollable--no-bars pad-left">
|
||||
<StatusTag
|
||||
statusCode={response.statusCode}
|
||||
statusMessage={response.statusMessage || null}
|
||||
<header className="pane__header row-spaced">
|
||||
<div className="no-wrap scrollable scrollable--no-bars pad-left">
|
||||
<StatusTag
|
||||
statusCode={response.statusCode}
|
||||
statusMessage={response.statusMessage || null}
|
||||
/>
|
||||
<TimeTag milliseconds={response.elapsedTime}/>
|
||||
<SizeTag bytes={response.bytesRead}/>
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
requestId={request._id}
|
||||
isLatestResponseActive={!activeResponseId}
|
||||
activeResponseId={response._id}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
handleDeleteResponses={handleDeleteResponses}
|
||||
onChange={nullFn}
|
||||
className="tall pane__header__right"
|
||||
right
|
||||
/>
|
||||
<TimeTag milliseconds={response.elapsedTime}/>
|
||||
<SizeTag bytes={response.bytesRead}/>
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
requestId={request._id}
|
||||
isLatestResponseActive={!activeResponseId}
|
||||
activeResponseId={response._id}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
handleDeleteResponses={handleDeleteResponses}
|
||||
onChange={nullFn}
|
||||
className="tall pane__header__right"
|
||||
right
|
||||
/>
|
||||
</header>
|
||||
)}
|
||||
</header>
|
||||
)}
|
||||
<Tabs className="pane__body" forceRenderTabPanel>
|
||||
<TabList>
|
||||
<Tab>
|
||||
@ -203,19 +212,19 @@ class ResponsePane extends PureComponent {
|
||||
<Tab>
|
||||
<Button onClick={this._trackTab} value="Cookies">
|
||||
Cookies {cookieHeaders.length ? (
|
||||
<span className="txt-sm">
|
||||
<span className="txt-sm">
|
||||
({cookieHeaders.length})
|
||||
</span>
|
||||
) : null}
|
||||
) : null}
|
||||
</Button>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<Button onClick={this._trackTab} value="Headers">
|
||||
Headers {response.headers.length ? (
|
||||
<span className="txt-sm">
|
||||
<span className="txt-sm">
|
||||
({response.headers.length})
|
||||
</span>
|
||||
) : null}
|
||||
) : null}
|
||||
</Button>
|
||||
</Tab>
|
||||
</TabList>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import Link from './base/Link';
|
||||
import * as fetch from '../../common/fetch';
|
||||
@ -9,20 +10,24 @@ import * as db from '../../common/database';
|
||||
|
||||
const LOCALSTORAGE_KEY = 'insomnia::notifications::seen';
|
||||
|
||||
@autobind
|
||||
class Toast extends PureComponent {
|
||||
state = {notification: null, visible: false};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {notification: null, visible: false};
|
||||
}
|
||||
|
||||
_handlePostCTACleanup = () => {
|
||||
_handlePostCTACleanup () {
|
||||
trackEvent('Notification', 'Click', this.state.notification.key);
|
||||
this._dismissNotification();
|
||||
};
|
||||
}
|
||||
|
||||
_handleCancelClick = () => {
|
||||
_handleCancelClick () {
|
||||
trackEvent('Notification', 'Dismiss', this.state.notification.key);
|
||||
this._dismissNotification();
|
||||
};
|
||||
}
|
||||
|
||||
_handleCheckNotifications = async () => {
|
||||
async _handleCheckNotifications () {
|
||||
// If there is a notification open, skip check
|
||||
if (this.state.notification) {
|
||||
return;
|
||||
@ -69,7 +74,7 @@ class Toast extends PureComponent {
|
||||
|
||||
// Fade the notification in
|
||||
setTimeout(() => this.setState({visible: true}), 1000);
|
||||
};
|
||||
}
|
||||
|
||||
_loadSeen () {
|
||||
try {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import {showModal, registerModal} from './modals/index';
|
||||
import AlertModal from '../components/modals/AlertModal';
|
||||
@ -12,10 +13,10 @@ import PromptModal from '../components/modals/PromptModal';
|
||||
import RequestCreateModal from '../components/modals/RequestCreateModal';
|
||||
import RequestPane from './RequestPane';
|
||||
import RequestSwitcherModal from '../components/modals/RequestSwitcherModal';
|
||||
import ResponsePane from './ResponsePane';
|
||||
import SetupSyncModal from '../components/modals/SetupSyncModal';
|
||||
import SettingsModal from '../components/modals/SettingsModal';
|
||||
import ResponsePane from './ResponsePane';
|
||||
import Sidebar from './sidebar/Sidebar';
|
||||
import SyncLogsModal from '../components/modals/SyncLogsModal';
|
||||
import WorkspaceEnvironmentsEditModal from '../components/modals/WorkspaceEnvironmentsEditModal';
|
||||
import WorkspaceSettingsModal from '../components/modals/WorkspaceSettingsModal';
|
||||
import WorkspaceShareSettingsModal from '../components/modals/WorkspaceShareSettingsModal';
|
||||
@ -27,11 +28,17 @@ import * as importers from 'insomnia-importers';
|
||||
const rUpdate = models.request.update;
|
||||
const sUpdate = models.settings.update;
|
||||
|
||||
@autobind
|
||||
class Wrapper extends PureComponent {
|
||||
state = {forceRefreshRequestPaneCounter: Date.now()};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
forceRefreshRequestPaneCounter: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
// Request updaters
|
||||
_handleForceUpdateRequest = async patch => {
|
||||
async _handleForceUpdateRequest (patch) {
|
||||
const newRequest = await rUpdate(this.props.activeRequest, patch);
|
||||
|
||||
// Give it a second for the app to render first. If we don't wait, it will refresh
|
||||
@ -39,18 +46,38 @@ class Wrapper extends PureComponent {
|
||||
window.setTimeout(this._forceRequestPaneRefresh, 100);
|
||||
|
||||
return newRequest;
|
||||
};
|
||||
}
|
||||
|
||||
_handleUpdateRequestBody = body => rUpdate(this.props.activeRequest, {body});
|
||||
_handleUpdateRequestMethod = method => rUpdate(this.props.activeRequest, {method});
|
||||
_handleUpdateRequestParameters = parameters => rUpdate(this.props.activeRequest, {parameters});
|
||||
_handleUpdateRequestAuthentication = authentication => rUpdate(this.props.activeRequest, {authentication});
|
||||
_handleUpdateRequestHeaders = headers => rUpdate(this.props.activeRequest, {headers});
|
||||
_handleUpdateRequestUrl = url => rUpdate(this.props.activeRequest, {url});
|
||||
_handleUpdateRequestBody (body) {
|
||||
rUpdate(this.props.activeRequest, {body});
|
||||
}
|
||||
|
||||
_handleUpdateRequestMethod (method) {
|
||||
rUpdate(this.props.activeRequest, {method});
|
||||
}
|
||||
|
||||
_handleUpdateRequestParameters (parameters) {
|
||||
rUpdate(this.props.activeRequest, {parameters});
|
||||
}
|
||||
|
||||
_handleUpdateRequestAuthentication (authentication) {
|
||||
rUpdate(this.props.activeRequest, {authentication});
|
||||
}
|
||||
|
||||
_handleUpdateRequestHeaders (headers) {
|
||||
rUpdate(this.props.activeRequest, {headers});
|
||||
}
|
||||
|
||||
_handleUpdateRequestUrl (url) {
|
||||
rUpdate(this.props.activeRequest, {url});
|
||||
}
|
||||
|
||||
// Special request updaters
|
||||
_handleUpdateRequestMimeType = mimeType => updateMimeType(this.props.activeRequest, mimeType);
|
||||
_handleImport = async text => {
|
||||
_handleUpdateRequestMimeType (mimeType) {
|
||||
updateMimeType(this.props.activeRequest, mimeType);
|
||||
}
|
||||
|
||||
async _handleImport (text) {
|
||||
// Allow user to paste any import file into the url. If it results in
|
||||
// only one item, it will overwrite the current request.
|
||||
try {
|
||||
@ -76,29 +103,44 @@ class Wrapper extends PureComponent {
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Settings updaters
|
||||
_handleUpdateSettingsShowPasswords = showPasswords => sUpdate(this.props.settings, {showPasswords});
|
||||
_handleUpdateSettingsUseBulkHeaderEditor = useBulkHeaderEditor => sUpdate(this.props.settings, {useBulkHeaderEditor});
|
||||
_handleUpdateSettingsShowPasswords (showPasswords) {
|
||||
sUpdate(this.props.settings, {showPasswords});
|
||||
}
|
||||
|
||||
_handleUpdateSettingsUseBulkHeaderEditor (useBulkHeaderEditor) {
|
||||
sUpdate(this.props.settings, {useBulkHeaderEditor});
|
||||
}
|
||||
|
||||
// Other Helpers
|
||||
_handleImportFile = () => {
|
||||
_handleImportFile () {
|
||||
this.props.handleImportFileToWorkspace(this.props.activeWorkspace._id);
|
||||
};
|
||||
}
|
||||
|
||||
_handleExportWorkspaceToFile = () => this.props.handleExportFile(this.props.activeWorkspace._id);
|
||||
_handleSetActiveResponse = responseId => this.props.handleSetActiveResponse(this.props.activeRequest._id, responseId);
|
||||
_handleShowEnvironmentsModal = () => showModal(WorkspaceEnvironmentsEditModal, this.props.activeWorkspace);
|
||||
_handleShowCookiesModal = () => showModal(CookiesModal, this.props.activeWorkspace);
|
||||
_handleExportWorkspaceToFile () {
|
||||
this.props.handleExportFile(this.props.activeWorkspace._id);
|
||||
}
|
||||
|
||||
_handleDeleteResponses = () => {
|
||||
_handleSetActiveResponse (responseId) {
|
||||
this.props.handleSetActiveResponse(this.props.activeRequest._id, responseId);
|
||||
}
|
||||
|
||||
_handleShowEnvironmentsModal () {
|
||||
showModal(WorkspaceEnvironmentsEditModal, this.props.activeWorkspace);
|
||||
}
|
||||
|
||||
_handleShowCookiesModal () {
|
||||
showModal(CookiesModal, this.props.activeWorkspace);
|
||||
}
|
||||
|
||||
_handleDeleteResponses () {
|
||||
models.response.removeForRequest(this.props.activeRequest._id);
|
||||
this._handleSetActiveResponse(null);
|
||||
};
|
||||
}
|
||||
|
||||
_handleRemoveActiveWorkspace = async () => {
|
||||
async _handleRemoveActiveWorkspace () {
|
||||
const {workspaces, activeWorkspace} = this.props;
|
||||
if (workspaces.length <= 1) {
|
||||
showModal(AlertModal, {
|
||||
@ -113,37 +155,37 @@ class Wrapper extends PureComponent {
|
||||
}
|
||||
|
||||
models.workspace.remove(activeWorkspace);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSendRequestWithActiveEnvironment = () => {
|
||||
_handleSendRequestWithActiveEnvironment () {
|
||||
const {activeRequest, activeEnvironment, handleSendRequestWithEnvironment} = this.props;
|
||||
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
|
||||
const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : 'n/a';
|
||||
handleSendRequestWithEnvironment(activeRequestId, activeEnvironmentId);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSendAndDownloadRequestWithActiveEnvironment = filename => {
|
||||
_handleSendAndDownloadRequestWithActiveEnvironment (filename) {
|
||||
const {activeRequest, activeEnvironment, handleSendAndDownloadRequestWithEnvironment} = this.props;
|
||||
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
|
||||
const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : 'n/a';
|
||||
handleSendAndDownloadRequestWithEnvironment(activeRequestId, activeEnvironmentId, filename);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetPreviewMode = previewMode => {
|
||||
_handleSetPreviewMode (previewMode) {
|
||||
const activeRequest = this.props.activeRequest;
|
||||
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
|
||||
this.props.handleSetResponsePreviewMode(activeRequestId, previewMode);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetResponseFilter = filter => {
|
||||
_handleSetResponseFilter (filter) {
|
||||
const activeRequest = this.props.activeRequest;
|
||||
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
|
||||
this.props.handleSetResponseFilter(activeRequestId, filter);
|
||||
};
|
||||
}
|
||||
|
||||
_forceRequestPaneRefresh = () => {
|
||||
_forceRequestPaneRefresh () {
|
||||
this.setState({forceRefreshRequestPaneCounter: Date.now()});
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
@ -243,7 +285,6 @@ class Wrapper extends PureComponent {
|
||||
editorFontSize={settings.editorFontSize}
|
||||
editorKeyMap={settings.editorKeyMap}
|
||||
editorLineWrapping={settings.editorLineWrapping}
|
||||
environmentId={activeEnvironment ? activeEnvironment._id : 'n/a'}
|
||||
workspace={activeWorkspace}
|
||||
forceUpdateRequest={this._handleForceUpdateRequest}
|
||||
handleCreateRequest={handleCreateRequestForWorkspace}
|
||||
@ -288,7 +329,6 @@ class Wrapper extends PureComponent {
|
||||
<AlertModal ref={registerModal}/>
|
||||
<CookiesModal ref={registerModal}/>
|
||||
<ChangelogModal ref={registerModal}/>
|
||||
<SyncLogsModal ref={registerModal}/>
|
||||
<LoginModal ref={registerModal}/>
|
||||
<PromptModal ref={registerModal}/>
|
||||
<RequestCreateModal ref={registerModal}/>
|
||||
@ -330,6 +370,10 @@ class Wrapper extends PureComponent {
|
||||
onChange={models.requestGroup.update}
|
||||
render={handleRender}
|
||||
/>
|
||||
<SetupSyncModal
|
||||
ref={registerModal}
|
||||
workspace={activeWorkspace}
|
||||
/>
|
||||
<WorkspaceEnvironmentsEditModal
|
||||
ref={registerModal}
|
||||
onChange={models.workspace.update}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {shell} from 'electron';
|
||||
|
||||
@autobind
|
||||
class Button extends PureComponent {
|
||||
_handleClick = e => {
|
||||
_handleClick (e) {
|
||||
const {onClick, onDisabledClick, disabled} = this.props;
|
||||
const fn = disabled ? onDisabledClick : onClick;
|
||||
|
||||
@ -11,7 +13,7 @@ class Button extends PureComponent {
|
||||
} else {
|
||||
fn && fn(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {children, value, ...props} = this.props;
|
||||
|
@ -1,10 +1,17 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
const {clipboard} = require('electron');
|
||||
|
||||
@autobind
|
||||
class CopyButton extends PureComponent {
|
||||
state = {showConfirmation: false};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showConfirmation: false,
|
||||
};
|
||||
}
|
||||
|
||||
_handleClick = e => {
|
||||
_handleClick (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {debounce} from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class DebouncedInput extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
@ -12,8 +14,13 @@ class DebouncedInput extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_handleChange = e => this._handleValueChange(e.target.value);
|
||||
_setRef = n => this._input = n;
|
||||
_handleChange (e) {
|
||||
this._handleValueChange(e.target.value);
|
||||
}
|
||||
|
||||
_setRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
getSelectionStart () {
|
||||
if (this._input) {
|
||||
|
@ -1,17 +1,26 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
|
||||
@autobind
|
||||
class Editable extends PureComponent {
|
||||
state = {editing: false};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editing: false
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetInputRef = n => this._input = n;
|
||||
_handleSetInputRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
_handleSingleClickEditStart = () => {
|
||||
_handleSingleClickEditStart () {
|
||||
if (this.props.singleClick) {
|
||||
this._handleEditStart();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditStart = () => {
|
||||
_handleEditStart () {
|
||||
this.setState({editing: true});
|
||||
|
||||
setTimeout(() => {
|
||||
@ -22,9 +31,9 @@ class Editable extends PureComponent {
|
||||
if (this.props.onEditStart) {
|
||||
this.props.onEditStart();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditEnd = () => {
|
||||
_handleEditEnd () {
|
||||
const value = this._input.value.trim();
|
||||
|
||||
if (!value) {
|
||||
@ -37,9 +46,9 @@ class Editable extends PureComponent {
|
||||
// This timeout prevents the UI from showing the old value after submit.
|
||||
// It should give the UI enough time to redraw the new value.
|
||||
setTimeout(async () => this.setState({editing: false}), 100);
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditKeyDown = e => {
|
||||
_handleEditKeyDown (e) {
|
||||
if (e.keyCode === 13) {
|
||||
// Pressed Enter
|
||||
this._handleEditEnd();
|
||||
@ -49,7 +58,7 @@ class Editable extends PureComponent {
|
||||
// TODO: Make escape blur without saving
|
||||
this._input && this._input.blur();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {value, singleClick, onEditStart, className, ...extra} = this.props;
|
||||
|
@ -1,15 +1,23 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {basename as pathBasename} from 'path';
|
||||
import {remote} from 'electron';
|
||||
|
||||
@autobind
|
||||
class FileInputButton extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
focus () {
|
||||
this._button.focus();
|
||||
}
|
||||
|
||||
_setRef = n => this._button = n;
|
||||
_setRef (n) {
|
||||
this._button = n;
|
||||
}
|
||||
|
||||
_handleChooseFile = () => {
|
||||
_handleChooseFile () {
|
||||
const options = {
|
||||
title: 'Import File',
|
||||
buttonLabel: 'Import',
|
||||
@ -25,7 +33,7 @@ class FileInputButton extends PureComponent {
|
||||
const path = paths[0];
|
||||
this.props.onChange(path);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {showFileName, path, name, ...extraProps} = this.props;
|
||||
|
@ -1,12 +1,18 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {shell} from 'electron';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
import * as querystring from '../../../common/querystring';
|
||||
import {getAppVersion} from '../../../common/constants';
|
||||
import {isDevelopment} from '../../../common/constants';
|
||||
|
||||
@autobind
|
||||
class Link extends PureComponent {
|
||||
_handleClick = e => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleClick (e) {
|
||||
e && e.preventDefault();
|
||||
const {href, onClick} = this.props;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import {isMac} from '../../../common/constants';
|
||||
|
||||
@ -6,16 +7,32 @@ import {isMac} from '../../../common/constants';
|
||||
// appear over top of an existing one.
|
||||
let globalZIndex = 1000;
|
||||
|
||||
@autobind
|
||||
class Modal extends PureComponent {
|
||||
state = {
|
||||
open: false,
|
||||
forceRefreshCounter: 0,
|
||||
zIndex: globalZIndex
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_handleSetNodeRef = n => this._node = n;
|
||||
this.state = {
|
||||
open: false,
|
||||
forceRefreshCounter: 0,
|
||||
zIndex: globalZIndex
|
||||
};
|
||||
}
|
||||
|
||||
_handleKeyDown = e => {
|
||||
_setModalRef (n) {
|
||||
this._node = n;
|
||||
this._addListener();
|
||||
}
|
||||
|
||||
_addListener () {
|
||||
this._node.addEventListener('keydown', this._handleKeyDown);
|
||||
}
|
||||
|
||||
_removeListener () {
|
||||
this._node.removeEventListener('keydown', this._handleKeyDown);
|
||||
}
|
||||
|
||||
_handleKeyDown (e) {
|
||||
if (!this.state.open) {
|
||||
return;
|
||||
}
|
||||
@ -27,6 +44,11 @@ class Modal extends PureComponent {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
// Don't check for close keys if we don't want them
|
||||
if (this.props.noEscape) {
|
||||
return;
|
||||
}
|
||||
|
||||
const closeOnKeyCodes = this.props.closeOnKeyCodes || [];
|
||||
const pressedEscape = e.keyCode === 27;
|
||||
const pressedElse = closeOnKeyCodes.find(c => c === e.keyCode);
|
||||
@ -36,9 +58,14 @@ class Modal extends PureComponent {
|
||||
// Pressed escape
|
||||
this.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleClick (e) {
|
||||
// Don't check for close keys if we don't want them
|
||||
if (this.props.noEscape) {
|
||||
return;
|
||||
}
|
||||
|
||||
_handleClick = e => {
|
||||
// Did we click a close button. Let's check a few parent nodes up as well
|
||||
// because some buttons might have nested elements. Maybe there is a better
|
||||
// way to check this?
|
||||
@ -57,7 +84,7 @@ class Modal extends PureComponent {
|
||||
if (shouldHide) {
|
||||
this.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
show () {
|
||||
const {freshState} = this.props;
|
||||
@ -88,16 +115,12 @@ class Modal extends PureComponent {
|
||||
this.setState({open: false});
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this._node.addEventListener('keydown', this._handleKeyDown);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this._node.removeEventListener('keydown', this._handleKeyDown);
|
||||
this._removeListener();
|
||||
}
|
||||
|
||||
render () {
|
||||
const {tall, top, wide, className} = this.props;
|
||||
const {tall, top, wide, noEscape, className} = this.props;
|
||||
const {open, zIndex, forceRefreshCounter} = this.state;
|
||||
|
||||
const classes = classnames(
|
||||
@ -106,17 +129,18 @@ class Modal extends PureComponent {
|
||||
{'modal--open': open},
|
||||
{'modal--fixed-height': tall},
|
||||
{'modal--fixed-top': top},
|
||||
{'modal--noescape': noEscape},
|
||||
{'modal--wide': wide},
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={this._handleSetNodeRef}
|
||||
<div ref={this._setModalRef}
|
||||
tabIndex="-1"
|
||||
className={classes}
|
||||
style={{zIndex: zIndex}}
|
||||
onClick={this._handleClick}>
|
||||
<div className="modal__content" key={forceRefreshCounter}>
|
||||
<div className="modal__backdrop overlay" onClick={() => this.hide()}></div>
|
||||
<div className="modal__backdrop overlay" data-close-modal></div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
@ -128,6 +152,7 @@ Modal.propTypes = {
|
||||
tall: PropTypes.bool,
|
||||
top: PropTypes.bool,
|
||||
wide: PropTypes.bool,
|
||||
noEscape: PropTypes.bool,
|
||||
dontFocus: PropTypes.bool,
|
||||
closeOnKeyCodes: PropTypes.array,
|
||||
freshState: PropTypes.bool,
|
||||
|
@ -9,7 +9,7 @@ class ModalHeader extends PureComponent {
|
||||
if (!hideCloseButton) {
|
||||
closeButton = (
|
||||
<button type="button" className="btn btn--compact modal__close-btn" data-close-modal="true">
|
||||
<i className="fa fa-times"></i>
|
||||
<i className="fa fa-times"/>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Button from '../base/Button';
|
||||
|
||||
const STATE_DEFAULT = 'default';
|
||||
const STATE_ASK = 'ask';
|
||||
const STATE_DONE = 'done';
|
||||
|
||||
@autobind
|
||||
class PromptButton extends PureComponent {
|
||||
state = {state: STATE_DEFAULT};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
state: STATE_DEFAULT
|
||||
};
|
||||
}
|
||||
|
||||
_confirm (...args) {
|
||||
// Clear existing timeouts
|
||||
@ -42,7 +50,7 @@ class PromptButton extends PureComponent {
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
_handleClick = (...args) => {
|
||||
_handleClick (...args) {
|
||||
const {state} = this.state;
|
||||
if (state === STATE_ASK) {
|
||||
this._confirm(...args)
|
||||
@ -51,7 +59,7 @@ class PromptButton extends PureComponent {
|
||||
} else {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
clearTimeout(this._triggerTimeout);
|
||||
|
@ -1,18 +1,28 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import DropdownButton from './DropdownButton';
|
||||
import DropdownItem from './DropdownItem';
|
||||
import DropdownDivider from './DropdownDivider';
|
||||
|
||||
@autobind
|
||||
class Dropdown extends PureComponent {
|
||||
state = {
|
||||
open: false,
|
||||
dropUp: false,
|
||||
focused: false,
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
dropUp: false,
|
||||
focused: false,
|
||||
};
|
||||
}
|
||||
|
||||
_setRef (n) {
|
||||
this._node = n;
|
||||
};
|
||||
|
||||
_handleKeyDown = e => {
|
||||
_handleKeyDown (e) {
|
||||
// Catch all key presses if we're open
|
||||
if (this.state.open) {
|
||||
e.stopPropagation();
|
||||
@ -23,30 +33,51 @@ class Dropdown extends PureComponent {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_checkSize = () => {
|
||||
_checkSize () {
|
||||
if (!this.state.open) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the dropdown scroll if it drops off screen.
|
||||
const rect = this._dropdownList.getBoundingClientRect();
|
||||
const rect = ReactDOM.findDOMNode(this._dropdownList).getBoundingClientRect();
|
||||
const maxHeight = document.body.clientHeight - rect.top - 10;
|
||||
this._dropdownList.style.maxHeight = `${maxHeight}px`;
|
||||
};
|
||||
}
|
||||
|
||||
_handleClick = () => {
|
||||
_handleClick () {
|
||||
this.toggle();
|
||||
};
|
||||
}
|
||||
|
||||
_handleMouseDown = e => {
|
||||
_handleMouseDown (e) {
|
||||
// Intercept mouse down so that clicks don't trigger things like
|
||||
// drag and drop.
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
_addDropdownListRef = n => this._dropdownList = n;
|
||||
_addDropdownListRef (n) {
|
||||
this._dropdownList = n;
|
||||
};
|
||||
|
||||
_getFlattenedChildren (children) {
|
||||
let newChildren = [];
|
||||
|
||||
for (const child of children) {
|
||||
if (!child) {
|
||||
// Ignore null components
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(child)) {
|
||||
newChildren = [...newChildren, ...this._getFlattenedChildren(child)];
|
||||
} else {
|
||||
newChildren.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return newChildren
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._checkSize();
|
||||
@ -69,7 +100,7 @@ class Dropdown extends PureComponent {
|
||||
|
||||
show () {
|
||||
const bodyHeight = document.body.getBoundingClientRect().height;
|
||||
const dropdownTop = ReactDOM.findDOMNode(this).getBoundingClientRect().top;
|
||||
const dropdownTop = this._node.getBoundingClientRect().top;
|
||||
const dropUp = dropdownTop > bodyHeight - 200;
|
||||
|
||||
this.setState({open: true, dropUp});
|
||||
@ -84,25 +115,6 @@ class Dropdown extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_getFlattenedChildren (children) {
|
||||
let newChildren = [];
|
||||
|
||||
for (const child of children) {
|
||||
if (!child) {
|
||||
// Ignore null components
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(child)) {
|
||||
newChildren = [...newChildren, ...this._getFlattenedChildren(child)];
|
||||
} else {
|
||||
newChildren.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return newChildren
|
||||
}
|
||||
|
||||
render () {
|
||||
const {right, outline, wide, className, style, children} = this.props;
|
||||
const {dropUp, open} = this.state;
|
||||
@ -120,20 +132,24 @@ class Dropdown extends PureComponent {
|
||||
const dropdownButtons = [];
|
||||
const dropdownItems = [];
|
||||
|
||||
const allChildren = this._getFlattenedChildren(Array.isArray(children) ? children : [children]);
|
||||
const listedChildren = Array.isArray(children) ? children : [children];
|
||||
const allChildren = this._getFlattenedChildren(listedChildren);
|
||||
for (const child of allChildren) {
|
||||
if (child.type === DropdownButton) {
|
||||
if (child.type.name === DropdownButton.name) {
|
||||
dropdownButtons.push(child);
|
||||
} else if (child.type === DropdownItem) {
|
||||
} else if (child.type.name === DropdownItem.name) {
|
||||
dropdownItems.push(child);
|
||||
} else if (child.type === DropdownDivider) {
|
||||
} else if (child.type.name === DropdownDivider.name) {
|
||||
dropdownItems.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
let finalChildren = [];
|
||||
if (dropdownButtons.length !== 1) {
|
||||
console.error(`Dropdown needs exactly one DropdownButton! Got ${dropdownButtons.length}`, this.props);
|
||||
console.error(
|
||||
`Dropdown needs exactly one DropdownButton! Got ${dropdownButtons.length}`,
|
||||
{allChildren}
|
||||
);
|
||||
} else {
|
||||
finalChildren = [
|
||||
dropdownButtons[0],
|
||||
@ -146,6 +162,7 @@ class Dropdown extends PureComponent {
|
||||
return (
|
||||
<div style={style}
|
||||
className={classes}
|
||||
ref={this._setRef}
|
||||
onClick={this._handleClick}
|
||||
onMouseDown={this._handleMouseDown}>
|
||||
{finalChildren}
|
||||
|
@ -1,10 +1,15 @@
|
||||
import React from 'react';
|
||||
import React, {PureComponent} from 'react';
|
||||
|
||||
const DropdownButton = ({children, ...props}) => (
|
||||
<button type="button" {...props}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
class DropdownButton extends PureComponent {
|
||||
render () {
|
||||
const {children, ...props} = this.props;
|
||||
return (
|
||||
<button type="button" {...props}>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DropdownButton.propTypes = {};
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
|
||||
@autobind
|
||||
class DropdownItem extends PureComponent {
|
||||
_handleClick = e => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleClick (e) {
|
||||
const {stayOpenAfterClick, onClick, disabled} = this.props;
|
||||
|
||||
if (stayOpenAfterClick) {
|
||||
@ -18,7 +24,7 @@ class DropdownItem extends PureComponent {
|
||||
} else {
|
||||
onClick(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -2,12 +2,10 @@ import _Dropdown from './Dropdown';
|
||||
import _DropdownButton from './DropdownButton';
|
||||
import _DropdownDivider from './DropdownDivider';
|
||||
import _DropdownHint from './DropdownHint';
|
||||
import _DropdownRight from './DropdownRight';
|
||||
import _DropdownItem from './DropdownItem';
|
||||
|
||||
export const Dropdown = _Dropdown;
|
||||
export const DropdownButton = _DropdownButton;
|
||||
export const DropdownDivider = _DropdownDivider;
|
||||
export const DropdownHint = _DropdownHint;
|
||||
export const DropdownRight = _DropdownRight;
|
||||
export const DropdownItem = _DropdownItem;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {getDOMNode} from 'react-dom';
|
||||
import CodeMirror from 'codemirror';
|
||||
import classnames from 'classnames';
|
||||
@ -90,12 +91,15 @@ const BASE_CODEMIRROR_OPTIONS = {
|
||||
}
|
||||
};
|
||||
|
||||
@autobind
|
||||
class Editor extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
filter: props.filter || ''
|
||||
};
|
||||
|
||||
this._originalCode = '';
|
||||
}
|
||||
|
||||
@ -187,7 +191,7 @@ class Editor extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_handleInitTextarea = textarea => {
|
||||
_handleInitTextarea (textarea) {
|
||||
if (!textarea) {
|
||||
// Not mounted
|
||||
return;
|
||||
@ -232,6 +236,11 @@ class Editor extends PureComponent {
|
||||
if (this.props.render) {
|
||||
this.codeMirror.enableNunjucksTags(this.props.render);
|
||||
}
|
||||
|
||||
// Make URLs clickable
|
||||
if (this.props.onClickLink) {
|
||||
this.codeMirror.makeLinksClickable(this.props.onClickLink);
|
||||
}
|
||||
};
|
||||
|
||||
// Do this a bit later for big values so we don't block the render process
|
||||
@ -258,10 +267,10 @@ class Editor extends PureComponent {
|
||||
return mode.indexOf('xml') !== -1
|
||||
}
|
||||
|
||||
_handleBeautify = () => {
|
||||
_handleBeautify () {
|
||||
trackEvent('Request', 'Beautify');
|
||||
this._prettify(this.codeMirror.getValue());
|
||||
};
|
||||
}
|
||||
|
||||
_prettify (code) {
|
||||
this._codemirrorSetValue(code, true);
|
||||
@ -311,7 +320,7 @@ class Editor extends PureComponent {
|
||||
/**
|
||||
* Sets options on the CodeMirror editor while also sanitizing them
|
||||
*/
|
||||
_codemirrorSetOptions = () => {
|
||||
_codemirrorSetOptions () {
|
||||
const {
|
||||
mode: rawMode,
|
||||
readOnly,
|
||||
@ -328,16 +337,15 @@ class Editor extends PureComponent {
|
||||
} = this.props;
|
||||
|
||||
let mode;
|
||||
if (this.props.readOnly) {
|
||||
// Should probably have an actual prop for this, but let's not
|
||||
// enable nunjucks on editors that the user can modify
|
||||
mode = this._normalizeMode(rawMode);
|
||||
} else {
|
||||
if (this.props.render) {
|
||||
mode = {name: 'nunjucks', baseMode: this._normalizeMode(rawMode)};
|
||||
} else {
|
||||
// foo bar baz
|
||||
mode = this._normalizeMode(rawMode);
|
||||
}
|
||||
|
||||
let options = {
|
||||
readOnly,
|
||||
readOnly: !!readOnly,
|
||||
placeholder: placeholder || '',
|
||||
mode: mode,
|
||||
tabIndex: typeof tabIndex === 'number' ? tabIndex : null,
|
||||
@ -376,9 +384,6 @@ class Editor extends PureComponent {
|
||||
|
||||
cm.setOption(key, options[key]);
|
||||
});
|
||||
|
||||
// Add overlays;
|
||||
this.codeMirror.makeLinksClickable(this.props.onClickLink);
|
||||
};
|
||||
|
||||
_normalizeMode (mode) {
|
||||
@ -391,9 +396,9 @@ class Editor extends PureComponent {
|
||||
} else {
|
||||
return mimeType;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_codemirrorKeyDown = (doc, e) => {
|
||||
_codemirrorKeyDown (doc, e) {
|
||||
// Use default tab behaviour if we're told
|
||||
if (this.props.defaultTabBehavior && e.keyCode === TAB_KEY) {
|
||||
e.codemirrorIgnore = true;
|
||||
@ -402,21 +407,21 @@ class Editor extends PureComponent {
|
||||
if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(e, doc.getValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_codemirrorFocus = (doc, e) => {
|
||||
_codemirrorFocus (doc, e) {
|
||||
if (this.props.onFocus) {
|
||||
this.props.onFocus(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_codemirrorBlur = (doc, e) => {
|
||||
_codemirrorBlur (doc, e) {
|
||||
if (this.props.onBlur) {
|
||||
this.props.onBlur(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_codemirrorValueBeforeChange = (doc, change) => {
|
||||
_codemirrorValueBeforeChange (doc, change) {
|
||||
// If we're in single-line mode, merge all changed lines into one
|
||||
if (this.props.singleLine && change.text.length > 1) {
|
||||
const text = change.text
|
||||
@ -426,12 +431,12 @@ class Editor extends PureComponent {
|
||||
const to = {ch: from.ch + text.length, line: 0};
|
||||
change.update(from, to, [text]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function to add extra behaviour to our onChange event
|
||||
*/
|
||||
_codemirrorValueChanged = () => {
|
||||
_codemirrorValueChanged () {
|
||||
// Don't trigger change event if we're ignoring changes
|
||||
if (this._ignoreNextChange || !this.props.onChange) {
|
||||
this._ignoreNextChange = false;
|
||||
@ -440,7 +445,7 @@ class Editor extends PureComponent {
|
||||
|
||||
const value = this.codeMirror.getDoc().getValue();
|
||||
this.props.onChange(value);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CodeMirror value without triggering the onChange event
|
||||
@ -468,7 +473,7 @@ class Editor extends PureComponent {
|
||||
this.codeMirror.setValue(code || '');
|
||||
}
|
||||
|
||||
_handleFilterChange = e => {
|
||||
_handleFilterChange (e) {
|
||||
const filter = e.target.value;
|
||||
|
||||
clearTimeout(this._filterTimeout);
|
||||
@ -490,7 +495,7 @@ class Editor extends PureComponent {
|
||||
`${filter ? 'Change' : 'Clear'}`
|
||||
);
|
||||
}, 2000);
|
||||
};
|
||||
}
|
||||
|
||||
_canPrettify () {
|
||||
const {mode} = this.props;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Editor from './Editor';
|
||||
import Input from '../base/DebouncedInput';
|
||||
|
||||
@ -7,6 +8,7 @@ const MODE_EDITOR = 'editor';
|
||||
const TYPE_TEXT = 'text';
|
||||
const NUNJUCKS_REGEX = /({%|%}|{{|}})/;
|
||||
|
||||
@autobind
|
||||
class OneLineEditor extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
@ -43,12 +45,12 @@ class OneLineEditor extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_handleEditorFocus = e => {
|
||||
_handleEditorFocus (e) {
|
||||
this._editor.focusEnd();
|
||||
this.props.onFocus && this.props.onFocus(e);
|
||||
};
|
||||
}
|
||||
|
||||
_handleInputFocus = e => {
|
||||
_handleInputFocus (e) {
|
||||
if (this.props.blurOnFocus) {
|
||||
e.target.blur();
|
||||
} else {
|
||||
@ -65,9 +67,9 @@ class OneLineEditor extends PureComponent {
|
||||
|
||||
// Also call the regular callback
|
||||
this.props.onFocus && this.props.onFocus(e);
|
||||
};
|
||||
}
|
||||
|
||||
_handleInputChange = value => {
|
||||
_handleInputChange (value) {
|
||||
if (!this.props.forceInput && this._mayContainNunjucks(value)) {
|
||||
const start = this._input.getSelectionStart();
|
||||
const end = this._input.getSelectionEnd();
|
||||
@ -87,15 +89,15 @@ class OneLineEditor extends PureComponent {
|
||||
}
|
||||
|
||||
this.props.onChange && this.props.onChange(value);
|
||||
};
|
||||
}
|
||||
|
||||
_handleInputKeyDown = e => {
|
||||
_handleInputKeyDown (e) {
|
||||
if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(e, e.target.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditorBlur = e => {
|
||||
_handleEditorBlur () {
|
||||
if (this.props.forceEditor) {
|
||||
return;
|
||||
}
|
||||
@ -107,9 +109,9 @@ class OneLineEditor extends PureComponent {
|
||||
this.setState({mode: MODE_INPUT});
|
||||
|
||||
this.props.onBlur && this.props.onBlur();
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditorKeyDown = e => {
|
||||
_handleEditorKeyDown (e) {
|
||||
// submit form if needed
|
||||
if (e.keyCode === 13) {
|
||||
let node = e.target;
|
||||
@ -124,11 +126,19 @@ class OneLineEditor extends PureComponent {
|
||||
|
||||
// Also call the original if there was one
|
||||
this.props.onKeyDown && this.props.onKeyDown(e, this.getValue());
|
||||
};
|
||||
}
|
||||
|
||||
_setEditorRef = n => this._editor = n;
|
||||
_setInputRef = n => this._input = n;
|
||||
_mayContainNunjucks = text => !!text.match(NUNJUCKS_REGEX);
|
||||
_setEditorRef (n) {
|
||||
this._editor = n;
|
||||
}
|
||||
|
||||
_setInputRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
_mayContainNunjucks (text) {
|
||||
return !!text.match(NUNJUCKS_REGEX);
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
@ -162,8 +172,8 @@ class OneLineEditor extends PureComponent {
|
||||
placeholder={placeholder}
|
||||
onBlur={this._handleEditorBlur}
|
||||
onKeyDown={this._handleEditorKeyDown}
|
||||
onChange={onChange}
|
||||
onFocus={this._handleEditorFocus}
|
||||
onChange={onChange}
|
||||
render={render}
|
||||
className="editor--single-line"
|
||||
defaultValue={defaultValue}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider} from '../base/dropdown';
|
||||
import {contentTypesMap} from '../../../common/constants';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
@ -7,11 +8,16 @@ import {getContentTypeName} from '../../../common/constants';
|
||||
|
||||
const EMPTY_MIME_TYPE = null;
|
||||
|
||||
@autobind
|
||||
class ContentTypeDropdown extends PureComponent {
|
||||
_handleChangeMimeType = mimeType => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleChangeMimeType (mimeType) {
|
||||
this.props.onChange(mimeType);
|
||||
trackEvent('Request', 'Content-Type Change', contentTypesMap[mimeType]);
|
||||
};
|
||||
}
|
||||
|
||||
_renderDropdownItem (mimeType, forcedName = null) {
|
||||
const contentType = typeof this.props.contentType !== 'string' ?
|
||||
|
@ -1,13 +1,19 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownDivider, DropdownButton, DropdownItem} from '../base/dropdown';
|
||||
import {PREVIEW_MODES, getPreviewModeName} from '../../../common/constants';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class PreviewModeDropdown extends PureComponent {
|
||||
_handleClick = previewMode => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleClick (previewMode) {
|
||||
this.props.updatePreviewMode(previewMode);
|
||||
trackEvent('Response', 'Preview Mode Change', previewMode);
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {download, previewMode} = this.props;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import {Dropdown, DropdownHint, DropdownButton, DropdownItem} from '../base/dropdown';
|
||||
import PromptModal from '../modals/PromptModal';
|
||||
@ -6,22 +7,27 @@ import * as models from '../../../models';
|
||||
import {showModal} from '../modals/index';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
|
||||
@autobind
|
||||
class RequestActionsDropdown extends PureComponent {
|
||||
_setDropdownRef = n => this._dropdown = n;
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
_setDropdownRef (n) {
|
||||
this._dropdown = n;
|
||||
}
|
||||
|
||||
_handleDuplicate = () => {
|
||||
_handleDuplicate () {
|
||||
const {request, handleDuplicateRequest} = this.props;
|
||||
handleDuplicateRequest(request);
|
||||
trackEvent('Request', 'Duplicate', 'Request Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleGenerateCode = () => {
|
||||
_handleGenerateCode () {
|
||||
this.props.handleGenerateCode(this.props.request);
|
||||
trackEvent('Request', 'Generate Code', 'Request Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handlePromptUpdateName = async () => {
|
||||
async _handlePromptUpdateName () {
|
||||
const {request} = this.props;
|
||||
|
||||
const name = await showModal(PromptModal, {
|
||||
@ -33,13 +39,13 @@ class RequestActionsDropdown extends PureComponent {
|
||||
models.request.update(request, {name});
|
||||
|
||||
trackEvent('Request', 'Rename', 'Request Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRemove = () => {
|
||||
_handleRemove () {
|
||||
const {request} = this.props;
|
||||
models.request.remove(request);
|
||||
trackEvent('Request', 'Delete', 'Action');
|
||||
};
|
||||
}
|
||||
|
||||
show () {
|
||||
this._dropdown.show();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider, DropdownHint} from '../base/dropdown';
|
||||
import EnvironmentEditModal from '../modals/EnvironmentEditModal';
|
||||
@ -7,10 +8,17 @@ import * as models from '../../../models';
|
||||
import {showModal} from '../modals';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class RequestGroupActionsDropdown extends PureComponent {
|
||||
_setDropdownRef = n => this._dropdown = n;
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleRename = async () => {
|
||||
_setDropdownRef (n) {
|
||||
this._dropdown = n;
|
||||
}
|
||||
|
||||
async _handleRename () {
|
||||
const {requestGroup} = this.props;
|
||||
|
||||
const name = await showModal(PromptModal, {
|
||||
@ -21,31 +29,31 @@ class RequestGroupActionsDropdown extends PureComponent {
|
||||
models.requestGroup.update(requestGroup, {name});
|
||||
|
||||
trackEvent('Folder', 'Rename', 'Folder Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestCreate = async () => {
|
||||
async _handleRequestCreate () {
|
||||
this.props.handleCreateRequest(this.props.requestGroup._id);
|
||||
trackEvent('Request', 'Create', 'Folder Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestGroupDuplicate = () => {
|
||||
_handleRequestGroupDuplicate () {
|
||||
this.props.handleDuplicateRequestGroup(this.props.requestGroup);
|
||||
trackEvent('Folder', 'Duplicate', 'Folder Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestGroupCreate = async () => {
|
||||
async _handleRequestGroupCreate () {
|
||||
this.props.handleCreateRequestGroup(this.props.requestGroup._id);
|
||||
trackEvent('Folder', 'Create', 'Folder Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleDeleteFolder = () => {
|
||||
_handleDeleteFolder () {
|
||||
models.requestGroup.remove(this.props.requestGroup);
|
||||
trackEvent('Folder', 'Delete', 'Folder Action');
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditEnvironment = () => {
|
||||
_handleEditEnvironment () {
|
||||
showModal(EnvironmentEditModal, this.props.requestGroup);
|
||||
};
|
||||
}
|
||||
|
||||
show () {
|
||||
this._dropdown.show();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider} from '../base/dropdown';
|
||||
import SizeTag from '../tags/SizeTag';
|
||||
import StatusTag from '../tags/StatusTag';
|
||||
@ -8,22 +9,28 @@ import PromptButton from '../base/PromptButton';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
import * as misc from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class ResponseHistoryDropdown extends PureComponent {
|
||||
state = {
|
||||
responses: [],
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
responses: [],
|
||||
};
|
||||
|
||||
_handleDeleteResponses = () => {
|
||||
this._load = misc.debounce(this._load);
|
||||
}
|
||||
|
||||
_handleDeleteResponses () {
|
||||
trackEvent('History', 'Delete Responses');
|
||||
this.props.handleDeleteResponses(this.props.requestId);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetActiveResponse = responseId => {
|
||||
_handleSetActiveResponse (responseId) {
|
||||
trackEvent('History', 'Activate Response');
|
||||
this.props.handleSetActiveResponse(responseId);
|
||||
};
|
||||
}
|
||||
|
||||
_load = misc.debounce(async requestId => {
|
||||
async _load (requestId) {
|
||||
const responses = await models.response.findRecentForRequest(requestId);
|
||||
|
||||
// NOTE: this is bad practice, but I can't figure out a better way.
|
||||
@ -36,7 +43,7 @@ class ResponseHistoryDropdown extends PureComponent {
|
||||
if (this.state.responses.length !== responses.length) {
|
||||
this.setState({responses});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this._unmounted = true;
|
||||
@ -51,7 +58,7 @@ class ResponseHistoryDropdown extends PureComponent {
|
||||
this._load(this.props.requestId);
|
||||
}
|
||||
|
||||
renderDropdownItem = (response, i) => {
|
||||
renderDropdownItem (response, i) {
|
||||
const {activeResponseId} = this.props;
|
||||
const active = response._id === activeResponseId;
|
||||
return (
|
||||
@ -68,7 +75,7 @@ class ResponseHistoryDropdown extends PureComponent {
|
||||
<SizeTag bytes={response.bytesRead} small/>
|
||||
</DropdownItem>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -1,35 +1,45 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownDivider, DropdownItem, DropdownButton} from '../base/dropdown';
|
||||
import {showModal} from '../modals';
|
||||
import SyncLogsModal from '../modals/SyncLogsModal';
|
||||
import * as syncStorage from '../../../sync/storage';
|
||||
import * as session from '../../../sync/session';
|
||||
import * as sync from '../../../sync';
|
||||
import {trackEvent} from '../../../analytics';
|
||||
import WorkspaceShareSettingsModal from '../modals/WorkspaceShareSettingsModal';
|
||||
import SetupSyncModal from '../modals/SetupSyncModal';
|
||||
|
||||
@autobind
|
||||
class SyncDropdown extends PureComponent {
|
||||
state = {
|
||||
loggedIn: null,
|
||||
syncData: null,
|
||||
loading: false,
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_trackShowMenu = () => trackEvent('Sync', 'Show Menu', 'Authenticated');
|
||||
_handleShowLogs = () => showModal(SyncLogsModal);
|
||||
this._hasPrompted = false;
|
||||
|
||||
_handleShowShareSettings = () => {
|
||||
this.state = {
|
||||
loggedIn: null,
|
||||
syncData: null,
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
_trackShowMenu () {
|
||||
trackEvent('Sync', 'Show Menu', 'Authenticated');
|
||||
}
|
||||
|
||||
_handleShowShareSettings () {
|
||||
showModal(WorkspaceShareSettingsModal, {workspace: this.props.workspace});
|
||||
};
|
||||
}
|
||||
|
||||
_handleToggleSyncMode = async () => {
|
||||
async _handleToggleSyncMode () {
|
||||
const {syncData} = this.state;
|
||||
const resourceGroupId = syncData.resourceGroupId;
|
||||
|
||||
const config = await sync.getOrCreateConfig(resourceGroupId);
|
||||
|
||||
let syncMode = config.syncMode === syncStorage.SYNC_MODE_OFF ?
|
||||
syncStorage.SYNC_MODE_ON : syncStorage.SYNC_MODE_OFF;
|
||||
let syncMode = config.syncMode !== syncStorage.SYNC_MODE_ON ?
|
||||
syncStorage.SYNC_MODE_ON :
|
||||
syncStorage.SYNC_MODE_OFF;
|
||||
|
||||
await sync.createOrUpdateConfig(resourceGroupId, syncMode);
|
||||
|
||||
@ -41,9 +51,9 @@ class SyncDropdown extends PureComponent {
|
||||
}
|
||||
|
||||
trackEvent('Sync', 'Change Mode', syncMode);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSyncResourceGroupId = async () => {
|
||||
async _handleSyncResourceGroupId () {
|
||||
const {syncData} = this.state;
|
||||
const resourceGroupId = syncData.resourceGroupId;
|
||||
|
||||
@ -60,7 +70,7 @@ class SyncDropdown extends PureComponent {
|
||||
this.setState({loading: false});
|
||||
|
||||
trackEvent('Sync', 'Manual Sync');
|
||||
};
|
||||
}
|
||||
|
||||
async _reloadData () {
|
||||
const loggedIn = session.isLoggedIn();
|
||||
@ -94,6 +104,11 @@ class SyncDropdown extends PureComponent {
|
||||
this.setState({syncData});
|
||||
}
|
||||
|
||||
async _handleShowSyncModePrompt () {
|
||||
await showModal(SetupSyncModal);
|
||||
await this._reloadData();
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this._interval = setInterval(() => this._reloadData(), 2000);
|
||||
this._reloadData();
|
||||
@ -103,16 +118,40 @@ class SyncDropdown extends PureComponent {
|
||||
clearInterval(this._interval);
|
||||
}
|
||||
|
||||
_getSyncDescription (syncMode, syncPercentage) {
|
||||
if (syncPercentage === 100) {
|
||||
return 'Up To Date'
|
||||
} else {
|
||||
return syncMode === syncStorage.SYNC_MODE_ON ? 'Sync Pending' : 'Sync Required'
|
||||
async componentDidUpdate () {
|
||||
const {syncData} = this.state;
|
||||
|
||||
if (!syncData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync has not yet been configured for this workspace, so prompt the user to do so
|
||||
const isModeUnset = syncData.syncMode === syncStorage.SYNC_MODE_UNSET;
|
||||
if (isModeUnset && !this._hasPrompted) {
|
||||
this._hasPrompted = true;
|
||||
await this._handleShowSyncModePrompt();
|
||||
}
|
||||
}
|
||||
|
||||
_getSyncDescription (syncMode, syncPercentage) {
|
||||
let el = null;
|
||||
if (syncMode === syncStorage.SYNC_MODE_NEVER) {
|
||||
el = <span>Sync Disabled</span>
|
||||
} else if (syncPercentage === 100) {
|
||||
el = <span>Sync Up To Date</span>
|
||||
} else if (syncMode === syncStorage.SYNC_MODE_OFF) {
|
||||
el = <span><i className="fa fa-pause-circle-o"/> Sync Required</span>
|
||||
} else if (syncMode === syncStorage.SYNC_MODE_ON) {
|
||||
el = <span>Sync Pending</span>
|
||||
} else if (syncMode === syncStorage.SYNC_MODE_UNSET) {
|
||||
el = <span><i className="fa fa-exclamation-circle"/> Configure Sync</span>
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
render () {
|
||||
const {className, workspace} = this.props;
|
||||
const {className} = this.props;
|
||||
const {syncData, loading, loggedIn} = this.state;
|
||||
|
||||
// Don't show the sync menu unless we're logged in
|
||||
@ -130,39 +169,51 @@ class SyncDropdown extends PureComponent {
|
||||
)
|
||||
} else {
|
||||
const {syncMode, syncPercent} = syncData;
|
||||
const description = this._getSyncDescription(syncMode, syncPercent);
|
||||
const isPaused = syncMode === syncStorage.SYNC_MODE_OFF;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Dropdown wide className="wide tall">
|
||||
<DropdownButton className="btn btn--compact wide" onClick={this._trackShowMenu}>
|
||||
{isPaused ? <span><i className="fa fa-pause-circle"/> </span> : null}
|
||||
{description}
|
||||
{this._getSyncDescription(syncMode, syncPercent)}
|
||||
</DropdownButton>
|
||||
<DropdownDivider>Workspace Synced {syncPercent}%</DropdownDivider>
|
||||
<DropdownItem onClick={this._handleToggleSyncMode} stayOpenAfterClick>
|
||||
{syncMode === syncStorage.SYNC_MODE_OFF ?
|
||||
<i className="fa fa-toggle-off"></i> :
|
||||
<i className="fa fa-toggle-on"></i>}
|
||||
Automatic Sync
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={this._handleSyncResourceGroupId} stayOpenAfterClick>
|
||||
{loading ?
|
||||
<i className="fa fa-refresh fa-spin"></i> :
|
||||
<i className="fa fa-cloud-upload"></i>}
|
||||
Sync Now
|
||||
</DropdownItem>
|
||||
|
||||
<DropdownDivider>Other</DropdownDivider>
|
||||
<DropdownItem onClick={this._handleShowShareSettings}>
|
||||
<i className="fa fa-users"></i>
|
||||
Configure Sharing
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={this._handleShowLogs}>
|
||||
<i className="fa fa-bug"></i>
|
||||
Show Debug Logs
|
||||
</DropdownItem>
|
||||
{/* SYNC DISABLED */}
|
||||
|
||||
{syncMode === syncStorage.SYNC_MODE_NEVER ?
|
||||
<DropdownItem onClick={this._handleShowSyncModePrompt}>
|
||||
<i className="fa fa-wrench"/>
|
||||
Change Sync Mode
|
||||
</DropdownItem> : null
|
||||
}
|
||||
|
||||
{/* SYNCED */}
|
||||
|
||||
{syncMode !== syncStorage.SYNC_MODE_NEVER ?
|
||||
<DropdownItem onClick={this._handleToggleSyncMode} stayOpenAfterClick={true}>
|
||||
{syncMode === syncStorage.SYNC_MODE_ON ?
|
||||
<i className="fa fa-toggle-on"/> :
|
||||
<i className="fa fa-toggle-off"/>
|
||||
}
|
||||
Automatic Sync
|
||||
</DropdownItem> : null
|
||||
}
|
||||
|
||||
{syncMode !== syncStorage.SYNC_MODE_NEVER ?
|
||||
<DropdownItem onClick={this._handleSyncResourceGroupId} stayOpenAfterClick>
|
||||
{loading ?
|
||||
<i className="fa fa-refresh fa-spin"/> :
|
||||
<i className="fa fa-cloud-upload"/>
|
||||
}
|
||||
Sync Now
|
||||
</DropdownItem> : null
|
||||
}
|
||||
|
||||
{syncMode !== syncStorage.SYNC_MODE_NEVER ?
|
||||
<DropdownItem onClick={this._handleShowShareSettings}>
|
||||
<i className="fa fa-users"></i>
|
||||
Share With Others
|
||||
</DropdownItem> : null
|
||||
}
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,7 +1,12 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import classnames from 'classnames';
|
||||
import autobind from 'autobind-decorator';
|
||||
import * as classnames from 'classnames';
|
||||
import {ipcRenderer, shell} from 'electron';
|
||||
import {Dropdown, DropdownDivider, DropdownButton, DropdownItem, DropdownHint, DropdownRight} from '../base/dropdown';
|
||||
import Dropdown from '../base/dropdown/Dropdown';
|
||||
import DropdownDivider from '../base/dropdown/DropdownDivider';
|
||||
import DropdownButton from '../base/dropdown/DropdownButton';
|
||||
import DropdownItem from '../base/dropdown/DropdownItem';
|
||||
import DropdownHint from '../base/dropdown/DropdownHint';
|
||||
import PromptModal from '../modals/PromptModal';
|
||||
import SettingsModal, {TAB_INDEX_EXPORT} from '../modals/SettingsModal';
|
||||
import * as models from '../../../models';
|
||||
@ -15,41 +20,49 @@ import * as session from '../../../sync/session';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import LoginModal from '../modals/LoginModal';
|
||||
|
||||
@autobind
|
||||
class WorkspaceDropdown extends PureComponent {
|
||||
state = {
|
||||
loggedIn: false
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loggedIn: false
|
||||
};
|
||||
}
|
||||
|
||||
_handleDropdownOpen = () => {
|
||||
_handleDropdownOpen () {
|
||||
if (this.state.loggedIn !== session.isLoggedIn()) {
|
||||
this.setState({loggedIn: session.isLoggedIn()});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleShowLogin = () => {
|
||||
_handleShowLogin () {
|
||||
showModal(LoginModal);
|
||||
};
|
||||
}
|
||||
|
||||
_handleShowExport = () => showModal(SettingsModal, TAB_INDEX_EXPORT);
|
||||
_handleShowSettings = () => showModal(SettingsModal);
|
||||
_handleShowWorkspaceSettings = () => {
|
||||
_handleShowExport () {
|
||||
showModal(SettingsModal, TAB_INDEX_EXPORT);
|
||||
}
|
||||
_handleShowSettings () {
|
||||
showModal(SettingsModal);
|
||||
}
|
||||
_handleShowWorkspaceSettings () {
|
||||
showModal(WorkspaceSettingsModal, {
|
||||
workspace: this.props.activeWorkspace,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
_handleShowShareSettings = () => {
|
||||
_handleShowShareSettings () {
|
||||
showModal(WorkspaceShareSettingsModal, {
|
||||
workspace: this.props.activeWorkspace,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
_handleSwitchWorkspace = workspaceId => {
|
||||
_handleSwitchWorkspace (workspaceId) {
|
||||
this.props.handleSetActiveWorkspace(workspaceId);
|
||||
trackEvent('Workspace', 'Switch');
|
||||
};
|
||||
}
|
||||
|
||||
_handleWorkspaceCreate = async noTrack => {
|
||||
async _handleWorkspaceCreate (noTrack) {
|
||||
const name = await showModal(PromptModal, {
|
||||
headerName: 'Create New Workspace',
|
||||
defaultValue: 'My Workspace',
|
||||
@ -63,7 +76,7 @@ class WorkspaceDropdown extends PureComponent {
|
||||
if (!noTrack) {
|
||||
trackEvent('Workspace', 'Create');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -1,17 +1,28 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import KeyValueEditor from '../keyvalueeditor/Editor';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class AuthEditor extends PureComponent {
|
||||
_handleOnCreate = () => trackEvent('Auth Editor', 'Create');
|
||||
_handleOnDelete = () => trackEvent('Auth Editor', 'Delete');
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleToggleDisable = pair => {
|
||||
_handleOnCreate () {
|
||||
trackEvent('Auth Editor', 'Create');
|
||||
}
|
||||
|
||||
_handleOnDelete () {
|
||||
trackEvent('Auth Editor', 'Delete');
|
||||
}
|
||||
|
||||
_handleToggleDisable (pair) {
|
||||
const label = pair.disabled ? 'Disable' : 'Enable';
|
||||
trackEvent('Auth Editor', 'Toggle', label);
|
||||
};
|
||||
}
|
||||
|
||||
_handleChange = pairs => {
|
||||
_handleChange (pairs) {
|
||||
const pair = {
|
||||
username: pairs.length ? pairs[0].name : '',
|
||||
password: pairs.length ? pairs[0].value : '',
|
||||
@ -19,7 +30,7 @@ class AuthEditor extends PureComponent {
|
||||
};
|
||||
|
||||
this.props.onChange(pair);
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {authentication, showPasswords, handleRender} = this.props;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Cookie} from 'tough-cookie';
|
||||
|
||||
import PromptButton from '../base/PromptButton';
|
||||
@ -6,9 +7,13 @@ import CookieInput from '../CookieInput';
|
||||
import {cookieToString} from '../../../common/cookies';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
|
||||
|
||||
@autobind
|
||||
class CookiesEditor extends PureComponent {
|
||||
_handleCookieAdd = () => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleCookieAdd () {
|
||||
const newCookie = new Cookie({
|
||||
key: 'foo',
|
||||
value: 'bar',
|
||||
@ -17,7 +22,7 @@ class CookiesEditor extends PureComponent {
|
||||
});
|
||||
|
||||
this.props.onCookieAdd(newCookie);
|
||||
};
|
||||
}
|
||||
|
||||
_handleCookieUpdate (cookie, cookieStr) {
|
||||
clearTimeout(this._cookieUpdateTimeout);
|
||||
|
@ -1,11 +1,20 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Editor from '../codemirror/Editor';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
|
||||
@autobind
|
||||
class EnvironmentEditor extends PureComponent {
|
||||
_handleChange = () => this.props.didChange();
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
_handleChange () {
|
||||
this.props.didChange();
|
||||
}
|
||||
|
||||
_setEditorRef = n => this._editor = n;
|
||||
_setEditorRef (n) {
|
||||
this._editor = n;
|
||||
}
|
||||
|
||||
getValue () {
|
||||
return JSON.parse(this._editor.getValue());
|
||||
|
@ -1,18 +1,31 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
|
||||
import autobind from 'autobind-decorator';
|
||||
import KeyValueEditor from '../keyvalueeditor/Editor';
|
||||
import Editor from '../codemirror/Editor';
|
||||
import Lazy from '../base/Lazy';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class RequestHeadersEditor extends PureComponent {
|
||||
_handleBulkUpdate = headersString => {
|
||||
this.props.onChange(this._getHeadersFromString(headersString));
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleTrackToggle = pair => trackEvent('Headers Editor', 'Toggle', pair.disabled ? 'Disable' : 'Enable');
|
||||
_handleTrackCreate = () => trackEvent('Headers Editor', 'Create');
|
||||
_handleTrackDelete = () => trackEvent('Headers Editor', 'Delete');
|
||||
_handleBulkUpdate (headersString) {
|
||||
this.props.onChange(this._getHeadersFromString(headersString));
|
||||
}
|
||||
|
||||
_handleTrackToggle (pair) {
|
||||
trackEvent('Headers Editor', 'Toggle', pair.disabled ? 'Disable' : 'Enable');
|
||||
}
|
||||
|
||||
_handleTrackCreate () {
|
||||
trackEvent('Headers Editor', 'Create');
|
||||
}
|
||||
|
||||
_handleTrackDelete () {
|
||||
trackEvent('Headers Editor', 'Delete');
|
||||
}
|
||||
|
||||
_getHeadersFromString (headersString) {
|
||||
const headers = [];
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import RawEditor from './RawEditor';
|
||||
import UrlEncodedEditor from './UrlEncodedEditor';
|
||||
import FormEditor from './FormEditor';
|
||||
@ -6,33 +7,38 @@ import FileEditor from './FileEditor';
|
||||
import {getContentTypeFromHeaders, CONTENT_TYPE_FORM_URLENCODED, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FILE} from '../../../../common/constants';
|
||||
import {newBodyRaw, newBodyFormUrlEncoded, newBodyForm, newBodyFile} from '../../../../models/request';
|
||||
|
||||
@autobind
|
||||
class BodyEditor extends PureComponent {
|
||||
_handleRawChange = rawValue => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleRawChange (rawValue) {
|
||||
const {onChange, request} = this.props;
|
||||
|
||||
const contentType = getContentTypeFromHeaders(request.headers);
|
||||
const newBody = newBodyRaw(rawValue, contentType || '');
|
||||
|
||||
onChange(newBody);
|
||||
};
|
||||
}
|
||||
|
||||
_handleFormUrlEncodedChange = parameters => {
|
||||
_handleFormUrlEncodedChange (parameters) {
|
||||
const {onChange} = this.props;
|
||||
const newBody = newBodyFormUrlEncoded(parameters);
|
||||
onChange(newBody);
|
||||
};
|
||||
}
|
||||
|
||||
_handleFormChange = parameters => {
|
||||
_handleFormChange (parameters) {
|
||||
const {onChange} = this.props;
|
||||
const newBody = newBodyForm(parameters);
|
||||
onChange(newBody);
|
||||
};
|
||||
}
|
||||
|
||||
_handleFileChange = path => {
|
||||
_handleFileChange (path) {
|
||||
const {onChange} = this.props;
|
||||
const newBody = newBodyFile(path);
|
||||
onChange(newBody);
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {keyMap, fontSize, lineWrapping, request, handleRender} = this.props;
|
||||
|
@ -1,18 +1,24 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import fs from 'fs';
|
||||
import electron from 'electron';
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import FileInputButton from '../../base/FileInputButton';
|
||||
import PromptButton from '../../base/PromptButton';
|
||||
import * as misc from '../../../../common/misc';
|
||||
import {trackEvent} from '../../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class FileEditor extends PureComponent {
|
||||
_handleResetFile = () => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleResetFile () {
|
||||
this.props.onChange('');
|
||||
trackEvent('File Editor', 'Reset');
|
||||
};
|
||||
}
|
||||
|
||||
_handleChooseFile = path => {
|
||||
_handleChooseFile (path) {
|
||||
this.props.onChange(path);
|
||||
trackEvent('File Editor', 'Choose');
|
||||
};
|
||||
|
@ -1,20 +1,37 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import KeyValueEditor from '../../keyvalueeditor/Editor';
|
||||
import {trackEvent} from '../../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class FormEditor extends PureComponent {
|
||||
_handleTrackToggle = pair => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleTrackToggle (pair) {
|
||||
trackEvent(
|
||||
'Form Editor',
|
||||
`Toggle ${pair.type || 'text'}`,
|
||||
pair.disabled ? 'Disable' : 'Enable'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
_handleTrackChangeType = type => trackEvent('Form Editor', 'Change Type', type);
|
||||
_handleTrackChooseFile = () => trackEvent('Form Editor', 'Choose File');
|
||||
_handleTrackCreate = () => trackEvent('Form Editor', 'Create');
|
||||
_handleTrackDelete = () => trackEvent('Form Editor', 'Delete');
|
||||
_handleTrackChangeType (type) {
|
||||
trackEvent('Form Editor', 'Change Type', type);
|
||||
}
|
||||
|
||||
_handleTrackChooseFile () {
|
||||
trackEvent('Form Editor', 'Choose File');
|
||||
}
|
||||
|
||||
_handleTrackCreate () {
|
||||
trackEvent('Form Editor', 'Create');
|
||||
}
|
||||
|
||||
_handleTrackDelete () {
|
||||
trackEvent('Form Editor', 'Delete');
|
||||
}
|
||||
|
||||
render () {
|
||||
const {parameters, onChange, handleRender} = this.props;
|
||||
|
@ -1,17 +1,30 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Lazy from '../../base/Lazy';
|
||||
import KeyValueEditor from '../../keyvalueeditor/Editor';
|
||||
import {trackEvent} from '../../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class UrlEncodedEditor extends PureComponent {
|
||||
_handleTrackToggle = pair => trackEvent(
|
||||
'Url Encoded Editor',
|
||||
'Toggle',
|
||||
pair.disabled ? 'Disable' : 'Enable'
|
||||
);
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleTrackCreate = () => trackEvent('Url Encoded Editor', 'Create');
|
||||
_handleTrackDelete = () => trackEvent('Url Encoded Editor', 'Delete');
|
||||
_handleTrackToggle (pair) {
|
||||
trackEvent(
|
||||
'Url Encoded Editor',
|
||||
'Toggle',
|
||||
pair.disabled ? 'Disable' : 'Enable'
|
||||
);
|
||||
}
|
||||
|
||||
_handleTrackCreate () {
|
||||
trackEvent('Url Encoded Editor', 'Create');
|
||||
}
|
||||
|
||||
_handleTrackDelete () {
|
||||
trackEvent('Url Encoded Editor', 'Delete');
|
||||
}
|
||||
|
||||
render () {
|
||||
const {parameters, onChange, handleRender} = this.props;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
import KeyValueEditorRow from './Row';
|
||||
@ -13,6 +14,7 @@ const DOWN = 40;
|
||||
const LEFT = 37;
|
||||
const RIGHT = 39;
|
||||
|
||||
@autobind
|
||||
class KeyValueEditor extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
@ -29,10 +31,12 @@ class KeyValueEditor extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {pairs};
|
||||
this.state = {
|
||||
pairs: pairs,
|
||||
};
|
||||
}
|
||||
|
||||
_handlePairChange = pair => {
|
||||
_handlePairChange (pair) {
|
||||
const i = this._getPairIndex(pair);
|
||||
const pairs = [
|
||||
...this.state.pairs.slice(0, i),
|
||||
@ -41,9 +45,9 @@ class KeyValueEditor extends PureComponent {
|
||||
];
|
||||
|
||||
this._onChange(pairs);
|
||||
};
|
||||
}
|
||||
|
||||
_handleMove = (pairToMove, pairToTarget, targetOffset) => {
|
||||
_handleMove (pairToMove, pairToTarget, targetOffset) {
|
||||
if (pairToMove.id === pairToTarget.id) {
|
||||
// Nothing to do
|
||||
return;
|
||||
@ -66,41 +70,41 @@ class KeyValueEditor extends PureComponent {
|
||||
this._onChange(pairs);
|
||||
};
|
||||
|
||||
_handlePairDelete = pair => {
|
||||
_handlePairDelete (pair) {
|
||||
const i = this.state.pairs.findIndex(p => p.id === pair.id);
|
||||
this._deletePair(i, true);
|
||||
};
|
||||
}
|
||||
|
||||
_handleFocusName = pair => {
|
||||
_handleFocusName (pair) {
|
||||
this._setFocusedPair(pair);
|
||||
this._focusedField = NAME;
|
||||
};
|
||||
}
|
||||
|
||||
_handleFocusValue = pair => {
|
||||
_handleFocusValue (pair) {
|
||||
this._setFocusedPair(pair);
|
||||
this._focusedField = VALUE;
|
||||
};
|
||||
}
|
||||
|
||||
_handleBlurName = () => {
|
||||
_handleBlurName () {
|
||||
this._setFocusedPair(null);
|
||||
}
|
||||
|
||||
_handleBlurValue () {
|
||||
this._setFocusedPair(null);
|
||||
};
|
||||
|
||||
_handleBlurValue = () => {
|
||||
this._setFocusedPair(null);
|
||||
};
|
||||
|
||||
_handleAddFromName = () => {
|
||||
_handleAddFromName () {
|
||||
this._focusedField = NAME;
|
||||
this._addPair();
|
||||
};
|
||||
}
|
||||
|
||||
// Sometimes multiple focus events come in, so lets debounce it
|
||||
_handleAddFromValue = () => {
|
||||
_handleAddFromValue () {
|
||||
this._focusedField = VALUE;
|
||||
this._addPair();
|
||||
};
|
||||
}
|
||||
|
||||
_handleKeyDown = (pair, e, value) => {
|
||||
_handleKeyDown (pair, e, value) {
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {DragSource, DropTarget} from 'react-dnd';
|
||||
import classnames from 'classnames';
|
||||
import FileInputButton from '../base/FileInputButton';
|
||||
@ -7,14 +8,18 @@ import {Dropdown, DropdownItem, DropdownButton} from '../base/dropdown/index';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import Button from '../base/Button';
|
||||
import OneLineEditor from '../codemirror/OneLineEditor';
|
||||
import {preventDefault} from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class KeyValueEditorRow extends PureComponent {
|
||||
_nameInput = null;
|
||||
_valueInput = null;
|
||||
state = {
|
||||
dragDirection: 0
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this._nameInput = null;
|
||||
this._valueInput = null;
|
||||
this.state = {
|
||||
dragDirection: 0
|
||||
};
|
||||
}
|
||||
|
||||
focusName () {
|
||||
this._nameInput.focus();
|
||||
@ -30,46 +35,64 @@ class KeyValueEditorRow extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_setNameInputRef = n => this._nameInput = n;
|
||||
_setValueInputRef = n => this._valueInput = n;
|
||||
_setNameInputRef (n) {
|
||||
this._nameInput = n;
|
||||
}
|
||||
_setValueInputRef (n) {
|
||||
this._valueInput = n;
|
||||
}
|
||||
|
||||
_sendChange = patch => {
|
||||
_sendChange (patch) {
|
||||
const pair = Object.assign({}, this.props.pair, patch);
|
||||
this.props.onChange && this.props.onChange(pair);
|
||||
};
|
||||
}
|
||||
|
||||
_handleNameChange = name => this._sendChange({name});
|
||||
_handleValueChange = value => this._sendChange({value});
|
||||
_handleFileNameChange = filename => this._sendChange({fileName});
|
||||
_handleTypeChange = type => this._sendChange({type});
|
||||
_handleDisableChange = disabled => this._sendChange({disabled});
|
||||
_handleNameChange (name) {
|
||||
this._sendChange({name});
|
||||
}
|
||||
_handleValueChange (value) {
|
||||
this._sendChange({value});
|
||||
}
|
||||
_handleFileNameChange (fileName) {
|
||||
this._sendChange({fileName});
|
||||
}
|
||||
_handleTypeChange (type) {
|
||||
this._sendChange({type});
|
||||
}
|
||||
_handleDisableChange (disabled) {
|
||||
this._sendChange({disabled});
|
||||
}
|
||||
|
||||
_handleFocusName = e => this.props.onFocusName(this.props.pair, e);
|
||||
_handleFocusValue = e => this.props.onFocusValue(this.props.pair, e);
|
||||
_handleFocusName (e) {
|
||||
this.props.onFocusName(this.props.pair, e);
|
||||
}
|
||||
_handleFocusValue (e) {
|
||||
this.props.onFocusValue(this.props.pair, e);
|
||||
}
|
||||
|
||||
_handleBlurName = e => {
|
||||
_handleBlurName (e) {
|
||||
if (this.props.onBlurName) {
|
||||
this.props.onBlurName(this.props.pair, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleBlurValue = e => {
|
||||
_handleBlurValue (e) {
|
||||
if (this.props.onBlurName) {
|
||||
this.props.onBlurValue(this.props.pair, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleDelete = () => {
|
||||
_handleDelete () {
|
||||
if (this.props.onDelete) {
|
||||
this.props.onDelete(this.props.pair);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleKeyDown = (e, value) => {
|
||||
_handleKeyDown (e, value) {
|
||||
if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(this.props.pair, e, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -1,18 +1,26 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
|
||||
@autobind
|
||||
class AlertModal extends PureComponent {
|
||||
state = {
|
||||
title: '',
|
||||
message: '',
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_setModalRef = m => this.modal = m;
|
||||
this.state = {
|
||||
title: '',
|
||||
message: '',
|
||||
};
|
||||
}
|
||||
|
||||
_handleOk = () => {
|
||||
_setModalRef (m) {
|
||||
this.modal = m;
|
||||
}
|
||||
|
||||
_handleOk () {
|
||||
this.hide();
|
||||
this._okCallback();
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Link from '../base/Link';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
@ -6,10 +7,19 @@ import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
import {getAppVersion, CHANGELOG_URL, CHANGELOG_PAGE} from '../../../common/constants';
|
||||
|
||||
@autobind
|
||||
class ChangelogModal extends PureComponent {
|
||||
state = {changelog: null};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
changelog: null,
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef = m => this.modal = m;
|
||||
|
||||
_setModalRef (m) {
|
||||
this.modal = m;
|
||||
}
|
||||
|
||||
show () {
|
||||
this.modal.show();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
@ -7,23 +8,36 @@ import CookiesEditor from '../editors/CookiesEditor';
|
||||
import * as models from '../../../models';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class CookiesModal extends PureComponent {
|
||||
state = {
|
||||
cookieJar: null,
|
||||
workspace: null,
|
||||
filter: ''
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
cookieJar: null,
|
||||
workspace: null,
|
||||
filter: ''
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setFilterInputRef = n => this.filterInput = n;
|
||||
_hide = () => this.modal.hide();
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_setFilterInputRef (n) {
|
||||
this.filterInput = n;
|
||||
}
|
||||
|
||||
_hide () {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
async _saveChanges () {
|
||||
const {cookieJar} = this.state;
|
||||
await models.cookieJar.update(cookieJar);
|
||||
this._load(this.state.workspace);
|
||||
}
|
||||
_handleCookieUpdate = (oldCookie, cookie) => {
|
||||
|
||||
_handleCookieUpdate (oldCookie, cookie) {
|
||||
const {cookieJar} = this.state;
|
||||
const {cookies} = cookieJar;
|
||||
const index = cookies.findIndex(c => c.domain === oldCookie.domain && c.key === oldCookie.key);
|
||||
@ -36,17 +50,17 @@ class CookiesModal extends PureComponent {
|
||||
|
||||
this._saveChanges(cookieJar);
|
||||
trackEvent('Cookie', 'Update');
|
||||
};
|
||||
}
|
||||
|
||||
_handleCookieAdd = cookie => {
|
||||
_handleCookieAdd (cookie) {
|
||||
const {cookieJar} = this.state;
|
||||
const {cookies} = cookieJar;
|
||||
cookieJar.cookies = [cookie, ...cookies];
|
||||
this._saveChanges(cookieJar);
|
||||
trackEvent('Cookie', 'Create');
|
||||
};
|
||||
}
|
||||
|
||||
_handleCookieDelete = cookie => {
|
||||
_handleCookieDelete (cookie) {
|
||||
const {cookieJar} = this.state;
|
||||
const {cookies} = cookieJar;
|
||||
|
||||
@ -55,9 +69,9 @@ class CookiesModal extends PureComponent {
|
||||
|
||||
this._saveChanges(cookieJar);
|
||||
trackEvent('Cookie', 'Delete');
|
||||
};
|
||||
}
|
||||
|
||||
_handleFilterChange = e => {
|
||||
_handleFilterChange (e) {
|
||||
const filter = e.target.value;
|
||||
this.setState({filter});
|
||||
trackEvent('Cookie Editor', 'Filter Change');
|
||||
|
@ -1,21 +1,32 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
|
||||
import autobind from 'autobind-decorator';
|
||||
import EnvironmentEditor from '../editors/EnvironmentEditor';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
|
||||
|
||||
@autobind
|
||||
class EnvironmentEditModal extends PureComponent {
|
||||
state = {
|
||||
requestGroup: null,
|
||||
isValid: true
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
requestGroup: null,
|
||||
isValid: true
|
||||
};
|
||||
}
|
||||
|
||||
_hide = () => this.modal.hide();
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setEditorRef = n => this._envEditor = n;
|
||||
_hide () {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_setEditorRef (n) {
|
||||
this._envEditor = n;
|
||||
}
|
||||
|
||||
_saveChanges () {
|
||||
if (!this._envEditor.isValid()) {
|
||||
@ -28,7 +39,7 @@ class EnvironmentEditModal extends PureComponent {
|
||||
this.props.onChange(Object.assign({}, requestGroup, {environment}));
|
||||
}
|
||||
|
||||
_didChange = () => {
|
||||
_didChange () {
|
||||
this._saveChanges();
|
||||
|
||||
const isValid = this._envEditor.isValid();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import HTTPSnippet, {availableTargets} from 'httpsnippet';
|
||||
|
||||
import CopyButton from '../base/CopyButton';
|
||||
import {Dropdown, DropdownButton, DropdownItem} from '../base/dropdown';
|
||||
import Editor from '../codemirror/Editor';
|
||||
@ -26,7 +26,7 @@ const TO_ADD_CONTENT_LENGTH = {
|
||||
node: ['native']
|
||||
};
|
||||
|
||||
|
||||
@autobind
|
||||
class GenerateCodeModal extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
@ -53,18 +53,24 @@ class GenerateCodeModal extends PureComponent {
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setEditorRef = n => this._editor = n;
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
_setEditorRef (n) {
|
||||
this._editor = n;
|
||||
}
|
||||
|
||||
_hide = () => this.modal.hide();
|
||||
_hide () {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_handleClientChange = client => {
|
||||
_handleClientChange (client) {
|
||||
const {target, request} = this.state;
|
||||
this._generateCode(request, target, client);
|
||||
trackEvent('Generate Code', 'Client Change', `${target.title}/${client.title}`);
|
||||
};
|
||||
}
|
||||
|
||||
_handleTargetChange = target => {
|
||||
_handleTargetChange (target) {
|
||||
const {target: currentTarget} = this.state;
|
||||
if (currentTarget.key === target.key) {
|
||||
// No change
|
||||
@ -74,7 +80,7 @@ class GenerateCodeModal extends PureComponent {
|
||||
const client = target.clients.find(c => c.key === target.default);
|
||||
this._generateCode(this.state.request, target, client);
|
||||
trackEvent('Generate Code', 'Target Change', target.title);
|
||||
};
|
||||
}
|
||||
|
||||
async _generateCode (request, target, client) {
|
||||
// Some clients need a content-length for the request to succeed
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Link from '../base/Link';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
@ -7,20 +8,33 @@ import ModalFooter from '../base/ModalFooter';
|
||||
import * as session from '../../../sync/session';
|
||||
import * as sync from '../../../sync';
|
||||
|
||||
@autobind
|
||||
class LoginModal extends PureComponent {
|
||||
state = {
|
||||
step: 1,
|
||||
loading: false,
|
||||
error: '',
|
||||
title: '',
|
||||
message: '',
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
step: 1,
|
||||
loading: false,
|
||||
error: '',
|
||||
title: '',
|
||||
message: '',
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_setPasswordInputRef (n) {
|
||||
this._passwordInput = n;
|
||||
}
|
||||
|
||||
_setEmailInputRef (n) {
|
||||
return this._emailInput = n;
|
||||
};
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setEmailInputRef = n => this._emailInput = n;
|
||||
_hide = () => this.hide();
|
||||
|
||||
_handleLogin = async e => {
|
||||
async _handleLogin (e) {
|
||||
e.preventDefault();
|
||||
this.setState({error: '', loading: true});
|
||||
|
||||
@ -60,9 +74,7 @@ class LoginModal extends PureComponent {
|
||||
inner = [
|
||||
<ModalHeader key="header">{title || "Login to Your Account"}</ModalHeader>,
|
||||
<ModalBody key="body" className="pad">
|
||||
{message ? (
|
||||
<p className="notice info">{message}</p>
|
||||
) : null}
|
||||
{message ? <p className="notice info">{message}</p> : null}
|
||||
<div className="form-control form-control--outlined no-pad-top">
|
||||
<label>Email
|
||||
<input
|
||||
@ -78,7 +90,7 @@ class LoginModal extends PureComponent {
|
||||
<input type="password"
|
||||
required="required"
|
||||
placeholder="•••••••••••••••••"
|
||||
ref={n => this._passwordInput = n}/>
|
||||
ref={this._setPasswordInputRef}/>
|
||||
</label>
|
||||
</div>
|
||||
{error ? <div className="danger pad-top">** {error}</div> : null}
|
||||
@ -109,7 +121,7 @@ class LoginModal extends PureComponent {
|
||||
</p>
|
||||
</ModalBody>,
|
||||
<ModalFooter key="footer">
|
||||
<button type="button" className="btn" onClick={this._hide}>
|
||||
<button type="button" className="btn" onClick={this.hide}>
|
||||
Close
|
||||
</button>
|
||||
</ModalFooter>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import Link from '../base/Link';
|
||||
import Modal from '../base/Modal';
|
||||
@ -8,16 +9,22 @@ import {trackEvent} from '../../../analytics';
|
||||
import * as session from '../../../sync/session';
|
||||
import * as sync from '../../../sync/index';
|
||||
|
||||
|
||||
let hidePaymentNotificationUntilNextLaunch = false;
|
||||
|
||||
@autobind
|
||||
class PaymentNotificationModal extends PureComponent {
|
||||
_handleCancel = async () => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
async _handleCancel () {
|
||||
await sync.cancelTrial();
|
||||
this.hide();
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
show () {
|
||||
// Don't trigger automatically if user has dismissed it already
|
||||
|
@ -1,27 +1,35 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
|
||||
@autobind
|
||||
class PromptModal extends PureComponent {
|
||||
state = {
|
||||
headerName: 'Not Set',
|
||||
defaultValue: '',
|
||||
submitName: 'Not Set',
|
||||
selectText: false,
|
||||
hint: null,
|
||||
inputType: 'text'
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
this.state = {
|
||||
headerName: 'Not Set',
|
||||
defaultValue: '',
|
||||
submitName: 'Not Set',
|
||||
selectText: false,
|
||||
hint: null,
|
||||
inputType: 'text'
|
||||
};
|
||||
}
|
||||
|
||||
_handleSubmit = e => {
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_handleSubmit (e) {
|
||||
e.preventDefault();
|
||||
|
||||
this._onSubmitCallback && this._onSubmitCallback(this._input.value);
|
||||
this.modal.hide();
|
||||
};
|
||||
}
|
||||
|
||||
show ({headerName, defaultValue, submitName, selectText, hint, inputType, placeholder, label}) {
|
||||
this.modal.show();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import ContentTypeDropdown from '../dropdowns/ContentTypeDropdown';
|
||||
import MethodDropdown from '../dropdowns/MethodDropdown';
|
||||
import Modal from '../base/Modal';
|
||||
@ -9,17 +10,27 @@ import {getContentTypeName, METHOD_GET, METHOD_HEAD, METHOD_OPTIONS, METHOD_DELE
|
||||
import * as models from '../../../models/index';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class RequestCreateModal extends PureComponent {
|
||||
state = {
|
||||
selectedContentType: null,
|
||||
selectedMethod: METHOD_GET,
|
||||
parentId: null,
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_setInputRef = n => this._input = n;
|
||||
this.state = {
|
||||
selectedContentType: null,
|
||||
selectedMethod: METHOD_GET,
|
||||
parentId: null,
|
||||
};
|
||||
}
|
||||
|
||||
_handleSubmit = async e => {
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_setInputRef (n) {
|
||||
this._input = n;
|
||||
}
|
||||
|
||||
async _handleSubmit (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {parentId, selectedContentType, selectedMethod} = this.state;
|
||||
@ -38,17 +49,17 @@ class RequestCreateModal extends PureComponent {
|
||||
this._onSubmitCallback(finalRequest);
|
||||
|
||||
this.hide();
|
||||
};
|
||||
}
|
||||
|
||||
_handleChangeSelectedContentType = selectedContentType => {
|
||||
_handleChangeSelectedContentType (selectedContentType) {
|
||||
this.setState({selectedContentType});
|
||||
trackEvent('Request Create', 'Content Type Change', selectedContentType);
|
||||
};
|
||||
}
|
||||
|
||||
_handleChangeSelectedMethod = selectedMethod => {
|
||||
_handleChangeSelectedMethod (selectedMethod) {
|
||||
this.setState({selectedMethod});
|
||||
trackEvent('Request Create', 'Method Change', selectedMethod);
|
||||
};
|
||||
}
|
||||
|
||||
_shouldNotHaveBody () {
|
||||
const {selectedMethod} = this.state;
|
||||
@ -107,19 +118,19 @@ class RequestCreateModal extends PureComponent {
|
||||
/>
|
||||
</div>
|
||||
{!this._shouldNotHaveBody() ? (
|
||||
<div className="form-control" style={{width: 'auto'}}>
|
||||
<label htmlFor="nothing">
|
||||
<ContentTypeDropdown className="btn btn--clicky no-wrap"
|
||||
right
|
||||
contentType={selectedContentType}
|
||||
onChange={this._handleChangeSelectedContentType}>
|
||||
{getContentTypeName(selectedContentType)}
|
||||
{" "}
|
||||
<i className="fa fa-caret-down"></i>
|
||||
</ContentTypeDropdown>
|
||||
</label>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="form-control" style={{width: 'auto'}}>
|
||||
<label htmlFor="nothing">
|
||||
<ContentTypeDropdown className="btn btn--clicky no-wrap"
|
||||
right
|
||||
contentType={selectedContentType}
|
||||
onChange={this._handleChangeSelectedContentType}>
|
||||
{getContentTypeName(selectedContentType)}
|
||||
{" "}
|
||||
<i className="fa fa-caret-down"></i>
|
||||
</ContentTypeDropdown>
|
||||
</label>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</ModalBody>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import ReactDOM from 'react-dom';
|
||||
import classnames from 'classnames';
|
||||
import Button from '../base/Button';
|
||||
@ -8,20 +9,29 @@ import ModalBody from '../base/ModalBody';
|
||||
import MethodTag from '../tags/MethodTag';
|
||||
import * as models from '../../../models';
|
||||
|
||||
|
||||
@autobind
|
||||
class RequestSwitcherModal extends PureComponent {
|
||||
state = {
|
||||
searchString: '',
|
||||
requestGroups: [],
|
||||
requests: [],
|
||||
workspaces: [],
|
||||
matchedRequests: [],
|
||||
matchedWorkspaces: [],
|
||||
activeIndex: -1
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_focusRef = n => n && n.focus();
|
||||
this.state = {
|
||||
searchString: '',
|
||||
requestGroups: [],
|
||||
requests: [],
|
||||
workspaces: [],
|
||||
matchedRequests: [],
|
||||
matchedWorkspaces: [],
|
||||
activeIndex: -1
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_focusRef (n) {
|
||||
n && n.focus();
|
||||
}
|
||||
|
||||
_setActiveIndex (activeIndex) {
|
||||
const maxIndex = this.state.matchedRequests.length + this.state.matchedWorkspaces.length;
|
||||
@ -34,7 +44,7 @@ class RequestSwitcherModal extends PureComponent {
|
||||
this.setState({activeIndex});
|
||||
}
|
||||
|
||||
_activateCurrentIndex = () => {
|
||||
_activateCurrentIndex () {
|
||||
const {
|
||||
activeIndex,
|
||||
matchedRequests,
|
||||
@ -54,7 +64,7 @@ class RequestSwitcherModal extends PureComponent {
|
||||
// Create request if no match
|
||||
this._createRequestFromSearch();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async _createRequestFromSearch () {
|
||||
const {activeRequestParentId} = this.props;
|
||||
@ -70,27 +80,29 @@ class RequestSwitcherModal extends PureComponent {
|
||||
this._activateRequest(request);
|
||||
}
|
||||
|
||||
_activateWorkspace = workspace => {
|
||||
_activateWorkspace (workspace) {
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.handleSetActiveWorkspace(workspace._id);
|
||||
this.modal.hide();
|
||||
};
|
||||
}
|
||||
|
||||
_activateRequest = request => {
|
||||
_activateRequest (request) {
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.activateRequest(request._id);
|
||||
this.modal.hide();
|
||||
};
|
||||
}
|
||||
|
||||
_handleChange = e => this._handleChangeValue(e.target.value);
|
||||
_handleChange (e) {
|
||||
this._handleChangeValue(e.target.value);
|
||||
}
|
||||
|
||||
_handleChangeValue = async searchString => {
|
||||
async _handleChangeValue (searchString) {
|
||||
const {workspaceChildren, workspaces} = this.props;
|
||||
const {workspaceId, activeRequestParentId} = this.props;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {shell} from 'electron';
|
||||
import Modal from '../base/Modal';
|
||||
import Button from '../base/Button';
|
||||
@ -17,44 +18,53 @@ import * as session from '../../../sync/session';
|
||||
|
||||
export const TAB_INDEX_EXPORT = 1;
|
||||
|
||||
@autobind
|
||||
class SettingsModal extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
this._currentTabIndex = -1;
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
_trackTab = name => trackEvent('Setting', `Tab ${name}`);
|
||||
_handleTabSelect = currentTabIndex => this.setState({currentTabIndex});
|
||||
_handleUpdateSetting = (key, value) => {
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_trackTab (name){
|
||||
trackEvent('Setting', `Tab ${name}`);
|
||||
}
|
||||
|
||||
_handleTabSelect (currentTabIndex) {
|
||||
this.setState({currentTabIndex});
|
||||
}
|
||||
_handleUpdateSetting (key, value) {
|
||||
models.settings.update(this.props.settings, {[key]: value});
|
||||
trackEvent('Setting', 'Change', key)
|
||||
};
|
||||
}
|
||||
|
||||
_handleExportAllToFile = () => {
|
||||
_handleExportAllToFile () {
|
||||
this.props.handleExportAllToFile();
|
||||
this.modal.hide()
|
||||
};
|
||||
}
|
||||
|
||||
_handleExportWorkspace = () => {
|
||||
_handleExportWorkspace () {
|
||||
this.props.handleExportWorkspaceToFile();
|
||||
this.modal.hide()
|
||||
};
|
||||
}
|
||||
|
||||
_handleImport = () => {
|
||||
_handleImport () {
|
||||
this.props.handleImportFile();
|
||||
this.modal.hide()
|
||||
};
|
||||
}
|
||||
|
||||
_handleChangeTheme = (theme, persist = true) => {
|
||||
_handleChangeTheme (theme, persist = true) {
|
||||
document.body.setAttribute('theme', theme);
|
||||
|
||||
if (persist) {
|
||||
trackEvent('Setting', 'Change Theme', theme);
|
||||
models.settings.update(this.props.settings, {theme});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
// Hacky way to set theme on launch
|
||||
@ -72,6 +82,7 @@ class SettingsModal extends PureComponent {
|
||||
}
|
||||
|
||||
toggle (currentTabIndex = 0) {
|
||||
console.log('THIS', this);
|
||||
this.setState({currentTabIndex});
|
||||
this.modal.toggle();
|
||||
}
|
||||
|
110
app/ui/components/modals/SetupSyncModal.js
Normal file
110
app/ui/components/modals/SetupSyncModal.js
Normal file
@ -0,0 +1,110 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
import * as sync from '../../../sync';
|
||||
import {SYNC_MODE_OFF, SYNC_MODE_ON, SYNC_MODE_NEVER, SYNC_MODE_UNSET} from '../../../sync/storage';
|
||||
|
||||
@autobind
|
||||
class SetupSyncModal extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
syncMode: SYNC_MODE_ON,
|
||||
};
|
||||
}
|
||||
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
async _handleDone () {
|
||||
const {workspace} = this.props;
|
||||
const {syncMode} = this.state;
|
||||
|
||||
const resource = await sync.getOrCreateResourceForDoc(workspace);
|
||||
await sync.createOrUpdateConfig(resource.resourceGroupId, syncMode);
|
||||
|
||||
this.hide();
|
||||
|
||||
this._resolvePromise && this._resolvePromise(syncMode);
|
||||
}
|
||||
|
||||
_handleSyncModeChange (e) {
|
||||
this.setState({syncMode: e.target.value});
|
||||
};
|
||||
|
||||
show () {
|
||||
(async () => {
|
||||
const {workspace} = this.props;
|
||||
|
||||
const resource = await sync.getOrCreateResourceForDoc(workspace);
|
||||
const config = await sync.getOrCreateConfig(resource.resourceGroupId);
|
||||
|
||||
console.log('CONFIG', config);
|
||||
this.setState({syncMode: config.syncMode});
|
||||
})();
|
||||
|
||||
this.modal.show();
|
||||
|
||||
this._promise = new Promise(resolve => this._resolvePromise = resolve);
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
hide () {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
render () {
|
||||
const {workspace} = this.props;
|
||||
const {syncMode} = this.state;
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef} noEscape>
|
||||
<ModalHeader>Workspace Sync Setup</ModalHeader>
|
||||
<ModalBody className="wide pad">
|
||||
|
||||
{syncMode === SYNC_MODE_UNSET ?
|
||||
<p className="notice info">
|
||||
You have not yet configured sync for your <strong>{workspace.name}</strong> workspace.
|
||||
</p> : null
|
||||
}
|
||||
|
||||
<br/>
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>Choose sync mode
|
||||
<select onChange={this._handleSyncModeChange} value={syncMode}>
|
||||
<option value={SYNC_MODE_ON}>
|
||||
Automatically sync changes
|
||||
</option>
|
||||
<option value={SYNC_MODE_OFF}>
|
||||
Manually sync changes
|
||||
</option>
|
||||
<option value={SYNC_MODE_NEVER}>
|
||||
Disable sync for this workspace
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<br/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<div className="margin-left faint italic txt-sm tall">
|
||||
* This can be changed at any time
|
||||
</div>
|
||||
<button className="btn" onClick={this._handleDone}>
|
||||
Continue
|
||||
</button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SetupSyncModal.propTypes = {
|
||||
workspace: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default SetupSyncModal;
|
@ -1,107 +0,0 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import classnames from 'classnames';
|
||||
import CopyButton from '../base/CopyButton';
|
||||
import Modal from '../base/Modal';
|
||||
import ModalBody from '../base/ModalBody';
|
||||
import ModalHeader from '../base/ModalHeader';
|
||||
import ModalFooter from '../base/ModalFooter';
|
||||
import * as sync from '../../../sync';
|
||||
|
||||
class SyncLogsModal extends PureComponent {
|
||||
state = {
|
||||
logs: []
|
||||
};
|
||||
|
||||
_setModalRef = n => this.modal = n;
|
||||
|
||||
show () {
|
||||
clearInterval(this._interval);
|
||||
this._interval = setInterval(() => this._updateModal(), 2000);
|
||||
this._updateModal();
|
||||
this.modal.show();
|
||||
}
|
||||
|
||||
hide () {
|
||||
clearInterval(this._interval);
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_updateModal () {
|
||||
this.setState({logs: sync.logger.tail()})
|
||||
}
|
||||
|
||||
_getColorClass (level) {
|
||||
return {
|
||||
debug: 'info',
|
||||
warn: 'warning',
|
||||
error: 'danger'
|
||||
}[level] || '';
|
||||
}
|
||||
|
||||
_formatLogs () {
|
||||
const {logs: allLogs} = this.state;
|
||||
const logs = allLogs.slice(allLogs.length - 1000);
|
||||
|
||||
function pad (n, length) {
|
||||
let s = n + '';
|
||||
while (s.length < length) {
|
||||
s = '0' + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
let i = 0;
|
||||
for (const entry of logs) {
|
||||
const colorClass = this._getColorClass(entry.type);
|
||||
const dateString =
|
||||
pad(entry.date.getFullYear(), 4) + '/' +
|
||||
pad(entry.date.getMonth() + 1, 2) + '/' +
|
||||
pad(entry.date.getDate(), 2) + ' ' +
|
||||
pad(entry.date.getHours(), 2) + ':' +
|
||||
pad(entry.date.getMinutes(), 2) + ':' +
|
||||
pad(entry.date.getSeconds(), 2);
|
||||
|
||||
rows.push({
|
||||
jsx: (
|
||||
<pre key={i++}>
|
||||
<span className="faint">
|
||||
{dateString}
|
||||
</span>
|
||||
{" "}
|
||||
<span style={{minWidth: '4rem'}}
|
||||
className={classnames(colorClass, 'inline-block')}>
|
||||
[{entry.type}]
|
||||
</span>
|
||||
{" "}
|
||||
{entry.message}
|
||||
</pre>
|
||||
),
|
||||
text: `${dateString} [${entry.type}] ${entry.message}`
|
||||
})
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
render () {
|
||||
const rows = this._formatLogs();
|
||||
return (
|
||||
<Modal ref={this._setModalRef} tall>
|
||||
<ModalHeader>Sync Debug Logs</ModalHeader>
|
||||
<ModalBody className="pad selectable txt-sm monospace">
|
||||
{rows.map(row => row.jsx)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<CopyButton className="btn" content={rows.map(r => r.text).join('\n')}>
|
||||
Copy To Clipboard
|
||||
</CopyButton>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SyncLogsModal.propTypes = {};
|
||||
|
||||
export default SyncLogsModal;
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import {Dropdown, DropdownButton, DropdownItem} from '../base/dropdown';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
@ -13,19 +14,31 @@ import ModalFooter from '../base/ModalFooter';
|
||||
import * as models from '../../../models';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
state = {
|
||||
workspace: null,
|
||||
isValid: true,
|
||||
subEnvironments: [],
|
||||
rootEnvironment: null,
|
||||
activeEnvironmentId: null,
|
||||
forceRefreshKey: 0,
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
workspace: null,
|
||||
isValid: true,
|
||||
subEnvironments: [],
|
||||
rootEnvironment: null,
|
||||
activeEnvironmentId: null,
|
||||
forceRefreshKey: 0,
|
||||
};
|
||||
}
|
||||
|
||||
_hide = () => this.modal.hide();
|
||||
_setEditorRef = n => this._envEditor = n;
|
||||
_setModalRef = n => this.modal = n;
|
||||
_hide () {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_setEditorRef (n) {
|
||||
this._envEditor = n;
|
||||
}
|
||||
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
async show (workspace) {
|
||||
this.modal.show();
|
||||
@ -64,7 +77,7 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
_handleAddEnvironment = async (isPrivate = false) => {
|
||||
async _handleAddEnvironment (isPrivate = false) {
|
||||
const {rootEnvironment, workspace} = this.state;
|
||||
const parentId = rootEnvironment._id;
|
||||
const environment = await models.environment.create({parentId, isPrivate});
|
||||
@ -74,9 +87,9 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
'Environment',
|
||||
isPrivate ? 'Create' : 'Create Private'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
_handleShowEnvironment = async environment => {
|
||||
async _handleShowEnvironment (environment) {
|
||||
// Don't allow switching if the current one has errors
|
||||
if (!this._envEditor.isValid()) {
|
||||
return;
|
||||
@ -89,9 +102,9 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
const {workspace} = this.state;
|
||||
await this._load(workspace, environment);
|
||||
trackEvent('Environment Editor', 'Show Environment');
|
||||
};
|
||||
}
|
||||
|
||||
_handleDeleteEnvironment = async () => {
|
||||
async _handleDeleteEnvironment () {
|
||||
const {rootEnvironment, workspace} = this.state;
|
||||
const environment = this._getActiveEnvironment();
|
||||
|
||||
@ -105,9 +118,9 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
|
||||
await this._load(workspace, rootEnvironment);
|
||||
trackEvent('Environment', 'Delete');
|
||||
};
|
||||
}
|
||||
|
||||
_handleChangeEnvironmentName = async (environment, name) => {
|
||||
async _handleChangeEnvironmentName (environment, name) {
|
||||
const {workspace} = this.state;
|
||||
|
||||
// NOTE: Fetch the environment first because it might not be up to date.
|
||||
@ -119,7 +132,7 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
trackEvent('Environment', 'Rename');
|
||||
};
|
||||
|
||||
_didChange = () => {
|
||||
_didChange () {
|
||||
const isValid = this._envEditor.isValid();
|
||||
|
||||
if (this.state.isValid === isValid) {
|
||||
@ -127,7 +140,7 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
}
|
||||
|
||||
this._saveChanges();
|
||||
};
|
||||
}
|
||||
|
||||
_getActiveEnvironment () {
|
||||
const {activeEnvironmentId, subEnvironments, rootEnvironment} = this.state;
|
||||
@ -178,8 +191,7 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
|
||||
<DropdownItem onClick={this._handleAddEnvironment} value={false}>
|
||||
<i className="fa fa-eye"/> Environment
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={this._handleAddEnvironment}
|
||||
value
|
||||
<DropdownItem onClick={this._handleAddEnvironment} value={true}
|
||||
title="Environment will not be exported or synced">
|
||||
<i className="fa fa-eye-slash"/> Private Environment
|
||||
</DropdownItem>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
import DebouncedInput from '../base/DebouncedInput';
|
||||
import FileInputButton from '../base/FileInputButton';
|
||||
@ -10,38 +11,60 @@ import * as models from '../../../models/index';
|
||||
import * as fs from 'fs';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
|
||||
@autobind
|
||||
class WorkspaceSettingsModal extends PureComponent {
|
||||
state = {
|
||||
showAddCertificateForm: false,
|
||||
crtPath: '',
|
||||
keyPath: '',
|
||||
pfxPath: '',
|
||||
host: '',
|
||||
passphrase: '',
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
_workspaceUpdate = patch => models.workspace.update(this.props.workspace, patch);
|
||||
this.state = {
|
||||
showAddCertificateForm: false,
|
||||
crtPath: '',
|
||||
keyPath: '',
|
||||
pfxPath: '',
|
||||
host: '',
|
||||
passphrase: '',
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetModalRef = n => this.modal = n;
|
||||
_handleRemoveWorkspace = () => {
|
||||
_workspaceUpdate (patch) {
|
||||
models.workspace.update(this.props.workspace, patch);
|
||||
}
|
||||
|
||||
_handleSetModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
_handleRemoveWorkspace () {
|
||||
this.props.handleRemoveWorkspace();
|
||||
this.hide();
|
||||
};
|
||||
}
|
||||
|
||||
_handleToggleCertificateForm = () => {
|
||||
_handleToggleCertificateForm () {
|
||||
this.setState({showAddCertificateForm: !this.state.showAddCertificateForm})
|
||||
};
|
||||
}
|
||||
|
||||
_handleRename = name => this._workspaceUpdate({name});
|
||||
_handleDescriptionChange = description => this._workspaceUpdate({description});
|
||||
_handleRename (name) {
|
||||
this._workspaceUpdate({name});
|
||||
}
|
||||
_handleDescriptionChange (description){
|
||||
this._workspaceUpdate({description});
|
||||
}
|
||||
|
||||
_handleCreateHostChange = e => this.setState({host: e.target.value});
|
||||
_handleCreatePfxChange = pfxPath => this.setState({pfxPath});
|
||||
_handleCreateCrtChange = crtPath => this.setState({crtPath});
|
||||
_handleCreateKeyChange = keyPath => this.setState({keyPath});
|
||||
_handleCreatePassphraseChange = e => this.setState({passphrase: e.target.value});
|
||||
_handleSubmitCertificate = async e => {
|
||||
_handleCreateHostChange (e) {
|
||||
this.setState({host: e.target.value});
|
||||
}
|
||||
_handleCreatePfxChange (pfxPath) {
|
||||
this.setState({pfxPath});
|
||||
}
|
||||
_handleCreateCrtChange (crtPath){
|
||||
this.setState({crtPath});
|
||||
}
|
||||
_handleCreateKeyChange (keyPath) {
|
||||
this.setState({keyPath});
|
||||
}
|
||||
_handleCreatePassphraseChange (e) {
|
||||
this.setState({passphrase: e.target.value});
|
||||
}
|
||||
async _handleSubmitCertificate (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {workspace} = this.props;
|
||||
@ -59,23 +82,23 @@ class WorkspaceSettingsModal extends PureComponent {
|
||||
await models.workspace.update(workspace, {certificates});
|
||||
this._handleToggleCertificateForm();
|
||||
trackEvent('Certificates', 'Create');
|
||||
};
|
||||
}
|
||||
|
||||
_handleDeleteCertificate = certificate => {
|
||||
_handleDeleteCertificate (certificate) {
|
||||
const {workspace} = this.props;
|
||||
const certificates = workspace.certificates.filter(c => c.host !== certificate.host);
|
||||
models.workspace.update(workspace, {certificates});
|
||||
trackEvent('Certificates', 'Delete');
|
||||
};
|
||||
}
|
||||
|
||||
_handleToggleCertificate = certificate => {
|
||||
_handleToggleCertificate (certificate) {
|
||||
const {workspace} = this.props;
|
||||
const certificates = workspace.certificates.map(
|
||||
c => c === certificate ? Object.assign({}, c, {disabled: !c.disabled}) : c
|
||||
);
|
||||
models.workspace.update(workspace, {certificates});
|
||||
trackEvent('Certificates', 'Toggle');
|
||||
};
|
||||
}
|
||||
|
||||
toggle (workspace) {
|
||||
this.modal.toggle();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider} from '../base/dropdown';
|
||||
import Link from '../base/Link';
|
||||
import Modal from '../base/Modal';
|
||||
@ -12,14 +13,24 @@ import PromptModal from './PromptModal';
|
||||
import PromptButton from '../base/PromptButton';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
@autobind
|
||||
class WorkspaceShareSettingsModal extends PureComponent {
|
||||
state = {};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
_handleSubmit = e => e.preventDefault();
|
||||
_handleClose = () => this.hide();
|
||||
_setModalRef = n => this.modal = n;
|
||||
_handleSubmit (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
_handleClose () {
|
||||
this.hide();
|
||||
}
|
||||
_setModalRef (n) {
|
||||
this.modal = n;
|
||||
}
|
||||
|
||||
_handleUnshare = async () => {
|
||||
async _handleUnshare () {
|
||||
if (!session.isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
@ -35,9 +46,9 @@ class WorkspaceShareSettingsModal extends PureComponent {
|
||||
console.warn('Failed to unshare workspace', err);
|
||||
this._resetState({error: err.message, loading: false});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleShareWithTeam = async team => {
|
||||
async _handleShareWithTeam (team) {
|
||||
const passphrase = await showModal(PromptModal, {
|
||||
headerName: 'Share Workspace',
|
||||
label: 'Confirm password to share workspace',
|
||||
|
@ -1,7 +1,13 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
|
||||
@autobind
|
||||
class SettingsGeneral extends PureComponent {
|
||||
_handleUpdateSetting = e => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleUpdateSetting (e) {
|
||||
let value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
|
||||
|
||||
if (e.target.type === 'number') {
|
||||
@ -9,7 +15,7 @@ class SettingsGeneral extends PureComponent {
|
||||
}
|
||||
|
||||
this.props.updateSetting(e.target.name, value);
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {settings} = this.props;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Button from '../base/Button';
|
||||
import Link from '../base/Link';
|
||||
|
||||
@ -26,10 +27,14 @@ const THEMES = [
|
||||
{key: 'railscasts', name: 'Railscasts', img: imgRailscasts, paid: true},
|
||||
];
|
||||
|
||||
@autobind
|
||||
class SettingsTheme extends PureComponent {
|
||||
state = {
|
||||
isPremium: localStorage.getItem('settings.theme.isPremium') || false,
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isPremium: localStorage.getItem('settings.theme.isPremium') || false,
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount () {
|
||||
// NOTE: This is kind of sketchy because we're relying on our parent (tab view)
|
||||
@ -48,7 +53,7 @@ class SettingsTheme extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
renderTheme = theme => {
|
||||
renderTheme (theme) {
|
||||
const {handleChangeTheme, activeTheme} = this.props;
|
||||
const {isPremium} = this.state;
|
||||
const isActive = activeTheme === theme.key;
|
||||
@ -72,7 +77,7 @@ class SettingsTheme extends PureComponent {
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
renderThemeRows (themes) {
|
||||
const rows = [];
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import EnvironmentsDropdown from '../dropdowns/EnvironmentsDropdown';
|
||||
import SidebarFilter from './SidebarFilter';
|
||||
@ -7,22 +8,25 @@ import SyncButton from '../dropdowns/SyncDropdown';
|
||||
import WorkspaceDropdown from '../dropdowns/WorkspaceDropdown';
|
||||
import {SIDEBAR_SKINNY_REMS, COLLAPSE_SIDEBAR_REMS} from '../../../common/constants';
|
||||
|
||||
|
||||
@autobind
|
||||
class Sidebar extends PureComponent {
|
||||
_handleChangeEnvironment = id => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
_handleChangeEnvironment (id) {
|
||||
const {handleSetActiveEnvironment} = this.props;
|
||||
handleSetActiveEnvironment(id);
|
||||
};
|
||||
}
|
||||
|
||||
_handleCreateRequestInWorkspace = () => {
|
||||
_handleCreateRequestInWorkspace () {
|
||||
const {workspace, handleCreateRequest} = this.props;
|
||||
handleCreateRequest(workspace._id);
|
||||
};
|
||||
}
|
||||
|
||||
_handleCreateRequestGroupInWorkspace = () => {
|
||||
_handleCreateRequestGroupInWorkspace () {
|
||||
const {workspace, handleCreateRequestGroup} = this.props;
|
||||
handleCreateRequestGroup(workspace._id);
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -1,11 +1,16 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownHint, DropdownButton, DropdownItem} from '../base/dropdown';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
|
||||
@autobind
|
||||
class SidebarFilter extends PureComponent {
|
||||
_handleOnChange = (e) => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_handleOnChange (e) {
|
||||
const value = e.target.value;
|
||||
|
||||
clearTimeout(this._triggerTimeout);
|
||||
@ -18,17 +23,17 @@ class SidebarFilter extends PureComponent {
|
||||
this._analyticsTimeout = setTimeout(() => {
|
||||
trackEvent('Sidebar', 'Filter', value ? 'Change' : 'Clear');
|
||||
}, 2000);
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestGroupCreate = () => {
|
||||
_handleRequestGroupCreate () {
|
||||
this.props.requestGroupCreate();
|
||||
trackEvent('Folder', 'Create', 'Sidebar Filter');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestCreate = () => {
|
||||
_handleRequestCreate () {
|
||||
this.props.requestCreate();
|
||||
trackEvent('Request', 'Create', 'Sidebar Filter');
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
|
@ -1,28 +1,36 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {DragSource, DropTarget} from 'react-dnd';
|
||||
import classnames from 'classnames';
|
||||
import RequestGroupActionsDropdown from '../dropdowns/RequestGroupActionsDropdown';
|
||||
import SidebarRequestRow from './SidebarRequestRow';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
import * as misc from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class SidebarRequestGroupRow extends PureComponent {
|
||||
state = {dragDirection: 0};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
dragDirection: 0
|
||||
};
|
||||
}
|
||||
|
||||
_setRequestGroupActionsDropdownRef = n => this._requestGroupActionsDropdown = n;
|
||||
_setRequestGroupActionsDropdownRef (n) {
|
||||
this._requestGroupActionsDropdown = n;
|
||||
}
|
||||
|
||||
_handleCollapse = () => {
|
||||
_handleCollapse () {
|
||||
const {requestGroup, handleSetRequestGroupCollapsed, isCollapsed} = this.props;
|
||||
handleSetRequestGroupCollapsed(requestGroup._id, !isCollapsed);
|
||||
trackEvent('Folder', 'Toggle Visible', !isCollapsed ? 'Close' : 'Open')
|
||||
};
|
||||
}
|
||||
|
||||
_handleShowActions = e => {
|
||||
_handleShowActions (e) {
|
||||
e.preventDefault();
|
||||
this._requestGroupActionsDropdown.show();
|
||||
};
|
||||
|
||||
_nullFunction = () => null;
|
||||
}
|
||||
|
||||
setDragDirection (dragDirection) {
|
||||
if (dragDirection !== this.state.dragDirection) {
|
||||
@ -93,9 +101,9 @@ class SidebarRequestGroupRow extends PureComponent {
|
||||
<ul className={classnames('sidebar__list', {'sidebar__list--collapsed': isCollapsed})}>
|
||||
{children.length > 0 ? children : (
|
||||
<SidebarRequestRow
|
||||
handleActivateRequest={this._nullFunction}
|
||||
handleDuplicateRequest={this._nullFunction}
|
||||
handleGenerateCode={this._nullFunction}
|
||||
handleActivateRequest={misc.nullFn}
|
||||
handleDuplicateRequest={misc.nullFn}
|
||||
handleGenerateCode={misc.nullFn}
|
||||
moveRequest={moveRequest}
|
||||
isActive={false}
|
||||
request={null}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {DragSource, DropTarget} from 'react-dnd';
|
||||
import classnames from 'classnames';
|
||||
@ -9,36 +10,42 @@ import * as models from '../../../models';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
|
||||
@autobind
|
||||
class SidebarRequestRow extends PureComponent {
|
||||
state = {
|
||||
dragDirection: 0,
|
||||
isEditing: false,
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
dragDirection: 0,
|
||||
isEditing: false,
|
||||
};
|
||||
}
|
||||
|
||||
_setRequestActionsDropdownRef = n => this._requestActionsDropdown = n;
|
||||
_setRequestActionsDropdownRef (n) {
|
||||
this._requestActionsDropdown = n;
|
||||
}
|
||||
|
||||
_handleShowRequestActions = e => {
|
||||
_handleShowRequestActions (e) {
|
||||
e.preventDefault();
|
||||
this._requestActionsDropdown.show();
|
||||
};
|
||||
}
|
||||
|
||||
_handleEditStart = () => {
|
||||
_handleEditStart () {
|
||||
trackEvent('Request', 'Rename', 'In Place');
|
||||
this.setState({isEditing: true});
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestUpdateName = name => {
|
||||
_handleRequestUpdateName (name) {
|
||||
models.request.update(this.props.request, {name})
|
||||
this.setState({isEditing: false});
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestCreateFromEmpty = () => {
|
||||
_handleRequestCreateFromEmpty () {
|
||||
const parentId = this.props.requestGroup._id;
|
||||
this.props.requestCreate(parentId);
|
||||
trackEvent('Request', 'Create', 'Empty Folder');
|
||||
};
|
||||
}
|
||||
|
||||
_handleRequestActivate = () => {
|
||||
_handleRequestActivate () {
|
||||
const {isActive, request, handleActivateRequest} = this.props;
|
||||
|
||||
if (isActive) {
|
||||
@ -47,7 +54,7 @@ class SidebarRequestRow extends PureComponent {
|
||||
|
||||
handleActivateRequest(request._id);
|
||||
trackEvent('Request', 'Activate', 'Sidebar');
|
||||
};
|
||||
}
|
||||
|
||||
setDragDirection (dragDirection) {
|
||||
if (dragDirection !== this.state.dragDirection) {
|
||||
|
@ -1,9 +1,15 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {debounce} from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class ResponseRaw extends PureComponent {
|
||||
// Use a timeout so it doesn't block the UI
|
||||
_update = debounce(value => this._setTextAreaValue(value));
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
// Use a timeout so it doesn't block the UI
|
||||
this._update = debounce(this._setTextAreaValue);
|
||||
}
|
||||
|
||||
_setTextAreaValue (value) {
|
||||
// Bail if we're not mounted
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {shell} from 'electron';
|
||||
import Editor from '../codemirror/Editor';
|
||||
import ResponseWebView from './ResponseWebview';
|
||||
@ -8,23 +9,27 @@ import {LARGE_RESPONSE_MB, PREVIEW_MODE_FRIENDLY, PREVIEW_MODE_SOURCE} from '../
|
||||
|
||||
let alwaysShowLargeResponses = false;
|
||||
|
||||
@autobind
|
||||
class ResponseViewer extends PureComponent {
|
||||
state = {
|
||||
blockingBecauseTooLarge: false
|
||||
};
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
blockingBecauseTooLarge: false
|
||||
};
|
||||
}
|
||||
|
||||
_handleOpenLink = link => {
|
||||
_handleOpenLink (link) {
|
||||
shell.openExternal(link);
|
||||
};
|
||||
}
|
||||
|
||||
_handleDismissBlocker = () => {
|
||||
_handleDismissBlocker () {
|
||||
this.setState({blockingBecauseTooLarge: false});
|
||||
};
|
||||
|
||||
_handleDisableBlocker = () => {
|
||||
_handleDisableBlocker () {
|
||||
alwaysShowLargeResponses = true;
|
||||
this._handleDismissBlocker();
|
||||
};
|
||||
}
|
||||
|
||||
_checkResponseBlocker (props) {
|
||||
if (alwaysShowLargeResponses) {
|
||||
|
@ -1,16 +1,21 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import contextMenu from 'electron-context-menu';
|
||||
|
||||
@autobind
|
||||
class ResponseWebview extends PureComponent {
|
||||
_handleSetWebviewRef = n => {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
_handleSetWebviewRef (n) {
|
||||
this._webview = n;
|
||||
contextMenu({window: this._webview});
|
||||
};
|
||||
}
|
||||
|
||||
_handleDOMReady = () => {
|
||||
_handleDOMReady () {
|
||||
this._webview.removeEventListener('dom-ready', this._handleDOMReady);
|
||||
this._setBody();
|
||||
};
|
||||
}
|
||||
|
||||
_setBody () {
|
||||
const {body, contentType, url} = this.props;
|
||||
|
@ -1,12 +1,11 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import fs from 'fs';
|
||||
import {ipcRenderer} from 'electron';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {DragDropContext} from 'react-dnd';
|
||||
import {toggleModal, showModal} from '../components/modals';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import Wrapper from '../components/Wrapper';
|
||||
import WorkspaceEnvironmentsEditModal from '../components/modals/WorkspaceEnvironmentsEditModal';
|
||||
import Toast from '../components/Toast';
|
||||
@ -39,9 +38,11 @@ const KEY_L = 76;
|
||||
const KEY_N = 78;
|
||||
const KEY_P = 80;
|
||||
|
||||
@autobind
|
||||
class App extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
draggingSidebar: false,
|
||||
draggingPane: false,
|
||||
@ -51,6 +52,9 @@ class App extends PureComponent {
|
||||
|
||||
this._getRenderContextCache = {};
|
||||
|
||||
this._savePaneWidth = debounce(paneWidth => this._updateActiveWorkspaceMeta({paneWidth}));
|
||||
this._saveSidebarWidth = debounce(sidebarWidth => this._updateActiveWorkspaceMeta({sidebarWidth}));
|
||||
|
||||
this._globalKeyMap = [
|
||||
{ // Show Workspace Settings
|
||||
meta: true,
|
||||
@ -130,11 +134,19 @@ class App extends PureComponent {
|
||||
];
|
||||
}
|
||||
|
||||
_setRequestPaneRef = n => this._requestPane = n;
|
||||
_setResponsePaneRef = n => this._responsePane = n;
|
||||
_setSidebarRef = n => this._sidebar = n;
|
||||
_setRequestPaneRef (n) {
|
||||
this._requestPane = n;
|
||||
}
|
||||
|
||||
_requestGroupCreate = async (parentId) => {
|
||||
_setResponsePaneRef (n) {
|
||||
this._responsePane = n;
|
||||
}
|
||||
|
||||
_setSidebarRef (n) {
|
||||
this._sidebar = n;
|
||||
}
|
||||
|
||||
async _requestGroupCreate (parentId) {
|
||||
const name = await showModal(PromptModal, {
|
||||
headerName: 'New Folder',
|
||||
defaultValue: 'My Folder',
|
||||
@ -144,25 +156,25 @@ class App extends PureComponent {
|
||||
});
|
||||
|
||||
models.requestGroup.create({parentId, name})
|
||||
};
|
||||
}
|
||||
|
||||
_requestCreate = async parentId => {
|
||||
async _requestCreate (parentId) {
|
||||
const request = await showModal(RequestCreateModal, {parentId});
|
||||
this._handleSetActiveRequest(request._id)
|
||||
};
|
||||
}
|
||||
|
||||
_requestGroupDuplicate = async requestGroup => {
|
||||
async _requestGroupDuplicate (requestGroup) {
|
||||
models.requestGroup.duplicate(requestGroup);
|
||||
};
|
||||
}
|
||||
|
||||
_requestDuplicate = async request => {
|
||||
async _requestDuplicate (request) {
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newRequest = await models.request.duplicate(request);
|
||||
await this._handleSetActiveRequest(newRequest._id)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Heavily optimized render function
|
||||
@ -173,7 +185,7 @@ class App extends PureComponent {
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_handleRenderText = async (text, strict = false, contextCacheKey = null) => {
|
||||
async _handleRenderText (text, strict = false, contextCacheKey = null) {
|
||||
if (!contextCacheKey || !this._getRenderContextCache[contextCacheKey]) {
|
||||
const {activeEnvironment, activeRequest} = this.props;
|
||||
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
||||
@ -187,17 +199,17 @@ class App extends PureComponent {
|
||||
|
||||
const context = await this._getRenderContextCache[contextCacheKey];
|
||||
return render.render(text, context, strict);
|
||||
};
|
||||
}
|
||||
|
||||
_handleGenerateCodeForActiveRequest = () => {
|
||||
_handleGenerateCodeForActiveRequest () {
|
||||
this._handleGenerateCode(this.props.activeRequest);
|
||||
};
|
||||
}
|
||||
|
||||
_handleGenerateCode = request => {
|
||||
_handleGenerateCode (request) {
|
||||
showModal(GenerateCodeModal, request);
|
||||
};
|
||||
}
|
||||
|
||||
_updateRequestGroupMetaByParentId = async (requestGroupId, patch) => {
|
||||
async _updateRequestGroupMetaByParentId (requestGroupId, patch) {
|
||||
const requestGroupMeta = await models.requestGroupMeta.getByParentId(requestGroupId);
|
||||
if (requestGroupMeta) {
|
||||
await models.requestGroupMeta.update(requestGroupMeta, patch);
|
||||
@ -205,9 +217,9 @@ class App extends PureComponent {
|
||||
const newPatch = Object.assign({parentId: requestGroupId}, patch);
|
||||
await models.requestGroupMeta.create(newPatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_updateActiveWorkspaceMeta = async (patch) => {
|
||||
async _updateActiveWorkspaceMeta (patch) {
|
||||
const workspaceId = this.props.activeWorkspace._id;
|
||||
const requestMeta = await models.workspaceMeta.getByParentId(workspaceId);
|
||||
if (requestMeta) {
|
||||
@ -216,9 +228,9 @@ class App extends PureComponent {
|
||||
const newPatch = Object.assign({parentId: workspaceId}, patch);
|
||||
await models.workspaceMeta.create(newPatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_updateRequestMetaByParentId = async (requestId, patch) => {
|
||||
async _updateRequestMetaByParentId (requestId, patch) {
|
||||
const requestMeta = await models.requestMeta.getByParentId(requestId);
|
||||
if (requestMeta) {
|
||||
await models.requestMeta.update(requestMeta, patch);
|
||||
@ -226,50 +238,48 @@ class App extends PureComponent {
|
||||
const newPatch = Object.assign({parentId: requestId}, patch);
|
||||
await models.requestMeta.create(newPatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_savePaneWidth = debounce(paneWidth => this._updateActiveWorkspaceMeta({paneWidth}));
|
||||
_handleSetPaneWidth = paneWidth => {
|
||||
_handleSetPaneWidth (paneWidth) {
|
||||
this.setState({paneWidth});
|
||||
this._savePaneWidth(paneWidth);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetActiveRequest = async activeRequestId => {
|
||||
async _handleSetActiveRequest (activeRequestId) {
|
||||
await this._updateActiveWorkspaceMeta({activeRequestId});
|
||||
};
|
||||
|
||||
_handleSetActiveEnvironment = async activeEnvironmentId => {
|
||||
async _handleSetActiveEnvironment (activeEnvironmentId) {
|
||||
await this._updateActiveWorkspaceMeta({activeEnvironmentId});
|
||||
this._wrapper._forceRequestPaneRefresh();
|
||||
};
|
||||
}
|
||||
|
||||
_saveSidebarWidth = debounce(sidebarWidth => this._updateActiveWorkspaceMeta({sidebarWidth}));
|
||||
_handleSetSidebarWidth = sidebarWidth => {
|
||||
_handleSetSidebarWidth (sidebarWidth) {
|
||||
this.setState({sidebarWidth});
|
||||
this._saveSidebarWidth(sidebarWidth);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetSidebarHidden = async sidebarHidden => {
|
||||
async _handleSetSidebarHidden (sidebarHidden) {
|
||||
await this._updateActiveWorkspaceMeta({sidebarHidden});
|
||||
};
|
||||
|
||||
_handleSetSidebarFilter = async sidebarFilter => {
|
||||
async _handleSetSidebarFilter (sidebarFilter) {
|
||||
await this._updateActiveWorkspaceMeta({sidebarFilter});
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetRequestGroupCollapsed = (requestGroupId, collapsed) => {
|
||||
_handleSetRequestGroupCollapsed (requestGroupId, collapsed) {
|
||||
this._updateRequestGroupMetaByParentId(requestGroupId, {collapsed});
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetResponsePreviewMode = (requestId, previewMode) => {
|
||||
_handleSetResponsePreviewMode (requestId, previewMode) {
|
||||
this._updateRequestMetaByParentId(requestId, {previewMode});
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetResponseFilter = (requestId, responseFilter) => {
|
||||
_handleSetResponseFilter (requestId, responseFilter) {
|
||||
this._updateRequestMetaByParentId(requestId, {responseFilter});
|
||||
};
|
||||
}
|
||||
|
||||
_handleSendAndDownloadRequestWithEnvironment = async (requestId, environmentId, dir) => {
|
||||
async _handleSendAndDownloadRequestWithEnvironment (requestId, environmentId, dir) {
|
||||
const request = await models.request.getById(requestId);
|
||||
if (!request) {
|
||||
return;
|
||||
@ -312,9 +322,9 @@ class App extends PureComponent {
|
||||
|
||||
// Stop loading
|
||||
this.props.handleStopLoading(requestId);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSendRequestWithEnvironment = async (requestId, environmentId) => {
|
||||
async _handleSendRequestWithEnvironment (requestId, environmentId) {
|
||||
const request = await models.request.getById(requestId);
|
||||
if (!request) {
|
||||
return;
|
||||
@ -343,39 +353,39 @@ class App extends PureComponent {
|
||||
|
||||
// Stop loading
|
||||
this.props.handleStopLoading(requestId);
|
||||
};
|
||||
}
|
||||
|
||||
_handleSetActiveResponse = (requestId, activeResponseId) => {
|
||||
_handleSetActiveResponse (requestId, activeResponseId) {
|
||||
this._updateRequestMetaByParentId(requestId, {activeResponseId});
|
||||
};
|
||||
}
|
||||
|
||||
_requestCreateForWorkspace = () => {
|
||||
_requestCreateForWorkspace () {
|
||||
this._requestCreate(this.props.activeWorkspace._id);
|
||||
};
|
||||
}
|
||||
|
||||
_startDragSidebar = () => {
|
||||
_startDragSidebar () {
|
||||
trackEvent('Sidebar', 'Drag');
|
||||
this.setState({draggingSidebar: true})
|
||||
};
|
||||
}
|
||||
|
||||
_resetDragSidebar = () => {
|
||||
_resetDragSidebar () {
|
||||
trackEvent('Sidebar', 'Drag');
|
||||
// TODO: Remove setTimeout need be not triggering drag on double click
|
||||
setTimeout(() => this._handleSetSidebarWidth(DEFAULT_SIDEBAR_WIDTH), 50);
|
||||
};
|
||||
}
|
||||
|
||||
_startDragPane = () => {
|
||||
_startDragPane () {
|
||||
trackEvent('App Pane', 'Drag Start');
|
||||
this.setState({draggingPane: true})
|
||||
};
|
||||
}
|
||||
|
||||
_resetDragPane = () => {
|
||||
_resetDragPane () {
|
||||
trackEvent('App Pane', 'Drag Reset');
|
||||
// TODO: Remove setTimeout need be not triggering drag on double click
|
||||
setTimeout(() => this._handleSetPaneWidth(DEFAULT_PANE_WIDTH), 50);
|
||||
};
|
||||
}
|
||||
|
||||
_handleMouseMove = (e) => {
|
||||
_handleMouseMove (e) {
|
||||
if (this.state.draggingPane) {
|
||||
const requestPane = ReactDOM.findDOMNode(this._requestPane);
|
||||
const responsePane = ReactDOM.findDOMNode(this._responsePane);
|
||||
@ -394,9 +404,9 @@ class App extends PureComponent {
|
||||
let sidebarWidth = Math.max(Math.min(width, MAX_SIDEBAR_REMS), MIN_SIDEBAR_REMS);
|
||||
this._handleSetSidebarWidth(sidebarWidth);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleMouseUp = () => {
|
||||
_handleMouseUp () {
|
||||
if (this.state.draggingSidebar) {
|
||||
this.setState({draggingSidebar: false});
|
||||
}
|
||||
@ -404,9 +414,9 @@ class App extends PureComponent {
|
||||
if (this.state.draggingPane) {
|
||||
this.setState({draggingPane: false});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleKeyDown = e => {
|
||||
_handleKeyDown (e) {
|
||||
const isMetaPressed = isMac() ? e.metaKey : e.ctrlKey;
|
||||
const isShiftPressed = e.shiftKey;
|
||||
|
||||
@ -425,15 +435,17 @@ class App extends PureComponent {
|
||||
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleToggleSidebar = async () => {
|
||||
async _handleToggleSidebar () {
|
||||
const sidebarHidden = !this.props.sidebarHidden;
|
||||
await this._handleSetSidebarHidden(sidebarHidden);
|
||||
trackEvent('Sidebar', 'Toggle Visibility', sidebarHidden ? 'Hide' : 'Show');
|
||||
};
|
||||
}
|
||||
|
||||
_setWrapperRef = n => this._wrapper = n;
|
||||
_setWrapperRef (n) {
|
||||
this._wrapper = n;
|
||||
}
|
||||
|
||||
async componentDidMount () {
|
||||
// Bind mouse and key handlers
|
||||
@ -747,6 +759,5 @@ async function _moveRequest (requestToMove, parentId, targetId, targetOffset) {
|
||||
}
|
||||
}
|
||||
|
||||
const reduxApp = connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
export default DragDropContext(HTML5Backend)(reduxApp);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
|
||||
|
@ -77,6 +77,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.modal--noescape .modal__close-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modal__body {
|
||||
overflow: auto;
|
||||
min-height: 2rem;
|
||||
|
@ -11,7 +11,7 @@ html, body, #root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html, h1, h2, h3, h4, h5, h6, input, p {
|
||||
html, h1, h2, h3, h4, h5, h6, input {
|
||||
font-weight: 400;
|
||||
font-family: @font-default;
|
||||
}
|
||||
@ -435,7 +435,7 @@ i.fa {
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hide-above-lg {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {AppContainer} from 'react-hot-loader';
|
||||
import {Provider} from 'react-redux';
|
||||
import {Tabs} from 'react-tabs';
|
||||
import App from './containers/App';
|
||||
@ -10,10 +11,13 @@ import {init as initSync} from '../sync';
|
||||
import {init as initAnalytics} from '../analytics';
|
||||
import {types as modelTypes} from '../models';
|
||||
import {getAccountId} from '../sync/session';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import {DragDropContext} from 'react-dnd';
|
||||
|
||||
// Don't inject component styles (use our own)
|
||||
Tabs.setUseDefaultStyles(false);
|
||||
|
||||
|
||||
(async function () {
|
||||
|
||||
await initDB(modelTypes());
|
||||
@ -22,11 +26,27 @@ Tabs.setUseDefaultStyles(false);
|
||||
// Create Redux store
|
||||
const store = await initStore();
|
||||
|
||||
// Actually render the app
|
||||
ReactDOM.render(
|
||||
<Provider store={store}><App /></Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
const context = DragDropContext(HTML5Backend);
|
||||
const DndComponent = context(App);
|
||||
const render = Component => {
|
||||
ReactDOM.render(
|
||||
<AppContainer>
|
||||
<Provider store={store}>
|
||||
<Component/>
|
||||
</Provider>
|
||||
</AppContainer>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
||||
render(DndComponent);
|
||||
|
||||
// Hot Module Replacement API
|
||||
if (module.hot) {
|
||||
module.hot.accept('./containers/App', () => {
|
||||
render(DndComponent);
|
||||
});
|
||||
}
|
||||
|
||||
// Do things that can wait
|
||||
process.nextTick(initSync);
|
||||
|
@ -13,7 +13,7 @@ export default function configureStore () {
|
||||
const store = createStore(reducer, applyMiddleware(...middleware));
|
||||
if (__DEV__ && module.hot) {
|
||||
module.hot.accept('./modules/index', () => {
|
||||
store.replaceReducer(require('./modules').reducer);
|
||||
store.replaceReducer(reducer);
|
||||
});
|
||||
}
|
||||
|
||||
|
51
package.json
51
package.json
@ -11,12 +11,13 @@
|
||||
"url": "https://github.com/gschier/insomnia"
|
||||
},
|
||||
"scripts": {
|
||||
"test:noisy": "jest",
|
||||
"test:coverage": "jest --coverage --silent && open ./coverage/lcov-report/index.html",
|
||||
"test:watch": "jest --silent --watch",
|
||||
"test": "jest --silent",
|
||||
"start-hot": "cross-env HOT=1 INSOMNIA_ENV=development electron -r babel-register ./app/main.development.js",
|
||||
"hot-server": "babel-node ./webpack/server.js",
|
||||
"test:noisy": "cross-env NODE_ENV=test jest",
|
||||
"test:coverage": "cross-env NODE_ENV=test jest --coverage --silent && open ./coverage/lcov-report/index.html",
|
||||
"test:watch": "cross-env NODE_ENV=test jest --silent --watch",
|
||||
"test": "cross-env NODE_ENV=test jest --silent",
|
||||
"start-hot": "npm run build-main && cross-env HOT=1 INSOMNIA_ENV=development electron -r babel-register ./app/main.tmp.js",
|
||||
"build-main": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.config.electron.babel.js",
|
||||
"hot-server": "webpack-dev-server --config ./webpack/webpack.config.development.babel.js",
|
||||
"dev": "concurrently --kill-others \"npm run hot-server\" \"npm run start-hot\"",
|
||||
"build:clean": "rm -rf ./build && rm -rf ./dist && mkdirp ./build",
|
||||
"build:renderer": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.production.babel.js",
|
||||
@ -34,26 +35,6 @@
|
||||
"build-n-package:linux": "npm run build && npm run package:linux",
|
||||
"sentry": "bash scripts/sentry-release.sh"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"es2015",
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"transform-class-properties",
|
||||
"transform-regenerator",
|
||||
"transform-runtime",
|
||||
"add-module-exports"
|
||||
],
|
||||
"env": {
|
||||
"development": {
|
||||
"presets": [
|
||||
"react-hmre"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"setupFiles": [
|
||||
"./__jest__/setup.js"
|
||||
@ -99,6 +80,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"analytics-node": "~2.1.0",
|
||||
"autobind-decorator": "^1.3.4",
|
||||
"classnames": "~2.2.5",
|
||||
"clone": "~2.1.0",
|
||||
"codemirror": "~5.24.2",
|
||||
@ -135,39 +117,36 @@
|
||||
"xpath": "~0.0.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "~6.23.0",
|
||||
"babel-cli": "^6.23.0",
|
||||
"babel-core": "~6.23.1",
|
||||
"babel-jest": "~19.0.0",
|
||||
"babel-loader": "~6.3.2",
|
||||
"babel-plugin-add-module-exports": "~0.2.1",
|
||||
"babel-plugin-transform-class-properties": "~6.23.0",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-object-rest-spread": "~6.23.0",
|
||||
"babel-plugin-transform-regenerator": "~6.22.0",
|
||||
"babel-plugin-transform-runtime": "~6.15.0",
|
||||
"babel-polyfill": "~6.23.0",
|
||||
"babel-preset-es2015": "~6.22.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-react": "~6.23.0",
|
||||
"babel-preset-react-hmre": "~1.1.1",
|
||||
"concurrently": "~2.0.0",
|
||||
"cross-env": "~2.0.0",
|
||||
"css-loader": "~0.26.2",
|
||||
"electron": "~1.4.15",
|
||||
"electron": "~1.6.1",
|
||||
"electron-builder": "~10.17.3",
|
||||
"express": "~4.14.0",
|
||||
"file-loader": "~0.10.1",
|
||||
"jest": "~18.1.0",
|
||||
"jsbn": "~0.1.0",
|
||||
"less": "~2.7.2",
|
||||
"less-loader": "~2.2.3",
|
||||
"nock": "~9.0.2",
|
||||
"react-addons-perf": "~15.3.0",
|
||||
"react-addons-test-utils": "~15.1.0",
|
||||
"react-hot-loader": "~1.3.1",
|
||||
"react-hot-loader": "~3.0.0-beta.6",
|
||||
"redux-mock-store": "~1.0.2",
|
||||
"style-loader": "~0.13.2",
|
||||
"url-loader": "^0.5.8",
|
||||
"webpack": "~2.2.1",
|
||||
"webpack-dev-middleware": "~1.10.1",
|
||||
"webpack-dev-server": "~2.4.1",
|
||||
"webpack-dev-server": "^2.4.1",
|
||||
"webpack-hot-middleware": "~2.17.1",
|
||||
"webpack-target-electron-renderer": "~0.4.0"
|
||||
},
|
||||
|
@ -1,30 +0,0 @@
|
||||
import express from 'express';
|
||||
import webpack from 'webpack';
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware';
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware';
|
||||
import {parse as urlParse} from 'url';
|
||||
|
||||
import config from './webpack.config.development.babel';
|
||||
|
||||
const app = express();
|
||||
const compiler = webpack(config);
|
||||
|
||||
app.use(webpackDevMiddleware(compiler, {
|
||||
publicPath: config.output.publicPath,
|
||||
noInfo: true,
|
||||
stats: {
|
||||
colors: true
|
||||
}
|
||||
}));
|
||||
|
||||
app.use(webpackHotMiddleware(compiler));
|
||||
|
||||
const parsedUrl = urlParse(config.output.publicPath);
|
||||
app.listen(parsedUrl.port, parsedUrl.hostname, err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Listening at http://${parsedUrl.hostname}:${parsedUrl.port}`);
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import * as pkg from '../app/package.json';
|
||||
const path = require('path');
|
||||
const pkg = require('../app/package.json');
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
devtool: 'source-map',
|
||||
context: path.join(__dirname, '../app'),
|
||||
entry: [
|
||||
@ -17,7 +17,7 @@ export default {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
use: ['babel-loader'],
|
||||
exclude: [/node_modules/, /__fixtures__/, /__tests__/],
|
||||
},
|
||||
{
|
||||
@ -29,11 +29,15 @@ export default {
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(html|png|woff2)$/,
|
||||
test: /\.(html|woff2)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]'
|
||||
}
|
||||
name: '[name].[ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(png)$/,
|
||||
loader: 'url-loader',
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1,28 +1,37 @@
|
||||
import webpack from 'webpack';
|
||||
import baseConfig from './webpack.config.base.babel';
|
||||
const webpack = require('webpack');
|
||||
const baseConfig = require('./webpack.config.base.babel');
|
||||
const path = require('path');
|
||||
|
||||
const PORT = 3333;
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
devtool: 'eval-source-map',
|
||||
entry: [
|
||||
'react-hot-loader/patch',
|
||||
...baseConfig.entry,
|
||||
`webpack-hot-middleware/client?path=http://localhost:${PORT}/__webpack_hmr`
|
||||
],
|
||||
output: {
|
||||
...baseConfig.output,
|
||||
publicPath: `http://localhost:${PORT}/build/`
|
||||
publicPath: `http://localhost:${PORT}/`,
|
||||
},
|
||||
devServer: {
|
||||
hot: true,
|
||||
hotOnly: true,
|
||||
noInfo: true,
|
||||
port: PORT,
|
||||
publicPath: `http://localhost:${PORT}/`,
|
||||
},
|
||||
plugins: [
|
||||
...baseConfig.plugins,
|
||||
new webpack.LoaderOptionsPlugin({debug: true}),
|
||||
new webpack.LoaderOptionsPlugin({debug: true}), // Legacy global loader option
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: true,
|
||||
'process.env.NODE_ENV': JSON.stringify('development'),
|
||||
'process.env.INSOMNIA_ENV': JSON.stringify('development')
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
|
@ -1,16 +1,24 @@
|
||||
import path from 'path';
|
||||
import productionConfig from './webpack.config.production.babel';
|
||||
const path = require('path');
|
||||
const productionConfig = require('./webpack.config.production.babel');
|
||||
|
||||
export default {
|
||||
const output = {
|
||||
libraryTarget: 'commonjs2'
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
output.path = path.join(__dirname, '../app');
|
||||
output.filename = 'main.tmp.js';
|
||||
} else {
|
||||
output.path = path.join(__dirname, '../build');
|
||||
output.filename = 'main.js';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
...productionConfig,
|
||||
entry: [
|
||||
'./main.development.js'
|
||||
],
|
||||
output: {
|
||||
path: path.join(__dirname, '../build'),
|
||||
filename: 'main.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
output: output,
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false
|
||||
|
@ -1,7 +1,7 @@
|
||||
import webpack from 'webpack';
|
||||
import baseConfig from './webpack.config.base.babel';
|
||||
const webpack = require('webpack');
|
||||
const baseConfig = require('./webpack.config.base.babel');
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
@ -15,4 +15,4 @@ export default {
|
||||
'process.env.HOT': JSON.stringify(null),
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user