mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Enterprise Search] Log retention settings logic (#82364)
This commit is contained in:
parent
66f7f9c306
commit
d5736b10a9
5 changed files with 636 additions and 0 deletions
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* 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 { resetContext } from 'kea';
|
||||
|
||||
import { mockHttpValues } from '../../../../__mocks__';
|
||||
jest.mock('../../../../shared/http', () => ({
|
||||
HttpLogic: { values: mockHttpValues },
|
||||
}));
|
||||
const { http } = mockHttpValues;
|
||||
|
||||
jest.mock('../../../../shared/flash_messages', () => ({
|
||||
flashAPIErrors: jest.fn(),
|
||||
}));
|
||||
import { flashAPIErrors } from '../../../../shared/flash_messages';
|
||||
|
||||
import { ELogRetentionOptions } from './types';
|
||||
import { LogRetentionLogic } from './log_retention_logic';
|
||||
|
||||
describe('LogRetentionLogic', () => {
|
||||
const TYPICAL_SERVER_LOG_RETENTION = {
|
||||
analytics: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: { is_default: true, min_age_days: 180 },
|
||||
},
|
||||
api: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: { is_default: true, min_age_days: 180 },
|
||||
},
|
||||
};
|
||||
|
||||
const TYPICAL_CLIENT_LOG_RETENTION = {
|
||||
analytics: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: { isDefault: true, minAgeDays: 180 },
|
||||
},
|
||||
api: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: { isDefault: true, minAgeDays: 180 },
|
||||
},
|
||||
};
|
||||
|
||||
const DEFAULT_VALUES = {
|
||||
logRetention: null,
|
||||
openedModal: null,
|
||||
isLogRetentionUpdating: false,
|
||||
};
|
||||
|
||||
const mount = (defaults?: object) => {
|
||||
if (!defaults) {
|
||||
resetContext({});
|
||||
} else {
|
||||
resetContext({
|
||||
defaults: {
|
||||
enterprise_search: {
|
||||
app_search: {
|
||||
log_retention_logic: {
|
||||
...defaults,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
LogRetentionLogic.mount();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('has expected default values', () => {
|
||||
mount();
|
||||
expect(LogRetentionLogic.values).toEqual(DEFAULT_VALUES);
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
describe('setOpenedModal', () => {
|
||||
describe('openedModal', () => {
|
||||
it('should be set to the provided value', () => {
|
||||
mount();
|
||||
|
||||
LogRetentionLogic.actions.setOpenedModal(ELogRetentionOptions.Analytics);
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
openedModal: ELogRetentionOptions.Analytics,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('closeModals', () => {
|
||||
describe('openedModal', () => {
|
||||
it('resets openedModal to null', () => {
|
||||
mount({
|
||||
openedModal: 'analytics',
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.closeModals();
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
openedModal: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLogRetentionUpdating', () => {
|
||||
it('resets isLogRetentionUpdating to false', () => {
|
||||
mount({
|
||||
isLogRetentionUpdating: true,
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.closeModals();
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
isLogRetentionUpdating: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearLogRetentionUpdating', () => {
|
||||
describe('isLogRetentionUpdating', () => {
|
||||
it('resets isLogRetentionUpdating to false', () => {
|
||||
mount({
|
||||
isLogRetentionUpdating: true,
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.clearLogRetentionUpdating();
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
isLogRetentionUpdating: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateLogRetention', () => {
|
||||
describe('logRetention', () => {
|
||||
it('updates the logRetention values that are passed', () => {
|
||||
mount({
|
||||
logRetention: {},
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.updateLogRetention({
|
||||
api: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: null,
|
||||
},
|
||||
analytics: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
logRetention: {
|
||||
api: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: null,
|
||||
},
|
||||
analytics: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveLogRetention', () => {
|
||||
beforeEach(() => {
|
||||
mount();
|
||||
jest.spyOn(LogRetentionLogic.actions, 'clearLogRetentionUpdating');
|
||||
});
|
||||
|
||||
describe('openedModal', () => {
|
||||
it('should be reset to null', () => {
|
||||
mount({
|
||||
openedModal: ELogRetentionOptions.Analytics,
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
openedModal: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('will call an API endpoint and update log retention', async () => {
|
||||
jest.spyOn(LogRetentionLogic.actions, 'updateLogRetention');
|
||||
const promise = Promise.resolve(TYPICAL_SERVER_LOG_RETENTION);
|
||||
http.put.mockReturnValue(promise);
|
||||
|
||||
LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
|
||||
|
||||
expect(http.put).toHaveBeenCalledWith('/api/app_search/log_settings', {
|
||||
body: JSON.stringify({
|
||||
analytics: {
|
||||
enabled: true,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
await promise;
|
||||
expect(LogRetentionLogic.actions.updateLogRetention).toHaveBeenCalledWith(
|
||||
TYPICAL_CLIENT_LOG_RETENTION
|
||||
);
|
||||
|
||||
expect(LogRetentionLogic.actions.clearLogRetentionUpdating).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles errors', async () => {
|
||||
const promise = Promise.reject('An error occured');
|
||||
http.put.mockReturnValue(promise);
|
||||
|
||||
LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
|
||||
|
||||
try {
|
||||
await promise;
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
expect(flashAPIErrors).toHaveBeenCalledWith('An error occured');
|
||||
expect(LogRetentionLogic.actions.clearLogRetentionUpdating).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggleLogRetention', () => {
|
||||
describe('isLogRetentionUpdating', () => {
|
||||
it('sets isLogRetentionUpdating to true', () => {
|
||||
mount({
|
||||
isLogRetentionUpdating: false,
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
isLogRetentionUpdating: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('will call setOpenedModal if already enabled', () => {
|
||||
mount({
|
||||
logRetention: {
|
||||
[ELogRetentionOptions.Analytics]: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
jest.spyOn(LogRetentionLogic.actions, 'setOpenedModal');
|
||||
|
||||
LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
|
||||
|
||||
expect(LogRetentionLogic.actions.setOpenedModal).toHaveBeenCalledWith(
|
||||
ELogRetentionOptions.Analytics
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchLogRetention', () => {
|
||||
describe('isLogRetentionUpdating', () => {
|
||||
it('sets isLogRetentionUpdating to true', () => {
|
||||
mount({
|
||||
isLogRetentionUpdating: false,
|
||||
});
|
||||
|
||||
LogRetentionLogic.actions.fetchLogRetention();
|
||||
|
||||
expect(LogRetentionLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
isLogRetentionUpdating: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('will call an API endpoint and update log retention', async () => {
|
||||
mount();
|
||||
jest.spyOn(LogRetentionLogic.actions, 'clearLogRetentionUpdating');
|
||||
jest
|
||||
.spyOn(LogRetentionLogic.actions, 'updateLogRetention')
|
||||
.mockImplementationOnce(() => {});
|
||||
|
||||
const promise = Promise.resolve(TYPICAL_SERVER_LOG_RETENTION);
|
||||
http.get.mockReturnValue(promise);
|
||||
|
||||
LogRetentionLogic.actions.fetchLogRetention();
|
||||
|
||||
expect(http.get).toHaveBeenCalledWith('/api/app_search/log_settings');
|
||||
await promise;
|
||||
expect(LogRetentionLogic.actions.updateLogRetention).toHaveBeenCalledWith(
|
||||
TYPICAL_CLIENT_LOG_RETENTION
|
||||
);
|
||||
|
||||
expect(LogRetentionLogic.actions.clearLogRetentionUpdating).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles errors', async () => {
|
||||
mount();
|
||||
jest.spyOn(LogRetentionLogic.actions, 'clearLogRetentionUpdating');
|
||||
const promise = Promise.reject('An error occured');
|
||||
http.get.mockReturnValue(promise);
|
||||
|
||||
LogRetentionLogic.actions.fetchLogRetention();
|
||||
|
||||
try {
|
||||
await promise;
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
expect(flashAPIErrors).toHaveBeenCalledWith('An error occured');
|
||||
expect(LogRetentionLogic.actions.clearLogRetentionUpdating).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('will call saveLogRetention if NOT already enabled', () => {
|
||||
mount({
|
||||
logRetention: {
|
||||
[ELogRetentionOptions.Analytics]: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
jest.spyOn(LogRetentionLogic.actions, 'saveLogRetention');
|
||||
|
||||
LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
|
||||
|
||||
expect(LogRetentionLogic.actions.saveLogRetention).toHaveBeenCalledWith(
|
||||
ELogRetentionOptions.Analytics,
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('will do nothing if logRetention option is not yet set', () => {
|
||||
mount({
|
||||
logRetention: {},
|
||||
});
|
||||
jest.spyOn(LogRetentionLogic.actions, 'saveLogRetention');
|
||||
jest.spyOn(LogRetentionLogic.actions, 'setOpenedModal');
|
||||
|
||||
LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.API);
|
||||
|
||||
expect(LogRetentionLogic.actions.saveLogRetention).not.toHaveBeenCalled();
|
||||
expect(LogRetentionLogic.actions.setOpenedModal).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 { kea, MakeLogicType } from 'kea';
|
||||
|
||||
import { ELogRetentionOptions, ILogRetention, ILogRetentionServer } from './types';
|
||||
import { HttpLogic } from '../../../../shared/http';
|
||||
import { flashAPIErrors } from '../../../../shared/flash_messages';
|
||||
import { convertLogRetentionFromServerToClient } from './utils/convert_log_retention';
|
||||
|
||||
interface ILogRetentionActions {
|
||||
clearLogRetentionUpdating(): { value: boolean };
|
||||
closeModals(): { value: boolean };
|
||||
fetchLogRetention(): { value: boolean };
|
||||
saveLogRetention(
|
||||
option: ELogRetentionOptions,
|
||||
enabled: boolean
|
||||
): { option: ELogRetentionOptions; enabled: boolean };
|
||||
setOpenedModal(option: ELogRetentionOptions): { option: ELogRetentionOptions };
|
||||
toggleLogRetention(option: ELogRetentionOptions): { option: ELogRetentionOptions };
|
||||
updateLogRetention(logRetention: ILogRetention): { logRetention: ILogRetention };
|
||||
}
|
||||
|
||||
interface ILogRetentionValues {
|
||||
logRetention: ILogRetention | null;
|
||||
isLogRetentionUpdating: boolean;
|
||||
openedModal: ELogRetentionOptions | null;
|
||||
}
|
||||
|
||||
export const LogRetentionLogic = kea<MakeLogicType<ILogRetentionValues, ILogRetentionActions>>({
|
||||
path: ['enterprise_search', 'app_search', 'log_retention_logic'],
|
||||
actions: () => ({
|
||||
clearLogRetentionUpdating: true,
|
||||
closeModals: true,
|
||||
fetchLogRetention: true,
|
||||
saveLogRetention: (option, enabled) => ({ enabled, option }),
|
||||
setOpenedModal: (option) => ({ option }),
|
||||
toggleLogRetention: (option) => ({ option }),
|
||||
updateLogRetention: (logRetention) => ({ logRetention }),
|
||||
}),
|
||||
reducers: () => ({
|
||||
logRetention: [
|
||||
null,
|
||||
{
|
||||
updateLogRetention: (_, { logRetention }) => logRetention,
|
||||
},
|
||||
],
|
||||
isLogRetentionUpdating: [
|
||||
false,
|
||||
{
|
||||
clearLogRetentionUpdating: () => false,
|
||||
closeModals: () => false,
|
||||
fetchLogRetention: () => true,
|
||||
toggleLogRetention: () => true,
|
||||
},
|
||||
],
|
||||
openedModal: [
|
||||
null,
|
||||
{
|
||||
closeModals: () => null,
|
||||
saveLogRetention: () => null,
|
||||
setOpenedModal: (_, { option }) => option,
|
||||
},
|
||||
],
|
||||
}),
|
||||
listeners: ({ actions, values }) => ({
|
||||
fetchLogRetention: async () => {
|
||||
try {
|
||||
const { http } = HttpLogic.values;
|
||||
const response = await http.get('/api/app_search/log_settings');
|
||||
actions.updateLogRetention(
|
||||
convertLogRetentionFromServerToClient(response as ILogRetentionServer)
|
||||
);
|
||||
} catch (e) {
|
||||
flashAPIErrors(e);
|
||||
} finally {
|
||||
actions.clearLogRetentionUpdating();
|
||||
}
|
||||
},
|
||||
saveLogRetention: async ({ enabled, option }) => {
|
||||
const updateData = { [option]: { enabled } };
|
||||
|
||||
try {
|
||||
const { http } = HttpLogic.values;
|
||||
const response = await http.put('/api/app_search/log_settings', {
|
||||
body: JSON.stringify(updateData),
|
||||
});
|
||||
actions.updateLogRetention(
|
||||
convertLogRetentionFromServerToClient(response as ILogRetentionServer)
|
||||
);
|
||||
} catch (e) {
|
||||
flashAPIErrors(e);
|
||||
} finally {
|
||||
actions.clearLogRetentionUpdating();
|
||||
}
|
||||
},
|
||||
toggleLogRetention: ({ option }) => {
|
||||
const logRetention = values.logRetention?.[option];
|
||||
|
||||
// If the user has found a way to call this before we've retrieved
|
||||
// log retention settings from the server, short circuit this and return early
|
||||
if (!logRetention) {
|
||||
return;
|
||||
}
|
||||
|
||||
const optionIsAlreadyEnabled = logRetention.enabled;
|
||||
if (optionIsAlreadyEnabled) {
|
||||
actions.setOpenedModal(option);
|
||||
} else {
|
||||
actions.saveLogRetention(option, true);
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export enum ELogRetentionOptions {
|
||||
Analytics = 'analytics',
|
||||
API = 'api',
|
||||
}
|
||||
|
||||
export interface ILogRetention {
|
||||
[ELogRetentionOptions.Analytics]: ILogRetentionSettings;
|
||||
[ELogRetentionOptions.API]: ILogRetentionSettings;
|
||||
}
|
||||
|
||||
export interface ILogRetentionPolicy {
|
||||
isDefault: boolean;
|
||||
minAgeDays: number | null;
|
||||
}
|
||||
|
||||
export interface ILogRetentionSettings {
|
||||
disabledAt?: string | null;
|
||||
enabled?: boolean;
|
||||
retentionPolicy?: ILogRetentionPolicy | null;
|
||||
}
|
||||
|
||||
export interface ILogRetentionServer {
|
||||
[ELogRetentionOptions.Analytics]: ILogRetentionServerSettings;
|
||||
[ELogRetentionOptions.API]: ILogRetentionServerSettings;
|
||||
}
|
||||
|
||||
export interface ILogRetentionServerPolicy {
|
||||
is_default: boolean;
|
||||
min_age_days: number | null;
|
||||
}
|
||||
|
||||
export interface ILogRetentionServerSettings {
|
||||
disabled_at: string | null;
|
||||
enabled: boolean;
|
||||
retention_policy: ILogRetentionServerPolicy | null;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 { convertLogRetentionFromServerToClient } from './convert_log_retention';
|
||||
|
||||
describe('convertLogRetentionFromServerToClient', () => {
|
||||
it('converts log retention from server to client', () => {
|
||||
expect(
|
||||
convertLogRetentionFromServerToClient({
|
||||
analytics: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: { is_default: true, min_age_days: 180 },
|
||||
},
|
||||
api: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: { is_default: true, min_age_days: 180 },
|
||||
},
|
||||
})
|
||||
).toEqual({
|
||||
analytics: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: { isDefault: true, minAgeDays: 180 },
|
||||
},
|
||||
api: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: { isDefault: true, minAgeDays: 180 },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('handles null retention policies and null min_age_days', () => {
|
||||
expect(
|
||||
convertLogRetentionFromServerToClient({
|
||||
analytics: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: null,
|
||||
},
|
||||
api: {
|
||||
disabled_at: null,
|
||||
enabled: true,
|
||||
retention_policy: { is_default: true, min_age_days: null },
|
||||
},
|
||||
})
|
||||
).toEqual({
|
||||
analytics: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: null,
|
||||
},
|
||||
api: {
|
||||
disabledAt: null,
|
||||
enabled: true,
|
||||
retentionPolicy: { isDefault: true, minAgeDays: null },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 {
|
||||
ELogRetentionOptions,
|
||||
ILogRetention,
|
||||
ILogRetentionPolicy,
|
||||
ILogRetentionServer,
|
||||
ILogRetentionServerPolicy,
|
||||
ILogRetentionServerSettings,
|
||||
ILogRetentionSettings,
|
||||
} from '../types';
|
||||
|
||||
export const convertLogRetentionFromServerToClient = (
|
||||
logRetention: ILogRetentionServer
|
||||
): ILogRetention => ({
|
||||
[ELogRetentionOptions.Analytics]: convertLogRetentionSettingsFromServerToClient(
|
||||
logRetention[ELogRetentionOptions.Analytics]
|
||||
),
|
||||
[ELogRetentionOptions.API]: convertLogRetentionSettingsFromServerToClient(
|
||||
logRetention[ELogRetentionOptions.API]
|
||||
),
|
||||
});
|
||||
|
||||
const convertLogRetentionSettingsFromServerToClient = ({
|
||||
disabled_at: disabledAt,
|
||||
enabled,
|
||||
retention_policy: retentionPolicy,
|
||||
}: ILogRetentionServerSettings): ILogRetentionSettings => ({
|
||||
disabledAt,
|
||||
enabled,
|
||||
retentionPolicy:
|
||||
retentionPolicy === null ? null : convertLogRetentionPolicyFromServerToClient(retentionPolicy),
|
||||
});
|
||||
|
||||
const convertLogRetentionPolicyFromServerToClient = ({
|
||||
min_age_days: minAgeDays,
|
||||
is_default: isDefault,
|
||||
}: ILogRetentionServerPolicy): ILogRetentionPolicy => ({
|
||||
isDefault,
|
||||
minAgeDays,
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue