diff --git a/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.html b/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.html
new file mode 100644
index 000000000..49b1889f3
--- /dev/null
+++ b/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.html
@@ -0,0 +1,83 @@
+
diff --git a/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.js b/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.js
new file mode 100644
index 000000000..008b7fe81
--- /dev/null
+++ b/public/kibana-integrations/kbn-global-timepicker/kbn_global_timepicker.js
@@ -0,0 +1,81 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you 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.
+ */
+
+import { uiModules } from 'ui/modules';
+import { once, clone } from 'lodash';
+
+import toggleHtml from './kbn_global_timepicker.html';
+import { timeNavigation } from './time_navigation';
+
+uiModules
+ .get('kibana')
+ .directive('wzKbnGlobalTimepicker', (timefilter, globalState, $rootScope) => {
+ const listenForUpdates = once($scope => {
+ $scope.$listen(timefilter, 'update', () => {
+ globalState.time = clone(timefilter.time);
+ globalState.refreshInterval = clone(timefilter.refreshInterval);
+ globalState.save();
+ });
+ });
+
+ return {
+ template: toggleHtml,
+ replace: true,
+ require: '^wzKbnTopNav',
+ link: ($scope, element, attributes, wzKbnTopNav) => {
+ listenForUpdates($rootScope);
+
+ $rootScope.timefilter = timefilter;
+ $rootScope.toggleRefresh = () => {
+ timefilter.refreshInterval.pause = !timefilter.refreshInterval.pause;
+ };
+
+ $scope.forward = function () {
+ timefilter.time = timeNavigation.stepForward(timefilter.getBounds());
+ };
+
+ $scope.back = function () {
+ timefilter.time = timeNavigation.stepBackward(timefilter.getBounds());
+ };
+
+ $scope.updateFilter = function (from, to) {
+ timefilter.time.from = from;
+ timefilter.time.to = to;
+ wzKbnTopNav.close('filter');
+ };
+
+ $scope.updateInterval = function (interval) {
+ timefilter.refreshInterval = interval;
+ wzKbnTopNav.close('interval');
+ };
+
+ $scope.getSharedTimeFilterFromDate = function () {
+ return (timefilter.isAutoRefreshSelectorEnabled || timefilter.isTimeRangeSelectorEnabled)
+ ? timefilter.getBounds().min.clone().utc().format()
+ : null;
+ };
+
+ $scope.getSharedTimeFilterToDate = function () {
+ return (timefilter.isAutoRefreshSelectorEnabled || timefilter.isTimeRangeSelectorEnabled)
+ ? timefilter.getBounds().max.clone().utc().format()
+ : null;
+ };
+ },
+ };
+ });
\ No newline at end of file
diff --git a/public/kibana-integrations/kbn-global-timepicker/time_navigation.js b/public/kibana-integrations/kbn-global-timepicker/time_navigation.js
new file mode 100644
index 000000000..54b0f9fb9
--- /dev/null
+++ b/public/kibana-integrations/kbn-global-timepicker/time_navigation.js
@@ -0,0 +1,62 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you 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.
+ */
+
+import moment from 'moment';
+
+export const timeNavigation = {
+ // travel forward in time based on the interval between from and to
+ stepForward({ min, max }) {
+ const diff = max.diff(min);
+ return {
+ from: moment(max).add(1, 'ms').toISOString(),
+ to: moment(max).add(diff + 1, 'ms').toISOString(),
+ mode: 'absolute'
+ };
+ },
+
+ // travel backwards in time based on the interval between from and to
+ stepBackward({ min, max }) {
+ const diff = max.diff(min);
+ return {
+ from: moment(min).subtract(diff + 1, 'ms').toISOString(),
+ to: moment(min).subtract(1, 'ms').toISOString(),
+ mode: 'absolute'
+ };
+ },
+
+ // zoom out, doubling the difference between start and end, keeping the same time range center
+ zoomOut({ min, max }) {
+ const diff = max.diff(min);
+ return {
+ from: moment(min).subtract(diff / 2, 'ms').toISOString(),
+ to: moment(max).add(diff / 2, 'ms').toISOString(),
+ mode: 'absolute'
+ };
+ },
+
+ // zoom in, halving the difference between start and end, keeping the same time range center
+ zoomIn({ min, max }) {
+ const diff = max.diff(min);
+ return {
+ from: moment(min).add(diff / 4, 'ms').toISOString(),
+ to: moment(max).subtract(diff / 4, 'ms').toISOString(),
+ mode: 'absolute'
+ };
+ }
+};