Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/elastic/kibana into increas…
Browse files Browse the repository at this point in the history
…e-exceptions-test-coverage
  • Loading branch information
WafaaNasr committed Jun 2, 2023
2 parents ffc405d + a584986 commit c494b59
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export const referenceLineFunction: ReferenceLineFn = {
forAccessor: {
types: ['string'],
help: '',
default: '',
},
},
fn(table, args) {
Expand Down
24 changes: 24 additions & 0 deletions src/plugins/input_control_vis/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { schema, TypeOf } from '@kbn/config-schema';

export const configSchema = schema.object({
readOnly: schema.conditional(
schema.contextRef('serverless'),
true,
schema.maybe(schema.boolean({ defaultValue: false })),
schema.never()
),
});

export type InputControlConfig = TypeOf<typeof configSchema>;

export interface InputControlPublicConfig {
readOnly?: boolean;
}
2 changes: 1 addition & 1 deletion src/plugins/input_control_vis/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Adds Input Control visualization to Kibana",
"plugin": {
"id": "inputControlVis",
"server": false,
"server": true,
"browser": true,
"requiredPlugins": [
"data",
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/input_control_vis/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

import { PluginInitializerContext } from '@kbn/core/public';
import { InputControlVisPlugin as Plugin } from './plugin';
import { InputControlPublicConfig } from '../config';

export function plugin(initializerContext: PluginInitializerContext) {
export function plugin(initializerContext: PluginInitializerContext<InputControlPublicConfig>) {
return new Plugin(initializerContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { toExpressionAst } from './to_ast';
import { InputControlVisParams } from './types';

export function createInputControlVisTypeDefinition(
deps: InputControlVisDependencies
deps: InputControlVisDependencies,
readOnly: boolean
): VisTypeDefinition<InputControlVisParams> {
const ControlsTab = getControlsTab(deps);

Expand All @@ -29,7 +30,8 @@ export function createInputControlVisTypeDefinition(
defaultMessage: 'Input controls are deprecated and will be removed in a future version.',
}),
stage: 'experimental',
disableCreate: true,
disableCreate: true, // input controls are deprecated and input control creation has been permanently disabled
disableEdit: readOnly,
isDeprecated: true,
visConfig: {
defaults: {
Expand Down
6 changes: 4 additions & 2 deletions src/plugins/input_control_vis/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { VisualizationsSetup, VisualizationsStart } from '@kbn/visualizations-pl
import { createInputControlVisFn } from './input_control_fn';
import { getInputControlVisRenderer } from './input_control_vis_renderer';
import { createInputControlVisTypeDefinition } from './input_control_vis_type';
import { InputControlPublicConfig } from '../config';

type InputControlVisCoreSetup = CoreSetup<InputControlVisPluginStartDependencies, void>;

Expand Down Expand Up @@ -51,7 +52,7 @@ export interface InputControlVisPluginStartDependencies {

/** @internal */
export class InputControlVisPlugin implements Plugin<void, void> {
constructor(public initializerContext: PluginInitializerContext) {}
constructor(public initializerContext: PluginInitializerContext<InputControlPublicConfig>) {}

public setup(
core: InputControlVisCoreSetup,
Expand All @@ -69,8 +70,9 @@ export class InputControlVisPlugin implements Plugin<void, void> {

expressions.registerFunction(createInputControlVisFn);
expressions.registerRenderer(getInputControlVisRenderer(visualizationDependencies));
const { readOnly } = this.initializerContext.config.get<InputControlPublicConfig>();
visualizations.createBaseVisualization(
createInputControlVisTypeDefinition(visualizationDependencies)
createInputControlVisTypeDefinition(visualizationDependencies, Boolean(readOnly))
);
}

Expand Down
36 changes: 36 additions & 0 deletions src/plugins/input_control_vis/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { CoreSetup, PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server';
import type { VisualizationsServerSetup } from '@kbn/visualizations-plugin/server';

import { configSchema, InputControlConfig } from '../config';

export const config: PluginConfigDescriptor<InputControlConfig> = {
exposeToBrowser: {
readOnly: true,
},
schema: configSchema,
};

interface PluginSetupDependencies {
visualizations: VisualizationsServerSetup;
}

export const plugin = (initializerContext: PluginInitializerContext) => ({
setup(core: CoreSetup, plugins: PluginSetupDependencies) {
const { readOnly } = initializerContext.config.get<InputControlConfig>();
if (readOnly) {
plugins.visualizations.registerReadOnlyVisType('input_control_vis');
}

return {};
},

start() {},
});
2 changes: 2 additions & 0 deletions src/plugins/input_control_vis/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"include": [
"public/**/*",
"server/**/*",
"*.ts",
],
"kbn_references": [
"@kbn/kibana-react-plugin",
Expand All @@ -21,6 +22,7 @@
"@kbn/expect",
"@kbn/i18n-react",
"@kbn/test-jest-helpers",
"@kbn/config-schema",
],
"exclude": [
"target/**/*",
Expand Down
6 changes: 6 additions & 0 deletions test/functional/page_objects/visualize_chart_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ export class VisualizeChartPageObject extends FtrService {
return items.map(({ name }) => name);
}

public async getReferenceLine(selector: string) {
const items = (await this.getEsChartDebugState(selector))?.annotations;
const referenceLine = items?.filter(({ type }) => type === 'line');
return referenceLine;
}

public async getLegendEntries() {
const isVisTypePieChart = await this.isNewLibraryChart(partitionVisChartSelector);
const isVisTypeHeatmapChart = await this.isNewLibraryChart(heatmapChartSelector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'usageCollection.uiCounters.debug (boolean)',
'usageCollection.uiCounters.enabled (boolean)',
// readOnly is boolean flag
'input_control_vis.readOnly (any)',
'vis_type_gauge.readOnly (any)',
'vis_type_heatmap.readOnly (any)',
'vis_type_metric.readOnly (any)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ describe('fetch indices lib functions', () => {
expect(mockClient.asCurrentUser.indices.get).toHaveBeenCalledWith({
expand_wildcards: ['open'],
features: ['aliases', 'settings'],
filter_path: ['*.aliases', '*.settings.index.hidden'],
filter_path: [
'*.aliases',
'*.settings.index.hidden',
'*.settings.index.verified_before_close',
],
index: '*search*',
});

Expand Down Expand Up @@ -363,7 +367,11 @@ describe('fetch indices lib functions', () => {
expect(mockClient.asCurrentUser.indices.get).toHaveBeenCalledWith({
expand_wildcards: ['hidden', 'all'],
features: ['aliases', 'settings'],
filter_path: ['*.aliases', '*.settings.index.hidden'],
filter_path: [
'*.aliases',
'*.settings.index.hidden',
'*.settings.index.verified_before_close',
],
index: '*',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ export const getIndexDataMapper = (totalIndexData: TotalIndexData) => {
function isHidden(index: IndicesIndexState): boolean {
return index.settings?.index?.hidden === true || index.settings?.index?.hidden === 'true';
}
function isClosed(index: IndicesIndexState): boolean {
return (
index.settings?.index?.verified_before_close === true ||
index.settings?.index?.verified_before_close === 'true'
);
}

export const getIndexData = async (
client: IScopedClusterClient,
Expand All @@ -107,14 +113,19 @@ export const getIndexData = async (
features: ['aliases', 'settings'],
// only get specified index properties from ES to keep the response under 536MB
// node.js string length limit: https://github.com/nodejs/node/issues/33960
filter_path: ['*.aliases', '*.settings.index.hidden'],
filter_path: ['*.aliases', '*.settings.index.hidden', '*.settings.index.verified_before_close'],
index: onlyShowSearchOptimizedIndices ? 'search-*' : indexPattern,
});

const allIndexNames = returnHiddenIndices
? Object.keys(allIndexMatches)
? Object.keys(allIndexMatches).filter(
(indexName) => allIndexMatches[indexName] && !isClosed(allIndexMatches[indexName])
)
: Object.keys(allIndexMatches).filter(
(indexName) => allIndexMatches[indexName] && !isHidden(allIndexMatches[indexName])
(indexName) =>
allIndexMatches[indexName] &&
!isHidden(allIndexMatches[indexName]) &&
!isClosed(allIndexMatches[indexName])
);
const indexNames =
onlyShowSearchOptimizedIndices && searchQuery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Agent } from '../../../../types';

import { createFleetTestRendererMock } from '../../../../../../mock';
import { ExperimentalFeaturesService } from '../../../../services';
import { AgentReassignAgentPolicyModal } from '../../components/agent_reassign_policy_modal';

import { sendGetAgents, sendGetAgentPolicies } from '../../../../hooks';

Expand All @@ -27,6 +28,8 @@ jest.mock('../../../../hooks', () => ({
sendGetAgentPolicies: jest.fn(),
}));

jest.mock('../../components/agent_reassign_policy_modal');

const mockedSendGetAgents = sendGetAgents as jest.Mock;
const mockedSendGetAgentPolicies = sendGetAgentPolicies as jest.Mock;

Expand All @@ -37,6 +40,11 @@ describe('AgentBulkActions', () => {
} as any);
});

beforeEach(() => {
jest.mocked(AgentReassignAgentPolicyModal).mockReset();
jest.mocked(AgentReassignAgentPolicyModal).mockReturnValue(null);
});

function render(props: any) {
const renderer = createFleetTestRendererMock();

Expand Down Expand Up @@ -248,5 +256,119 @@ describe('AgentBulkActions', () => {
results.getByText('Request diagnostics for 8 agents').closest('button')!
).toBeEnabled();
});

it('should generate a correct kuery to select agents', async () => {
mockedSendGetAgentPolicies.mockResolvedValue({
data: {
items: [
{
name: 'Managed agent policy',
namespace: 'default',
description: '',
monitoring_enabled: ['logs', 'metrics'],
is_managed: true,
id: 'test-managed-policy',
},
],
},
});
mockedSendGetAgents.mockResolvedValueOnce({
data: {
items: [],
total: 0,
totalInactive: 0,
},
});
const selectedAgents: Agent[] = [];

const props = {
totalAgents: 10,
totalInactiveAgents: 0,
selectionMode: 'query',
currentQuery: '(Base query)',
selectedAgents,
visibleAgents: [],
refreshAgents: () => undefined,
allTags: [],
agentPolicies: [],
};
const results = render(props);

const bulkActionsButton = results.getByTestId('agentBulkActionsButton');

await act(async () => {
fireEvent.click(bulkActionsButton);
});

expect(results.getByText('Assign to new policy').closest('button')!).toBeEnabled();

await act(async () => {
fireEvent.click(results.getByText('Assign to new policy').closest('button')!);
});

expect(jest.mocked(AgentReassignAgentPolicyModal)).toHaveBeenCalledWith(
expect.objectContaining({
agents: '(Base query)',
}),
expect.anything()
);
});

it('should generate a correct kuery to select agents with managed agents too', async () => {
const selectedAgents: Agent[] = [];
mockedSendGetAgentPolicies.mockResolvedValue({
data: {
items: [
{
name: 'Managed agent policy',
namespace: 'default',
description: '',
monitoring_enabled: ['logs', 'metrics'],
is_managed: true,
id: 'test-managed-policy',
},
],
},
});
mockedSendGetAgents.mockResolvedValueOnce({
data: {
items: [{ id: 'agentId1' }, { id: 'agentId2' }],
total: 2,
totalInactive: 0,
},
});

const props = {
totalAgents: 10,
totalInactiveAgents: 0,
selectionMode: 'query',
currentQuery: '(Base query)',
selectedAgents,
visibleAgents: [],
refreshAgents: () => undefined,
allTags: [],
agentPolicies: [],
};
const results = render(props);

const bulkActionsButton = results.getByTestId('agentBulkActionsButton');

await act(async () => {
fireEvent.click(bulkActionsButton);
});

expect(results.getByText('Assign to new policy').closest('button')!).toBeEnabled();

await act(async () => {
fireEvent.click(results.getByText('Assign to new policy').closest('button')!);
});

expect(jest.mocked(AgentReassignAgentPolicyModal)).toHaveBeenCalledWith(
expect.objectContaining({
agents: '(Base query) AND NOT (fleet-agents.agent.id : ("agentId1" or "agentId2"))',
}),
expect.anything()
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({

// update the query removing the "managed" agents
const selectionQuery = useMemo(() => {
if (managedAgents) {
if (managedAgents.length) {
const excludedKuery = `${AGENTS_PREFIX}.agent.id : (${managedAgents
.map((id) => `"${id}"`)
.join(' or ')})`;
Expand Down
Loading

0 comments on commit c494b59

Please sign in to comment.