mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.6`: - [[Osquery] - Enable resizing of Osquery query editor (#145231)](https://github.com/elastic/kibana/pull/145231) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Tomasz Ciecierski","email":"tomasz.ciecierski@elastic.co"},"sourceCommit":{"committedDate":"2022-11-28T13:01:28Z","message":"[Osquery] - Enable resizing of Osquery query editor (#145231)","sha":"b300aa55fb421a3b0c98d24faa1895f28ccd67f2","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","Team:Asset Management","Feature:Osquery","v8.6.0","v8.7.0"],"number":145231,"url":"https://github.com/elastic/kibana/pull/145231","mergeCommit":{"message":"[Osquery] - Enable resizing of Osquery query editor (#145231)","sha":"b300aa55fb421a3b0c98d24faa1895f28ccd67f2"}},"sourceBranch":"main","suggestedTargetBranches":["8.6"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/145231","number":145231,"mergeCommit":{"message":"[Osquery] - Enable resizing of Osquery query editor (#145231)","sha":"b300aa55fb421a3b0c98d24faa1895f28ccd67f2"}}]}] BACKPORT--> Co-authored-by: Tomasz Ciecierski <tomasz.ciecierski@elastic.co>
This commit is contained in:
parent
e1a755107c
commit
12f1b6179c
11 changed files with 202 additions and 48 deletions
|
@ -20,6 +20,7 @@ import {
|
|||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { removeMultilines } from '../../common/utils/build_query/remove_multilines';
|
||||
import { useAllLiveQueries } from './use_all_live_queries';
|
||||
import type { SearchHit } from '../../common/search_strategy';
|
||||
import { Direction } from '../../common/search_strategy';
|
||||
|
@ -90,9 +91,13 @@ const ActionsTableComponent = () => {
|
|||
);
|
||||
}
|
||||
|
||||
const query = item._source.queries[0].query;
|
||||
const singleLine = removeMultilines(query);
|
||||
const content = singleLine.length > 90 ? `${singleLine?.substring(0, 90)}...` : singleLine;
|
||||
|
||||
return (
|
||||
<EuiCodeBlock language="sql" fontSize="s" paddingSize="none" transparentBackground>
|
||||
{item._source.queries[0].query}
|
||||
{content}
|
||||
</EuiCodeBlock>
|
||||
);
|
||||
}, []);
|
||||
|
@ -196,6 +201,7 @@ const ActionsTableComponent = () => {
|
|||
defaultMessage: 'Query',
|
||||
}),
|
||||
truncateText: true,
|
||||
width: '60%',
|
||||
render: renderQueryColumn,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ export const WithHeaderLayout: React.FC<WithHeaderLayoutProps> = ({
|
|||
>
|
||||
<EuiPageBody>
|
||||
<ContentWrapper>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiSpacer size="l" />
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
</EuiPageBody>
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useCallback, useRef } from 'react';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import styled from 'styled-components';
|
||||
import { EuiResizeObserver } from '@elastic/eui';
|
||||
|
||||
import type { EuiCodeEditorProps } from '../shared_imports';
|
||||
import { EuiCodeEditor } from '../shared_imports';
|
||||
|
@ -29,30 +31,76 @@ interface OsqueryEditorProps {
|
|||
commands?: EuiCodeEditorProps['commands'];
|
||||
}
|
||||
|
||||
const ResizeWrapper = styled.div`
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
`;
|
||||
|
||||
const MIN_HEIGHT = 100;
|
||||
const OsqueryEditorComponent: React.FC<OsqueryEditorProps> = ({
|
||||
defaultValue,
|
||||
onChange,
|
||||
commands,
|
||||
}) => {
|
||||
const [editorValue, setEditorValue] = useState(defaultValue ?? '');
|
||||
const [height, setHeight] = useState(MIN_HEIGHT);
|
||||
const editorRef = useRef<{ renderer: { layerConfig: { maxHeight: number; minHeight: number } } }>(
|
||||
{
|
||||
renderer: { layerConfig: { maxHeight: 100, minHeight: 100 } },
|
||||
}
|
||||
);
|
||||
|
||||
useDebounce(() => onChange(editorValue), 500, [editorValue]);
|
||||
useDebounce(
|
||||
() => {
|
||||
onChange(editorValue);
|
||||
const config = editorRef.current?.renderer.layerConfig;
|
||||
|
||||
if (config.maxHeight > config.minHeight) {
|
||||
setHeight(config.maxHeight);
|
||||
}
|
||||
},
|
||||
500,
|
||||
[editorValue]
|
||||
);
|
||||
|
||||
useEffect(() => setEditorValue(defaultValue), [defaultValue]);
|
||||
|
||||
const resizeEditor = useCallback((editorInstance) => {
|
||||
editorRef.current.renderer = editorInstance.renderer;
|
||||
|
||||
setTimeout(() => {
|
||||
const { maxHeight } = editorInstance.renderer.layerConfig;
|
||||
if (maxHeight > MIN_HEIGHT) {
|
||||
setHeight(maxHeight);
|
||||
}
|
||||
}, 0);
|
||||
}, []);
|
||||
|
||||
const onResize = useCallback((dimensions) => {
|
||||
setHeight(dimensions.height);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<EuiCodeEditor
|
||||
value={editorValue}
|
||||
mode="osquery"
|
||||
onChange={setEditorValue}
|
||||
theme="tomorrow"
|
||||
name="osquery_editor"
|
||||
setOptions={EDITOR_SET_OPTIONS}
|
||||
editorProps={EDITOR_PROPS}
|
||||
height="100px"
|
||||
width="100%"
|
||||
commands={commands}
|
||||
/>
|
||||
<EuiResizeObserver onResize={onResize}>
|
||||
{(resizeRef) => (
|
||||
<ResizeWrapper ref={resizeRef}>
|
||||
<EuiCodeEditor
|
||||
value={editorValue}
|
||||
mode="osquery"
|
||||
onChange={setEditorValue}
|
||||
theme="tomorrow"
|
||||
name="osquery_editor"
|
||||
setOptions={EDITOR_SET_OPTIONS}
|
||||
editorProps={EDITOR_PROPS}
|
||||
onLoad={resizeEditor}
|
||||
height={height + 'px'}
|
||||
width="100%"
|
||||
commands={commands}
|
||||
/>
|
||||
</ResizeWrapper>
|
||||
)}
|
||||
</EuiResizeObserver>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -286,10 +286,12 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
|
|||
}
|
||||
}, [queryType, cleanupLiveQuery, resetField, setValue, clearErrors, defaultValue]);
|
||||
|
||||
const groupStyles = useMemo(() => ({ gap: 16 }), []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormProvider {...hooksForm}>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexGroup direction="column" css={groupStyles}>
|
||||
{queryField && (
|
||||
<QueryPackSelectable
|
||||
queryType={queryType}
|
||||
|
|
|
@ -14,7 +14,6 @@ import { useController, useFormContext } from 'react-hook-form';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { OsqueryEditor } from '../../editor';
|
||||
import { useKibana } from '../../common/lib/kibana';
|
||||
import { MAX_QUERY_LENGTH } from '../../packs/queries/validations';
|
||||
import { ECSMappingEditorField } from '../../packs/queries/lazy_ecs_mapping_editor_field';
|
||||
import type { SavedQueriesDropdownProps } from '../../saved_queries/saved_queries_dropdown';
|
||||
import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown';
|
||||
|
@ -57,13 +56,6 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
|
|||
}),
|
||||
value: queryType !== 'pack',
|
||||
},
|
||||
maxLength: {
|
||||
message: i18n.translate('xpack.osquery.liveQuery.queryForm.largeQueryError', {
|
||||
defaultMessage: 'Query is too large (max {maxLength} characters)',
|
||||
values: { maxLength: MAX_QUERY_LENGTH },
|
||||
}),
|
||||
value: MAX_QUERY_LENGTH,
|
||||
},
|
||||
},
|
||||
defaultValue: '',
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
|
||||
import { QueryDetailsFlyout } from './query_details_flyout';
|
||||
import { PackResultsHeader } from './pack_results_header';
|
||||
import { Direction } from '../../../common/search_strategy';
|
||||
import { removeMultilines } from '../../../common/utils/build_query/remove_multilines';
|
||||
|
@ -43,6 +44,10 @@ const TruncateTooltipText = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const StyledEuiFlexItem = styled(EuiFlexItem)`
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const EMPTY_ARRAY: PackQueryStatusItem[] = [];
|
||||
|
||||
// @ts-expect-error TS2769
|
||||
|
@ -51,13 +56,16 @@ const StyledEuiBasicTable = styled(EuiBasicTable)`
|
|||
padding: 0;
|
||||
border: 1px solid #d3dae6;
|
||||
}
|
||||
|
||||
div.euiDataGrid__virtualized::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.euiDataGrid > div {
|
||||
.euiDataGrid__scrollOverlay {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
border-left: 0px;
|
||||
border-right: 0px;
|
||||
}
|
||||
|
@ -143,6 +151,19 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
|
|||
expirationDate,
|
||||
showResultsHeader,
|
||||
}) => {
|
||||
const [queryDetailsFlyoutOpen, setQueryDetailsFlyoutOpen] = useState<{
|
||||
id: string;
|
||||
query: string;
|
||||
} | null>(null);
|
||||
|
||||
const handleQueryFlyoutOpen = useCallback(
|
||||
(item) => () => {
|
||||
setQueryDetailsFlyoutOpen(item);
|
||||
},
|
||||
[]
|
||||
);
|
||||
const handleQueryFlyoutClose = useCallback(() => setQueryDetailsFlyoutOpen(null), []);
|
||||
|
||||
const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<Record<string, unknown>>({});
|
||||
const renderIDColumn = useCallback(
|
||||
(id: string) => (
|
||||
|
@ -155,18 +176,21 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
|
|||
[]
|
||||
);
|
||||
|
||||
const renderQueryColumn = useCallback((query: string, item) => {
|
||||
const singleLine = removeMultilines(query);
|
||||
const content = singleLine.length > 55 ? `${singleLine.substring(0, 55)}...` : singleLine;
|
||||
const renderQueryColumn = useCallback(
|
||||
(query: string, item) => {
|
||||
const singleLine = removeMultilines(query);
|
||||
const content = singleLine.length > 55 ? `${singleLine.substring(0, 55)}...` : singleLine;
|
||||
|
||||
return (
|
||||
<EuiToolTip title={item.id} content={<EuiFlexItem>{query}</EuiFlexItem>}>
|
||||
<EuiCodeBlock language="sql" fontSize="s" paddingSize="none" transparentBackground>
|
||||
{content}
|
||||
</EuiCodeBlock>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}, []);
|
||||
return (
|
||||
<StyledEuiFlexItem onClick={handleQueryFlyoutOpen(item)}>
|
||||
<EuiCodeBlock language="sql" fontSize="s" paddingSize="none" transparentBackground>
|
||||
{content}
|
||||
</EuiCodeBlock>
|
||||
</StyledEuiFlexItem>
|
||||
);
|
||||
},
|
||||
[handleQueryFlyoutOpen]
|
||||
);
|
||||
|
||||
const renderDocsColumn = useCallback(
|
||||
(item: PackQueryStatusItem) => (
|
||||
|
@ -269,11 +293,22 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
|
|||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
render: (item: { action_id: string }) => (
|
||||
<EuiButtonIcon iconType={'expand'} onClick={handleQueryFlyoutOpen(item)} />
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return resultActions.map((action) => action.render(row));
|
||||
},
|
||||
[actionId, agentIds, renderDiscoverResultsAction, renderLensResultsAction]
|
||||
[
|
||||
actionId,
|
||||
agentIds,
|
||||
handleQueryFlyoutOpen,
|
||||
renderDiscoverResultsAction,
|
||||
renderLensResultsAction,
|
||||
]
|
||||
);
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
|
@ -381,6 +416,9 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
|
|||
itemIdToExpandedRowMap={itemIdToExpandedRowMap}
|
||||
isExpandable
|
||||
/>
|
||||
{queryDetailsFlyoutOpen ? (
|
||||
<QueryDetailsFlyout onClose={handleQueryFlyoutClose} action={queryDetailsFlyoutOpen} />
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import {
|
||||
EuiFlyout,
|
||||
EuiTitle,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutHeader,
|
||||
EuiPortal,
|
||||
EuiFlexItem,
|
||||
EuiCodeBlock,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
interface QueryDetailsFlyoutProps {
|
||||
action: {
|
||||
id: string;
|
||||
query: string;
|
||||
};
|
||||
onClose: () => void;
|
||||
}
|
||||
const additionalZIndexStyle = { style: 'z-index: 6000' };
|
||||
|
||||
const QueryDetailsFlyoutComponent: React.FC<QueryDetailsFlyoutProps> = ({ action, onClose }) => (
|
||||
<EuiPortal>
|
||||
<EuiFlyout
|
||||
size="m"
|
||||
ownFocus
|
||||
onClose={onClose}
|
||||
aria-labelledby="flyoutTitle"
|
||||
maskProps={additionalZIndexStyle} // For an edge case to display above the alerts flyout
|
||||
>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="s">
|
||||
<h2 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
id="xpack.osquery.liveQueryActions.details.title"
|
||||
defaultMessage="Query Details"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<EuiFlexItem grow={false}>
|
||||
<strong>
|
||||
<FormattedMessage id="xpack.osquery.liveQueryActions.details.id" defaultMessage="Id" />
|
||||
</strong>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiCodeBlock fontSize="m" paddingSize="s" isCopyable={true}>
|
||||
{action.id}
|
||||
</EuiCodeBlock>
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexItem grow={false}>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="xpack.osquery.liveQueryActions.details.query"
|
||||
defaultMessage="Query"
|
||||
/>
|
||||
</strong>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiCodeBlock language="sql" fontSize="m" paddingSize="s" isCopyable={true}>
|
||||
{action.query}
|
||||
</EuiCodeBlock>
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="m" />
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
</EuiPortal>
|
||||
);
|
||||
|
||||
export const QueryDetailsFlyout = React.memo(QueryDetailsFlyoutComponent);
|
|
@ -12,7 +12,6 @@ import styled from 'styled-components';
|
|||
|
||||
import { useController } from 'react-hook-form';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { MAX_QUERY_LENGTH } from '../../packs/queries/validations';
|
||||
import { OsquerySchemaLink } from '../../components/osquery_schema_link';
|
||||
import { OsqueryEditor } from '../../editor';
|
||||
|
||||
|
@ -43,13 +42,6 @@ const CodeEditorFieldComponent: React.FC<CodeEditorFieldProps> = ({
|
|||
}),
|
||||
value: true,
|
||||
},
|
||||
maxLength: {
|
||||
message: i18n.translate('xpack.osquery.liveQuery.queryForm.largeQueryError', {
|
||||
defaultMessage: 'Query is too large (max {maxLength} characters)',
|
||||
values: { maxLength: MAX_QUERY_LENGTH },
|
||||
}),
|
||||
value: MAX_QUERY_LENGTH,
|
||||
},
|
||||
},
|
||||
defaultValue: '',
|
||||
});
|
||||
|
|
|
@ -23769,7 +23769,6 @@
|
|||
"xpack.osquery.fleetIntegration.osqueryConfig.packConfigFilesErrorMessage": "Les fichiers de configuration de pack ne sont pas pris en charge. Les packs suivants doivent être supprimés : {packNames}.",
|
||||
"xpack.osquery.fleetIntegration.osqueryConfig.restrictedOptionsErrorMessage": "Les options Osquery suivantes ne sont pas prises en charge et doivent être supprimées : {restrictedFlags}.",
|
||||
"xpack.osquery.liveQuery.permissionDeniedPromptBody": "Pour pouvoir consulter les résultats de requête, demandez à votre administrateur de mettre à jour votre rôle utilisateur de sorte à disposer des privilèges de {read} pour les index {logs}.",
|
||||
"xpack.osquery.liveQuery.queryForm.largeQueryError": "La recherche est trop volumineuse ({maxLength} caractères maxi)",
|
||||
"xpack.osquery.newPack.successToastMessageText": "Le pack \"{packName}\" a bien été créé.",
|
||||
"xpack.osquery.newSavedQuery.successToastMessageText": "Enregistrement réussi de la recherche \"{savedQueryId}\"",
|
||||
"xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "Supprimer {queryName}",
|
||||
|
|
|
@ -23747,7 +23747,6 @@
|
|||
"xpack.osquery.fleetIntegration.osqueryConfig.packConfigFilesErrorMessage": "パック構成ファイルはサポートされていません。これらのパックを削除する必要があります:{packNames}。",
|
||||
"xpack.osquery.fleetIntegration.osqueryConfig.restrictedOptionsErrorMessage": "次のosqueryオプションはサポートされていないため、削除する必要があります:{restrictedFlags}。",
|
||||
"xpack.osquery.liveQuery.permissionDeniedPromptBody": "クエリ結果を表示するには、ユーザーロールを更新して、{logs}インデックスに対する{read}権限を付与するように、管理者に依頼してください。",
|
||||
"xpack.osquery.liveQuery.queryForm.largeQueryError": "クエリが大きすぎます(最大{maxLength}文字)",
|
||||
"xpack.osquery.newPack.successToastMessageText": "\"{packName}\"パックが正常に作成されました",
|
||||
"xpack.osquery.newSavedQuery.successToastMessageText": "\"{savedQueryId}\"クエリが正常に保存されました",
|
||||
"xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "{queryName}を削除",
|
||||
|
|
|
@ -23778,7 +23778,6 @@
|
|||
"xpack.osquery.fleetIntegration.osqueryConfig.packConfigFilesErrorMessage": "不支持包配置文件。必须移除这些包:{packNames}。",
|
||||
"xpack.osquery.fleetIntegration.osqueryConfig.restrictedOptionsErrorMessage": "不支持以下 osquery 选项,必须将其移除:{restrictedFlags}。",
|
||||
"xpack.osquery.liveQuery.permissionDeniedPromptBody": "要查看查询结果,请要求管理员将您的角色更新为具有 {logs} 索引的索引 {read} 权限。",
|
||||
"xpack.osquery.liveQuery.queryForm.largeQueryError": "查询过大(最多 {maxLength} 个字符)",
|
||||
"xpack.osquery.newPack.successToastMessageText": "已成功创建“{packName}”包",
|
||||
"xpack.osquery.newSavedQuery.successToastMessageText": "已成功保存“{savedQueryId}”查询",
|
||||
"xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "删除 {queryName}",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue