mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[App Search] Analytics - initial logic file & server API routes (#88250)
* Set up server API routes * Set up very basic AnalyticsLogic file - mostly just contains API call & basic loading/error state for now - actual usable vars will be defined in a future PR * [PR feedback] Unnecessary exports * [PR feedback] Clean up analyticsAvailable reducer * [PR feedback] Types order * [PR feedback] Unnecessary API validation
This commit is contained in:
parent
e4293a85fc
commit
53efccbc3b
7 changed files with 663 additions and 0 deletions
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* 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 { LogicMounter } from '../../../__mocks__/kea.mock';
|
||||
|
||||
jest.mock('../../../shared/kibana', () => ({
|
||||
KibanaLogic: { values: { history: { location: { search: '' } } } },
|
||||
}));
|
||||
import { KibanaLogic } from '../../../shared/kibana';
|
||||
|
||||
jest.mock('../../../shared/http', () => ({
|
||||
HttpLogic: { values: { http: { get: jest.fn() } } },
|
||||
}));
|
||||
import { HttpLogic } from '../../../shared/http';
|
||||
|
||||
jest.mock('../../../shared/flash_messages', () => ({
|
||||
flashAPIErrors: jest.fn(),
|
||||
}));
|
||||
import { flashAPIErrors } from '../../../shared/flash_messages';
|
||||
|
||||
jest.mock('../engine', () => ({
|
||||
EngineLogic: { values: { engineName: 'test-engine' } },
|
||||
}));
|
||||
|
||||
import { AnalyticsLogic } from './';
|
||||
|
||||
describe('AnalyticsLogic', () => {
|
||||
const DEFAULT_VALUES = {
|
||||
dataLoading: true,
|
||||
analyticsUnavailable: false,
|
||||
};
|
||||
|
||||
const MOCK_TOP_QUERIES = [
|
||||
{
|
||||
doc_count: 5,
|
||||
key: 'some-key',
|
||||
},
|
||||
{
|
||||
doc_count: 0,
|
||||
key: 'another-key',
|
||||
},
|
||||
];
|
||||
const MOCK_RECENT_QUERIES = [
|
||||
{
|
||||
document_ids: ['1', '2'],
|
||||
query_string: 'some-query',
|
||||
tags: ['some-tag'],
|
||||
timestamp: 'some-timestamp',
|
||||
},
|
||||
];
|
||||
const MOCK_TOP_CLICKS = [
|
||||
{
|
||||
key: 'highly-clicked-query',
|
||||
doc_count: 1,
|
||||
document: {
|
||||
id: 'some-id',
|
||||
engine: 'some-engine',
|
||||
tags: [],
|
||||
},
|
||||
clicks: {
|
||||
doc_count: 100,
|
||||
},
|
||||
},
|
||||
];
|
||||
const MOCK_ANALYTICS_RESPONSE = {
|
||||
analyticsUnavailable: false,
|
||||
allTags: ['some-tag'],
|
||||
recentQueries: MOCK_RECENT_QUERIES,
|
||||
topQueries: MOCK_TOP_QUERIES,
|
||||
topQueriesNoResults: MOCK_TOP_QUERIES,
|
||||
topQueriesNoClicks: MOCK_TOP_QUERIES,
|
||||
topQueriesWithClicks: MOCK_TOP_QUERIES,
|
||||
totalClicks: 1000,
|
||||
totalQueries: 5000,
|
||||
totalQueriesNoResults: 500,
|
||||
clicksPerDay: [0, 10, 50],
|
||||
queriesPerDay: [10, 50, 100],
|
||||
queriesNoResultsPerDay: [1, 2, 3],
|
||||
};
|
||||
const MOCK_QUERY_RESPONSE = {
|
||||
analyticsUnavailable: false,
|
||||
allTags: ['some-tag'],
|
||||
totalQueriesForQuery: 50,
|
||||
queriesPerDayForQuery: [25, 0, 25],
|
||||
topClicksForQuery: MOCK_TOP_CLICKS,
|
||||
};
|
||||
|
||||
const { mount } = new LogicMounter(AnalyticsLogic);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
KibanaLogic.values.history.location.search = '';
|
||||
});
|
||||
|
||||
it('has expected default values', () => {
|
||||
mount();
|
||||
expect(AnalyticsLogic.values).toEqual(DEFAULT_VALUES);
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
describe('onAnalyticsUnavailable', () => {
|
||||
it('should set state', () => {
|
||||
mount();
|
||||
AnalyticsLogic.actions.onAnalyticsUnavailable();
|
||||
|
||||
expect(AnalyticsLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
dataLoading: false,
|
||||
analyticsUnavailable: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAnalyticsDataLoad', () => {
|
||||
it('should set state', () => {
|
||||
mount();
|
||||
AnalyticsLogic.actions.onAnalyticsDataLoad(MOCK_ANALYTICS_RESPONSE);
|
||||
|
||||
expect(AnalyticsLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
dataLoading: false,
|
||||
analyticsUnavailable: false,
|
||||
// TODO: more state will get set here in future PRs
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onQueryDataLoad', () => {
|
||||
it('should set state', () => {
|
||||
mount();
|
||||
AnalyticsLogic.actions.onQueryDataLoad(MOCK_QUERY_RESPONSE);
|
||||
|
||||
expect(AnalyticsLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
dataLoading: false,
|
||||
analyticsUnavailable: false,
|
||||
// TODO: more state will get set here in future PRs
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('listeners', () => {
|
||||
describe('loadAnalyticsData', () => {
|
||||
it('should set state', () => {
|
||||
mount({ dataLoading: false });
|
||||
|
||||
AnalyticsLogic.actions.loadAnalyticsData();
|
||||
|
||||
expect(AnalyticsLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
dataLoading: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should make an API call and set state based on the response', async () => {
|
||||
const promise = Promise.resolve(MOCK_ANALYTICS_RESPONSE);
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onAnalyticsDataLoad');
|
||||
|
||||
AnalyticsLogic.actions.loadAnalyticsData();
|
||||
await promise;
|
||||
|
||||
expect(HttpLogic.values.http.get).toHaveBeenCalledWith(
|
||||
'/api/app_search/engines/test-engine/analytics/queries',
|
||||
{
|
||||
query: { size: 20 },
|
||||
}
|
||||
);
|
||||
expect(AnalyticsLogic.actions.onAnalyticsDataLoad).toHaveBeenCalledWith(
|
||||
MOCK_ANALYTICS_RESPONSE
|
||||
);
|
||||
});
|
||||
|
||||
it('parses and passes the current search query string', async () => {
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce({});
|
||||
KibanaLogic.values.history.location.search =
|
||||
'?start=1970-01-01&end=1970-01-02&&tag=some_tag';
|
||||
mount();
|
||||
|
||||
AnalyticsLogic.actions.loadAnalyticsData();
|
||||
|
||||
expect(HttpLogic.values.http.get).toHaveBeenCalledWith(
|
||||
'/api/app_search/engines/test-engine/analytics/queries',
|
||||
{
|
||||
query: {
|
||||
start: '1970-01-01',
|
||||
end: '1970-01-02',
|
||||
tag: 'some_tag',
|
||||
size: 20,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('calls onAnalyticsUnavailable if analyticsUnavailable is in response', async () => {
|
||||
const promise = Promise.resolve({ analyticsUnavailable: true });
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onAnalyticsUnavailable');
|
||||
|
||||
AnalyticsLogic.actions.loadAnalyticsData();
|
||||
await promise;
|
||||
|
||||
expect(AnalyticsLogic.actions.onAnalyticsUnavailable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles errors', async () => {
|
||||
const promise = Promise.reject('error');
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onAnalyticsUnavailable');
|
||||
|
||||
try {
|
||||
AnalyticsLogic.actions.loadAnalyticsData();
|
||||
await promise;
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
expect(flashAPIErrors).toHaveBeenCalledWith('error');
|
||||
expect(AnalyticsLogic.actions.onAnalyticsUnavailable).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadQueryData', () => {
|
||||
it('should set state', () => {
|
||||
mount({ dataLoading: false });
|
||||
|
||||
AnalyticsLogic.actions.loadQueryData('some-query');
|
||||
|
||||
expect(AnalyticsLogic.values).toEqual({
|
||||
...DEFAULT_VALUES,
|
||||
dataLoading: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should make an API call and set state based on the response', async () => {
|
||||
const promise = Promise.resolve(MOCK_QUERY_RESPONSE);
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onQueryDataLoad');
|
||||
|
||||
AnalyticsLogic.actions.loadQueryData('some-query');
|
||||
await promise;
|
||||
|
||||
expect(HttpLogic.values.http.get).toHaveBeenCalledWith(
|
||||
'/api/app_search/engines/test-engine/analytics/queries/some-query',
|
||||
expect.any(Object) // empty query obj
|
||||
);
|
||||
expect(AnalyticsLogic.actions.onQueryDataLoad).toHaveBeenCalledWith(MOCK_QUERY_RESPONSE);
|
||||
});
|
||||
|
||||
it('parses and passes the current search query string', async () => {
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce({});
|
||||
KibanaLogic.values.history.location.search =
|
||||
'?start=1970-12-30&end=1970-12-31&&tag=another_tag';
|
||||
mount();
|
||||
|
||||
AnalyticsLogic.actions.loadQueryData('some-query');
|
||||
|
||||
expect(HttpLogic.values.http.get).toHaveBeenCalledWith(
|
||||
'/api/app_search/engines/test-engine/analytics/queries/some-query',
|
||||
{
|
||||
query: {
|
||||
start: '1970-12-30',
|
||||
end: '1970-12-31',
|
||||
tag: 'another_tag',
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('calls onAnalyticsUnavailable if analyticsUnavailable is in response', async () => {
|
||||
const promise = Promise.resolve({ analyticsUnavailable: true });
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onAnalyticsUnavailable');
|
||||
|
||||
AnalyticsLogic.actions.loadQueryData('some-query');
|
||||
await promise;
|
||||
|
||||
expect(AnalyticsLogic.actions.onAnalyticsUnavailable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles errors', async () => {
|
||||
const promise = Promise.reject('error');
|
||||
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
|
||||
mount();
|
||||
jest.spyOn(AnalyticsLogic.actions, 'onAnalyticsUnavailable');
|
||||
|
||||
try {
|
||||
AnalyticsLogic.actions.loadQueryData('some-query');
|
||||
await promise;
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
expect(flashAPIErrors).toHaveBeenCalledWith('error');
|
||||
expect(AnalyticsLogic.actions.onAnalyticsUnavailable).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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 queryString from 'query-string';
|
||||
|
||||
import { KibanaLogic } from '../../../shared/kibana';
|
||||
import { HttpLogic } from '../../../shared/http';
|
||||
import { flashAPIErrors } from '../../../shared/flash_messages';
|
||||
import { EngineLogic } from '../engine';
|
||||
|
||||
import { AnalyticsData, QueryDetails } from './types';
|
||||
|
||||
interface AnalyticsValues extends AnalyticsData, QueryDetails {
|
||||
dataLoading: boolean;
|
||||
}
|
||||
|
||||
interface AnalyticsActions {
|
||||
onAnalyticsUnavailable(): void;
|
||||
onAnalyticsDataLoad(data: AnalyticsData): AnalyticsData;
|
||||
onQueryDataLoad(data: QueryDetails): QueryDetails;
|
||||
loadAnalyticsData(): void;
|
||||
loadQueryData(query: string): string;
|
||||
}
|
||||
|
||||
export const AnalyticsLogic = kea<MakeLogicType<AnalyticsValues, AnalyticsActions>>({
|
||||
path: ['enterprise_search', 'app_search', 'analytics_logic'],
|
||||
actions: () => ({
|
||||
onAnalyticsUnavailable: true,
|
||||
onAnalyticsDataLoad: (data) => data,
|
||||
onQueryDataLoad: (data) => data,
|
||||
loadAnalyticsData: true,
|
||||
loadQueryData: (query) => query,
|
||||
}),
|
||||
reducers: () => ({
|
||||
dataLoading: [
|
||||
true,
|
||||
{
|
||||
loadAnalyticsData: () => true,
|
||||
loadQueryData: () => true,
|
||||
onAnalyticsUnavailable: () => false,
|
||||
onAnalyticsDataLoad: () => false,
|
||||
onQueryDataLoad: () => false,
|
||||
},
|
||||
],
|
||||
analyticsUnavailable: [
|
||||
false,
|
||||
{
|
||||
onAnalyticsUnavailable: () => true,
|
||||
onAnalyticsDataLoad: () => false,
|
||||
onQueryDataLoad: () => false,
|
||||
},
|
||||
],
|
||||
}),
|
||||
listeners: ({ actions }) => ({
|
||||
loadAnalyticsData: async () => {
|
||||
const { history } = KibanaLogic.values;
|
||||
const { http } = HttpLogic.values;
|
||||
const { engineName } = EngineLogic.values;
|
||||
|
||||
try {
|
||||
const { start, end, tag } = queryString.parse(history.location.search);
|
||||
const query = { start, end, tag, size: 20 };
|
||||
const url = `/api/app_search/engines/${engineName}/analytics/queries`;
|
||||
|
||||
const response = await http.get(url, { query });
|
||||
|
||||
if (response.analyticsUnavailable) {
|
||||
actions.onAnalyticsUnavailable();
|
||||
} else {
|
||||
actions.onAnalyticsDataLoad(response);
|
||||
}
|
||||
} catch (e) {
|
||||
flashAPIErrors(e);
|
||||
actions.onAnalyticsUnavailable();
|
||||
}
|
||||
},
|
||||
loadQueryData: async (query) => {
|
||||
const { history } = KibanaLogic.values;
|
||||
const { http } = HttpLogic.values;
|
||||
const { engineName } = EngineLogic.values;
|
||||
|
||||
try {
|
||||
const { start, end, tag } = queryString.parse(history.location.search);
|
||||
const queryParams = { start, end, tag };
|
||||
const url = `/api/app_search/engines/${engineName}/analytics/queries/${query}`;
|
||||
|
||||
const response = await http.get(url, { query: queryParams });
|
||||
|
||||
if (response.analyticsUnavailable) {
|
||||
actions.onAnalyticsUnavailable();
|
||||
} else {
|
||||
actions.onQueryDataLoad(response);
|
||||
}
|
||||
} catch (e) {
|
||||
flashAPIErrors(e);
|
||||
actions.onAnalyticsUnavailable();
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
export { ANALYTICS_TITLE } from './constants';
|
||||
export { AnalyticsLogic } from './analytics_logic';
|
||||
export { AnalyticsRouter } from './analytics_router';
|
||||
export { AnalyticsChart } from './components';
|
||||
export { convertToChartData } from './utils';
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
interface Query {
|
||||
doc_count: number;
|
||||
key: string;
|
||||
clicks?: { doc_count: number };
|
||||
searches?: { doc_count: number };
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
interface QueryClick extends Query {
|
||||
document?: {
|
||||
id: string;
|
||||
engine: string;
|
||||
tags?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
interface RecentQuery {
|
||||
document_ids: string[];
|
||||
query_string: string;
|
||||
tags: string[];
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* API response data
|
||||
*/
|
||||
|
||||
interface BaseData {
|
||||
analyticsUnavailable: boolean;
|
||||
allTags: string[];
|
||||
// NOTE: The API sends us back even more data than this (e.g.,
|
||||
// startDate, endDate, currentTag, logRetentionSettings, query),
|
||||
// but we currently don't need that data in our front-end code,
|
||||
// so I'm opting not to list them in our types
|
||||
}
|
||||
|
||||
export interface AnalyticsData extends BaseData {
|
||||
recentQueries: RecentQuery[];
|
||||
topQueries: Query[];
|
||||
topQueriesWithClicks: Query[];
|
||||
topQueriesNoClicks: Query[];
|
||||
topQueriesNoResults: Query[];
|
||||
totalClicks: number;
|
||||
totalQueries: number;
|
||||
totalQueriesNoResults: number;
|
||||
clicksPerDay: number[];
|
||||
queriesPerDay: number[];
|
||||
queriesNoResultsPerDay: number[];
|
||||
}
|
||||
|
||||
export interface QueryDetails extends BaseData {
|
||||
totalQueriesForQuery: number;
|
||||
queriesPerDayForQuery: number[];
|
||||
topClicksForQuery: QueryClick[];
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__';
|
||||
|
||||
import { registerAnalyticsRoutes } from './analytics';
|
||||
|
||||
describe('analytics routes', () => {
|
||||
describe('GET /api/app_search/engines/{engineName}/analytics/queries', () => {
|
||||
let mockRouter: MockRouter;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockRouter = new MockRouter({
|
||||
method: 'get',
|
||||
path: '/api/app_search/engines/{engineName}/analytics/queries',
|
||||
payload: 'query',
|
||||
});
|
||||
|
||||
registerAnalyticsRoutes({
|
||||
...mockDependencies,
|
||||
router: mockRouter.router,
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a request handler', () => {
|
||||
mockRouter.callRoute({
|
||||
params: { engineName: 'some-engine' },
|
||||
});
|
||||
|
||||
expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
|
||||
path: '/as/engines/some-engine/analytics/queries',
|
||||
});
|
||||
});
|
||||
|
||||
describe('validates', () => {
|
||||
it('correctly without optional query params', () => {
|
||||
const request = { query: {} };
|
||||
mockRouter.shouldValidate(request);
|
||||
});
|
||||
|
||||
it('correctly with all optional query params', () => {
|
||||
const request = {
|
||||
query: {
|
||||
size: 20,
|
||||
start: '1970-01-01',
|
||||
end: '1970-01-02',
|
||||
tag: 'some-tag',
|
||||
},
|
||||
};
|
||||
mockRouter.shouldValidate(request);
|
||||
});
|
||||
|
||||
it('incorrect types', () => {
|
||||
const request = {
|
||||
query: {
|
||||
start: 100,
|
||||
size: '100',
|
||||
},
|
||||
};
|
||||
mockRouter.shouldThrow(request);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/app_search/engines/{engineName}/analytics/queries/{query}', () => {
|
||||
let mockRouter: MockRouter;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockRouter = new MockRouter({
|
||||
method: 'get',
|
||||
path: '/api/app_search/engines/{engineName}/analytics/queries/{query}',
|
||||
payload: 'query',
|
||||
});
|
||||
|
||||
registerAnalyticsRoutes({
|
||||
...mockDependencies,
|
||||
router: mockRouter.router,
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a request handler', () => {
|
||||
mockRouter.callRoute({
|
||||
params: { engineName: 'some-engine', query: 'some-query' },
|
||||
});
|
||||
|
||||
expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
|
||||
path: '/as/engines/some-engine/analytics/query/some-query',
|
||||
});
|
||||
});
|
||||
|
||||
describe('validates', () => {
|
||||
it('correctly without optional query params', () => {
|
||||
const request = { query: {} };
|
||||
mockRouter.shouldValidate(request);
|
||||
});
|
||||
|
||||
it('correctly with all optional query params', () => {
|
||||
const request = {
|
||||
query: {
|
||||
start: '1970-01-01',
|
||||
end: '1970-01-02',
|
||||
tag: 'some-tag',
|
||||
},
|
||||
};
|
||||
mockRouter.shouldValidate(request);
|
||||
});
|
||||
|
||||
it('incorrect types', () => {
|
||||
const request = {
|
||||
query: {
|
||||
start: 100,
|
||||
tag: false,
|
||||
},
|
||||
};
|
||||
mockRouter.shouldThrow(request);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 { schema } from '@kbn/config-schema';
|
||||
|
||||
import { RouteDependencies } from '../../plugin';
|
||||
|
||||
const querySchema = {
|
||||
start: schema.maybe(schema.string()), // Date string, expected format 'YYYY-MM-DD'
|
||||
end: schema.maybe(schema.string()), // Date string, expected format 'YYYY-MM-DD'
|
||||
tag: schema.maybe(schema.string()),
|
||||
};
|
||||
const queriesSchema = {
|
||||
...querySchema,
|
||||
size: schema.maybe(schema.number()),
|
||||
};
|
||||
|
||||
export function registerAnalyticsRoutes({
|
||||
router,
|
||||
enterpriseSearchRequestHandler,
|
||||
}: RouteDependencies) {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/app_search/engines/{engineName}/analytics/queries',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
engineName: schema.string(),
|
||||
}),
|
||||
query: schema.object(queriesSchema),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const { engineName } = request.params;
|
||||
|
||||
return enterpriseSearchRequestHandler.createRequest({
|
||||
path: `/as/engines/${engineName}/analytics/queries`,
|
||||
})(context, request, response);
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: '/api/app_search/engines/{engineName}/analytics/queries/{query}',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
engineName: schema.string(),
|
||||
query: schema.string(),
|
||||
}),
|
||||
query: schema.object(querySchema),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const { engineName, query } = request.params;
|
||||
|
||||
return enterpriseSearchRequestHandler.createRequest({
|
||||
path: `/as/engines/${engineName}/analytics/query/${query}`,
|
||||
})(context, request, response);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -9,12 +9,14 @@ import { RouteDependencies } from '../../plugin';
|
|||
import { registerEnginesRoutes } from './engines';
|
||||
import { registerCredentialsRoutes } from './credentials';
|
||||
import { registerSettingsRoutes } from './settings';
|
||||
import { registerAnalyticsRoutes } from './analytics';
|
||||
import { registerDocumentsRoutes, registerDocumentRoutes } from './documents';
|
||||
|
||||
export const registerAppSearchRoutes = (dependencies: RouteDependencies) => {
|
||||
registerEnginesRoutes(dependencies);
|
||||
registerCredentialsRoutes(dependencies);
|
||||
registerSettingsRoutes(dependencies);
|
||||
registerAnalyticsRoutes(dependencies);
|
||||
registerDocumentsRoutes(dependencies);
|
||||
registerDocumentRoutes(dependencies);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue