Improve extend search session UI (#89126)
* Fix extend search session UI * code review
This commit is contained in:
parent
1994c5bfd9
commit
de44af3eeb
|
@ -66,8 +66,8 @@ export class DataEnhancedPlugin
|
||||||
|
|
||||||
this.config = this.initializerContext.config.get<ConfigSchema>();
|
this.config = this.initializerContext.config.get<ConfigSchema>();
|
||||||
if (this.config.search.sessions.enabled) {
|
if (this.config.search.sessions.enabled) {
|
||||||
const { management: sessionsMgmtConfig } = this.config.search.sessions;
|
const sessionsConfig = this.config.search.sessions;
|
||||||
registerSearchSessionsMgmt(core, sessionsMgmtConfig, { management });
|
registerSearchSessionsMgmt(core, sessionsConfig, { management });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import type {
|
||||||
AppDependencies,
|
AppDependencies,
|
||||||
IManagementSectionsPluginsSetup,
|
IManagementSectionsPluginsSetup,
|
||||||
IManagementSectionsPluginsStart,
|
IManagementSectionsPluginsStart,
|
||||||
SessionsMgmtConfigSchema,
|
SessionsConfigSchema,
|
||||||
} from '../';
|
} from '../';
|
||||||
import { APP } from '../';
|
import { APP } from '../';
|
||||||
import { SearchSessionsMgmtAPI } from '../lib/api';
|
import { SearchSessionsMgmtAPI } from '../lib/api';
|
||||||
|
@ -20,7 +20,7 @@ import { renderApp } from './render';
|
||||||
export class SearchSessionsMgmtApp {
|
export class SearchSessionsMgmtApp {
|
||||||
constructor(
|
constructor(
|
||||||
private coreSetup: CoreSetup<IManagementSectionsPluginsStart>,
|
private coreSetup: CoreSetup<IManagementSectionsPluginsStart>,
|
||||||
private config: SessionsMgmtConfigSchema,
|
private config: SessionsConfigSchema,
|
||||||
private params: ManagementAppMountParams,
|
private params: ManagementAppMountParams,
|
||||||
private pluginsSetup: IManagementSectionsPluginsSetup
|
private pluginsSetup: IManagementSectionsPluginsSetup
|
||||||
) {}
|
) {}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { Duration } from 'moment';
|
||||||
|
import moment from 'moment';
|
||||||
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
||||||
import { TableText } from '../';
|
import { TableText } from '../';
|
||||||
import { OnActionComplete } from './types';
|
import { OnActionComplete } from './types';
|
||||||
|
@ -15,6 +17,8 @@ import { OnActionComplete } from './types';
|
||||||
interface ExtendButtonProps {
|
interface ExtendButtonProps {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
expires: string | null;
|
||||||
|
extendBy: Duration;
|
||||||
api: SearchSessionsMgmtAPI;
|
api: SearchSessionsMgmtAPI;
|
||||||
onActionComplete: OnActionComplete;
|
onActionComplete: OnActionComplete;
|
||||||
}
|
}
|
||||||
|
@ -23,8 +27,11 @@ const ExtendConfirm = ({
|
||||||
onConfirmDismiss,
|
onConfirmDismiss,
|
||||||
...props
|
...props
|
||||||
}: ExtendButtonProps & { onConfirmDismiss: () => void }) => {
|
}: ExtendButtonProps & { onConfirmDismiss: () => void }) => {
|
||||||
const { id, name, api, onActionComplete } = props;
|
const { id, name, expires, api, extendBy, onActionComplete } = props;
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const extendByDuration = moment.duration(extendBy);
|
||||||
|
|
||||||
|
const newExpiration = moment(expires).add(extendByDuration);
|
||||||
|
|
||||||
const title = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.title', {
|
const title = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.title', {
|
||||||
defaultMessage: 'Extend search session expiration',
|
defaultMessage: 'Extend search session expiration',
|
||||||
|
@ -36,9 +43,10 @@ const ExtendConfirm = ({
|
||||||
defaultMessage: 'Cancel',
|
defaultMessage: 'Cancel',
|
||||||
});
|
});
|
||||||
const message = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.extendMessage', {
|
const message = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.extendMessage', {
|
||||||
defaultMessage: "When would you like the search session '{name}' to expire?",
|
defaultMessage: "The search session '{name}' expiration would be extended until {newExpires}.",
|
||||||
values: {
|
values: {
|
||||||
name,
|
name,
|
||||||
|
newExpires: newExpiration.toLocaleString(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -49,7 +57,7 @@ const ExtendConfirm = ({
|
||||||
onCancel={onConfirmDismiss}
|
onCancel={onConfirmDismiss}
|
||||||
onConfirm={async () => {
|
onConfirm={async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await api.sendExtend(id, '1');
|
await api.sendExtend(id, `${extendByDuration.asMilliseconds()}ms`);
|
||||||
onActionComplete();
|
onActionComplete();
|
||||||
}}
|
}}
|
||||||
confirmButtonText={confirm}
|
confirmButtonText={confirm}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { ACTION, OnActionComplete } from './types';
|
||||||
export const getAction = (
|
export const getAction = (
|
||||||
api: SearchSessionsMgmtAPI,
|
api: SearchSessionsMgmtAPI,
|
||||||
actionType: string,
|
actionType: string,
|
||||||
{ id, name, reloadUrl }: UISession,
|
{ id, name, expires, reloadUrl }: UISession,
|
||||||
onActionComplete: OnActionComplete
|
onActionComplete: OnActionComplete
|
||||||
): IClickActionDescriptor | null => {
|
): IClickActionDescriptor | null => {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
|
@ -39,7 +39,16 @@ export const getAction = (
|
||||||
return {
|
return {
|
||||||
iconType: extendSessionIcon,
|
iconType: extendSessionIcon,
|
||||||
textColor: 'default',
|
textColor: 'default',
|
||||||
label: <ExtendButton api={api} id={id} name={name} onActionComplete={onActionComplete} />,
|
label: (
|
||||||
|
<ExtendButton
|
||||||
|
api={api}
|
||||||
|
id={id}
|
||||||
|
name={name}
|
||||||
|
expires={expires}
|
||||||
|
extendBy={api.getExtendByDuration()}
|
||||||
|
onActionComplete={onActionComplete}
|
||||||
|
/>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -12,7 +12,7 @@ import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { coreMock } from 'src/core/public/mocks';
|
import { coreMock } from 'src/core/public/mocks';
|
||||||
import { SessionsClient } from 'src/plugins/data/public/search';
|
import { SessionsClient } from 'src/plugins/data/public/search';
|
||||||
import { SessionsMgmtConfigSchema } from '..';
|
import { SessionsConfigSchema } from '..';
|
||||||
import { SearchSessionsMgmtAPI } from '../lib/api';
|
import { SearchSessionsMgmtAPI } from '../lib/api';
|
||||||
import { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
import { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
||||||
import { LocaleWrapper, mockUrls } from '../__mocks__';
|
import { LocaleWrapper, mockUrls } from '../__mocks__';
|
||||||
|
@ -20,7 +20,7 @@ import { SearchSessionsMgmtMain } from './main';
|
||||||
|
|
||||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||||
let mockCoreStart: MockedKeys<CoreStart>;
|
let mockCoreStart: MockedKeys<CoreStart>;
|
||||||
let mockConfig: SessionsMgmtConfigSchema;
|
let mockConfig: SessionsConfigSchema;
|
||||||
let sessionsClient: SessionsClient;
|
let sessionsClient: SessionsClient;
|
||||||
let api: SearchSessionsMgmtAPI;
|
let api: SearchSessionsMgmtAPI;
|
||||||
|
|
||||||
|
@ -29,11 +29,14 @@ describe('Background Search Session Management Main', () => {
|
||||||
mockCoreSetup = coreMock.createSetup();
|
mockCoreSetup = coreMock.createSetup();
|
||||||
mockCoreStart = coreMock.createStart();
|
mockCoreStart = coreMock.createStart();
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
expiresSoonWarning: moment.duration(1, 'days'),
|
defaultExpiration: moment.duration('7d'),
|
||||||
maxSessions: 2000,
|
management: {
|
||||||
refreshInterval: moment.duration(1, 'seconds'),
|
expiresSoonWarning: moment.duration(1, 'days'),
|
||||||
refreshTimeout: moment.duration(10, 'minutes'),
|
maxSessions: 2000,
|
||||||
};
|
refreshInterval: moment.duration(1, 'seconds'),
|
||||||
|
refreshTimeout: moment.duration(10, 'minutes'),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import type { CoreStart, HttpStart } from 'kibana/public';
|
import type { CoreStart, HttpStart } from 'kibana/public';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type { SessionsMgmtConfigSchema } from '../';
|
import type { SessionsConfigSchema } from '../';
|
||||||
import type { SearchSessionsMgmtAPI } from '../lib/api';
|
import type { SearchSessionsMgmtAPI } from '../lib/api';
|
||||||
import type { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
import type { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
||||||
import { TableText } from './';
|
import { TableText } from './';
|
||||||
|
@ -29,7 +29,7 @@ interface Props {
|
||||||
api: SearchSessionsMgmtAPI;
|
api: SearchSessionsMgmtAPI;
|
||||||
http: HttpStart;
|
http: HttpStart;
|
||||||
timezone: string;
|
timezone: string;
|
||||||
config: SessionsMgmtConfigSchema;
|
config: SessionsConfigSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SearchSessionsMgmtMain({ documentation, ...tableProps }: Props) {
|
export function SearchSessionsMgmtMain({ documentation, ...tableProps }: Props) {
|
||||||
|
|
|
@ -13,14 +13,14 @@ import React from 'react';
|
||||||
import { coreMock } from 'src/core/public/mocks';
|
import { coreMock } from 'src/core/public/mocks';
|
||||||
import { SessionsClient } from 'src/plugins/data/public/search';
|
import { SessionsClient } from 'src/plugins/data/public/search';
|
||||||
import { SearchSessionStatus } from '../../../../../common/search';
|
import { SearchSessionStatus } from '../../../../../common/search';
|
||||||
import { SessionsMgmtConfigSchema } from '../../';
|
import { SessionsConfigSchema } from '../../';
|
||||||
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
||||||
import { LocaleWrapper, mockUrls } from '../../__mocks__';
|
import { LocaleWrapper, mockUrls } from '../../__mocks__';
|
||||||
import { SearchSessionsMgmtTable } from './table';
|
import { SearchSessionsMgmtTable } from './table';
|
||||||
|
|
||||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||||
let mockCoreStart: CoreStart;
|
let mockCoreStart: CoreStart;
|
||||||
let mockConfig: SessionsMgmtConfigSchema;
|
let mockConfig: SessionsConfigSchema;
|
||||||
let sessionsClient: SessionsClient;
|
let sessionsClient: SessionsClient;
|
||||||
let api: SearchSessionsMgmtAPI;
|
let api: SearchSessionsMgmtAPI;
|
||||||
|
|
||||||
|
@ -29,11 +29,14 @@ describe('Background Search Session Management Table', () => {
|
||||||
mockCoreSetup = coreMock.createSetup();
|
mockCoreSetup = coreMock.createSetup();
|
||||||
mockCoreStart = coreMock.createStart();
|
mockCoreStart = coreMock.createStart();
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
expiresSoonWarning: moment.duration(1, 'days'),
|
defaultExpiration: moment.duration('7d'),
|
||||||
maxSessions: 2000,
|
management: {
|
||||||
refreshInterval: moment.duration(1, 'seconds'),
|
expiresSoonWarning: moment.duration(1, 'days'),
|
||||||
refreshTimeout: moment.duration(10, 'minutes'),
|
maxSessions: 2000,
|
||||||
};
|
refreshInterval: moment.duration(1, 'seconds'),
|
||||||
|
refreshTimeout: moment.duration(10, 'minutes'),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||||
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
||||||
|
@ -134,7 +137,10 @@ describe('Background Search Session Management Table', () => {
|
||||||
sessionsClient.find = jest.fn();
|
sessionsClient.find = jest.fn();
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
...mockConfig,
|
...mockConfig,
|
||||||
refreshInterval: moment.duration(10, 'seconds'),
|
management: {
|
||||||
|
...mockConfig.management,
|
||||||
|
refreshInterval: moment.duration(10, 'seconds'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
@ -162,8 +168,11 @@ describe('Background Search Session Management Table', () => {
|
||||||
|
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
...mockConfig,
|
...mockConfig,
|
||||||
refreshInterval: moment.duration(1, 'day'),
|
management: {
|
||||||
refreshTimeout: moment.duration(2, 'days'),
|
...mockConfig.management,
|
||||||
|
refreshInterval: moment.duration(1, 'day'),
|
||||||
|
refreshTimeout: moment.duration(2, 'days'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import React, { useCallback, useMemo, useRef, useEffect, useState } from 'react'
|
||||||
import useDebounce from 'react-use/lib/useDebounce';
|
import useDebounce from 'react-use/lib/useDebounce';
|
||||||
import useInterval from 'react-use/lib/useInterval';
|
import useInterval from 'react-use/lib/useInterval';
|
||||||
import { TableText } from '../';
|
import { TableText } from '../';
|
||||||
import { SessionsMgmtConfigSchema } from '../..';
|
import { SessionsConfigSchema } from '../..';
|
||||||
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
||||||
import { getColumns } from '../../lib/get_columns';
|
import { getColumns } from '../../lib/get_columns';
|
||||||
import { UISession } from '../../types';
|
import { UISession } from '../../types';
|
||||||
|
@ -26,7 +26,7 @@ interface Props {
|
||||||
core: CoreStart;
|
core: CoreStart;
|
||||||
api: SearchSessionsMgmtAPI;
|
api: SearchSessionsMgmtAPI;
|
||||||
timezone: string;
|
timezone: string;
|
||||||
config: SessionsMgmtConfigSchema;
|
config: SessionsConfigSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SearchSessionsMgmtTable({ core, api, timezone, config, ...props }: Props) {
|
export function SearchSessionsMgmtTable({ core, api, timezone, config, ...props }: Props) {
|
||||||
|
@ -35,9 +35,10 @@ export function SearchSessionsMgmtTable({ core, api, timezone, config, ...props
|
||||||
const [debouncedIsLoading, setDebouncedIsLoading] = useState(false);
|
const [debouncedIsLoading, setDebouncedIsLoading] = useState(false);
|
||||||
const [pagination, setPagination] = useState({ pageIndex: 0 });
|
const [pagination, setPagination] = useState({ pageIndex: 0 });
|
||||||
const showLatestResultsHandler = useRef<Function>();
|
const showLatestResultsHandler = useRef<Function>();
|
||||||
const refreshInterval = useMemo(() => moment.duration(config.refreshInterval).asMilliseconds(), [
|
const refreshInterval = useMemo(
|
||||||
config.refreshInterval,
|
() => moment.duration(config.management.refreshInterval).asMilliseconds(),
|
||||||
]);
|
[config.management.refreshInterval]
|
||||||
|
);
|
||||||
|
|
||||||
// Debounce rendering the state of the Refresh button
|
// Debounce rendering the state of the Refresh button
|
||||||
useDebounce(
|
useDebounce(
|
||||||
|
|
|
@ -33,7 +33,7 @@ export interface AppDependencies {
|
||||||
api: SearchSessionsMgmtAPI;
|
api: SearchSessionsMgmtAPI;
|
||||||
http: HttpStart;
|
http: HttpStart;
|
||||||
i18n: I18nStart;
|
i18n: I18nStart;
|
||||||
config: SessionsMgmtConfigSchema;
|
config: SessionsConfigSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const APP = {
|
export const APP = {
|
||||||
|
@ -44,11 +44,11 @@ export const APP = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SessionsMgmtConfigSchema = ConfigSchema['search']['sessions']['management'];
|
export type SessionsConfigSchema = ConfigSchema['search']['sessions'];
|
||||||
|
|
||||||
export function registerSearchSessionsMgmt(
|
export function registerSearchSessionsMgmt(
|
||||||
coreSetup: CoreSetup<DataEnhancedStartDependencies>,
|
coreSetup: CoreSetup<DataEnhancedStartDependencies>,
|
||||||
config: SessionsMgmtConfigSchema,
|
config: SessionsConfigSchema,
|
||||||
services: IManagementSectionsPluginsSetup
|
services: IManagementSectionsPluginsSetup
|
||||||
) {
|
) {
|
||||||
services.management.sections.section.kibana.registerApp({
|
services.management.sections.section.kibana.registerApp({
|
||||||
|
|
|
@ -11,14 +11,14 @@ import { coreMock } from 'src/core/public/mocks';
|
||||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||||
import type { SavedObjectsFindResponse } from 'src/core/server';
|
import type { SavedObjectsFindResponse } from 'src/core/server';
|
||||||
import { SessionsClient } from 'src/plugins/data/public/search';
|
import { SessionsClient } from 'src/plugins/data/public/search';
|
||||||
import type { SessionsMgmtConfigSchema } from '../';
|
import type { SessionsConfigSchema } from '../';
|
||||||
import { SearchSessionStatus } from '../../../../common/search';
|
import { SearchSessionStatus } from '../../../../common/search';
|
||||||
import { mockUrls } from '../__mocks__';
|
import { mockUrls } from '../__mocks__';
|
||||||
import { SearchSessionsMgmtAPI } from './api';
|
import { SearchSessionsMgmtAPI } from './api';
|
||||||
|
|
||||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||||
let mockCoreStart: MockedKeys<CoreStart>;
|
let mockCoreStart: MockedKeys<CoreStart>;
|
||||||
let mockConfig: SessionsMgmtConfigSchema;
|
let mockConfig: SessionsConfigSchema;
|
||||||
let sessionsClient: SessionsClient;
|
let sessionsClient: SessionsClient;
|
||||||
|
|
||||||
describe('Search Sessions Management API', () => {
|
describe('Search Sessions Management API', () => {
|
||||||
|
@ -26,11 +26,14 @@ describe('Search Sessions Management API', () => {
|
||||||
mockCoreSetup = coreMock.createSetup();
|
mockCoreSetup = coreMock.createSetup();
|
||||||
mockCoreStart = coreMock.createStart();
|
mockCoreStart = coreMock.createStart();
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
expiresSoonWarning: moment.duration('1d'),
|
defaultExpiration: moment.duration('7d'),
|
||||||
maxSessions: 2000,
|
management: {
|
||||||
refreshInterval: moment.duration('1s'),
|
expiresSoonWarning: moment.duration(1, 'days'),
|
||||||
refreshTimeout: moment.duration('10m'),
|
maxSessions: 2000,
|
||||||
};
|
refreshInterval: moment.duration(1, 'seconds'),
|
||||||
|
refreshTimeout: moment.duration(10, 'minutes'),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||||
});
|
});
|
||||||
|
@ -93,8 +96,11 @@ describe('Search Sessions Management API', () => {
|
||||||
test('handle timeout error', async () => {
|
test('handle timeout error', async () => {
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
...mockConfig,
|
...mockConfig,
|
||||||
refreshInterval: moment.duration(1, 'hours'),
|
management: {
|
||||||
refreshTimeout: moment.duration(1, 'seconds'),
|
...mockConfig.management,
|
||||||
|
refreshInterval: moment.duration(1, 'hours'),
|
||||||
|
refreshTimeout: moment.duration(1, 'seconds'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
sessionsClient.find = jest.fn().mockImplementation(async () => {
|
sessionsClient.find = jest.fn().mockImplementation(async () => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import moment from 'moment';
|
||||||
import { from, race, timer } from 'rxjs';
|
import { from, race, timer } from 'rxjs';
|
||||||
import { mapTo, tap } from 'rxjs/operators';
|
import { mapTo, tap } from 'rxjs/operators';
|
||||||
import type { SharePluginStart } from 'src/plugins/share/public';
|
import type { SharePluginStart } from 'src/plugins/share/public';
|
||||||
import { SessionsMgmtConfigSchema } from '../';
|
import { SessionsConfigSchema } from '../';
|
||||||
import type { ISessionsClient } from '../../../../../../../src/plugins/data/public';
|
import type { ISessionsClient } from '../../../../../../../src/plugins/data/public';
|
||||||
import type { SearchSessionSavedObjectAttributes } from '../../../../common';
|
import type { SearchSessionSavedObjectAttributes } from '../../../../common';
|
||||||
import { SearchSessionStatus } from '../../../../common/search';
|
import { SearchSessionStatus } from '../../../../common/search';
|
||||||
|
@ -47,10 +47,9 @@ async function getUrlFromState(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: factory for a function to map server objects to UI objects
|
// Helper: factory for a function to map server objects to UI objects
|
||||||
const mapToUISession = (
|
const mapToUISession = (urls: UrlGeneratorsStart, config: SessionsConfigSchema) => async (
|
||||||
urls: UrlGeneratorsStart,
|
savedObject: SavedObject<SearchSessionSavedObjectAttributes>
|
||||||
{ expiresSoonWarning }: SessionsMgmtConfigSchema
|
): Promise<UISession> => {
|
||||||
) => async (savedObject: SavedObject<SearchSessionSavedObjectAttributes>): Promise<UISession> => {
|
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
appId,
|
appId,
|
||||||
|
@ -92,7 +91,7 @@ interface SearcgSessuibManagementDeps {
|
||||||
export class SearchSessionsMgmtAPI {
|
export class SearchSessionsMgmtAPI {
|
||||||
constructor(
|
constructor(
|
||||||
private sessionsClient: ISessionsClient,
|
private sessionsClient: ISessionsClient,
|
||||||
private config: SessionsMgmtConfigSchema,
|
private config: SessionsConfigSchema,
|
||||||
private deps: SearcgSessuibManagementDeps
|
private deps: SearcgSessuibManagementDeps
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -101,12 +100,14 @@ export class SearchSessionsMgmtAPI {
|
||||||
saved_objects: object[];
|
saved_objects: object[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshTimeout = moment.duration(this.config.refreshTimeout);
|
const mgmtConfig = this.config.management;
|
||||||
|
|
||||||
|
const refreshTimeout = moment.duration(mgmtConfig.refreshTimeout);
|
||||||
|
|
||||||
const fetch$ = from(
|
const fetch$ = from(
|
||||||
this.sessionsClient.find({
|
this.sessionsClient.find({
|
||||||
page: 1,
|
page: 1,
|
||||||
perPage: this.config.maxSessions,
|
perPage: mgmtConfig.maxSessions,
|
||||||
sortField: 'created',
|
sortField: 'created',
|
||||||
sortOrder: 'asc',
|
sortOrder: 'asc',
|
||||||
})
|
})
|
||||||
|
@ -149,6 +150,10 @@ export class SearchSessionsMgmtAPI {
|
||||||
this.deps.application.navigateToUrl(reloadUrl);
|
this.deps.application.navigateToUrl(reloadUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getExtendByDuration() {
|
||||||
|
return this.config.defaultExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel and expire
|
// Cancel and expire
|
||||||
public async sendCancel(id: string): Promise<void> {
|
public async sendCancel(id: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import moment from 'moment';
|
||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import { coreMock } from 'src/core/public/mocks';
|
import { coreMock } from 'src/core/public/mocks';
|
||||||
import { SessionsClient } from 'src/plugins/data/public/search';
|
import { SessionsClient } from 'src/plugins/data/public/search';
|
||||||
import { SessionsMgmtConfigSchema } from '../';
|
import { SessionsConfigSchema } from '../';
|
||||||
import { SearchSessionStatus } from '../../../../common/search';
|
import { SearchSessionStatus } from '../../../../common/search';
|
||||||
import { OnActionComplete } from '../components';
|
import { OnActionComplete } from '../components';
|
||||||
import { UISession } from '../types';
|
import { UISession } from '../types';
|
||||||
|
@ -22,7 +22,7 @@ import { getColumns } from './get_columns';
|
||||||
|
|
||||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||||
let mockCoreStart: CoreStart;
|
let mockCoreStart: CoreStart;
|
||||||
let mockConfig: SessionsMgmtConfigSchema;
|
let mockConfig: SessionsConfigSchema;
|
||||||
let api: SearchSessionsMgmtAPI;
|
let api: SearchSessionsMgmtAPI;
|
||||||
let sessionsClient: SessionsClient;
|
let sessionsClient: SessionsClient;
|
||||||
let handleAction: OnActionComplete;
|
let handleAction: OnActionComplete;
|
||||||
|
@ -35,11 +35,14 @@ describe('Search Sessions Management table column factory', () => {
|
||||||
mockCoreSetup = coreMock.createSetup();
|
mockCoreSetup = coreMock.createSetup();
|
||||||
mockCoreStart = coreMock.createStart();
|
mockCoreStart = coreMock.createStart();
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
expiresSoonWarning: moment.duration(1, 'days'),
|
defaultExpiration: moment.duration('7d'),
|
||||||
maxSessions: 2000,
|
management: {
|
||||||
refreshInterval: moment.duration(1, 'seconds'),
|
expiresSoonWarning: moment.duration(1, 'days'),
|
||||||
refreshTimeout: moment.duration(10, 'minutes'),
|
maxSessions: 2000,
|
||||||
};
|
refreshInterval: moment.duration(1, 'seconds'),
|
||||||
|
refreshTimeout: moment.duration(10, 'minutes'),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||||
|
|
||||||
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { capitalize } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { RedirectAppLinks } from '../../../../../../../src/plugins/kibana_react/public';
|
import { RedirectAppLinks } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import { SessionsMgmtConfigSchema } from '../';
|
import { SessionsConfigSchema } from '../';
|
||||||
import { SearchSessionStatus } from '../../../../common/search';
|
import { SearchSessionStatus } from '../../../../common/search';
|
||||||
import { TableText } from '../components';
|
import { TableText } from '../components';
|
||||||
import { OnActionComplete, PopoverActionsMenu } from '../components';
|
import { OnActionComplete, PopoverActionsMenu } from '../components';
|
||||||
|
@ -45,7 +45,7 @@ function isSessionRestorable(status: SearchSessionStatus) {
|
||||||
export const getColumns = (
|
export const getColumns = (
|
||||||
core: CoreStart,
|
core: CoreStart,
|
||||||
api: SearchSessionsMgmtAPI,
|
api: SearchSessionsMgmtAPI,
|
||||||
config: SessionsMgmtConfigSchema,
|
config: SessionsConfigSchema,
|
||||||
timezone: string,
|
timezone: string,
|
||||||
onActionComplete: OnActionComplete
|
onActionComplete: OnActionComplete
|
||||||
): Array<EuiBasicTableColumn<UISession>> => {
|
): Array<EuiBasicTableColumn<UISession>> => {
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { SessionsMgmtConfigSchema } from '../';
|
import { SessionsConfigSchema } from '../';
|
||||||
|
|
||||||
export const getExpirationStatus = (config: SessionsMgmtConfigSchema, expires: string | null) => {
|
export const getExpirationStatus = (config: SessionsConfigSchema, expires: string | null) => {
|
||||||
const tNow = moment.utc().valueOf();
|
const tNow = moment.utc().valueOf();
|
||||||
const tFuture = moment.utc(expires).valueOf();
|
const tFuture = moment.utc(expires).valueOf();
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const getExpirationStatus = (config: SessionsMgmtConfigSchema, expires: s
|
||||||
// and the session was early expired when the browser refreshed the listing
|
// and the session was early expired when the browser refreshed the listing
|
||||||
const durationToExpire = moment.duration(tFuture - tNow);
|
const durationToExpire = moment.duration(tFuture - tNow);
|
||||||
const expiresInDays = Math.floor(durationToExpire.asDays());
|
const expiresInDays = Math.floor(durationToExpire.asDays());
|
||||||
const sufficientDays = Math.ceil(moment.duration(config.expiresSoonWarning).asDays());
|
const sufficientDays = Math.ceil(moment.duration(config.management.expiresSoonWarning).asDays());
|
||||||
|
|
||||||
let toolTipContent = i18n.translate('xpack.data.mgmt.searchSessions.status.expiresSoonInDays', {
|
let toolTipContent = i18n.translate('xpack.data.mgmt.searchSessions.status.expiresSoonInDays', {
|
||||||
defaultMessage: 'Expires in {numDays} days',
|
defaultMessage: 'Expires in {numDays} days',
|
||||||
|
|
|
@ -76,7 +76,7 @@ export async function scheduleSearchSessionsTasks(
|
||||||
params: {},
|
params: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.debug(`Background search task, scheduled to run`);
|
logger.debug(`Search sessions task, scheduled to run`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.debug(`Error scheduling task, received ${e.message}`);
|
logger.debug(`Error scheduling task, received ${e.message}`);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue