summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--package.json9
-rw-r--r--resources/images/icons/reports.pngbin0 -> 378 bytes
-rw-r--r--resources/images/icons/reports.svg1
-rw-r--r--resources/scss/common/_layout.scss4
-rw-r--r--resources/views/customComponents.json2
-rw-r--r--scripts/build/build.sh35
-rw-r--r--src/app/AppStore.js5
-rw-r--r--src/app/MainScreenHeader.jsx61
-rw-r--r--src/app/MainScreenWrapper.jsx67
-rw-r--r--src/app/MainScreenWrapperActionHelper.js1
-rw-r--r--src/app/configurableViews/ConfigurableViewActions.js48
-rw-r--r--src/app/configurableViews/ConfigurableViewConstants.js11
-rw-r--r--src/app/configurableViews/ConfigurableViewManager.js27
-rw-r--r--src/app/configurableViews/ConfigurableViewReducer.js26
-rw-r--r--src/app/configurableViews/index.js27
-rw-r--r--src/app/networking/NetworkCalls.js31
-rw-r--r--src/app/tierSupport/TierSupportActions.js121
-rw-r--r--src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx16
-rw-r--r--src/generic-components/componentManager/ComponentManagerContainer.jsx16
-rw-r--r--src/generic-components/graph/Link.jsx66
-rw-r--r--src/generic-components/graph/Node.jsx54
-rw-r--r--src/generic-components/graph/SVGShape.jsx66
-rw-r--r--src/generic-components/input/ToggleInput.jsx100
-rw-r--r--src/generic-components/input/inputOptions/InputOptions.jsx418
-rw-r--r--src/generic-components/map/TopographicMap.jsx2
-rw-r--r--src/generic-components/notifications/NotificationModal.jsx158
-rw-r--r--src/generic-components/panel/SlidePanel.jsx216
-rw-r--r--src/generic-components/titledContainer/TitledContainer.jsx2
-rw-r--r--src/generic-components/toggleButtonGroup/ToggleButtonGroup.jsx78
-rw-r--r--src/utils/Crypto.js13
-rw-r--r--src/utils/SpinnerContainer.jsx4
-rw-r--r--test/autoCompleteSearchBar/AutoCompleteSearchBar.test.js40
-rw-r--r--test/configurableViews/ConfigurableViewActions.test.js208
-rw-r--r--test/configurableViews/ConfigurableViewReducer.test.js54
-rw-r--r--test/fileMock.js (renamed from scripts/test/fileMock.js)0
-rw-r--r--test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.test.js35
-rw-r--r--test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarReducer.test.js154
-rw-r--r--test/globalInlineMessageBar/GlobalInlineMessageBar.test.js37
-rw-r--r--test/globalInlineMessageBar/GlobalInlineMessageBarAction.test.js42
-rw-r--r--test/globalInlineMessageBar/GlobalInlineMessageBarReducer.test.js40
-rw-r--r--test/input/SelectInput.test.js13
-rw-r--r--test/input/ToggleInput.test.js12
-rw-r--r--test/setupTests.js (renamed from scripts/test/setupTests.js)0
-rw-r--r--test/styleMock.js (renamed from scripts/test/styleMock.js)0
-rw-r--r--test/tierSupport/TierSupportActions.test.js177
-rw-r--r--test/tierSupport/TierSupportReducer.test.js206
-rw-r--r--test/utils/KeyMirror.test.js79
-rw-r--r--test/utils/Routes.test.js129
-rw-r--r--test/utils/SpinnerContainer.test.js6
-rw-r--r--webpack.config.js131
-rw-r--r--webpack.devConfig.js135
52 files changed, 2268 insertions, 918 deletions
diff --git a/.gitignore b/.gitignore
index f759a7f..d5fd50c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,3 @@ test/coverage
npm-debug.log
.vscode
scripts/elasticsearch/auditBulkLoad.json
-.classpath
-.project
-.settings/ \ No newline at end of file
diff --git a/package.json b/package.json
index 211d047..898e70e 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,6 @@
"license": "Apache-2.0",
"dependencies": {
"collapsible-sliding-panel": "1.0.0",
- "configurable-interactive-layout": "^2.2.14",
"core-js": "^2.4.0",
"crypto-js": "^3.1.9-1",
"d3": "^4.12.0",
@@ -48,13 +47,11 @@
"redux": "^3.3.1",
"redux-form": "^6.2.1",
"redux-thunk": "^2.1.0",
- "spinner-container": "^1.0.27",
"topojson": "^2.2.0",
"uuid-js": "^0.7.5",
"validator": "^4.3.0",
"velocity-react": "^1.4.1",
- "vertical-filter-bar": "^1.0.7",
- "wolfy87-eventemitter": "^5.2.5"
+ "vertical-filter-bar": "^1.0.7"
},
"devDependencies": {
"babel-core": "^6.25.0",
@@ -134,6 +131,10 @@
"!**/resources/**",
"!**/dist/**",
"!**/scripts/**",
+ "!**/gulpfile.js/**",
+ "!**/karma.conf.js/**",
+ "!**/webpack.config.js/**",
+ "!**/webpack.devConfig.js/**",
"!**/tools/**"
]
},
diff --git a/resources/images/icons/reports.png b/resources/images/icons/reports.png
new file mode 100644
index 0000000..b3d3c4c
--- /dev/null
+++ b/resources/images/icons/reports.png
Binary files differ
diff --git a/resources/images/icons/reports.svg b/resources/images/icons/reports.svg
new file mode 100644
index 0000000..3ca0bf1
--- /dev/null
+++ b/resources/images/icons/reports.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 22.89"><title>Asset 5</title><g id="ec3f4fde-b9c3-41a2-ac22-ee6c286fa00e" data-name="Layer 2"><g id="07b86c20-b47a-4f9d-8616-1a3add252348" data-name="Layer 1"><path d="M9.9,3.74A9.25,9.25,0,1,0,19.15,13H9.9Z" fill="none" stroke="#06afd1" stroke-linejoin="round" stroke-width="1.3"/><path d="M13.1.65V9.9h9.25A9.25,9.25,0,0,0,13.1.65Z" fill="none" stroke="#06afd1" stroke-linejoin="round" stroke-width="1.3"/></g></g></svg> \ No newline at end of file
diff --git a/resources/scss/common/_layout.scss b/resources/scss/common/_layout.scss
index 6863baf..11265c5 100644
--- a/resources/scss/common/_layout.scss
+++ b/resources/scss/common/_layout.scss
@@ -38,7 +38,7 @@
.showContainer {
}
-.spinner-container {
+.spin-container {
overflow: hidden;
position: relative;
}
@@ -50,6 +50,6 @@
top: 49%;
}
-.spinner-content {
+.spin-content {
opacity: 0.2;
}
diff --git a/resources/views/customComponents.json b/resources/views/customComponents.json
new file mode 100644
index 0000000..0d4f101
--- /dev/null
+++ b/resources/views/customComponents.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/scripts/build/build.sh b/scripts/build/build.sh
index 9fd9fd2..7af49cd 100644
--- a/scripts/build/build.sh
+++ b/scripts/build/build.sh
@@ -4,10 +4,10 @@
#
# UpdateFEwithExtensions
#
-# Description: Update files in the FE code based on the content of the
-# extensions. For this to work, extensions are required to fill
+# Description: Update files in the FE code based on the content of the
+# extensions. For this to work, extensions are required to fill
# some files. The current script does not care too much about
-# their locations (other than being in the component
+# their locations (other than being in the component
# nodes-modules) but the file name must match.
#
###############################################################################
@@ -39,7 +39,7 @@ UpdateFEwithExtensions(){
# Get extensible json additions
echo "build.sh --- Appending to resources/views/extensibleViews.json"
extConfig=`find node_modules/ -name "extensibleViews.json"`
- if [ ! -z "$extConfig" ]; then
+ if [ ! -z "$extConfig" ]; then
jq -n 'input | . +=[inputs]' resources/views/extensibleViews.json $extConfig > tmp
mv tmp resources/views/extensibleViews.json
fi
@@ -58,7 +58,7 @@ UpdateFEwithExtensions(){
# Get overlay json additions
echo "build.sh --- Appending to resources/overlays/overlaysDetails.json"
extConfig=`find node_modules/ -name "overlaysDetails.json"`
- if [ ! -z "$extConfig" ]; then
+ if [ ! -z "$extConfig" ]; then
jq -n 'input | . +=[inputs]' resources/overlays/overlaysDetails.json $extConfig > tmp
mv tmp resources/overlays/overlaysDetails.json
fi
@@ -67,11 +67,11 @@ UpdateFEwithExtensions(){
echo "build.sh --- Appending to resources/scss/customViews.scss"
touch resources/scss/customViews.scss
extSCSS=`find -name "extensibility.scss"`
- for i in $extSCSS; do
+ for i in $extSCSS; do
cat $i >> resources/scss/customViews.scss
done
-
-
+
+
}
updateStyle()
@@ -101,8 +101,8 @@ updateStyle()
if [ -f tmp.style.imports ]; then
sed -i /"import 'resources\/scss\/style\.scss';"/d src/app/main.app.jsx
fi
-
- # Update bootstrap
+
+ # Update bootstrap
echo "build.sh --- Update resources/scss/bootstrap.scss"
bootImports=`find extStyle/ -name "bootstrap.scss"`
for i in $bootImports; do
@@ -115,6 +115,19 @@ updateStyle()
fi
}
+UpdateFEWithCustomViews(){
+ # Append statements to src/app/configurableViews/index.js
+ echo "build.sh --- Appending to src/app/configurableViews/index.js"
+ custViewImports=`find -name "confViewIndex"`
+ for i in $custViewImports; do
+ cat $i | grep import > tmp.imports
+ cat $i | grep 'components\[' > tmp.components
+
+ sed -i '/Import section/ r tmp.imports' src/app/configurableViews/index.js
+ sed -i '/Components section/ r tmp.components' src/app/configurableViews/index.js
+ done
+}
+
###############################################################################
#
# Main
@@ -143,4 +156,4 @@ updateStyle
# npm run build
echo "build.sh --- Running npm run build"
-npm run build \ No newline at end of file
+npm run build
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>
diff --git a/test/autoCompleteSearchBar/AutoCompleteSearchBar.test.js b/test/autoCompleteSearchBar/AutoCompleteSearchBar.test.js
new file mode 100644
index 0000000..7ba3d11
--- /dev/null
+++ b/test/autoCompleteSearchBar/AutoCompleteSearchBar.test.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import {Provider} from 'react-redux'
+import configureStore from 'redux-mock-store';
+
+import AutoCompleteSearchBar from 'generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx';
+
+describe('AutoCompleteSearchBarTests', () => {
+ const suggestions = [
+ {
+ text: 'Apple'
+ },
+ {
+ text: 'Orange'
+ },
+ {
+ text: 'Banana'
+ }
+ ];
+ const initialState = {
+ globalAutoCompleteSearchBarReducer: {
+ value: '',
+ suggestions: [],
+ cachedSuggestions: [],
+ suggestionName: ''
+ }
+ };
+ const mockStore = configureStore();
+ let store, wrapper;
+
+ beforeEach( () => {
+ store = mockStore(initialState);
+ wrapper = shallow(<Provider store={store}><AutoCompleteSearchBar /></Provider>);
+ })
+
+ it('render search bar - visible', () => {
+ expect(wrapper).toHaveLength(1); // ensure the message bar is mounted
+ expect(wrapper.find(AutoCompleteSearchBar)).toHaveLength(1); // ensure the InlineMessage is mounted
+ });
+})
diff --git a/test/configurableViews/ConfigurableViewActions.test.js b/test/configurableViews/ConfigurableViewActions.test.js
new file mode 100644
index 0000000..9d7bc9e
--- /dev/null
+++ b/test/configurableViews/ConfigurableViewActions.test.js
@@ -0,0 +1,208 @@
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk'
+import fetchMock from 'fetch-mock';
+import {
+ configurableViewsActionTypes
+} from 'app/configurableViews/ConfigurableViewConstants.js';
+import {
+ newCustomComponentsEvent,
+ setCustomRoutes,
+ getConfigurableViewConfigs
+} from 'app/configurableViews/ConfigurableViewActions.js'
+
+
+describe('ConfigurableViewActionTests', () => {
+ const sampleConfig = {
+ "id": "aggregateReport",
+ "title": "Aggregate Report",
+ "iconURL": "resources/images/sampleAggReportIcon.svg",
+ "iconHoverURL": "resources/images/sampleAggReportIconHover.svg",
+ "viewType": "ConfigurableCardView",
+ "layout": {
+ "draggable": true,
+ "resizable": true,
+ "rowHeight": 100,
+ "cardMargin": [
+ 20,
+ 20
+ ],
+ "cardPadding": [
+ 20,
+ 20
+ ],
+ "breakpoints": [
+ {
+ "id": "lg",
+ "col": 12,
+ "width": 1400
+ },
+ {
+ "id": "md",
+ "col": 8,
+ "width": 1200
+ },
+ {
+ "id": "sm",
+ "col": 6,
+ "width": 1024
+ }
+ ]
+ },
+ "components": [
+ {
+ "id": "visualization1",
+ "title": "Total VNFs",
+ "queryData": {
+ "eventId": "visualization1",
+ "api": "/get-component-data",
+ "method": "POST",
+ "headers": {
+ "accept": "application/json"
+ },
+ "componentDataDescriptor": {
+ "index": "aggregate_generic-vnf_index",
+ "queryType": "aggregation",
+ "query": {
+ "filter": {},
+ "queries": [],
+ "aggregations": [
+ {
+ "name": "prov-status",
+ "aggregation": {
+ "group-by": {
+ "field": "prov-status",
+ "size": 0
+ }
+ }
+ },
+ {
+ "name": "orchestration-status",
+ "aggregation": {
+ "group-by": {
+ "field": "orchestration-status",
+ "size": 0
+ }
+ }
+ },
+ {
+ "name": "nf-type",
+ "aggregation": {
+ "group-by": {
+ "field": "nf-type",
+ "size": 0
+ }
+ }
+ },
+ {
+ "name": "nf-role",
+ "aggregation": {
+ "group-by": {
+ "field": "nf-role",
+ "size": 0
+ }
+ }
+ }
+ ]
+ },
+ "responseTransformation": {
+ "type": "count",
+ "spec": {
+ "countType": "total",
+ "countResponseLabel": "display"
+ }
+ }
+ }
+ },
+ "containerData": {
+ "containerType": "NetworkQueryCard",
+ "visualizationType": "text",
+ "visualizationProp": {
+ "display": "",
+ "style": {
+ "textAlign": "center",
+ "fontSize": "50px",
+ "fontWeight": "bold",
+ "paddingTop": "50px"
+ }
+ },
+ "breakpoints": {
+ "lg": {
+ "w": 2,
+ "h": 2,
+ "x": 0,
+ "y": 0
+ },
+ "md": {
+ "w": 2,
+ "h": 2,
+ "x": 0,
+ "y": 0
+ },
+ "sm": {
+ "w": 6,
+ "h": 2,
+ "x": 0,
+ "y": 0
+ }
+ }
+ }
+ }
+ ]
+ };
+
+ it('newCustomComponentsEvent', () => {
+ const components = [
+ {
+ compId: 'someId',
+ compName: 'Some Name'
+ }
+ ];
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({});
+ store.dispatch(newCustomComponentsEvent(components));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: configurableViewsActionTypes.CUSTOM_COMPONENTS_RECEIVED,
+ data: components
+ }]);
+ });
+
+ it('setCustomRoutes', () => {
+ const routes = [
+ {
+ routeName: 'Some Custom Route',
+ path: 'some/route/path'
+ }
+ ];
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({});
+ store.dispatch(setCustomRoutes(routes));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: configurableViewsActionTypes.CUSTOM_ROUTES,
+ data: routes
+ }]);
+ });
+
+ it('getConfigurableViewConfigs', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({});
+ const expectedActions = [
+ {
+ type: configurableViewsActionTypes.CONFIGURABLE_VIEWS_CONFIG_RECEIVED,
+ data: sampleConfig
+ }
+ ];
+ fetchMock.mock('*', sampleConfig);
+
+ return store.dispatch(getConfigurableViewConfigs())
+ .then( () => {
+ const actions = store.getActions();
+ expect(actions).toEqual(expectedActions);
+ fetchMock.restore();
+ });
+ });
+})
diff --git a/test/configurableViews/ConfigurableViewReducer.test.js b/test/configurableViews/ConfigurableViewReducer.test.js
new file mode 100644
index 0000000..0c5c46e
--- /dev/null
+++ b/test/configurableViews/ConfigurableViewReducer.test.js
@@ -0,0 +1,54 @@
+import {
+ configurableViewsActionTypes
+} from 'app/configurableViews/ConfigurableViewConstants.js';
+import ConfigurableViewReducer from 'app/configurableViews/ConfigurableViewReducer.js'
+describe('ConfigurableViewsReducerTests', () => {
+ it('Action Type: CONFIGURABLE_VIEWS_CONFIG_RECEIVED', () => {
+ const data = {
+ viewId: 'someViewId',
+ viewName: 'Some View Name',
+ viewRoute: 'some/view/route'
+ };
+ const action = {
+ type: configurableViewsActionTypes.CONFIGURABLE_VIEWS_CONFIG_RECEIVED,
+ data: data
+ };
+ let state = {};
+ state = ConfigurableViewReducer(state, action);
+ expect(state).toEqual({
+ configurableViewsConfig: data
+ });
+ });
+
+ it('Action Type: CUSTOM_COMPONENTS_RECEIVED', () => {
+ const data = {
+ componentName: 'someComponentName',
+ componentData: {
+ blah: 'blah',
+ filler: 'filler'
+ }
+ };
+ const action = {
+ type: configurableViewsActionTypes.CUSTOM_COMPONENTS_RECEIVED,
+ data: data
+ };
+ let state = {};
+ state = ConfigurableViewReducer(state, action);
+ expect(state).toEqual({
+ customComponents: data
+ });
+ });
+
+ it('Action Type: CUSTOM_ROUTES', () => {
+ const data = 'some/custom/route';
+ const action = {
+ type: configurableViewsActionTypes.CUSTOM_ROUTES,
+ data: data
+ };
+ let state = {};
+ state = ConfigurableViewReducer(state, action);
+ expect(state).toEqual({
+ customRoutes: data
+ });
+ });
+})
diff --git a/scripts/test/fileMock.js b/test/fileMock.js
index 86059f3..86059f3 100644
--- a/scripts/test/fileMock.js
+++ b/test/fileMock.js
diff --git a/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.test.js b/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.test.js
new file mode 100644
index 0000000..25676b7
--- /dev/null
+++ b/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.test.js
@@ -0,0 +1,35 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import {Provider} from 'react-redux'
+import configureStore from 'redux-mock-store';
+
+import GlobalAutoCompleteSearchBar from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.jsx'
+import AutoCompleteSearchBar from 'generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx';
+import {
+ globalAutoCompleteSearchBarActionTypes
+} from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarConstants.js';
+
+describe('GlobalAutoCompleteSearchBarTests', () => {
+ const initValue = 'some random search text';
+ const initialState = {
+ globalAutoCompleteSearchBarReducer: {
+ value: initValue
+ }
+ };
+ const mockStore = configureStore();
+ let store, wrapper;
+
+ beforeEach( () => {
+ store = mockStore(initialState);
+ wrapper = mount(<Provider store={store}><GlobalAutoCompleteSearchBar /></Provider>);
+ })
+
+ it('render search bar - visible', () => {
+ expect(wrapper).toHaveLength(1); // ensure the message bar is mounted
+ expect(wrapper.find(AutoCompleteSearchBar)).toHaveLength(1); // ensure the InlineMessage is mounted
+ });
+
+ it('props assigned properly', () => {
+ expect(wrapper.find(AutoCompleteSearchBar).props().value).toEqual(initValue); // check that the props match
+ })
+})
diff --git a/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarReducer.test.js b/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarReducer.test.js
new file mode 100644
index 0000000..1078df6
--- /dev/null
+++ b/test/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarReducer.test.js
@@ -0,0 +1,154 @@
+import i18n from 'utils/i18n/i18n';
+import GlobalAutoCompleteSearchBarReducer from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarReducer.js';
+import {
+ globalAutoCompleteSearchBarActionTypes,
+ NO_MATCHES_FOUND
+} from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarConstants.js';
+import {
+ MESSAGE_LEVEL_WARNING,
+ MESSAGE_LEVEL_DANGER
+} from 'utils/GlobalConstants.js';
+
+describe('GlobalAutoCompleteSearchBarReducerTests', () => {
+ it('Action Type: SUGGESTION_FOUND', () => {
+ const suggestions = [
+ {
+ entityType: 'some entity type',
+ value: 'selected value'
+ },
+ {
+ entityType: 'some entity type',
+ value: 'other selected value'
+ }
+ ];
+ const errMsg = 'some error message';
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SUGGESTION_FOUND,
+ data: {
+ suggestions: suggestions,
+ errorMsg: errMsg
+ }
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: suggestions,
+ cachedSuggestions: suggestions,
+ feedbackMsgText: errMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_DANGER
+ });
+ });
+
+ it('Action Type: SUGGESTION_NOT_FOUND', () => {
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SUGGESTION_NOT_FOUND,
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: [{ text: i18n(NO_MATCHES_FOUND)}],
+ cachedSuggestions: [{ entityType: i18n(NO_MATCHES_FOUND)}],
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+
+ it('Action Type: CLEAR_SUGGESTIONS_TEXT_FIELD', () => {
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.CLEAR_SUGGESTIONS_TEXT_FIELD,
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: [],
+ cachedSuggestions: [],
+ value: '',
+ feedbackMsgText: '',
+ feedbackMsgSeverity: '',
+ clearSearchText: false
+ });
+ });
+
+ it('Action Type: CLEAR_SUGGESTIONS', () => {
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.CLEAR_SUGGESTIONS,
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: []
+ });
+ });
+
+ it('Action Type: SUGGESTION_CHANGED', () => {
+ const suggestionText = 'some suggestion text';
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SUGGESTION_CHANGED,
+ data: suggestionText
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ value: suggestionText,
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+
+ it('Action Type: SUGGESTION_CLICKED', () => {
+ const suggestion = {
+ entityType: 'some entity type',
+ value: 'selected value'
+ };
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SUGGESTION_CLICKED,
+ data: {
+ selectedSuggestion: suggestion
+ }
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ selectedSuggestion: suggestion,
+ performPrepareVisualization: true,
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+
+ it('Action Type: NETWORK_ERROR', () => {
+ const errMsg = 'some error message';
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.NETWORK_ERROR,
+ data: {
+ errorMsg: errMsg
+ }
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: [],
+ cachedSuggestions: [],
+ feedbackMsgText: errMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_DANGER
+ });
+ });
+
+ it('Action Type: SEARCH_WARNING_EVENT', () => {
+ const errMsg = 'some error message';
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SEARCH_WARNING_EVENT,
+ data: {
+ errorMsg: errMsg
+ }
+ };
+ let state = {};
+ state = GlobalAutoCompleteSearchBarReducer(state, action);
+ expect(state).toEqual({
+ suggestions: [],
+ cachedSuggestions: [],
+ feedbackMsgText: errMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_WARNING
+ });
+ });
+})
diff --git a/test/globalInlineMessageBar/GlobalInlineMessageBar.test.js b/test/globalInlineMessageBar/GlobalInlineMessageBar.test.js
new file mode 100644
index 0000000..9dc2a28
--- /dev/null
+++ b/test/globalInlineMessageBar/GlobalInlineMessageBar.test.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import {Provider} from 'react-redux'
+import configureStore from 'redux-mock-store';
+
+import GlobalInlineMessageBar from 'app/globalInlineMessageBar/GlobalInlineMessageBar.jsx'
+import {
+ MESSAGE_LEVEL_WARNING
+} from 'utils/GlobalConstants.js'
+import InlineMessage from 'generic-components/InlineMessage/InlineMessage.jsx';
+
+describe('GlobalInlineMessageBarTests', () => {
+ const errMsg = 'some random message';
+ const initialState = {
+ globalInlineMessageBar: {
+ feedbackMsgText: errMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_WARNING
+ }
+ };
+ const mockStore = configureStore();
+ let store, wrapper;
+
+ beforeEach( () => {
+ store = mockStore(initialState);
+ wrapper = mount(<Provider store={store}><GlobalInlineMessageBar /></Provider>);
+ })
+
+ it('render message bar - visible', () => {
+ expect(wrapper).toHaveLength(1); // ensure the message bar is mounted
+ expect(wrapper.find(InlineMessage)).toHaveLength(1); // ensure the InlineMessage is mounted
+ });
+
+ it('props assigned properly', () => {
+ expect(wrapper.find(InlineMessage).props().level).toEqual(MESSAGE_LEVEL_WARNING); // check that the props match
+ expect(wrapper.find(InlineMessage).props().messageTxt).toEqual(errMsg); // check that the props match
+ })
+})
diff --git a/test/globalInlineMessageBar/GlobalInlineMessageBarAction.test.js b/test/globalInlineMessageBar/GlobalInlineMessageBarAction.test.js
new file mode 100644
index 0000000..4def5ac
--- /dev/null
+++ b/test/globalInlineMessageBar/GlobalInlineMessageBarAction.test.js
@@ -0,0 +1,42 @@
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+
+import {
+ getSetGlobalMessageEvent,
+ getClearGlobalMessageEvent
+} from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js';
+import {
+ globalInlineMessageBarActionTypes
+} from 'app/globalInlineMessageBar/GlobalInlineMessageBarConstants.js';
+import {
+ MESSAGE_LEVEL_WARNING
+} from 'utils/GlobalConstants.js'
+
+describe('GlobalInlineMessageBarActionTests', () => {
+ it('getSetGlobalMessageEvent', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({});
+ const msgText = 'some test msg';
+ store.dispatch(getSetGlobalMessageEvent(msgText, MESSAGE_LEVEL_WARNING));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE,
+ data: {
+ msgText: msgText,
+ msgSeverity: MESSAGE_LEVEL_WARNING
+ }
+ }]);
+ });
+
+ it('getClearGlobalMessageEvent', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({});
+ store.dispatch(getClearGlobalMessageEvent());
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: globalInlineMessageBarActionTypes.CLEAR_GLOBAL_MESSAGE
+ }]);
+ });
+})
diff --git a/test/globalInlineMessageBar/GlobalInlineMessageBarReducer.test.js b/test/globalInlineMessageBar/GlobalInlineMessageBarReducer.test.js
new file mode 100644
index 0000000..62389b4
--- /dev/null
+++ b/test/globalInlineMessageBar/GlobalInlineMessageBarReducer.test.js
@@ -0,0 +1,40 @@
+import GlobalInlineMessageBarReducer from 'app/globalInlineMessageBar/GlobalInlineMessageBarReducer.js';
+import {
+ globalInlineMessageBarActionTypes
+} from 'app/globalInlineMessageBar/GlobalInlineMessageBarConstants.js';
+import {
+ MESSAGE_LEVEL_WARNING
+} from 'utils/GlobalConstants.js'
+
+describe('GlobalInlineMessageBarReducerTests', () => {
+ it('Action Type: SET_GLOBAL_MESSAGE', () => {
+ const action = {
+ type: globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE,
+ data: {
+ msgText: 'some error message here',
+ msgSeverity: MESSAGE_LEVEL_WARNING
+ }
+ };
+ let state = {};
+ state = GlobalInlineMessageBarReducer(state, action);
+ expect(state).toEqual({
+ feedbackMsgText: action.data.msgText,
+ feedbackMsgSeverity: action.data.msgSeverity
+ });
+ });
+
+ it('Action Type: CLEAR_GLOBAL_MESSAGE', () => {
+ const action = {
+ type: globalInlineMessageBarActionTypes.CLEAR_GLOBAL_MESSAGE
+ };
+ let state = {
+ feedbackMsgText: 'some error message here',
+ feedbackMsgSeverity: MESSAGE_LEVEL_WARNING
+ };
+ state = GlobalInlineMessageBarReducer(state, action);
+ expect(state).toEqual({
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+})
diff --git a/test/input/SelectInput.test.js b/test/input/SelectInput.test.js
new file mode 100644
index 0000000..a669361
--- /dev/null
+++ b/test/input/SelectInput.test.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import Select from 'react-select';
+
+import SelectInput from 'generic-components/input/SelectInput.jsx';
+
+describe('SelectInput Tests', () => {
+ it('render select input - visible', () => {
+ const select = mount( <SelectInput /> );
+ expect(select).toHaveLength(1); // ensure the message bar is mounted
+ expect(select.find(Select)).toHaveLength(1); // ensure the InlineMessage is mounted
+ });
+})
diff --git a/test/input/ToggleInput.test.js b/test/input/ToggleInput.test.js
new file mode 100644
index 0000000..80f0345
--- /dev/null
+++ b/test/input/ToggleInput.test.js
@@ -0,0 +1,12 @@
+import React from 'react';
+import { mount } from 'enzyme';
+
+import ToggleInput from 'generic-components/input/ToggleInput.jsx';
+
+describe('ToggleInput Tests', () => {
+ it('render toggle input - visible', () => {
+ const toggle = mount( <ToggleInput /> );
+ expect(toggle).toHaveLength(1); // ensure the message bar is mounted
+ expect(toggle.find('input')).toHaveLength(1); // ensure the InlineMessage is mounted
+ });
+})
diff --git a/scripts/test/setupTests.js b/test/setupTests.js
index 2318628..2318628 100644
--- a/scripts/test/setupTests.js
+++ b/test/setupTests.js
diff --git a/scripts/test/styleMock.js b/test/styleMock.js
index f053ebf..f053ebf 100644
--- a/scripts/test/styleMock.js
+++ b/test/styleMock.js
diff --git a/test/tierSupport/TierSupportActions.test.js b/test/tierSupport/TierSupportActions.test.js
new file mode 100644
index 0000000..62485ee
--- /dev/null
+++ b/test/tierSupport/TierSupportActions.test.js
@@ -0,0 +1,177 @@
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk'
+import {
+ onNodeDetailsChange,
+ splitPaneResize,
+ onNodeMenuChange,
+ clearVIData,
+ setNotificationText
+} from 'app/tierSupport/TierSupportActions.js';
+import {
+ tierSupportActionTypes
+} from 'app/tierSupport/TierSupportConstants.js';
+import {
+ MESSAGE_LEVEL_WARNING
+} from 'utils/GlobalConstants.js';
+import {
+ globalInlineMessageBarActionTypes
+} from 'app/globalInlineMessageBar/GlobalInlineMessageBarConstants.js';
+
+describe('TierSupportActionTests', () => {
+ it('onNodeDetailsChange', () => {
+ const newDetails = {
+ id: '7352312c7bfa814c3071a803d98c5b670952765974876e55ef954e0f8a930b1c',
+ itemType: 'complex',
+ nodeMeta: {
+ nodeLabel1: 'Artic',
+ nodeValidated: false,
+ nodeLocation: 'bottom'
+ },
+ rootNode: false,
+ index: 2,
+ };
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ store.dispatch(onNodeDetailsChange(newDetails));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: tierSupportActionTypes.TS_GRAPH_NODE_SELECTED,
+ data: newDetails
+ }]);
+ });
+
+ it('splitPaneResize', () => {
+ const initialLoad = {
+ test: 'message'
+ };
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ store.dispatch(splitPaneResize(initialLoad));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: tierSupportActionTypes.SPLIT_PANE_RESIZE,
+ data: initialLoad
+ }]);
+ });
+
+ it('onNodeMenuChange', () => {
+ const selectedMenu = {
+ test: 'menuData'
+ };
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ store.dispatch(onNodeMenuChange(selectedMenu));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: tierSupportActionTypes.TS_GRAPH_NODE_MENU_SELECTED,
+ data: selectedMenu
+ }]);
+ });
+
+ it('clearVIData', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ store.dispatch(clearVIData());
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: tierSupportActionTypes.TIER_SUPPORT_CLEAR_DATA
+ }]);
+ });
+ //
+ // it('fetchSelectedNodeElement - no results', () => {
+ // const middlewares = [thunk];
+ // const mockStore = configureStore(middlewares);
+ // const store = mockStore({ tierSupportReducer: {} });
+ // const nodes = [
+ // {
+ // id: '7352312c7bfa814c3071a803d98c5b670952765974876e55ef954e0f8a930b1c',
+ // itemType: 'complex',
+ // nodeMeta: {
+ // className: 'selectedSearchedNodeClass',
+ // nodeLabel1: 'Artic',
+ // nodeValidated: false,
+ // nodeLocation: 'bottom'
+ // },
+ // rootNode: false,
+ // index: 2
+ // },
+ // {
+ // id: '3899453d98c5b670952765974876e55ef954e0f8a930b1c',
+ // itemType: 'generic-vnf',
+ // nodeMeta: {
+ // className: 'someOtherClassName',
+ // nodeLabel1: 'Artic',
+ // nodeValidated: false,
+ // nodeLocation: 'bottom'
+ // },
+ // rootNode: false,
+ // index: 1
+ // }
+ // ];
+ // const expectedActions = [
+ // {
+ // type: tierSupportActionTypes.TS_NODE_SEARCH_RESULTS,
+ // data: {
+ // nodes: nodes
+ // }
+ // },
+ // {
+ // type: tierSupportActionTypes.TS_GRAPH_NODE_SELECTED,
+ // data: nodes[0]
+ // }
+ // ];
+ //
+ // console.log(nodes);
+ //
+ // let fetchRequestCallback = () => {
+ // const results = {
+ // nodes: nodes
+ // };
+ // let init = { status: 200 };
+ // let myBlob = new Blob();
+ // let response = new Response();
+ // return new Promise((resolve, reject) => {
+ // resolve(response);
+ // });
+ // };
+ // return store.dispatch(fetchSelectedNodeElement(fetchRequestCallback))
+ // .then( () => {
+ // const actions = store.getActions();
+ // expect(actions).toEqual(expectedActions);
+ // });
+ // });
+
+ it('setNotificationText', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ const msgText = 'some test text';
+ const msgSeverity = MESSAGE_LEVEL_WARNING;
+ store.dispatch(setNotificationText(msgText, msgSeverity));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: globalInlineMessageBarActionTypes.SET_GLOBAL_MESSAGE,
+ data: {
+ msgText: msgText,
+ msgSeverity: msgSeverity
+ }
+ }]);
+ });
+
+ it('Clear notification text with setNotificationText', () => {
+ const middlewares = [thunk];
+ const mockStore = configureStore(middlewares);
+ const store = mockStore({ tierSupportReducer: {} });
+ const msgText = '';
+ const msgSeverity = MESSAGE_LEVEL_WARNING;
+ store.dispatch(setNotificationText(msgText, msgSeverity));
+ const actions = store.getActions();
+ expect(actions).toEqual([{
+ type: globalInlineMessageBarActionTypes.CLEAR_GLOBAL_MESSAGE
+ }]);
+ });
+})
diff --git a/test/tierSupport/TierSupportReducer.test.js b/test/tierSupport/TierSupportReducer.test.js
new file mode 100644
index 0000000..9825a06
--- /dev/null
+++ b/test/tierSupport/TierSupportReducer.test.js
@@ -0,0 +1,206 @@
+import TierSupportReducer from 'app/tierSupport/TierSupportReducer.js';
+import ForceDirectedGraph from 'generic-components/graph/ForceDirectedGraph.jsx';
+import {
+ tierSupportActionTypes,
+ TSUI_GRAPH_MENU_NODE_DETAILS
+} from 'app/tierSupport/TierSupportConstants.js';
+import {
+ MESSAGE_LEVEL_WARNING,
+ MESSAGE_LEVEL_DANGER
+} from 'utils/GlobalConstants.js';
+import {
+ globalAutoCompleteSearchBarActionTypes
+} from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarConstants.js';
+
+describe('TierSupportReducerTests', () => {
+ it('Action Type: TS_NODE_SEARCH_RESULTS', () => {
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous tests
+ const action = {
+ type: tierSupportActionTypes.TS_NODE_SEARCH_RESULTS,
+ data: {
+ nodes: [
+ {
+ nodeMeta: {
+ searchTarget: true
+ },
+ itemProperties: 'someProperty'
+ }
+ ],
+ links: ['link', 'information'],
+ graphMeta: { graph: 'meta' }
+ }
+ };
+ let graphData = ForceDirectedGraph.generateNewProps(action.data.nodes, action.data.links,
+ action.data.graphMeta);
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous statement
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ forceDirectedGraphRawData: graphData,
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+
+ it('Action Type: TS_GRAPH_NODE_MENU_SELECTED', () => {
+ const action = {
+ type: tierSupportActionTypes.TS_GRAPH_NODE_MENU_SELECTED,
+ data: {
+ attr1: 'someValue',
+ attr2: 'someOterValue'
+ }
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ graphNodeSelectedMenu: action.data
+ });
+ });
+
+ it('Action Type: TS_NODE_SEARCH_NO_RESULTS', () => {
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous tests
+ let emptyNodesAndLinksNoResults = {
+ graphCounter: 1,
+ graphMeta: {},
+ linkDataArray: [],
+ nodeDataArray: []
+ };
+ const action = {
+ type: tierSupportActionTypes.TS_NODE_SEARCH_NO_RESULTS,
+ data: {
+ errorMsg: 'some error message'
+ }
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ forceDirectedGraphRawData: emptyNodesAndLinksNoResults,
+ graphNodeSelectedMenu: TSUI_GRAPH_MENU_NODE_DETAILS,
+ feedbackMsgText: action.data.errorMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_WARNING
+ });
+ });
+
+ it('Action Type: TIER_SUPPORT_NETWORK_ERROR', () => {
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous tests
+ let emptyNodesAndLinksNoResults = {
+ graphCounter: 1,
+ graphMeta: {},
+ linkDataArray: [],
+ nodeDataArray: []
+ };
+ const action = {
+ type: tierSupportActionTypes.TIER_SUPPORT_NETWORK_ERROR,
+ data: {
+ errorMsg: 'some error message'
+ }
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ forceDirectedGraphRawData: emptyNodesAndLinksNoResults,
+ graphNodeSelectedMenu: TSUI_GRAPH_MENU_NODE_DETAILS,
+ feedbackMsgText: action.data.errorMsg,
+ feedbackMsgSeverity: MESSAGE_LEVEL_DANGER
+ });
+ });
+
+ it('Action Type: TIER_SUPPORT_CLEAR_DATA', () => {
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous tests
+ let emptyNodesAndLinksNoResults = {
+ graphCounter: 1,
+ graphMeta: {},
+ linkDataArray: [],
+ nodeDataArray: []
+ };
+ const action = {
+ type: tierSupportActionTypes.TIER_SUPPORT_CLEAR_DATA
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ forceDirectedGraphRawData: emptyNodesAndLinksNoResults,
+ graphNodeSelectedMenu: TSUI_GRAPH_MENU_NODE_DETAILS,
+ feedbackMsgText: '',
+ feedbackMsgSeverity: ''
+ });
+ });
+
+ it('Action Type: TS_GRAPH_NODE_SELECTED', () => {
+ const action = {
+ type: tierSupportActionTypes.TS_GRAPH_NODE_SELECTED,
+ data: 'some action data'
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ nodeData: action.data
+ });
+ });
+
+ it('Action Type: TIER_SUPPORT_ACTIVATE_BUSY_FEEDBACK', () => {
+ const action = {
+ type: tierSupportActionTypes.TIER_SUPPORT_ACTIVATE_BUSY_FEEDBACK,
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ enableBusyFeedback: true
+ });
+ });
+
+ it('Action Type: TIER_SUPPORT_DISABLE_BUSY_FEEDBACK', () => {
+ const action = {
+ type: tierSupportActionTypes.TIER_SUPPORT_DISABLE_BUSY_FEEDBACK,
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ enableBusyFeedback: false
+ });
+ });
+
+ it('Action Type: SEARCH_WARNING_EVENT', () => {
+ ForceDirectedGraph.graphCounter = 0; // ensuring counter is at zero after previous tests
+ let emptyNodesAndLinksNoResults = {
+ graphCounter: 1,
+ graphMeta: {},
+ linkDataArray: [],
+ nodeDataArray: []
+ };
+ const action = {
+ type: globalAutoCompleteSearchBarActionTypes.SEARCH_WARNING_EVENT,
+ data: {
+ errorMsg: 'some warning msg'
+ }
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ forceDirectedGraphRawData: emptyNodesAndLinksNoResults,
+ graphNodeSelectedMenu: TSUI_GRAPH_MENU_NODE_DETAILS
+ });
+ });
+
+ it('Action Type: TS_OVERLAY_NETWORK_CALLBACK_RESPONSE_RECEIVED', () => {
+ const action = {
+ type: tierSupportActionTypes.TS_OVERLAY_NETWORK_CALLBACK_RESPONSE_RECEIVED,
+ data: {
+ curData: {
+ attr1: 'value1',
+ attr2: 'value2'
+ },
+ paramName: 'attr2',
+ overlayData: 'someValue2'
+ }
+ };
+ let state = {};
+ state = TierSupportReducer(state, action);
+ expect(state.tierSupportReducer).toEqual({
+ nodeData: {
+ attr1: 'value1',
+ attr2: 'someValue2'
+ }
+ });
+ });
+})
diff --git a/test/utils/KeyMirror.test.js b/test/utils/KeyMirror.test.js
new file mode 100644
index 0000000..22f6ff5
--- /dev/null
+++ b/test/utils/KeyMirror.test.js
@@ -0,0 +1,79 @@
+import keyMirror from 'utils/KeyMirror.js';
+
+describe('KeyMirror', () => {
+ it('valid key mirror with nulls', () => {
+ const obj = {
+ TIER_SUPPORT: null,
+ INVENTORY: null,
+ VNF_SEARCH: null
+ }
+ const mirror = keyMirror(obj);
+
+ for (let key in obj) {
+ expect(mirror).toHaveProperty(key);
+ expect(JSON.stringify(mirror[key])).toBe(JSON.stringify(Symbol(key)));
+ }
+ });
+
+ it('valid key mirror with undefined', () => {
+ const obj = {
+ TIER_SUPPORT: undefined,
+ INVENTORY: undefined,
+ VNF_SEARCH: undefined
+ }
+ const mirror = keyMirror(obj);
+
+ for (let key in obj) {
+ expect(mirror).toHaveProperty(key);
+ expect(JSON.stringify(mirror[key])).toBe(JSON.stringify(Symbol(key)));
+ }
+ });
+
+ it('valid key mirror with values', () => {
+ let preMirrorList = {
+ TIER_SUPPORT: 'tier support',
+ INVENTORY: 'inventory',
+ VNF_SEARCH: 'vnf search'
+ };
+ const mirror = keyMirror(preMirrorList);
+
+ for (let key in preMirrorList) {
+ expect(mirror).toHaveProperty(key);
+ expect(JSON.stringify(mirror[key])).toBe(JSON.stringify(preMirrorList[key]));
+ }
+ });
+
+ it('valid key mirror with objects', () => {
+ let preMirrorList = {
+ TIER_SUPPORT: {
+ name: 'tier support'
+ },
+ INVENTORY: {
+ name: 'inventory'
+ },
+ VNF_SEARCH: {
+ name: 'vnf search'
+ }
+ };
+ const mirror = keyMirror(preMirrorList);
+
+ for (let key in preMirrorList) {
+ expect(mirror).toHaveProperty(key);
+ expect(JSON.stringify(mirror[key])).toBe(JSON.stringify(preMirrorList[key]));
+ }
+ });
+
+ it('invalid key mirror', () => {
+ let preMirrorList = [
+ 'tier support',
+ 'inventory',
+ 'vnf search'
+ ]
+ const mirror = () => {
+ keyMirror(preMirrorList);
+ }
+
+ expect(mirror).toThrow(Error);
+ expect(mirror).toThrowError('keyMirror(...): Argument must be an object.');
+ });
+})
diff --git a/test/utils/Routes.test.js b/test/utils/Routes.test.js
new file mode 100644
index 0000000..12d318c
--- /dev/null
+++ b/test/utils/Routes.test.js
@@ -0,0 +1,129 @@
+import {
+ buildRouteObjWithHash,
+ decryptParamsForView,
+ buildRouteObjWithFilters,
+ changeUrlAddress
+} from 'utils/Routes.js';
+import {
+ encrypt
+} from 'utils/Crypto.js';
+
+describe('Routes', () => {
+ it('build route with hash', () => {
+ const expectedResult = {
+ route: '/vnfSearch',
+ hashId: 'someCrazyHashHere'
+ };
+
+ const result = buildRouteObjWithHash(expectedResult.route, expectedResult.hashId);
+
+ expect(JSON.stringify(result)).toBe(JSON.stringify(expectedResult));
+ });
+
+ it('decrypt params for view', () => {
+ const stringToEncrypt = 'someCrazyStringHere';
+ const encryptedString = encrypt(stringToEncrypt);
+ const result = decryptParamsForView(encryptedString);
+
+ expect(JSON.stringify(result)).toBe(JSON.stringify({}));
+ });
+
+ it('decrypt params for view with obj', () => {
+ const objToEncrypt = [{id: 'someCrazyParamHere'}, {id: 'anotherCrazyParam'}];
+ const encryptedObj = encrypt(JSON.stringify(objToEncrypt));
+ const result = decryptParamsForView(encryptedObj);
+
+ expect(JSON.stringify(result)).toBe(JSON.stringify(objToEncrypt));
+ });
+
+ it('build routes with filters', () => {
+ const objToEncrypt = [{id: 'someCrazyParamHere'}, {id: 'anotherCrazyParam'}];
+ const encryptedObj = encrypt(JSON.stringify(objToEncrypt));
+ const result = decryptParamsForView(encryptedObj);
+
+ expect(JSON.stringify(result)).toBe(JSON.stringify(objToEncrypt));
+ const filterObj = {
+ filter1: 'value1',
+ filter2: undefined,
+ filter3: 'anotherValue'
+ };
+ const routePath = '/vnfSearch';
+ const expectedResults = {
+ route: routePath,
+ filterValues: [
+ {
+ filterId: 'filter1',
+ filterValue: 'value1'
+ },
+ {
+ filterId: 'filter2',
+ filterValue: ''
+ },
+ {
+ filterId: 'filter3',
+ filterValue: 'anotherValue'
+ }
+ ]
+ }
+
+ const routeWithFilters = buildRouteObjWithFilters(routePath, filterObj);
+
+ expect(JSON.stringify(routeWithFilters)).toBe(JSON.stringify(expectedResults));
+ });
+
+ it('change URL address for well known paths', () => {
+ const pathObj = {
+ route: 'schema',
+ filterValues: [
+ {
+ filterId: 'filter1',
+ filterValue: 'value1'
+ },
+ {
+ filterId: 'filter2',
+ filterValue: undefined
+ },
+ {
+ filterId: 'filter3',
+ filterValue: 'anotherValue'
+ }
+ ]
+ };
+ let historyObj = [];
+ const filterList = [
+ 'filter1=value1',
+ 'filter2=',
+ 'filter3=anotherValue'
+ ];
+ const toGo = '/' + pathObj.route + '/' + filterList.toString();
+ const expectedResult = [
+ toGo,
+ {
+ lastRoute: pathObj.route
+ }
+ ];
+
+ changeUrlAddress(pathObj, historyObj);
+
+ expect(JSON.stringify(historyObj)).toBe(JSON.stringify(expectedResult));
+ });
+
+ it('change URL address for well known paths with hash id', () => {
+ const pathObj = {
+ route: 'schema',
+ hashId: 'someCrazyHashIdHere'
+ };
+ let historyObj = [];
+ const toGo = '/' + pathObj.route + '/' + pathObj.hashId;
+ const expectedResult = [
+ toGo,
+ {
+ lastRoute: pathObj.route
+ }
+ ];
+
+ changeUrlAddress(pathObj, historyObj);
+
+ expect(JSON.stringify(historyObj)).toBe(JSON.stringify(expectedResult));
+ });
+})
diff --git a/test/utils/SpinnerContainer.test.js b/test/utils/SpinnerContainer.test.js
index 90c7cf5..f9c01e2 100644
--- a/test/utils/SpinnerContainer.test.js
+++ b/test/utils/SpinnerContainer.test.js
@@ -17,8 +17,8 @@ describe('SpinnerContainer', () => {
expect(spinner.find(ClipLoader)).toHaveLength(1); // ensure the ClipLoader is mounted
expect(spinner.find(ClipLoader).props().color).toEqual(COLOR_BLUE); // ensure spinner is blue
expect(spinner.find(ClipLoader).props().loading).toEqual(true); // ensure spinner is showing
- expect(spinner.find('div.spinner-content')).toHaveLength(1); // ensure the children are grayed out
- expect(spinner.find('div.spinner-content').children()).toHaveLength(2); // ensure number of children is accurate
+ expect(spinner.find('div.spin-content')).toHaveLength(1); // ensure the children are grayed out
+ expect(spinner.find('div.spin-content').children()).toHaveLength(2); // ensure number of children is accurate
});
it('render spinner - not visible', () => {
@@ -30,6 +30,6 @@ describe('SpinnerContainer', () => {
expect(spinner.props().loading).toEqual(false);
expect(spinner.find(ClipLoader)).toHaveLength(1);
expect(spinner.find(ClipLoader).props().loading).toEqual(false); // ensure spinner is not showing
- expect(spinner.find('div.spinner-content')).toHaveLength(0);
+ expect(spinner.find('div.spin-content')).toHaveLength(0);
});
})
diff --git a/webpack.config.js b/webpack.config.js
index 5d99160..f038d4d 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -25,70 +25,71 @@ var webpack = require('webpack');
var devPort = process.env.PORT || 8001;
module.exports = {
- devtool: 'eval-source-map',
- entry: {
- bundle: [
- 'app/main.app.jsx',
- 'webpack/hot/only-dev-server'
- ],
- 'editAttributes/editAttributesBundle': [
- 'editAttributes/main.app.jsx',
- 'webpack/hot/only-dev-server'
- ]
- },
- output: {
- path: path.join(__dirname, 'dist'),
- publicPath: `http://localhost:${devPort}/services/aai/webapp`,
- filename: '[name].js'
- },
- resolve: {
- root: [path.resolve('.')],
- alias: {
- app: 'src/app',
- 'generic-components': 'src/generic-components',
- utils: 'src/utils',
- images: 'resources/images',
- editAttributes: 'src/editAttributes'
- }
- },
- devServer: {
- port: devPort,
- historyApiFallback: true,
- publicPath: `http://localhost:${devPort}/`,
- contentBase: path.join(__dirname, 'dist'),
- hot: true,
- progress: true,
- inline: true,
- debug: true,
- stats: {
- colors: true
- }
- },
- module: {
- preLoaders: [{
- test: /\.(js|jsx)$/,
- loader: 'source-map-loader'
- }],
- loaders: [
- {test: /\.(js|jsx)$/, loaders: ['babel-loader', 'eslint-loader'], exclude: /node_modules/},
- {test: /\.(css|scss)$/, loaders: ['style', 'css?sourceMap', 'sass?sourceMap']},
- // required for font icons
- {test: /\.(woff|woff2)(\?.*)?$/, loader: 'url-loader?limit=16384&mimetype=application/font-woff'},
- {test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader'},
- {test: /\.(png|jpg|svg)(\?.*)?$/, loader: 'url-loader?limit=16384'},
- {test: /\.json$/, loaders: ['json']}
- ]
- },
- eslint: {
- configFile: './.eslintrc',
- emitError: true,
- emitWarning: true
- },
- plugins: [
- new webpack.DefinePlugin({
- DEBUG: true
- }),
+ devtool: 'eval-source-map',
+ entry: {
+ bundle: [
+ 'app/main.app.jsx',
+ 'webpack/hot/only-dev-server'
+ ],
+ 'editAttributes/editAttributesBundle': [
+ 'editAttributes/main.app.jsx',
+ 'webpack/hot/only-dev-server'
+ ]
+ },
+ output: {
+ path: path.join(__dirname, 'dist'),
+ publicPath: `http://localhost:${devPort}/services/aai/webapp`,
+ filename: '[name].js'
+ },
+ resolve: {
+ root: [path.resolve('.')],
+ alias: {
+ app: 'src/app',
+ 'generic-components': 'src/generic-components',
+ utils: 'src/utils',
+ images: 'resources/images',
+ editAttributes: 'src/editAttributes'
+ },
+ extensions: ["", ".webpack.js", ".web.js", ".js", ".json", ".jsx"]
+ },
+ devServer: {
+ port: devPort,
+ historyApiFallback: true,
+ publicPath: `http://localhost:${devPort}/`,
+ contentBase: path.join(__dirname, 'dist'),
+ hot: true,
+ progress: true,
+ inline: true,
+ debug: true,
+ stats: {
+ colors: true
+ }
+ },
+ module: {
+ preLoaders: [{
+ test: /\.(js|jsx)$/,
+ loader: 'source-map-loader'
+ }],
+ loaders: [
+ {test: /\.(js|jsx)$/, loaders: ['babel-loader', 'eslint-loader'], exclude: /node_modules/},
+ {test: /\.(css|scss)$/, loaders: ['style', 'css?sourceMap', 'sass?sourceMap']},
+ // required for font icons
+ {test: /\.(woff|woff2)(\?.*)?$/, loader: 'url-loader?limit=16384&mimetype=application/font-woff'},
+ {test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader'},
+ {test: /\.(png|jpg|svg)(\?.*)?$/, loader: 'url-loader?limit=16384'},
+ {test: /\.json$/, loaders: ['json']}
+ ]
+ },
+ eslint: {
+ configFile: './.eslintrc',
+ emitError: true,
+ emitWarning: true
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ DEBUG: true
+ }),
- new webpack.HotModuleReplacementPlugin()
- ]
+ new webpack.HotModuleReplacementPlugin()
+ ]
};
diff --git a/webpack.devConfig.js b/webpack.devConfig.js
index b7c570b..e1e8876 100644
--- a/webpack.devConfig.js
+++ b/webpack.devConfig.js
@@ -25,72 +25,73 @@ var webpack = require('webpack');
var devPort = process.env.PORT || 8001;
module.exports = {
- devtool: 'eval-source-map',
- entry: {
- 'aai/bundle': [
- 'app/main.app.jsx',
- `webpack-dev-server/client?https://localhost:${devPort}`,
- 'webpack/hot/only-dev-server'
- ],
- 'editAttributes/editAttributesBundle': [
- 'editAttributes/main.app.jsx',
- `webpack-dev-server/client?https://localhost:${devPort}`,
- 'webpack/hot/only-dev-server'
- ]
- },
- output: {
- path: path.join(__dirname, 'dist'),
- publicPath: `https://localhost:${devPort}/`,
- filename: '[name].js'
- },
- resolve: {
- root: [path.resolve('.')],
- alias: {
- app: 'src/app',
- 'generic-components': 'src/generic-components',
- utils: 'src/utils',
- images: 'resources/images',
- editAttributes: 'src/editAttributes'
- }
- },
- devServer: {
- port: devPort,
- historyApiFallback: true,
- publicPath: `https://localhost:${devPort}/`,
- contentBase: path.join(__dirname, 'dist'),
- hot: true,
- progress: true,
- inline: true,
- debug: true,
- https: true,
- stats: {
- colors: true
- }
- },
- module: {
- preLoaders: [
- {test: /\.(js|jsx)$/, loader: 'source-map-loader'}
- ],
- loaders: [
- {test: /\.(js|jsx)$/, loaders: ['babel-loader', 'eslint-loader'], exclude: /node_modules/},
- {test: /\.(css|scss)$/, loaders: ['style', 'css?sourceMap', 'sass?sourceMap']},
- // required for font icons
- {test: /\.(woff|woff2)(\?.*)?$/, loader: 'url-loader?limit=16384&mimetype=application/font-woff'},
- {test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader'},
- {test: /\.(png|jpg|svg)(\?.*)?$/, loader: 'url-loader?limit=16384'},
- {test: /\.json$/, loaders: ['json']}
- ]
- },
- eslint: {
- configFile: './.eslintrc',
- emitError: true,
- emitWarning: true
- },
- plugins: [
- new webpack.DefinePlugin({
- DEBUG: true
- }),
+ devtool: 'eval-source-map',
+ entry: {
+ 'aai/bundle': [
+ 'app/main.app.jsx',
+ `webpack-dev-server/client?https://localhost:${devPort}`,
+ 'webpack/hot/only-dev-server'
+ ],
+ 'editAttributes/editAttributesBundle': [
+ 'editAttributes/main.app.jsx',
+ `webpack-dev-server/client?https://localhost:${devPort}`,
+ 'webpack/hot/only-dev-server'
+ ]
+ },
+ output: {
+ path: path.join(__dirname, 'dist'),
+ publicPath: `https://localhost:${devPort}/`,
+ filename: '[name].js'
+ },
+ resolve: {
+ root: [path.resolve('.')],
+ alias: {
+ app: 'src/app',
+ 'generic-components': 'src/generic-components',
+ utils: 'src/utils',
+ images: 'resources/images',
+ editAttributes: 'src/editAttributes'
+ },
+ extensions: ["", ".webpack.js", ".web.js", ".js", ".json", ".jsx"]
+ },
+ devServer: {
+ port: devPort,
+ historyApiFallback: true,
+ publicPath: `https://localhost:${devPort}/`,
+ contentBase: path.join(__dirname, 'dist'),
+ hot: true,
+ progress: true,
+ inline: true,
+ debug: true,
+ https: true,
+ stats: {
+ colors: true
+ }
+ },
+ module: {
+ preLoaders: [
+ {test: /\.(js|jsx)$/, loader: 'source-map-loader'}
+ ],
+ loaders: [
+ {test: /\.(js|jsx)$/, loaders: ['babel-loader', 'eslint-loader'], exclude: /node_modules/},
+ {test: /\.(css|scss)$/, loaders: ['style', 'css?sourceMap', 'sass?sourceMap']},
+ // required for font icons
+ {test: /\.(woff|woff2)(\?.*)?$/, loader: 'url-loader?limit=16384&mimetype=application/font-woff'},
+ {test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader'},
+ {test: /\.(png|jpg|svg)(\?.*)?$/, loader: 'url-loader?limit=16384'},
+ {test: /\.json$/, loaders: ['json']}
+ ]
+ },
+ eslint: {
+ configFile: './.eslintrc',
+ emitError: true,
+ emitWarning: true
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ DEBUG: true
+ }),
- new webpack.HotModuleReplacementPlugin()
- ]
+ new webpack.HotModuleReplacementPlugin()
+ ]
};