1 import React from 'react'
2 import Modal from 'react-modal'
3 import Dialog from 'react-dialog'
4 import LeafField from './editor/LeafField'
5 import yang from '../yang/leaf-utils.js'
6 import changeCase from 'change-case'
8 const Button = ({ name, onClick, disabled }) => (
9 <button disabled={disabled}
10 style={{ padding: '.25rem .5rem', margin: '0 0.25rem', boxShadow: '1px 1px rgba(0, 0, 0, 0.15)' }}
11 onClick={onClick}>{name}</button>
14 const ButtonBar = ({ submitName, submitDisabled, onSubmit, onCancel }) => (
15 <div className='button-bar' style={{ width: '100%', textAlign: 'right', marginTop: '18px' }} >
16 <Button name="Cancel" onClick={onCancel} />
17 <Button name={submitName} onClick={onSubmit} disabled={submitDisabled} />
21 function initErrorInfo(leaves, container) {
22 return leaves.reduce((errorInfo, p) => {
23 const value = container && container[p.name];
24 const readOnly = p.isKey && !operation.isCreate;
25 if (!readOnly && p.mandatory && !value) {
26 errorInfo[p.name] = 'required';
32 function buildChoiceProperty(choiceProperty) {
33 let description = choiceProperty.description + ' ';
34 const choices = choiceProperty.properties.reduce((o, p) => {
35 o[p.name] = { value: p.name };
36 description = `${description} ${p.name} - ${p.description}`;
39 const choicePicker = Object.assign({}, choiceProperty);
40 choicePicker['type'] = 'leaf';
41 choicePicker['description'] = description;
42 choicePicker['data-type'] = {
50 function getIntialState(props) {
51 const { isOpen, model, path, operation } = props;
52 const baseLeaves = [];
56 let shadowErrorInfo = {};
57 let leaves = baseLeaves;
58 if (isOpen && path && !operation.isDelete) {
59 const element = model.getElement(path);
62 leaf_list: baseLeaves,
65 element.schema.properties.forEach((property, index) => {
66 const list = dataDivided[property.type]
67 list && list.push(property)
69 if (!operation.isCreate) {
70 // we are not going to prompt for choices so add in appropriate files now
71 choices.forEach((choice) => {
72 const caseSelected = choice.properties.find(c => c.properties && c.properties.some(p => element.value[p.name]));
74 caseSelected.properties.forEach(p => yang.isLeafOrLeafList(p) && baseLeaves.push(p));
78 // on create we first propmt for "features"
79 leaves = choices.map(choice => buildChoiceProperty(choice));
81 shadowErrorInfo = initErrorInfo(leaves, element.value);
83 return { dataSet, shadowErrorInfo, errorInfo, baseLeaves, leaves, choices };
86 export default class extends React.Component {
89 this.state = getIntialState(props);
90 this.state.showHelp = true;
93 handleCloseEditor = () => {
96 componentWillReceiveProps(nextProps) {
97 if (this.props.isOpen !== nextProps.isOpen) {
98 this.setState(getIntialState(nextProps));
104 const { isOpen, model, isReadonly, properties, operation, onSave, onCancel } = this.props;
108 let dataPath = this.props.path.slice();
109 const element = model.getElement(dataPath);
110 const container = element.value;
112 let submitHandler = () => {
113 if (Object.keys(this.state.errorInfo).length === 0) {
114 onSave(this.state.dataSet);
117 const checkForSubmitKey = (e) => {
118 if (e.keyCode == 13) {
124 let submitButtonLabel = operation.isCreate ? "Add" : "Save";
125 let submitDisabled = true;
126 let headerText = null;
127 if (operation.isDelete) {
128 const id = dataPath[dataPath.length - 1];
129 const deletePrompt = `Delete ${id}?`;
130 submitButtonLabel = "Delete";
131 submitDisabled = false;
132 editors = (<div style={{ paddingBottom: '10px' }}>{deletePrompt}</div>);
134 let { leaves, choices } = this.state;
135 if (choices.length) {
136 if (operation.isCreate) {
137 headerText = `Select feature(s) for ${element.name}`
138 submitButtonLabel = "Continue";
139 submitHandler = () => {
140 const { dataSet, baseLeaves } = this.state;
141 const leaves = choices.reduce((leafList, choice) => {
142 const caseSelected = dataSet[choice.name].value;
143 delete dataSet[choice.name];
145 return leafList.concat(choice.properties.find((p) => p.name === caseSelected).properties.reduce((list, p) => {
146 yang.isLeafOrLeafList(p) && list.push(p);
151 }, baseLeaves.slice());
152 const shadowErrorInfo = initErrorInfo(leaves, element.value);
153 this.setState({ dataSet, leaves, choices: [], errorInfo: {}, shadowErrorInfo });
157 submitDisabled = (Object.keys(this.state.shadowErrorInfo).length
158 || (!operation.isCreate && Object.keys(this.state.dataSet).length === 0));
159 // process the named field value change
160 function processFieldValueChange(property, currentValue, value) {
161 console.debug(`processed change for -- ${name} -- with value -- ${value}`);
162 const dataSet = this.state.dataSet;
163 const name = property.name;
164 if ((currentValue && currentValue !== value) || (!currentValue && value)) {
165 dataSet[name] = { property, value, currentValue };
167 delete dataSet[name];
169 const { errorInfo, shadowErrorInfo } = this.state;
170 delete errorInfo[name];
171 delete shadowErrorInfo[name];
172 this.setState({ dataSet, errorInfo, shadowErrorInfo });
175 function onErrorHandler(name, message) {
176 const { errorInfo, shadowErrorInfo } = this.state;
177 errorInfo[name] = message;
178 shadowErrorInfo[name] = message;
179 this.setState({ errorInfo, shadowErrorInfo });
182 editors = leaves.reduce((editors, property, index) => {
183 const itemPath = dataPath.slice();
184 itemPath.push(property.name);
185 const props = { model, 'path': itemPath };
186 const value = container && container[property.name];
187 let readOnly = isReadonly;
188 let extraHelp = null;
190 if (yang.isKey(property) && !operation.isCreate) {
191 extraHelp = "Id fields are not modifiable.";
193 } else if (yang.isLeafList(property)) {
194 extraHelp = "Enter a comma separated list of values."
200 container={container}
204 showHelp={this.state.showHelp}
205 onChange={processFieldValueChange.bind(this, property, value)}
206 onError={onErrorHandler.bind(this, property.name)}
208 extraHelp={extraHelp}
209 errorMessage={this.state.errorInfo[property.name]}
215 const customStyles = {
222 transform: 'translate(-50%, -50%)'
225 const dlgHeader = headerText ? (<div style={{ paddingBottom: '16px' }} >{headerText}</div>) : null;
230 onRequestClose={onCancel}
231 shouldCloseOnOverlayClick={false}
234 <div className='leaf-group' style={{ maxWidth: '400px', maxHeight: '600px' }} onKeyUp={checkForSubmitKey} >
238 submitName={submitButtonLabel}
239 submitDisabled={submitDisabled}
240 onSubmit={submitHandler}
241 onCancel={onCancel} />
246 console.error("component render", e);