Skip to content

Commit

Permalink
[8.x] [Fix] [Synonyms UI] Fix infinite loading when permissions missi…
Browse files Browse the repository at this point in the history
…ng (#211530) (#212160)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Fix] [Synonyms UI] Fix infinite loading when permissions missing
(#211530)](#211530)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Efe Gürkan
YALAMAN","email":"efeguerkan.yalaman@elastic.co"},"sourceCommit":{"committedDate":"2025-02-21T20:40:48Z","message":"[Fix]
[Synonyms UI] Fix infinite loading when permissions missing
(#211530)\n\n## Summary\n\nFixes infinite loading when user had missing
permissions.\n<img width=\"948\" alt=\"Screenshot 2025-02-18 at 12 24
22\"\nsrc=\"https://github.com/user-attachments/assets/975c46ef-a729-4bec-9442-fdb38b59fe19\"\n/>\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] This was
checked for breaking HTTP API changes, and any breaking\nchanges have
been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [x] The PR description includes the appropriate Release
Notes section,\nand the correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"c0da61a2256ae23465772470b3694ea57cf01256","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","v9.0.0","backport:version","v8.18.0","v9.1.0","v8.19.0"],"title":"[Fix]
[Synonyms UI] Fix infinite loading when permissions
missing","number":211530,"url":"https://github.com/elastic/kibana/pull/211530","mergeCommit":{"message":"[Fix]
[Synonyms UI] Fix infinite loading when permissions missing
(#211530)\n\n## Summary\n\nFixes infinite loading when user had missing
permissions.\n<img width=\"948\" alt=\"Screenshot 2025-02-18 at 12 24
22\"\nsrc=\"https://github.com/user-attachments/assets/975c46ef-a729-4bec-9442-fdb38b59fe19\"\n/>\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] This was
checked for breaking HTTP API changes, and any breaking\nchanges have
been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [x] The PR description includes the appropriate Release
Notes section,\nand the correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"c0da61a2256ae23465772470b3694ea57cf01256"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/211530","number":211530,"mergeCommit":{"message":"[Fix]
[Synonyms UI] Fix infinite loading when permissions missing
(#211530)\n\n## Summary\n\nFixes infinite loading when user had missing
permissions.\n<img width=\"948\" alt=\"Screenshot 2025-02-18 at 12 24
22\"\nsrc=\"https://github.com/user-attachments/assets/975c46ef-a729-4bec-9442-fdb38b59fe19\"\n/>\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] This was
checked for breaking HTTP API changes, and any breaking\nchanges have
been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [x] The PR description includes the appropriate Release
Notes section,\nand the correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"c0da61a2256ae23465772470b3694ea57cf01256"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Efe Gürkan YALAMAN <efeguerkan.yalaman@elastic.co>
  • Loading branch information
kibanamachine and efegurkan authored Feb 21, 2025
1 parent 10396d6 commit e623cbc
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -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: (
<FormattedMessage id="xpack.search.synonyms.errorTitle" defaultMessage="An error occurred" />
),
body: (
<FormattedMessage
id="xpack.search.synonyms.errorDescription"
defaultMessage="An error occured while fetching synonyms. Check Kibana logs for more information."
/>
),
},
missingPermissions: {
title: (
<FormattedMessage
id="xpack.search.synonyms.missingPermissionsTitle"
defaultMessage="Missing permissions"
/>
),
body: (
<FormattedMessage
id="xpack.search.synonyms.missingPermissionsDescription"
defaultMessage="You do not have the necessary permissions to manage synonyms. Contact your system administrator."
/>
),
},
};

export const ErrorPrompt: React.FC<{ errorType: 'missingPermissions' | 'generic' }> = ({
errorType,
}) => {
return (
<EuiEmptyPrompt
iconType="logoEnterpriseSearch"
title={<h2>{ERROR_MESSAGES[errorType].title}</h2>}
body={<p>{ERROR_MESSAGES[errorType].body}</p>}
/>
);
};
Original file line number Diff line number Diff line change
@@ -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 }) => (
<I18nProvider>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</I18nProvider>
);
it('should show error prompt when we get a generic error', () => {
render(
<Wrapper>
<SearchSynonymsOverview />
</Wrapper>
);

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(
<Wrapper>
<SearchSynonymsOverview />
</Wrapper>
);

expect(screen.getByText('Missing permissions')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -44,50 +46,52 @@ export const SearchSynonymsOverview = () => {
solutionNav={searchNavigation?.useClassicNavigation(history)}
color="primary"
>
<KibanaPageTemplate.Header
pageTitle="Synonyms"
restrictWidth
color="primary"
rightSideItems={[
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiLink
data-test-subj="searchSynonymsSearchSynonymsOverviewApiDocumentationLink"
external
target="_blank"
href={docLinks.synonymsApi}
>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.documentationLink"
defaultMessage="API Documentation"
/>
</EuiLink>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="searchSynonymsSearchSynonymsOverviewCreateButton"
fill
iconType="plusInCircle"
onClick={() => {
setIsCreateModalVisible(true);
}}
>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.createButton"
defaultMessage="Create"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>,
]}
>
<EuiText>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.description"
defaultMessage="Create and manage synonym sets and synonym rules."
/>
</EuiText>
</KibanaPageTemplate.Header>
{synonymsData && !isInitialLoading && !isError && (
<KibanaPageTemplate.Header
pageTitle="Synonyms"
restrictWidth
color="primary"
rightSideItems={[
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiLink
data-test-subj="searchSynonymsSearchSynonymsOverviewApiDocumentationLink"
external
target="_blank"
href={docLinks.synonymsApi}
>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.documentationLink"
defaultMessage="API Documentation"
/>
</EuiLink>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="searchSynonymsSearchSynonymsOverviewCreateButton"
fill
iconType="plusInCircle"
onClick={() => {
setIsCreateModalVisible(true);
}}
>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.createButton"
defaultMessage="Create"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>,
]}
>
<EuiText>
<FormattedMessage
id="xpack.searchSynonyms.synonymsSetDetail.description"
defaultMessage="Create and manage synonym sets and synonym rules."
/>
</EuiText>
</KibanaPageTemplate.Header>
)}
<KibanaPageTemplate.Section restrictWidth>
{isCreateModalVisible && (
<CreateSynonymsSetModal
Expand All @@ -97,6 +101,9 @@ export const SearchSynonymsOverview = () => {
/>
)}
{isInitialLoading && <EuiLoadingSpinner />}
{isError && (
<ErrorPrompt errorType={isPermissionError(error) ? 'missingPermissions' : 'generic'} />
)}

{!isInitialLoading && synonymsData && synonymsData._meta.totalItemCount > 0 && (
<SynonymSets />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -16,7 +17,7 @@ export const useFetchSynonymsSets = (page: Page = DEFAULT_PAGE_VALUE) => {
const {
services: { http },
} = useKibana();
return useQuery({
return useQuery<Paginate<SynonymsGetSynonymsSetsSynonymsSetItem>, { body: KibanaServerError }>({
queryKey: [SYNONYMS_SETS_QUERY_KEY, page.from, page.size],
queryFn: async () => {
return await http.get<Paginate<SynonymsGetSynonymsSetsSynonymsSetItem>>(
Expand All @@ -26,5 +27,7 @@ export const useFetchSynonymsSets = (page: Page = DEFAULT_PAGE_VALUE) => {
}
);
},
refetchOnWindowFocus: false,
retry: false,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -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('=>');
Expand Down Expand Up @@ -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;
};

0 comments on commit e623cbc

Please sign in to comment.