diff --git a/x-pack/solutions/search/plugins/search_synonyms/public/components/error_prompt/error_prompt.tsx b/x-pack/solutions/search/plugins/search_synonyms/public/components/error_prompt/error_prompt.tsx new file mode 100644 index 0000000000000..f50b30caa5f7f --- /dev/null +++ b/x-pack/solutions/search/plugins/search_synonyms/public/components/error_prompt/error_prompt.tsx @@ -0,0 +1,51 @@ +/* + * 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 { EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +const ERROR_MESSAGES = { + generic: { + title: ( + + ), + body: ( + + ), + }, + missingPermissions: { + title: ( + + ), + body: ( + + ), + }, +}; + +export const ErrorPrompt: React.FC<{ errorType: 'missingPermissions' | 'generic' }> = ({ + errorType, +}) => { + return ( + {ERROR_MESSAGES[errorType].title}} + body={

{ERROR_MESSAGES[errorType].body}

} + /> + ); +}; diff --git a/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.test.tsx b/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.test.tsx new file mode 100644 index 0000000000000..ba7d230c3405b --- /dev/null +++ b/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.test.tsx @@ -0,0 +1,57 @@ +/* + * 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 { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { SearchSynonymsOverview } from './overview'; +import { I18nProvider } from '@kbn/i18n-react'; +import { useFetchSynonymsSets } from '../../hooks/use_fetch_synonyms_sets'; + +jest.mock('../../hooks/use_fetch_synonyms_sets', () => ({ + useFetchSynonymsSets: jest.fn(() => ({ + data: undefined, + isLoading: false, + isError: true, + error: { body: { statusCode: 500 } }, + })), +})); + +describe('Search Synonyms Overview', () => { + const queryClient = new QueryClient(); + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + it('should show error prompt when we get a generic error', () => { + render( + + + + ); + + expect(screen.getByText('An error occurred')).toBeInTheDocument(); + }); + + it('should show error prompt when we get a missing permissions error', () => { + (useFetchSynonymsSets as jest.Mock).mockReturnValue({ + data: undefined, + isLoading: false, + isError: true, + error: { body: { statusCode: 403 } }, + }); + + render( + + + + ); + + expect(screen.getByText('Missing permissions')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.tsx b/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.tsx index 3dfd1bc9da4e8..59028311047ca 100644 --- a/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.tsx +++ b/x-pack/solutions/search/plugins/search_synonyms/public/components/overview/overview.tsx @@ -23,12 +23,14 @@ import { SynonymSets } from '../synonym_sets/synonym_sets'; import { useFetchSynonymsSets } from '../../hooks/use_fetch_synonyms_sets'; import { EmptyPrompt } from '../empty_prompt/empty_prompt'; import { CreateSynonymsSetModal } from '../synonym_sets/create_new_set_modal'; +import { ErrorPrompt } from '../error_prompt/error_prompt'; +import { isPermissionError } from '../../utils/synonyms_utils'; export const SearchSynonymsOverview = () => { const { services: { console: consolePlugin, history, searchNavigation }, } = useKibana(); - const { data: synonymsData, isInitialLoading } = useFetchSynonymsSets(); + const { data: synonymsData, isInitialLoading, isError, error } = useFetchSynonymsSets(); const [isCreateModalVisible, setIsCreateModalVisible] = useState(false); const embeddableConsole = useMemo( @@ -44,50 +46,52 @@ export const SearchSynonymsOverview = () => { solutionNav={searchNavigation?.useClassicNavigation(history)} color="primary" > - - - - - - - - { - setIsCreateModalVisible(true); - }} - > - - - - , - ]} - > - - - - + {synonymsData && !isInitialLoading && !isError && ( + + + + + + + + { + setIsCreateModalVisible(true); + }} + > + + + + , + ]} + > + + + + + )} {isCreateModalVisible && ( { /> )} {isInitialLoading && } + {isError && ( + + )} {!isInitialLoading && synonymsData && synonymsData._meta.totalItemCount > 0 && ( diff --git a/x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.ts b/x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.ts index 79c42d852526a..d8d7b341da3c1 100644 --- a/x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.ts +++ b/x-pack/solutions/search/plugins/search_synonyms/public/hooks/use_fetch_synonyms_sets.ts @@ -7,6 +7,7 @@ import { useQuery } from '@tanstack/react-query'; import type { SynonymsGetSynonymsSetsSynonymsSetItem } from '@elastic/elasticsearch/lib/api/types'; +import { KibanaServerError } from '@kbn/kibana-utils-plugin/common'; import { SYNONYMS_SETS_QUERY_KEY } from '../../common/constants'; import { DEFAULT_PAGE_VALUE, Page, Paginate } from '../../common/pagination'; import { APIRoutes } from '../../common/api_routes'; @@ -16,7 +17,7 @@ export const useFetchSynonymsSets = (page: Page = DEFAULT_PAGE_VALUE) => { const { services: { http }, } = useKibana(); - return useQuery({ + return useQuery, { body: KibanaServerError }>({ queryKey: [SYNONYMS_SETS_QUERY_KEY, page.from, page.size], queryFn: async () => { return await http.get>( @@ -26,5 +27,7 @@ export const useFetchSynonymsSets = (page: Page = DEFAULT_PAGE_VALUE) => { } ); }, + refetchOnWindowFocus: false, + retry: false, }); }; diff --git a/x-pack/solutions/search/plugins/search_synonyms/public/utils/synonyms_utils.ts b/x-pack/solutions/search/plugins/search_synonyms/public/utils/synonyms_utils.ts index cdcaef93c1445..59a1c2fc802d9 100644 --- a/x-pack/solutions/search/plugins/search_synonyms/public/utils/synonyms_utils.ts +++ b/x-pack/solutions/search/plugins/search_synonyms/public/utils/synonyms_utils.ts @@ -6,6 +6,7 @@ */ import { EuiComboBoxOptionOption } from '@elastic/eui'; +import { KibanaServerError } from '@kbn/kibana-utils-plugin/common'; export const isExplicitSynonym = (synonym: string) => { return synonym.trim().includes('=>'); @@ -41,3 +42,7 @@ export const synonymsOptionToString = ({ `${fromTerms.map((s) => s.label).join(',')}${ isExplicit ? ' => ' + toTerms.map((s) => s.label).join(',') : '' }`; + +export const isPermissionError = (error: { body: KibanaServerError }) => { + return error.body.statusCode === 403; +};