aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--web/package.json1
-rw-r--r--web/src/js/__tests__/components/ContentView/ContentLoaderSpec.js74
-rw-r--r--web/src/js/__tests__/components/ContentView/ContentViewSpec.js85
-rw-r--r--web/src/js/__tests__/components/ContentView/DownloadContentButtonSpec.js15
-rw-r--r--web/src/js/__tests__/components/ContentView/MetaViewsSpec.js37
-rw-r--r--web/src/js/__tests__/components/ContentView/ShowFullContentButtonSpec.js39
-rw-r--r--web/src/js/__tests__/components/ContentView/UploadContentButtonSpec.js12
-rw-r--r--web/src/js/__tests__/components/ContentView/ViewSelectorSpec.js38
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/ContentLoaderSpec.js.snap11
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewSpec.js.snap52
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/DownloadContentButtonSpec.js.snap13
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/MetaViewsSpec.js.snap66
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/ShowFullContentButtonSpec.js.snap25
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/UploadContentButtonSpec.js.snap19
-rw-r--r--web/src/js/__tests__/components/ContentView/__snapshots__/ViewSelectorSpec.js.snap123
-rw-r--r--web/src/js/components/ContentView/ContentLoader.jsx156
-rw-r--r--web/src/js/components/ContentView/ContentViews.jsx6
-rw-r--r--web/src/js/components/ContentView/DownloadContentButton.jsx1
-rw-r--r--web/src/js/components/ContentView/ShowFullContentButton.jsx2
-rw-r--r--web/src/js/components/ContentView/UploadContentButton.jsx1
-rw-r--r--web/src/js/components/ContentView/ViewSelector.jsx2
-rw-r--r--web/yarn.lock4
22 files changed, 700 insertions, 82 deletions
diff --git a/web/package.json b/web/package.json
index 94b0ee60..a4ef0f29 100644
--- a/web/package.json
+++ b/web/package.json
@@ -26,6 +26,7 @@
"bootstrap": "^3.3.7",
"classnames": "^2.2.5",
"lodash": "^4.17.4",
+ "mock-xmlhttprequest": "^1.1.0",
"prop-types": "^15.5.0",
"react": "^15.4.2",
"react-codemirror": "^0.3.0",
diff --git a/web/src/js/__tests__/components/ContentView/ContentLoaderSpec.js b/web/src/js/__tests__/components/ContentView/ContentLoaderSpec.js
new file mode 100644
index 00000000..80b40c72
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/ContentLoaderSpec.js
@@ -0,0 +1,74 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import withContentLoader from '../../../components/ContentView/ContentLoader'
+import { TFlow } from '../../ducks/tutils'
+import TestUtils from 'react-dom/test-utils'
+import mockXMLHttpRequest from 'mock-xmlhttprequest'
+
+global.XMLHttpRequest = mockXMLHttpRequest
+class tComponent extends React.Component {
+ constructor(props, context){
+ super(props, context)
+ }
+ render() {
+ return (<p>foo</p>)
+ }
+}
+
+let tflow = new TFlow(),
+ ContentLoader = withContentLoader(tComponent)
+
+describe('ContentLoader Component', () => {
+ it('should render correctly', () => {
+ let contentLoader = renderer.create(<ContentLoader flow={tflow} message={tflow.response}/>),
+ tree = contentLoader.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ let contentLoader = TestUtils.renderIntoDocument(<ContentLoader flow={tflow} message={tflow.response}/>)
+
+ it('should handle updateContent', () => {
+ tflow.response.content = 'foo'
+ contentLoader.updateContent({flow: tflow, message: tflow.response})
+ expect(contentLoader.state.request).toEqual(undefined)
+ expect(contentLoader.state.content).toEqual('foo')
+ // when content length is 0 or null
+ tflow.response.contentLength = 0
+ tflow.response.content = undefined
+ contentLoader.updateContent({flow: tflow, message: tflow.response})
+ expect(contentLoader.state.request).toEqual(undefined)
+ expect(contentLoader.state.content).toEqual('')
+ })
+
+ it('should handle componentWillReceiveProps', () => {
+ contentLoader.updateContent = jest.fn()
+ contentLoader.componentWillReceiveProps({flow: tflow, message: tflow.request})
+ expect(contentLoader.updateContent).toBeCalled()
+ })
+
+ it('should handle requestComplete', () => {
+ expect(contentLoader.requestComplete(tflow.request, {})).toEqual(undefined)
+ // request == this.state.request
+ contentLoader.state.request = tflow.request
+ contentLoader.requestComplete(tflow.request, {})
+ expect(contentLoader.state.content).toEqual(tflow.request.responseText)
+ expect(contentLoader.state.request).toEqual(undefined)
+ })
+
+ it('should handle requestFailed', () => {
+ console.error = jest.fn()
+ expect(contentLoader.requestFailed(tflow.request, {})).toEqual(undefined)
+ //request == this.state.request
+ contentLoader.state.request = tflow.request
+ contentLoader.requestFailed(tflow.request, 'foo error')
+ expect(contentLoader.state.content).toEqual('Error getting content.')
+ expect(contentLoader.state.request).toEqual(undefined)
+ expect(console.error).toBeCalledWith('foo error')
+ })
+
+ it('should handle componentWillUnmount', () => {
+ contentLoader.state.request = { abort : jest.fn() }
+ contentLoader.componentWillUnmount()
+ expect(contentLoader.state.request.abort).toBeCalled()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/ContentViewSpec.js b/web/src/js/__tests__/components/ContentView/ContentViewSpec.js
new file mode 100644
index 00000000..f519185d
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/ContentViewSpec.js
@@ -0,0 +1,85 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import TestUtils from 'react-dom/test-utils'
+import { Provider } from 'react-redux'
+import { ViewServer, ViewImage, PureViewServer, Edit } from '../../../components/ContentView/ContentViews'
+import { TFlow, TStore } from '../../ducks/tutils'
+import mockXMLHttpRequest from 'mock-xmlhttprequest'
+
+global.XMLHttpRequest = mockXMLHttpRequest
+let tflow = new TFlow()
+
+describe('ViewImage Component', () => {
+ let viewImage = renderer.create(<ViewImage flow={tflow} message={tflow.response}/>),
+ tree = viewImage.toJSON()
+
+ it('should render correctly', () => {
+ expect(tree).toMatchSnapshot()
+ })
+})
+
+describe('ViewServer Component', () => {
+ let store = TStore(),
+ setContentViewDescFn = jest.fn(),
+ setContentFn = jest.fn()
+
+ it('should render correctly and connect to state', () => {
+ let provider = renderer.create(
+ <Provider store={store}>
+ <ViewServer
+ setContentViewDescription={setContentViewDescFn}
+ setContent={setContentFn}
+ flow={tflow}
+ message={tflow.response}
+ />
+ </Provider>),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+
+ let viewServer = renderer.create(
+ <PureViewServer
+ showFullContent={true}
+ maxLines={10}
+ setContentViewDescription={setContentViewDescFn}
+ setContent={setContentViewDescFn}
+ flow={tflow}
+ message={tflow.response}
+ content={JSON.stringify({lines: [['k1', 'v1']]})}
+ />
+ )
+ tree = viewServer.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle componentWillReceiveProps', () => {
+ // case of fail to parse content
+ let viewSever = TestUtils.renderIntoDocument(
+ <PureViewServer
+ showFullContent={true}
+ maxLines={10}
+ setContentViewDescription={setContentViewDescFn}
+ setContent={setContentViewDescFn}
+ flow={tflow}
+ message={tflow.response}
+ content={JSON.stringify({lines: [['k1', 'v1']]})}
+ />
+ )
+ viewSever.componentWillReceiveProps({...viewSever.props, content: '{foo' })
+ let e = ''
+ try {JSON.parse('{foo') } catch(err){ e = err.message}
+ expect(viewSever.data).toEqual({ description: e, lines: [] })
+ })
+})
+
+describe('Edit Component', () => {
+ it('should render correctly', () => {
+ let edit = renderer.create(<Edit
+ content="foo"
+ onChange={jest.fn}
+ flow={tflow}
+ message={tflow.response}
+ />),
+ tree = edit.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/DownloadContentButtonSpec.js b/web/src/js/__tests__/components/ContentView/DownloadContentButtonSpec.js
new file mode 100644
index 00000000..fd00627d
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/DownloadContentButtonSpec.js
@@ -0,0 +1,15 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import DownloadContentButton from '../../../components/ContentView/DownloadContentButton'
+import { TFlow } from '../../ducks/tutils'
+
+let tflow = new TFlow()
+describe('DownloadContentButton Component', () => {
+ it('should render correctly', () => {
+ let downloadContentButton = renderer.create(
+ <DownloadContentButton flow={tflow} message={tflow.response}/>
+ ),
+ tree = downloadContentButton.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/MetaViewsSpec.js b/web/src/js/__tests__/components/ContentView/MetaViewsSpec.js
new file mode 100644
index 00000000..26b2a27c
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/MetaViewsSpec.js
@@ -0,0 +1,37 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { ContentEmpty, ContentMissing, ContentTooLarge } from '../../../components/ContentView/MetaViews'
+import { TFlow } from '../../ducks/tutils'
+
+let tflow = new TFlow()
+
+describe('ContentEmpty Components', () => {
+ it('should render correctly', () => {
+ let contentEmpty = renderer.create(<ContentEmpty flow={tflow} message={tflow.response}/>),
+ tree = contentEmpty.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
+
+describe('ContentMissing Components', () => {
+ it('should render correctly', () => {
+ let contentMissing = renderer.create(<ContentMissing flow={tflow} message={tflow.response}/>),
+ tree = contentMissing.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
+
+describe('ContentTooLarge Components', () => {
+ it('should render correctly', () => {
+ let clickFn = jest.fn(),
+ uploadContentFn = jest.fn(),
+ contentTooLarge = renderer.create(<ContentTooLarge
+ flow={tflow}
+ message={tflow.response}
+ onClick={clickFn}
+ uploadContent={uploadContentFn}
+ />),
+ tree = contentTooLarge.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/ShowFullContentButtonSpec.js b/web/src/js/__tests__/components/ContentView/ShowFullContentButtonSpec.js
new file mode 100644
index 00000000..14871f13
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/ShowFullContentButtonSpec.js
@@ -0,0 +1,39 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import { Provider } from 'react-redux'
+import ConnectedComponent, { ShowFullContentButton } from '../../../components/ContentView/ShowFullContentButton'
+import { TStore } from '../../ducks/tutils'
+
+
+describe('ShowFullContentButton Component', () => {
+ let setShowFullContentFn = jest.fn(),
+ showFullContentButton = renderer.create(
+ <ShowFullContentButton
+ setShowFullContent={setShowFullContentFn}
+ showFullContent={false}
+ visibleLines={10}
+ contentLines={20}
+ />
+ ),
+ tree = showFullContentButton.toJSON()
+
+ it('should render correctly', () => {
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle click', () => {
+ tree.children[0].props.onClick()
+ expect(setShowFullContentFn).toBeCalled()
+ })
+
+ it('should connect to state', () => {
+ let store = TStore(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <ConnectedComponent/>
+ </Provider>
+ ),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/UploadContentButtonSpec.js b/web/src/js/__tests__/components/ContentView/UploadContentButtonSpec.js
new file mode 100644
index 00000000..3695be72
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/UploadContentButtonSpec.js
@@ -0,0 +1,12 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import UploadContentButton from '../../../components/ContentView/UploadContentButton'
+
+describe('UpdateContentButton Component', () => {
+ it('should render correctly', () => {
+ let uploadContentFn = jest.fn(),
+ uploadContentButton = renderer.create(<UploadContentButton uploadContent={uploadContentFn}/>),
+ tree = uploadContentButton.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/ViewSelectorSpec.js b/web/src/js/__tests__/components/ContentView/ViewSelectorSpec.js
new file mode 100644
index 00000000..9e87e2f0
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/ViewSelectorSpec.js
@@ -0,0 +1,38 @@
+import React from 'react'
+import renderer from 'react-test-renderer'
+import ConnectedComponent, { ViewSelector } from '../../../components/ContentView/ViewSelector'
+import { Provider } from 'react-redux'
+import { TStore } from '../../ducks/tutils'
+
+
+describe('ViewSelector Component', () => {
+ let contentViews = ['Auto', 'Raw', 'Text'],
+ activeView = 'Auto',
+ setContentViewFn = jest.fn(),
+ viewSelector = renderer.create(
+ <ViewSelector contentViews={contentViews} activeView={activeView} setContentView={setContentViewFn}/>
+ ),
+ tree = viewSelector.toJSON()
+
+ it('should render correctly', () => {
+ expect(tree).toMatchSnapshot()
+ })
+
+ it('should handle click', () => {
+ let mockEvent = { preventDefault: jest.fn() },
+ tab = tree.children[1].children[0].children[1]
+ tab.props.onClick(mockEvent)
+ expect(mockEvent.preventDefault).toBeCalled()
+ })
+
+ it('should connect to state', () => {
+ let store = TStore(),
+ provider = renderer.create(
+ <Provider store={store}>
+ <ConnectedComponent/>
+ </Provider>
+ ),
+ tree = provider.toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/ContentLoaderSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentLoaderSpec.js.snap
new file mode 100644
index 00000000..88d4a380
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentLoaderSpec.js.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ContentLoader Component should render correctly 1`] = `
+<div
+ className="text-center"
+>
+ <i
+ className="fa fa-spinner fa-spin"
+ />
+</div>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewSpec.js.snap
new file mode 100644
index 00000000..a4bc06c5
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/ContentViewSpec.js.snap
@@ -0,0 +1,52 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Edit Component should render correctly 1`] = `
+<div
+ className="text-center"
+>
+ <i
+ className="fa fa-spinner fa-spin"
+ />
+</div>
+`;
+
+exports[`ViewImage Component should render correctly 1`] = `
+<div
+ className="flowview-image"
+>
+ <img
+ alt="preview"
+ className="img-thumbnail"
+ src="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
+ />
+</div>
+`;
+
+exports[`ViewServer Component should render correctly and connect to state 1`] = `
+<div
+ className="text-center"
+>
+ <i
+ className="fa fa-spinner fa-spin"
+ />
+</div>
+`;
+
+exports[`ViewServer Component should render correctly and connect to state 2`] = `
+<div>
+ <pre>
+ <div>
+ <span
+ className="k"
+ >
+ 1
+ </span>
+ <span
+ className="v"
+ >
+ 1
+ </span>
+ </div>
+ </pre>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/DownloadContentButtonSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/DownloadContentButtonSpec.js.snap
new file mode 100644
index 00000000..66900ca4
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/DownloadContentButtonSpec.js.snap
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DownloadContentButton Component should render correctly 1`] = `
+<a
+ className="btn btn-default btn-xs"
+ href="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
+ title="Download the content of the flow."
+>
+ <i
+ className="fa fa-download"
+ />
+</a>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/MetaViewsSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/MetaViewsSpec.js.snap
new file mode 100644
index 00000000..18ec5bba
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/MetaViewsSpec.js.snap
@@ -0,0 +1,66 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ContentEmpty Components should render correctly 1`] = `
+<div
+ className="alert alert-info"
+>
+ No
+ response
+ content.
+</div>
+`;
+
+exports[`ContentMissing Components should render correctly 1`] = `
+<div
+ className="alert alert-info"
+>
+ Response
+ content missing.
+</div>
+`;
+
+exports[`ContentTooLarge Components should render correctly 1`] = `
+<div>
+ <div
+ className="alert alert-warning"
+ >
+ <button
+ className="btn btn-xs btn-warning pull-right"
+ onClick={[Function]}
+ >
+ Display anyway
+ </button>
+ 7b
+ content size.
+ </div>
+ <div
+ className="view-options text-center"
+ >
+ <a
+ className="btn btn-default btn-xs"
+ href="#"
+ onClick={[Function]}
+ title="Upload a file to replace the content."
+ >
+ <i
+ className="fa fa-fw fa-upload"
+ />
+ <input
+ className="hidden"
+ onChange={[Function]}
+ type="file"
+ />
+ </a>
+  
+ <a
+ className="btn btn-default btn-xs"
+ href="/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content"
+ title="Download the content of the flow."
+ >
+ <i
+ className="fa fa-download"
+ />
+ </a>
+ </div>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/ShowFullContentButtonSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/ShowFullContentButtonSpec.js.snap
new file mode 100644
index 00000000..e0532154
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/ShowFullContentButtonSpec.js.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ShowFullContentButton Component should connect to state 1`] = `null`;
+
+exports[`ShowFullContentButton Component should render correctly 1`] = `
+<div>
+ <div
+ className="view-all-content-btn btn-xs btn btn-default"
+ disabled={undefined}
+ onClick={[Function]}
+ title={undefined}
+ >
+ Show full content
+ </div>
+ <span
+ className="pull-right"
+ >
+
+ 10
+ /
+ 20
+ are visible  
+ </span>
+</div>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/UploadContentButtonSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/UploadContentButtonSpec.js.snap
new file mode 100644
index 00000000..f642d731
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/UploadContentButtonSpec.js.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`UpdateContentButton Component should render correctly 1`] = `
+<a
+ className="btn btn-default btn-xs"
+ href="#"
+ onClick={[Function]}
+ title="Upload a file to replace the content."
+>
+ <i
+ className="fa fa-fw fa-upload"
+ />
+ <input
+ className="hidden"
+ onChange={[Function]}
+ type="file"
+ />
+</a>
+`;
diff --git a/web/src/js/__tests__/components/ContentView/__snapshots__/ViewSelectorSpec.js.snap b/web/src/js/__tests__/components/ContentView/__snapshots__/ViewSelectorSpec.js.snap
new file mode 100644
index 00000000..481bd56a
--- /dev/null
+++ b/web/src/js/__tests__/components/ContentView/__snapshots__/ViewSelectorSpec.js.snap
@@ -0,0 +1,123 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ViewSelector Component should connect to state 1`] = `
+<div
+ className="dropup pull-left"
+>
+ <a
+ className="btn btn-default btn-xs"
+ href="#"
+ onClick={[Function]}
+ >
+ <span>
+
+ <b>
+ View:
+ </b>
+
+ auto
+
+ <span
+ className="caret"
+ />
+
+ </span>
+ </a>
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ auto
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ raw
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ text
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
+
+exports[`ViewSelector Component should render correctly 1`] = `
+<div
+ className="dropup pull-left"
+>
+ <a
+ className="btn btn-default btn-xs"
+ href="#"
+ onClick={[Function]}
+ >
+ <span>
+
+ <b>
+ View:
+ </b>
+
+ auto
+
+ <span
+ className="caret"
+ />
+
+ </span>
+ </a>
+ <ul
+ className="dropdown-menu"
+ role="menu"
+ >
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ auto
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ raw
+ </a>
+
+ </li>
+ <li>
+
+ <a
+ href="#"
+ onClick={[Function]}
+ >
+ text
+ </a>
+
+ </li>
+ </ul>
+</div>
+`;
diff --git a/web/src/js/components/ContentView/ContentLoader.jsx b/web/src/js/components/ContentView/ContentLoader.jsx
index 4cafde28..69e4a988 100644
--- a/web/src/js/components/ContentView/ContentLoader.jsx
+++ b/web/src/js/components/ContentView/ContentLoader.jsx
@@ -2,98 +2,100 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { MessageUtils } from '../../flow/utils.js'
-export default View => class extends React.Component {
+export default function withContentLoader(View) {
+
+ return class extends React.Component {
+ static displayName = View.displayName || View.name
+ static matches = View.matches
- static displayName = View.displayName || View.name
- static matches = View.matches
-
- static propTypes = {
- ...View.propTypes,
- content: PropTypes.string, // mark as non-required
- flow: PropTypes.object.isRequired,
- message: PropTypes.object.isRequired,
- }
-
- constructor(props) {
- super(props)
- this.state = {
- content: undefined,
- request: undefined,
+ static propTypes = {
+ ...View.propTypes,
+ content: PropTypes.string, // mark as non-required
+ flow: PropTypes.object.isRequired,
+ message: PropTypes.object.isRequired,
}
- }
- componentWillMount() {
- this.updateContent(this.props)
- }
-
- componentWillReceiveProps(nextProps) {
- if (
- nextProps.message.content !== this.props.message.content ||
- nextProps.message.contentHash !== this.props.message.contentHash ||
- nextProps.contentView !== this.props.contentView
- ) {
- this.updateContent(nextProps)
+ constructor(props) {
+ super(props)
+ this.state = {
+ content: undefined,
+ request: undefined,
+ }
}
- }
- componentWillUnmount() {
- if (this.state.request) {
- this.state.request.abort()
+ componentWillMount() {
+ this.updateContent(this.props)
}
- }
- updateContent(props) {
- if (this.state.request) {
- this.state.request.abort()
+ componentWillReceiveProps(nextProps) {
+ if (
+ nextProps.message.content !== this.props.message.content ||
+ nextProps.message.contentHash !== this.props.message.contentHash ||
+ nextProps.contentView !== this.props.contentView
+ ) {
+ this.updateContent(nextProps)
+ }
}
- // We have a few special cases where we do not need to make an HTTP request.
- if(props.message.content !== undefined) {
- return this.setState({request: undefined, content: props.message.content})
- }
- if(props.message.contentLength === 0 || props.message.contentLength === null){
- return this.setState({request: undefined, content: ""})
+
+ componentWillUnmount() {
+ if (this.state.request) {
+ this.state.request.abort()
+ }
}
- let requestUrl = MessageUtils.getContentURL(props.flow, props.message, (View.name == 'ViewServer' ? props.contentView : undefined))
+ updateContent(props) {
+ if (this.state.request) {
+ this.state.request.abort()
+ }
+ // We have a few special cases where we do not need to make an HTTP request.
+ if (props.message.content !== undefined) {
+ return this.setState({request: undefined, content: props.message.content})
+ }
+ if (props.message.contentLength === 0 || props.message.contentLength === null) {
+ return this.setState({request: undefined, content: ""})
+ }
- // We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable.
- let request = new XMLHttpRequest();
- request.addEventListener("load", this.requestComplete.bind(this, request));
- request.addEventListener("error", this.requestFailed.bind(this, request));
- request.open("GET", requestUrl);
- request.send();
- this.setState({ request, content: undefined })
- }
+ let requestUrl = MessageUtils.getContentURL(props.flow, props.message, (View.name == 'ViewServer' ? props.contentView : undefined))
- requestComplete(request, e) {
- if (request !== this.state.request) {
- return // Stale request
+ // We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable.
+ let request = new XMLHttpRequest();
+ request.addEventListener("load", this.requestComplete.bind(this, request));
+ request.addEventListener("error", this.requestFailed.bind(this, request));
+ request.open("GET", requestUrl);
+ request.send();
+ this.setState({request, content: undefined})
}
- this.setState({
- content: request.responseText,
- request: undefined
- })
- }
- requestFailed(request, e) {
- if (request !== this.state.request) {
- return // Stale request
+ requestComplete(request, e) {
+ if (request !== this.state.request) {
+ return // Stale request
+ }
+ this.setState({
+ content: request.responseText,
+ request: undefined
+ })
+ }
+
+ requestFailed(request, e) {
+ if (request !== this.state.request) {
+ return // Stale request
+ }
+ console.error(e)
+ // FIXME: Better error handling
+ this.setState({
+ content: "Error getting content.",
+ request: undefined
+ })
}
- console.error(e)
- // FIXME: Better error handling
- this.setState({
- content: "Error getting content.",
- request: undefined
- })
- }
- render() {
- return this.state.content !== undefined ? (
- <View content={this.state.content} {...this.props}/>
- ) : (
- <div className="text-center">
- <i className="fa fa-spinner fa-spin"></i>
- </div>
- )
+ render() {
+ return this.state.content !== undefined ? (
+ <View content={this.state.content} {...this.props}/>
+ ) : (
+ <div className="text-center">
+ <i className="fa fa-spinner fa-spin"></i>
+ </div>
+ )
+ }
}
};
diff --git a/web/src/js/components/ContentView/ContentViews.jsx b/web/src/js/components/ContentView/ContentViews.jsx
index 136188d4..dfae937e 100644
--- a/web/src/js/components/ContentView/ContentViews.jsx
+++ b/web/src/js/components/ContentView/ContentViews.jsx
@@ -30,7 +30,7 @@ function Edit({ content, onChange }) {
}
Edit = ContentLoader(Edit)
-class ViewServer extends Component {
+export class PureViewServer extends Component {
static propTypes = {
showFullContent: PropTypes.bool.isRequired,
maxLines: PropTypes.number.isRequired,
@@ -85,7 +85,7 @@ class ViewServer extends Component {
}
-ViewServer = connect(
+const ViewServer = connect(
state => ({
showFullContent: state.ui.flow.showFullContent,
maxLines: state.ui.flow.maxContentLines
@@ -94,6 +94,6 @@ ViewServer = connect(
setContentViewDescription,
setContent
}
-)(ContentLoader(ViewServer))
+)(ContentLoader(PureViewServer))
export { Edit, ViewServer, ViewImage }
diff --git a/web/src/js/components/ContentView/DownloadContentButton.jsx b/web/src/js/components/ContentView/DownloadContentButton.jsx
index 447db211..f32a19ca 100644
--- a/web/src/js/components/ContentView/DownloadContentButton.jsx
+++ b/web/src/js/components/ContentView/DownloadContentButton.jsx
@@ -1,3 +1,4 @@
+import React from 'react'
import { MessageUtils } from "../../flow/utils"
import PropTypes from 'prop-types'
diff --git a/web/src/js/components/ContentView/ShowFullContentButton.jsx b/web/src/js/components/ContentView/ShowFullContentButton.jsx
index fd627ad9..c6d8c2f2 100644
--- a/web/src/js/components/ContentView/ShowFullContentButton.jsx
+++ b/web/src/js/components/ContentView/ShowFullContentButton.jsx
@@ -12,7 +12,7 @@ ShowFullContentButton.propTypes = {
showFullContent: PropTypes.bool.isRequired
}
-function ShowFullContentButton ( {setShowFullContent, showFullContent, visibleLines, contentLines} ){
+export function ShowFullContentButton ( {setShowFullContent, showFullContent, visibleLines, contentLines} ){
return (
!showFullContent &&
diff --git a/web/src/js/components/ContentView/UploadContentButton.jsx b/web/src/js/components/ContentView/UploadContentButton.jsx
index 0021593f..847d4eb0 100644
--- a/web/src/js/components/ContentView/UploadContentButton.jsx
+++ b/web/src/js/components/ContentView/UploadContentButton.jsx
@@ -1,3 +1,4 @@
+import React from 'react'
import PropTypes from 'prop-types'
import FileChooser from '../common/FileChooser'
diff --git a/web/src/js/components/ContentView/ViewSelector.jsx b/web/src/js/components/ContentView/ViewSelector.jsx
index 4c99d5ed..812d87e5 100644
--- a/web/src/js/components/ContentView/ViewSelector.jsx
+++ b/web/src/js/components/ContentView/ViewSelector.jsx
@@ -11,7 +11,7 @@ ViewSelector.propTypes = {
setContentView: PropTypes.func.isRequired
}
-function ViewSelector ({contentViews, activeView, setContentView}){
+export function ViewSelector ({contentViews, activeView, setContentView}){
let inner = <span> <b>View:</b> {activeView.toLowerCase()} <span className="caret"></span> </span>
return (
diff --git a/web/yarn.lock b/web/yarn.lock
index 602b4916..54baf85e 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -3648,6 +3648,10 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
dependencies:
minimist "0.0.8"
+mock-xmlhttprequest@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mock-xmlhttprequest/-/mock-xmlhttprequest-1.1.0.tgz#310edeccb4390a2d630e1a0b4e747615215bf7af"
+
module-deps@^4.0.8:
version "4.1.1"
resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd"