aboutsummaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits
diff options
context:
space:
mode:
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding/licenseModel/limits')
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js25
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx193
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js30
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js52
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js70
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx108
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js46
7 files changed, 524 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js
new file mode 100644
index 0000000000..d483383472
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js
@@ -0,0 +1,25 @@
+import {connect} from 'react-redux';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import LimitEditor from './LimitEditor.jsx';
+
+const mapStateToProps = ({licenseModel: {limitEditor}}) => {
+
+ let {data, genericFieldInfo, formReady} = limitEditor;
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo);
+
+ return {
+ data,
+ genericFieldInfo,
+ isFormValid,
+ formReady
+ };
+};
+
+const mapActionsToProps = (dispatch) => {
+ return {
+ onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}),
+ onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName)
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(LimitEditor); \ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx
new file mode 100644
index 0000000000..f70f917725
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx
@@ -0,0 +1,193 @@
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import {LIMITS_FORM_NAME, selectValues} from './LimitEditorConstants.js';
+import Button from 'sdc-ui/lib/react/Button.js';
+import Validator from 'nfvo-utils/Validator.js';
+
+const LimitPropType = React.PropTypes.shape({
+ id: React.PropTypes.string,
+ name: React.PropTypes.string,
+ description: React.PropTypes.string,
+ metric: React.PropTypes.string,
+ value: React.PropTypes.number,
+ aggregationFunction: React.PropTypes.string,
+ time: React.PropTypes.string,
+ unit: React.PropTypes.number
+});
+
+class LimitEditor extends React.Component {
+ static propTypes = {
+ data: LimitPropType,
+ limitsNames: React.PropTypes.object,
+ isReadOnlyMode: React.PropTypes.bool,
+ isFormValid: React.PropTypes.bool,
+ formReady: React.PropTypes.bool,
+ genericFieldInfo: React.PropTypes.object.isRequired,
+ onDataChanged: React.PropTypes.func.isRequired,
+ onSubmit: React.PropTypes.func.isRequired,
+ onValidateForm: React.PropTypes.func.isRequired,
+ onCancel: React.PropTypes.func.isRequired
+ };
+
+ componentDidUpdate(prevProps) {
+ if (this.props.formReady && this.props.formReady !== prevProps.formReady) {
+ this.submit();
+ }
+ }
+
+ render() {
+ let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo, onCancel, isFormValid, formReady, onValidateForm} = this.props;
+ let {name, description, metric, value, aggregationFunction, time, unit} = data;
+ return (
+ <div className='limit-editor'>
+ {!data.id &&
+ <div className='limit-editor-title'>
+ {data.name ? data.name : i18n('NEW LIMIT')}
+ </div>}
+ {
+ genericFieldInfo &&
+ <Form
+ ref='validationForm'
+ hasButtons={false}
+ isValid={isFormValid}
+ formReady={formReady}
+ onValidateForm={() => onValidateForm(LIMITS_FORM_NAME) }
+ labledButtons={false}
+ isReadOnlyMode={isReadOnlyMode}
+ className='limit-editor-form'>
+ <GridSection className='limit-editor-form-grid-section'>
+ <GridItem colSpan={2}>
+ <Input
+ onChange={name => onDataChanged({name}, LIMITS_FORM_NAME, {name: () => this.validateName(name)})}
+ label={i18n('Name')}
+ data-test-id='limit-editor-name'
+ value={name}
+ isValid={genericFieldInfo.name.isValid}
+ errorText={genericFieldInfo.name.errorText}
+ isRequired={true}
+ type='text'/>
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
+ onChange={description => onDataChanged({description}, LIMITS_FORM_NAME)}
+ label={i18n('Description')}
+ data-test-id='limit-editor-description'
+ value={description}
+ isValid={genericFieldInfo.description.isValid}
+ errorText={genericFieldInfo.description.errorText}
+ isRequired={false}
+ type='text'/>
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
+ onChange={e => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onDataChanged({metric: val}, LIMITS_FORM_NAME);}
+ }
+ isRequired={true}
+ value={metric}
+ label={i18n('Metric')}
+ data-test-id='limit-editor-metric'
+ isValid={genericFieldInfo.metric.isValid}
+ errorText={genericFieldInfo.metric.errorText}
+ groupClassName='bootstrap-input-options'
+ className='input-options-select'
+ type='select' >
+ {selectValues.METRIC.map(mtype =>
+ <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
+ </Input>
+ </GridItem>
+ <GridItem>
+ <Input
+ onChange={value => onDataChanged({value}, LIMITS_FORM_NAME)}
+ label={i18n('Metric value')}
+ data-test-id='limit-editor-metric-value'
+ value={value}
+ isValid={genericFieldInfo.value.isValid}
+ errorText={genericFieldInfo.value.errorText}
+ isRequired={true}
+ type='number'/>
+ </GridItem>
+ <GridItem>
+ <Input
+ onChange={unit => onDataChanged({unit}, LIMITS_FORM_NAME)}
+ label={i18n('Units')}
+ data-test-id='limit-editor-units'
+ value={unit}
+ isValid={genericFieldInfo.unit.isValid}
+ errorText={genericFieldInfo.unit.errorText}
+ isRequired={false}
+ type='number'/>
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
+ onChange={e => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onDataChanged({aggregationFunction: val}, LIMITS_FORM_NAME);}
+ }
+ value={aggregationFunction}
+ label={i18n('Aggregation Function')}
+ data-test-id='limit-editor-aggregation-function'
+ isValid={genericFieldInfo.aggregationFunction.isValid}
+ errorText={genericFieldInfo.aggregationFunction.errorText}
+ groupClassName='bootstrap-input-options'
+ className='input-options-select'
+ type='select' >
+ {selectValues.AGGREGATION_FUNCTION.map(mtype =>
+ <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
+ </Input>
+ </GridItem>
+ <GridItem>
+ <Input
+ onChange={e => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onDataChanged({time: val}, LIMITS_FORM_NAME);}
+ }
+ value={time}
+ label={i18n('Time')}
+ data-test-id='limit-editor-time'
+ isValid={genericFieldInfo.time.isValid}
+ errorText={genericFieldInfo.time.errorText}
+ groupClassName='bootstrap-input-options'
+ className='input-options-select'
+ type='select' >
+ {selectValues.TIME.map(mtype =>
+ <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
+ </Input>
+ </GridItem>
+ </GridSection>
+ <GridSection className='limit-editor-buttons'>
+ <Button btnType='outline' disabled={!isFormValid} onClick={() => this.submit()} type='reset'>{i18n('Save')}</Button>
+ <Button btnType='outline' color='gray' onClick={onCancel} type='reset'>{i18n('Cancel')}</Button>
+ </GridSection>
+ </Form>
+ }
+ </div>
+ );
+ }
+
+ validateName(value) {
+ const {data: {id}, limitsNames} = this.props;
+ const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: limitsNames});
+
+ return !isExists ? {isValid: true, errorText: ''} :
+ {isValid: false, errorText: i18n('Limit by the name \'' + value + '\' already exists. Limit name must be unique')};
+ }
+
+ submit() {
+ if (!this.props.formReady) {
+ this.props.onValidateForm(LIMITS_FORM_NAME);
+ } else {
+ this.props.onSubmit();
+ }
+ }
+}
+
+export default LimitEditor; \ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js
new file mode 100644
index 0000000000..09c64ada62
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js
@@ -0,0 +1,30 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import {actionTypes} from './LimitEditorConstants.js';
+
+
+const LimitEditorActionHelper = {
+ openLimitsEditor(dispatch, {limit}) {
+ dispatch({type: actionTypes.OPEN, limitItem: limit});
+ },
+
+ closeLimitsEditor(dispatch) {
+ dispatch({type: actionTypes.CLOSE});
+ }
+};
+
+export default LimitEditorActionHelper; \ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js
new file mode 100644
index 0000000000..1bef286442
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js
@@ -0,0 +1,52 @@
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+// import InputOptions, {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx';
+
+export const actionTypes = keyMirror({
+ OPEN: null,
+ CLOSE: null,
+ DATA_CHANGED: null,
+});
+
+export const LIMITS_FORM_NAME = 'LIMITSFORM';
+
+export const selectValues = {
+ METRIC: [
+ {enum: '', title: i18n('please select…')},
+ {enum: 'Software_Instances_Count', title: 'Software Instances'},
+ {enum: 'Core', title: 'Core'},
+ {enum: 'CPU', title: 'CPU'},
+ {enum: 'Trunks', title: 'Trunks'},
+ {enum: 'User', title: 'User'},
+ {enum: 'Subscribers', title: 'Subscribers'},
+ {enum: 'Tenants', title: 'Tenants'},
+ {enum: 'Tokens', title: 'Tokens'},
+ {enum: 'Seats', title: 'Seats'},
+ {enum: 'Units_TB', title: 'Units-TB'},
+ {enum: 'Units_GB', title: 'Units-GB'},
+ {enum: 'Units_MB', title: 'Units-MB'}
+ ],
+ AGGREGATION_FUNCTION: [
+ {enum: '', title: i18n('please select…')},
+ {enum: 'Peak', title: 'Peak'},
+ {enum: 'Average', title: 'Average'}
+ ],
+ TIME: [
+ {enum: '', title: i18n('please select…')},
+ {enum: 'Hour', title: 'Hour'},
+ {enum: 'Day', title: 'Day'},
+ {enum: 'Month', title: 'Month'}
+ ]
+
+};
+
+export const limitType = {
+ SERVICE_PROVIDER: 'ServiceProvider',
+ VENDOR: 'Vendor'
+};
+
+export const defaultState = {
+ LIMITS_EDITOR_DATA: {}
+};
+
+export const NEW_LIMIT_TEMP_ID = 'NEW_LIMIT_TEMP_ID'; \ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js
new file mode 100644
index 0000000000..2499093af2
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js
@@ -0,0 +1,70 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import {actionTypes, LIMITS_FORM_NAME, defaultState} from './LimitEditorConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.OPEN:
+ return {
+ ...state,
+ data: action.limitItem ? {...action.limitItem} : defaultState.LIMITS_EDITOR_DATA,
+ formReady: null,
+ formName: LIMITS_FORM_NAME,
+ genericFieldInfo: {
+ 'description' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 1000}]
+ },
+ 'name' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}]
+ },
+ 'metric' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}]
+ },
+ 'value' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}, {type: 'numeric', data: true}, {type: 'minimum', data: 0}]
+ },
+ 'unit' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'numeric', data: true}]
+ },
+ 'aggregationFunction' : {
+ isValid: true,
+ errorText: '',
+ validations: []
+ },
+ 'time' : {
+ isValid: true,
+ errorText: '',
+ validations: []
+ }
+ }
+ };
+ case actionTypes.CLOSE:
+ return {};
+ default:
+ return state;
+ }
+}; \ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx
new file mode 100644
index 0000000000..ec5a1dff72
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx
@@ -0,0 +1,108 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+import LimitEditor from './LimitEditor.js';
+import {NEW_LIMIT_TEMP_ID, selectValues} from './LimitEditorConstants.js';
+
+const LimitItem = ({isReadOnlyMode, limit, onDelete, onSelect}) => {
+ const {name, description, metric, value, aggregationFunction = '', time = ''} = limit;
+ const timeLabel = time ? `per ${time}` : '';
+ return (
+ <ListEditorItemView
+ onDelete={onDelete}
+ onSelect={onSelect}
+ isReadOnlyMode={isReadOnlyMode}>
+ <div className='list-editor-item-view-field limit-name'>
+ <div className='text name'>{name}</div>
+ </div>
+
+ <div className='list-editor-item-view-field limit-description'>
+ <div className='text description'>{description}</div>
+ </div>
+
+ <div className='list-editor-item-view-field limit-metric-details'>
+ <div className='text description'>{`${selectValues.METRIC.find(item => item.enum === metric).title} ${value} ${aggregationFunction} ${timeLabel}`}</div>
+ </div>
+ </ListEditorItemView>
+ );
+};
+
+class Limits extends React.Component {
+
+
+ state = {
+ localFilter: ''
+ };
+
+ render() {
+ const {isReadOnlyMode = false, limitEditor, limitsList = [], onCloseLimitEditor, selectedLimit} = this.props;
+ let limitsNames = {};
+ for (let i = 0; i < limitsList.length; i++) {
+ limitsNames[limitsList[i].name.toLowerCase()] = limitsList[i].id;
+ }
+ return (
+ <div className='license-model-limits-view'>
+ <ListEditorView
+ isReadOnlyMode={isReadOnlyMode}>
+ {this.props.selectedLimit === NEW_LIMIT_TEMP_ID && limitEditor.data &&
+ <LimitEditor limitsNames={limitsNames} onCancel={onCloseLimitEditor} onSubmit={ () => this.submit()}/>
+ }
+ {limitsList.length === 0 && !limitEditor.data && <div className='no-limits-text'>{i18n('There are no limits')}</div>}
+ {limitsList.map(limit =>
+ <div key={limit.id} className='limit-item-wrapper'>
+ <LimitItem
+ onDelete={() => this.delete(limit)}
+ onSelect={selectedLimit ? undefined : () => this.props.onSelectLimit(limit)}
+ clickable={!selectedLimit}
+ isReadOnlyMode={isReadOnlyMode}
+ limit={limit}/>
+ {limit.id === selectedLimit && limitEditor.data && <LimitEditor limitsNames={limitsNames} onCancel={onCloseLimitEditor} onSubmit={ () => this.submit()}/>}
+ </div> )}
+ </ListEditorView>
+
+ </div>
+ );
+ }
+
+ submit() {
+ let {onSubmit, onCloseLimitEditor, parent, limitEditor, licenseModelId, version, limitType} = this.props;
+ onSubmit({type: limitType, ...limitEditor.data}, parent, licenseModelId, version).then(() => onCloseLimitEditor());
+ }
+
+ delete(limit) {
+ let {onDelete, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit} = this.props;
+ onDelete({limit, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit});
+ }
+
+ filterList() {
+ let {limitsList = []} = this.props;
+ let {localFilter} = this.state;
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return limitsList.filter(({name = '', description = ''}) => {
+ return escape(name).match(filter) || escape(description).match(filter);
+ });
+ }
+ else {
+ return limitsList;
+ }
+ }
+}
+
+export default Limits;
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js
new file mode 100644
index 0000000000..1b8ecb9d94
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js
@@ -0,0 +1,46 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ */
+
+// items/{itemId}/users
+
+let list = [
+
+];
+
+export default {
+ fetch() {
+ return Promise.resolve({
+ listCount: list.length,
+ results: list
+ });
+ },
+
+ put(url, payload) {
+ // let {removedUsers, addedUsers} = payload;
+ // users = users.filter(user => !removedUsers.map(user => user.userId).includes(user.userId)).concat(addedUsers);
+ payload.id = Math.random() * (1000 - 1) + 1;
+ list.push(payload);
+ return Promise.resolve();
+ },
+
+ destroy(url) {
+ const parts = url.split('/');
+ const id = parts[parts.length - 1];
+ let newList = list.filter(item => item.id !== id);
+ list = newList;
+ return Promise.resolve();
+ }
+}; \ No newline at end of file