mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 14:19:58 +00:00
Better cookie handling/editing
This commit is contained in:
parent
2887282032
commit
c69c8d2dd0
@ -3,4 +3,5 @@ charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
@ -2,8 +2,10 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Tabs, TabList, Tab, TabPanel} from 'react-tabs';
|
||||
import autobind from 'autobind-decorator';
|
||||
import deepEqual from 'deep-equal';
|
||||
import * as toughCookie from 'tough-cookie';
|
||||
import * as models from '../../../models';
|
||||
import clone from 'clone';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
import Modal from '../base/modal';
|
||||
@ -96,9 +98,11 @@ class CookieModifyModal extends PureComponent {
|
||||
}
|
||||
|
||||
async _handleCookieUpdate (oldCookie: Cookie, cookie: Cookie) {
|
||||
const {cookieJar} = this.props;
|
||||
// Clone so we don't modify the original
|
||||
const cookieJar = clone(this.props.cookieJar);
|
||||
|
||||
const {cookies} = cookieJar;
|
||||
const index = cookies.findIndex(c => c.domain === oldCookie.domain && c.key === oldCookie.key);
|
||||
const index = cookies.findIndex(c => deepEqual(c, oldCookie));
|
||||
|
||||
cookieJar.cookies = [
|
||||
...cookies.slice(0, index),
|
||||
@ -144,6 +148,21 @@ class CookieModifyModal extends PureComponent {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
_getRawCookieString () {
|
||||
const {cookie} = this.state;
|
||||
|
||||
if (!cookie) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
return cookieToString(toughCookie.Cookie.fromJSON(JSON.stringify(cookie)));
|
||||
} catch (err) {
|
||||
console.warn('Failed to parse cookie string', err);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
cookieJar,
|
||||
@ -151,91 +170,78 @@ class CookieModifyModal extends PureComponent {
|
||||
handleGetRenderContext
|
||||
} = this.props;
|
||||
|
||||
if (!cookieJar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
isValid,
|
||||
cookie
|
||||
} = this.state;
|
||||
|
||||
if (!cookie || !cookieJar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const textFields = ['key', 'value', 'domain', 'path', 'expires'];
|
||||
const checkFields = ['secure', 'httpOnly'];
|
||||
|
||||
let rawCookieString = '';
|
||||
try {
|
||||
rawCookieString = cookieToString(toughCookie.Cookie.fromJSON(JSON.stringify(cookie)));
|
||||
} catch (err) {
|
||||
console.warn('Failed to parse cookie', err);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef} {...this.props}>
|
||||
<ModalHeader>Edit Cookie</ModalHeader>
|
||||
<ModalBody className="cookie-modify">
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>
|
||||
<button>Friendly</button>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<button>Raw</button>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<div className="pad">
|
||||
{textFields.map((field, i) => {
|
||||
const val = (cookie[field] || '').toString();
|
||||
{cookieJar && cookie && (
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>
|
||||
<button>Friendly</button>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<button>Raw</button>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<div className="pad">
|
||||
{textFields.map((field, i) => {
|
||||
const val = (cookie[field] || '').toString();
|
||||
|
||||
return (
|
||||
<div className="form-control form-control--outlined" key={i}>
|
||||
<label>{this._capitalize(field)}
|
||||
<OneLineEditor
|
||||
className={isValid[field] ? '' : 'input--error'}
|
||||
forceEditor
|
||||
type="text"
|
||||
render={handleRender}
|
||||
getRenderContext={handleGetRenderContext}
|
||||
defaultValue={val || ''}
|
||||
onChange={value => this._handleChange(field, value)}/>
|
||||
return (
|
||||
<div className="form-control form-control--outlined" key={i}>
|
||||
<label>{this._capitalize(field)}
|
||||
<OneLineEditor
|
||||
className={isValid[field] ? '' : 'input--error'}
|
||||
forceEditor
|
||||
type="text"
|
||||
render={handleRender}
|
||||
getRenderContext={handleGetRenderContext}
|
||||
defaultValue={val || ''}
|
||||
onChange={value => this._handleChange(field, value)}/>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="pad no-pad-top cookie-modify__checkboxes row-around txt-lg">
|
||||
{checkFields.map((field, i) => {
|
||||
const checked = !!cookie[field];
|
||||
|
||||
return (
|
||||
<label key={i}>{this._capitalize(field)}
|
||||
<input
|
||||
className="space-left"
|
||||
type="checkbox"
|
||||
name={field}
|
||||
defaultChecked={checked || false}
|
||||
onChange={e => this._handleChange(field, e)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="pad no-pad-top cookie-modify__checkboxes row-around txt-lg">
|
||||
{checkFields.map((field, i) => {
|
||||
const checked = !!cookie[field];
|
||||
|
||||
return (
|
||||
<label key={i}>{this._capitalize(field)}
|
||||
<input
|
||||
className="space-left"
|
||||
type="checkbox"
|
||||
name={field}
|
||||
defaultChecked={checked || false}
|
||||
onChange={e => this._handleChange(field, e)}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel pad">
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>Raw Cookie String
|
||||
<input type="text"
|
||||
onChange={this._handleChangeRawValue}
|
||||
defaultValue={rawCookieString}/>
|
||||
</label>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel pad">
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>Raw Cookie String
|
||||
<input type="text"
|
||||
onChange={this._handleChangeRawValue}
|
||||
defaultValue={this._getRawCookieString()}/>
|
||||
</label>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<button className="btn" onClick={this.hide}>
|
||||
|
@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
import React, {PureComponent} from 'react';
|
||||
import deepEqual from 'deep-equal';
|
||||
import autobind from 'autobind-decorator';
|
||||
import Modal from '../base/modal';
|
||||
import ModalBody from '../base/modal-body';
|
||||
@ -10,6 +11,7 @@ import * as models from '../../../models';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
import type {Cookie, CookieJar} from '../../../models/cookie-jar';
|
||||
import type {Workspace} from '../../../models/workspace';
|
||||
import {fuzzyMatch} from '../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class CookiesModal extends PureComponent {
|
||||
@ -21,7 +23,8 @@ class CookiesModal extends PureComponent {
|
||||
};
|
||||
|
||||
state: {
|
||||
filter: string
|
||||
filter: string,
|
||||
visibleCookieIndexes: Array<number> | null
|
||||
};
|
||||
|
||||
modal: Modal | null;
|
||||
@ -29,8 +32,10 @@ class CookiesModal extends PureComponent {
|
||||
|
||||
constructor (props: any) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
filter: ''
|
||||
filter: '',
|
||||
visibleCookieIndexes: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -74,21 +79,56 @@ class CookiesModal extends PureComponent {
|
||||
trackEvent('Cookie', 'Delete');
|
||||
}
|
||||
|
||||
_handleFilterChange (e: Event & {target: HTMLInputElement}) {
|
||||
async _handleFilterChange (e: Event & {target: HTMLInputElement}) {
|
||||
const filter = e.target.value;
|
||||
this.setState({filter});
|
||||
trackEvent('Cookie Editor', 'Filter Change');
|
||||
this._applyFilter(filter, this.props.cookieJar.cookies);
|
||||
}
|
||||
|
||||
_getFilteredSortedCookies () {
|
||||
const {cookieJar} = this.props;
|
||||
const {filter} = this.state;
|
||||
componentWillReceiveProps (nextProps: any) {
|
||||
// Re-filter if we received new cookies
|
||||
// Compare cookies with Dates cast to strings
|
||||
const sameCookies = deepEqual(
|
||||
this.props.cookieJar.cookies,
|
||||
nextProps.cookieJar.cookies
|
||||
);
|
||||
|
||||
const {cookies} = cookieJar;
|
||||
return cookies.filter(c => {
|
||||
const toSearch = JSON.stringify(c).toLowerCase();
|
||||
return toSearch.indexOf(filter.toLowerCase()) !== -1;
|
||||
});
|
||||
if (!sameCookies) {
|
||||
this._applyFilter(this.state.filter, nextProps.cookieJar.cookies);
|
||||
}
|
||||
}
|
||||
|
||||
async _applyFilter (filter: string, cookies: Array<Cookie>) {
|
||||
const renderedCookies = await this.props.handleRender(cookies);
|
||||
|
||||
let visibleCookieIndexes;
|
||||
|
||||
if (filter) {
|
||||
visibleCookieIndexes = [];
|
||||
for (let i = 0; i < renderedCookies.length; i++) {
|
||||
const toSearch = JSON.stringify(renderedCookies[i]);
|
||||
const matched = fuzzyMatch(filter, toSearch);
|
||||
if (matched) {
|
||||
visibleCookieIndexes.push(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visibleCookieIndexes = null;
|
||||
}
|
||||
|
||||
console.log('APPLIED FILTER', filter, visibleCookieIndexes);
|
||||
|
||||
this.setState({filter, visibleCookieIndexes});
|
||||
}
|
||||
|
||||
_getVisibleCookies () {
|
||||
const {cookieJar} = this.props;
|
||||
const {visibleCookieIndexes} = this.state;
|
||||
|
||||
if (visibleCookieIndexes === null) {
|
||||
return cookieJar.cookies;
|
||||
}
|
||||
|
||||
return cookieJar.cookies.filter((c, i) => visibleCookieIndexes.includes(i));
|
||||
}
|
||||
|
||||
async show () {
|
||||
@ -98,6 +138,9 @@ class CookiesModal extends PureComponent {
|
||||
this.filterInput && this.filterInput.focus();
|
||||
}, 100);
|
||||
|
||||
// make sure the filter is up to date
|
||||
await this._applyFilter(this.state.filter, this.props.cookieJar.cookies);
|
||||
|
||||
this.modal && this.modal.show();
|
||||
trackEvent('Cookie Manager', 'Show');
|
||||
}
|
||||
@ -113,44 +156,42 @@ class CookiesModal extends PureComponent {
|
||||
cookieJar
|
||||
} = this.props;
|
||||
|
||||
if (!cookieJar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
filter
|
||||
} = this.state;
|
||||
|
||||
const filteredCookies = this._getFilteredSortedCookies();
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef} wide tall {...this.props}>
|
||||
<ModalHeader>Manage Cookies</ModalHeader>
|
||||
<ModalBody className="cookie-list" noScroll>
|
||||
<div className="pad">
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>Filter Cookies
|
||||
<input ref={this._setFilterInputRef}
|
||||
onChange={this._handleFilterChange}
|
||||
type="text"
|
||||
placeholder="twitter.com"
|
||||
defaultValue=""/>
|
||||
</label>
|
||||
{cookieJar && (
|
||||
<div>
|
||||
<div className="pad">
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>Filter Cookies
|
||||
<input ref={this._setFilterInputRef}
|
||||
onChange={this._handleFilterChange}
|
||||
type="text"
|
||||
placeholder="twitter.com"
|
||||
defaultValue=""/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cookie-list__list border-top">
|
||||
<div className="pad-top">
|
||||
<CookieList
|
||||
handleShowModifyCookieModal={handleShowModifyCookieModal}
|
||||
handleRender={handleRender}
|
||||
cookies={this._getVisibleCookies()}
|
||||
onCookieAdd={this._handleCookieAdd}
|
||||
onCookieDelete={this._handleCookieDelete}
|
||||
// Set the domain to the filter so that it shows up if we're filtering
|
||||
newCookieDomainName={filter || 'domain.com'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cookie-list__list border-top">
|
||||
<div className="pad-top">
|
||||
<CookieList
|
||||
handleShowModifyCookieModal={handleShowModifyCookieModal}
|
||||
handleRender={handleRender}
|
||||
cookies={filteredCookies}
|
||||
onCookieAdd={this._handleCookieAdd}
|
||||
onCookieDelete={this._handleCookieDelete}
|
||||
// Set the domain to the filter so that it shows up if we're filtering
|
||||
newCookieDomainName={filter || 'domain.com'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<div className="margin-left faint italic txt-sm tall">
|
||||
|
3
flow-typed/deep-equal.js
vendored
Normal file
3
flow-typed/deep-equal.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare module 'deep-equal' {
|
||||
declare module.exports: Function
|
||||
}
|
Loading…
Reference in New Issue
Block a user