"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useTimeSlider = exports.TimeSliderControlEmbeddable = exports.TimeSliderControlContext = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _lodash = _interopRequireDefault(require("lodash")); var _operators = require("rxjs/operators"); var _momentTimezone = _interopRequireDefault(require("moment-timezone")); var _public = require("@kbn/embeddable-plugin/public"); var _public2 = require("@kbn/kibana-react-plugin/public"); var _react = _interopRequireWildcard(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _2 = require("../.."); var _services = require("../../services"); var _components = require("../components"); var _time_slider_reducers = require("../time_slider_reducers"); var _time_utils = require("../time_utils"); var _time_slider_selectors = require("../time_slider_selectors"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ const TimeSliderControlContext = /*#__PURE__*/(0, _react.createContext)(null); exports.TimeSliderControlContext = TimeSliderControlContext; const useTimeSlider = () => { const timeSlider = (0, _react.useContext)(TimeSliderControlContext); if (timeSlider == null) { throw new Error('useTimeSlider must be used inside TimeSliderControlContext.'); } return timeSlider; }; exports.useTimeSlider = useTimeSlider; class TimeSliderControlEmbeddable extends _public.Embeddable { // state management constructor(reduxToolsPackage, input, output, parent) { super(input, output, parent); (0, _defineProperty2.default)(this, "type", _2.TIME_SLIDER_CONTROL); (0, _defineProperty2.default)(this, "deferEmbeddedLoad", true); (0, _defineProperty2.default)(this, "inputSubscription", void 0); (0, _defineProperty2.default)(this, "node", void 0); (0, _defineProperty2.default)(this, "select", void 0); (0, _defineProperty2.default)(this, "getState", void 0); (0, _defineProperty2.default)(this, "dispatch", void 0); (0, _defineProperty2.default)(this, "onStateChange", void 0); (0, _defineProperty2.default)(this, "cleanupStateTools", void 0); (0, _defineProperty2.default)(this, "getTimezone", void 0); (0, _defineProperty2.default)(this, "timefilter", void 0); (0, _defineProperty2.default)(this, "prevTimeRange", void 0); (0, _defineProperty2.default)(this, "prevTimesliceAsPercentage", void 0); (0, _defineProperty2.default)(this, "waitForControlOutputConsumersToLoad$", void 0); (0, _defineProperty2.default)(this, "destroy", () => { super.destroy(); this.cleanupStateTools(); if (this.inputSubscription) { this.inputSubscription.unsubscribe(); } }); (0, _defineProperty2.default)(this, "debouncedPublishChange", _lodash.default.debounce(value => { this.dispatch.publishValue({ value }); }, 500)); (0, _defineProperty2.default)(this, "onTimesliceChange", value => { const { timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange } = this.getTimeSliceAsPercentageOfTimeRange(value); this.dispatch.setValueAsPercentageOfTimeRange({ timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange }); this.dispatch.setValue({ value }); this.debouncedPublishChange(value); }); (0, _defineProperty2.default)(this, "onRangeChange", range => { const timeRangeBounds = this.getState().componentState.timeRangeBounds; const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]; this.dispatch.setRange({ range: range !== undefined && range < timeRange ? range : undefined }); }); (0, _defineProperty2.default)(this, "onNext", () => { const { value, range, ticks } = this.getState().componentState; const isAnchored = (0, _time_slider_selectors.getIsAnchored)(this.getState()); const tickRange = ticks[1].value - ticks[0].value; const timeRangeBounds = (0, _time_slider_selectors.getRoundedTimeRangeBounds)(this.getState()); if (isAnchored) { if (value === undefined || value[_time_utils.TO_INDEX] >= timeRangeBounds[_time_utils.TO_INDEX]) { this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], ticks[0].value]); return; } const nextTick = ticks.find(tick => { return tick.value > value[_time_utils.TO_INDEX]; }); this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], nextTick ? nextTick.value : timeRangeBounds[_time_utils.TO_INDEX]]); return; } if (value === undefined || value[_time_utils.TO_INDEX] >= timeRangeBounds[_time_utils.TO_INDEX]) { const from = timeRangeBounds[_time_utils.FROM_INDEX]; if (range === undefined || range === tickRange) { const firstTickValue = ticks[0].value; const secondTickValue = ticks[1].value; const to = firstTickValue === from ? secondTickValue : firstTickValue; this.onTimesliceChange([from, to]); this.onRangeChange(tickRange); } else { const to = from + range; this.onTimesliceChange([from, Math.min(to, timeRangeBounds[_time_utils.TO_INDEX])]); } return; } const from = value[_time_utils.TO_INDEX]; const safeRange = range === undefined ? tickRange : range; const to = from + safeRange; this.onTimesliceChange([from, Math.min(to, timeRangeBounds[_time_utils.TO_INDEX])]); }); (0, _defineProperty2.default)(this, "onPrevious", () => { const { value, range, ticks } = this.getState().componentState; const isAnchored = (0, _time_slider_selectors.getIsAnchored)(this.getState()); const tickRange = ticks[1].value - ticks[0].value; const timeRangeBounds = (0, _time_slider_selectors.getRoundedTimeRangeBounds)(this.getState()); if (isAnchored) { const prevTick = value ? [...ticks].reverse().find(tick => { return tick.value < value[_time_utils.TO_INDEX]; }) : ticks[ticks.length - 1]; this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], prevTick ? prevTick.value : timeRangeBounds[_time_utils.TO_INDEX]]); return; } if (value === undefined || value[_time_utils.FROM_INDEX] <= timeRangeBounds[_time_utils.FROM_INDEX]) { const to = timeRangeBounds[_time_utils.TO_INDEX]; if (range === undefined || range === tickRange) { const lastTickValue = ticks[ticks.length - 1].value; const secondToLastTickValue = ticks[ticks.length - 2].value; const from = lastTickValue === to ? secondToLastTickValue : lastTickValue; this.onTimesliceChange([from, to]); this.onRangeChange(tickRange); } else { const from = to - range; this.onTimesliceChange([Math.max(from, timeRangeBounds[_time_utils.FROM_INDEX]), to]); } return; } const to = value[_time_utils.FROM_INDEX]; const safeRange = range === undefined ? tickRange : range; const from = to - safeRange; this.onTimesliceChange([Math.max(from, timeRangeBounds[_time_utils.FROM_INDEX]), to]); }); (0, _defineProperty2.default)(this, "formatDate", epoch => { return _momentTimezone.default.tz(epoch, (0, _time_utils.getMomentTimezone)(this.getTimezone())).format(this.getState().componentState.format); }); (0, _defineProperty2.default)(this, "render", node => { if (this.node) { _reactDom.default.unmountComponentAtNode(this.node); } this.node = node; _reactDom.default.render( /*#__PURE__*/_react.default.createElement(_public2.KibanaThemeProvider, { theme$: _services.pluginServices.getServices().theme.theme$ }, /*#__PURE__*/_react.default.createElement(TimeSliderControlContext.Provider, { value: this }, /*#__PURE__*/_react.default.createElement(_components.TimeSlider, { formatDate: this.formatDate, onChange: value => { this.onTimesliceChange(value); const range = value ? value[_time_utils.TO_INDEX] - value[_time_utils.FROM_INDEX] : undefined; this.onRangeChange(range); } }))), node); }); const { data: { timefilter }, settings: { getDefaultTimeRange, getTimezone } } = _services.pluginServices.getServices(); this.getTimezone = getTimezone; this.timefilter = timefilter; const _timeRangeBounds = this.timeRangeToBounds(input.timeRange ? input.timeRange : getDefaultTimeRange()); const _ticks = (0, _time_utils.getTicks)(_timeRangeBounds[_time_utils.FROM_INDEX], _timeRangeBounds[_time_utils.TO_INDEX], this.getTimezone()); const reduxEmbeddableTools = reduxToolsPackage.createReduxEmbeddableTools({ embeddable: this, reducers: _time_slider_reducers.timeSliderReducers, initialComponentState: { isOpen: false, ...(0, _time_utils.getStepSize)(_ticks), ticks: _ticks, timeRangeBounds: _timeRangeBounds } }); this.select = reduxEmbeddableTools.select; this.getState = reduxEmbeddableTools.getState; this.dispatch = reduxEmbeddableTools.dispatch; this.onStateChange = reduxEmbeddableTools.onStateChange; this.cleanupStateTools = reduxEmbeddableTools.cleanup; this.inputSubscription = this.getInput$().subscribe(() => this.onInputChange()); this.waitForControlOutputConsumersToLoad$ = parent && 'anyControlOutputConsumerLoading$' in parent ? parent.anyControlOutputConsumerLoading$.pipe((0, _operators.debounceTime)(300), (0, _operators.first)(isAnyControlOutputConsumerLoading => { return !isAnyControlOutputConsumerLoading; }), (0, _operators.map)(() => { // Observable notifies subscriber when loading is finished // Return void to not expose internal implemenation details of observabale return; })) : undefined; this.prevTimesliceAsPercentage = { timesliceStartAsPercentageOfTimeRange: this.getInput().timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange: this.getInput().timesliceEndAsPercentageOfTimeRange }; this.syncWithTimeRange(); } onInputChange() { var _this$prevTimesliceAs; const input = this.getInput(); const { timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange } = (_this$prevTimesliceAs = this.prevTimesliceAsPercentage) !== null && _this$prevTimesliceAs !== void 0 ? _this$prevTimesliceAs : {}; if (timesliceStartAsPercentageOfTimeRange !== input.timesliceStartAsPercentageOfTimeRange || timesliceEndAsPercentageOfTimeRange !== input.timesliceEndAsPercentageOfTimeRange) { // Discarding edit mode changes results in replacing edited input with original input // Re-sync with time range when edited input timeslice changes are discarded if (!input.timesliceStartAsPercentageOfTimeRange && !input.timesliceEndAsPercentageOfTimeRange) { // If no selections have been saved into the timeslider, then both `timesliceStartAsPercentageOfTimeRange` // and `timesliceEndAsPercentageOfTimeRange` will be undefined - so, need to reset component state to match this.dispatch.publishValue({ value: undefined }); this.dispatch.setValue({ value: undefined }); } else { // Otherwise, need to call `syncWithTimeRange` so that the component state value can be calculated and set this.syncWithTimeRange(); } } else if (input.timeRange && !_lodash.default.isEqual(input.timeRange, this.prevTimeRange)) { const nextBounds = this.timeRangeToBounds(input.timeRange); const ticks = (0, _time_utils.getTicks)(nextBounds[_time_utils.FROM_INDEX], nextBounds[_time_utils.TO_INDEX], this.getTimezone()); this.dispatch.setTimeRangeBounds({ ...(0, _time_utils.getStepSize)(ticks), ticks, timeRangeBounds: nextBounds }); this.syncWithTimeRange(); } } syncWithTimeRange() { this.prevTimeRange = this.getInput().timeRange; const stepSize = this.getState().componentState.stepSize; const { timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange } = this.getState().explicitInput; if (timesliceStartAsPercentageOfTimeRange !== undefined && timesliceEndAsPercentageOfTimeRange !== undefined) { const timeRangeBounds = this.getState().componentState.timeRangeBounds; const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]; const from = timeRangeBounds[_time_utils.FROM_INDEX] + timesliceStartAsPercentageOfTimeRange * timeRange; const to = timeRangeBounds[_time_utils.FROM_INDEX] + timesliceEndAsPercentageOfTimeRange * timeRange; const value = [(0, _time_utils.roundDownToNextStepSizeFactor)(from, stepSize), (0, _time_utils.roundUpToNextStepSizeFactor)(to, stepSize)]; this.dispatch.publishValue({ value }); this.dispatch.setValue({ value }); this.onRangeChange(value[_time_utils.TO_INDEX] - value[_time_utils.FROM_INDEX]); } } timeRangeToBounds(timeRange) { const timeRangeBounds = this.timefilter.calculateBounds(timeRange); return timeRangeBounds.min === undefined || timeRangeBounds.max === undefined ? [Date.now() - 1000 * 60 * 15, Date.now()] : [timeRangeBounds.min.valueOf(), timeRangeBounds.max.valueOf()]; } reload() { return; } getTimeSliceAsPercentageOfTimeRange(value) { let timesliceStartAsPercentageOfTimeRange; let timesliceEndAsPercentageOfTimeRange; if (value) { const timeRangeBounds = this.getState().componentState.timeRangeBounds; const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]; timesliceStartAsPercentageOfTimeRange = (value[_time_utils.FROM_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]) / timeRange; timesliceEndAsPercentageOfTimeRange = (value[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]) / timeRange; } this.prevTimesliceAsPercentage = { timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange }; return { timesliceStartAsPercentageOfTimeRange, timesliceEndAsPercentageOfTimeRange }; } clearSelections() { this.onTimesliceChange(); } renderPrepend() { return /*#__PURE__*/_react.default.createElement(TimeSliderControlContext.Provider, { value: this }, /*#__PURE__*/_react.default.createElement(_components.TimeSliderPrepend, { onNext: this.onNext, onPrevious: this.onPrevious, waitForControlOutputConsumersToLoad$: this.waitForControlOutputConsumersToLoad$ })); } isChained() { return false; } } exports.TimeSliderControlEmbeddable = TimeSliderControlEmbeddable;