[Defend workflows] [On-week] Migrate osquery from styled-components to @emotion (#161179)

This commit is contained in:
Tomasz Ciecierski 2023-08-02 19:18:10 +02:00 committed by GitHub
parent 41e5df703a
commit ffb716d8af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 505 additions and 495 deletions

View file

@ -14,7 +14,7 @@ module.exports = {
USES_STYLED_COMPONENTS: [
/packages[\/\\]kbn-ui-shared-deps-(npm|src)[\/\\]/,
/src[\/\\]plugins[\/\\](kibana_react)[\/\\]/,
/x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|observability_shared|exploratory_view|osquery|security_solution|timelines|synthetics|ux|uptime)[\/\\]/,
/x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|observability_shared|exploratory_view|security_solution|timelines|synthetics|ux|uptime)[\/\\]/,
/x-pack[\/\\]test[\/\\]plugin_functional[\/\\]plugins[\/\\]resolver_test[\/\\]/,
/x-pack[\/\\]packages[\/\\]elastic_assistant[\/\\]/,
/x-pack[\/\\]packages[\/\\]security-solution[\/\\]ecs_data_quality_dashboard[\/\\]/,

View file

@ -8,6 +8,8 @@
import { EuiLoadingSpinner } from '@elastic/eui';
import type { ReactNode } from 'react';
import React, { lazy, Suspense } from 'react';
import { EuiThemeProvider as StyledComponentsThemeProvider } from '@kbn/kibana-react-plugin/common';
import { useIsDarkTheme } from '../../common/use_is_dark_theme';
import type { CasesContextProps } from '../../components/cases_context';
export type GetCasesContextPropsInternal = CasesContextProps;
@ -32,21 +34,25 @@ const CasesProviderLazyWrapper = ({
releasePhase,
getFilesClient,
}: GetCasesContextPropsInternal & { children: ReactNode }) => {
const isDarkTheme = useIsDarkTheme();
return (
<Suspense fallback={<EuiLoadingSpinner />}>
<CasesProviderLazy
value={{
externalReferenceAttachmentTypeRegistry,
persistableStateAttachmentTypeRegistry,
owner,
permissions,
features,
releasePhase,
getFilesClient,
}}
>
{children}
</CasesProviderLazy>
<StyledComponentsThemeProvider darkMode={isDarkTheme}>
<CasesProviderLazy
value={{
externalReferenceAttachmentTypeRegistry,
persistableStateAttachmentTypeRegistry,
owner,
permissions,
features,
releasePhase,
getFilesClient,
}}
>
{children}
</CasesProviderLazy>
</StyledComponentsThemeProvider>
</Suspense>
);
};

View file

@ -49,7 +49,12 @@ export const checkResults = () => {
export const typeInECSFieldInput = (text: string, index = 0) =>
cy.getBySel('ECS-field-input').eq(index).type(text);
export const typeInOsqueryFieldInput = (text: string, index = 0) =>
cy.react('OsqueryColumnFieldComponent').eq(index).react('ResultComboBox').type(text);
cy
.react('OsqueryColumnFieldComponent')
.eq(index)
.within(() => {
cy.getBySel('comboBoxInput').type(text);
});
export const getOsqueryFieldTypes = (value: 'Osquery value' | 'Static value', index = 0) => {
cy.getBySel(`osquery-result-type-select-${index}`).click();

View file

@ -86,7 +86,7 @@ export const getSavedQueriesComplexTest = () =>
cy.contains('Save query');
findFormFieldByRowsLabelAndType('ID', savedQueryId);
findFormFieldByRowsLabelAndType('Description (optional)', savedQueryDescription);
cy.react('EuiButtonDisplay').contains('Save').click();
cy.getBySel('savedQueryFlyoutSaveButton').click();
cy.contains('Successfully saved');
closeToastIfVisible();
@ -120,10 +120,12 @@ export const getSavedQueriesComplexTest = () =>
inputQuery('{selectall}{backspace}{selectall}{backspace}');
cy.contains('Query is a required field');
inputQuery(BIG_QUERY);
cy.contains('Query is a required field').should('not.exist');
});
// Save edited
cy.react('EuiButton').contains('Update query').click();
cy.getBySel('euiFlyoutCloseButton').click();
cy.getBySel('savedQueryFormUpdateButton').click();
cy.contains(`${savedQueryDescription} Edited`);
// delete saved query

14
x-pack/plugins/osquery/emotion.d.ts vendored Normal file
View file

@ -0,0 +1,14 @@
/*
* 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 '@emotion/react';
import type { UseEuiTheme } from '@elastic/eui';
declare module '@emotion/react' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Theme extends UseEuiTheme {}
}

View file

@ -5,22 +5,19 @@
* 2.0.
*/
import styled from 'styled-components';
import { EuiColorPaletteDisplay } from '@elastic/eui';
import React, { useMemo } from 'react';
import { AGENT_STATUSES, getColorForAgentStatus } from './services/agent_status';
import type { ActionAgentStatus } from './types';
const StyledEuiColorPaletteDisplay = styled(EuiColorPaletteDisplay)`
&.osquery-action-agent-status-bar {
border: none;
border-radius: 0;
&:after {
border: none;
}
}
`;
const euiColorPaletteDisplayCss = {
border: 'none',
borderRadius: 0,
'&:after': {
border: 'none',
},
};
export const AgentStatusBar: React.FC<{
agentStatus: { [k in ActionAgentStatus]: number };
@ -39,11 +36,5 @@ export const AgentStatusBar: React.FC<{
}, [] as Array<{ stop: number; color: string }>);
}, [agentStatus]);
return (
<StyledEuiColorPaletteDisplay
className="osquery-action-agent-status-bar"
size="s"
palette={palette}
/>
);
return <EuiColorPaletteDisplay css={euiColorPaletteDisplayCss} size="s" palette={palette} />;
};

View file

@ -7,18 +7,17 @@
import { EuiLink } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
import { PLUGIN_ID } from '@kbn/fleet-plugin/common';
import { pagePathGetters } from '@kbn/fleet-plugin/public';
import { useKibana, isModifiedEvent, isLeftClickEvent } from '../common/lib/kibana';
import { useAgentPolicy } from './use_agent_policy';
const StyledEuiLink = styled(EuiLink)`
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
`;
const euiLinkCss = {
whiteSpace: 'nowrap' as const,
textOverflow: 'ellipsis',
overflow: 'hidden',
};
interface AgentsPolicyLinkProps {
policyId: string;
@ -52,9 +51,10 @@ const AgentsPolicyLinkComponent: React.FC<AgentsPolicyLinkProps> = ({ policyId }
);
return (
<StyledEuiLink href={href} onClick={handleClick}>
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink href={href} onClick={handleClick} css={euiLinkCss}>
{data?.name ?? policyId}
</StyledEuiLink>
</EuiLink>
);
};

View file

