"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.tableHasFocus = exports.showGlobalFilters = exports.resolverIsShowing = exports.resetKeyboardFocus = exports.onTimelineTabKeyPressed = exports.isPrimitiveArray = exports.handleIsOperator = exports.focusUtilityBarAction = exports.focusActiveTimelineButton = exports.calculateTotalPages = exports.buildIsQueryMatch = exports.buildIsOneOfQueryMatch = exports.buildGlobalQuery = exports.buildExistsQueryMatch = exports.STATEFUL_EVENT_CSS_CLASS_NAME = exports.FLYOUT_BUTTON_BAR_CLASS_NAME = exports.EVENTS_COUNT_BUTTON_CLASS_NAME = exports.ARIA_COLUMN_INDEX_OFFSET = exports.ACTIVE_TIMELINE_BUTTON_CLASS_NAME = exports.ACTIONS_COLUMN_ARIA_COL_INDEX = void 0; var _fp = require("lodash/fp"); var _public = require("@kbn/timelines-plugin/public"); var _kql = require("../../../../common/utils/kql"); var _utility_types = require("../../../../common/utility_types"); var _kuery = require("../../../common/lib/kuery"); var _data_provider = require("./data_providers/data_provider"); var _styles = require("./styles"); /* * 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; you may not use this file except in compliance with the Elastic License * 2.0. */ const buildQueryMatch = (dataProvider, browserFields) => { const { excluded, type, queryMatch: { field, operator, value } } = dataProvider; const isFieldTypeNested = (0, _kuery.checkIfFieldTypeIsNested)(field, browserFields); const isExcluded = excluded ? 'NOT ' : ''; switch (operator) { case _data_provider.IS_OPERATOR: return handleIsOperator({ browserFields, field, isExcluded, isFieldTypeNested, type, value }); case _data_provider.EXISTS_OPERATOR: return `${isExcluded}${buildExistsQueryMatch({ browserFields, field, isFieldTypeNested })}`; case _data_provider.IS_ONE_OF_OPERATOR: return handleIsOneOfOperator({ field, isExcluded, value }); default: (0, _utility_types.assertUnreachable)(operator); } }; const buildGlobalQuery = (dataProviders, browserFields) => dataProviders.reduce((queries, dataProvider) => { const flatDataProviders = [dataProvider, ...dataProvider.and]; const activeDataProviders = flatDataProviders.filter(flatDataProvider => flatDataProvider.enabled); if (!activeDataProviders.length) return queries; const activeDataProvidersQueries = activeDataProviders.map(activeDataProvider => buildQueryMatch(activeDataProvider, browserFields)); const activeDataProvidersQueryMatch = activeDataProvidersQueries.join(' and '); return [...queries, activeDataProvidersQueryMatch]; }, []).filter(queriesItem => !(0, _fp.isEmpty)(queriesItem)).reduce((globalQuery, queryMatch, index, queries) => { if (queries.length <= 1) return queryMatch; return !index ? `(${queryMatch})` : `${globalQuery} or (${queryMatch})`; }, ''); /** * The CSS class name of a "stateful event", which appears in both * the `Timeline` and the `Events Viewer` widget */ exports.buildGlobalQuery = buildGlobalQuery; const STATEFUL_EVENT_CSS_CLASS_NAME = 'event-column-view'; exports.STATEFUL_EVENT_CSS_CLASS_NAME = STATEFUL_EVENT_CSS_CLASS_NAME; const resolverIsShowing = graphEventId => graphEventId != null && graphEventId !== ''; exports.resolverIsShowing = resolverIsShowing; const showGlobalFilters = ({ globalFullScreen, graphEventId }) => globalFullScreen && resolverIsShowing(graphEventId) ? false : true; /** * The `aria-colindex` of the Timeline actions column */ exports.showGlobalFilters = showGlobalFilters; const ACTIONS_COLUMN_ARIA_COL_INDEX = '1'; /** * Every column index offset by `2`, because, per https://www.w3.org/TR/wai-aria-practices-1.1/examples/grid/dataGrids.html * the `aria-colindex` attribute starts at `1`, and the "actions column" is always the first column */ exports.ACTIONS_COLUMN_ARIA_COL_INDEX = ACTIONS_COLUMN_ARIA_COL_INDEX; const ARIA_COLUMN_INDEX_OFFSET = 2; exports.ARIA_COLUMN_INDEX_OFFSET = ARIA_COLUMN_INDEX_OFFSET; const EVENTS_COUNT_BUTTON_CLASS_NAME = 'local-events-count-button'; /** Calculates the total number of pages in a (timeline) events view */ exports.EVENTS_COUNT_BUTTON_CLASS_NAME = EVENTS_COUNT_BUTTON_CLASS_NAME; const calculateTotalPages = ({ itemsCount, itemsPerPage }) => itemsCount === 0 || itemsPerPage === 0 ? 0 : Math.ceil(itemsCount / itemsPerPage); /** Returns true if the events table has focus */ exports.calculateTotalPages = calculateTotalPages; const tableHasFocus = containerElement => (0, _public.elementOrChildrenHasFocus)(containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelector(`.${_styles.EVENTS_TABLE_CLASS_NAME}`)); /** * This function has a side effect. It will skip focus "after" or "before" * Timeline's events table, with exceptions as noted below. * * If the currently-focused table cell has additional focusable children, * i.e. action buttons, draggables, or always-open popover content, the * browser's "natural" focus management will determine which element is * focused next. */ exports.tableHasFocus = tableHasFocus; const onTimelineTabKeyPressed = ({ containerElement, keyboardEvent, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable }) => { const { shiftKey } = keyboardEvent; const eventsTableSkipFocus = (0, _public.getTableSkipFocus)({ containerElement, getFocusedCell: _public.getFocusedAriaColindexCell, shiftKey, tableHasFocus, tableClassName: _styles.EVENTS_TABLE_CLASS_NAME }); if (eventsTableSkipFocus !== 'SKIP_FOCUS_NOOP') { (0, _public.stopPropagationAndPreventDefault)(keyboardEvent); (0, _public.handleSkipFocus)({ onSkipFocusBackwards: onSkipFocusBeforeEventsTable, onSkipFocusForward: onSkipFocusAfterEventsTable, skipFocus: eventsTableSkipFocus }); } }; exports.onTimelineTabKeyPressed = onTimelineTabKeyPressed; const ACTIVE_TIMELINE_BUTTON_CLASS_NAME = 'active-timeline-button'; exports.ACTIVE_TIMELINE_BUTTON_CLASS_NAME = ACTIVE_TIMELINE_BUTTON_CLASS_NAME; const FLYOUT_BUTTON_BAR_CLASS_NAME = 'timeline-flyout-button-bar'; /** * This function focuses the active timeline button on the next tick. Focus * is updated on the next tick because this function is typically * invoked in `onClick` handlers that also dispatch Redux actions (that * in-turn update focus states). */ exports.FLYOUT_BUTTON_BAR_CLASS_NAME = FLYOUT_BUTTON_BAR_CLASS_NAME; const focusActiveTimelineButton = () => { setTimeout(() => { var _document$querySelect; (_document$querySelect = document.querySelector(`div.${FLYOUT_BUTTON_BAR_CLASS_NAME} .${ACTIVE_TIMELINE_BUTTON_CLASS_NAME}`)) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.focus(); }, 0); }; /** * Focuses the utility bar action contained by the provided `containerElement` * when a valid container is provided */ exports.focusActiveTimelineButton = focusActiveTimelineButton; const focusUtilityBarAction = containerElement => { var _containerElement$que; containerElement === null || containerElement === void 0 ? void 0 : (_containerElement$que = containerElement.querySelector('div.siemUtilityBar__action:last-of-type button')) === null || _containerElement$que === void 0 ? void 0 : _containerElement$que.focus(); }; /** * Resets keyboard focus on the page */ exports.focusUtilityBarAction = focusUtilityBarAction; const resetKeyboardFocus = () => { var _document$querySelect2; (_document$querySelect2 = document.querySelector('header.headerGlobalNav a.chrHeaderLogo')) === null || _document$querySelect2 === void 0 ? void 0 : _document$querySelect2.focus(); }; exports.resetKeyboardFocus = resetKeyboardFocus; const handleIsOperator = ({ browserFields, field, isExcluded, isFieldTypeNested, type, value }) => { if (!isPrimitiveArray(value)) { return `${isExcluded}${type !== _data_provider.DataProviderType.template ? buildIsQueryMatch({ browserFields, field, isFieldTypeNested, value }) : buildExistsQueryMatch({ browserFields, field, isFieldTypeNested })}`; } else { return `${isExcluded}${field} : ${JSON.stringify(value)}`; } }; exports.handleIsOperator = handleIsOperator; const handleIsOneOfOperator = ({ field, isExcluded, value }) => { if (isPrimitiveArray(value)) { return `${isExcluded}${buildIsOneOfQueryMatch({ field, value })}`; } else { return `${isExcluded}${field} : ${JSON.stringify(value)}`; } }; const buildIsQueryMatch = ({ browserFields, field, isFieldTypeNested, value }) => { if (isFieldTypeNested) { return (0, _kuery.convertNestedFieldToQuery)(field, value, browserFields); } else if ((0, _kuery.checkIfFieldTypeIsDate)(field, browserFields)) { return (0, _kuery.convertDateFieldToQuery)(field, value); } else { return `${field} : ${(0, _kql.prepareKQLParam)(value)}`; } }; exports.buildIsQueryMatch = buildIsQueryMatch; const buildExistsQueryMatch = ({ browserFields, field, isFieldTypeNested }) => { return isFieldTypeNested ? (0, _kuery.convertNestedFieldToExistQuery)(field, browserFields).trim() : `${field} ${_data_provider.EXISTS_OPERATOR}`.trim(); }; exports.buildExistsQueryMatch = buildExistsQueryMatch; const buildIsOneOfQueryMatch = ({ field, value }) => { const trimmedField = field.trim(); if (value.length) { return `${trimmedField} : (${value.map(item => (0, _fp.isNumber)(item) ? item : (0, _kql.prepareKQLStringParam)(String(item).trim())).join(' OR ')})`; } return `${trimmedField} : ''`; }; exports.buildIsOneOfQueryMatch = buildIsOneOfQueryMatch; const isPrimitiveArray = value => Array.isArray(value) && (value.every(x => typeof x === 'string') || value.every(x => typeof x === 'number')); exports.isPrimitiveArray = isPrimitiveArray;