Skip to content

Commit

Permalink
Merge branch 'main' into split-types-from-code-on-kbn-test
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Feb 3, 2022
2 parents 01f2b25 + 21710df commit 1a74b7f
Show file tree
Hide file tree
Showing 14 changed files with 422 additions and 231 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import type { DatatableColumn } from '../../../../expressions/public';
import { ExpressionValueVisDimension } from '../../../../visualizations/public';
import type { HeatmapRenderProps, FilterEvent, BrushEvent } from '../../common';
import { applyPaletteParams, findMinMaxByColumnId, getSortPredicate } from './helpers';
import { getColorPicker } from '../utils/get_color_picker';
import {
LegendColorPickerWrapperContext,
LegendColorPickerWrapper,
} from '../utils/get_color_picker';
import { DEFAULT_PALETTE_NAME, defaultPaletteParams } from '../constants';
import { HeatmapIcon } from './heatmap_icon';
import './index.scss';
Expand Down Expand Up @@ -172,10 +175,6 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = memo(
[uiState]
);

const legendColorPicker = useMemo(
() => getColorPicker(args.legend.position, setColor, uiState),
[args.legend.position, setColor, uiState]
);
const table = data;
const valueAccessor = args.valueAccessor
? getAccessor(args.valueAccessor, table.columns)
Expand Down Expand Up @@ -484,55 +483,63 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = memo(
legendPosition={args.legend.position}
/>
)}
<Chart>
<Settings
onElementClick={interactive ? (onElementClick as ElementClickListener) : undefined}
showLegend={showLegend ?? args.legend.isVisible}
legendPosition={args.legend.position}
legendColorPicker={uiState ? legendColorPicker : undefined}
debugState={window._echDebugStateFlag ?? false}
tooltip={tooltip}
theme={[themeOverrides, chartTheme]}
xDomain={{
min:
dateHistogramMeta && dateHistogramMeta.timeRange
? new Date(dateHistogramMeta.timeRange.from).getTime()
: NaN,
max:
dateHistogramMeta && dateHistogramMeta.timeRange
? new Date(dateHistogramMeta.timeRange.to).getTime()
: NaN,
}}
onBrushEnd={interactive ? (onBrushEnd as BrushEndListener) : undefined}
/>
<Heatmap
id="heatmap"
name={valueColumn.name}
colorScale={{
type: 'bands',
bands,
}}
timeZone={timeZone}
data={chartData}
xAccessor={xAccessor}
yAccessor={yAccessor || 'unifiedY'}
valueAccessor={valueAccessor}
valueFormatter={valueFormatter}
xScale={xScale}
ySortPredicate={yAxisColumn ? getSortPredicate(yAxisColumn) : 'dataIndex'}
xSortPredicate={xAxisColumn ? getSortPredicate(xAxisColumn) : 'dataIndex'}
xAxisLabelName={xAxisColumn?.name}
yAxisLabelName={yAxisColumn?.name}
xAxisTitle={args.gridConfig.isXAxisTitleVisible ? xAxisTitle : undefined}
yAxisTitle={args.gridConfig.isYAxisTitleVisible ? yAxisTitle : undefined}
xAxisLabelFormatter={(v) => `${xValuesFormatter.convert(v) ?? ''}`}
yAxisLabelFormatter={
yAxisColumn
? (v) => `${formatFactory(yAxisColumn.meta.params).convert(v) ?? ''}`
: undefined
}
/>
</Chart>
<LegendColorPickerWrapperContext.Provider
value={{
uiState,
setColor,
legendPosition: args.legend.position,
}}
>
<Chart>
<Settings
onElementClick={interactive ? (onElementClick as ElementClickListener) : undefined}
showLegend={showLegend ?? args.legend.isVisible}
legendPosition={args.legend.position}
legendColorPicker={uiState ? LegendColorPickerWrapper : undefined}
debugState={window._echDebugStateFlag ?? false}
tooltip={tooltip}
theme={[themeOverrides, chartTheme]}
xDomain={{
min:
dateHistogramMeta && dateHistogramMeta.timeRange
? new Date(dateHistogramMeta.timeRange.from).getTime()
: NaN,
max:
dateHistogramMeta && dateHistogramMeta.timeRange
? new Date(dateHistogramMeta.timeRange.to).getTime()
: NaN,
}}
onBrushEnd={interactive ? (onBrushEnd as BrushEndListener) : undefined}
/>
<Heatmap
id="heatmap"
name={valueColumn.name}
colorScale={{
type: 'bands',
bands,
}}
timeZone={timeZone}
data={chartData}
xAccessor={xAccessor}
yAccessor={yAccessor || 'unifiedY'}
valueAccessor={valueAccessor}
valueFormatter={valueFormatter}
xScale={xScale}
ySortPredicate={yAxisColumn ? getSortPredicate(yAxisColumn) : 'dataIndex'}
xSortPredicate={xAxisColumn ? getSortPredicate(xAxisColumn) : 'dataIndex'}
xAxisLabelName={xAxisColumn?.name}
yAxisLabelName={yAxisColumn?.name}
xAxisTitle={args.gridConfig.isXAxisTitleVisible ? xAxisTitle : undefined}
yAxisTitle={args.gridConfig.isYAxisTitleVisible ? yAxisTitle : undefined}
xAxisLabelFormatter={(v) => `${xValuesFormatter.convert(v) ?? ''}`}
yAxisLabelFormatter={
yAxisColumn
? (v) => `${formatFactory(yAxisColumn.meta.params).convert(v) ?? ''}`
: undefined
}
/>
</Chart>
</LegendColorPickerWrapperContext.Provider>
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
* Side Public License, v 1.
*/

import React, { useCallback } from 'react';
import React, { createContext, useCallback, useContext } from 'react';
import { LegendColorPicker, Position } from '@elastic/charts';
import { PopoverAnchorPosition, EuiPopover, EuiOutsideClickDetector } from '@elastic/eui';
import { PopoverAnchorPosition, EuiWrappingPopover, EuiOutsideClickDetector } from '@elastic/eui';
import type { PersistedState } from '../../../../visualizations/public';
import { ColorPicker } from '../../../../charts/public';

Expand All @@ -27,59 +27,77 @@ function getAnchorPosition(legendPosition: Position): PopoverAnchorPosition {
}
}

export const getColorPicker =
(
legendPosition: Position,
setColor: (newColor: string | null, seriesKey: string | number) => void,
uiState: PersistedState
): LegendColorPicker =>
({ anchor, color, onClose, onChange, seriesIdentifiers: [seriesIdentifier] }) => {
const seriesName = seriesIdentifier.key;
const overwriteColors: Record<string, string> = uiState?.get('vis.colors', {}) ?? {};
const colorIsOverwritten = seriesName.toString() in overwriteColors;
let keyDownEventOn = false;
const handleChange = (newColor: string | null) => {
if (newColor) {
onChange(newColor);
}
setColor(newColor, seriesName);
// close the popover if no color is applied or the user has clicked a color
if (!newColor || !keyDownEventOn) {
onClose();
}
};
export interface LegendColorPickerWrapperContextType {
legendPosition: Position;
setColor: (newColor: string | null, seriesKey: string | number) => void;
uiState: PersistedState;
}

const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
if (e.keyCode === KEY_CODE_ENTER) {
onClose?.();
}
keyDownEventOn = true;
};
export const LegendColorPickerWrapperContext = createContext<
LegendColorPickerWrapperContextType | undefined
>(undefined);

const handleOutsideClick = useCallback(() => {
onClose?.();
}, [onClose]);
export const LegendColorPickerWrapper: LegendColorPicker = ({
anchor,
color,
onClose,
onChange,
seriesIdentifiers: [seriesIdentifier],
}) => {
const colorPickerWrappingContext = useContext(LegendColorPickerWrapperContext);
const handleOutsideClick = useCallback(() => {
onClose?.();
}, [onClose]);

if (!colorPickerWrappingContext) {
return null;
}

const { legendPosition, setColor, uiState } = colorPickerWrappingContext;
const seriesName = seriesIdentifier.key;

return (
<EuiOutsideClickDetector onOutsideClick={handleOutsideClick}>
<EuiPopover
isOpen
ownFocus
display="block"
button={anchor}
anchorPosition={getAnchorPosition(legendPosition)}
closePopover={onClose}
panelPaddingSize="s"
>
<ColorPicker
color={color}
onChange={handleChange}
label={seriesName}
useLegacyColors={false}
colorIsOverwritten={colorIsOverwritten}
onKeyDown={onKeyDown}
/>
</EuiPopover>
</EuiOutsideClickDetector>
);
const overwriteColors: Record<string, string> = uiState?.get('vis.colors', {}) ?? {};
const colorIsOverwritten = seriesName.toString() in overwriteColors;
let keyDownEventOn = false;

const handleChange = (newColor: string | null) => {
if (newColor) {
onChange(newColor);
}
setColor(newColor, seriesName);
// close the popover if no color is applied or the user has clicked a color
if (!newColor || !keyDownEventOn) {
onClose();
}
};

const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
if (e.keyCode === KEY_CODE_ENTER) {
onClose?.();
}
keyDownEventOn = true;
};

return (
<EuiOutsideClickDetector onOutsideClick={handleOutsideClick}>
<EuiWrappingPopover
isOpen={true}
ownFocus
display="block"
button={anchor}
anchorPosition={getAnchorPosition(legendPosition)}
closePopover={onClose}
panelPaddingSize="s"
>
<ColorPicker
color={color}
onChange={handleChange}
label={seriesName}
useLegacyColors={false}
colorIsOverwritten={colorIsOverwritten}
onKeyDown={onKeyDown}
/>
</EuiWrappingPopover>
</EuiOutsideClickDetector>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 { spawn } from 'child_process';
import type { ChildProcess } from 'child_process';

import fetch from 'node-fetch';

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

export function useDockerRegistry() {
const packageRegistryPort = process.env.FLEET_PACKAGE_REGISTRY_PORT || '8081';

if (!packageRegistryPort.match(/^[0-9]{4}/)) {
throw new Error('Invalid FLEET_PACKAGE_REGISTRY_PORT');
}

let dockerProcess: ChildProcess | undefined;
async function startDockerRegistryServer() {
const dockerImage = `docker.elastic.co/package-registry/distribution@sha256:de952debe048d903fc73e8a4472bb48bb95028d440cba852f21b863d47020c61`;

const args = ['run', '--rm', '-p', `${packageRegistryPort}:8080`, dockerImage];

dockerProcess = spawn('docker', args, { stdio: 'inherit' });

let isExited = dockerProcess.exitCode !== null;
dockerProcess.once('exit', () => {
isExited = true;
});

let retries = 0;
while (!isExited && retries++ <= 20) {
try {
const res = await fetch(`http://localhost:${packageRegistryPort}/`);
if (res.status === 200) {
return;
}
} catch (err) {
// swallow errors
}

await delay(3000);
}

dockerProcess.kill();
throw new Error('Unable to setup docker registry');
}

async function cleanupDockerRegistryServer() {
if (dockerProcess && !dockerProcess.killed) {
dockerProcess.kill();
}
}

beforeAll(async () => {
jest.setTimeout(5 * 60 * 1000); // 5 minutes timeout
await startDockerRegistryServer();
});

afterAll(async () => {
await cleanupDockerRegistryServer();
});

return `http://localhost:${packageRegistryPort}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import type { HttpMethod } from 'src/core/test_helpers/kbn_server';

import type { AgentPolicySOAttributes } from '../types';

import { useDockerRegistry } from './docker_registry_helper';

const logFilePath = Path.join(__dirname, 'logs.log');

type Root = ReturnType<typeof kbnTestServer.createRoot>;
Expand Down Expand Up @@ -46,6 +48,8 @@ describe('Fleet preconfiguration reset', () => {
let esServer: kbnTestServer.TestElasticsearchUtils;
let kbnServer: kbnTestServer.TestKibanaUtils;

const registryUrl = useDockerRegistry();

const startServers = async () => {
const { startES } = kbnTestServer.createTestServers({
adjustTimeout: (t) => jest.setTimeout(t),
Expand All @@ -63,6 +67,7 @@ describe('Fleet preconfiguration reset', () => {
{
xpack: {
fleet: {
registryUrl,
packages: [
{
name: 'fleet_server',
Expand Down Expand Up @@ -195,8 +200,7 @@ describe('Fleet preconfiguration reset', () => {
await stopServers();
});

// FLAKY: https://github.com/elastic/kibana/issues/123103
describe.skip('Reset all policy', () => {
describe('Reset all policy', () => {
it('Works and reset all preconfigured policies', async () => {
const resetAPI = getSupertestWithAdminUser(
kbnServer.root,
Expand Down Expand Up @@ -225,9 +229,7 @@ describe('Fleet preconfiguration reset', () => {
});
});

// FLAKY: https://github.com/elastic/kibana/issues/123104
// FLAKY: https://github.com/elastic/kibana/issues/123105
describe.skip('Reset one preconfigured policy', () => {
describe('Reset one preconfigured policy', () => {
const POLICY_ID = 'test-12345';

it('Works and reset one preconfigured policies if the policy is already deleted (with a ghost package policy)', async () => {
Expand Down
Loading

0 comments on commit 1a74b7f

Please sign in to comment.