Rewrote broken PDF viewer

This commit is contained in:
Gregory Schier 2017-10-12 19:32:26 +02:00
parent 6ca5204961
commit 0d56b84c21
13 changed files with 247 additions and 162 deletions

View File

@ -11,8 +11,4 @@ describe('package.json', () => {
expect(`${name}::${actual}`).toBe(`${name}::${expected}`); expect(`${name}::${actual}`).toBe(`${name}::${expected}`);
} }
}); });
it('pdfjs should not be in deps', () => {
expect(appPackage.dependencies['simple-react-pdf']).toBeUndefined();
});
}); });

View File

@ -1,7 +1,7 @@
import * as google from './google'; import * as google from './google';
import * as models from '../models'; import * as models from '../models';
import {ipcRenderer} from 'electron'; import {ipcRenderer} from 'electron';
import {getAppVersion, getAppPlatform} from '../common/constants'; import {getAppVersion, getAppPlatform, isDevelopment} from '../common/constants';
let initialized = false; let initialized = false;
export async function init (accountId) { export async function init (accountId) {
@ -24,7 +24,7 @@ export async function init (accountId) {
trackEvent(...args); trackEvent(...args);
}); });
if (window) { if (window && !isDevelopment()) {
window.addEventListener('error', e => { window.addEventListener('error', e => {
trackEvent('Error', 'Uncaught Error'); trackEvent('Error', 'Uncaught Error');
console.error('Uncaught Error', e); console.error('Uncaught Error', e);

View File

@ -13,15 +13,15 @@ describe('buildMultipart()', () => {
expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY'); expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY');
expect(body.toString()).toBe([ expect(body.toString()).toBe([
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="foo"', 'Content-Disposition: form-data; name="foo"',
'', '',
'bar', 'bar',
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="multi-line"', 'Content-Disposition: form-data; name="multi-line"',
'', '',
'Hello\nWorld!', 'Hello\nWorld!',
`${boundary}--`, `--${boundary}--`,
'' ''
].join('\r\n')); ].join('\r\n'));
}); });
@ -36,20 +36,20 @@ describe('buildMultipart()', () => {
expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY'); expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY');
expect(body.toString()).toBe([ expect(body.toString()).toBe([
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="foo"', 'Content-Disposition: form-data; name="foo"',
'', '',
'bar', 'bar',
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="file"; filename="testfile.txt"', 'Content-Disposition: form-data; name="file"; filename="testfile.txt"',
'Content-Type: text/plain', 'Content-Type: text/plain',
'', '',
'Hello World!\n\nHow are you?', 'Hello World!\n\nHow are you?',
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="baz"', 'Content-Disposition: form-data; name="baz"',
'', '',
'qux', 'qux',
`${boundary}--`, `--${boundary}--`,
'' ''
].join('\r\n')); ].join('\r\n'));
}); });
@ -64,15 +64,15 @@ describe('buildMultipart()', () => {
expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY'); expect(boundary).toBe('------------------------X-INSOMNIA-BOUNDARY');
expect(body.toString()).toBe([ expect(body.toString()).toBe([
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name=""', 'Content-Disposition: form-data; name=""',
'', '',
'bar', 'bar',
`${boundary}`, `--${boundary}`,
'Content-Disposition: form-data; name="foo"', 'Content-Disposition: form-data; name="foo"',
'', '',
'', '',
`${boundary}--`, `--${boundary}--`,
'' ''
].join('\r\n')); ].join('\r\n'));
}); });

View File

