diff options
Diffstat (limited to 'workflow-designer-ui/src/main/frontend')
11 files changed, 223 insertions, 65 deletions
diff --git a/workflow-designer-ui/src/main/frontend/package.json b/workflow-designer-ui/src/main/frontend/package.json index f1f33712..e3c657e0 100644 --- a/workflow-designer-ui/src/main/frontend/package.json +++ b/workflow-designer-ui/src/main/frontend/package.json @@ -34,7 +34,6 @@ "react-datepicker": "^0.48.0", "react-dom": "^16.3.2", "react-hot-loader": "^4.3.3", - "react-infinite-scroller": "^1.2.0", "react-redux": "^5.0.6", "react-redux-i18n": "^1.9.2", "react-router": "^4.3.1", diff --git a/workflow-designer-ui/src/main/frontend/src/App.js b/workflow-designer-ui/src/main/frontend/src/App.js index 4b42f6f3..3d9f302b 100644 --- a/workflow-designer-ui/src/main/frontend/src/App.js +++ b/workflow-designer-ui/src/main/frontend/src/App.js @@ -5,9 +5,9 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 +* http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software +* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and @@ -17,6 +17,7 @@ import { hot } from 'react-hot-loader'; import React, { Component } from 'react'; import { Route } from 'react-router-dom'; +import qs from 'qs'; import { PluginPubSub } from 'shared/pubsub/plugin-pubsub'; import 'resources/scss/style.scss'; @@ -36,28 +37,35 @@ class App extends Component { constructor(props) { super(props); - this.searchParams = new URLSearchParams(location.search); + this.searchParams = qs.parse(location.search, { + ignoreQueryPrefix: true + }); - if (this.searchParams.get('userId')) { - localStorage.setItem(USER_ID, this.searchParams.get('userId')); + if (this.searchParams && this.searchParams.userId) { + localStorage.setItem(USER_ID, this.searchParams.userId); } } componentDidMount() { - const eventsClientId = this.searchParams.get('eventsClientId'); - const parentUrl = this.searchParams.get('parentUrl'); + if (this.searchParams) { + const { eventsClientId, parentUrl } = this.searchParams; - if (eventsClientId && parentUrl) { - const client = new PluginPubSub(eventsClientId, parentUrl); + if (eventsClientId && parentUrl) { + const client = new PluginPubSub(eventsClientId, parentUrl); - client.notify('READY'); + client.notify('READY'); + } } } render() { - return routes.map((route, i) => ( - <RouteWithSubRoutes key={`App.route.${i}`} {...route} /> - )); + return ( + <div className="workflow-app"> + {routes.map((route, i) => ( + <RouteWithSubRoutes key={`App.route.${i}`} {...route} /> + ))} + </div> + ); } } diff --git a/workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx b/workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx index e833a01e..2d8c8d7d 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx +++ b/workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx @@ -16,7 +16,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import InfiniteScroll from 'react-infinite-scroller'; +import InfiniteScroll from 'shared/scroll/InfiniteScroll'; import Workflows from 'features/catalog/views/Workflows'; import AddWorkflow from 'features/catalog/views/AddWorkflow'; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js index d549456f..f47a6ecc 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js @@ -27,7 +27,7 @@ class CompositionView extends Component { static propTypes = { compositionUpdate: PropTypes.func, showErrorModal: PropTypes.func, - composition: PropTypes.string, + composition: PropTypes.bool, name: PropTypes.string }; constructor() { diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap b/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap index 08389c6e..55357b5c 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap +++ b/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap @@ -51,7 +51,7 @@ exports[`Create new version snapshot renders correctly 1`] = ` className="custom-textarea field-section sdc-input__input" data-test-id="new-version-description" onChange={[Function]} - value={undefined} + value="" /> </div> </div> diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/general/GeneralView.js b/workflow-designer-ui/src/main/frontend/src/features/version/general/GeneralView.js index 930c6071..d10d5784 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/general/GeneralView.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/general/GeneralView.js @@ -5,9 +5,9 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 +* http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software +* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and @@ -16,36 +16,39 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n, Localize, Translate } from 'react-redux-i18n'; +import { I18n, Translate } from 'react-redux-i18n'; import Description from 'shared/components/Description'; import { VersionInfo, LabeledValue } from 'shared/components/VersionInfo'; -const GeneralView = ({ onDataChange, description, created, modified }) => ( - <div className="general-page"> - <div className="general-page-title"> - <Translate value="workflow.general.headerTitle" /> - </div> - <div className="general-page-content"> - <Description - description={description} - onDataChange={onDataChange} - /> - <VersionInfo> - <LabeledValue - title={I18n.t('workflow.general.modified')} - value={ - <Localize value={modified} dateFormat="date.short" /> - } - /> - <LabeledValue - title={I18n.t('workflow.general.created')} - value={<Localize value={created} dateFormat="date.short" />} +const GeneralView = ({ onDataChange, description, created, modified }) => { + const modifiedValue = I18n.l(modified, { dateFormat: 'date.short' }); + const createdValue = I18n.l(created, { dateFormat: 'date.short' }); + + return ( + <div className="general-page"> + <div className="general-page-title"> + <Translate value="workflow.general.headerTitle" /> + </div> + <div className="general-page-content"> + <Description + description={description} + onDataChange={onDataChange} /> - </VersionInfo> + <VersionInfo> + <LabeledValue + title={I18n.t('workflow.general.modified')} + value={modifiedValue} + /> + <LabeledValue + title={I18n.t('workflow.general.created')} + value={createdValue} + /> + </VersionInfo> + </div> </div> - </div> -); + ); +}; GeneralView.propTypes = { onDataChange: PropTypes.func, diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap index de14dc3e..1a050ef9 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap @@ -49,7 +49,7 @@ exports[`New Workflow View Snapshot renders correctly 1`] = ` className="custom-textarea field-section sdc-input__input" data-test-id="description" onChange={[Function]} - value={undefined} + value="" /> </div> </div> diff --git a/workflow-designer-ui/src/main/frontend/src/index.js b/workflow-designer-ui/src/main/frontend/src/index.js index d33f47cb..46a87603 100644 --- a/workflow-designer-ui/src/main/frontend/src/index.js +++ b/workflow-designer-ui/src/main/frontend/src/index.js @@ -27,18 +27,14 @@ import store from './store'; ReactDOM.render( <Provider store={store}> - <React.Fragment> - <Notifications /> - <Loader /> - <BrowserRouter> - <React.Fragment> - <div className="workflow-app"> - <App /> - </div> - <ModalWrapper /> - </React.Fragment> - </BrowserRouter> - </React.Fragment> + <BrowserRouter> + <React.Fragment> + <App /> + <Notifications /> + <ModalWrapper /> + <Loader /> + </React.Fragment> + </BrowserRouter> </Provider>, document.getElementById('root') ); diff --git a/workflow-designer-ui/src/main/frontend/src/shared/components/Description/index.js b/workflow-designer-ui/src/main/frontend/src/shared/components/Description/index.js index 15a88341..4aa48f8a 100644 --- a/workflow-designer-ui/src/main/frontend/src/shared/components/Description/index.js +++ b/workflow-designer-ui/src/main/frontend/src/shared/components/Description/index.js @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at -* +* * http://www.apache.org/licenses/LICENSE-2.0 -* +* * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,7 +24,7 @@ const Description = ({ description, onDataChange, dataTestId }) => ( {I18n.t('workflow.general.description')} </div> <textarea - value={description} + value={description || ''} data-test-id={dataTestId || 'description'} onChange={event => { onDataChange({ description: event.target.value }); diff --git a/workflow-designer-ui/src/main/frontend/src/shared/scroll/InfiniteScroll.js b/workflow-designer-ui/src/main/frontend/src/shared/scroll/InfiniteScroll.js new file mode 100644 index 00000000..8db3d841 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/shared/scroll/InfiniteScroll.js @@ -0,0 +1,158 @@ +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +class InfiniteScroll extends React.Component { + componentDidMount() { + this.pageLoaded = this.props.pageStart; + this.scrollEl = this.getScrollElement(); + this.attachScrollListener(); + } + + componentDidUpdate() { + this.attachScrollListener(); + } + + componentWillUnmount() { + this.detachScrollListener(); + } + + getParentElement(el) { + return el.parentNode; + } + + getScrollElement() { + if (this.props.useWindow) { + return window; + } + + return this.getParentElement(this.scrollComponent); + } + + detachScrollListener() { + this.scrollEl.removeEventListener( + 'scroll', + this.scrollListener, + this.props.useCapture + ); + window.removeEventListener( + 'resize', + this.scrollListener, + this.props.useCapture + ); + } + + attachScrollListener() { + if (!this.props.hasMore || !this.scrollEl) { + return; + } + + const options = { + capture: this.props.useCapture, + passive: true + }; + + this.scrollEl.addEventListener('scroll', this.scrollListener, options); + window.addEventListener('resize', this.scrollListener, options); + + if (this.props.initialLoad) { + this.scrollListener(); + } + } + + scrollListener = () => { + const el = this.scrollComponent; + const scrollEl = window; + const parentNode = this.getParentElement(el); + + let offset; + if (this.props.useWindow) { + const doc = + document.documentElement || + document.body.parentNode || + document.body; + const scrollTop = + scrollEl.pageYOffset !== undefined + ? scrollEl.pageYOffset + : doc.scrollTop; + + offset = + this.calculateTopPosition(el) + + (el.offsetHeight - scrollTop - window.innerHeight); + } else { + offset = + el.scrollHeight - + parentNode.scrollTop - + parentNode.clientHeight; + } + + // Here we make sure the element is visible as well as checking the offset + if (offset < Number(this.props.threshold) && el.offsetParent !== null) { + this.detachScrollListener(); + // Call loadMore after detachScrollListener to allow for non-async loadMore functions + if (typeof this.props.loadMore === 'function') { + this.props.loadMore((this.pageLoaded += 1)); + } + } + }; + + calculateTopPosition(el) { + if (!el) { + return 0; + } + return el.offsetTop + this.calculateTopPosition(el.offsetParent); + } + + render() { + const { children, element } = this.props; + + const props = { + ref: node => { + this.scrollComponent = node; + } + }; + + const childrenArray = [children]; + + return React.createElement(element, props, childrenArray); + } +} + +InfiniteScroll.propTypes = { + children: PropTypes.node.isRequired, + element: PropTypes.node, + hasMore: PropTypes.bool, + initialLoad: PropTypes.bool, + loadMore: PropTypes.func.isRequired, + pageStart: PropTypes.number, + threshold: PropTypes.number, + useCapture: PropTypes.bool, + useWindow: PropTypes.bool +}; + +InfiniteScroll.defaultProps = { + element: 'div', + hasMore: false, + initialLoad: true, + pageStart: 0, + threshold: 250, + useWindow: true, + useCapture: false +}; + +export default InfiniteScroll; diff --git a/workflow-designer-ui/src/main/frontend/yarn.lock b/workflow-designer-ui/src/main/frontend/yarn.lock index 5a1ac9af..86a6301c 100644 --- a/workflow-designer-ui/src/main/frontend/yarn.lock +++ b/workflow-designer-ui/src/main/frontend/yarn.lock @@ -9479,12 +9479,6 @@ react-icons@^2.2.7: dependencies: react-icon-base "2.1.0" -react-infinite-scroller@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.2.0.tgz#ea89906c5bc918dce486880b59e88847518aa538" - dependencies: - prop-types "^15.5.8" - react-input-autosize@^2.1.2: version "2.2.1" resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8" |