fuel-web/nailgun/static/views/custom_controls.js

193 lines
8.7 KiB
JavaScript

/*
* Copyright 2015 Mirantis, Inc.
*
* 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.
**/
define([
'jquery',
'underscore',
'i18n',
'react',
'utils',
'views/controls'
], function($, _, i18n, React, utils, controls) {
'use strict';
var customControls = {};
customControls.custom_repo_configuration = React.createClass({
statics: {
// validate method represented as static method to support cluster settings validation
validate: function(setting, models) {
var ns = 'cluster_page.settings_tab.custom_repo_configuration.errors.',
nameRegexp = /^[\w-.]+$/,
os = models.release.get('operating_system');
var errors = setting.value.map(function(repo) {
var error = {},
value = this.repoToString(repo, os);
if (!repo.name) {
error.name = i18n(ns + 'empty_name');
} else if (!repo.name.match(nameRegexp)) {
error.name = i18n(ns + 'invalid_name');
}
if (!value || !value.match(this.defaultProps.repoRegexes[os])) {
error.uri = i18n(ns + 'invalid_repo');
}
var priority = repo.priority;
if (_.isNaN(priority) || !_.isNull(priority) && (!(priority == _.parseInt(priority, 10)) || os == 'CentOS' && (priority < 1 || priority > 99))) {
error.priority = i18n(ns + 'invalid_priority');
}
return _.isEmpty(error) ? null : error;
}, this);
return _.compact(errors).length ? errors : null;
},
repoToString: function(repo, os) {
var repoData = _.compact(this.defaultProps.repoAttributes[os].map(function(attribute) {return repo[attribute];}));
if (!repoData.length) return ''; // in case of new repo
return repoData.join(' ');
}
},
getInitialState: function() {
return {};
},
getDefaultProps: function() {
return {
repoRegexes: {
Ubuntu: /^(deb|deb-src)\s+(\w+:\/\/[\w\-.\/]+(?::\d+)?[\w\-.\/]+)\s+([\w\-.\/]+)(?:\s+([\w\-.\/\s]+))?$/i,
CentOS: /^(\w+:\/\/[\w\-.\/]+(?::\d+)?[\w\-.\/]+)\s*$/i
},
repoAttributes: {
Ubuntu: ['type', 'uri', 'suite', 'section'],
CentOS: ['uri']
}
};
},
changeRepos: function(method, index, value) {
value = _.trim(value).replace(/\s+/g, ' ');
var repos = _.cloneDeep(this.props.value),
os = this.props.cluster.get('release').get('operating_system');
switch (method) {
case 'add':
var data = {
name: '',
type: '',
uri: '',
priority: this.props.extra_priority
};
if (os == 'Ubuntu') {
data.suite = '';
data.section = '';
} else {
data.type = 'rpm';
}
repos.push(data);
break;
case 'delete':
repos.splice(index, 1);
this.setState({key: _.now()});
break;
case 'change_name':
repos[index].name = value;
break;
case 'change_priority':
repos[index].priority = value == '' ? null : Number(value);
break;
default:
var repo = repos[index],
match = value.match(this.props.repoRegexes[os]);
if (match) {
_.each(this.props.repoAttributes[os], function(attribute, index) {
repo[attribute] = match[index + 1] || '';
});
} else {
repo.uri = value;
}
}
var path = this.props.settings.makePath(this.props.path, 'value');
this.props.settings.set(path, repos);
this.props.settings.isValid({models: this.props.configModels});
},
renderDeleteButton: function(index) {
return (
<button
className='btn btn-link'
onClick={this.changeRepos.bind(this, 'delete', index)}
disabled={this.props.disabled}
>
<i className='glyphicon glyphicon-minus-sign' />
</button>
);
},
render: function() {
var ns = 'cluster_page.settings_tab.custom_repo_configuration.',
os = this.props.cluster.get('release').get('operating_system');
return (
<div className='repos' key={this.state.key}>
{this.props.description &&
<span className='help-block' dangerouslySetInnerHTML={{__html: utils.urlify(utils.linebreaks(_.escape(this.props.description)))}} />
}
{this.props.value.map(function(repo, index) {
var error = (this.props.error || {})[index],
props = {
name: index,
type: 'text',
disabled: this.props.disabled
};
return (
<div className='form-inline' key={'repo-' + index}>
<controls.Input
{...props}
defaultValue={repo.name}
error={error && error.name}
wrapperClassName='repo-name'
onChange={this.changeRepos.bind(this, 'change_name')}
label={index == 0 && i18n(ns + 'labels.name')}
debounce
/>
<controls.Input
{...props}
defaultValue={this.constructor.repoToString(repo, os)}
error={error && (error.uri ? error.name ? '' : error.uri : null)}
onChange={this.changeRepos.bind(this, null)}
label={index == 0 && i18n(ns + 'labels.uri')}
wrapperClassName='repo-uri'
debounce
/>
<controls.Input
{...props}
defaultValue={repo.priority}
error={error && (error.priority ? (error.name || error.uri) ? '' : error.priority : null)}
wrapperClassName='repo-priority'
onChange={this.changeRepos.bind(this, 'change_priority')}
extraContent={index > 0 && this.renderDeleteButton(index)}
label={index == 0 && i18n(ns + 'labels.priority')}
placeholder={i18n(ns + 'placeholders.priority')}
debounce
/>
</div>
);
}, this)}
<div className='buttons'>
<button key='addExtraRepo' className='btn btn-default btn-add-repo' onClick={this.changeRepos.bind(this, 'add')} disabled={this.props.disabled}>
{i18n(ns + 'add_repo_button')}
</button>
</div>
</div>
);
}
});
return customControls;
});