diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/tabs/RelatedTerms.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/tabs/RelatedTerms.tsx
index dfa3cc64832..d0221548db3 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/tabs/RelatedTerms.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/tabs/RelatedTerms.tsx
@@ -269,6 +269,7 @@ const RelatedTerms = ({
defaultValue={selectedOption.map(
(item) => item.fullyQualifiedName ?? ''
)}
+ filterOptions={[glossaryTerm?.fullyQualifiedName ?? '']}
placeholder={t('label.add-entity', {
entity: t('label.related-term-plural'),
})}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsSelectForm/TagsSelectForm.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsSelectForm/TagsSelectForm.component.tsx
index 9dcf637d4e9..393bb42f1ed 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsSelectForm/TagsSelectForm.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsSelectForm/TagsSelectForm.component.tsx
@@ -28,6 +28,7 @@ const TagSelectForm = ({
onCancel,
tagData,
tagType,
+ filterOptions,
}: TagsSelectFormProps) => {
const [form] = useForm();
const [isSubmitLoading, setIsSubmitLoading] = useState(false);
@@ -52,6 +53,7 @@ const TagSelectForm = ({
) : (
void;
onSubmit: (option: DefaultOptionType | DefaultOptionType[]) => Promise;
onCancel: () => void;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.test.tsx
index 888f7b71289..1093729a8f7 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.test.tsx
@@ -32,6 +32,7 @@ jest.mock('../../../utils/GlossaryUtils', () => ({
]),
convertGlossaryTermsToTreeOptions: jest.fn(),
findGlossaryTermByFqn: jest.fn(),
+ filterTreeNodeOptions: jest.fn().mockReturnValue([]),
}));
describe('TreeAsyncSelectList', () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.tsx
index 7223100839c..57adb0e744e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/common/AsyncSelectList/TreeAsyncSelectList.tsx
@@ -41,6 +41,7 @@ import {
import { getEntityName } from '../../../utils/EntityUtils';
import {
convertGlossaryTermsToTreeOptions,
+ filterTreeNodeOptions,
findGlossaryTermByFqn,
} from '../../../utils/GlossaryUtils';
import {
@@ -63,6 +64,7 @@ const TreeAsyncSelectList: FC> = ({
initialOptions,
tagType,
isSubmitLoading,
+ filterOptions = [],
onCancel,
...props
}) => {
@@ -82,7 +84,9 @@ const TreeAsyncSelectList: FC> = ({
const { data } = await getGlossariesList({
limit: PAGE_SIZE_LARGE,
});
- setGlossaries((prev) => [...prev, ...data]);
+ setGlossaries((prev) =>
+ filterTreeNodeOptions([...prev, ...data], filterOptions)
+ );
} catch (error) {
showErrorToast(error as AxiosError);
} finally {
@@ -229,14 +233,17 @@ const TreeAsyncSelectList: FC> = ({
const activeGlossary = results[0];
setGlossaries((prev) =>
- prev.map((glossary) => ({
- ...glossary,
- children: get(
- glossary.id === activeGlossary?.id ? activeGlossary : glossary,
- 'children',
- []
- ),
- }))
+ filterTreeNodeOptions(
+ prev.map((glossary) => ({
+ ...glossary,
+ children: get(
+ glossary.id === activeGlossary?.id ? activeGlossary : glossary,
+ 'children',
+ []
+ ),
+ })),
+ filterOptions
+ )
);
} catch (error) {
showErrorToast(error as AxiosError);
@@ -248,7 +255,7 @@ const TreeAsyncSelectList: FC> = ({
const encodedValue = getEncodedFqn(escapeESReservedCharacters(value));
const results: Glossary[] = await searchGlossaryTerms(encodedValue);
- setSearchOptions(results);
+ setSearchOptions(filterTreeNodeOptions(results, filterOptions));
setExpandedRowKeys(
results.map((result) => result.fullyQualifiedName as string)
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.test.ts
index c6cb6006e23..bea6c81ae09 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.test.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.test.ts
@@ -12,6 +12,7 @@
*/
import { ModifiedGlossaryTerm } from '../components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
import { EntityType } from '../enums/entity.enum';
+import { Glossary } from '../generated/entity/data/glossary';
import {
MOCKED_GLOSSARY_TERMS,
MOCKED_GLOSSARY_TERMS_1,
@@ -20,6 +21,7 @@ import {
} from '../mocks/Glossary.mock';
import {
buildTree,
+ filterTreeNodeOptions,
findExpandableKeys,
findExpandableKeysForArray,
getQueryFilterToExcludeTerm,
@@ -159,4 +161,61 @@ describe('Glossary Utils', () => {
expect(expandableKeys).toEqual(['example1', 'example2']);
});
+
+ it('Should return same Glossary when no filterOption is provided', () => {
+ const glossary = [
+ {
+ fullyQualifiedName: 'example1',
+ children: [
+ {
+ fullyQualifiedName: 'child1',
+ },
+ ],
+ },
+ {
+ fullyQualifiedName: 'example2',
+ childrenCount: 2,
+ },
+ {
+ fullyQualifiedName: 'example3',
+ },
+ ];
+
+ const filteredOptions = filterTreeNodeOptions(glossary as Glossary[], []);
+
+ expect(filteredOptions).toEqual(glossary);
+ });
+
+ it('Should return filtered Glossary when filterOption is provided', () => {
+ const glossary = [
+ {
+ fullyQualifiedName: 'example1',
+ children: [
+ {
+ fullyQualifiedName: 'child1',
+ },
+ ],
+ },
+ {
+ fullyQualifiedName: 'example3',
+ },
+ ];
+
+ const expected_glossary = [
+ {
+ fullyQualifiedName: 'example1',
+ children: [],
+ },
+ {
+ fullyQualifiedName: 'example3',
+ children: [],
+ },
+ ];
+
+ const filteredOptions = filterTreeNodeOptions(glossary as Glossary[], [
+ 'child1',
+ ]);
+
+ expect(filteredOptions).toEqual(expected_glossary);
+ });
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx
index fef037b108d..3522c20bb83 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx
@@ -13,7 +13,7 @@
import { Typography } from 'antd';
import { DefaultOptionType } from 'antd/lib/select';
-import { isEmpty } from 'lodash';
+import { isEmpty, isUndefined } from 'lodash';
import React from 'react';
import { StatusType } from '../components/common/StatusBadge/StatusBadge.interface';
import { ModifiedGlossaryTerm } from '../components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
@@ -265,3 +265,47 @@ export const findExpandableKeysForArray = (
return expandableKeys;
};
+
+/**
+ * Filter out the tree node options based on the filter options.
+ *
+ * @param options - An array of Glossary objects.
+ * @param filterOptions - An array of FQN string to filter.
+ * @returns An array of filtered Glossary
+ */
+export const filterTreeNodeOptions = (
+ options: Glossary[],
+ filterOptions: string[]
+): Glossary[] => {
+ if (isEmpty(filterOptions)) {
+ return options;
+ }
+
+ const filterNodes = (
+ nodes: ModifiedGlossaryTerm[]
+ ): ModifiedGlossaryTerm[] => {
+ return nodes.reduce(
+ (acc: ModifiedGlossaryTerm[], node: ModifiedGlossaryTerm) => {
+ const isMatching = filterOptions.includes(
+ node.fullyQualifiedName ?? ''
+ );
+
+ const filteredChildren = !isUndefined(node.children)
+ ? filterNodes(node.children as unknown as ModifiedGlossaryTerm[])
+ : [];
+
+ if (!isMatching) {
+ acc.push({
+ ...node,
+ children: filteredChildren as GlossaryTerm[],
+ });
+ }
+
+ return acc;
+ },
+ []
+ );
+ };
+
+ return filterNodes(options as ModifiedGlossaryTerm[]);
+};