@ -6,40 +6,21 @@
*/
import { EuiErrorBoundary } from '@elastic/eui';
import { euiLightVars, euiDarkVars } from '@kbn/ui-theme';
import React, { useMemo } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from '@kbn/shared-ux-router';
import { I18nProvider } from '@kbn/i18n-react';
import { ThemeProvider } from 'styled-components';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
import { useUiSetting$, KibanaThemeProvider } from './shared_imports';
import type { AppPluginStartDependencies } from './types';
import { OsqueryApp } from './components/app';
import { DEFAULT_DARK_MODE, PLUGIN_NAME } from '../common';
import { PLUGIN_NAME } from '../common';
import { KibanaContextProvider } from './common/lib/kibana';
import { queryClient } from './query_client';
const OsqueryAppContext = () => {
const [darkMode] = useUiSetting$<boolean>(DEFAULT_DARK_MODE);
const theme = useMemo(
() => ({
eui: darkMode ? euiDarkVars : euiLightVars,
darkMode,
}),
[darkMode]
);
return (
<ThemeProvider theme={theme}>
<OsqueryApp />
</ThemeProvider>
);
};
import { KibanaThemeProvider } from './shared_imports';
export const renderApp = (
core: CoreStart,
@ -64,7 +45,7 @@ export const renderApp = (
<Router history={history}>
<I18nProvider>
<QueryClientProvider client={queryClient}>
<OsqueryAppContext />
<OsqueryApp />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</I18nProvider>

View file

@ -11,13 +11,13 @@ import {
EuiLoadingSpinner,
EuiPage,
EuiPageBody,
EuiPageContent_Deprecated as EuiPageContent,
EuiPageSection,
} from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import useObservable from 'react-use/lib/useObservable';
import { of } from 'rxjs';
import { Container, Wrapper } from './layouts';
import { containerCss, wrapperCss } from './layouts/default';
import { OsqueryAppRoutes } from '../routes';
import { useOsqueryIntegrationStatus } from '../common/hooks';
import { OsqueryAppEmptyState } from './empty_state';
@ -31,19 +31,13 @@ const OsqueryAppComponent = () => {
return (
<EuiPage paddingSize="none">
<EuiPageBody>
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
paddingSize="none"
color="subdued"
hasShadow={false}
>
<EuiPageSection paddingSize="none" color="subdued">
{hasCustomBranding ? (
<EuiLoadingSpinner size="xxl" />
) : (
<EuiLoadingElastic size="xxl" />
)}
</EuiPageContent>
</EuiPageSection>
</EuiPageBody>
</EuiPage>
);
@ -54,12 +48,12 @@ const OsqueryAppComponent = () => {
}
return (
<Container id="osquery-app">
<Wrapper>
<div css={containerCss} id="osquery-app">
<div css={wrapperCss}>
<MainNavigation />
<OsqueryAppRoutes />
</Wrapper>
</Container>
</div>
</div>
);
};

View file

@ -5,30 +5,26 @@
* 2.0.
*/
import styled from 'styled-components';
import type { UseEuiTheme } from '@elastic/eui';
export const containerCss = ({ euiTheme }: UseEuiTheme) => ({
minHeight: `calc(100vh - ${parseFloat(euiTheme.size.xxxl) * 2}px)`,
background: euiTheme.colors.emptyShade,
display: 'flex',
flexDirection: 'column' as const,
});
export const Container = styled.div`
min-height: calc(
100vh - ${(props) => parseFloat(props.theme.eui.euiHeaderHeightCompensation) * 2}px
);
background: ${(props) => props.theme.eui.euiColorEmptyShade};
display: flex;
flex-direction: column;
`;
export const wrapperCss = {
display: 'flex',
flexDirection: 'column' as const,
flex: 1,
};
export const Wrapper = styled.div`
display: flex;
flex-direction: column;
flex: 1;
`;
export const Nav = styled.nav`
background: ${(props) => props.theme.eui.euiColorEmptyShade};
border-bottom: ${(props) => props.theme.eui.euiBorderThin};
padding: ${(props) =>
`${props.theme.eui.euiSize} ${props.theme.eui.euiSizeL} ${props.theme.eui.euiSize} ${props.theme.eui.euiSizeL}`};
.euiTabs {
padding-left: 3px;
margin-left: -3px;
}
`;
export const navCss = ({ euiTheme }: UseEuiTheme) => ({
background: euiTheme.colors.emptyShade,
borderBottom: euiTheme.border.thin,
padding: `${euiTheme.size.base} ${euiTheme.size.l} ${euiTheme.size.base} ${euiTheme.size.l}`,
'.euiTabs': {
paddingLeft: '3px',
marginLeft: '-3px',
},
});

View file

@ -7,32 +7,24 @@
// copied from x-pack/plugins/fleet/public/applications/fleet/components/header.tsx
import React, { memo } from 'react';
import styled from 'styled-components';
import React, { memo, useCallback } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui';
import type { UseEuiTheme } from '@elastic/eui';
import type { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
import type { EuiFlexItemProps } from '@elastic/eui/src/components/flex/flex_item';
import { css } from '@emotion/react';
const Container = styled.div`
border-bottom: ${(props) => props.theme.eui.euiBorderThin};
background-color: ${(props) => props.theme.eui.euiPageBackgroundColor};
`;
const containerCss = ({ euiTheme }: UseEuiTheme) => ({
borderBottom: euiTheme.border.thin,
backgroundColor: euiTheme.colors.body,
});
const Wrapper = styled.div<{ maxWidth?: number }>`
max-width: ${(props) => props.maxWidth || 1200}px;
margin-left: auto;
margin-right: auto;
padding-top: ${(props) => props.theme.eui.euiSizeXL};
padding-left: ${(props) => props.theme.eui.euiSizeM};
padding-right: ${(props) => props.theme.eui.euiSizeM};
`;
const Tabs = styled(EuiTabs)`
top: 1px;
&:before {
height: 0px;
}
`;
const tabsCss = {
top: '1px',
'&:before': {
height: '0px',
},
};
export interface HeaderProps {
children?: React.ReactNode;
@ -65,35 +57,50 @@ const HeaderComponent: React.FC<HeaderProps> = ({
maxWidth,
tabsClassName,
'data-test-subj': dataTestSubj,
}) => (
<Container data-test-subj={dataTestSubj}>
<Wrapper maxWidth={maxWidth}>
<HeaderColumns
leftColumn={leftColumn}
rightColumn={rightColumn}
rightColumnGrow={rightColumnGrow}
/>
{children}
<EuiFlexGroup>
{tabs ? (
<EuiFlexItem>
<EuiSpacer size="s" />
<Tabs className={tabsClassName}>
{tabs.map((props) => (
<EuiTab {...(props as EuiTabProps)} key={props.id}>
{props.name}
</EuiTab>
))}
</Tabs>
</EuiFlexItem>
) : (
<EuiFlexItem>
<EuiSpacer size="l" />
</EuiFlexItem>
)}
</EuiFlexGroup>
</Wrapper>
</Container>
);
}) => {
const wrapperCss = useCallback(
({ euiTheme }: UseEuiTheme) => css`
max-width: ${maxWidth || 1200}px;
margin-left: auto;
margin-right: auto;
padding-top: ${euiTheme.size.xl};
padding-left: ${euiTheme.size.m};
padding-right: ${euiTheme.size.m};
`,
[maxWidth]
);
return (
<div css={containerCss} data-test-subj={dataTestSubj}>
<div css={wrapperCss}>
<HeaderColumns
leftColumn={leftColumn}
rightColumn={rightColumn}
rightColumnGrow={rightColumnGrow}
/>
{children}
<EuiFlexGroup>
{tabs ? (
<EuiFlexItem>
<EuiSpacer size="s" />
<EuiTabs className={tabsClassName} css={tabsCss}>
{tabs.map((props) => (
<EuiTab {...(props as EuiTabProps)} key={props.id}>
{props.name}
</EuiTab>
))}
</EuiTabs>
</EuiFlexItem>
) : (
<EuiFlexItem>
<EuiSpacer size="l" />
</EuiFlexItem>
)}
</EuiFlexGroup>
</div>
</div>
);
};
export const Header = React.memo(HeaderComponent);

View file

@ -7,7 +7,7 @@
// copied from x-pack/plugins/fleet/public/applications/fleet/layouts/index.tsx
export { Container, Nav, Wrapper } from './default';
export { containerCss, navCss, wrapperCss } from './default';
export type { WithHeaderLayoutProps } from './with_header';
export { WithHeaderLayout } from './with_header';
export { WithoutHeaderLayout } from './without_header';

View file

@ -6,11 +6,12 @@
*/
import React, { Fragment } from 'react';
import { EuiPageBody, EuiSpacer } from '@elastic/eui';
import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui';
import type { HeaderProps } from './header';
import { Header } from './header';
import { Page, ContentWrapper } from './without_header';
import { contentCss } from './without_header';
import { pageCss } from './without_header';
export interface WithHeaderLayoutProps extends HeaderProps {
restrictWidth?: number;
@ -36,16 +37,17 @@ export const WithHeaderLayout: React.FC<WithHeaderLayoutProps> = ({
>
{headerChildren}
</Header>
<Page
<EuiPage
css={pageCss}
restrictWidth={restrictWidth || 1200}
data-test-subj={dataTestSubj ? `${dataTestSubj}_page` : undefined}
>
<EuiPageBody>
<ContentWrapper>
<div css={contentCss}>
<EuiSpacer size="l" />
{children}
</ContentWrapper>
</div>
</EuiPageBody>
</Page>
</EuiPage>
</Fragment>
);

View file

@ -6,21 +6,21 @@
*/
import React, { Fragment } from 'react';
import styled from 'styled-components';
import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui';
import type { UseEuiTheme } from '@elastic/eui';
export const Page = styled(EuiPage)`
background: ${(props) => props.theme.eui.euiColorEmptyShade};
width: 100%;
align-self: center;
margin-left: 0;
margin-right: 0;
flex: 1;
`;
export const pageCss = ({ euiTheme }: UseEuiTheme) => ({
background: euiTheme.colors.emptyShade,
width: '100%',
alignSelf: 'center',
marginLeft: 0,
marginRight: 0,
flex: 1,
});
export const ContentWrapper = styled.div`
height: 100%;
`;
export const contentCss = {
height: '100%',
};
interface Props {
restrictWidth?: number;
@ -29,13 +29,13 @@ interface Props {
export const WithoutHeaderLayout: React.FC<Props> = ({ restrictWidth, children }) => (
<Fragment>
<Page restrictWidth={restrictWidth || 1200}>
<EuiPage css={pageCss} restrictWidth={restrictWidth || 1200}>
<EuiPageBody>
<ContentWrapper>
<div css={contentCss}>
<EuiSpacer size="m" />
{children}
</ContentWrapper>
</div>
</EuiPageBody>
</Page>
</EuiPage>
</Fragment>
);

View file

@ -9,9 +9,9 @@ import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiTab, EuiTabs } from '@elastic/eui';
import { useLocation } from 'react-router-dom';
import { navCss } from './layouts/default';
import { useRouterNavigate } from '../common/lib/kibana';
import { ManageIntegrationLink } from './manage_integration_link';
import { Nav } from './layouts';
enum Section {
LiveQueries = 'live_queries',
@ -24,7 +24,7 @@ export const MainNavigation = () => {
const section = useMemo(() => location.pathname.split('/')[1] ?? 'overview', [location.pathname]);
return (
<Nav>
<div css={navCss}>
<EuiFlexGroup gutterSize="l" alignItems="center">
<EuiFlexItem>
<EuiTabs bottomBorder={false}>
@ -72,6 +72,6 @@ export const MainNavigation = () => {
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</Nav>
</div>
);
};

View file

@ -15,12 +15,12 @@ import {
EuiCallOut,
EuiLink,
EuiAccordion,
useEuiTheme,
} from '@elastic/eui';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { produce } from 'immer';
import { i18n } from '@kbn/i18n';
import useDebounce from 'react-use/lib/useDebounce';
import styled from 'styled-components';
import type { AgentPolicy } from '@kbn/fleet-plugin/common';
import { agentRouteService, agentPolicyRouteService, PLUGIN_ID } from '@kbn/fleet-plugin/common';
@ -136,12 +136,6 @@ export const packConfigFilesValidator = (
const CommonUseField = getUseField({ component: Field });
const StyledEuiAccordion = styled(EuiAccordion)`
.euiAccordion__button {
color: ${({ theme }) => theme.eui.euiColorPrimary};
}
`;
/**
* Exports Osquery-specific package policy instructions
* for use in the Fleet app create / edit package policy
@ -343,6 +337,17 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
const { permissionDenied } = useFetchStatus();
const { euiTheme } = useEuiTheme();
const euiAccordionCss = useMemo(
() => ({
'.euiAccordion__button': {
color: euiTheme.colors.primary,
},
}),
[euiTheme]
);
return (
<>
{!editMode ? <DisabledCallout /> : null}
@ -373,7 +378,8 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
<>
<NavigationButtons isDisabled={!editMode} agentPolicyId={policy?.policy_id} />
<EuiSpacer size="xxl" />
<StyledEuiAccordion
<EuiAccordion
css={euiAccordionCss}
id="advanced"
buttonContent={i18n.translate(
'xpack.osquery.fleetIntegration.osqueryConfig.accordionFieldLabel',
@ -387,7 +393,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
<CommonUseField path="config" />
<ConfigUploader onChange={handleConfigUpload} />
</Form>
</StyledEuiAccordion>
</EuiAccordion>
</>
)}
</>

View file

@ -6,10 +6,9 @@
*/
import { isEmpty } from 'lodash';
import type { EuiAccordionProps } from '@elastic/eui';
import type { EuiAccordionProps, UseEuiTheme } from '@elastic/eui';
import { EuiCodeBlock, EuiFormRow, EuiAccordion, EuiSpacer } from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import { useController, useFormContext } from 'react-hook-form';
import { i18n } from '@kbn/i18n';
import type { LiveQueryFormFields } from '.';
@ -19,19 +18,18 @@ import { ECSMappingEditorField } from '../../packs/queries/lazy_ecs_mapping_edit
import type { SavedQueriesDropdownProps } from '../../saved_queries/saved_queries_dropdown';
import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown';
const StyledEuiAccordion = styled(EuiAccordion)`
${({ isDisabled }: { isDisabled?: boolean }) => isDisabled && 'display: none;'}
.euiAccordion__button {
color: ${({ theme }) => theme.eui.euiColorPrimary};
}
.euiAccordion__childWrapper {
-webkit-transition: none;
}
`;
const euiCodeBlockCss = {
minHeight: '100px',
};
const StyledEuiCodeBlock = styled(EuiCodeBlock)`
min-height: 100px;
`;
const euiAccordionCss = ({ euiTheme }: UseEuiTheme) => ({
'.euiAccordion__button': {
color: euiTheme.colors.primary,
},
'.euiAccordion__childWrapper': {
'-webkit-transition': 'none',
},
});
export interface LiveQueryQueryFieldProps {
handleSubmitForm?: () => void;
@ -131,14 +129,15 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
isDisabled={!permissions.writeLiveQueries || disabled}
>
{!permissions.writeLiveQueries || disabled ? (
<StyledEuiCodeBlock
<EuiCodeBlock
css={euiCodeBlockCss}
language="sql"
fontSize="m"
paddingSize="m"
transparentBackground={!value.length}
>
{value}
</StyledEuiCodeBlock>
</EuiCodeBlock>
) : (
<OsqueryEditor defaultValue={value} onChange={onChange} commands={commands} />
)}
@ -147,7 +146,8 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
<EuiSpacer size="m" />
{!isAdvancedToggleHidden && (
<StyledEuiAccordion
<EuiAccordion
css={euiAccordionCss}
id="advanced"
forceState={advancedContentState}
onToggle={handleToggle}
@ -156,7 +156,7 @@ const LiveQueryQueryFieldComponent: React.FC<LiveQueryQueryFieldProps> = ({
>
<EuiSpacer size="xs" />
<ECSMappingEditorField euiFieldProps={ecsFieldProps} />
</StyledEuiAccordion>
</EuiAccordion>
)}
</>
);

View file

@ -21,7 +21,6 @@ import {
EuiText,
} from '@elastic/eui';
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';
@ -34,43 +33,43 @@ import { PackViewInDiscoverAction } from '../../discover/pack_view_in_discover';
import { AddToCaseWrapper } from '../../cases/add_to_cases';
import { AddToTimelineButton } from '../../timelines/add_to_timeline_button';
const TruncateTooltipText = styled.div`
width: 100%;
const truncateTooltipTextCss = {
width: '100%',
> span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`;
'> span': {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap' as const,
},
};
const StyledEuiFlexItem = styled(EuiFlexItem)`
cursor: pointer;
`;
const euiFlexItemCss = {
cursor: 'pointer',
};
// TODO fix types
const euiBasicTableCss = {
'.euiTableRow.euiTableRow-isExpandedRow > td > div': {
padding: '0',
border: '1px solid #d3dae6',
},
'div.euiDataGrid__virtualized::-webkit-scrollbar': {
display: 'none',
},
'.euiDataGrid > div': {
'.euiDataGrid__scrollOverlay': {
boxShadow: 'none',
},
borderLeft: '0px',
borderRight: '0px',
},
};
const EMPTY_ARRAY: PackQueryStatusItem[] = [];
// @ts-expect-error TS2769
const StyledEuiBasicTable = styled(EuiBasicTable)`
.euiTableRow.euiTableRow-isExpandedRow > td > div {
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;
}
`;
export enum ViewResultsActionButtonType {
icon = 'icon',
button = 'button',
@ -165,14 +164,16 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
);
const handleQueryFlyoutClose = useCallback(() => setQueryDetailsFlyoutOpen(null), []);
const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<Record<string, unknown>>({});
const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<
Record<string, React.ReactNode>
>({});
const renderIDColumn = useCallback(
(id: string) => (
<TruncateTooltipText>
<div css={truncateTooltipTextCss}>
<EuiToolTip content={id} display="block">
<>{id}</>
</EuiToolTip>
</TruncateTooltipText>
</div>
),
[]
);
@ -183,11 +184,11 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
const content = singleLine.length > 55 ? `${singleLine.substring(0, 55)}...` : singleLine;
return (
<StyledEuiFlexItem onClick={handleQueryFlyoutOpen(item)}>
<EuiFlexItem css={euiFlexItemCss} onClick={handleQueryFlyoutOpen(item)}>
<EuiCodeBlock language="sql" fontSize="s" paddingSize="none" transparentBackground>
{content}
</EuiCodeBlock>
</StyledEuiFlexItem>
</EuiFlexItem>
);
},
[handleQueryFlyoutOpen]
@ -264,7 +265,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
[data, getHandleErrorsToggle, itemIdToExpandedRowMap]
);
const getItemId = useCallback((item: PackItem) => get(item, 'id'), []);
const getItemId = useCallback((item: PackItem) => get(item, 'id'), []) as unknown as string;
const renderResultActions = useCallback(
(row: { action_id: string }) => {
@ -329,6 +330,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
width: '40%',
},
{
field: '',
name: i18n.translate('xpack.osquery.pack.queriesTable.docsResultsColumnTitle', {
defaultMessage: 'Docs',
}),
@ -336,6 +338,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
render: renderDocsColumn,
},
{
field: '',
name: i18n.translate('xpack.osquery.pack.queriesTable.agentsResultsColumnTitle', {
defaultMessage: 'Agents',
}),
@ -343,6 +346,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
render: renderAgentsColumn,
},
{
field: '',
name: i18n.translate('xpack.osquery.pack.queriesTable.viewResultsColumnTitle', {
defaultMessage: 'View results',
}),
@ -350,6 +354,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
render: renderResultActions,
},
{
field: '',
id: 'actions',
width: '45px',
isVisuallyHiddenLabel: true,
@ -373,7 +378,7 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
const sorting = useMemo(
() => ({
sort: {
field: 'id' as keyof PackItem,
field: 'id' as const,
direction: Direction.asc,
},
}),
@ -407,8 +412,8 @@ const PackQueriesStatusTableComponent: React.FC<PackQueriesStatusTableProps> = (
agentIds={agentIds}
/>
)}
<StyledEuiBasicTable
<EuiBasicTable
css={euiBasicTableCss}
items={data ?? EMPTY_ARRAY}
itemId={getItemId}
columns={columns}

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import React, { useMemo } from 'react';
import type { UseEuiTheme } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import styled from 'styled-components';
import { AddToTimelineButton } from '../../timelines/add_to_timeline_button';
import { AddToCaseWrapper } from '../../cases/add_to_cases';
@ -17,16 +17,16 @@ interface PackResultsHeadersProps {
agentIds?: string[];
}
const StyledResultsHeading = styled(EuiFlexItem)`
padding-right: 20px;
border-right: 2px solid #d3dae6;
`;
const resultsHeadingCss = ({ euiTheme }: UseEuiTheme) => ({
paddingRight: '20px',
borderRight: euiTheme.border.thick,
});
const StyledIconsList = styled(EuiFlexItem)`
align-content: center;
justify-content: center;
padding-left: 10px;
`;
const iconsListCss = {
alignContent: 'center',
justifyContent: 'center',
paddingLeft: '10px',
};
export const PackResultsHeader = React.memo<PackResultsHeadersProps>(
({ actionId, agentIds, queryIds }) => {
@ -36,7 +36,7 @@ export const PackResultsHeader = React.memo<PackResultsHeadersProps>(
<>
<EuiSpacer size={'l'} />
<EuiFlexGroup direction="row" gutterSize="m">
<StyledResultsHeading grow={false}>
<EuiFlexItem css={resultsHeadingCss} grow={false}>
<EuiText>
<h2>
<FormattedMessage
@ -45,8 +45,8 @@ export const PackResultsHeader = React.memo<PackResultsHeadersProps>(
/>
</h2>
</EuiText>
</StyledResultsHeading>
<StyledIconsList grow={false}>
</EuiFlexItem>
<EuiFlexItem css={iconsListCss} grow={false}>
<span>
{actionId && (
<EuiFlexGroup>
@ -69,7 +69,7 @@ export const PackResultsHeader = React.memo<PackResultsHeadersProps>(
</EuiFlexGroup>
)}
</span>
</StyledIconsList>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size={'l'} />
</>

View file

@ -10,16 +10,10 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
import type { EuiComboBoxOptionOption } from '@elastic/eui';
import { EuiFormRow, EuiComboBox, EuiTextColor, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import styled from 'styled-components';
import { useController } from 'react-hook-form';
import type { PackSavedObject } from '../../packs/types';
const TextTruncate = styled.div`
overflow: hidden;
text-overflow: ellipsis;
`;
interface PackComboBoxFieldProps {
fieldProps?: {
packsData?: PackSavedObject[];
@ -103,9 +97,9 @@ export const PacksComboBoxField = ({
<strong>{option?.name}</strong>
</EuiFlexItem>
<EuiFlexItem>
<TextTruncate>
<div className="eui-textTruncate">
<EuiTextColor color="subdued">{option?.description}</EuiTextColor>
</TextTruncate>
</div>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -8,16 +8,16 @@
import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import styled from 'styled-components';
import { useController } from 'react-hook-form';
import styled from '@emotion/styled';
const StyledEuiCard = styled(EuiCard)`
padding: 0;
display: flex;
flex-direction: row;
border: ${(props) => {
if (props.selectable?.isSelected) {
return `1px solid ${props.theme.eui.euiColorSuccess}`;
border: ${({ theme, selectable }) => {
if (selectable?.isSelected) {
return `${theme.euiTheme.border.width.thin} solid ${theme.euiTheme.colors.success}`;
}
}};
.euiCard__content {
@ -28,7 +28,7 @@ const StyledEuiCard = styled(EuiCard)`
}
.euiText {
margin-top: 0;
color: ${(props) => props.theme.eui.euiTextSubduedColor};
color: ${({ theme }) => theme.euiTheme.colors.subduedText};
}
> button[role='switch'] {
@ -51,6 +51,7 @@ const StyledEuiCard = styled(EuiCard)`
}
}
`;
interface QueryPackSelectableProps {
canRunSingleQuery: boolean;
canRunPacks: boolean;

View file

@ -6,9 +6,9 @@
*/
import { EuiSwitch, EuiLoadingSpinner } from '@elastic/eui';
import type { UseEuiTheme } from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { useKibana } from '../common/lib/kibana';
@ -19,9 +19,9 @@ import { useUpdatePack } from './use_update_pack';
import { PACKS_ID } from './constants';
import type { PackSavedObject } from './types';
const StyledEuiLoadingSpinner = styled(EuiLoadingSpinner)`
margin-right: ${({ theme }) => theme.eui.euiSizeS};
`;
const euiLoadingSpinnerCss = ({ euiTheme }: UseEuiTheme) => ({
marginRight: euiTheme.size.s,
});
interface ActiveStateSwitchProps {
disabled?: boolean;
@ -91,7 +91,7 @@ const ActiveStateSwitchComponent: React.FC<ActiveStateSwitchProps> = ({ item })
return (
<>
{isLoading && <StyledEuiLoadingSpinner />}
{isLoading && <EuiLoadingSpinner css={euiLoadingSpinnerCss} />}
<EuiSwitch
checked={!!item.enabled}
disabled={!permissions.writePacks || isLoading}

View file

@ -7,6 +7,7 @@
import { filter, isEmpty, map, omit, reduce } from 'lodash';
import type { EuiAccordionProps } from '@elastic/eui';
import type { UseEuiTheme } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
@ -22,7 +23,6 @@ import { FormattedMessage } from '@kbn/i18n-react';
import deepEqual from 'fast-deep-equal';
import { FormProvider, useForm as useHookForm } from 'react-hook-form';
import styled from 'styled-components';
import { PackShardsField } from './shards/pack_shards_field';
import { useRouterNavigate } from '../../common/lib/kibana';
import { PolicyIdComboBoxField } from './policy_id_combobox_field';
@ -41,12 +41,11 @@ import { overflowCss } from '../utils';
type PackFormData = Omit<PackItem, 'id' | 'queries'> & { queries: PackQueryFormData[] };
const StyledEuiAccordion = styled(EuiAccordion)`
${({ isDisabled }: { isDisabled?: boolean }) => isDisabled && 'display: none;'}
.euiAccordion__button {
color: ${({ theme }) => theme.eui.euiColorPrimary};
}
`;
const euiAccordionCss = ({ euiTheme }: UseEuiTheme) => ({
'.euiAccordion__button': {
color: euiTheme.colors.primary,
},
});
interface PackFormProps {
defaultValue?: PackItem;
@ -271,7 +270,8 @@ const PackFormComponent: React.FC<PackFormProps> = ({
<EuiFlexGroup>
<EuiFlexItem css={overflowCss}>
<StyledEuiAccordion
<EuiAccordion
css={euiAccordionCss}
id="shardsToggle"
forceState={shardsToggleState}
onToggle={handleToggle}
@ -279,7 +279,7 @@ const PackFormComponent: React.FC<PackFormProps> = ({
>
<EuiSpacer size="xs" />
<PackShardsField options={availableOptions} />
</StyledEuiAccordion>
</EuiAccordion>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />

View file

@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import type { EuiComboBoxProps, EuiComboBoxOptionOption } from '@elastic/eui';
import { EuiComboBox, EuiFormRow, EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
import styled from '@emotion/styled';
import deepEqual from 'fast-deep-equal';
import { i18n } from '@kbn/i18n';
import { useController } from 'react-hook-form';
@ -21,12 +21,9 @@ import { useAgentPolicies } from '../../agent_policies';
// names/descriptions from overflowing the flex items
// 2) max-width is built from the grow property on the flex items because the value
// changes based on if Fleet is enabled/setup or not
const AgentPolicyNameColumn = styled(EuiFlexItem)`
max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`};
overflow: hidden;
`;
const AgentPolicyDescriptionColumn = styled(EuiFlexItem)`
max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`};
const StyledAgentPolicyColumn = styled(EuiFlexItem)`
max-width: ${({ grow }) => ((grow as number) / 9) * 100};
overflow: hidden;
`;
@ -71,16 +68,16 @@ const PolicyIdComboBoxFieldComponent: React.FC<PolicyIdComboBoxFieldProps> = ({
const renderOption = useCallback(
(option: EuiComboBoxOptionOption<string>) => (
<EuiFlexGroup>
<AgentPolicyNameColumn grow={2}>
<StyledAgentPolicyColumn grow={2}>
<span className="eui-textTruncate">
{(option.key && agentPoliciesById?.[option.key]?.name) ?? option.label}
</span>
</AgentPolicyNameColumn>
<AgentPolicyDescriptionColumn grow={5}>
</StyledAgentPolicyColumn>
<StyledAgentPolicyColumn grow={5}>
<EuiTextColor className="eui-textTruncate" color="subdued">
{(option.key && agentPoliciesById?.[option.key].description) ?? ''}
</EuiTextColor>
</AgentPolicyDescriptionColumn>
</StyledAgentPolicyColumn>
<EuiFlexItem grow={2} className="eui-textRight">
<EuiTextColor color="subdued">
<FormattedMessage

View file

@ -8,14 +8,14 @@
import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiRadio } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import styled from 'styled-components';
import { noop } from 'lodash';
import styled from '@emotion/styled';
const StyledEuiCard = styled(EuiCard)`
padding: 16px 92px 16px 16px !important;
border: ${(props) => {
if (props.selectable?.isSelected) {
return `1px solid ${props.theme.eui.euiColorPrimary}`;
border: ${({ theme, selectable }) => {
if (selectable?.isSelected) {
return `${theme.euiTheme.border.width.thin} solid ${theme.euiTheme.colors.success}`;
}
}};
@ -30,7 +30,7 @@ const StyledEuiCard = styled(EuiCard)`
.euiText {
margin-top: 0;
margin-left: 25px;
color: ${(props) => props.theme.eui.EuiTextSubduedColor};
color: ${({ theme }) => theme.euiTheme.colors.subduedText};
}
> button[role='switch'] {

View file

@ -9,17 +9,12 @@ import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import type { EuiComboBoxOptionOption } from '@elastic/eui';
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import styled from 'styled-components';
import type { UseFieldArrayRemove, UseFormReturn } from 'react-hook-form';
import type { ShardsArray } from '../../../../common/utils/converters';
import { ShardsPolicyField } from './shards_policy_field';
import { ShardsPercentageField } from './shards_percentage_field';
import { overflowCss } from '../../utils';
const StyledButtonWrapper = styled.div`
margin-top: ${(props: { index: number }) => props.index === 0 && '16px'};
`;
export type ShardsFormReturn = UseFormReturn<{ shardsArray: ShardsArray }>;
interface ShardsFormProps {
@ -43,6 +38,11 @@ const ShardsFormComponent = ({
}
}, [index, onDelete]);
const buttonWrapperCss = useCallback(
({ euiTheme }) => (index === 0 ? { marginTop: euiTheme.size.base } : {}),
[index]
);
return (
<>
<EuiFlexGroup
@ -65,7 +65,7 @@ const ShardsFormComponent = ({
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StyledButtonWrapper index={index}>
<div css={buttonWrapperCss}>
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.osquery.pack.form.deleteShardsRowButtonAriaLabel',
@ -78,7 +78,7 @@ const ShardsFormComponent = ({
disabled={isLastItem}
onClick={handleDeleteClick}
/>
</StyledButtonWrapper>
</div>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

View file

@ -18,7 +18,6 @@ import {
} from '@elastic/eui';
import moment from 'moment-timezone';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { useHistory } from 'react-router-dom';
@ -28,11 +27,11 @@ import { ActiveStateSwitch } from './active_state_switch';
import { AgentsPolicyLink } from '../agent_policies/agents_policy_link';
import type { PackSavedObject } from './types';
const UpdatedBy = styled.span`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
const updatedAtCss = {
whiteSpace: 'nowrap' as const,
overflow: 'hidden',
textOverflow: 'ellipsis',
};
const EMPTY_ARRAY: PackSavedObject[] = [];
@ -105,7 +104,7 @@ const PacksTableComponent = () => {
return updatedAt ? (
<EuiToolTip content={`${moment(updatedAt).fromNow()}${updatedBy}`}>
<UpdatedBy>{`${moment(updatedAt).fromNow()}${updatedBy}`}</UpdatedBy>
<span css={updatedAtCss}>{`${moment(updatedAt).fromNow()}${updatedBy}`}</span>
</EuiToolTip>
) : (
'-'

View file

@ -0,0 +1,59 @@
/*
* 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.
*/
export const resultComboBoxCss = {
'&.euiComboBox': {
position: 'relative',
left: '-1px',
'.euiComboBox__inputWrap': {
borderRadius: '0 6px 6px 0',
},
},
};
export const euiSuperSelectCss = {
minWidth: '70px',
borderRadius: '6px 0 0 6px',
'.euiIcon': {
padding: 0,
width: '18px',
background: 'none',
},
};
export const fieldIconCss = {
width: '32px',
'> svg': {
padding: '0 6px !important',
},
};
export const fieldSpanCss = {
paddingTop: '0 !important',
paddingBottom: '0 !important',
};
export const descriptionWrapperCss = {
overflow: 'hidden',
};
export const semicolonWrapperCss = {
marginTop: '28px',
};
// align the icon to the inputs
export const buttonWrapperCss = {
marginTop: '28px',
width: '24px',
};
export const ECSFieldWrapperCss = {
maxWidth: '100%',
};

View file

@ -36,7 +36,6 @@ import {
import sqliteParser from '@appland/sql-parser';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import type { FieldErrors, UseFieldArrayRemove, UseFormReturn } from 'react-hook-form';
@ -55,6 +54,16 @@ import { FieldIcon } from '../../common/lib/kibana';
import { OsqueryIcon } from '../../components/osquery_icon';
import { removeMultilines } from '../../../common/utils/build_query/remove_multilines';
import { overflowCss } from '../utils';
import {
resultComboBoxCss,
fieldSpanCss,
fieldIconCss,
buttonWrapperCss,
descriptionWrapperCss,
semicolonWrapperCss,
ECSFieldWrapperCss,
euiSuperSelectCss,
} from './ecs_field_css';
export type ECSMappingFormReturn = UseFormReturn<{ ecsMappingArray: ECSMappingArray }>;
@ -77,61 +86,6 @@ const typeMap = {
constant_keyword: 'string',
};
// @ts-expect-error update types
const ResultComboBox = styled(EuiComboBox)`
&.euiComboBox {
position: relative;
left: -1px;
.euiComboBox__inputWrap {
border-radius: 0 6px 6px 0;
}
}
`;
const StyledEuiSuperSelect = styled(EuiSuperSelect)`
min-width: 70px;
border-radius: 6px 0 0 6px;
.euiIcon {
padding: 0;
width: 18px;
background: none;
}
`;
const StyledFieldIcon = styled(FieldIcon)`
width: 32px;
> svg {
padding: 0 6px !important;
}
`;
const StyledFieldSpan = styled.span`
padding-top: 0 !important;
padding-bottom: 0 !important;
`;
const DescriptionWrapper = styled(EuiFlexItem)`
overflow: hidden;
`;
// align the icon to the inputs
const StyledSemicolonWrapper = styled.div`
margin-top: 28px;
`;
// align the icon to the inputs
const StyledButtonWrapper = styled.div`
margin-top: 28px;
width: 24px;
`;
const ECSFieldWrapper = styled(EuiFlexItem)`
max-width: 100%;
`;
const SINGLE_SELECTION = { asPlainText: true };
const ECSSchemaOptions = ECSSchema.map((ecs) => ({
@ -207,16 +161,19 @@ const ECSComboboxFieldComponent: React.FC<ECSComboboxFieldProps> = ({
}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StyledFieldSpan className="euiSuggestItem__label euiSuggestItem__label--expand">
<span css={fieldSpanCss} className="euiSuggestItem__label euiSuggestItem__label--expand">
{option.value.field}
</StyledFieldSpan>
</span>
</EuiFlexItem>
<DescriptionWrapper grow={false}>
<StyledFieldSpan className="euiSuggestItem__description euiSuggestItem__description">
<EuiFlexItem css={descriptionWrapperCss} grow={false}>
<span
css={fieldSpanCss}
className="euiSuggestItem__description euiSuggestItem__description"
>
{option.value.description}
</StyledFieldSpan>
</DescriptionWrapper>
</span>
</EuiFlexItem>
</EuiFlexGroup>
),
[]
@ -224,7 +181,8 @@ const ECSComboboxFieldComponent: React.FC<ECSComboboxFieldProps> = ({
const prepend = useMemo(
() => (
<StyledFieldIcon
<FieldIcon
css={fieldIconCss}
size="l"
type={
// @ts-expect-error update types
@ -435,15 +393,18 @@ const OsqueryColumnFieldComponent: React.FC<OsqueryColumnFieldProps> = ({
gutterSize="none"
>
<EuiFlexItem grow={false}>
<StyledFieldSpan className="euiSuggestItem__label euiSuggestItem__label--expand">
<span css={fieldSpanCss} className="euiSuggestItem__label euiSuggestItem__label--expand">
{option.value.suggestion_label}
</StyledFieldSpan>
</span>
</EuiFlexItem>
<DescriptionWrapper grow={false}>
<StyledFieldSpan className="euiSuggestItem__description euiSuggestItem__description">
<EuiFlexItem css={descriptionWrapperCss} grow={false}>
<span
css={fieldSpanCss}
className="euiSuggestItem__description euiSuggestItem__description"
>
{option.value.description}
</StyledFieldSpan>
</DescriptionWrapper>
</span>
</EuiFlexItem>
</EuiFlexGroup>
),
[]
@ -510,7 +471,8 @@ const OsqueryColumnFieldComponent: React.FC<OsqueryColumnFieldProps> = ({
const Prepend = useMemo(
() => (
<StyledEuiSuperSelect
<EuiSuperSelect
css={euiSuperSelectCss}
disabled={euiFieldProps.isDisabled}
options={OSQUERY_COLUMN_VALUE_TYPE_OPTIONS}
data-test-subj={`osquery-result-type-select-${index}`}
@ -577,7 +539,10 @@ const OsqueryColumnFieldComponent: React.FC<OsqueryColumnFieldProps> = ({
{Prepend}
</EuiFlexItem>
<EuiFlexItem css={overflowCss}>
<ResultComboBox
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore*/}
<EuiComboBox
css={resultComboBoxCss}
error={resultFieldState.error?.message}
// eslint-disable-next-line react/jsx-no-bind, react-perf/jsx-no-new-function-as-prop
inputRef={(ref: HTMLInputElement) => {
@ -660,16 +625,14 @@ export const ECSMappingEditorForm: React.FC<ECSMappingEditorFormProps> = ({
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StyledSemicolonWrapper>
<EuiText>:</EuiText>
</StyledSemicolonWrapper>
<EuiFlexItem grow={false} css={semicolonWrapperCss}>
<EuiText>:</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem css={overflowCss}>
<EuiFlexGroup alignItems="flexStart" gutterSize="s" wrap>
<ECSFieldWrapper>
<EuiFlexItem css={ECSFieldWrapperCss}>
<OsqueryColumnField
control={control}
watch={watch}
@ -683,10 +646,10 @@ export const ECSMappingEditorForm: React.FC<ECSMappingEditorFormProps> = ({
isDisabled,
}}
/>
</ECSFieldWrapper>
</EuiFlexItem>
{!isDisabled && (
<EuiFlexItem grow={false}>
<StyledButtonWrapper>
<div css={buttonWrapperCss}>
{!isLastItem && (
<EuiButtonIcon
aria-label={i18n.translate(
@ -700,7 +663,7 @@ export const ECSMappingEditorForm: React.FC<ECSMappingEditorFormProps> = ({
onClick={handleDeleteClick}
/>
)}
</StyledButtonWrapper>
</div>
</EuiFlexItem>
)}
</EuiFlexGroup>

View file

@ -6,7 +6,6 @@
*/
import { get, isEmpty, isArray, isObject, isEqual, keys, map, reduce } from 'lodash/fp';
import { css } from '@emotion/react';
import type {
EuiDataGridSorting,
EuiDataGridProps,
@ -29,7 +28,6 @@ import { FormattedMessage } from '@kbn/i18n-react';
import React, { createContext, useEffect, useState, useCallback, useContext, useMemo } from 'react';
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
import { pagePathGetters } from '@kbn/fleet-plugin/public';
import styled from 'styled-components';
import { AddToTimelineButton } from '../timelines/add_to_timeline_button';
import { useAllResults } from './use_all_results';
import type { ResultEdges } from '../../common/search_strategy';
@ -48,14 +46,18 @@ import { AddToCaseWrapper } from '../cases/add_to_cases';
const DataContext = createContext<ResultEdges>([]);
const StyledEuiDataGrid = styled(EuiDataGrid)`
:not(.euiDataGrid--fullScreen) {
.euiDataGrid__virtualized {
height: 100% !important;
max-height: 500px;
}
}
`;
const euiDataGridCss = {
':not(.euiDataGrid--fullScreen)': {
'.euiDataGrid__virtualized': {
height: '100% !important',
maxHeight: '500px',
},
},
};
const euiProgressCss = {
marginTop: '-2px',
};
export interface ResultsTableComponentProps {
actionId: string;
@ -425,15 +427,7 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
return (
<>
{isLive && (
<EuiProgress
color="primary"
size="xs"
css={css`
margin-top: -2px;
`}
/>
)}
{isLive && <EuiProgress color="primary" size="xs" css={euiProgressCss} />}
{!allResultsData?.edges.length ? (
<EuiPanel hasShadow={false} data-test-subj={'osqueryResultsPanel'}>
@ -441,7 +435,8 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
</EuiPanel>
) : (
<DataContext.Provider value={allResultsData?.edges}>
<StyledEuiDataGrid
<EuiDataGrid
css={euiDataGridCss}
data-test-subj="osqueryResultsTable"
aria-label="Osquery results"
columns={columns}

View file

@ -8,18 +8,17 @@
import React from 'react';
import { EuiEmptyPrompt, EuiPanel, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import styled from 'styled-components';
const Panel = styled(EuiPanel)`
max-width: 500px;
margin-right: auto;
margin-left: auto;
`;
const panelCss = {
maxWidth: '500px',
marginRight: 'auto',
marginLeft: 'auto',
};
const MissingPrivilegesComponent = () => (
<div>
<EuiSpacer />
<Panel>
<EuiPanel css={panelCss}>
<EuiEmptyPrompt
iconType="securityApp"
title={
@ -39,7 +38,7 @@ const MissingPrivilegesComponent = () => (
</p>
}
/>
</Panel>
</EuiPanel>
<EuiSpacer />
</div>
);

View file

@ -10,16 +10,15 @@ import { FormattedMessage } from '@kbn/i18n-react';
import React, { useLayoutEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { useRouterNavigate } from '../../../common/lib/kibana';
import { WithHeaderLayout } from '../../../components/layouts';
import { useLiveQueryDetails } from '../../../actions/use_live_query_details';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { PackQueriesStatusTable } from '../../../live_queries/form/pack_queries_status_table';
const StyledTableWrapper = styled(EuiFlexItem)`
padding-left: 10px;
`;
const tableWrapperCss = {
paddingLeft: '10px',
};
const LiveQueryDetailsPageComponent = () => {
const { actionId } = useParams<{ actionId: string }>();
@ -60,7 +59,7 @@ const LiveQueryDetailsPageComponent = () => {
return (
<WithHeaderLayout leftColumn={LeftColumn} rightColumnGrow={false}>
<StyledTableWrapper>
<EuiFlexItem css={tableWrapperCss}>
<PackQueriesStatusTable
actionId={actionId}
data={data?.queries}
@ -69,7 +68,7 @@ const LiveQueryDetailsPageComponent = () => {
agentIds={data?.agents}
showResultsHeader
/>
</StyledTableWrapper>
</EuiFlexItem>
</WithHeaderLayout>
);
};

View file

@ -16,10 +16,10 @@ import {
EuiSpacer,
EuiText,
} from '@elastic/eui';
import type { UseEuiTheme } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import React, { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
import { WithHeaderLayout } from '../../../components/layouts';
@ -29,11 +29,11 @@ import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { useAgentPolicyAgentIds } from '../../../agents/use_agent_policy_agent_ids';
import { AgentPoliciesPopover } from '../../../packs/packs_table';
const Divider = styled.div`
width: 0;
height: 100%;
border-left: ${({ theme }) => theme.eui.euiBorderThin};
`;
const dividerCss = ({ euiTheme }: UseEuiTheme) => ({
width: 0,
height: '100%',
borderLeft: euiTheme.border.thin,
});
const PackDetailsPageComponent = () => {
const permissions = useKibana().services.application.capabilities.osquery;
@ -112,7 +112,7 @@ const PackDetailsPageComponent = () => {
</EuiDescriptionList>
</EuiFlexItem>
<EuiFlexItem grow={false} key="agents_failed_count_divider">
<Divider />
<div css={dividerCss} />
</EuiFlexItem>
<EuiFlexItem grow={false} key="edit_button">
<EuiButton

View file

@ -76,6 +76,7 @@ const EditSavedQueryFormComponent: React.FC<EditSavedQueryFormProps> = ({
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="savedQueryFormUpdateButton"
isLoading={isSubmitting}
color="primary"
fill

View file

@ -19,16 +19,15 @@ import React, { useCallback, useMemo, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
import { WithHeaderLayout } from '../../../components/layouts';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { EditSavedQueryForm } from './form';
import { useDeleteSavedQuery, useUpdateSavedQuery, useSavedQuery } from '../../../saved_queries';
const StyledEuiCallOut = styled(EuiCallOut)`
margin: 10px;
`;
const euiCalloutCss = {
margin: '10px',
};
const EditSavedQueryPageComponent = () => {
const permissions = useKibana().services.application.capabilities.osquery;
@ -88,12 +87,12 @@ const EditSavedQueryPageComponent = () => {
}}
/>
{elasticPrebuiltQuery && (
<StyledEuiCallOut size="s">
<EuiCallOut css={euiCalloutCss} size="s">
<FormattedMessage
id="xpack.osquery.viewSavedQuery.prebuiltInfo"
defaultMessage="This is a prebuilt Elastic query, and it cannot be edited."
/>
</StyledEuiCallOut>
</EuiCallOut>
)}
</>
) : (

View file

@ -9,15 +9,14 @@ import { EuiTabbedContent, EuiNotificationBadge } from '@elastic/eui';
import React, { useMemo } from 'react';
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
import styled from 'styled-components';
import { ResultsTable } from '../../../results/results_table';
import { ActionResultsSummary } from '../../../action_results/action_results_summary';
const StyledEuiTabbedContent = styled(EuiTabbedContent)`
div.euiTabs {
padding-left: 8px;
}
`;
const euiTabbedContentCss = {
'div.euiTabs': {
paddingLeft: '8px',
},
};
interface ResultTabsProps {
actionId: string;
@ -90,7 +89,8 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
);
return (
<StyledEuiTabbedContent
<EuiTabbedContent
css={euiTabbedContentCss}
// TODO: extend the EuiTabbedContent component to support EuiTabs props
// bottomBorder={false}
tabs={tabs}

View file

@ -8,16 +8,15 @@
import { isEmpty } from 'lodash/fp';
import { EuiCodeBlock, EuiFormRow } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { useController } from 'react-hook-form';
import { i18n } from '@kbn/i18n';
import { OsquerySchemaLink } from '../../components/osquery_schema_link';
import { OsqueryEditor } from '../../editor';
const StyledEuiCodeBlock = styled(EuiCodeBlock)`
min-height: 100px;
`;
const euiCodeBlockCss = {
minHeight: '100px',
};
interface CodeEditorFieldProps {
euiFieldProps?: Record<string, unknown>;
@ -58,14 +57,15 @@ const CodeEditorFieldComponent: React.FC<CodeEditorFieldProps> = ({
fullWidth
>
{euiFieldProps?.isDisabled ? (
<StyledEuiCodeBlock
<EuiCodeBlock
css={euiCodeBlockCss}
language="sql"
fontSize="m"
paddingSize="m"
transparentBackground={!value.length}
>
{value}
</StyledEuiCodeBlock>
</EuiCodeBlock>
) : (
<OsqueryEditor defaultValue={value} onChange={onChange} />
)}

View file

@ -7,18 +7,17 @@
import { EuiFlyout, EuiFlyoutHeader, EuiTitle, EuiFlyoutBody } from '@elastic/eui';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { FormattedMessage } from '@kbn/i18n-react';
import { useFormContext } from 'react-hook-form';
import { LiveQuery } from '../../live_queries';
const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)`
&.euiFlyoutHeader {
padding-top: 21px;
padding-bottom: 20px;
}
`;
const euiFlyoutHeaderCss = {
'&.euiFlyoutHeader': {
paddingTop: '21px',
paddingBottom: '20px',
},
};
interface PlaygroundFlyoutProps {
enabled?: boolean;
@ -36,7 +35,7 @@ const PlaygroundFlyoutComponent: React.FC<PlaygroundFlyoutProps> = ({ enabled, o
return (
<EuiFlyout type="push" size="m" onClose={onClose} data-test-subj={'osquery-save-query-flyout'}>
<StyledEuiFlyoutHeader hasBorder>
<EuiFlyoutHeader css={euiFlyoutHeaderCss} hasBorder>
<EuiTitle size="s">
<h5>
<FormattedMessage
@ -45,7 +44,7 @@ const PlaygroundFlyoutComponent: React.FC<PlaygroundFlyoutProps> = ({ enabled, o
/>
</h5>
</EuiTitle>
</StyledEuiFlyoutHeader>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<LiveQuery
enabled={enabled && query !== ''}

View file

@ -8,7 +8,6 @@
import { find } from 'lodash/fp';
import { EuiCodeBlock, EuiFormRow, EuiComboBox, EuiTextColor } from '@elastic/eui';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import { useWatch, useFormContext } from 'react-hook-form';
import { QUERIES_DROPDOWN_LABEL, QUERIES_DROPDOWN_SEARCH_FIELD_LABEL } from './constants';
import { OsquerySchemaLink } from '../components/osquery_schema_link';
@ -16,16 +15,11 @@ import { OsquerySchemaLink } from '../components/osquery_schema_link';
import { useSavedQueries } from './use_saved_queries';
import type { SavedQuerySO } from '../routes/saved_queries/list';
const TextTruncate = styled.div`
overflow: hidden;
text-overflow: ellipsis;
`;
const StyledEuiCodeBlock = styled(EuiCodeBlock)`
.euiCodeBlock__line {
white-space: nowrap;
}
`;
const euiCodeBlockCss = {
'.euiCodeBlock__line': {
whiteSpace: 'nowrap' as const,
},
};
export interface SavedQueriesDropdownProps {
disabled?: boolean;
@ -96,12 +90,12 @@ const SavedQueriesDropdownComponent: React.FC<SavedQueriesDropdownProps> = ({
({ value }) => (
<>
<strong>{value.id}</strong>
<TextTruncate>
<div className="eui-textTruncate">
<EuiTextColor color="subdued">{value.description}</EuiTextColor>
</TextTruncate>
<StyledEuiCodeBlock language="sql" fontSize="m" paddingSize="s">
</div>
<EuiCodeBlock css={euiCodeBlockCss} language="sql" fontSize="m" paddingSize="s">
{value.query.split('\n').join(' ')}
</StyledEuiCodeBlock>
</EuiCodeBlock>
</>
),
[]

View file

@ -95,7 +95,12 @@ const SavedQueryFlyoutComponent: React.FC<AddQueryFlyoutProps> = ({
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton isLoading={isSubmitting} onClick={handleSubmit(onSubmit)} fill>
<EuiButton
data-test-subj="savedQueryFlyoutSaveButton"
isLoading={isSubmitting}
onClick={handleSubmit(onSubmit)}
fill
>
<FormattedMessage
id="xpack.osquery.pack.queryFlyoutForm.saveButtonLabel"
defaultMessage="Save"

View file

@ -6,8 +6,6 @@
*/
import React, { lazy, Suspense } from 'react';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '../query_client';
import type { OsqueryResponseActionsParamsFormProps } from './osquery_response_action_type';
const OsqueryResponseActionParamsForm = lazy(() => import('./osquery_response_action_type'));
@ -19,13 +17,11 @@ export const getLazyOsqueryResponseActionTypeForm =
return (
<Suspense fallback={null}>
<QueryClientProvider client={queryClient}>
<OsqueryResponseActionParamsForm
onChange={onChange}
defaultValues={defaultValues}
onError={onError}
/>
</QueryClientProvider>
<OsqueryResponseActionParamsForm
onChange={onChange}
defaultValues={defaultValues}
onError={onError}
/>
</Suspense>
);
};

View file

@ -18,6 +18,8 @@
"../../../typings/**/*",
// ECS and Osquery schema files
"public/common/schemas/*/**.json",
// Emotion theme typing
"./emotion.d.ts"
],
"kbn_references": [
"@kbn/core",
@ -43,7 +45,6 @@
"@kbn/utility-types",
"@kbn/securitysolution-io-ts-utils",
"@kbn/osquery-io-ts-types",
"@kbn/ui-theme",
"@kbn/i18n-react",
"@kbn/discover-plugin",
"@kbn/lens-plugin",