aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xui-react-lib/libIndex.js1
-rw-r--r--ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js437
-rw-r--r--ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js463
-rw-r--r--ui-react/src/components/dialogs/Policy/PolicyModal.js63
-rw-r--r--ui-react/src/utils/OnapUtils.js65
5 files changed, 709 insertions, 320 deletions
diff --git a/ui-react-lib/libIndex.js b/ui-react-lib/libIndex.js
index f090b6145..583cc7128 100755
--- a/ui-react-lib/libIndex.js
+++ b/ui-react-lib/libIndex.js
@@ -36,6 +36,7 @@ export { default as MenuBar } from './src/components/menu/MenuBar';
export { default as ModifyLoopModal } from './src/components/dialogs/Loop/ModifyLoopModal';
export { default as NotFound } from './src/NotFound';
export { default as OnapConstants } from './src/utils/OnapConstants';
+export { default as OnapUtils } from './src/utils/OnapUtils';
export { default as OpenLoopModal } from './src/components/dialogs/Loop/OpenLoopModal';
export { default as PerformActions } from './src/components/dialogs/PerformActions';
export { default as PolicyModal } from './src/components/dialogs/Policy/PolicyModal';
diff --git a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
index 58cb9c6c3..90bbc887c 100644
--- a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
+++ b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
@@ -74,7 +74,9 @@ const ColPullLeftStyled = styled(Col)`
const cellStyle = { border: '1px solid black' };
const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
let dictList = [];
+let subDictFlag = false;
function SelectSubDictType(props) {
const {onChange} = props;
@@ -90,9 +92,10 @@ function SelectSubDictType(props) {
SelectedDictTypes = SelectedDictTypes.slice(0,-1);
onChange(SelectedDictTypes);
}
+ // When the subDictFlag is true, we need to disable selection of element "type"
return(
<div>
- <select multiple={true} onChange={selectedValues}>
+ <select disabled={subDictFlag} multiple={true} onChange={selectedValues}>
<option value="string">string</option>
<option value="number">number</option>
<option value="datetime">datetime</option>
@@ -100,66 +103,75 @@ function SelectSubDictType(props) {
<option value="json">json</option>
</select>
</div>
- )
+ );
}
function SubDict(props) {
const {onChange} = props;
const subDicts = [];
- subDicts.push('Default');
+ subDicts.push('none');
if (dictList !== undefined && dictList.length > 0) {
- let item;
- for(item in dictList) {
- if(dictList[item].secondLevelDictionary === 1) {
- subDicts.push(dictList[item].name);
- }
- };
+ let item;
+ for(item in dictList) {
+ if(dictList[item].secondLevelDictionary === 1) {
+ subDicts.push(dictList[item].name);
+ }
+ }
+ }
+ let optionItems = [];
+ for (let i=0; i<subDicts.length; ++i) {
+ if (i === 0) {
+ optionItems.push(<option selected key={subDicts[i]}>{subDicts[i]}</option>);
+ } else {
+ optionItems.push(<option key={subDicts[i]}>{subDicts[i]}</option>);
+ }
}
- subDicts.push('');
- let optionItems = subDicts.map(
- (item) => <option key={item}>{item}</option>
- );
+
function selectedValue (e) {
onChange(e.target.value);
}
+ // When the subDictFlag is true, we need to disable selection of
+ // the sub-dictionary flag
return(
- <select onChange={selectedValue} >
- {optionItems}
- </select>
- )
+ <select disabled={subDictFlag} onChange={selectedValue} >
+ {optionItems}
+ </select>
+ );
}
export default class ManageDictionaries extends React.Component {
constructor(props, context) {
super(props, context);
- this.handleClose = this.handleClose.bind(this);
+ this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
+ this.addDictionaryRow = this.addDictionaryRow.bind(this);
+ this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
this.clickHandler = this.clickHandler.bind(this);
+ this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
+ this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
+ this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
+ this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
this.getDictionaries = this.getDictionaries.bind(this);
this.getDictionaryElements = this.getDictionaryElements.bind(this);
- this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
- this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleDictionaryRowClick = this.handleDictionaryRowClick.bind(this);
+ this.importCsvData = this.importCsvData.bind(this);
+ this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
this.updateDictionaryElementsRequest = this.updateDictionaryElementsRequest.bind(this);
- this.addDictionaryRow = this.addDictionaryRow.bind(this);
this.updateDictionaryRow = this.updateDictionaryRow.bind(this);
- this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
- this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
- this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
- this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
- this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
+ this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
this.state = {
show: true,
- selectedFile: '',
currentSelectedDictionary: null,
exportFilename: '',
content: null,
dictionaryElements: [],
tableIcons: {
Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
- Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
- Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
+ Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
+ Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Export: forwardRef((props, ref) => <VerticalAlignBottomIcon {...props} ref={ref} />),
Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
@@ -226,10 +238,10 @@ export default class ManageDictionaries extends React.Component {
headerStyle: headerStyle
},
{
- title: "Sub-Dictionary", field: "subDictionary",
- editComponent: props => (
+ title: "Sub-Dictionary", field: "subDictionary",
+ editComponent: props => (
<div>
- <SubDict value={props.value} onChange={props.onChange} />
+ <SubDict value={props.value} onChange={props.onChange} />
</div>
),
cellStyle: cellStyle,
@@ -256,14 +268,19 @@ export default class ManageDictionaries extends React.Component {
getDictionaries() {
TemplateMenuService.getDictionary().then(arrayOfdictionaries => {
this.setState({ dictionaries: arrayOfdictionaries, currentSelectedDictionary: null })
+ // global variable setting used functional components in this file
+ dictList = arrayOfdictionaries;
+ }).catch(() => {
+ console.error('Failed to retrieve dictionaries');
+ this.setState({ dictionaries: [], currentSelectedDictionary: null })
});
}
getDictionaryElements(dictionaryName) {
TemplateMenuService.getDictionaryElements(dictionaryName).then(dictionaryElements => {
- dictList = this.state.dictionaries;
this.setState({ dictionaryElements: dictionaryElements.dictionaryElements} );
- });
+ this.setState({ currentSelectDictionary: dictionaryName });
+ }).catch(() => console.error('Failed to retrieve dictionary elements'))
}
clickHandler(rowData) {
@@ -277,27 +294,33 @@ export default class ManageDictionaries extends React.Component {
addReplaceDictionaryRequest(dictionaryEntry) {
TemplateMenuService.insDictionary(dictionaryEntry)
- .then(resp => {})
- .then(() => {this.getDictionaries()});
+ .then(resp => {
+ this.getDictionaries();
+ })
+ .catch(() => console.error('Failed to insert new dictionary elements'));
}
updateDictionaryElementsRequest(dictElements) {
let reqData = { "name": this.state.currentSelectedDictionary, 'dictionaryElements': dictElements };
TemplateMenuService.insDictionaryElements(reqData)
- .then(resp => {})
- .then(() => { this.getDictionaryElements(this.state.currentSelectedDictionary) });
+ .then(resp => { this.getDictionaryElements(this.state.currentSelectedDictionary) })
+ .catch(() => console.error('Failed to update dictionary elements'));
}
deleteDictionaryRequest(dictionaryName) {
TemplateMenuService.deleteDictionary(dictionaryName)
- .then(resp => { this.getDictionaries() });
+ .then(resp => {
+ this.getDictionaries();
+ })
+ .catch(() => console.error('Failed to delete dictionary'));
}
deleteDictionaryElementRequest(dictionaryName, elemenetShortName) {
TemplateMenuService.deleteDictionaryElements({ 'name': dictionaryName, 'shortName': elemenetShortName })
.then(resp => {
this.getDictionaryElements(dictionaryName);
- });
+ })
+ .catch(() => console.error('Failed to delete dictionary elements'));
}
fileSelectedHandler = (event) => {
@@ -306,83 +329,94 @@ export default class ManageDictionaries extends React.Component {
if (event.target.files && event.target.files[0]) {
const reader = new FileReader();
reader.onload = (e) => {
+ let errorMessages = this.importCsvData(reader.result);
+ if (errorMessages !== '') {
+ alert(errorMessages);
+ }
+ }
+ reader.readAsText(event.target.files[0]);
+ }
+ } else {
+ alert('Please upload .csv extention files only.');
+ }
+ }
- const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
- const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary' ];
- const mandatory = [ true, true, true, true, false ];
- const validTypes = ['string','number','datetime','json','map'];
+ importCsvData(rawCsvData) {
- let result = CsvToJson(reader.result, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
+ const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
+ const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary' ];
+ const validTypes = ['string','number','datetime','json','map'];
- let errorMessages = result.errorMessages;
- let jsonObjArray = result.jsonObjArray;
+ let mandatory;
- let validTypesErrorMesg = '';
+ if (subDictFlag) {
+ mandatory = [ true, true, true, false, false ];
+ } else {
+ mandatory = [ true, true, true, true, false ];
+ }
- for (let i=0; i < validTypes.length; ++i) {
- if (i === 0) {
- validTypesErrorMesg = validTypes[i];
- } else {
- validTypesErrorMesg += ',' + validTypes[i];
- }
- }
+ let result = CsvToJson(rawCsvData, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
- if (errorMessages !== '') {
- alert(errorMessages);
- return;
- }
+ let errorMessages = result.errorMessages;
+ let jsonObjArray = result.jsonObjArray;
- // Perform further checks on data that is now in JSON form
- let subDictionaries = [];
+ let validTypesErrorMesg = '';
- // NOTE: dictList is a global variable maintained faithfully
- // by the getDictionaries() method outside this import
- // functionality.
- let item;
- for (item in dictList) {
- if (dictList[item].secondLevelDictionary === 1) {
- subDictionaries.push(dictList[item].name);
- }
- };
-
- // Check for valid Sub-Dictionary and Element Type values
- subDictionaries = subDictionaries.toString();
- let row = 2;
- let dictElem;
- for (dictElem of jsonObjArray) {
- let itemKey;
- for (itemKey in dictElem){
- let value = dictElem[itemKey].trim();
- let keyIndex = jsonKeyNames.indexOf(itemKey);
- if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
- errorMessages += '\n' + userHeaderNames[keyIndex] +
- ' at row #' + row +
- ' can only contain alphanumeric characters and periods, hyphens or underscores';
- }
- if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
- errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
- errorMessages += '\nValid types are: ' + validTypesErrorMesg;
- }
- if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
- errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
- }
- }
- ++row;
- }
- if (errorMessages) {
- alert(errorMessages);
- return;
- }
+ for (let i=0; i < validTypes.length; ++i) {
+ if (i === 0) {
+ validTypesErrorMesg = validTypes[i];
+ } else {
+ validTypesErrorMesg += ',' + validTypes[i];
+ }
+ }
+
+ if (errorMessages !== '') {
+ return errorMessages;
+ }
+
+ // Perform further checks on data that is now in JSON form
+ let subDictionaries = [];
- // We made it through all the checks. Send it to back end
- this.updateDictionaryElementsRequest(jsonObjArray);
+ // NOTE: dictList is a global variable maintained faithfully
+ // by the getDictionaries() method outside this import
+ // functionality.
+ let item;
+ for (item in dictList) {
+ if (dictList[item].secondLevelDictionary === 1) {
+ subDictionaries.push(dictList[item].name);
+ }
+ };
+
+ // Check for valid Sub-Dictionary and Element Type values
+ subDictionaries = subDictionaries.toString();
+ let row = 2;
+ let dictElem;
+ for (dictElem of jsonObjArray) {
+ let itemKey;
+ for (itemKey in dictElem){
+ let value = dictElem[itemKey].trim();
+ let keyIndex = jsonKeyNames.indexOf(itemKey);
+ if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
+ errorMessages += '\n' + userHeaderNames[keyIndex] +
+ ' at row #' + row +
+ ' can only contain alphanumeric characters and periods, hyphens or underscores';
+ }
+ if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
+ errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
+ errorMessages += '\nValid types are: ' + validTypesErrorMesg;
+ }
+ if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
+ errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
}
- reader.readAsText(event.target.files[0]);
}
- this.setState({selectedFile: event.target.files[0]})
- } else {
- alert('Please upload .csv extention files only.');
+ ++row;
+ }
+ if (errorMessages === '') {
+ // We made it through all the checks. Send it to back end
+ this.updateDictionaryElementsRequest(jsonObjArray);
}
+
+ return errorMessages;
}
addDictionaryRow(newData) {
@@ -392,13 +426,13 @@ export default class ManageDictionaries extends React.Component {
if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
validData = false;
alert('Please enter alphanumeric input. Only allowed special characters are:(period, hyphen, underscore)');
- reject(() => {});
+ reject();
}
for (let i = 0; i < this.state.dictionaries.length; i++) {
if (this.state.dictionaries[i].name === newData.name) {
validData = false;
alert(newData.name + ' dictionary name already exists')
- reject(() => {});
+ reject();
}
}
if (validData) {
@@ -410,13 +444,14 @@ export default class ManageDictionaries extends React.Component {
}
- updateDictionaryRow(oldData, newData) {
+ updateDictionaryRow(newData, oldData) {
let validData = true;
- return new Promise((resolve) => {
+ return new Promise((resolve, reject) => {
setTimeout(() => {
if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
validData = false;
alert('Please enter alphanumberic input. Only allowed special characters are:(period, hyphen, underscore)');
+ reject();
}
if (validData) {
this.addReplaceDictionaryRequest(newData);
@@ -427,7 +462,7 @@ export default class ManageDictionaries extends React.Component {
}
deleteDictionaryRow(oldData) {
- return new Promise((resolve) => {
+ return new Promise((resolve, reject) => {
setTimeout(() => {
this.deleteDictionaryRequest(oldData.name);
resolve();
@@ -439,53 +474,63 @@ export default class ManageDictionaries extends React.Component {
return new Promise((resolve, reject) => {
setTimeout(() => {
let dictionaryElements = this.state.dictionaryElements;
- let errorMessage = '';
+ let errorMessages = '';
for (let i = 0; i < this.state.dictionaryElements.length; i++) {
if (this.state.dictionaryElements[i].shortName === newData.shortName) {
alert('Short Name "' + newData.shortName + '" already exists');
- reject(() => {});
+ reject("");
}
}
- if (newData.shortName !== '' && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
- errorMessage += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
+ // MaterialTable returns no property at all if the user has not touched a
+ // new column, so we want to add the property with an emptry string
+ // for several cases if that is the case to simplify other checks.
+ if (newData.description === undefined) {
+ newData.description = "";
+ }
+ if (newData.subDictionary === undefined) {
+ newData.subDictionary = null;
+ }
+ if (newData.type === undefined) {
+ newData.type = "";
+ }
+ if (!newData.shortName && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
+ errorMessages += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
}
if (!newData.shortName){
- errorMessage += '\nShort Name must be specified';
+ errorMessages += '\nShort Name must be specified';
}
if (!newData.name){
- errorMessage += '\nElement Name must be specified';
+ errorMessages += '\nElement Name must be specified';
}
- if (!newData.type){
- errorMessage += '\nElement Type must be specified';
+ if (!newData.type && !subDictFlag){
+ errorMessages += '\nElement Type must be specified';
}
- if (!newData.description){
- errorMessage += '\nElement Description must be specified';
- }
- if (errorMessage === '') {
+ if (errorMessages === '') {
dictionaryElements.push(newData);
- this.updateDictionaryElementsRequest(dictionaryElements);
+ this.updateDictionaryElementsRequest([newData]);
resolve();
} else {
- alert(errorMessage);
- reject(() => {});
+ alert(errorMessages);
+ reject("");
}
}, 1000);
});
}
updateDictionaryElementRow(newData, oldData) {
- return new Promise((resolve) => {
+ return new Promise((resolve, reject) => {
setTimeout(() => {
let dictionaryElements = this.state.dictionaryElements;
let validData = true;
if (!newData.type) {
validData = false;
alert('Element Type cannot be null');
+ reject();
}
if (validData) {
const index = dictionaryElements.indexOf(oldData);
dictionaryElements[index] = newData;
- this.updateDictionaryElementsRequest(dictionaryElements);
+ this.updateDictionaryElementsRequest([newData]);
}
resolve();
}, 1000);
@@ -502,6 +547,15 @@ export default class ManageDictionaries extends React.Component {
});
}
+ handleDictionaryRowClick(event, rowData) {
+ subDictFlag = rowData.secondLevelDictionary === 1 ? true : false;
+ this.setState({
+ currentSelectedDictionary : rowData.name,
+ exportFilename: rowData.name
+ })
+ this.getDictionaryElements(rowData.name);
+ }
+
render() {
return (
<ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
@@ -509,70 +563,69 @@ export default class ManageDictionaries extends React.Component {
<Modal.Title>Manage Dictionaries</Modal.Title>
</Modal.Header>
<Modal.Body>
- {this.state.currentSelectedDictionary === null ? <MaterialTable
- title={"Dictionary List"}
- data={this.state.dictionaries}
- columns={this.state.dictColumns}
- icons={this.state.tableIcons}
- onRowClick={(event, rowData) => {
- this.setState({
- currentSelectedDictionary : rowData.name,
- exportFilename: rowData.name
- })
- this.getDictionaryElements(rowData.name);
- }}
- options={{
- headerStyle: rowHeaderStyle,
- }}
- editable={{
- onRowAdd: this.addDictionaryRow,
- onRowUpdate: this.updateDictionaryRow,
- onRowDelete: this.deleteDictionaryRow
- }}
+ {this.state.currentSelectedDictionary === null ?
+ <MaterialTable
+ title={"Dictionary List"}
+ data={this.state.dictionaries}
+ columns={this.state.dictColumns}
+ icons={this.state.tableIcons}
+ onRowClick={this.handleDictionaryRowClick}
+ options={{
+ headerStyle: rowHeaderStyle,
+ }}
+ editable={!this.readOnly ?
+ {
+ onRowAdd: this.addDictionaryRow,
+ onRowUpdate: this.updateDictionaryRow,
+ onRowDelete: this.deleteDictionaryRow
+ } : undefined }
+ /> : null
+ }
+ {this.state.currentSelectedDictionary !== null ?
+ <MaterialTable
+ title={'Dictionary Elements List for ' + (subDictFlag ? 'Sub-Dictionary "' : '"') + this.state.currentSelectedDictionary + '"'}
+ data={this.state.dictionaryElements}
+ columns={this.state.dictElementColumns}
+ icons={this.state.tableIcons}
+ options={{
+ exportAllData: true,
+ exportButton: true,
+ exportFileName: this.state.exportFilename,
+ headerStyle:{backgroundColor:'white', fontSize: '15pt', text: 'bold', border: '1px solid black'}
+ }}
+ components={{
+ Toolbar: props => (
+ <Row>
+ <Col sm="11">
+ <MTableToolbarStyled {...props} />
+ </Col>
+ <ColPullLeftStyled sm="1">
+ <Tooltip title="Import" placement = "bottom">
+ <IconButton aria-label="import" disabled={this.readOnly} onClick={() => this.fileUpload.click()}>
+ <VerticalAlignTopIcon />
+ </IconButton>
+ </Tooltip>
+ <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
+ style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
+ </ColPullLeftStyled>
+ </Row>
+ )
+ }}
+ editable={!this.readOnly ?
+ {
+ onRowAdd: this.addDictionaryElementRow,
+ onRowUpdate: this.updateDictionaryElementRow,
+ onRowDelete: this.deleteDictionaryElementRow
+ } : undefined
+ }
/> : null
- }
- {this.state.currentSelectedDictionary !== null ? <MaterialTable
- title={'Dictionary Elements List for "' + this.state.currentSelectedDictionary + '"'}
- data={this.state.dictionaryElements}
- columns={this.state.dictElementColumns}
- icons={this.state.tableIcons}
- options={{
- exportAllData: true,
- exportButton: true,
- exportFileName: this.state.exportFilename,
- headerStyle:{backgroundColor:'white', fontSize: '15pt', text: 'bold', border: '1px solid black'}
- }}
- components={{
- Toolbar: props => (
- <Row>
- <Col sm="11">
- <MTableToolbarStyled {...props} />
- </Col>
- <ColPullLeftStyled sm="1">
- <Tooltip title="Import" placement = "bottom">
- <IconButton aria-label="import" onClick={() => this.fileUpload.click()}>
- <VerticalAlignTopIcon />
- </IconButton>
- </Tooltip>
- <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
- style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
- </ColPullLeftStyled>
- </Row>
- )
- }}
- editable={{
- onRowAdd: this.addDictionaryElementRow,
- onRowUpdate: this.updateDictionaryElementRow,
- onRowDelete: this.deleteDictionaryElementRow
- }}
- /> : null
- }
- {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
- </Modal.Body>
- <Modal.Footer>
- <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
- </Modal.Footer>
- </ModalStyled>
- );
- }
+ }
+ {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
}
diff --git a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js
index d1d4aa662..a4c1335d8 100644
--- a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js
+++ b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js
@@ -27,7 +27,94 @@ import { render } from 'enzyme';
import ManageDictionaries from './ManageDictionaries';
import TemplateMenuService from '../../../api/TemplateService'
+const TestDictionaryElements = {
+ name: "test",
+ secondLevelDictionary: 0,
+ subDictionaryType: "",
+ dictionaryElements: [
+ {
+ shortName: "alertType",
+ name: "Alert Type",
+ description: "Type of Alert",
+ type: "string",
+ subDictionary: "",
+ createdDate: "2020-06-12T13:58:51.443931Z",
+ updatedDate: "2020-06-13T16:27:57.084870Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+ ]
+};
+
+const TestDictionaries =
+[
+ {
+ name: "test",
+ secondLevelDictionary: 0,
+ subDictionaryType: "string",
+ dictionaryElements: [ TestDictionaryElements ],
+ createdDate: "2020-06-14T21:00:33.231166Z",
+ updatedDate: "2020-06-14T21:00:33.231166Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ },
+ {
+ name: "testSub1",
+ secondLevelDictionary: 1,
+ subDictionaryType: "string",
+ dictionaryElements: [
+ {
+ shortName: "subElem",
+ name: "Sub Element",
+ description: "Sub Element Description",
+ type: "string",
+ createdDate: "2020-06-14T21:04:44.402287Z",
+ updatedDate: "2020-06-14T21:04:44.402287Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+ ],
+ createdDate: "2020-06-14T21:01:16.390250Z",
+ updatedDate: "2020-06-14T21:01:16.390250Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+];
+
+
+const historyMock = { push: jest.fn() };
+
+let errorMessage = '';
+
+window.alert = jest.fn().mockImplementation((mesg) => { errorMessage = mesg ; return });
+
+TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve(TestDictionaries);
+});
+
+TemplateMenuService.insDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+});
+
+TemplateMenuService.deleteDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+TemplateMenuService.getDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve(TestDictionaryElements);
+});
+
+TemplateMenuService.deleteDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+
describe('Verify ManageDictionaries', () => {
+
beforeEach(() => {
fetch.resetMocks();
});
@@ -40,7 +127,7 @@ describe('Verify ManageDictionaries', () => {
json: () => {
return Promise.resolve({
"name": "vtest",
- "secondLevelDictionary": "1",
+ "secondLevelDictionary": 1,
"subDictionaryType": "string",
"updatedBy": "test",
"updatedDate": "05-07-2019 19:09:42"
@@ -60,7 +147,7 @@ describe('Verify ManageDictionaries', () => {
json: () => {
return Promise.resolve({
"name": "vtest",
- "secondLevelDictionary": "1",
+ "secondLevelDictionary": 1,
"subDictionaryType": "string",
"updatedBy": "test",
"updatedDate": "05-07-2019 19:09:42"
@@ -71,124 +158,283 @@ describe('Verify ManageDictionaries', () => {
const component = shallow(<ManageDictionaries />);
});
- it('Test API Rejection', () => {
- const myMockFunc = fetch.mockImplementationOnce(() => Promise.reject('error'));
- setTimeout( () => myMockFunc().catch(e => {
- console.info(e);
- }),
- 100
- );
- const component = shallow(<ManageDictionaries />);
- expect(myMockFunc.mock.calls.length).toBe(1);
- });
-
it('Test Table icons', () => {
- fetch.mockImplementationOnce(() => {
- return Promise.resolve({
- ok: true,
- status: 200,
- json: () => {
- return Promise.resolve({
- "name": "vtest",
- "secondLevelDictionary": "1",
- "subDictionaryType": "string",
- "updatedBy": "test",
- "updatedDate": "05-07-2019 19:09:42"
- });
- }
- });
- });
+
const component = mount(<ManageDictionaries />);
expect(component.find('[className="MuiSelect-icon MuiTablePagination-selectIcon"]')).toBeTruthy();
});
- test('Test get dictionaryNames/dictionaryElements, add/delete dictionary functions', async () => {
- const dictionaries = [
- {
- name: "DefaultActors",
- secondLevelDictionary: 0,
- subDictionaryType: "",
- dictionaryElements: [
- {
- "shortName": "SDNR",
- "name": "SDNR Change",
- "description": "SDNR component",
- "type": "string",
- "createdDate": "2020-06-07T18:57:18.130858Z",
- "updatedDate": "2020-06-11T13:10:52.239282Z",
- "updatedBy": "admin"
- }
- ],
- createdDate: "2020-06-07T22:21:08.428742Z",
- updatedDate: "2020-06-10T00:41:49.122908Z",
- updatedBy: "Not found"
- }
- ];
- const historyMock = { push: jest.fn() };
- TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
- return Promise.resolve(dictionaries);
- });
- TemplateMenuService.getDictionaryElements = jest.fn().mockImplementation(() => {
- return Promise.resolve(dictionaries[0]);
- });
- TemplateMenuService.insDictionary = jest.fn().mockImplementation(() => {
- return Promise.resolve(200);
- });
- TemplateMenuService.deleteDictionary = jest.fn().mockImplementation(() => {
- return Promise.resolve(200);
- });
- const flushPromises = () => new Promise(setImmediate);
- const component = shallow(<ManageDictionaries history={historyMock} />)
+ test('Test add/replace and delete dictionary requests', async () => {
+
+ const component = shallow(<ManageDictionaries history={historyMock}/>)
const instance = component.instance();
- instance.getDictionaryElements("DefaultActors");
- instance.clickHandler();
- instance.addReplaceDictionaryRequest();
- instance.deleteDictionaryRequest();
+
+ const flushPromises = () => new Promise(setImmediate);
+
+ instance.addReplaceDictionaryRequest({name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string"});
+ instance.deleteDictionaryRequest("test");
+
await flushPromises();
- expect(component.state('dictionaries')).toEqual(dictionaries);
+
+ expect(component.state('currentSelectedDictionary')).toEqual(null);
+ expect(component.state('dictionaries')).toEqual(TestDictionaries);
});
- test('Test adding and deleting dictionaryelements', async () => {
- const historyMock = { push: jest.fn() };
- const dictionaries = [
- {
- name: "DefaultActors",
- secondLevelDictionary: 0,
- subDictionaryType: "",
- dictionaryElements: [
- {
- "shortName": "SDNR",
- "name": "SDNR Change",
- "description": "SDNR component",
- "type": "string",
- "createdDate": "2020-06-07T18:57:18.130858Z",
- "updatedDate": "2020-06-11T13:10:52.239282Z",
- "updatedBy": "admin"
- }
- ],
- createdDate: "2020-06-07T22:21:08.428742Z",
- updatedDate: "2020-06-10T00:41:49.122908Z",
- updatedBy: "Not found"
- }
- ];
- TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
- return Promise.resolve(dictionaries);
- });
- TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
- return Promise.resolve(200);
- });
- TemplateMenuService.deleteDictionaryElements = jest.fn().mockImplementation(() => {
- return Promise.resolve(200);
- });
- const flushPromises = () => new Promise(setImmediate);
+ test('Test update dictionary row', async () => {
+
const component = shallow(<ManageDictionaries history={historyMock}/>)
const instance = component.instance();
- instance.addReplaceDictionaryRequest({ name: "EventDictionary", secondLevelDictionary: "0", subDictionaryType: "string"} );
- instance.deleteDictionaryRequest('EventDictionary');
- await flushPromises();
- expect(component.state('currentSelectedDictionary')).toEqual(null);
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await expect(instance.updateDictionaryRow(rowData, rowData)).resolves.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test add dictionary row', async () => {
+
+ const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await instance.addDictionaryRow(rowData);
+ expect(addReplaceRequest).toHaveBeenCalledWith(rowData);
+
+ }, 2000);
+
+ test('Test add dictionary row with errors name already exists', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test add dictionary row with errors illegal chars in name', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test update dictionary row with errors illegal chars in name', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.updateDictionaryRow(rowData)).rejects.toEqual(undefined);
+ });
+
+
+ test('Test add dictionary row with errors (illegal chars)', async () => {
+
+ const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+
+ test('Test delete dictionary row', async () => {
+
+ const deleteRequest = jest.spyOn(ManageDictionaries.prototype,'deleteDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await instance.deleteDictionaryRow(rowData);
+ expect(deleteRequest).toHaveBeenCalledWith("newdict");
+
+ }, 2000);
+
+ test('Test handle select dictionary row click', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ instance.handleDictionaryRowClick("event", rowData);
+ expect(component.state('currentSelectedDictionary')).toEqual("newdict");
+ }, 2000);
+
+ test('Test dictionary element row add, update, delete', async () => {
+
+ const rowData = {
+ createdBy: "admin",
+ createdDate: "2020-06-15T13:59:20.467381Z",
+ description: "Description",
+ name: "Some Elem",
+ shortName: "someElem",
+ type: "string",
+ updatedBy: "admin",
+ updatedDate: "2020-06-15T13:59:20.467381Z"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ const badRowData = {
+ description: "Description",
+ name: "Some Elem",
+ shortName: "someElem",
+ type: "string"
+ };
+
+ await instance.clickHandler();
+ await instance.getDictionaryElements("test");
+
+ await expect(instance.addDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+ await expect(instance.updateDictionaryElementRow(rowData, rowData)).resolves.toEqual(undefined);
+ await expect(instance.deleteDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+ });
+
+ test('Test dictionary element row add with errors', async () => {
+
+ const badRowData = {
+ description: "",
+ name: "",
+ shortName: "some#Elem",
+ type: ""
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+ test('Test dictionary element update with error illegal name', async () => {
+
+ const badRowData = {
+ description: "",
+ name: "test@@",
+ shortName: "some#Elem",
+ type: ""
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ await expect(instance.updateDictionaryElementRow(badRowData)).rejects.toEqual(undefined);
+ });
+
+ test('Test dictionary element addition with duplicate name error', async () => {
+
+ const badRowData = {
+ description: "description",
+ name: "Alert Type",
+ shortName: "alertType",
+ type: "string"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ component.setState({ currentSelectedDictionary: 'test' });
+
+ await instance.getDictionaryElements();
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+ test('Test dictionary element addition with empty name error', async () => {
+
+ const badRowData = {
+ description: "description",
+ name: "Alert Type",
+ shortName: "",
+ type: "string"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ component.setState({ currentSelectedDictionary: 'test' });
+
+ await instance.getDictionaryElements();
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+
+ it('Test Import CSV Sunny Day', async () => {
+
+ TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+ });
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"alertType","Alert Type","Alert Type Description","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = [
+ {
+ description: "Alert Type Description",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ];
+
+ const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+
+ await expect(instance.importCsvData(rawCsvData)).toEqual('');
+ expect(updateDictionaryElementsRequest).toHaveBeenCalledWith(expectedResult);
+ });
+
+ it('Test Import CSV Mandatory Field Check Errors', () => {
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"","","","","","",""';
+
+ // The empty values for all the fields in row 1 of the rawCsvData will trigger a bunch of errors.
+ // Getting Enzyme to properly match them with embedded newlines turned out to be impossible
+ // and maybe not desirable anyway; so our test for "success" here is simply that the
+ // routine returns a non-empty error string.
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ expect(instance.importCsvData(rawCsvData)).not.toEqual('');
+ });
+
+ it('Test Import CSV Errors in Row Data', async () => {
+
+ TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+ });
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"alert@Type","Alert Type","Alert Type Description","strin","subby","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = [
+ {
+ description: "Alert Type Description",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ];
+
+ const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+
+ await expect(instance.importCsvData(rawCsvData)).not.toEqual('');
});
+
it('Test handleClose', () => {
fetch.mockImplementationOnce(() => {
return Promise.resolve({
@@ -197,7 +443,7 @@ describe('Verify ManageDictionaries', () => {
json: () => {
return Promise.resolve({
"name": "vtest",
- "secondLevelDictionary": "1",
+ "secondLevelDictionary": 1,
"subDictionaryType": "string",
"updatedBy": "test",
"updatedDate": "05-07-2019 19:09:42"
@@ -205,7 +451,6 @@ describe('Verify ManageDictionaries', () => {
}
});
});
- const historyMock = { push: jest.fn() };
const handleClose = jest.spyOn(ManageDictionaries.prototype,'handleClose');
const component = shallow(<ManageDictionaries history={historyMock} />)
component.find('[variant="secondary"]').prop('onClick')();
diff --git a/ui-react/src/components/dialogs/Policy/PolicyModal.js b/ui-react/src/components/dialogs/Policy/PolicyModal.js
index d3b427396..6b1ebe178 100644
--- a/ui-react/src/components/dialogs/Policy/PolicyModal.js
+++ b/ui-react/src/components/dialogs/Policy/PolicyModal.js
@@ -34,11 +34,16 @@ import LoopCache from '../../../api/LoopCache';
import JSONEditor from '@json-editor/json-editor';
import Alert from 'react-bootstrap/Alert';
import OnapConstant from '../../../utils/OnapConstants';
+import OnapUtils from '../../../utils/OnapUtils';
const ModalStyled = styled(Modal)`
background-color: transparent;
`
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
export default class PolicyModal extends React.Component {
state = {
@@ -70,42 +75,49 @@ export default class PolicyModal extends React.Component {
this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this);
this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this);
this.renderModalTitle = this.renderModalTitle.bind(this);
+ this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
}
handleSave() {
- var errors = this.state.jsonEditor.validate();
var editorData = this.state.jsonEditor.getValue();
+ var errors = this.state.jsonEditor.validate();
+ errors = errors.concat(this.customValidation(editorData, this.state.loopCache.getTemplateName()));
if (errors.length !== 0) {
console.error("Errors detected during policy data validation ", errors);
this.setState({
- showFailAlert: true,
- showMessage: "Errors detected during policy data validation " + errors
- });
+ showFailAlert: true,
+ showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
+ });
return;
}
else {
console.info("NO validation errors found in policy data");
if (this.state.policyInstanceType === OnapConstant.microServiceType) {
- this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData);
- this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
- LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => {
- this.setState({ show: false });
- this.props.history.push('/');
- this.props.loadLoopFunction(this.state.loopCache.getLoopName());
- });
+ this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData);
+ this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
+ LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ });
} else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData);
this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => {
this.setState({ show: false });
- this.props.history.push('/');
+ this.props.history.push('/');
this.props.loadLoopFunction(this.state.loopCache.getLoopName());
});
}
}
}
+ customValidation(editorData, templateName) {
+ // method for sub-classes to override with customized validation
+ return [];
+ }
+
handleClose() {
this.setState({ show: false });
this.props.history.push('/');
@@ -115,6 +127,15 @@ export default class PolicyModal extends React.Component {
this.renderJsonEditor();
}
+ componentDidUpdate() {
+ if (this.state.showSucAlert === true || this.state.showFailAlert === true) {
+ let modalElement = document.getElementById("policyModal")
+ if (modalElement) {
+ modalElement.scrollTo(0, 0);
+ }
+ }
+ }
+
createJsonEditor(toscaModel, editorData) {
JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
getTab: function(text,tabId) {
@@ -313,12 +334,16 @@ export default class PolicyModal extends React.Component {
<Modal.Header closeButton>
{this.renderModalTitle()}
</Modal.Header>
- <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
- {this.state.showMessage}
- </Alert>
- <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
- {this.state.showMessage}
- </Alert>
+ <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
<Modal.Body>
{this.renderOpenLoopMessage()}
<div id="editor" />
@@ -330,4 +355,4 @@ export default class PolicyModal extends React.Component {
</ModalStyled>
);
}
-} \ No newline at end of file
+}
diff --git a/ui-react/src/utils/OnapUtils.js b/ui-react/src/utils/OnapUtils.js
new file mode 100644
index 000000000..316a0d65f
--- /dev/null
+++ b/ui-react/src/utils/OnapUtils.js
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 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.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+export default class OnapUtils {
+
+ constructor() {
+ this.clickBlocked = false;
+ }
+
+ static jsonEditorErrorFormatter(errors) {
+
+ let messages = [];
+ let messagesOutputString = null;
+
+ // errors is an array of JSON Editor "error" objects, where each
+ // object looks like this:
+
+ // {
+ // message: "Please populate the required property "Threshold""
+ // path: "root.signatures.0"
+ // property: "required"
+ // }
+
+ // In this function we concatenate all the messages, removing any duplicates,
+ // and adding a newline between each message. The result returned is a single
+ // string that can be displayed to the user in an alert message
+
+ if (!Array.isArray(errors)) {
+ console.error('jsoneEditorErrorFormatter was passed a non-array argument');
+ } else {
+ for (let ii=0; ii < errors.length; ++ii) {
+ if (!messages.includes(errors[ii].message)) {
+ messages.push(errors[ii].message);
+ if (messagesOutputString) {
+ messagesOutputString += '\n' + errors[ii].message;
+ } else {
+ messagesOutputString = errors[ii].message;
+ }
+ }
+ }
+ }
+
+ return messagesOutputString;
+ }
+}