@ -1,8 +1,9 @@
import * as networkUtils from '../network'; import * as networkUtils from '../network';
import fs from 'fs';
import {join as pathJoin, resolve as pathResolve} from 'path'; import {join as pathJoin, resolve as pathResolve} from 'path';
import {getRenderedRequest} from '../../common/render'; import {getRenderedRequest} from '../../common/render';
import * as models from '../../models'; import * as models from '../../models';
import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_URLENCODED, getAppVersion} from '../../common/constants'; import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion} from '../../common/constants';
import {filterHeaders} from '../../common/misc'; import {filterHeaders} from '../../common/misc';
import {globalBeforeEach} from '../../__jest__/before-each'; import {globalBeforeEach} from '../../__jest__/before-each';
@ -281,74 +282,74 @@ describe('actuallySend()', () => {
}); });
}); });
// it('sends multipart form data', async () => { it('sends multipart form data', async () => {
// const workspace = await models.workspace.create(); const workspace = await models.workspace.create();
// const settings = await models.settings.create(); const settings = await models.settings.create();
// await models.cookieJar.create({parentId: workspace._id}); await models.cookieJar.create({parentId: workspace._id});
// const fileName = pathResolve(pathJoin(__dirname, './testfile.txt')); const fileName = pathResolve(pathJoin(__dirname, './testfile.txt'));
//
// const request = Object.assign(models.request.init(), { const request = Object.assign(models.request.init(), {
// _id: 'req_123', _id: 'req_123',
// parentId: workspace._id, parentId: workspace._id,
// headers: [{name: 'Content-Type', value: 'multipart/form-data'}], headers: [{name: 'Content-Type', value: 'multipart/form-data'}],
// url: 'http://localhost', url: 'http://localhost',
// method: 'POST', method: 'POST',
// body: { body: {
// mimeType: CONTENT_TYPE_FORM_DATA, mimeType: CONTENT_TYPE_FORM_DATA,
// params: [ params: [
// // Should ignore value and send the file since type is set to file // Should ignore value and send the file since type is set to file
// {name: 'foo', fileName: fileName, value: 'bar', type: 'file'}, {name: 'foo', fileName: fileName, value: 'bar', type: 'file'},
//
// // Some extra params // Some extra params
// {name: 'a', value: 'AA'}, {name: 'a', value: 'AA'},
// {name: 'baz', value: 'qux', disabled: true} {name: 'baz', value: 'qux', disabled: true}
// ] ]
// } }
// }); });
//
// const renderedRequest = await getRenderedRequest(request); const renderedRequest = await getRenderedRequest(request);
// const {bodyBuffer} = await networkUtils._actuallySend( const {bodyBuffer} = await networkUtils._actuallySend(
// renderedRequest, renderedRequest,
// workspace, workspace,
// settings settings
// ); );
// const body = JSON.parse(bodyBuffer); const body = JSON.parse(bodyBuffer);
// expect(body.meta.READFUNCTION_VALUE).toBe([ expect(body.meta.READFUNCTION_VALUE).toBe([
// '------------------------X-INSOMNIA-BOUNDARY', '--------------------------X-INSOMNIA-BOUNDARY',
// 'Content-Disposition: form-data; name="foo"; filename="testfile.txt"', 'Content-Disposition: form-data; name="foo"; filename="testfile.txt"',
// 'Content-Type: text/plain', 'Content-Type: text/plain',
// '', '',
// fs.readFileSync(fileName), fs.readFileSync(fileName),
// '------------------------X-INSOMNIA-BOUNDARY', '--------------------------X-INSOMNIA-BOUNDARY',
// 'Content-Disposition: form-data; name="a"', 'Content-Disposition: form-data; name="a"',
// '', '',
// 'AA', 'AA',
// '------------------------X-INSOMNIA-BOUNDARY--', '--------------------------X-INSOMNIA-BOUNDARY--',
// '' ''
// ].join('\r\n')); ].join('\r\n'));
//
// expect(body.options).toEqual({ expect(body.options).toEqual({
// POST: 1, POST: 1,
// ACCEPT_ENCODING: '', ACCEPT_ENCODING: '',
// COOKIEFILE: '', COOKIEFILE: '',
// FOLLOWLOCATION: true, FOLLOWLOCATION: true,
// MAXREDIRS: -1, MAXREDIRS: -1,
// CUSTOMREQUEST: 'POST', CUSTOMREQUEST: 'POST',
// HTTPHEADER: [ HTTPHEADER: [
// 'Content-Type: multipart/form-data; boundary=------------------------X-INSOMNIA-BOUNDARY', 'Content-Type: multipart/form-data; boundary=------------------------X-INSOMNIA-BOUNDARY',
// 'Expect: ', 'Expect: ',
// 'Transfer-Encoding: ' 'Transfer-Encoding: '
// ], ],
// INFILESIZE_LARGE: 310, INFILESIZE_LARGE: 316,
// NOPROGRESS: false, NOPROGRESS: false,
// PROXY: '', PROXY: '',
// TIMEOUT_MS: 0, TIMEOUT_MS: 0,
// URL: 'http://localhost/', URL: 'http://localhost/',
// UPLOAD: 1, UPLOAD: 1,
// USERAGENT: `insomnia/${getAppVersion()}`, USERAGENT: `insomnia/${getAppVersion()}`,
// VERBOSE: true VERBOSE: true
// }); });
// }); });
it('uses unix socket', async () => { it('uses unix socket', async () => {
const workspace = await models.workspace.create(); const workspace = await models.workspace.create();

View File

@ -11,7 +11,7 @@ export function buildMultipart (params: Array<RequestBodyParameter>): {boundary:
const add = (v: Buffer | string) => { const add = (v: Buffer | string) => {
if (typeof v === 'string') { if (typeof v === 'string') {
buffers.push(Buffer.from(v, 'utf8')); buffers.push(Buffer.from(v));
} else { } else {
buffers.push(v); buffers.push(v);
} }
@ -25,7 +25,7 @@ export function buildMultipart (params: Array<RequestBodyParameter>): {boundary:
continue; continue;
} }
add(`${boundary}`); add(`--${boundary}`);
add(lineBreak); add(lineBreak);
if (param.type === 'file' && param.fileName) { if (param.type === 'file' && param.fileName) {
@ -54,7 +54,7 @@ export function buildMultipart (params: Array<RequestBodyParameter>): {boundary:
add(lineBreak); add(lineBreak);
} }
add(`${boundary}--`); add(`--${boundary}--`);
add(lineBreak); add(lineBreak);
const body = Buffer.concat(buffers); const body = Buffer.concat(buffers);

View File

@ -15,9 +15,8 @@ import {join as pathJoin} from 'path';
import * as models from '../models'; import * as models from '../models';
import * as querystring from '../common/querystring'; import * as querystring from '../common/querystring';
import * as util from '../common/misc.js'; import * as util from '../common/misc.js';
import mimes from 'mime-types';
import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, STATUS_CODE_PLUGIN_ERROR} from '../common/constants'; import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, STATUS_CODE_PLUGIN_ERROR} from '../common/constants';
import {describeByteSize, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, setDefaultProtocol} from '../common/misc'; import {describeByteSize, getContentTypeHeader, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, setDefaultProtocol} from '../common/misc';
import fs from 'fs'; import fs from 'fs';
import * as db from '../common/database'; import * as db from '../common/database';
import * as CACerts from './cacert'; import * as CACerts from './cacert';
@ -27,6 +26,7 @@ import {getAuthHeader} from './authentication';
import {cookiesFromJar, jarFromCookies} from '../common/cookies'; import {cookiesFromJar, jarFromCookies} from '../common/cookies';
import {urlMatchesCertHost} from './url-matches-cert-host'; import {urlMatchesCertHost} from './url-matches-cert-host';
import aws4 from 'aws4'; import aws4 from 'aws4';
import {buildMultipart} from './multipart';
export type ResponsePatch = { export type ResponsePatch = {
statusMessage?: string, statusMessage?: string,
@ -389,15 +389,34 @@ export function _actuallySend (
requestBody = querystring.buildFromParams(renderedRequest.body.params || [], false); requestBody = querystring.buildFromParams(renderedRequest.body.params || [], false);
} else if (renderedRequest.body.mimeType === CONTENT_TYPE_FORM_DATA) { } else if (renderedRequest.body.mimeType === CONTENT_TYPE_FORM_DATA) {
const params = renderedRequest.body.params || []; const params = renderedRequest.body.params || [];
const data = params.map(param => { const {body: multipartBody, boundary} = buildMultipart(params);
if (param.type === 'file' && param.fileName) {
const type = mimes.lookup(param.fileName) || 'application/octet-stream'; // Extend the Content-Type header
return {name: param.name, file: param.fileName, type}; const contentTypeHeader = getContentTypeHeader(headers);
} else { if (contentTypeHeader) {
return {name: param.name, contents: param.value}; contentTypeHeader.value = `multipart/form-data; boundary=${boundary}`;
} else {
headers.push({
name: 'Content-Type',
value: `multipart/form-data; boundary=${boundary}`
});
}
setOpt(Curl.option.UPLOAD, 1);
setOpt(Curl.option.INFILESIZE_LARGE, multipartBody.length);
// We need this, otherwise curl will send it as a PUT
setOpt(Curl.option.CUSTOMREQUEST, renderedRequest.method);
let bytesUploaded = 0;
curl.setOpt(Curl.option.READFUNCTION, function (buffer, size, nmemb) {
if (bytesUploaded >= multipartBody.length || size === 0 || nmemb === 0) {
return 0;
} }
const wrote = multipartBody.copy(buffer, 0, bytesUploaded);
bytesUploaded += wrote;
return wrote;
}); });
setOpt(Curl.option.HTTPPOST, data);
} else if (renderedRequest.body.fileName) { } else if (renderedRequest.body.fileName) {
const {size} = fs.statSync(renderedRequest.body.fileName); const {size} = fs.statSync(renderedRequest.body.fileName);
const fileName = renderedRequest.body.fileName || ''; const fileName = renderedRequest.body.fileName || '';

View File

@ -0,0 +1,112 @@
// @flow
import * as React from 'react';
import autobind from 'autobind-decorator';
import PDF from 'pdfjs-dist/webpack';
type Props = {
body: Buffer,
uniqueKey: string
};
type State = {
numPages: number | null;
};
@autobind
class PDFViewer extends React.PureComponent<Props, State> {
container: ?HTMLDivElement;
debounceTimeout: any;
setRef (n: ?HTMLDivElement) {
this.container = n;
}
loadPDF () {
clearTimeout(this.debounceTimeout);
this.debounceTimeout = setTimeout(async () => {
// get node for this react component
const container = this.container;
if (!container) {
return;
}
container.innerHTML = '';
const containerWidth = container.clientWidth;
const pdf = await PDF.getDocument({data: this.props.body.toString('binary')});
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const density = window.devicePixelRatio || 1;
const {width: pdfWidth, height: pdfHeight} = page.getViewport(1);
const ratio = pdfHeight / pdfWidth;
const scale = containerWidth / pdfWidth;
const viewport = page.getViewport(scale * density);
// set canvas for page
const canvas = document.createElement('canvas');
canvas.width = containerWidth * density;
// canvas.height = containerWidth * (viewport.height / viewport.width);
canvas.height = containerWidth * ratio * density;
canvas.style.width = `${containerWidth}px`;
canvas.style.height = `${containerWidth * ratio}px`;
container.appendChild(canvas);
// get context and render page
const context = canvas.getContext('2d');
const renderContext = {
id: `${this.props.uniqueKey}.${i}`,
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
}
}, 100);
}
handleResize (e: SyntheticEvent<HTMLDivElement>) {
if (!this.container) {
return;
}
clearTimeout(this.debounceTimeout);
this.debounceTimeout = setTimeout(this.loadPDF, 300);
}
componentDidUpdate () {
this.loadPDF();
}
componentDidMount () {
this.loadPDF();
window.addEventListener('resize', this.handleResize);
}
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize);
}
render () {
const styles = {
width: '100%',
height: '100%',
overflowX: 'hidden',
overflowY: 'scroll',
padding: '0px'
};
return (
<div className="S-PDF-ID" ref={this.setRef} style={styles}>
<div className="faded text-center vertically-center tall">
Loading PDF...
</div>
</div>
);
}
}
export default PDFViewer;

View File

@ -281,6 +281,7 @@ class ResponsePane extends React.PureComponent<Props> {
<ResponseViewer <ResponseViewer
key={response._id} key={response._id}
// Send larger one because legacy responses have bytesContent === -1 // Send larger one because legacy responses have bytesContent === -1
responseId={response._id}
bytes={Math.max(response.bytesContent, response.bytesRead)} bytes={Math.max(response.bytesContent, response.bytesRead)}
contentType={response.contentType || ''} contentType={response.contentType || ''}
previewMode={response.error ? PREVIEW_MODE_SOURCE : previewMode} previewMode={response.error ? PREVIEW_MODE_SOURCE : previewMode}

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import iconv from 'iconv-lite'; import iconv from 'iconv-lite';
import autobind from 'autobind-decorator'; import autobind from 'autobind-decorator';
import {shell} from 'electron'; import {shell} from 'electron';
import {SimplePDF} from 'simple-react-pdf'; import PDFViewer from '../pdf-viewer';
import CodeEditor from '../codemirror/code-editor'; import CodeEditor from '../codemirror/code-editor';
import ResponseWebView from './response-webview'; import ResponseWebView from './response-webview';
import ResponseRaw from './response-raw'; import ResponseRaw from './response-raw';
@ -113,6 +113,7 @@ class ResponseViewer extends React.Component {
editorIndentSize, editorIndentSize,
editorKeyMap, editorKeyMap,
updateFilter, updateFilter,
responseId,
url, url,
error error
} = this.props; } = this.props;
@ -214,11 +215,9 @@ class ResponseViewer extends React.Component {
/> />
); );
} else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('application/pdf') === 0) { } else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('application/pdf') === 0) {
const justContentType = contentType.split(';')[0];
const base64Body = bodyBuffer.toString('base64');
return ( return (
<div className="tall wide scrollable"> <div className="tall wide scrollable">
<SimplePDF file={`data:${justContentType};base64,${base64Body}`}/> <PDFViewer body={bodyBuffer} uniqueKey={responseId}/>
</div> </div>
); );
} else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('audio/') === 0) { } else if (previewMode === PREVIEW_MODE_FRIENDLY && ct.indexOf('audio/') === 0) {
@ -277,6 +276,7 @@ class ResponseViewer extends React.Component {
ResponseViewer.propTypes = { ResponseViewer.propTypes = {
getBody: PropTypes.func.isRequired, getBody: PropTypes.func.isRequired,
responseId: PropTypes.string.isRequired,
previewMode: PropTypes.string.isRequired, previewMode: PropTypes.string.isRequired,
filter: PropTypes.string.isRequired, filter: PropTypes.string.isRequired,
filterHistory: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, filterHistory: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,

View File

@ -1,3 +0,0 @@
declare module 'form-data/lib/form_data' {
declare module.exports: *
}

3
flow-typed/pdfjs-dist.js vendored Normal file
View File

@ -0,0 +1,3 @@
declare module 'pdfjs-dist/webpack' {
declare module.exports: *
}

67
package-lock.json generated
View File

@ -2421,16 +2421,6 @@
"sha.js": "2.4.8" "sha.js": "2.4.8"
} }
}, },
"create-react-class": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.2.tgz",
"integrity": "sha1-zx7RXxKq1/FO9fLf4F5sQvke8Co=",
"requires": {
"fbjs": "0.8.12",
"loose-envify": "1.3.1",
"object-assign": "4.1.1"
}
},
"cross-env": { "cross-env": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-2.0.0.tgz", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-2.0.0.tgz",
@ -9449,12 +9439,12 @@
"dev": true "dev": true
}, },
"pdfjs-dist": { "pdfjs-dist": {
"version": "1.8.618", "version": "1.9.640",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.8.618.tgz", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.9.640.tgz",
"integrity": "sha1-/Cx235u3SZafqj79ARWqrIcd0fE=", "integrity": "sha1-8EOFg2R9d2nGGXHE+cfi+m4Qdjo=",
"requires": { "requires": {
"node-ensure": "0.0.0", "node-ensure": "0.0.0",
"worker-loader": "0.8.1" "worker-loader": "1.0.0"
} }
}, },
"pend": { "pend": {
@ -11134,13 +11124,13 @@
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
"requires": { "requires": {
"ajv": "5.2.2" "ajv": "5.2.3"
}, },
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "5.2.2", "version": "5.2.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz",
"integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=",
"requires": { "requires": {
"co": "4.6.0", "co": "4.6.0",
"fast-deep-equal": "1.0.0", "fast-deep-equal": "1.0.0",
@ -11330,41 +11320,6 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
}, },
"simple-react-pdf": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/simple-react-pdf/-/simple-react-pdf-1.0.8.tgz",
"integrity": "sha1-QtlNWMyxxSJ84snpISuWiE2fItQ=",
"requires": {
"pdfjs-dist": "1.8.618",
"react": "15.6.2",
"react-dom": "15.6.2"
},
"dependencies": {
"react": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz",
"integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=",
"requires": {
"create-react-class": "15.6.2",
"fbjs": "0.8.12",
"loose-envify": "1.3.1",
"object-assign": "4.1.1",
"prop-types": "15.5.10"
}
},
"react-dom": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz",
"integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=",
"requires": {
"fbjs": "0.8.12",
"loose-envify": "1.3.1",
"object-assign": "4.1.1",
"prop-types": "15.5.10"
}
}
}
},
"single-line-log": { "single-line-log": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz",
@ -13394,9 +13349,9 @@
} }
}, },
"worker-loader": { "worker-loader": {
"version": "0.8.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.8.1.tgz", "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-1.0.0.tgz",
"integrity": "sha1-6OmVMx6jTfW/aCloJL+38K1XjUM=", "integrity": "sha512-dUwgs4Rdi1qG3VciM1+EPgAoO8m9USpCXxE3xmpWrnHJSMKGkzpCUNeYLjBRgYcSkf2A5xnXpR450Wqtu+pq0w==",
"requires": { "requires": {
"loader-utils": "1.1.0", "loader-utils": "1.1.0",
"schema-utils": "0.3.0" "schema-utils": "0.3.0"

View File

@ -43,7 +43,8 @@
"./__jest__/setup.js" "./__jest__/setup.js"
], ],
"moduleNameMapper": { "moduleNameMapper": {
"\\.(css|less|png)$": "<rootDir>/__mocks__/dummy.js" "\\.(css|less|png)$": "<rootDir>/__mocks__/dummy.js",
"^worker-loader!": "<rootDir>/__mocks__/dummy.js"
}, },
"testMatch": [ "testMatch": [
"**/__tests__/**/*.test.js?(x)" "**/__tests__/**/*.test.js?(x)"
@ -142,6 +143,7 @@
"nedb": "^1.8.0", "nedb": "^1.8.0",
"node-forge": "^0.7.0", "node-forge": "^0.7.0",
"nunjucks": "^3.0.0", "nunjucks": "^3.0.0",
"pdfjs-dist": "^1.9.640",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react": "^16.0.0", "react": "^16.0.0",
"react-dnd": "^2.4.0", "react-dnd": "^2.4.0",
@ -152,7 +154,6 @@
"redux": "^3.7.2", "redux": "^3.7.2",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"reselect": "^3.0.1", "reselect": "^3.0.1",
"simple-react-pdf": "^1.0.8",
"srp-js": "^0.2.0", "srp-js": "^0.2.0",
"tar": "^3.1.7", "tar": "^3.1.7",
"tough-cookie": "^2.3.1", "tough-cookie": "^2.3.1",