Skip to content

Commit

Permalink
Merge branch 'main' into unskip-functional-test
Browse files Browse the repository at this point in the history
  • Loading branch information
viduni94 authored Feb 28, 2025
2 parents 72b7b32 + 0a56262 commit c7eae24
Show file tree
Hide file tree
Showing 58 changed files with 3,602 additions and 637 deletions.
663 changes: 566 additions & 97 deletions oas_docs/output/kibana.serverless.yaml

Large diffs are not rendered by default.

663 changes: 566 additions & 97 deletions oas_docs/output/kibana.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ export const SECURITY_SOLUTION_ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING =
'securitySolution:enableVisualizationsInFlyout' as const;
export const SECURITY_SOLUTION_ENABLE_GRAPH_VISUALIZATION_SETTING =
'securitySolution:enableGraphVisualization' as const;
export const SECURITY_SOLUTION_ENABLE_ASSET_INVENTORY_SETTING =
'securitySolution:enableAssetInventory' as const;

// Timelion settings
export const TIMELION_ES_DEFAULT_INDEX_ID = 'timelion:es.default_index';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,44 @@ describe('ruleActionsConnectorsBody', () => {
})
);
});

test('filters out when no connector matched action type id', async () => {
const actionTypeRegistry = new TypeRegistry<ActionTypeModel>();
actionTypeRegistry.register(getActionTypeModel('1', { id: 'actionType-1' }));

useRuleFormState.mockReturnValue({
plugins: {
actionTypeRegistry,
},
formData: {
actions: [],
},
connectors: [
...mockConnectors,
{
id: `connector-foobar-1`,
secrets: { secret: 'secret' },
actionTypeId: `actionType-foobar`,
name: `connector-foobar`,
config: { config: `config-foobar-1` },
isPreconfigured: true,
isSystemAction: false,
isDeprecated: false,
},
],
connectorTypes: mockActionTypes,
aadTemplateFields: [],
selectedRuleType: {
defaultActionGroupId: 'default',
},
});
useRuleFormDispatch.mockReturnValue(mockOnChange);
render(<RuleActionsConnectorsBody onSelectConnector={mockOnSelectConnector} />);

expect(screen.queryByText('connector-foobar')).not.toBeInTheDocument();
expect(screen.queryByText('connector-2')).not.toBeInTheDocument();

expect(await screen.findAllByTestId('ruleActionsConnectorsModalCard')).toHaveLength(1);
expect(await screen.findByText('connector-1')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,18 @@ export const RuleActionsConnectorsBody = ({
const availableConnectors = useMemo(() => {
return connectors.filter(({ actionTypeId }) => {
const actionType = connectorTypes.find(({ id }) => id === actionTypeId);

if (!actionTypeRegistry.has(actionTypeId)) {
return false;
}

const actionTypeModel = actionTypeRegistry.get(actionTypeId);

if (!actionType) {
return false;
}

if (!actionTypeModel.actionParamsFields) {
if (!actionTypeModel?.actionParamsFields) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ export const SECURITY_PROJECT_SETTINGS = [
settings.SECURITY_SOLUTION_DEFAULT_ALERT_TAGS_KEY,
settings.SECURITY_SOLUTION_ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
settings.SECURITY_SOLUTION_ENABLE_GRAPH_VISUALIZATION_SETTING,
settings.SECURITY_SOLUTION_ENABLE_ASSET_INVENTORY_SETTING,
];
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
},
'securitySolution:enableAssetInventory': {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
},
'search:includeFrozen': {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export interface UsageStats {
'securitySolution:enableCcsWarning': boolean;
'securitySolution:enableVisualizationsInFlyout': boolean;
'securitySolution:enableGraphVisualization': boolean;
'securitySolution:enableAssetInventory': boolean;
'search:includeFrozen': boolean;
'courier:maxConcurrentShardRequests': number;
'courier:setRequestPreference': string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export const useDashboardListingTable = ({
options: {
// include only tags references in the response to save bandwidth
includeReferences: ['tag'],
fields: ['title', 'description', 'timeRestore'],
},
})
.then(({ total, hits }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,15 @@ export function registerAPIRoutes({
let result;
try {
// TODO add filtering
({ result } = await client.search({ cursor: page.toString(), limit }));
({ result } = await client.search(
{
cursor: page.toString(),
limit,
},
{
fields: ['title', 'description', 'timeRestore'],
}
));
} catch (e) {
if (e.isBoom && e.output.statusCode === 403) {
return res.forbidden();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ const searchArgsToSOFindOptions = (
return {
type: DASHBOARD_SAVED_OBJECT_TYPE,
searchFields: options?.onlyTitle ? ['title'] : ['title^3', 'description'],
fields: options?.fields ?? ['title', 'description', 'timeRestore'],
fields: options?.fields,
search: query.text,
perPage: query.limit,
page: query.cursor ? +query.cursor : undefined,
defaultSearchOperator: 'AND',
namespaces: options?.spaces,
...tagsToFindOptions(query.tags),
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,14 @@ export const dashboardSearchOptionsSchema = schema.maybe(
kuery: schema.maybe(schema.string()),
cursor: schema.maybe(schema.number()),
limit: schema.maybe(schema.number()),
spaces: schema.maybe(
schema.arrayOf(schema.string(), {
meta: {
description:
'An array of spaces to search or "*" to search all spaces. Defaults to the current space if not specified.',
},
})
),
},
{ unknowns: 'forbid' }
)
Expand Down
8 changes: 6 additions & 2 deletions src/platform/plugins/shared/dashboard/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface StartDeps {
export class DashboardPlugin
implements Plugin<DashboardPluginSetup, DashboardPluginStart, SetupDeps, StartDeps>
{
private contentClient?: ReturnType<ContentManagementServerSetup['register']>['contentClient'];
private readonly logger: Logger;

constructor(private initializerContext: PluginInitializerContext) {
Expand All @@ -64,7 +65,7 @@ export class DashboardPlugin
})
);

plugins.contentManagement.register({
const { contentClient } = plugins.contentManagement.register({
id: CONTENT_ID,
storage: new DashboardStorage({
throwOnResultValidationError: this.initializerContext.env.mode.dev,
Expand All @@ -74,6 +75,7 @@ export class DashboardPlugin
latest: LATEST_VERSION,
},
});
this.contentClient = contentClient;

plugins.contentManagement.favorites.registerFavoriteType('dashboard');

Expand Down Expand Up @@ -136,7 +138,9 @@ export class DashboardPlugin
});
}

return {};
return {
contentClient: this.contentClient,
};
}

public stop() {}
Expand Down
43 changes: 41 additions & 2 deletions src/platform/plugins/shared/dashboard/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,46 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { ContentManagementServerSetup } from '@kbn/content-management-plugin/server';

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DashboardPluginSetup {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DashboardPluginStart {}
export interface DashboardPluginStart {
/**
* Use contentClient.getForRequest to get a scoped client to perform CRUD and search operations for dashboards using the methods available in the {@link DashboardStorage} class.
*
* @example
* Get a dashboard client for the current request
* ```ts
* // dashboardClient is scoped to the current user
* // specifying the version is recommended to return a consistent result
* const dashboardClient = plugins.dashboard.contentClient.getForRequest({ requestHandlerContext, request, version: 3 });
*
* const { search, create, update, delete: deleteDashboard } = dashboardClient;
* ```
*
* @example
* Search using {@link DashboardStorage#search}
* ```ts
* const dashboardList = await search({ text: 'my dashboard' }, { spaces: ['default'] } });
* ```
* @example
* Create a new dashboard using {@link DashboardCreateIn}
* ```ts
* const newDashboard = await create({ attributes: { title: 'My Dashboard' } });
* ```
*
* @example
* Update an existing dashboard using {@link DashboardUpdateIn}
* ```ts
* const updatedDashboard = await update({ id: 'dashboard-id', attributes: { title: 'My Updated Dashboard' } });
* ```
*
* @example
* Delete an existing dashboard using {@link DashboardDeleteIn}
* ```ts
* deleteDashboard({ id: 'dashboard-id' });
* ```
*/
contentClient?: ReturnType<ContentManagementServerSetup['register']>['contentClient'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -10505,6 +10505,12 @@
"description": "Non-default value of setting."
}
},
"securitySolution:enableAssetInventory": {
"type": "boolean",
"_meta": {
"description": "Non-default value of setting."
}
},
"search:includeFrozen": {
"type": "boolean",
"_meta": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,58 @@ export function toSafeColumnName(columnName: unknown): string | undefined {
const safeName = columnName.replace(/[^a-zA-Z0-9_]/g, '_');
return /^[0-9]/.test(safeName) ? `Column${safeName}` : safeName;
}
// Returns the column list from a header row. We skip values that are not strings.

/**
* Extracts column names from the provided header doc by truncating unnecessary columns
* and converting each name into a normalized format.
*
* @param tempColumnNames - The list of temporary column names (integer-based).
* @param headerObject - The processed first document (corresponding to the header row).
* @returns A filtered array of valid column names in a safe format or undefined where the value was neither string nor numbers.
*/
export function columnsFromHeader(
tempColumnNames: string[],
headerObject: { [key: string]: unknown }
): Array<string | undefined> {
return valuesFromHeader(tempColumnNames, headerObject).map(toSafeColumnName);
}

/**
* Extracts values from a header object based on column names, converting non-string/numeric values to undefined.
* The function processes the array up to the last non-undefined value in the header object.
*
* @param tempColumnNames - Array of column names to look up in the header object
* @param headerObject - Object containing header values indexed by column names
* @returns Array of string/number values or undefined for non-string/number values, truncated at the last non-undefined entry
*
* @example
* const columns = ['col1', 'col2', 'col3', 'col4'];
* const header = { col1: 'value1', col2: 123, col3: 'value3', 'col4': null };
* valuesFromHeader(columns, header); // ['value1', 123, 'value3', undefined]
*/
export function valuesFromHeader(
tempColumnNames: string[],
headerObject: { [key: string]: unknown }
): Array<string | number | undefined> {
const maxIndex = tempColumnNames.findLastIndex(
(columnName) => headerObject[columnName] !== undefined
);
return tempColumnNames
.slice(0, maxIndex + 1)
.map((columnName) => headerObject[columnName])
.map(toSafeColumnName);
.map((value) => (typeof value === 'string' || typeof value === 'number' ? value : undefined));
}
// Count the number of columns actually present in the rows.

/**
* Calculates the total number of columns in a CSV by going through the processed
* documents to find the last defined value across all rows.
*
* @param tempColumnNames - An array of column names used to reference CSV row properties.
* @param csvRows - An array of row objects representing CSV data, where each key
* corresponds to a column name from `tempColumnNames`.
* @returns The total number of columns, determined by the position of the last
* defined value across all rows.
*/
export function totalColumnCount(
tempColumnNames: string[],
csvRows: Array<{ [key: string]: unknown }>
Expand Down
Loading

0 comments on commit c7eae24

Please sign in to comment.