mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 23:00:30 +00:00
42341e6e6e
* readability improvements and reduced indirection * adds type for handleShowModifyCookieModal * correctly types wrapperProps property, thereby fixing bug. if you add `console.log({ previewHidden, propsOne: this.props.wrapperProps.activeWorkspaceMeta });` to the third line of `_renderPreview()` you'll see that `activeWorkspaceMeta` is indeed, sometimes, `undefined. Also, there's no reason to use `await` on `this.setState`. I didn't find any more of these in the codebase, I just found this one. * adds type for swaggerUiSpec * undoes lifting props to state almost always, this is done for performance reasons, but I removed it the app is working pretty quick-and-snappy for me without needing to introduced duplicated application state and keep track of it. I went ahead and measured it before and after this commit (using performance.now): before = [ 1.93500000750646, 1.149999996414408, 0.9499999869149178, 0.9950000094249845, 0.8650000090710819, 1.560000004246831, 1.5699999930802733, 0.8450000023003668, 1.4550000196322799, 1.3299999991431832, 1.3050000125076622, 1.4099999971222132, 1.3099999923724681, 1.3100000214762986, 1.1999999987892807, 1.0099999781232327, 0.830000004498288, 1.2449999921955168, 1.2500000011641532, 1.4349999837577343, ] after = [ 2.9400000057648867, 2.449999999953434, 2.33499999740161, 2.2849999950267375, 1.7700000025797635, 1.8149999959859997, 2.1249999990686774, 1.9150000007357448, 2.074999996693805, 1.9899999897461385, 2.0200000144541264, 2.869999996619299, 2.1450000058393925, 2.33499999740161, 2.130000008037314, 2.119999990100041, 2.144999976735562, 2.130000008037314, 2.380000009201467, 2.8999999922234565, ] > R.mean(before) > 1.2480000004870817 > R.mean(after) > 2.243749999080319 > R.median(before) > 1.2775000068359077 > R.median(after) > 2.137499992386438 So basically, considering a 16ms render rate (i.e. 60hz), 1ms saved by lifting props to state makes no difference in application performance. This is committed separately so that if there's any reason we want to keep the prior implementation, we can just still do so.
209 lines
6.1 KiB
TypeScript
209 lines
6.1 KiB
TypeScript
import React, { ChangeEvent, PureComponent } from 'react';
|
|
import deepEqual from 'deep-equal';
|
|
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
|
import { AUTOBIND_CFG } from '../../../common/constants';
|
|
import Modal, { ModalProps } from '../base/modal';
|
|
import ModalBody from '../base/modal-body';
|
|
import ModalHeader from '../base/modal-header';
|
|
import ModalFooter from '../base/modal-footer';
|
|
import CookieList, { CookieListProps } from '../cookie-list';
|
|
import * as models from '../../../models';
|
|
import type { Cookie, CookieJar } from '../../../models/cookie-jar';
|
|
import type { Workspace } from '../../../models/workspace';
|
|
import { fuzzyMatch } from '../../../common/misc';
|
|
import { HandleRender } from '../../../common/render';
|
|
|
|
interface Props extends ModalProps {
|
|
handleShowModifyCookieModal: CookieListProps['handleShowModifyCookieModal'];
|
|
handleRender: HandleRender;
|
|
cookieJar: CookieJar;
|
|
workspace: Workspace;
|
|
}
|
|
|
|
interface State {
|
|
filter: string;
|
|
visibleCookieIndexes: number[] | null;
|
|
}
|
|
|
|
@autoBindMethodsForReact(AUTOBIND_CFG)
|
|
class CookiesModal extends PureComponent<Props, State> {
|
|
modal: Modal | null = null;
|
|
filterInput: HTMLInputElement | null = null;
|
|
|
|
state: State = {
|
|
filter: '',
|
|
visibleCookieIndexes: null,
|
|
}
|
|
|
|
_setModalRef(n: Modal) {
|
|
this.modal = n;
|
|
}
|
|
|
|
_setFilterInputRef(n: HTMLInputElement) {
|
|
this.filterInput = n;
|
|
}
|
|
|
|
async _saveChanges() {
|
|
const { cookieJar } = this.props;
|
|
await models.cookieJar.update(cookieJar);
|
|
}
|
|
|
|
async _handleCookieAdd(cookie: Cookie) {
|
|
const { cookieJar } = this.props;
|
|
const { cookies } = cookieJar;
|
|
cookieJar.cookies = [cookie, ...cookies];
|
|
await this._saveChanges();
|
|
}
|
|
|
|
async _handleDeleteAllCookies() {
|
|
const { cookieJar } = this.props;
|
|
cookieJar.cookies = [];
|
|
await this._saveChanges();
|
|
}
|
|
|
|
async _handleCookieDelete(cookie: Cookie) {
|
|
const { cookieJar } = this.props;
|
|
const { cookies } = cookieJar;
|
|
// NOTE: This is sketchy because it relies on the same reference
|
|
cookieJar.cookies = cookies.filter(c => c.id !== cookie.id);
|
|
await this._saveChanges();
|
|
}
|
|
|
|
async _handleFilterChange(e: ChangeEvent<HTMLInputElement>) {
|
|
if (!(e.target instanceof HTMLInputElement)) {
|
|
return;
|
|
}
|
|
|
|
const filter = e.target.value;
|
|
|
|
this._applyFilter(filter, this.props.cookieJar.cookies);
|
|
}
|
|
|
|
// eslint-disable-next-line camelcase
|
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
|
// Re-filter if we received new cookies
|
|
// Compare cookies with Dates cast to strings
|
|
const sameCookies = deepEqual(this.props.cookieJar.cookies, nextProps.cookieJar.cookies);
|
|
|
|
if (!sameCookies) {
|
|
this._applyFilter(this.state.filter, nextProps.cookieJar.cookies);
|
|
}
|
|
}
|
|
|
|
async _applyFilter(filter: string, cookies: Cookie[]) {
|
|
const renderedCookies: Cookie[] = [];
|
|
|
|
for (const cookie of cookies) {
|
|
try {
|
|
const renderedCookie = await this.props.handleRender(cookie);
|
|
renderedCookies.push(renderedCookie);
|
|
} catch (err) {
|
|
// It's okay. Filter the raw version instead
|
|
renderedCookies.push(cookie);
|
|
}
|
|
}
|
|
|
|
let visibleCookieIndexes;
|
|
|
|
if (filter) {
|
|
visibleCookieIndexes = [];
|
|
|
|
for (let i = 0; i < renderedCookies.length; i++) {
|
|
const toSearch = JSON.stringify(renderedCookies[i]);
|
|
const match = fuzzyMatch(filter, toSearch, {
|
|
splitSpace: true,
|
|
});
|
|
|
|
if (match) {
|
|
visibleCookieIndexes.push(i);
|
|
}
|
|
}
|
|
} else {
|
|
visibleCookieIndexes = null;
|
|
}
|
|
|
|
this.setState({
|
|
filter,
|
|
visibleCookieIndexes,
|
|
});
|
|
}
|
|
|
|
_getVisibleCookies(): Cookie[] {
|
|
const { cookieJar } = this.props;
|
|
const { visibleCookieIndexes } = this.state;
|
|
|
|
if (visibleCookieIndexes === null) {
|
|
return cookieJar.cookies;
|
|
}
|
|
|
|
return cookieJar.cookies.filter((_, i) => visibleCookieIndexes.includes(i));
|
|
}
|
|
|
|
async show() {
|
|
setTimeout(() => {
|
|
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();
|
|
}
|
|
|
|
hide() {
|
|
this.modal && this.modal.hide();
|
|
}
|
|
|
|
render() {
|
|
const { handleShowModifyCookieModal, handleRender, cookieJar } = this.props;
|
|
const { filter } = this.state;
|
|
|
|
const cookies = this._getVisibleCookies();
|
|
|
|
return (
|
|
<Modal ref={this._setModalRef} wide tall {...this.props}>
|
|
<ModalHeader>Manage Cookies</ModalHeader>
|
|
<ModalBody noScroll>
|
|
{cookieJar && (
|
|
<div className="cookie-list">
|
|
<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-tops pad">
|
|
<CookieList
|
|
cookies={cookies}
|
|
handleShowModifyCookieModal={handleShowModifyCookieModal}
|
|
handleRender={handleRender}
|
|
handleDeleteAll={this._handleDeleteAllCookies}
|
|
handleCookieAdd={this._handleCookieAdd}
|
|
handleCookieDelete={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">
|
|
* cookies are automatically sent with relevant requests
|
|
</div>
|
|
<button className="btn" onClick={this.hide}>
|
|
Done
|
|
</button>
|
|
</ModalFooter>
|
|
</Modal>
|
|
);
|
|
}
|
|
} // export CookiesModal;
|
|
|
|
export default CookiesModal;
|