forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Synonyms UI] Search synonyms set list (elastic#206931)
## Summary Adds Synonyms set table and endpoint to the synonyms. Actions are just a placeholder and will be working in next PR following this with Delete modal. <img width="1161" alt="Screenshot 2025-01-16 at 13 43 44" src="https://github.com/user-attachments/assets/bc410a58-85e0-4e89-baff-e7a427d82ecd" /> <img width="1163" alt="Screenshot 2025-01-16 at 13 43 55" src="https://github.com/user-attachments/assets/e087bd51-71a9-49a5-936e-00fde2492ddd" /> ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
49d1cea
commit 3543852
Showing
13 changed files
with
450 additions
and
9 deletions.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
x-pack/solutions/search/plugins/search_synonyms/common/api_routes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export enum APIRoutes { | ||
SYNONYM_SETS = '/internal/search_synonyms/synonyms', | ||
} |
43 changes: 43 additions & 0 deletions
43
x-pack/solutions/search/plugins/search_synonyms/common/pagination.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export const DEFAULT_PAGE_VALUE: Page = { | ||
from: 0, | ||
size: 10, | ||
}; | ||
|
||
export interface Pagination { | ||
pageIndex: number; | ||
pageSize: number; | ||
totalItemCount: number; | ||
} | ||
|
||
export interface Page { | ||
from: number; // current page index, 0-based | ||
size: number; | ||
} | ||
|
||
export interface Paginate<T> { | ||
_meta: Pagination; | ||
data: T[]; | ||
} | ||
|
||
export function paginationToPage(pagination: Pagination): Page { | ||
return { | ||
from: pagination.pageIndex * pagination.pageSize, | ||
size: pagination.pageSize, | ||
}; | ||
} | ||
export function pageToPagination(page: { from: number; size: number; total: number }) { | ||
// Prevent divide-by-zero-error | ||
const pageIndex = page.size ? Math.trunc(page.from / page.size) : 0; | ||
return { | ||
pageIndex, | ||
pageSize: page.size, | ||
totalItemCount: page.total, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...tions/search/plugins/search_synonyms/public/components/synonym_sets/synonym_sets.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
|
||
import { render, screen } from '@testing-library/react'; | ||
import { SynonymSets } from './synonym_sets'; | ||
|
||
jest.mock('../../hooks/use_fetch_synonyms_sets', () => ({ | ||
useFetchSynonymsSets: () => ({ | ||
data: { | ||
data: [ | ||
{ | ||
synonyms_set: 'Synonyms Set 1', | ||
count: 2, | ||
}, | ||
{ | ||
synonyms_set: 'Synonyms Set 2', | ||
count: 3, | ||
}, | ||
], | ||
_meta: { pageIndex: 0, pageSize: 10, totalItemCount: 2 }, | ||
}, | ||
isLoading: false, | ||
isError: false, | ||
}), | ||
})); | ||
|
||
describe('Search Synonym Sets list', () => { | ||
it('should render the list with synonym sets', () => { | ||
render(<SynonymSets />); | ||
const synonymSetTable = screen.getByTestId('synonyms-set-table'); | ||
expect(synonymSetTable).toBeInTheDocument(); | ||
|
||
const synonymSetItemNames = screen.getAllByTestId('synonyms-set-item-name'); | ||
expect(synonymSetItemNames).toHaveLength(2); | ||
expect(synonymSetItemNames[0].textContent).toBe('Synonyms Set 1'); | ||
expect(synonymSetItemNames[1].textContent).toBe('Synonyms Set 2'); | ||
|
||
const synonymSetItemRuleCounts = screen.getAllByTestId('synonyms-set-item-rule-count'); | ||
expect(synonymSetItemRuleCounts).toHaveLength(2); | ||
expect(synonymSetItemRuleCounts[0].textContent).toBe('2'); | ||
expect(synonymSetItemRuleCounts[1].textContent).toBe('3'); | ||
|
||
const synonymSetItemPageSize = screen.getByTestId('tablePaginationPopoverButton'); | ||
const synonymSetPageButton = screen.getByTestId('pagination-button-0'); | ||
expect(synonymSetItemPageSize).toBeInTheDocument(); | ||
expect(synonymSetPageButton).toBeInTheDocument(); | ||
}); | ||
}); |
64 changes: 64 additions & 0 deletions
64
.../solutions/search/plugins/search_synonyms/public/components/synonym_sets/synonym_sets.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { SynonymsGetSynonymsSetsSynonymsSetItem } from '@elastic/elasticsearch/lib/api/types'; | ||
import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
import React, { useState } from 'react'; | ||
import { DEFAULT_PAGE_VALUE, paginationToPage } from '../../../common/pagination'; | ||
import { useFetchSynonymsSets } from '../../hooks/use_fetch_synonyms_sets'; | ||
|
||
export const SynonymSets = () => { | ||
const [pageIndex, setPageIndex] = useState(0); | ||
const [pageSize, setPageSize] = useState(DEFAULT_PAGE_VALUE.size); | ||
const { from } = paginationToPage({ pageIndex, pageSize, totalItemCount: 0 }); | ||
const { data: synonyms } = useFetchSynonymsSets({ from, size: pageSize }); | ||
|
||
if (!synonyms) { | ||
return null; | ||
} | ||
|
||
const pagination = { | ||
initialPageSize: 10, | ||
pageSizeOptions: [10, 25, 50], | ||
...synonyms._meta, | ||
pageSize, | ||
pageIndex, | ||
}; | ||
const columns: Array<EuiBasicTableColumn<SynonymsGetSynonymsSetsSynonymsSetItem>> = [ | ||
{ | ||
field: 'synonyms_set', | ||
name: i18n.translate('xpack.searchSynonyms.synonymsSetTable.nameColumn', { | ||
defaultMessage: 'Synonyms Set', | ||
}), | ||
render: (name: string) => <div data-test-subj="synonyms-set-item-name">{name}</div>, | ||
}, | ||
{ | ||
field: 'count', | ||
name: i18n.translate('xpack.searchSynonyms.synonymsSetTable.ruleCount', { | ||
defaultMessage: 'Rule Count', | ||
}), | ||
render: (ruleCount: number) => ( | ||
<div data-test-subj="synonyms-set-item-rule-count">{ruleCount}</div> | ||
), | ||
}, | ||
]; | ||
return ( | ||
<div> | ||
<EuiBasicTable | ||
data-test-subj="synonyms-set-table" | ||
items={synonyms.data} | ||
columns={columns} | ||
pagination={pagination} | ||
onChange={({ page: changedPage }) => { | ||
setPageIndex(changedPage.index); | ||
setPageSize(changedPage.size); | ||
}} | ||
/> | ||
</div> | ||
); | ||
}; |
56 changes: 56 additions & 0 deletions
56
x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { renderHook, waitFor } from '@testing-library/react'; | ||
|
||
const mockHttpGet = jest.fn(); | ||
|
||
jest.mock('@tanstack/react-query', () => ({ | ||
useQuery: jest.fn().mockImplementation(async ({ queryKey, queryFn, opts }) => { | ||
try { | ||
const res = await queryFn(); | ||
return Promise.resolve(res); | ||
} catch (e) { | ||
// opts.onError(e); | ||
} | ||
}), | ||
})); | ||
|
||
jest.mock('./use_kibana', () => ({ | ||
useKibana: jest.fn().mockReturnValue({ | ||
services: { | ||
http: { | ||
get: mockHttpGet, | ||
}, | ||
notifications: { | ||
toasts: { | ||
addError: jest.fn(), | ||
}, | ||
}, | ||
}, | ||
}), | ||
})); | ||
|
||
describe('useFetchSynonymsSet Hook', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should return synonyms set', async () => { | ||
const synonyms = [ | ||
{ | ||
id: '1', | ||
synonyms: ['foo', 'bar'], | ||
}, | ||
]; | ||
mockHttpGet.mockReturnValue(synonyms); | ||
const { useFetchSynonymsSets } = jest.requireActual('./use_fetch_synonyms_sets'); | ||
|
||
const { result } = renderHook(() => useFetchSynonymsSets()); | ||
await waitFor(() => expect(result.current).resolves.toStrictEqual(synonyms)); | ||
}); | ||
}); |
29 changes: 29 additions & 0 deletions
29
x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { useQuery } from '@tanstack/react-query'; | ||
import type { SynonymsGetSynonymsSetsSynonymsSetItem } from '@elastic/elasticsearch/lib/api/types'; | ||
import { DEFAULT_PAGE_VALUE, Page, Paginate } from '../../common/pagination'; | ||
import { APIRoutes } from '../../common/api_routes'; | ||
import { useKibana } from './use_kibana'; | ||
|
||
export const useFetchSynonymsSets = (page: Page = DEFAULT_PAGE_VALUE) => { | ||
const { | ||
services: { http }, | ||
} = useKibana(); | ||
return useQuery({ | ||
queryKey: ['synonyms-sets-fetch', page.from, page.size], | ||
queryFn: async () => { | ||
return await http.get<Paginate<SynonymsGetSynonymsSetsSynonymsSetItem>>( | ||
APIRoutes.SYNONYM_SETS, | ||
{ | ||
query: { from: page.from, size: page.size }, | ||
} | ||
); | ||
}, | ||
}); | ||
}; |
60 changes: 60 additions & 0 deletions
60
x-pack/solutions/search/plugins/search_synonyms/server/lib/fetch_synonym_sets.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { ElasticsearchClient } from '@kbn/core/server'; | ||
import { fetchSynonymSets } from './fetch_synonym_sets'; | ||
|
||
describe('fetch synonym sets lib function', () => { | ||
const mockClient = { | ||
security: { | ||
hasPrivileges: jest.fn(), | ||
}, | ||
synonyms: { | ||
getSynonymsSets: jest.fn(), | ||
}, | ||
}; | ||
|
||
const client = () => mockClient as unknown as ElasticsearchClient; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
it('should return synonym sets', async () => { | ||
mockClient.synonyms.getSynonymsSets.mockResolvedValue({ | ||
count: 2, | ||
results: [ | ||
{ | ||
synonyms_set: 'my_synonyms_set', | ||
count: 2, | ||
}, | ||
{ | ||
synonyms_set: 'my_synonyms_set_2', | ||
count: 3, | ||
}, | ||
], | ||
}); | ||
|
||
const result = await fetchSynonymSets(client(), { from: 0, size: 10 }); | ||
expect(result).toEqual({ | ||
_meta: { | ||
pageIndex: 0, | ||
pageSize: 10, | ||
totalItemCount: 2, | ||
}, | ||
data: [ | ||
{ | ||
synonyms_set: 'my_synonyms_set', | ||
count: 2, | ||
}, | ||
{ | ||
synonyms_set: 'my_synonyms_set_2', | ||
count: 3, | ||
}, | ||
], | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.