More changes to cookie editing

This commit is contained in:
Gregory Schier 2017-08-22 16:54:31 -07:00
parent d654feca82
commit 9e3d79ccc0
10 changed files with 112 additions and 66 deletions

View File

@ -12,7 +12,9 @@ export type Cookie = {
path: string, path: string,
key: string, key: string,
value: string, value: string,
expires: number expires: number,
httpOnly: boolean,
secure: boolean
} }
type BaseCookieJar = { type BaseCookieJar = {

View File

@ -59,7 +59,7 @@ export function types () {
return all().map(model => model.type); return all().map(model => model.type);
} }
export function getModel (type: string) { export function getModel (type: string): Object | null {
return all().find(m => m.type === type) || null; return all().find(m => m.type === type) || null;
} }
@ -99,7 +99,7 @@ export function initModel (type: string, ...sources: Array<Object>) {
created: Date.now() created: Date.now()
}, model.init()); }, model.init());
const fullObject = Object.assign({}, objectDefaults, ...sources); const fullObject = Object.assign(objectDefaults, ...sources);
// Generate an _id if there isn't one yet // Generate an _id if there isn't one yet
if (!fullObject._id) { if (!fullObject._id) {

View File

@ -1,5 +1,5 @@
// @flow
import React, {PureComponent} from 'react'; import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import autobind from 'autobind-decorator'; import autobind from 'autobind-decorator';
import {Cookie} from 'tough-cookie'; import {Cookie} from 'tough-cookie';
@ -9,6 +9,15 @@ import RenderedText from './rendered-text';
@autobind @autobind
class CookieList extends PureComponent { class CookieList extends PureComponent {
props: {
onCookieAdd: Function,
onCookieDelete: Function,
cookies: Array<Cookie>,
newCookieDomainName: string,
handleShowModifyCookieModal: Function,
handleRender: Function
};
_handleCookieAdd () { _handleCookieAdd () {
const newCookie = new Cookie({ const newCookie = new Cookie({
key: 'foo', key: 'foo',
@ -22,7 +31,7 @@ class CookieList extends PureComponent {
this.props.onCookieAdd(newCookie); this.props.onCookieAdd(newCookie);
} }
_handleDeleteCookie (cookie) { _handleDeleteCookie (cookie: Cookie) {
this.props.onCookieDelete(cookie); this.props.onCookieDelete(cookie);
} }
@ -58,7 +67,8 @@ class CookieList extends PureComponent {
<RenderedText render={handleRender} component="td"> <RenderedText render={handleRender} component="td">
{cookie.domain} {cookie.domain}
</RenderedText> </RenderedText>
<RenderedText render={handleRender} component="td"> <RenderedText render={handleRender} component="td"
props={{className: 'force-wrap wide'}}>
{cookieString} {cookieString}
</RenderedText> </RenderedText>
<td onClick={null} className="text-right no-wrap"> <td onClick={null} className="text-right no-wrap">
@ -98,13 +108,4 @@ class CookieList extends PureComponent {
} }
} }
CookieList.propTypes = {
onCookieAdd: PropTypes.func.isRequired,
onCookieDelete: PropTypes.func.isRequired,
cookies: PropTypes.array.isRequired,
newCookieDomainName: PropTypes.string.isRequired,
handleShowModifyCookieModal: PropTypes.func.isRequired,
handleRender: PropTypes.func.isRequired
};
export default CookieList; export default CookieList;

View File

@ -1,8 +1,8 @@
// @flow
import React, {PureComponent} from 'react'; import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Tabs, TabList, Tab, TabPanel} from 'react-tabs'; import {Tabs, TabList, Tab, TabPanel} from 'react-tabs';
import autobind from 'autobind-decorator'; import autobind from 'autobind-decorator';
import {Cookie} from 'tough-cookie'; import * as toughCookie from 'tough-cookie';
import * as models from '../../../models'; import * as models from '../../../models';
import {DEBOUNCE_MILLIS} from '../../../common/constants'; import {DEBOUNCE_MILLIS} from '../../../common/constants';
import {trackEvent} from '../../../analytics/index'; import {trackEvent} from '../../../analytics/index';
@ -12,14 +12,38 @@ import ModalHeader from '../base/modal-header';
import ModalFooter from '../base/modal-footer'; import ModalFooter from '../base/modal-footer';
import OneLineEditor from '../codemirror/one-line-editor'; import OneLineEditor from '../codemirror/one-line-editor';
import {cookieToString} from '../../../common/cookies'; import {cookieToString} from '../../../common/cookies';
import type {Cookie, CookieJar} from '../../../models/cookie-jar';
import type {Workspace} from '../../../models/workspace';
@autobind @autobind
class CookieModifyModal extends PureComponent { class CookieModifyModal extends PureComponent {
constructor (props) { props: {
handleRender: Function,
handleGetRenderContext: Function,
workspace: Workspace,
cookieJar: CookieJar
};
state: {
cookie: Cookie | null,
rawValue: string,
isValid: {
key: boolean,
value: boolean,
domain: boolean,
path: boolean,
expires: boolean
}
};
modal: Modal | null;
_rawTimeout: number | null;
_cookieUpdateTimeout: number | null;
constructor (props: any) {
super(props); super(props);
this.state = { this.state = {
cookieJar: null,
cookie: null, cookie: null,
rawValue: '', rawValue: '',
isValid: { isValid: {
@ -30,52 +54,49 @@ class CookieModifyModal extends PureComponent {
expires: true expires: true
} }
}; };
this._rawTimeout = null;
this._cookieUpdateTimeout = null;
} }
_setModalRef (n) { _setModalRef (n: Modal | null) {
this.modal = n; this.modal = n;
} }
async _load () { async show (cookie: Cookie) {
const {workspace} = this.props;
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id);
this.setState({cookieJar});
}
async show (cookie) {
await this._load();
// Dunno why this is sent as an array // Dunno why this is sent as an array
cookie = cookie[0] || cookie; cookie = cookie[0] || cookie;
this.setState({cookie}); this.setState({cookie});
this.modal.show(); this.modal && this.modal.show();
trackEvent('Cookie Modifier', 'Show'); trackEvent('Cookie Modifier', 'Show');
} }
hide () { hide () {
this.modal.hide(); this.modal && this.modal.hide();
} }
async _saveChanges () { async _saveChanges (cookieJar: CookieJar) {
const {cookieJar} = this.state;
await models.cookieJar.update(cookieJar); await models.cookieJar.update(cookieJar);
await this._load();
} }
_handleChangeRawValue (e) { _handleChangeRawValue (e: Event & {target: HTMLInputElement}) {
const value = e.target.value; const value = e.target.value;
clearTimeout(this._rawTimeout); clearTimeout(this._rawTimeout);
this._rawTimeout = setTimeout(async () => { this._rawTimeout = setTimeout(async () => {
const cookie = Cookie.parse(value); const cookie = toughCookie.Cookie.parse(value);
if (!this.state.cookie) {
return;
}
await this._handleCookieUpdate(this.state.cookie, cookie); await this._handleCookieUpdate(this.state.cookie, cookie);
}, DEBOUNCE_MILLIS); }, DEBOUNCE_MILLIS);
} }
async _handleCookieUpdate (oldCookie, cookie) { async _handleCookieUpdate (oldCookie: Cookie, cookie: Cookie) {
const {cookieJar} = this.state; const {cookieJar} = this.props;
const {cookies} = cookieJar; const {cookies} = cookieJar;
const index = cookies.findIndex(c => c.domain === oldCookie.domain && c.key === oldCookie.key); const index = cookies.findIndex(c => c.domain === oldCookie.domain && c.key === oldCookie.key);
@ -91,21 +112,23 @@ class CookieModifyModal extends PureComponent {
trackEvent('Cookie', 'Update'); trackEvent('Cookie', 'Update');
} }
_handleChange (input, field) { _handleChange (field: string, eventOrValue: Event & {target: HTMLInputElement}) {
const {cookie} = this.state; const {cookie} = this.state;
let valid = true; let valid = true;
if (typeof input === 'object') { const value = typeof eventOrValue === 'object'
input = input.target.checked; ? eventOrValue.target.checked
} : eventOrValue;
if (valid) { if (valid) {
const newCookie = Object.assign({}, cookie, {[field]: input}); const newCookie = Object.assign({}, cookie, {[field]: value});
clearTimeout(this._cookieUpdateTimeout); clearTimeout(this._cookieUpdateTimeout);
this._cookieUpdateTimeout = setTimeout(() => { this._cookieUpdateTimeout = setTimeout(async () => {
this._handleCookieUpdate(cookie, newCookie); if (cookie) {
this.setState({cookie: newCookie}); await this._handleCookieUpdate(cookie, newCookie);
this.setState({cookie: newCookie});
}
}, DEBOUNCE_MILLIS * 2); }, DEBOUNCE_MILLIS * 2);
} }
@ -117,20 +140,24 @@ class CookieModifyModal extends PureComponent {
}); });
} }
_capitalize (str) { _capitalize (str: string) {
return str.charAt(0).toUpperCase() + str.slice(1); return str.charAt(0).toUpperCase() + str.slice(1);
} }
render () { render () {
const { const {
cookieJar,
handleRender, handleRender,
handleGetRenderContext handleGetRenderContext
} = this.props; } = this.props;
if (!cookieJar) {
return null;
}
const { const {
isValid, isValid,
cookie, cookie
cookieJar
} = this.state; } = this.state;
if (!cookie || !cookieJar) { if (!cookie || !cookieJar) {
@ -142,7 +169,7 @@ class CookieModifyModal extends PureComponent {
let rawCookieString = ''; let rawCookieString = '';
try { try {
rawCookieString = cookieToString(Cookie.fromJSON(JSON.stringify(cookie))); rawCookieString = cookieToString(toughCookie.Cookie.fromJSON(JSON.stringify(cookie)));
} catch (err) { } catch (err) {
console.warn('Failed to parse cookie', err); console.warn('Failed to parse cookie', err);
} }
@ -170,13 +197,12 @@ class CookieModifyModal extends PureComponent {
<label>{this._capitalize(field)} <label>{this._capitalize(field)}
<OneLineEditor <OneLineEditor
className={isValid[field] ? '' : 'input--error'} className={isValid[field] ? '' : 'input--error'}
ref={this._setInputRef}
forceEditor forceEditor
type="text" type="text"
render={handleRender} render={handleRender}
getRenderContext={handleGetRenderContext} getRenderContext={handleGetRenderContext}
defaultValue={val || ''} defaultValue={val || ''}
onChange={(i) => this._handleChange(i, field)}/> onChange={value => this._handleChange(field, value)}/>
</label> </label>
</div> </div>
); );
@ -193,7 +219,7 @@ class CookieModifyModal extends PureComponent {
type="checkbox" type="checkbox"
name={field} name={field}
defaultChecked={checked || false} defaultChecked={checked || false}
onChange={(e) => this._handleChange(e, field)} onChange={e => this._handleChange(field, e)}
/> />
</label> </label>
); );
@ -221,11 +247,5 @@ class CookieModifyModal extends PureComponent {
} }
} }
CookieModifyModal.propTypes = {
handleRender: PropTypes.func.isRequired,
handleGetRenderContext: PropTypes.func.isRequired,
workspace: PropTypes.object.isRequired
};
// export CookieModifyModal; // export CookieModifyModal;
export default CookieModifyModal; export default CookieModifyModal;

View File

@ -34,6 +34,13 @@ class CookiesModal extends PureComponent {
}; };
} }
async _ensureCookieJarExists () {
const {cookieJar, workspace} = this.props;
if (!cookieJar) {
models.cookieJar.getOrCreateForParentId(workspace._id);
}
}
_setModalRef (n: React.Element<*> | null) { _setModalRef (n: React.Element<*> | null) {
this.modal = n; this.modal = n;
} }
@ -85,11 +92,13 @@ class CookiesModal extends PureComponent {
} }
async show () { async show () {
this.modal && this.modal.show(); await this._ensureCookieJarExists();
setTimeout(() => { setTimeout(() => {
this.filterInput && this.filterInput.focus(); this.filterInput && this.filterInput.focus();
}, 100); }, 100);
this.modal && this.modal.show();
trackEvent('Cookie Manager', 'Show'); trackEvent('Cookie Manager', 'Show');
} }
@ -98,16 +107,22 @@ class CookiesModal extends PureComponent {
} }
render () { render () {
const filteredCookies = this._getFilteredSortedCookies();
const { const {
handleShowModifyCookieModal, handleShowModifyCookieModal,
handleRender handleRender,
cookieJar
} = this.props; } = this.props;
if (!cookieJar) {
return null;
}
const { const {
filter filter
} = this.state; } = this.state;
const filteredCookies = this._getFilteredSortedCookies();
return ( return (
<Modal ref={this._setModalRef} wide tall {...this.props}> <Modal ref={this._setModalRef} wide tall {...this.props}>
<ModalHeader>Manage Cookies</ModalHeader> <ModalHeader>Manage Cookies</ModalHeader>

View File

@ -5,7 +5,8 @@ class RenderedText extends React.PureComponent {
props: { props: {
component: string, component: string,
children: string, children: string,
render: Function render: Function,
props?: Object
}; };
state: { state: {
@ -34,8 +35,8 @@ class RenderedText extends React.PureComponent {
} }
render () { render () {
const {component} = this.props; const {component, props} = this.props;
return React.createElement(component, {}, this.state.renderedText); return React.createElement(component, props || {}, this.state.renderedText);
} }
} }

View File

@ -540,6 +540,7 @@ class Wrapper extends React.PureComponent {
handleRender={handleRender} handleRender={handleRender}
handleGetRenderContext={handleGetRenderContext} handleGetRenderContext={handleGetRenderContext}
ref={registerModal} ref={registerModal}
cookieJar={activeCookieJar}
workspace={activeWorkspace} workspace={activeWorkspace}
/> />
<NunjucksModal <NunjucksModal

View File

@ -903,11 +903,13 @@ function mapStateToProps (state, props) {
// Request stuff // Request stuff
const requestMeta = selectActiveRequestMeta(state, props) || {}; const requestMeta = selectActiveRequestMeta(state, props) || {};
const activeRequest = selectActiveRequest(state, props); const activeRequest = selectActiveRequest(state, props);
const activeCookieJar = selectActiveCookieJar(state, props);
const responsePreviewMode = requestMeta.previewMode || PREVIEW_MODE_SOURCE; const responsePreviewMode = requestMeta.previewMode || PREVIEW_MODE_SOURCE;
const responseFilter = requestMeta.responseFilter || ''; const responseFilter = requestMeta.responseFilter || '';
const responseFilterHistory = requestMeta.responseFilterHistory || []; const responseFilterHistory = requestMeta.responseFilterHistory || [];
// Cookie Jar
const activeCookieJar = selectActiveCookieJar(state, props);
// Response stuff // Response stuff
const activeRequestResponses = selectActiveRequestResponses(state, props) || []; const activeRequestResponses = selectActiveRequestResponses(state, props) || [];
const activeResponse = selectActiveResponse(state, props) || null; const activeResponse = selectActiveResponse(state, props) || null;

View File

@ -1,5 +1,6 @@
import {createSelector} from 'reselect'; import {createSelector} from 'reselect';
import {fuzzyMatch} from '../../common/misc'; import {fuzzyMatch} from '../../common/misc';
import * as models from '../../models/index';
// ~~~~~~~~~ // // ~~~~~~~~~ //
// Selectors // // Selectors //

3
flow-typed/tough-cookie.js vendored Normal file
View File

@ -0,0 +1,3 @@
declare module 'tough-cookie' {
declare module.exports: *
}