diff options
Diffstat (limited to 'src')
25 files changed, 871 insertions, 763 deletions
diff --git a/src/app/AppStore.js b/src/app/AppStore.js index 9205937..842b683 100644 --- a/src/app/AppStore.js +++ b/src/app/AppStore.js @@ -27,7 +27,7 @@ import InventoryReducer from './inventory/InventoryReducer.js'; import VnfSearchReducer from './vnfSearch/VnfSearchReducer.js'; import GlobalInlineMessageBarReducer from 'app/globalInlineMessageBar/GlobalInlineMessageBarReducer.js'; import ExtensibilityReducer from 'app/extensibility/ExtensibilityReducer.js'; - +import ConfigurableViewReducer from 'app/configurableViews/ConfigurableViewReducer.js'; function createCompose() { @@ -45,7 +45,8 @@ export const storeCreator = (initialState) => createStore( inventoryReducer: InventoryReducer, vnfSearch: VnfSearchReducer, globalInlineMessageBar: GlobalInlineMessageBarReducer, - extensibility: ExtensibilityReducer + extensibility: ExtensibilityReducer, + configurableViews: ConfigurableViewReducer }), initialState, createCompose() diff --git a/src/app/MainScreenHeader.jsx b/src/app/MainScreenHeader.jsx index e485161..8c5e13d 100644 --- a/src/app/MainScreenHeader.jsx +++ b/src/app/MainScreenHeader.jsx @@ -30,6 +30,7 @@ import {postAnalyticsData} from 'app/analytics/AnalyticsActions.js'; import GlobalInlineMessageBar from 'app/globalInlineMessageBar/GlobalInlineMessageBar.jsx'; import {getClearGlobalMessageEvent} from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js'; import {externalUrlRequest, externalMessageRequest, getSubscriptionPayload} from 'app/contextHandler/ContextHandlerActions.js'; +import { getConfigurableViewConfigs } from 'app/configurableViews/ConfigurableViewActions.js'; import { filterBarActionTypes } from 'utils/GlobalConstants.js'; @@ -56,7 +57,7 @@ import {changeUrlAddress} from 'utils/Routes.js'; import extensibleViews from 'resources/views/extensibleViews.json'; -const mapStateToProps = ({mainWrapper}) => { +const mapStateToProps = ({mainWrapper, configurableViews}) => { let { showMenu = false, toggleButtonActive = false, @@ -66,13 +67,18 @@ const mapStateToProps = ({mainWrapper}) => { subscriptionEnabled = false } = mainWrapper; + let { + configurableViewsConfig + } = configurableViews; + return { showMenu, toggleButtonActive, externalRequestFound, secondaryTitle, subscriptionPayload, - subscriptionEnabled + subscriptionEnabled, + configurableViewsConfig }; }; @@ -100,6 +106,9 @@ const mapActionsToProps = (dispatch) => { }, onGetSubscriptionPayload: () => { dispatch(getSubscriptionPayload()); + }, + onFetchCustomViews: () => { + dispatch(getConfigurableViewConfigs()); } }; }; @@ -132,7 +141,7 @@ class MainScreenHeader extends Component { return false; } } - + isValidExternalURL(url) { if(decodeURIComponent(url).indexOf('&') > 0 ) { return true; @@ -168,7 +177,7 @@ class MainScreenHeader extends Component { this.props.onExternalUrlRequest(nextProps.match.params.externalUrl); } /* if the externalURL is not valid, we do not add any message as other proper - views will get that messages since the route will be this parameter.*/ + views will get that messages since the route will be this parameter.*/ if(this.props.externalRequestFound !== nextProps.externalRequestFound && nextProps.externalRequestFound !== undefined && nextProps.externalRequestFound.suggestion !== undefined) { @@ -216,13 +225,17 @@ class MainScreenHeader extends Component { $this.receiveMessage(e, $this); }, false); } + + // fetch custom views + this.props.onFetchCustomViews(); } + componentWillUnmount() { if(this.props.subscriptionEnabled) { var $this = this; window.removeEventListener('message', function (e) { - $this.receiveMessage(e, $this); - } + $this.receiveMessage(e, $this); + } ); } } @@ -233,7 +246,8 @@ class MainScreenHeader extends Component { onShowMenu, onHideMenu, toggleButtonActive, - secondaryTitle + secondaryTitle, + configurableViewsConfig } = this.props; let menuOptions = []; @@ -249,6 +263,18 @@ class MainScreenHeader extends Component { )}/> ); + const ConfigurableMenuItem = ({label, to}) => ( + <Route path={to} children={({location}) => ( + <NavLink to={to} onClick={onHideMenu}> + <div className={this.navigationLinkAndCurrentPathMatch(location, to) ? + 'main-menu-button-active' : 'main-menu-button'}> + <div className='button-icon configurable-view-button-icon'/> + <div className='button-icon'>{label}</div> + </div> + </NavLink> + )}/> + ); + // add Tier Support view menuOptions.push( <MenuItem key='schemaMenu' to='/schema' label={MENU_ITEM_TIER_SUPPORT} @@ -258,9 +284,9 @@ class MainScreenHeader extends Component { // add VNF view menuOptions.push( <MenuItem key='vnfSearchMenu' - to='/vnfSearch' - label={MENU_ITEM_VNF_SEARCH} - iconClass='button-icon vnf-search-button-icon'/> + to='/vnfSearch' + label={MENU_ITEM_VNF_SEARCH} + iconClass='button-icon vnf-search-button-icon'/> ); // add all custom view menu options @@ -277,7 +303,16 @@ class MainScreenHeader extends Component { label={extensibleViews[view]['displayName']} iconClass={'button-icon ' + extensibleViews[view]['iconClass']}/> ); - } + } + } + + if (configurableViewsConfig && configurableViewsConfig.layouts) { + for (let configurableView in configurableViewsConfig.layouts) { + menuOptions.push( + <ConfigurableMenuItem key={configurableViewsConfig.layouts[configurableView]['id'] + 'Menu'} to={'/' + configurableViewsConfig.layouts[configurableView]['id']} + label={configurableViewsConfig.layouts[configurableView]['title']}/> + ); + } } let secondaryTitleClass = 'secondary-header'; @@ -290,8 +325,8 @@ class MainScreenHeader extends Component { <div> <Button bsClass={(toggleButtonActive) - ? 'toggle-view-button-active' - : 'toggle-view-button'} + ? 'toggle-view-button-active' + : 'toggle-view-button'} onClick={onShowMenu}> <FontAwesome name='bars'/> </Button> diff --git a/src/app/MainScreenWrapper.jsx b/src/app/MainScreenWrapper.jsx index 6689af9..730ac93 100644 --- a/src/app/MainScreenWrapper.jsx +++ b/src/app/MainScreenWrapper.jsx @@ -25,6 +25,10 @@ import TierSupport from './tierSupport/TierSupport.jsx'; import VnfSearch from './vnfSearch/VnfSearch.jsx'; import MainScreenHeader from './MainScreenHeader.jsx'; import {decryptParamsForView, changeUrlAddress} from 'utils/Routes.js'; +import { + getConfigurableViewConfigs, + setCustomRoutes +} from 'app/configurableViews/ConfigurableViewActions.js'; import {isEmpty} from 'lodash'; import {genericRequest} from 'app/networking/NetworkCalls.js'; import { @@ -42,18 +46,36 @@ import { } from './MainScreenWrapperActionHelper.js'; import extensibleViews from 'resources/views/extensibleViews.json'; +import customComponentConfig from 'resources/views/customComponents.json'; +import { newCustomComponentsEvent } from 'app/configurableViews/ConfigurableViewActions.js'; +import { + getConfigurableRoutes +} from 'app/configurableViews/ConfigurableViewManager.js'; + +import { + getConfiguredComponentList +} from 'app/configurableViews/index.js'; -const mapStateToProps = ({mainWrapper}) => { +const mapStateToProps = ({mainWrapper, configurableViews}) => { let { showMenu = false, toggleButtonActive = false, extensibleViewNetworkCallbackData = {} } = mainWrapper; + let { + configurableViewsConfig = {}, + customComponents = {}, + customRoutes = [] + } = configurableViews; + return { showMenu, toggleButtonActive, - extensibleViewNetworkCallbackData + extensibleViewNetworkCallbackData, + configurableViewsConfig, + customComponents, + customRoutes }; }; @@ -68,6 +90,15 @@ const mapActionsToProps = (dispatch) => { }, onOverlayNetworkCallback: (apiUrl, body, viewName, curViewData, responseEventKey) => { dispatch(overlayNetworkCallback(apiUrl, body, viewName, curViewData, responseEventKey)); + }, + onConfigurableViewsInitialLoad: (components) => { + dispatch(newCustomComponentsEvent(components)); + }, + onFetchCustomViews: () => { + dispatch(getConfigurableViewConfigs()); + }, + onSetCustomRoutes: (routes) => { + dispatch(setCustomRoutes(routes)); } }; }; @@ -82,6 +113,25 @@ class MainScreenWrapper extends Component { } + componentDidMount() { + // fetch custom views + this.props.onFetchCustomViews(); + + // fetch custom components + let components = getConfiguredComponentList(customComponentConfig); + this.props.onConfigurableViewsInitialLoad(components); + } + + componentDidUpdate(prevProps) { + if ((Object.keys(this.props.customComponents).length > 0 && + Object.keys(this.props.configurableViewsConfig).length > 0) && + ((JSON.stringify(prevProps.configurableViewsConfig) !== JSON.stringify(this.props.configurableViewsConfig)) || + (JSON.stringify(prevProps.customComponents) !== JSON.stringify(this.props.customComponents)))) { + // we have both config and components populated and one was just set + let customRoutes = getConfigurableRoutes(this.props.configurableViewsConfig, this.props.customComponents); + this.props.onSetCustomRoutes(customRoutes); + } + } render() { @@ -89,14 +139,14 @@ class MainScreenWrapper extends Component { onExtensibleViewNetworkCallback, extensibleViewNetworkCallbackData, onExtensibleViewMessageCallback, - onOverlayNetworkCallback + onOverlayNetworkCallback, + customRoutes } = this.props; let customViewList = []; extensibleViews.forEach(function(view,key) { - let path = '', - extKey = ''; + let path = '', extKey = ''; if(isEmpty(extensibleViews[key]['viewParams'])){ path = '/' + view.viewName + '/:extensibleViewParams?'; extKey = view.viewName + 'Route'; @@ -140,13 +190,13 @@ class MainScreenWrapper extends Component { if(isEmpty(extensibleViews[key]['isExact']) && !extensibleViews[key]['isExact']){ customViewList.push( <Route key={extKey} path={path} render={renderComponent}/> - ); + ); } else { customViewList.push( <Route key={extKey} exact path={path} render={renderComponent}/> - ); + ); } - + }); return ( @@ -159,6 +209,7 @@ class MainScreenWrapper extends Component { <Route key='TierSupportRoue' path='/schema/:viParam?' component={TierSupport}/> <Route key='VnfSearchRoute' path='/vnfSearch/:filters?' component={VnfSearch}/> {customViewList} + {customRoutes} </div> </Router> ); diff --git a/src/app/MainScreenWrapperActionHelper.js b/src/app/MainScreenWrapperActionHelper.js index 371ea42..dd7450b 100644 --- a/src/app/MainScreenWrapperActionHelper.js +++ b/src/app/MainScreenWrapperActionHelper.js @@ -136,7 +136,6 @@ export function extensibleViewNetworkCallback(urlApi, postBody, paramName, curVi () => fetchRequestObj(BASE_URL + urlApi, POST, POST_HEADER, postBody); - return dispatch => { dispatch(extensibleViewData(dataFetchRequest, paramName, curViewData)); }; diff --git a/src/app/configurableViews/ConfigurableViewActions.js b/src/app/configurableViews/ConfigurableViewActions.js new file mode 100644 index 0000000..7cffacc --- /dev/null +++ b/src/app/configurableViews/ConfigurableViewActions.js @@ -0,0 +1,48 @@ +import { + GET, + POST_HEADER +} from 'app/networking/NetworkConstants.js'; +import { + GET_LAYOUTS_URL, + configurableViewsActionTypes +} from './ConfigurableViewConstants.js'; + +function createConfigReceivedEvent(config) { + return { + type: configurableViewsActionTypes.CONFIGURABLE_VIEWS_CONFIG_RECEIVED, + data: config + }; +} + +export function newCustomComponentsEvent(components) { + return { + type: configurableViewsActionTypes.CUSTOM_COMPONENTS_RECEIVED, + data: components + }; +} + +export function setCustomRoutes(routes) { + return { + type: configurableViewsActionTypes.CUSTOM_ROUTES, + data: routes + }; +} + +export function getConfigurableViewConfigs() { + return dispatch => { + return fetch(GET_LAYOUTS_URL, { + method: GET, + headers: POST_HEADER + }).then( + (response) => response.json() + ).then( + (responseJson) => { + dispatch(createConfigReceivedEvent(responseJson)); + } + ).catch( + (err) => { + console.log(`problems fetching configurable view configs: ${err}`); + } + ); + }; +} diff --git a/src/app/configurableViews/ConfigurableViewConstants.js b/src/app/configurableViews/ConfigurableViewConstants.js new file mode 100644 index 0000000..202dd18 --- /dev/null +++ b/src/app/configurableViews/ConfigurableViewConstants.js @@ -0,0 +1,11 @@ +import keyMirror from 'utils/KeyMirror.js'; +import {BASE_URL} from 'app/networking/NetworkConstants.js'; + +export const configurableViewsActionTypes = keyMirror({ + CONFIGURABLE_VIEWS_CONFIG_RECEIVED: null, + CONFIGURABLE_VIEWS_DATA_RECEIVED: null, + CUSTOM_ROUTES: null, + CUSTOM_COMPONENTS_RECEIVED: null +}); + +export const GET_LAYOUTS_URL = BASE_URL + '/layouts'; diff --git a/src/app/configurableViews/ConfigurableViewManager.js b/src/app/configurableViews/ConfigurableViewManager.js new file mode 100644 index 0000000..71cc6cf --- /dev/null +++ b/src/app/configurableViews/ConfigurableViewManager.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { + Route +} from 'react-router-dom'; +import { fetchConfigurableViewRequest } from 'app/networking/NetworkCalls'; + +export function getConfigurableRoutes(config, components) { + let routes = []; + if (config && Object.keys(config).length > 0 && components && Object.keys(components).length > 0) { + config.layouts.forEach( (viewConfig) => { + let ConfigurableView = components[viewConfig.viewType]; + if (ConfigurableView) { + routes.push( + <Route key={viewConfig.id} path={`/${viewConfig.id}`} render={ () => { + return ( + <ConfigurableView + config={ viewConfig } + networkAPI={ fetchConfigurableViewRequest }/> + ); + }}/> + ); + } + }); + } + + return routes; +} diff --git a/src/app/configurableViews/ConfigurableViewReducer.js b/src/app/configurableViews/ConfigurableViewReducer.js new file mode 100644 index 0000000..9a5eee0 --- /dev/null +++ b/src/app/configurableViews/ConfigurableViewReducer.js @@ -0,0 +1,26 @@ +import { + configurableViewsActionTypes +} from './ConfigurableViewConstants.js'; + +export default (state = {}, action) => { + let data = action.data; + switch (action.type) { + case configurableViewsActionTypes.CONFIGURABLE_VIEWS_CONFIG_RECEIVED: + return { + ...state, + configurableViewsConfig: data + }; + case configurableViewsActionTypes.CUSTOM_COMPONENTS_RECEIVED: + return { + ...state, + customComponents: data + }; + case configurableViewsActionTypes.CUSTOM_ROUTES: + return { + ...state, + customRoutes: data + }; + } + + return state; +}; diff --git a/src/app/configurableViews/index.js b/src/app/configurableViews/index.js new file mode 100644 index 0000000..3490fef --- /dev/null +++ b/src/app/configurableViews/index.js @@ -0,0 +1,27 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +// Import section (used as anchor to add extension imports) +export function getConfiguredComponentList() { + let components = {}; + + // Components section (used as an anchor to add extension components) + return components; +} diff --git a/src/app/networking/NetworkCalls.js b/src/app/networking/NetworkCalls.js index 63c08ed..e391391 100644 --- a/src/app/networking/NetworkCalls.js +++ b/src/app/networking/NetworkCalls.js @@ -32,6 +32,16 @@ function fetchRequest(URL, POST, POST_HEADER, BODY) { ); } +const fetchConfigurableViewRequest = (queryData) => { + const URL = `${BASE_URL}${queryData.api}`; + return fetch(URL, { + credentials: 'same-origin', + method: queryData.method, + headers: queryData.headers, + body: JSON.stringify(queryData.componentDataDescriptor) + }); +}; + function fetchRequestObj(URL, POST, POST_HEADER, BODY) { return fetch(URL, { credentials: 'same-origin', @@ -72,25 +82,6 @@ module.exports = { fetchRequest: fetchRequest, fetchRequestObj: fetchRequestObj, getRequest: getRequest, + fetchConfigurableViewRequest: fetchConfigurableViewRequest, genericRequest: genericRequest }; - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/tierSupport/TierSupportActions.js b/src/app/tierSupport/TierSupportActions.js index 08e4e30..afb37be 100644 --- a/src/app/tierSupport/TierSupportActions.js +++ b/src/app/tierSupport/TierSupportActions.js @@ -18,24 +18,13 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -import {tierSupportActionTypes, - TS_BACKEND_SEARCH_SELECTED_NODE_URL} from 'app/tierSupport/TierSupportConstants.js'; import { - POST, - POST_HEADER, - ERROR_RETRIEVING_DATA, - NO_RESULTS_FOUND -} from 'app/networking/NetworkConstants.js'; -import networkCall from 'app/networking/NetworkCalls.js'; + tierSupportActionTypes +} from 'app/tierSupport/TierSupportConstants.js'; import { getSetGlobalMessageEvent, getClearGlobalMessageEvent } from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js'; -import { - STATUS_CODE_204_NO_CONTENT, - STATUS_CODE_3XX_REDIRECTION, - STATUS_CODE_5XX_SERVER_ERROR -} from 'utils/GlobalConstants.js'; function createOnNodeDetailsChangeEvent(newDetails) { return { @@ -76,118 +65,12 @@ export function onNodeMenuChange(selectedMenu) { }; } -function createNodeDetailsFoundEvent(nodeDetails) { - return { - type: tierSupportActionTypes.TS_NODE_SEARCH_RESULTS, - data: nodeDetails - }; -} - -function createSelectedNodeDetails(nodeDetails) { - var selectedNodeDetail; - for(let i = 0; i < nodeDetails.nodes.length; i++) { - if(nodeDetails.nodes[i].nodeMeta.className === 'selectedSearchedNodeClass') { - selectedNodeDetail = nodeDetails.nodes[i]; - break; - } - } - return { - type: tierSupportActionTypes.TS_GRAPH_NODE_SELECTED, - data: selectedNodeDetail - }; -} - -function noNodeDetailsFoundEvent(errorText) { - return { - type: tierSupportActionTypes.TS_NODE_SEARCH_NO_RESULTS, - data: {errorMsg: errorText} - }; -} - -function getInvalidSelectedNodeSearchEvent(errorText) { - return { - type: tierSupportActionTypes.TIER_SUPPORT_NETWORK_ERROR, - data: {value: errorText, errorMsg: ERROR_RETRIEVING_DATA} - }; -} - export function clearVIData() { return { type: tierSupportActionTypes.TIER_SUPPORT_CLEAR_DATA }; } -function setBusyFeedback(){ - return { - type: tierSupportActionTypes.TIER_SUPPORT_ACTIVATE_BUSY_FEEDBACK - }; -} - -function disableBusyFeedback(){ - return { - type: tierSupportActionTypes.TIER_SUPPORT_DISABLE_BUSY_FEEDBACK - }; -} - -export function fetchSelectedNodeElement(fetchRequestCallback) { - return dispatch => { - return fetchRequestCallback().then( - (response) => { - if (response.status === STATUS_CODE_204_NO_CONTENT || response.status >= STATUS_CODE_3XX_REDIRECTION) { - return Promise.reject(new Error(response.status)); - } else { - // assume 200 status - return response.json(); - } - } - ).then( - (responseJson) => { - if (responseJson.nodes.length > 0) { - dispatch(createNodeDetailsFoundEvent(responseJson)); - dispatch(createSelectedNodeDetails(responseJson)); - } else { - dispatch(noNodeDetailsFoundEvent(NO_RESULTS_FOUND)); - } - } - ).then( - () => { - dispatch(disableBusyFeedback()); - } - ).catch( - (errorCode) => { - dispatch(disableBusyFeedback()); - if (errorCode.message >= STATUS_CODE_5XX_SERVER_ERROR) { - dispatch(getInvalidSelectedNodeSearchEvent(ERROR_RETRIEVING_DATA)); - } else { - // TODO - assuming 204 status, but should include additional - // statuses in the future with proper messaging in order to return - // better messaging - dispatch(noNodeDetailsFoundEvent(NO_RESULTS_FOUND)); - } - } - ); - }; -} - -export function querySelectedNodeElement( - searchHashId, selectedNodeFetchRequest) { - let payload = { - hashId: searchHashId - }; - - if (selectedNodeFetchRequest === undefined) { - let postBody = JSON.stringify(payload); - selectedNodeFetchRequest = - () => networkCall.fetchRequestObj(TS_BACKEND_SEARCH_SELECTED_NODE_URL, POST, - POST_HEADER, postBody); - } - - return dispatch => { - dispatch(setBusyFeedback()); - dispatch(fetchSelectedNodeElement(selectedNodeFetchRequest)); - }; -} - export function setNotificationText(msgText, msgSeverity) { if (msgText.length > 0) { return dispatch => { diff --git a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx index b7fca67..4f93125 100644 --- a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx +++ b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx @@ -94,13 +94,13 @@ export default class AutoCompleteSearchBar extends Component { render() { const { - value, suggestions, - suggestionName, cachedSuggestions, - onInputChange, onInvalidSearch, - onClearSuggestionsTextFieldRequested, - onSuggestionsClearRequested, - dispatchAnalytics - } = this.props; + value, suggestions, + suggestionName, cachedSuggestions, + onInputChange, onInvalidSearch, + onClearSuggestionsTextFieldRequested, + onSuggestionsClearRequested, + dispatchAnalytics + } = this.props; const inputProps = { placeholder: SEARCH_PLACEHOLDER_TEXT, value, @@ -201,7 +201,7 @@ export default class AutoCompleteSearchBar extends Component { rest.className = 'react-autosuggest__suggestions-containerCopy'; } return ( - <div {...rest}> + <div {...rest.containerProps} {...rest}> {children} </div> ); diff --git a/src/generic-components/componentManager/ComponentManagerContainer.jsx b/src/generic-components/componentManager/ComponentManagerContainer.jsx index 02a3eba..cd51d37 100644 --- a/src/generic-components/componentManager/ComponentManagerContainer.jsx +++ b/src/generic-components/componentManager/ComponentManagerContainer.jsx @@ -18,7 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -import React, {Component, PropTypes} from 'react'; +import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'; import Button from 'react-bootstrap/lib/Button'; @@ -53,13 +53,13 @@ export default class ComponentManagerContainer extends Component { render() { let { - title, - actions, - children, - showHeader, - showTitle, - showBorder - } = this.props; + title, + actions, + children, + showHeader, + showTitle, + showBorder + } = this.props; let buttons = []; actions.forEach((action) => { switch (action.type) { diff --git a/src/generic-components/graph/Link.jsx b/src/generic-components/graph/Link.jsx index aec33b8..8c87ac5 100644 --- a/src/generic-components/graph/Link.jsx +++ b/src/generic-components/graph/Link.jsx @@ -24,39 +24,39 @@ import { PropTypes } from 'prop-types'; import TempCreateAttributes from './TempCreateAttributes.js'; class Link extends Component { - - static propTypes = { - x1: PropTypes.number, - y1: PropTypes.number, - x2: PropTypes.number, - y2: PropTypes.number, - linkAttributes: PropTypes.object - }; - - static defaultProps = { - x1: 0, - y1: 0, - x2: 0, - y2: 0, - linkAttributes: {} - }; - - render() { - let {x1, y1, x2, y2, linkAttributes} = this.props; - - let combinedAttributes = { - ...linkAttributes, - x1: x1, - y1: y1, - x2: x2, - y2: y2 - }; - - return ( - <line {...combinedAttributes} - style={TempCreateAttributes.createLineStyle()}/> - ); - } + + static propTypes = { + x1: PropTypes.number, + y1: PropTypes.number, + x2: PropTypes.number, + y2: PropTypes.number, + linkAttributes: PropTypes.object + }; + + static defaultProps = { + x1: 0, + y1: 0, + x2: 0, + y2: 0, + linkAttributes: {} + }; + + render() { + let {x1, y1, x2, y2, linkAttributes} = this.props; + + let combinedAttributes = { + ...linkAttributes, + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }; + + return ( + <line {...combinedAttributes} + style={TempCreateAttributes.createLineStyle()}/> + ); + } } export default Link; diff --git a/src/generic-components/graph/Node.jsx b/src/generic-components/graph/Node.jsx index 6de4715..67d954c 100644 --- a/src/generic-components/graph/Node.jsx +++ b/src/generic-components/graph/Node.jsx @@ -22,33 +22,33 @@ import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; class Node extends Component { - - static propTypes = { - x: PropTypes.number, - y: PropTypes.number, - nodeClass: PropTypes.string, - visualElements: PropTypes.array, - meta: PropTypes.object - }; - - static defaultProps = { - x: 0, - y: 0, - nodeClass: '', - visualElements: [], - meta: {} - }; - - render() { - let {x, y, nodeClass, visualElements} = this.props; - let translate = `translate(${x}, ${y})`; - - return ( - <g className={nodeClass} transform={translate}> - {visualElements} - </g> - ); - } + + static propTypes = { + x: PropTypes.number, + y: PropTypes.number, + nodeClass: PropTypes.string, + visualElements: PropTypes.array, + meta: PropTypes.object + }; + + static defaultProps = { + x: 0, + y: 0, + nodeClass: '', + visualElements: [], + meta: {} + }; + + render() { + let {x, y, nodeClass, visualElements} = this.props; + let translate = `translate(${x}, ${y})`; + + return ( + <g className={nodeClass} transform={translate}> + {visualElements} + </g> + ); + } } export default Node; diff --git a/src/generic-components/graph/SVGShape.jsx b/src/generic-components/graph/SVGShape.jsx index b06c46f..8b33598 100644 --- a/src/generic-components/graph/SVGShape.jsx +++ b/src/generic-components/graph/SVGShape.jsx @@ -23,39 +23,39 @@ import { PropTypes } from 'prop-types'; import NodeVisualElementConstants from './NodeVisualElementConstants'; class SVGShape extends Component { - - static propTypes = { - shapeType: PropTypes.string.isRequired, - shapeAttributes: PropTypes.object.isRequired, - shapeClass: PropTypes.object.isRequired, - textValue: PropTypes.string - }; - - static defaultProps = { - shapeType: '', - shapeAttributes: {}, - shapeClass: {}, - textValue: '' - }; - - render() { - let {shapeType, shapeAttributes, shapeClass, textValue} = this.props; - - switch (shapeType) { - case NodeVisualElementConstants.SVG_CIRCLE: - return <circle {...shapeAttributes} className={shapeClass}/>; - - case NodeVisualElementConstants.SVG_LINELINE: - return <line {...shapeAttributes} className={shapeClass}/>; - - case NodeVisualElementConstants.TEXT: - return <text {...shapeAttributes} - className={shapeClass}>{textValue}</text>; - - default: - return undefined; - } - } + + static propTypes = { + shapeType: PropTypes.string.isRequired, + shapeAttributes: PropTypes.object.isRequired, + shapeClass: PropTypes.object.isRequired, + textValue: PropTypes.string + }; + + static defaultProps = { + shapeType: '', + shapeAttributes: {}, + shapeClass: {}, + textValue: '' + }; + + render() { + let {shapeType, shapeAttributes, shapeClass, textValue} = this.props; + + switch (shapeType) { + case NodeVisualElementConstants.SVG_CIRCLE: + return <circle {...shapeAttributes} className={shapeClass}/>; + + case NodeVisualElementConstants.SVG_LINELINE: + return <line {...shapeAttributes} className={shapeClass}/>; + + case NodeVisualElementConstants.TEXT: + return <text {...shapeAttributes} + className={shapeClass}>{textValue}</text>; + + default: + return undefined; + } + } } export default SVGShape; diff --git a/src/generic-components/input/ToggleInput.jsx b/src/generic-components/input/ToggleInput.jsx index 49b0376..f68758a 100644 --- a/src/generic-components/input/ToggleInput.jsx +++ b/src/generic-components/input/ToggleInput.jsx @@ -23,54 +23,54 @@ import { PropTypes } from 'prop-types'; export default class ToggleInput extends React.Component { - - static propTypes = { - label: PropTypes.node, - value: PropTypes.bool, - onChange: PropTypes.func, - disabled: PropTypes.bool - } - - static defaultProps = { - value: false, - label: '' - } - - state = { - value: this.props.value - } - - status() { - return this.state.value ? 'on' : 'off'; - } - - render() { - let {label, disabled} = this.props; - let checked = this.status() === 'on'; - return ( - <div className='toggle-input-wrapper form-group' - onClick={!disabled && this.click}> - <div className='toggle-input-label'>{label}</div> - <div className='toggle-switch'> - <input className='toggle toggle-round-flat' type='checkbox' - checked={checked} readOnly/> - <label></label> - </div> - </div> - ); - } - - click = () => { - let value = !this.state.value; - this.setState({value}); - - let onChange = this.props.onChange; - if (onChange) { - onChange(value); - } - } - - getValue() { - return this.state.value; - } + + static propTypes = { + label: PropTypes.node, + value: PropTypes.bool, + onChange: PropTypes.func, + disabled: PropTypes.bool + } + + static defaultProps = { + value: false, + label: '' + } + + state = { + value: this.props.value + } + + status() { + return this.state.value ? 'on' : 'off'; + } + + render() { + let {label, disabled} = this.props; + let checked = this.status() === 'on'; + return ( + <div className='toggle-input-wrapper form-group' + onClick={!disabled && this.click}> + <div className='toggle-input-label'>{label}</div> + <div className='toggle-switch'> + <input className='toggle toggle-round-flat' type='checkbox' + checked={checked} readOnly/> + <label></label> + </div> + </div> + ); + } + + click = () => { + let value = !this.state.value; + this.setState({value}); + + let onChange = this.props.onChange; + if (onChange) { + onChange(value); + } + } + + getValue() { + return this.state.value; + } } diff --git a/src/generic-components/input/inputOptions/InputOptions.jsx b/src/generic-components/input/inputOptions/InputOptions.jsx index bb9d777..bf17df1 100644 --- a/src/generic-components/input/inputOptions/InputOptions.jsx +++ b/src/generic-components/input/inputOptions/InputOptions.jsx @@ -27,215 +27,215 @@ import Select from 'generic-components/input/SelectInput.jsx'; export const other = {OTHER: 'Other'}; class InputOptions extends React.Component { - - static propTypes = { - values: PropTypes.arrayOf(PropTypes.shape({ - enum: PropTypes.string, - title: PropTypes.string - })), - isEnabledOther: PropTypes.bool, - title: PropTypes.string, - selectedValue: PropTypes.string, - multiSelectedEnum: PropTypes.array, - selectedEnum: PropTypes.string, - otherValue: PropTypes.string, - onEnumChange: PropTypes.func, - onOtherChange: PropTypes.func, - isRequired: PropTypes.bool, - isMultiSelect: PropTypes.bool - }; - - - static contextTypes = { - isReadOnlyMode: PropTypes.bool - }; - - state = { - otherInputDisabled: !this.props.otherValue - }; - - oldProps = { - selectedEnum: '', - otherValue: '', - multiSelectedEnum: [] - }; - - render() { - let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, hasError, validations, children} = this.props; - - let currentMultiSelectedEnum = []; - let currentSelectedEnum = ''; - let {otherInputDisabled} = this.state; - if (isMultiSelect) { - currentMultiSelectedEnum = multiSelectedEnum; - if (!otherInputDisabled) { - currentSelectedEnum = - multiSelectedEnum ? multiSelectedEnum.toString() : undefined; - } - } - else { - currentSelectedEnum = selectedEnum; - } - - let isReadOnlyMode = this.context.isReadOnlyMode; - - return ( - <div - className={classNames('form-group', {'required' : validations.required , 'has-error' : hasError})}> - <label className='control-label'>{label}</label> - {isMultiSelect && otherInputDisabled ? - <Select - ref='_myInput' - value={currentMultiSelectedEnum} - className='options-input' - clearable={false} - required={isRequired} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - onBlur={() => onBlur()} - onMultiSelectChanged={value => this.multiSelectEnumChanged(value)} - options={this.renderMultiSelectOptions(values)} - multi/> : - <div className={classNames('input-options',{'has-error' : hasError})}> - <select - ref={'_myInput'} - label={label} - className='form-control input-options-select' - value={currentSelectedEnum} - style={{'width' : otherInputDisabled ? '100%' : '95px'}} - onBlur={() => onBlur()} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - onChange={ value => this.enumChanged(value)} - type='select'> - {values && - values.length && - values.map(val => this.renderOptions(val))} - {onOtherChange && <option key='other' - value={other.OTHER}>{i18n( - other.OTHER)}</option>} - {children} - </select> - - {!otherInputDisabled && <div className='input-options-separator'/>} - <input - className='form-control input-options-other' - placeholder={i18n('other')} - ref='_otherValue' - style={{'display' : otherInputDisabled ? 'none' : 'block'}} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - value={otherValue || ''} - onBlur={() => onBlur()} - onChange={() => this.changedOtherInput()}/> - </div> - } - </div> - ); - } - - renderOptions(val) { - return ( - <option key={val.enum} value={val.enum}>{val.title}</option> - ); - } - - - renderMultiSelectOptions(values) { - let {onOtherChange} = this.props; - let optionsList = []; - if (onOtherChange) { - optionsList = values.map(option => { - return { - label: option.title, - value: option.enum, - }; - }).concat([{ - label: i18n(other.OTHER), - value: i18n(other.OTHER), - }]); - } - else { - optionsList = values.map(option => { - return { - label: option.title, - value: option.enum, - }; - }); - } - if (optionsList.length > 0 && optionsList[0].value === '') { - optionsList.shift(); - } - return optionsList; - } - - getValue() { - let res = ''; - let {isMultiSelect} = this.props; - let {otherInputDisabled} = this.state; - - if (otherInputDisabled) { - res = - isMultiSelect - ? this.refs._myInput.getValue() - : this.refs._myInput.value; - } else { - res = this.refs._otherValue.value; - } - return res; - } - - enumChanged() { - let enumValue = this.refs._myInput.value; - let {onEnumChange, isMultiSelect, onChange} = this.props; - this.setState({ - otherInputDisabled: enumValue !== other.OTHER - }); - if (onEnumChange) { - onEnumChange(isMultiSelect ? [enumValue] : enumValue); - } - - if (onChange) { - onChange(enumValue); - } - - } - - multiSelectEnumChanged(enumValue) { - let {onEnumChange} = this.props; - let selectedValues = enumValue.map(enumVal => { - return enumVal.value; - }); - - if (this.state.otherInputDisabled === false) { - selectedValues.shift(); - } - else if (selectedValues.includes(i18n(other.OTHER))) { - selectedValues = [i18n(other.OTHER)]; - } - - this.setState({ - otherInputDisabled: !selectedValues.includes(i18n(other.OTHER)) - }); - onEnumChange(selectedValues); - } - - changedOtherInput() { - let {onOtherChange} = this.props; - onOtherChange(this.refs._otherValue.value); - } - - componentDidUpdate() { - let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props; - if (this.oldProps.otherValue !== otherValue - || this.oldProps.selectedEnum !== selectedEnum - || this.oldProps.multiSelectedEnum !== multiSelectedEnum) { - this.oldProps = { - otherValue, - selectedEnum, - multiSelectedEnum - }; - onInputChange(); - } - } - + + static propTypes = { + values: PropTypes.arrayOf(PropTypes.shape({ + enum: PropTypes.string, + title: PropTypes.string + })), + isEnabledOther: PropTypes.bool, + title: PropTypes.string, + selectedValue: PropTypes.string, + multiSelectedEnum: PropTypes.array, + selectedEnum: PropTypes.string, + otherValue: PropTypes.string, + onEnumChange: PropTypes.func, + onOtherChange: PropTypes.func, + isRequired: PropTypes.bool, + isMultiSelect: PropTypes.bool + }; + + + static contextTypes = { + isReadOnlyMode: PropTypes.bool + }; + + state = { + otherInputDisabled: !this.props.otherValue + }; + + oldProps = { + selectedEnum: '', + otherValue: '', + multiSelectedEnum: [] + }; + + render() { + let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, hasError, validations, children} = this.props; + + let currentMultiSelectedEnum = []; + let currentSelectedEnum = ''; + let {otherInputDisabled} = this.state; + if (isMultiSelect) { + currentMultiSelectedEnum = multiSelectedEnum; + if (!otherInputDisabled) { + currentSelectedEnum = + multiSelectedEnum ? multiSelectedEnum.toString() : undefined; + } + } + else { + currentSelectedEnum = selectedEnum; + } + + let isReadOnlyMode = this.context.isReadOnlyMode; + + return ( + <div + className={classNames('form-group', {'required' : validations.required , 'has-error' : hasError})}> + <label className='control-label'>{label}</label> + {isMultiSelect && otherInputDisabled ? + <Select + ref='_myInput' + value={currentMultiSelectedEnum} + className='options-input' + clearable={false} + required={isRequired} + disabled={isReadOnlyMode || Boolean(this.props.disabled)} + onBlur={() => onBlur()} + onMultiSelectChanged={value => this.multiSelectEnumChanged(value)} + options={this.renderMultiSelectOptions(values)} + multi/> : + <div className={classNames('input-options',{'has-error' : hasError})}> + <select + ref={'_myInput'} + label={label} + className='form-control input-options-select' + value={currentSelectedEnum} + style={{'width' : otherInputDisabled ? '100%' : '95px'}} + onBlur={() => onBlur()} + disabled={isReadOnlyMode || Boolean(this.props.disabled)} + onChange={ value => this.enumChanged(value)} + type='select'> + {values && + values.length && + values.map(val => this.renderOptions(val))} + {onOtherChange && <option key='other' + value={other.OTHER}>{i18n( + other.OTHER)}</option>} + {children} + </select> + + {!otherInputDisabled && <div className='input-options-separator'/>} + <input + className='form-control input-options-other' + placeholder={i18n('other')} + ref='_otherValue' + style={{'display' : otherInputDisabled ? 'none' : 'block'}} + disabled={isReadOnlyMode || Boolean(this.props.disabled)} + value={otherValue || ''} + onBlur={() => onBlur()} + onChange={() => this.changedOtherInput()}/> + </div> + } + </div> + ); + } + + renderOptions(val) { + return ( + <option key={val.enum} value={val.enum}>{val.title}</option> + ); + } + + + renderMultiSelectOptions(values) { + let {onOtherChange} = this.props; + let optionsList = []; + if (onOtherChange) { + optionsList = values.map(option => { + return { + label: option.title, + value: option.enum, + }; + }).concat([{ + label: i18n(other.OTHER), + value: i18n(other.OTHER), + }]); + } + else { + optionsList = values.map(option => { + return { + label: option.title, + value: option.enum, + }; + }); + } + if (optionsList.length > 0 && optionsList[0].value === '') { + optionsList.shift(); + } + return optionsList; + } + + getValue() { + let res = ''; + let {isMultiSelect} = this.props; + let {otherInputDisabled} = this.state; + + if (otherInputDisabled) { + res = + isMultiSelect + ? this.refs._myInput.getValue() + : this.refs._myInput.value; + } else { + res = this.refs._otherValue.value; + } + return res; + } + + enumChanged() { + let enumValue = this.refs._myInput.value; + let {onEnumChange, isMultiSelect, onChange} = this.props; + this.setState({ + otherInputDisabled: enumValue !== other.OTHER + }); + if (onEnumChange) { + onEnumChange(isMultiSelect ? [enumValue] : enumValue); + } + + if (onChange) { + onChange(enumValue); + } + + } + + multiSelectEnumChanged(enumValue) { + let {onEnumChange} = this.props; + let selectedValues = enumValue.map(enumVal => { + return enumVal.value; + }); + + if (this.state.otherInputDisabled === false) { + selectedValues.shift(); + } + else if (selectedValues.includes(i18n(other.OTHER))) { + selectedValues = [i18n(other.OTHER)]; + } + + this.setState({ + otherInputDisabled: !selectedValues.includes(i18n(other.OTHER)) + }); + onEnumChange(selectedValues); + } + + changedOtherInput() { + let {onOtherChange} = this.props; + onOtherChange(this.refs._otherValue.value); + } + + componentDidUpdate() { + let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props; + if (this.oldProps.otherValue !== otherValue + || this.oldProps.selectedEnum !== selectedEnum + || this.oldProps.multiSelectedEnum !== multiSelectedEnum) { + this.oldProps = { + otherValue, + selectedEnum, + multiSelectedEnum + }; + onInputChange(); + } + } + } export default InputOptions; diff --git a/src/generic-components/map/TopographicMap.jsx b/src/generic-components/map/TopographicMap.jsx index fc0fb64..6da9909 100644 --- a/src/generic-components/map/TopographicMap.jsx +++ b/src/generic-components/map/TopographicMap.jsx @@ -18,7 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -import React, {Component, PropTypes} from 'react'; +import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; import {geoAlbersUsa, geoEquirectangular, geoPath} from 'd3-geo'; import {feature, mesh} from 'topojson'; diff --git a/src/generic-components/notifications/NotificationModal.jsx b/src/generic-components/notifications/NotificationModal.jsx index 1547da3..0e747d5 100644 --- a/src/generic-components/notifications/NotificationModal.jsx +++ b/src/generic-components/notifications/NotificationModal.jsx @@ -19,17 +19,17 @@ * ============LICENSE_END========================================================= */ /** - * NotificationModal options: - * - * show: whether to show notification or not, - * type: the type of the notification. valid values are: 'default', 'error', - * 'warning', 'success' msg: the notification content. could be a string or - * node (React component) title: the notification title timeout: timeout for - * the notification to fade out. if timeout == 0 then the notification is - * rendered until the user closes it - * - */ -import React, {Component, PropTypes} from 'react'; + * NotificationModal options: + * + * show: whether to show notification or not, + * type: the type of the notification. valid values are: 'default', 'error', + * 'warning', 'success' msg: the notification content. could be a string or + * node (React component) title: the notification title timeout: timeout for + * the notification to fade out. if timeout == 0 then the notification is + * rendered until the user closes it + * + */ +import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; import {connect} from 'react-redux'; import Button from 'react-bootstrap/lib/Button.js'; @@ -39,83 +39,83 @@ import Modal from 'generic-components/modal/Modal.jsx'; import NotificationConstants from './NotificationConstants.js'; let typeClass = { - 'default': 'primary', - error: 'danger', - warning: 'warning', - success: 'success' + 'default': 'primary', + error: 'danger', + warning: 'warning', + success: 'success' }; const mapActionsToProps = (dispatch) => { - return { - onCloseClick: () => dispatch({type: NotificationConstants.NOTIFY_CLOSE}) - }; + return { + onCloseClick: () => dispatch({type: NotificationConstants.NOTIFY_CLOSE}) + }; }; const mapStateToProps = ({notification}) => { - - let show = notification !== null && notification.title !== 'Conflict'; - let mapResult = {show}; - if (show) { - mapResult = {show, ...notification}; - } - - return mapResult; + + let show = notification !== null && notification.title !== 'Conflict'; + let mapResult = {show}; + if (show) { + mapResult = {show, ...notification}; + } + + return mapResult; }; class NotificationModal extends Component { - - static propTypes = { - show: PropTypes.bool, - type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), - msg: PropTypes.node, - title: PropTypes.string, - timeout: PropTypes.number - }; - - static defaultProps = { - show: false, - type: 'default', - title: '', - msg: '', - timeout: 0 - }; - - state = {type: undefined}; - - componentWillReceiveProps(nextProps) { - if (this.props.show !== nextProps.show && nextProps.show === false) { - this.setState({type: this.props.type}); - } - else { - this.setState({type: undefined}); - } - } - - componentDidUpdate() { - if (this.props.timeout) { - setTimeout(this.props.onCloseClick, this.props.timeout); - } - } - - render() { - let {title, type, msg, show} = this.props; - if (!show) { - type = this.state.type; - } - return ( - <Modal show={this.props.show} - className={`notification-modal ${typeClass[type]}`}> - <Modal.Header> - <Modal.Title>{title}</Modal.Title> - </Modal.Header> - <Modal.Body>{msg}</Modal.Body> - <Modal.Footer> - <Button bsStyle={typeClass[type]} - onClick={this.props.onCloseClick}>{i18n('OK')}</Button> - </Modal.Footer> - </Modal> - ); - } + + static propTypes = { + show: PropTypes.bool, + type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), + msg: PropTypes.node, + title: PropTypes.string, + timeout: PropTypes.number + }; + + static defaultProps = { + show: false, + type: 'default', + title: '', + msg: '', + timeout: 0 + }; + + state = {type: undefined}; + + componentWillReceiveProps(nextProps) { + if (this.props.show !== nextProps.show && nextProps.show === false) { + this.setState({type: this.props.type}); + } + else { + this.setState({type: undefined}); + } + } + + componentDidUpdate() { + if (this.props.timeout) { + setTimeout(this.props.onCloseClick, this.props.timeout); + } + } + + render() { + let {title, type, msg, show} = this.props; + if (!show) { + type = this.state.type; + } + return ( + <Modal show={this.props.show} + className={`notification-modal ${typeClass[type]}`}> + <Modal.Header> + <Modal.Title>{title}</Modal.Title> + </Modal.Header> + <Modal.Body>{msg}</Modal.Body> + <Modal.Footer> + <Button bsStyle={typeClass[type]} + onClick={this.props.onCloseClick}>{i18n('OK')}</Button> + </Modal.Footer> + </Modal> + ); + } } export default connect(mapStateToProps, mapActionsToProps)(NotificationModal); diff --git a/src/generic-components/panel/SlidePanel.jsx b/src/generic-components/panel/SlidePanel.jsx index 9580837..1550cee 100644 --- a/src/generic-components/panel/SlidePanel.jsx +++ b/src/generic-components/panel/SlidePanel.jsx @@ -24,114 +24,114 @@ import FontAwesome from 'react-fontawesome'; import ReactDOM from 'react-dom'; class SlidePanel extends React.Component { - - static PropTypes = { - direction: PropTypes.string.isRequired, - className: PropTypes.string, - title: PropTypes.string, - isOpen: PropTypes.bool - }; - - static defaultProps = { - title: '', - className: '', - isOpen: true - }; - - state = { - isOpen: this.props.isOpen, - direction: this.props.direction, - width: 0, - arrowWidth: 0 - }; - - componentDidMount() { - this.setSliderPosition(); - } - - componentDidUpdate() { - this.setSliderPosition(); - } - - render() { - - let {children, className} = this.props; - let {isOpen} = this.state; - - return ( - <div className={ `slide-panel ${className}`}> - {this.renderHeader(isOpen)} - <div - className={'slide-panel-content ' + (isOpen ? 'opened' : 'closed')}>{children}</div> - </div> - ); - } - - renderHeader(isOpen) { - let {direction: initialDirection, title} = this.props; - let {direction: currentDirection} = this.state; - - let iconName = currentDirection === - 'right' - ? 'angle-double-right collapse-double-icon' - : 'angle-double-left collapse-double-icon'; - - let awestyle = {padding: '5px'}; - - if (!isOpen && initialDirection === 'right') { - awestyle.marginLeft = '-1px'; - } - return ( - <div className='slide-panel-header'> - { initialDirection === 'left' && - <span className='slide-panel-header-title'>{title}</span>} - <FontAwesome - ref='arrowIcon' - style={awestyle} - onClick={this.handleClick} - className='pull-right' - name={iconName} - size='2x'/> - { initialDirection === 'right' && - <span className='slide-panel-header-title'>{title}</span>} - </div> - ); - } - - handleClick = () => { - this.setState({ - isOpen: !this.state.isOpen, - direction: this.state.direction === 'left' ? 'right' : 'left' - }); - } - - setSliderPosition = () => { - - let el = ReactDOM.findDOMNode(this); - let {style} = el; - - let {direction: initialDirection} = this.props; - let arrowIconSize = Math.floor(ReactDOM.findDOMNode(this.refs.arrowIcon) - .getBoundingClientRect().width) * 2; - if (!this.state.isOpen) { - if (this.props.direction === 'left') { - style.left = arrowIconSize - el.getBoundingClientRect().width + 'px'; - } - if (initialDirection === 'right') { - style.right = arrowIconSize - el.getBoundingClientRect().width + 'px'; - } - } - else { - if (initialDirection === 'left') { - style.left = '0px'; - } - - if (this.props.direction === 'right') { - style.right = '0px'; - } - } - } - + + static PropTypes = { + direction: PropTypes.string.isRequired, + className: PropTypes.string, + title: PropTypes.string, + isOpen: PropTypes.bool + }; + + static defaultProps = { + title: '', + className: '', + isOpen: true + }; + + state = { + isOpen: this.props.isOpen, + direction: this.props.direction, + width: 0, + arrowWidth: 0 + }; + + componentDidMount() { + this.setSliderPosition(); + } + + componentDidUpdate() { + this.setSliderPosition(); + } + + render() { + + let {children, className} = this.props; + let {isOpen} = this.state; + + return ( + <div className={ `slide-panel ${className}`}> + {this.renderHeader(isOpen)} + <div + className={'slide-panel-content ' + (isOpen ? 'opened' : 'closed')}>{children}</div> + </div> + ); + } + + renderHeader(isOpen) { + let {direction: initialDirection, title} = this.props; + let {direction: currentDirection} = this.state; + + let iconName = currentDirection === + 'right' + ? 'angle-double-right collapse-double-icon' + : 'angle-double-left collapse-double-icon'; + + let awestyle = {padding: '5px'}; + + if (!isOpen && initialDirection === 'right') { + awestyle.marginLeft = '-1px'; + } + return ( + <div className='slide-panel-header'> + { initialDirection === 'left' && + <span className='slide-panel-header-title'>{title}</span>} + <FontAwesome + ref='arrowIcon' + style={awestyle} + onClick={this.handleClick} + className='pull-right' + name={iconName} + size='2x'/> + { initialDirection === 'right' && + <span className='slide-panel-header-title'>{title}</span>} + </div> + ); + } + + handleClick = () => { + this.setState({ + isOpen: !this.state.isOpen, + direction: this.state.direction === 'left' ? 'right' : 'left' + }); + } + + setSliderPosition = () => { + + let el = ReactDOM.findDOMNode(this); + let {style} = el; + + let {direction: initialDirection} = this.props; + let arrowIconSize = Math.floor(ReactDOM.findDOMNode(this.refs.arrowIcon) + .getBoundingClientRect().width) * 2; + if (!this.state.isOpen) { + if (this.props.direction === 'left') { + style.left = arrowIconSize - el.getBoundingClientRect().width + 'px'; + } + if (initialDirection === 'right') { + style.right = arrowIconSize - el.getBoundingClientRect().width + 'px'; + } + } + else { + if (initialDirection === 'left') { + style.left = '0px'; + } + + if (this.props.direction === 'right') { + style.right = '0px'; + } + } + } + } export default SlidePanel; diff --git a/src/generic-components/titledContainer/TitledContainer.jsx b/src/generic-components/titledContainer/TitledContainer.jsx index d3d606a..6aa626d 100644 --- a/src/generic-components/titledContainer/TitledContainer.jsx +++ b/src/generic-components/titledContainer/TitledContainer.jsx @@ -18,7 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -import React, {Component, PropTypes} from 'react'; +import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; import Button from 'react-bootstrap/lib/Button'; diff --git a/src/generic-components/toggleButtonGroup/ToggleButtonGroup.jsx b/src/generic-components/toggleButtonGroup/ToggleButtonGroup.jsx index 6d57637..0fe8939 100644 --- a/src/generic-components/toggleButtonGroup/ToggleButtonGroup.jsx +++ b/src/generic-components/toggleButtonGroup/ToggleButtonGroup.jsx @@ -18,7 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -import React, {Component, PropTypes} from 'react'; +import React, {Component} from 'react'; import { PropTypes } from 'prop-types'; import {connect} from 'react-redux'; @@ -28,49 +28,49 @@ import Button from 'react-bootstrap/lib/Button.js'; import ToggleButtonGroupActions from 'generic-components/toggleButtonGroup/ToggleButtonGroupActions.js'; let mapActionToProps = (dispatch) => { - return { - onButtonToggle: (buttonName) => { - dispatch(ToggleButtonGroupActions.onToggle({button: buttonName})); - } - }; + return { + onButtonToggle: (buttonName) => { + dispatch(ToggleButtonGroupActions.onToggle({button: buttonName})); + } + }; }; let mapStateToProps = ({toggleButtonGroupData}) => { - - let {selectedButton} = toggleButtonGroupData; - - return { - selectedButton - }; + + let {selectedButton} = toggleButtonGroupData; + + return { + selectedButton + }; }; class ToggleButtonGroup extends Component { - - static propTypes = { - buttonDefinitions: PropTypes.object.isRequired - }; - - onButtonSelect(buttonName) { - this.props.onButtonToggle(buttonName); - } - - render() { - let {selectedButton, buttonDefinitions} = this.props; - let buttonListElements = []; - Object.keys(buttonDefinitions).map(function (item) { - buttonListElements.push( - <Button id={item} active={selectedButton === item ? true : false} - onClick={() => this.onButtonSelect(item)}> - <i className={buttonDefinitions[item]} aria-hidden='true'></i> - </Button> - ); - }.bind(this)); - - return ( - <ButtonGroup bsClass='btn-group displayOptionButtons'> - {buttonListElements} - </ButtonGroup> - ); - } + + static propTypes = { + buttonDefinitions: PropTypes.object.isRequired + }; + + onButtonSelect(buttonName) { + this.props.onButtonToggle(buttonName); + } + + render() { + let {selectedButton, buttonDefinitions} = this.props; + let buttonListElements = []; + Object.keys(buttonDefinitions).map(function (item) { + buttonListElements.push( + <Button id={item} active={selectedButton === item ? true : false} + onClick={() => this.onButtonSelect(item)}> + <i className={buttonDefinitions[item]} aria-hidden='true'></i> + </Button> + ); + }.bind(this)); + + return ( + <ButtonGroup bsClass='btn-group displayOptionButtons'> + {buttonListElements} + </ButtonGroup> + ); + } } export default connect(mapStateToProps, mapActionToProps)(ToggleButtonGroup); diff --git a/src/utils/Crypto.js b/src/utils/Crypto.js index c84ca76..91b6799 100644 --- a/src/utils/Crypto.js +++ b/src/utils/Crypto.js @@ -23,7 +23,7 @@ */ import CryptoJS from 'crypto-js'; -var key = 'key2017'; +const key = 'key2017'; function encrypt(text) { var encrypted = CryptoJS.AES.encrypt(text, key); @@ -35,8 +35,17 @@ function decrypt(text) { return decrypted.toString(CryptoJS.enc.Utf8); } +function encode(phrase) { + return CryptoJS.enc.Utf16.parse(phrase); +} + +function decode(encodedPhrase) { + return CryptoJS.enc.Utf16.stringify(encodedPhrase); +} module.exports = { encrypt: encrypt, - decrypt: decrypt + decrypt: decrypt, + encode: encode, + decode: decode }; diff --git a/src/utils/SpinnerContainer.jsx b/src/utils/SpinnerContainer.jsx index 9bcf769..17e6e58 100644 --- a/src/utils/SpinnerContainer.jsx +++ b/src/utils/SpinnerContainer.jsx @@ -26,9 +26,9 @@ import {COLOR_BLUE} from 'utils/GlobalConstants.js'; class SpinnerContainer extends Component { render() { // if loading, show content as busy (ex: grey out) - const spinnerContentClass = this.props.loading ? 'spinner-content' : ''; + const spinnerContentClass = this.props.loading ? 'spin-content' : ''; return ( - <div className='spinner-container'> + <div className='spin-container'> <div className='spinner'> <ClipLoader color={COLOR_BLUE} loading={this.props.loading} /> </div> |