Merge pull request #4223 from panda01/angularUpgrade

Angular upgrade
This commit is contained in:
Rashid Khan 2015-10-29 10:35:15 -07:00
commit e547cd3965
21 changed files with 47 additions and 236 deletions

View file

@ -60,19 +60,16 @@
"url": "https://github.com/elastic/kibana.git"
},
"dependencies": {
"@spalger/angular-bootstrap": "0.10.0",
"@spalger/angular-nvd3": "1.0.0-beta",
"@spalger/angular-bootstrap": "0.12.1",
"@spalger/filesaver": "1.1.2",
"@spalger/leaflet-draw": "0.2.3",
"@spalger/leaflet-heat": "0.1.3",
"@spalger/numeral": "^2.0.0",
"@spalger/nvd3": "1.8.1",
"@spalger/ui-ace": "0.2.3",
"angular": "1.2.28",
"angular-bindonce": "0.3.1",
"angular": "1.4.7",
"angular-bootstrap-colorpicker": "3.0.19",
"angular-elastic": "2.5.0",
"angular-route": "1.2.28",
"angular-route": "1.4.7",
"ansicolors": "0.3.2",
"autoprefixer": "5.1.1",
"autoprefixer-loader": "2.0.0",
@ -133,7 +130,7 @@
},
"devDependencies": {
"Nonsense": "0.1.2",
"angular-mocks": "1.2.28",
"angular-mocks": "1.4.7",
"auto-release-sinon": "1.0.3",
"babel-eslint": "4.1.3",
"chokidar": "1.0.5",

View file

@ -1,6 +1,6 @@
<div dashboard-app class="app-container dashboard-container">
<navbar ng-show="chrome.getVisible()">
<span class="name" ng-if="dash.id" bindonce bo-bind="dash.title" tooltip="{{dash.title}}"></span>
<span class="name" ng-if="dash.id" ng-bind="::dash.title" tooltip="{{::dash.title}}"></span>
<form name="queryInput"
class="fill inline-form"

View file

@ -1,11 +1,11 @@
<li bindonce class="sidebar-item" bo-attr bo-attr-field="field.name">
<li class="sidebar-item" attr-field="{{::field.name}}">
<div ng-click="toggleDetails(field)" class="sidebar-item-title">
<field-name field="field"></field-name>
<button
ng-click="toggleDisplay(field)"
bo-class="field.display ? 'btn-danger' : 'btn-primary'"
bo-text="field.display ? 'remove' : 'add'"
ng-class="::field.display ? 'btn-danger' : 'btn-primary'"
ng-bind="::field.display ? 'remove' : 'add'"
class="btn btn-xs btn-primary discover-field-toggle" ></button>
</div>
</li>

View file

@ -1,11 +1,11 @@
<div bindonce>
<div>
<div class="discover-field-details">
<h5 ng-show="!field.details.error">Quick Count <kbn-info info="Top 5 values based on documents in the table" placement="right"></kbn-info>
<span ng-if="!field.details.error" class="small discover-field-details-count">
(
<a ng-show="field.indexed" ng-click="updateFilterInQuery('_exists_', field.name, '+')">{{field.details.exists}}</a>
<span ng-show="!field.indexed">{{field.details.exists}}</span>
/{{field.details.total}} records
<a ng-show="field.indexed" ng-click="updateFilterInQuery('_exists_', field.name, '+')">{{::field.details.exists}}</a>
<span ng-show="!field.indexed">{{::field.details.exists}}</span>
/{{::field.details.total}} records
)
</span>
</h5>
@ -15,7 +15,7 @@
<div ng-if="field.details.error" class="discover-field-details-error">{{field.details.error}}</div>
<div ng-if="!field.details.error">
<div ng-repeat="bucket in field.details.buckets" class="discover-field-details-item">
<div ng-repeat="bucket in ::field.details.buckets" class="discover-field-details-item">
<div>
<span ng-show="field.filterable" class="pull-right">
<i aria-hidden="true" class="fa fa-search-minus pull-right discover-field-details-filter"
@ -24,10 +24,10 @@
ng-click="updateFilterInQuery(field, bucket.value, '+')"></i>
</span>
<div css-truncate css-truncate-expandable="true" class="discover-field-details-value">
{{bucket.display}} <i ng-show="bucket.display === ''">Empty string</i>
{{::bucket.display}} <i ng-show="bucket.display === ''">Empty string</i>
</div>
</div>
<kbn-tooltip text="{{bucket.count}}" placement="right" append-to-body="1">
<kbn-tooltip text="{{::bucket.count}}" placement="right" append-to-body="1">
<progressbar value="bucket.percent" max="100" animate="false"><span>{{bucket.percent}}%</span></progressbar>
</kbn-tooltip>
</div>
@ -40,7 +40,7 @@
class="sidebar-item-button primary">
Visualize
<span class="discover-field-vis-warning" ng-show="warnings.length" tooltip="{{warnings.join(' ')}}">
( {{warnings.length}} <ng-pluralize count="warnings.length" when="{'1':'warning', 'other':'warnings'}"></ng-pluralize> <i aria-hidden="true" class="fa fa-warning"></i> )
( {{::warnings.length}} <ng-pluralize count="warnings.length" when="{'1':'warning', 'other':'warnings'}"></ng-pluralize> <i aria-hidden="true" class="fa fa-warning"></i> )
</span>
</a>

View file

@ -77,7 +77,7 @@
<div class="discover-info">
<span ng-show="opts.savedSearch.id" class="discover-info-title">
<span bindonce bo-bind="opts.savedSearch.title"></span>
<span ng-bind="::opts.savedSearch.title"></span>
<i aria-label="Reload Saved Search" tooltip="Reload Saved Search" ng-click="resetQuery();" class="fa fa-undo small"></i>
</span>

View file

@ -1,6 +1,6 @@
<kbn-settings-app section="indices">
<kbn-settings-indices>
<div ng-controller="settingsIndicesEdit" bindonce>
<div ng-controller="settingsIndicesEdit">
<div class="page-header">
<kbn-settings-index-header
index-pattern="indexPattern"
@ -10,7 +10,7 @@
</kbn-settings-index-header>
<p>
This page lists every field in the <strong>{{indexPattern.id}}</strong>
This page lists every field in the <strong>{{::indexPattern.id}}</strong>
index and the field's associated core type as recorded by Elasticsearch.
While this list allows you to view the core type of each field, changing
field types must be done using Elasticsearch's
@ -20,7 +20,7 @@
</a>
</p>
<div ng-if="indexPattern.timeFieldName && indexPattern.intervalName" class="alert alert-info">
This index uses a <strong>Time-based index pattern</strong> which repeats <span bo-text="indexPattern.getInterval().display"></span>
This index uses a <strong>Time-based index pattern</strong> which repeats <span ng-bind="::indexPattern.getInterval().display"></span>
</div>
<div ng-if="conflictFields.length" class="alert alert-warning">
<strong>Mapping conflict!</strong> {{conflictFields.length > 1 ? conflictFields.length : 'A'}} field{{conflictFields.length > 1 ? 's' : ''}} {{conflictFields.length > 1 ? 'are' : 'is'}} defined as several types (string, integer, etc) across the indices that match this pattern. You may still be able to use these conflict fields in parts of Kibana, but they will be unavailable for functions that require Kibana to know their type. Correcting this issue will require reindexing your data.

View file

@ -1,4 +1,4 @@
<div class="col-md-2 sidebar-container" bindonce="indexPatternList">
<div class="col-md-2 sidebar-container">
<div class="sidebar-list">
<div class="sidebar-list-header">
<h5>
@ -24,10 +24,10 @@
<li
ng-repeat="pattern in indexPatternList | orderBy:['-default','id'] track by pattern.id "
class="sidebar-item">
<a bo-href="pattern.url">
<div bo-class="pattern.class">
<a href="{{::pattern.url}}">
<div class="{{::pattern.class}}">
<i aria-hidden="true" ng-if="pattern.default" class="fa fa-star"></i>
<span bo-text="pattern.id"></span>
<span ng-bind="::pattern.id"></span>
</div>
</a>
</li>

View file

@ -132,9 +132,9 @@
<div class="vis-editor-canvas" ng-class="{ embedded: !chrome.getVisible() }">
<div class="visualize-info" ng-if="savedVis.id">
<div class="visualize-info-tab" title="{{savedVis.vis.type.title}}">
<i class="fa" aria-label="{{savedVis.vis.type.title}} Icon" ng-class="savedVis.vis.type.icon"></i>
<span bindonce bo-bind="savedVis.title"></span>
<div class="visualize-info-tab" title="{{::savedVis.vis.type.title}}">
<i class="fa" aria-label="{{::savedVis.vis.type.title}} Icon" ng-class="savedVis.vis.type.icon"></i>
<span ng-bind="::savedVis.title"></span>
</div>
</div>

View file

@ -1,7 +1,6 @@
var _ = require('lodash');
var moment = require('moment');
var numeral = require('numeral');
require('angular-nvd3');
var toTitleCase = require('./lib/toTitleCase');
var formatNumber = require('./lib/formatNumber');
@ -17,7 +16,7 @@ function calcAvg(metricList, metricNumberType) {
}
require('ui/modules')
.get('kibana', ['nvd3'])
.get('kibana', [])
.directive('statusPageMetric', function () {
return {
restrict: 'E',

View file

@ -40,7 +40,7 @@ module.exports = class UiBundlerEnv {
// regular expressions which will prevent webpack from parsing the file
this.noParse = [
/node_modules[\/\\](angular|elasticsearch-browser)[\/\\]/,
/node_modules[\/\\](angular-nvd3|mocha|moment)[\/\\]/
/node_modules[\/\\](mocha|moment)[\/\\]/
];
// webpack aliases, like require paths, mapping a prefix to a directory

View file

@ -1,9 +1,8 @@
<kbn-notifications list="notifList"></kbn-notifications>
<div class="content" chrome-context >
<nav
ng-style="{ background: chrome.getNavBackground() }"
ng-class="{ show: chrome.getVisible() }"
bindonce
ng-style="::{ background: chrome.getNavBackground() }"
ng-class="::{ show: chrome.getVisible() }"
class="hide navbar navbar-inverse navbar-static-top">
<!-- Mobile navbar -->

View file

@ -237,7 +237,7 @@ describe('timepicker directive', function () {
expect(button.length).to.be(0);
// Make the form invalid
$scope.relative.count = 'foo';
$scope.relative.count = -3;
$scope.formatRelative();
$scope.$digest();
@ -263,12 +263,12 @@ describe('timepicker directive', function () {
expect(checkbox.length).to.be(1);
// Rounding is disabled by default
expect(checkbox.attr('checked')).to.be(undefined);
expect(checkbox.prop('checked')).to.be(false);
// Enable rounding
$scope.relative.round = true;
$scope.$digest();
expect(checkbox.attr('checked')).to.be('checked');
expect(checkbox.prop('checked')).to.be(true);
done();
});
@ -344,13 +344,11 @@ describe('timepicker directive', function () {
// Should update the selected option
var i = 0;
_.each($scope.units, function (longUnit, shortUnit) {
$scope.relative.unit = shortUnit;
$scope.$digest();
expect(select.val()).to.be(i.toString());
i++;
expect(select.val().split(':')[1]).to.be(shortUnit);
});
done();
@ -371,8 +369,8 @@ describe('timepicker directive', function () {
inputs = {
fromInput: $elem.find('.kbn-timepicker-section input[ng-model="absolute.from"]'),
toInput: $elem.find('.kbn-timepicker-section input[ng-model="absolute.to"]'),
fromCalendar: $elem.find('.kbn-timepicker-section table[ng-model="absolute.from"] '),
toCalendar: $elem.find('.kbn-timepicker-section table[ng-model="absolute.to"] '),
fromCalendar: $elem.find('.kbn-timepicker-section div[ng-model="absolute.from"] '),
toCalendar: $elem.find('.kbn-timepicker-section div[ng-model="absolute.to"] '),
};
});

View file

@ -33,7 +33,7 @@ var init = function () {
this.options = options;
}
PersistedLogMock.prototype.add = sinon.stub();
PersistedLogMock.prototype.add = sinon.stub().returns(typeaheadItems);
PersistedLogMock.prototype.get = sinon.stub().returns(typeaheadItems);
return PersistedLogMock;

View file

@ -1,135 +0,0 @@
define(function (require) {
var _ = require('lodash');
var angular = require('angular');
var PRISTINE_CLASS = 'ng-pristine';
var DIRTY_CLASS = 'ng-dirty';
var UNTOUCHED_CLASS = 'ng-untouched';
var TOUCHED_CLASS = 'ng-touched';
// http://goo.gl/eJofve
var nullFormCtrl = {
$addControl: _.noop,
$removeControl: _.noop,
$setValidity: _.noop,
$setDirty: _.noop,
$setPristine: _.noop
};
/**
* Extension of Angular's NgModelController class
* that ensures models are marked "dirty" after
* they move from an invalid state to valid.
*
* @param {$scope} $scope
*/
function KbnModelController($scope, $element, $animate) {
var ngModel = this;
// verify that angular works the way we are assuming it does
if (angular.version.full !== '1.2.28') {
throw new Error('angular version has updated but KbnModelController has not!');
}
/**
* Get the form a model belongs to
*
* @return {NgFormController} - the parent controller of a noop controller
*/
ngModel.$getForm = function () {
return $element.inheritedData('$formController') || nullFormCtrl;
};
/**
* Update the ngModel to be "dirty" if it is pristine.
*
* @return {undefined}
*/
ngModel.$setDirty = function () {
ngModel.$setTouched();
$$setDirty();
};
function $$setDirty() {
if (ngModel.$dirty) return;
ngModel.$dirty = true;
ngModel.$pristine = false;
$animate.removeClass($element, PRISTINE_CLASS);
$animate.addClass($element, DIRTY_CLASS);
ngModel.$getForm().$setDirty();
}
ngModel.$setTouched = toggleTouched(true);
ngModel.$setUntouched = toggleTouched(false);
function toggleTouched(val) {
return function () {
if (ngModel.$touched === val) return;
ngModel.$touched = val;
ngModel.$untouched = !val;
$animate.addClass($element, val ? TOUCHED_CLASS : UNTOUCHED_CLASS);
$animate.removeClass($element, val ? UNTOUCHED_CLASS : TOUCHED_CLASS);
};
}
/**
* While the model is pristine, ensure that the model
* gets set to dirty if it becomes invalid. If the model
* becomes dirty of other reasons stop watching and
* waitForPristine()
*
* @return {undefined}
*/
function watchForDirtyOrInvalid() {
var unwatch = $scope.$watch(get, react);
function get() {
return ngModel.$dirty || ngModel.$invalid;
}
function react(is, was) {
if (is === was) return;
unwatch();
waitForPristine();
$$setDirty();
}
}
/**
* Once a model becomes dirty, there is no longer a need
* for a watcher. Instead, we will react to the $setPristine
* method being called. This is the only way for a model to go
* from dirty -> pristine.
*
* @return {[type]} [description]
*/
function waitForPristine() {
var fn = ngModel.$setPristine;
ngModel.$setPristine = function () {
var ret = fn.apply(this, arguments);
if (ngModel.$pristine) {
ngModel.$setPristine = fn;
watchForDirtyOrInvalid();
}
return ret;
};
}
ngModel.$setUntouched();
$element.one('blur', function () {
ngModel.$setTouched();
$scope.$apply();
});
$scope.$on('$destroy', function () {
$element.off('blur', ngModel.$setTouched);
});
// wait for child scope to init before watching validity
$scope.$evalAsync(function () {
if (ngModel.$dirty) waitForPristine();
else watchForDirtyOrInvalid();
});
}
return KbnModelController;
});

View file

@ -59,44 +59,4 @@ describe('fancy forms', function () {
expect(ngForm.describeErrors()).to.be('1 Error');
});
});
describe('ngModelController', function () {
it('gives access to the ngFormController', function () {
expect(ngModel.$getForm()).to.be(ngForm);
});
it('allows setting the model dirty', function () {
expect($el.find('input.ng-dirty')).to.have.length(0);
ngModel.$setDirty();
expect($el.find('input.ng-dirty')).to.have.length(1);
});
it('sets the model dirty when it moves from valid to invalid', function () {
// clear out the old scope/el
$scope.$destroy();
$el = generateEl();
$scope = $rootScope.$new();
// start with a valid value
$scope.val = 'something';
$compile($el)($scope);
$rootScope.$apply();
// ensure that the field is valid and pristinve
var $valid = $el.find('input.ng-valid');
expect($valid).to.have.length(1);
expect($valid.hasClass('ng-pristine')).to.be(true);
expect($valid.hasClass('ng-dirty')).to.be(false);
// remove the value without actually setting the view model
$scope.val = null;
$rootScope.$apply();
// ensure that the field is now invalid and dirty
var $invalid = $el.find('input.ng-invalid');
expect($invalid).to.have.length(1);
expect($valid.hasClass('ng-pristine')).to.be(false);
expect($valid.hasClass('ng-dirty')).to.be(true);
});
});
});

View file

@ -3,7 +3,6 @@ define(function (require) {
var $ = require('jquery');
var KbnFormController = require('ui/fancy_forms/KbnFormController');
var KbnModelController = require('ui/fancy_forms/KbnModelController');
require('ui/modules')
.get('kibana')
@ -40,6 +39,5 @@ define(function (require) {
$provide.decorator('formDirective', decorateDirectiveController(KbnFormController));
$provide.decorator('ngFormDirective', decorateDirectiveController(KbnFormController));
$provide.decorator('ngModelDirective', decorateDirectiveController(KbnModelController));
});
});

View file

@ -6,12 +6,12 @@
<div class="agg-table-paginated">
<table class="table table-condensed">
<thead>
<tr bindonce>
<tr>
<th
ng-repeat="col in columns"
ng-repeat="col in ::columns"
ng-click="paginatedTable.sortColumn($index)"
class="{{ col.class }}">
<span bo-text="col.title"></span>
<span ng-bind="::col.title"></span>
<kbn-info ng-if="col.info" info="{{ col.info }}" placement="top"></kbn-info>
<i
ng-if="col.sortable !== false"

View file

@ -213,6 +213,7 @@ kbn-info i {
.kbn-timepicker .btn-info {
.button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);
.text-info { color: @btn-info-color; }
text-shadow: none;
}

View file

@ -41,12 +41,12 @@
<div class="col-md-10">
<div ng-switch on="mode" class="container-fluid">
<div ng-switch-when="quick" bindonce>
<div ng-switch-when="quick">
<div ng-repeat="list in quickLists" class="kbn-timepicker-section">
<ul class="list-unstyled">
<li ng-repeat="option in list">
<a ng-click="setQuick(option.from, option.to)" bo-text="option.display"></a>
<a ng-click="setQuick(option.from, option.to)" ng-bind="::option.display"></a>
</li>
</ul>
</div>
@ -124,7 +124,7 @@
<input type="text" required class="form-control" input-datetime="{{format}}" ng-model="absolute.from">
</div>
<div>
<datepicker ng-model="absolute.from" max="absolute.to" show-weeks="false"></datepicker>
<datepicker ng-model="absolute.from" max-date="absolute.to" show-weeks="false"></datepicker>
</div>
</div>
@ -137,7 +137,7 @@
<input type="text" required class="form-control" input-datetime="{{format}}" ng-model="absolute.to">
</div>
<div>
<datepicker ng-model="absolute.to" min="absolute.from" show-weeks="false"></datepicker>
<datepicker ng-model="absolute.to" min-date="absolute.from" show-weeks="false"></datepicker>
</div>
</div>

View file

@ -1,5 +0,0 @@
require('d3');
require('@spalger/nvd3/build/nv.d3.css');
require('@spalger/nvd3/build/nv.d3.js');
require('@spalger/angular-nvd3/dist/angular-nvd3.min.js');
module.exports = window.nv;

View file

@ -2,8 +2,7 @@ require('jquery');
require('node_modules/angular/angular');
module.exports = window.angular;
require('node_modules/angular-bindonce/bindonce');
require('node_modules/angular-elastic/elastic');
require('node_modules/angular-route/angular-route');
require('ui/modules').get('kibana', ['ngRoute', 'monospaced.elastic', 'pasvaz.bindonce']);
require('ui/modules').get('kibana', ['ngRoute', 'monospaced.elastic']);