Skip to content

Commit

Permalink
Merge branch 'main' into chore/assistant-modal-cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
patrykkopycinski committed May 17, 2024
2 parents e97496f + d87d04c commit 6bca407
Show file tree
Hide file tree
Showing 21 changed files with 331 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { i18n } from '@kbn/i18n';

export interface CopyInputProps {
value: string;
onCopyClick?: React.MouseEventHandler<HTMLAnchorElement>;
}

export const CopyInput: React.FC<CopyInputProps> = ({ value }) => {
export const CopyInput: React.FC<CopyInputProps> = ({ value, onCopyClick }) => {
const textRef = React.useRef<HTMLSpanElement>(null);

return (
Expand Down Expand Up @@ -52,7 +53,10 @@ export const CopyInput: React.FC<CopyInputProps> = ({ value }) => {
<EuiCopy textToCopy={value}>
{(copy) => (
<EuiButtonIcon
onClick={copy}
onClick={(event: React.MouseEvent<HTMLAnchorElement>) => {
onCopyClick?.(event);
copy();
}}
iconType="copyClipboard"
size="m"
color={'text'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import React from 'react';
import { EuiFlyout } from '@elastic/eui';
import { action } from '@storybook/addon-actions';
import {
StoriesProvider,
StoriesProviderKeyCreationError,
Expand All @@ -22,7 +23,7 @@ export default {
export const Default = () => {
return (
<EuiFlyout size="s" onClose={() => {}}>
<StoriesProvider>
<StoriesProvider onTelemetryEvent={action('onTelemetryEvent')}>
<ConnectionDetailsFlyoutContent />
</StoriesProvider>
</EuiFlyout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ConnectionDetails } from './connection_details';
import { useConnectionDetailsOpts } from './context';
import { useConnectionDetailsOpts, useConnectionDetailsService } from './context';
import { Tabs } from './tabs';

export const ConnectionDetailsFlyoutContent: React.FC = () => {
const ctx = useConnectionDetailsOpts();
const service = useConnectionDetailsService();

const header = (
<EuiFlyoutHeader hasBorder>
Expand All @@ -39,7 +40,15 @@ export const ConnectionDetailsFlyoutContent: React.FC = () => {
defaultMessage: 'Connect to the Elasticsearch API by using the following details.',
})}{' '}
{!!ctx.links?.learnMore && (
<EuiLink external href={ctx.links.learnMore} target="_blank">
// Below onClick is used only for telemetry, but `href` is the real
// semantic action.
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink
external
href={ctx.links.learnMore}
target="_blank"
onClick={() => service.emitTelemetryEvent(['learn_more_clicked'])}
>
{i18n.translate('cloud.connectionDetails.learnMoreButtonLabel', {
defaultMessage: 'Learn more',
})}
Expand Down
1 change: 1 addition & 0 deletions packages/cloud/connection_details/kibana/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface ConnectionDetailsGlobalDependencies {
http: CoreStart['http'];
application: CoreStart['application'];
overlays: CoreStart['overlays'];
analytics?: CoreStart['analytics'];
};
plugins: {
cloud?: CloudStart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useAsyncMemo } from '../hooks/use_async_memo';

const createOpts = async (props: KibanaConnectionDetailsProviderProps) => {
const { options, start } = props;
const { http, docLinks } = start.core;
const { http, docLinks, analytics } = start.core;
const locator = start.plugins?.share?.url?.locators.get('MANAGEMENT_APP_LOCATOR');
const manageKeysLink = await locator?.getUrl({ sectionId: 'security', appId: 'api_keys' });
const result: ConnectionDetailsOpts = {
Expand Down Expand Up @@ -68,6 +68,51 @@ const createOpts = async (props: KibanaConnectionDetailsProviderProps) => {
hasPermission: async () => true,
...options?.apiKeys,
},
onTelemetryEvent: (event) => {
if (!analytics) return;
switch (event[0]) {
case 'learn_more_clicked': {
analytics.reportEvent('connection_details_learn_more_clicked', {});
break;
}
case 'tab_switched': {
analytics.reportEvent('connection_details_tab_switched', { tab: event[1]!.tab });
break;
}
case 'copy_endpoint_url_clicked': {
analytics.reportEvent('connection_details_copy_endpoint_url_clicked', {});
break;
}
case 'show_cloud_id_toggled': {
analytics.reportEvent('connection_details_show_cloud_id_toggled', {});
break;
}
case 'copy_cloud_id_clicked': {
analytics.reportEvent('connection_details_copy_cloud_id_clicked', {});
break;
}
case 'new_api_key_created': {
analytics.reportEvent('connection_details_new_api_key_created', {});
break;
}
case 'manage_api_keys_clicked': {
analytics.reportEvent('connection_details_manage_api_keys_clicked', {});
break;
}
case 'key_encoding_changed': {
analytics.reportEvent('connection_details_key_encoding_changed', {
format: event[1]!.format,
});
break;
}
case 'copy_api_key_clicked': {
analytics.reportEvent('connection_details_copy_api_key_clicked', {
format: event[1]!.format,
});
break;
}
}
},
};

return result;
Expand All @@ -83,6 +128,7 @@ export interface KibanaConnectionDetailsProviderProps {
theme: CoreStart['theme'];
http?: CoreStart['http'];
application?: CoreStart['application'];
analytics?: CoreStart['analytics'];
};
plugins?: {
cloud?: CloudStart;
Expand Down
14 changes: 13 additions & 1 deletion packages/cloud/connection_details/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { BehaviorSubject } from 'rxjs';
import { i18n } from '@kbn/i18n';
import { ApiKey } from './tabs/api_keys_tab/views/success_form/types';
import type { Format } from './tabs/api_keys_tab/views/success_form/format_select';
import type { ConnectionDetailsOpts, TabID } from './types';
import type { ConnectionDetailsOpts, TabID, ConnectionDetailsTelemetryEvents } from './types';

export class ConnectionDetailsService {
public readonly tabId$ = new BehaviorSubject<TabID>('endpoints');
Expand Down Expand Up @@ -39,6 +39,7 @@ export class ConnectionDetailsService {
};

public readonly toggleShowCloudId = () => {
this.emitTelemetryEvent(['show_cloud_id_toggled']);
this.showCloudId$.next(!this.showCloudId$.getValue());
};

Expand All @@ -48,6 +49,7 @@ export class ConnectionDetailsService {
};

public readonly setApiKeyFormat = (format: Format) => {
this.emitTelemetryEvent(['key_encoding_changed', { format }]);
this.apiKeyFormat$.next(format);
};

Expand Down Expand Up @@ -76,6 +78,7 @@ export class ConnectionDetailsService {
name: this.apiKeyName$.getValue(),
});
this.apiKey$.next(apiKey);
this.emitTelemetryEvent(['new_api_key_created']);
} catch (error) {
this.apiKeyError$.next(error);
} finally {
Expand All @@ -88,4 +91,13 @@ export class ConnectionDetailsService {
this.apiKeyError$.next(error);
});
};

public readonly emitTelemetryEvent = (event: ConnectionDetailsTelemetryEvents) => {
try {
this.opts.onTelemetryEvent?.(event);
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error emitting telemetry event', error);
}
};
}
11 changes: 9 additions & 2 deletions packages/cloud/connection_details/stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,15 @@ const defaultOpts: ConnectionDetailsOpts = {
},
};

export const StoriesProvider: React.FC = ({ children }) => {
return <ConnectionDetailsOptsProvider {...defaultOpts}>{children}</ConnectionDetailsOptsProvider>;
export const StoriesProvider: React.FC<Partial<ConnectionDetailsOpts>> = ({
children,
...rest
}) => {
return (
<ConnectionDetailsOptsProvider {...{ ...defaultOpts, ...rest }}>
{children}
</ConnectionDetailsOptsProvider>
);
};

export const StoriesProviderKeyCreationError: React.FC = ({ children }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export const ManageKeysLink: React.FC = () => {
return (
<SpaNoRouterLink
url={link}
go={service.opts?.navigateToUrl}
go={() => {
service.emitTelemetryEvent(['manage_api_keys_clicked']);
service.opts?.navigateToUrl?.(link);
}}
data-test-subj={'connectionDetailsManageApiKeysLink'}
>
{i18n.translate('cloud.connectionDetails.apiKeys.managerLinkLabel', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const SuccessForm: React.FC = () => {
apiKey={apiKey}
format={format}
onFormatChange={service.setApiKeyFormat}
onCopyClick={() => service.emitTelemetryEvent(['copy_api_key_clicked', { format }])}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export interface SuccessFormControlledProps {
apiKey: ApiKey;
format: Format;
onFormatChange: (format: Format) => void;
onCopyClick?: () => void;
}

export const SuccessFormControlled: React.FC<SuccessFormControlledProps> = ({
apiKey,
format,
onFormatChange,
onCopyClick,
}) => {
const keyValue = format === 'encoded' ? apiKey.encoded : `${apiKey.id}:${apiKey.key}`;

Expand Down Expand Up @@ -62,7 +64,7 @@ export const SuccessFormControlled: React.FC<SuccessFormControlledProps> = ({
fullWidth
data-test-subj={'connectionDetailsApiKeyValueRow'}
>
<CopyInput value={keyValue} />
<CopyInput value={keyValue} onCopyClick={onCopyClick} />
</EuiFormRow>
</EuiCallOut>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,35 @@

import { EuiForm } from '@elastic/eui';
import * as React from 'react';
import { useConnectionDetailsOpts } from '../../context';
import { useConnectionDetailsOpts, useConnectionDetailsService } from '../../context';
import { useBehaviorSubject } from '../../hooks/use_behavior_subject';
import { CloudIdRow } from './rows/cloud_id_row';
import { EndpointUrlRow } from './rows/endpoints_url_row';

export const EndpointsTab: React.FC = () => {
const { endpoints } = useConnectionDetailsOpts();
const service = useConnectionDetailsService();
const showCloudId = useBehaviorSubject(service.showCloudId$);

if (!endpoints) return null;

return (
<EuiForm component="div">
{!!endpoints?.url && <EndpointUrlRow url={endpoints.url} />}
{!!endpoints?.id && <CloudIdRow value={endpoints.id} />}
{!!endpoints?.url && (
<EndpointUrlRow
url={endpoints.url}
onCopyClick={() => service.emitTelemetryEvent(['copy_endpoint_url_clicked'])}
/>
)}
{!!endpoints?.id && (
<CloudIdRow
value={endpoints.id}
showCloudId={showCloudId}
learnMoreUrl={service.opts.endpoints?.cloudIdLearMoreLink}
onShowCloudIdToggle={service.toggleShowCloudId}
onCopyClick={() => service.emitTelemetryEvent(['copy_cloud_id_clicked'])}
/>
)}
</EuiForm>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ import * as React from 'react';
import { EuiFormRow, EuiSpacer, EuiSwitch } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { CopyInput } from '../../../../components/copy_input';
import { useConnectionDetailsService } from '../../../../context';
import { useBehaviorSubject } from '../../../../hooks/use_behavior_subject';
import { Label } from './label';

export interface CloudIdRowProps {
value: string;
showCloudId: boolean;
learnMoreUrl?: string;
onShowCloudIdToggle: () => void;
onCopyClick?: () => void;
}

export const CloudIdRow: React.FC<CloudIdRowProps> = ({ value }) => {
const service = useConnectionDetailsService();
const showCloudId = useBehaviorSubject(service.showCloudId$);

export const CloudIdRow: React.FC<CloudIdRowProps> = ({
value,
showCloudId,
learnMoreUrl,
onShowCloudIdToggle,
onCopyClick,
}) => {
return (
<>
<EuiSpacer size="l" />
Expand All @@ -31,23 +36,23 @@ export const CloudIdRow: React.FC<CloudIdRowProps> = ({ value }) => {
defaultMessage: 'Show Cloud ID',
})}
checked={showCloudId}
onChange={service.toggleShowCloudId}
onChange={() => onShowCloudIdToggle()}
data-test-subj="connectionDetailsCloudIdSwitch"
/>

{showCloudId && <EuiSpacer size="l" />}

{showCloudId && (
<EuiFormRow
label={<Label learnMoreUrl={service.opts.endpoints?.cloudIdLearMoreLink} />}
label={<Label learnMoreUrl={learnMoreUrl} />}
helpText={i18n.translate('cloud.connectionDetails.tab.endpoints.cloudIdField.helpText', {
defaultMessage:
'Specific client libraries and connectors can use this unique identifier specific to Elastic Cloud.',
})}
fullWidth
data-test-subj="connectionDetailsCloudId"
>
<CopyInput value={value} />
<CopyInput value={value} onCopyClick={() => onCopyClick?.()} />
</EuiFormRow>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import { CopyInput } from '../../../components/copy_input';

export interface EndpointUrlProps {
url: string;
onCopyClick?: () => void;
}

export const EndpointUrlRow: React.FC<EndpointUrlProps> = ({ url }) => {
export const EndpointUrlRow: React.FC<EndpointUrlProps> = ({ url, onCopyClick }) => {
return (
<EuiFormRow
label={i18n.translate('cloud.connectionDetails.tab.endpoints.endpointField.label', {
Expand All @@ -27,7 +28,7 @@ export const EndpointUrlRow: React.FC<EndpointUrlProps> = ({ url }) => {
fullWidth
data-test-subj="connectionDetailsEsUrl"
>
<CopyInput value={url} />
<CopyInput value={url} onCopyClick={() => onCopyClick?.()} />
</EuiFormRow>
);
};

0 comments on commit 6bca407

Please sign in to comment.