Skip to content

Commit

Permalink
Merge branch 'main' into 207322_fleetserver_ssl_options
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Feb 28, 2025
2 parents 1641adf + 5c0db3e commit 9d12386
Show file tree
Hide file tree
Showing 31 changed files with 1,774 additions and 1,096 deletions.
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 @@ -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 @@ -73,13 +73,13 @@ export function ConversationList({

const { element: confirmDeleteElement, confirm: confirmDeleteCallback } = useConfirmModal({
title: i18n.translate('xpack.aiAssistant.flyout.confirmDeleteConversationTitle', {
defaultMessage: 'Delete this conversation?',
defaultMessage: 'Delete conversation',
}),
children: i18n.translate('xpack.aiAssistant.flyout.confirmDeleteConversationContent', {
defaultMessage: 'This action cannot be undone.',
defaultMessage: 'This action is permanent and cannot be undone.',
}),
confirmButtonText: i18n.translate('xpack.aiAssistant.flyout.confirmDeleteButtonText', {
defaultMessage: 'Delete conversation',
defaultMessage: 'Delete',
}),
});

Expand Down Expand Up @@ -169,7 +169,15 @@ export function ConversationList({
}
),
onClick: () => {
confirmDeleteCallback().then((confirmed) => {
confirmDeleteCallback(
i18n.translate(
'xpack.aiAssistant.flyout.confirmDeleteCheckboxLabel',
{
defaultMessage: 'Delete "{title}"',
values: { title: conversation.label },
}
)
).then((confirmed) => {
if (!confirmed) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,59 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiConfirmModal } from '@elastic/eui';
import { EuiCheckbox, EuiConfirmModal, EuiText } from '@elastic/eui';
import { useState } from 'react';
import { css } from '@emotion/css';

const ConfirmModal = ({
checkboxLabel,
onClose,
title,
children,
confirmButtonText,
setElement,
}: {
checkboxLabel: string;
onClose: (confirmed: boolean) => void;
title: React.ReactNode;
children: React.ReactNode;
confirmButtonText: React.ReactNode;
setElement: (element: React.ReactNode | undefined) => void;
}) => {
const [isChecked, setIsChecked] = useState(false);

return (
<EuiConfirmModal
title={title}
onConfirm={() => {
onClose(true);
setElement(undefined);
}}
onCancel={() => {
onClose(false);
setElement(undefined);
}}
confirmButtonText={confirmButtonText}
cancelButtonText="Cancel"
buttonColor="danger"
confirmButtonDisabled={!isChecked}
maxWidth
>
<EuiText>{children}</EuiText>
<EuiCheckbox
id="deleteConfirmationCheckbox"
label={checkboxLabel}
checked={isChecked}
onChange={(e) => setIsChecked(e.target.checked)}
className={css`
margin-top: 15px;
`}
/>
</EuiConfirmModal>
);
};

export function useConfirmModal({
title,
Expand All @@ -16,27 +66,26 @@ export function useConfirmModal({
title: React.ReactNode;
children: React.ReactNode;
confirmButtonText: React.ReactNode;
}) {
}): {
element: React.ReactNode | undefined;
confirm: (checkBoxLabel: string) => Promise<boolean>;
} {
const [element, setElement] = useState<React.ReactNode | undefined>(undefined);

const confirm = () => {
const confirm = (checkboxLabel: string) => {
return new Promise<boolean>((resolve) => {
setElement(
<EuiConfirmModal
title={title}
onConfirm={() => {
resolve(true);
setElement(undefined);
}}
onCancel={() => {
resolve(false);
setElement(undefined);
}}
confirmButtonText={confirmButtonText}
>
{children}
</EuiConfirmModal>
);
setElement(() => {
return (
<ConfirmModal
checkboxLabel={checkboxLabel}
onClose={resolve}
title={title}
children={children}
confirmButtonText={confirmButtonText}
setElement={setElement}
/>
);
});
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,12 @@ export const ConfirmSettingsStep = React.memo<ConfirmSettingsStepProps>(
const authOptions = endpointOperation?.prepareSecurity();
const endpointAuth = getAuthDetails(auth, authOptions);

const schemas = reduceSpecComponents(oas, path);
let schemas;
try {
schemas = reduceSpecComponents(oas, path);
} catch (parsingError) {
throw new Error('Error parsing OpenAPI spec for required components');
}

const celRequest: CelInputRequestBody = {
dataStreamTitle: integrationSettings.dataStreamTitle ?? '',
Expand Down Expand Up @@ -273,6 +278,8 @@ export const ConfirmSettingsStep = React.memo<ConfirmSettingsStepProps>(
});

setError(errorMessage);
onUpdateValidation(!!errorMessage);
onUpdateNeedsGeneration(true);
} finally {
setIsFlyoutGenerating(false);
}
Expand All @@ -294,6 +301,7 @@ export const ConfirmSettingsStep = React.memo<ConfirmSettingsStepProps>(
setIsFlyoutGenerating,
reportCelGenerationComplete,
onCelInputGenerationComplete,
onUpdateValidation,
]);

const onCancel = useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ export const UploadSpecStep = React.memo<UploadSpecStepProps>(
e.body ? ` (${e.body.statusCode}): ${e.body.message}` : ''
}`;
setError(errorMessage);
onUpdateValidation(!!errorMessage);
onUpdateNeedsGeneration(true);
} finally {
setIsFlyoutGenerating(false);
}
Expand All @@ -150,6 +152,7 @@ export const UploadSpecStep = React.memo<UploadSpecStepProps>(
setIsFlyoutGenerating,
dataStreamTitle,
onAnalyzeApiGenerationComplete,
onUpdateValidation,
]);

const onCancel = useCallback(() => {
Expand Down
Loading

0 comments on commit 9d12386

Please sign in to comment.