Skip to content

Commit

Permalink
appState defaults are now applied everytime time the state changes, f…
Browse files Browse the repository at this point in the history
…ixes #31
  • Loading branch information
Spencer Alger committed Apr 24, 2014
1 parent b57be6b commit f7ccc62
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 188 deletions.
39 changes: 18 additions & 21 deletions src/kibana/apps/discover/controllers/discover.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ define(function (require) {
});


app.controller('discover', function ($scope, config, courier, $route, savedSearches, Notifier, $location, AppState, timefilter) {
app.controller('discover', function ($scope, config, courier, $route, savedSearches,
Notifier, $location, globalState, AppState, timefilter) {

var notify = new Notifier({
location: 'Discover'
});
Expand Down Expand Up @@ -90,33 +92,23 @@ define(function (require) {
$scope.time = timefilter.time;

// TODO: Switch this to watching time.string when we implement it
$scope.$watchCollection('time', function () {
updateDataSource();
$scope.fetch();
});
$scope.$watchCollection('time', _.bindKey($scope, 'fetch'));

// stores the complete list of fields
$scope.fields = null;

var init = _.once(function () {
return setFields()
.then(updateDataSource)
.then(function () {
// the index to use when they don't specify one
$scope.$on('change:config.defaultIndex', function (event, val) {
if (!$state.index) $state.index = val;
});
updateDataSource();

// changes to state.columns don't require a refresh
var ignore = ['columns'];
// state fields that shouldn't trigger a fetch when changed
var ignoreStateChanges = ['columns'];

// listen for changes, and relisten everytime something happens
$state.onUpdate(function (changed) {
// if we only have ignorable changes, do nothing
if (_.difference(changed, ignore).length) {
updateDataSource();
courier.fetch();
}
if (_.difference(changed, ignoreStateChanges).length) $scope.fetch();
});

$scope.$watch('state.sort', function (sort) {
Expand Down Expand Up @@ -166,18 +158,20 @@ define(function (require) {
});

$scope.opts.saveDataSource = function () {
updateDataSource();
savedSearch.id = savedSearch.title;

savedSearch.save()
.then(function () {
notify.info('Saved Data Source "' + savedSearch.title + '"');
if (savedSearch.id !== $route.current.params.id) {
$location.url('/discover/' + savedSearch.id);
$location.url(globalState.writeToUrl('/discover/' + savedSearch.id));
}
}, notify.error);
};

$scope.fetch = function () {
updateDataSource();
$state.commit();
courier.fetch();
};
Expand Down Expand Up @@ -241,19 +235,22 @@ define(function (require) {

if (!!$scope.opts.timefield) {
timefilter.enabled(true);

chartOptions = interval.calculate(timefilter.time.from, timefilter.time.to, 100);
var bounds = timefilter.getBounds();

searchSource
.aggs({
events: {
date_histogram: {
field: $scope.opts.timefield,
interval: chartOptions.interval + 'ms',
format: chartOptions.format,
min_doc_count: 0,

field: $scope.opts.timefield,
extended_bounds: {
min: datemath.parse(timefilter.time.from).valueOf(),
max: datemath.parse(timefilter.time.to, true).valueOf()
min: bounds.min,
max: bounds.max
}
}
}
Expand Down Expand Up @@ -362,7 +359,7 @@ define(function (require) {
return;
}

$state.commit();
$scope.fetch();
}

// TODO: Move to utility class
Expand Down
2 changes: 1 addition & 1 deletion src/kibana/apps/visualize/controllers/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ define(function (require) {
var writeStateAndFetch = function () {
updateDataSource();
_.assign($state, vis.getState());
var changes = $state.commit();
$state.commit();
vis.searchSource.fetch();
};

Expand Down
139 changes: 139 additions & 0 deletions src/kibana/components/state_management/_state_sync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
define(function (require) {

var angular = require('angular');
var _ = require('lodash');

// invokable/private angular dep
return function ($location) {
// feed in some of the private state from globalState
return function (globalState, updateListeners, app) {
var getAppStash = function (search) {
var appStash = search._a && rison.decode(search._a);
if (app.current) {
appStash = _.defaults(appStash || {}, app.defaults);
}
return appStash;
};

var diffTrans = function (trans) {
var obj = trans[0];
var update = trans[1];

var diff = {};

// the keys that are currently set on obj, excluding methods
var objKeys = Object.keys(obj).filter(function (key) {
return typeof obj[key] !== 'function';
});

if (update) {
// the keys obj should have after applying the update
var updateKeys = diff.keys = Object.keys(update).filter(function (key) {
return typeof update[key] !== 'function';
});

// the keys that will be removed
diff.remove = _.difference(objKeys, updateKeys);

// list of keys that will be added or changed
diff.change = updateKeys.filter(function (key) {
return !angular.equals(obj[key], update[key]);
});
} else {
diff.keys = objKeys.slice(0);
diff.remove = [];
diff.change = [];
}

// single list of all keys that are effected
diff.all = [].concat(diff.remove, diff.change);

return diff;
};

var notify = function (trans, diff) {
var listeners = null;

if (trans[0] === app.current) {
listeners = app.listeners;
} else if (trans[0] === globalState) {
listeners = updateListeners;
}

listeners && listeners.splice(0).forEach(function (defer) {
defer.resolve(diff.all.slice(0));
});
};

var applyDiff = function (trans, diff) {
if (!diff.all.length) return;

var obj = trans[0];
var update = trans[1];

diff.remove.forEach(function (key) {
delete obj[key];
});

diff.change.forEach(function (key) {
obj[key] = update[key];
});
};

var syncTrans = function (trans, forceNotify) {
// obj that will be modified by update(trans[1])
// if it is empty, we can skip it all
var skipWrite = !trans[0];
trans[0] = trans[0] || {};

var diff = diffTrans(trans);
if (!skipWrite && (forceNotify || diff.all.length)) {
applyDiff(trans, diff);
notify(trans, diff);
}
return diff;
};

return {
// sync by pushing to the url
push: function (forceNotify) {
var search = $location.search();

var appStash = getAppStash(search) || {};
var globalStash = search._g ? rison.decode(search._g) : {};

var res = _.mapValues({
app: [appStash, app.current],
global: [globalStash, globalState]
}, function (trans, key) {
var diff = syncTrans(trans, forceNotify);
var urlKey = '_' + key.charAt(0);
if (diff.keys.length === 0) {
delete search[urlKey];
} else {
search[urlKey] = rison.encode(trans[0]);
}
return diff;
});

$location.search(search);
return res;
},
// sync by pulling from the url
pull: function (forceNotify) {
var search = $location.search();

var appStash = getAppStash(search);
var globalStash = search._g && rison.decode(search._g);

return _.mapValues({
app: [app.current, appStash],
global: [globalState, globalStash]
}, function (trans) {
return syncTrans(trans, forceNotify);
});
}
};
};
};
});
3 changes: 1 addition & 2 deletions src/kibana/components/state_management/app_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ define(function (require) {
module.factory('AppState', function (globalState, $route, $location, Promise) {

function AppState(defaults) {
_.assign(this, defaults);
globalState._setApp(this);
globalState._setApp(this, defaults);

this.onUpdate = function (handler) {
return globalState.onAppUpdate(handler);
Expand Down
Loading

0 comments on commit f7ccc62

Please sign in to comment.