+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.title', {
+ defaultMessage: 'Log Retention',
+ })}
+
+
+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.description', {
+ defaultMessage: 'Manage the default write settings for API Logs and Analytics.',
+ })}{' '}
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.learnMore', {
+ defaultMessage: 'Learn more about retention settings.',
+ })}
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.label',
+ {
+ defaultMessage: 'Analytics Logs',
+ }
+ )}
+
+ {': '}
+ {hasILM && (
+
+
+
+ )}
+ >
+ }
+ checked={!!analyticsLogRetentionSettings?.enabled}
+ onChange={() => toggleLogRetention(ELogRetentionOptions.Analytics)}
+ disabled={isLogRetentionUpdating}
+ data-test-subj="LogRetentionPanelAnalyticsSwitch"
+ />
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.label',
+ {
+ defaultMessage: 'API Logs',
+ }
+ )}
+
+ {': '}
+ {hasILM && (
+
+
+
+ )}
+ >
+ }
+ checked={!!apiLogRetentionSettings?.enabled}
+ onChange={() => toggleLogRetention(ELogRetentionOptions.API)}
+ disabled={isLogRetentionUpdating}
+ data-test-subj="LogRetentionPanelAPISwitch"
+ />
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts
new file mode 100644
index 0000000000000..f7f0fbdff1acb
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts
@@ -0,0 +1,119 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+import { ILogRetentionMessages } from './types';
+import { renderLogRetentionDate } from '.';
+
+const ANALYTICS_NO_LOGGING = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging',
+ {
+ defaultMessage: 'Analytics collection has been disabled for all engines.',
+ }
+);
+
+const ANALYTICS_NO_LOGGING_COLLECTED = (disabledAt: string) =>
+ i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging.collected',
+ {
+ defaultMessage: 'The last date analytics were collected was {disabledAt}.',
+ values: { disabledAt },
+ }
+ );
+
+const ANALYTICS_NO_LOGGING_NOT_COLLECTED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging.notCollected',
+ {
+ defaultMessage: 'There are no analytics collected.',
+ }
+);
+
+const ANALYTICS_ILM_DISABLED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.ilmDisabled',
+ {
+ defaultMessage: "App Search isn't managing analytics retention.",
+ }
+);
+
+const ANALYTICS_CUSTOM_POLICY = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.customPolicy',
+ {
+ defaultMessage: 'You have a custom analytics retention policy.',
+ }
+);
+
+const ANALYTICS_STORED = (minAgeDays: number | null | undefined) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.stored', {
+ defaultMessage: 'Your analytics are being stored for at least {minAgeDays} days.',
+ values: { minAgeDays },
+ });
+
+const API_NO_LOGGING = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging',
+ {
+ defaultMessage: 'API logging has been disabled for all engines.',
+ }
+);
+
+const API_NO_LOGGING_COLLECTED = (disabledAt: string) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging.collected', {
+ defaultMessage: 'The last date logs were collected was {disabledAt}.',
+ values: { disabledAt },
+ });
+
+const API_NO_LOGGING_NOT_COLLECTED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging.notCollected',
+ {
+ defaultMessage: 'There are no logs collected.',
+ }
+);
+
+const API_ILM_DISABLED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.ilmDisabled',
+ {
+ defaultMessage: "App Search isn't managing API log retention.",
+ }
+);
+
+const API_CUSTOM_POLICY = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.customPolicy',
+ {
+ defaultMessage: 'You have a custom API log retention policy.',
+ }
+);
+
+const API_STORED = (minAgeDays: number | null | undefined) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.api.stored', {
+ defaultMessage: 'Your logs are being stored for at least {minAgeDays} days.',
+ values: { minAgeDays },
+ });
+
+export const ANALYTICS_MESSAGES: ILogRetentionMessages = {
+ noLogging: (_, logRetentionSettings) =>
+ `${ANALYTICS_NO_LOGGING} ${
+ logRetentionSettings.disabledAt
+ ? ANALYTICS_NO_LOGGING_COLLECTED(renderLogRetentionDate(logRetentionSettings.disabledAt))
+ : ANALYTICS_NO_LOGGING_NOT_COLLECTED
+ }`,
+ ilmDisabled: ANALYTICS_ILM_DISABLED,
+ customPolicy: ANALYTICS_CUSTOM_POLICY,
+ defaultPolicy: (_, logRetentionSettings) =>
+ ANALYTICS_STORED(logRetentionSettings.retentionPolicy?.minAgeDays),
+};
+
+export const API_MESSAGES: ILogRetentionMessages = {
+ noLogging: (_, logRetentionSettings) =>
+ `${API_NO_LOGGING} ${
+ logRetentionSettings.disabledAt
+ ? API_NO_LOGGING_COLLECTED(renderLogRetentionDate(logRetentionSettings.disabledAt))
+ : API_NO_LOGGING_NOT_COLLECTED
+ }`,
+ ilmDisabled: API_ILM_DISABLED,
+ customPolicy: API_CUSTOM_POLICY,
+ defaultPolicy: (_, logRetentionSettings) =>
+ API_STORED(logRetentionSettings.retentionPolicy?.minAgeDays),
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts
new file mode 100644
index 0000000000000..fbc2ccfbc8a52
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts
@@ -0,0 +1,168 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { determineTooltipContent } from './determine_tooltip_content';
+import { ANALYTICS_MESSAGES, API_MESSAGES } from './constants';
+
+describe('determineTooltipContent', () => {
+ const BASE_SETTINGS = {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: null,
+ };
+
+ it('will return nothing if settings are not provided', () => {
+ expect(determineTooltipContent(ANALYTICS_MESSAGES, true)).toBeUndefined();
+ });
+
+ describe('analytics messages', () => {
+ describe('when analytics logs are enabled', () => {
+ describe("and they're using the default policy", () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('Your analytics are being stored for at least 7 days.');
+ });
+ });
+
+ describe('and there is a custom policy', () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: false,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('You have a custom analytics retention policy.');
+ });
+ });
+ });
+
+ describe('when analytics logs are disabled', () => {
+ describe('and there is no disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: null,
+ })
+ ).toEqual(
+ 'Analytics collection has been disabled for all engines. There are no analytics collected.'
+ );
+ });
+ });
+
+ describe('and there is a disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: 'Thu, 05 Nov 2020 18:57:28 +0000',
+ })
+ ).toEqual(
+ 'Analytics collection has been disabled for all engines. The last date analytics were collected was November 5, 2020.'
+ );
+ });
+ });
+ });
+
+ describe('when ilm is disabled entirely', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, false, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ })
+ ).toEqual("App Search isn't managing analytics retention.");
+ });
+ });
+ });
+
+ describe('api messages', () => {
+ describe('when analytics logs are enabled', () => {
+ describe("and they're using the default policy", () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('Your logs are being stored for at least 7 days.');
+ });
+ });
+
+ describe('and there is a custom policy', () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: false,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('You have a custom API log retention policy.');
+ });
+ });
+ });
+
+ describe('when analytics logs are disabled', () => {
+ describe('and there is no disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: null,
+ })
+ ).toEqual('API logging has been disabled for all engines. There are no logs collected.');
+ });
+ });
+
+ describe('and there is a disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: 'Thu, 05 Nov 2020 18:57:28 +0000',
+ })
+ ).toEqual(
+ 'API logging has been disabled for all engines. The last date logs were collected was November 5, 2020.'
+ );
+ });
+ });
+ });
+
+ describe('when ilm is disabled entirely', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, false, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ })
+ ).toEqual("App Search isn't managing API log retention.");
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts
new file mode 100644
index 0000000000000..e361e28490a83
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { ILogRetentionSettings } from '../types';
+import { TMessageStringOrFunction, ILogRetentionMessages } from './types';
+
+export const determineTooltipContent = (
+ messages: ILogRetentionMessages,
+ ilmEnabled: boolean,
+ logRetentionSettings?: ILogRetentionSettings
+) => {
+ if (typeof logRetentionSettings === 'undefined') {
+ return;
+ }
+
+ const renderOrReturnMessage = (message: TMessageStringOrFunction) => {
+ if (typeof message === 'function') {
+ return message(ilmEnabled, logRetentionSettings);
+ }
+ return message;
+ };
+
+ if (!logRetentionSettings.enabled) {
+ return renderOrReturnMessage(messages.noLogging);
+ }
+ if (logRetentionSettings.enabled && !ilmEnabled) {
+ return renderOrReturnMessage(messages.ilmDisabled);
+ }
+ if (
+ logRetentionSettings.enabled &&
+ ilmEnabled &&
+ !logRetentionSettings.retentionPolicy?.isDefault
+ ) {
+ return renderOrReturnMessage(messages.customPolicy);
+ }
+ if (
+ logRetentionSettings.enabled &&
+ ilmEnabled &&
+ logRetentionSettings.retentionPolicy?.isDefault
+ ) {
+ return renderOrReturnMessage(messages.defaultPolicy);
+ }
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx
new file mode 100644
index 0000000000000..b65ffc04ad700
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx
@@ -0,0 +1,74 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import '../../../../../__mocks__/kea.mock';
+import { setMockValues } from '../../../../../__mocks__';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { AnalyticsLogRetentionMessage, ApiLogRetentionMessage, renderLogRetentionDate } from '.';
+
+describe('LogRetentionMessaging', () => {
+ const LOG_RETENTION = {
+ analytics: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ api: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ };
+
+ describe('renderLogRetentionDate', () => {
+ it('renders a formatted date', () => {
+ expect(renderLogRetentionDate('Thu, 05 Nov 2020 18:57:28 +0000')).toEqual('November 5, 2020');
+ });
+ });
+
+ describe('AnalyticsLogRetentionMessage', () => {
+ it('renders', () => {
+ setMockValues({
+ ilmEnabled: true,
+ logRetention: LOG_RETENTION,
+ });
+ const wrapper = shallow(