mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 02:29:03 +00:00 
			
		
		
		
	fix(ui): shown children tab in storage container in case of schema empty (#13172)
* shown children tab in storage container in case of schema empty * fix unit test * fix unit test --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									af6cd905e9
								
							
						
					
					
						commit
						64607c8869
					
				| @ -15,6 +15,7 @@ import React from 'react'; | |||||||
| import { BrowserRouter } from 'react-router-dom'; | import { BrowserRouter } from 'react-router-dom'; | ||||||
| import ContainerChildren from './ContainerChildren'; | import ContainerChildren from './ContainerChildren'; | ||||||
| 
 | 
 | ||||||
|  | const mockFetchChildren = jest.fn(); | ||||||
| const mockChildrenList = [ | const mockChildrenList = [ | ||||||
|   { |   { | ||||||
|     id: '1', |     id: '1', | ||||||
| @ -32,11 +33,26 @@ const mockChildrenList = [ | |||||||
|   }, |   }, | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
|  | const mockDataProps = { | ||||||
|  |   childrenList: mockChildrenList, | ||||||
|  |   fetchChildren: mockFetchChildren, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| describe('ContainerChildren', () => { | describe('ContainerChildren', () => { | ||||||
|  |   it('Should call fetch container function on load', () => { | ||||||
|  |     render( | ||||||
|  |       <BrowserRouter> | ||||||
|  |         <ContainerChildren {...mockDataProps} /> | ||||||
|  |       </BrowserRouter> | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     expect(mockFetchChildren).toHaveBeenCalled(); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|   it('Should render table with correct columns', () => { |   it('Should render table with correct columns', () => { | ||||||
|     render( |     render( | ||||||
|       <BrowserRouter> |       <BrowserRouter> | ||||||
|         <ContainerChildren childrenList={mockChildrenList} /> |         <ContainerChildren {...mockDataProps} /> | ||||||
|       </BrowserRouter> |       </BrowserRouter> | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -48,7 +64,7 @@ describe('ContainerChildren', () => { | |||||||
|   it('Should render container names as links', () => { |   it('Should render container names as links', () => { | ||||||
|     render( |     render( | ||||||
|       <BrowserRouter> |       <BrowserRouter> | ||||||
|         <ContainerChildren childrenList={mockChildrenList} /> |         <ContainerChildren {...mockDataProps} /> | ||||||
|       </BrowserRouter> |       </BrowserRouter> | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -68,7 +84,7 @@ describe('ContainerChildren', () => { | |||||||
|   it('Should render container descriptions as rich text', () => { |   it('Should render container descriptions as rich text', () => { | ||||||
|     render( |     render( | ||||||
|       <BrowserRouter> |       <BrowserRouter> | ||||||
|         <ContainerChildren childrenList={mockChildrenList} /> |         <ContainerChildren {...mockDataProps} /> | ||||||
|       </BrowserRouter> |       </BrowserRouter> | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ import Table from 'components/common/Table/Table'; | |||||||
| import { getContainerDetailPath } from 'constants/constants'; | import { getContainerDetailPath } from 'constants/constants'; | ||||||
| import { Container } from 'generated/entity/data/container'; | import { Container } from 'generated/entity/data/container'; | ||||||
| import { EntityReference } from 'generated/type/entityReference'; | import { EntityReference } from 'generated/type/entityReference'; | ||||||
| import React, { FC, useMemo } from 'react'; | import React, { FC, useEffect, useMemo } from 'react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
| import { getEntityName } from 'utils/EntityUtils'; | import { getEntityName } from 'utils/EntityUtils'; | ||||||
| @ -26,11 +26,13 @@ import { getEntityName } from 'utils/EntityUtils'; | |||||||
| interface ContainerChildrenProps { | interface ContainerChildrenProps { | ||||||
|   childrenList: Container['children']; |   childrenList: Container['children']; | ||||||
|   isLoading?: boolean; |   isLoading?: boolean; | ||||||
|  |   fetchChildren: () => void; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const ContainerChildren: FC<ContainerChildrenProps> = ({ | const ContainerChildren: FC<ContainerChildrenProps> = ({ | ||||||
|   childrenList, |   childrenList, | ||||||
|   isLoading, |   isLoading, | ||||||
|  |   fetchChildren, | ||||||
| }) => { | }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
| 
 | 
 | ||||||
| @ -72,6 +74,10 @@ const ContainerChildren: FC<ContainerChildrenProps> = ({ | |||||||
|     [] |     [] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     fetchChildren(); | ||||||
|  |   }, []); | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Table |     <Table | ||||||
|       bordered |       bordered | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ import { CreateThread, ThreadType } from 'generated/api/feed/createThread'; | |||||||
| import { Container } from 'generated/entity/data/container'; | import { Container } from 'generated/entity/data/container'; | ||||||
| import { Include } from 'generated/type/include'; | import { Include } from 'generated/type/include'; | ||||||
| import { LabelType, State, TagLabel, TagSource } from 'generated/type/tagLabel'; | import { LabelType, State, TagLabel, TagSource } from 'generated/type/tagLabel'; | ||||||
| import { isUndefined, omitBy, toString } from 'lodash'; | import { isEmpty, isUndefined, omitBy, toString } from 'lodash'; | ||||||
| import { observer } from 'mobx-react'; | import { observer } from 'mobx-react'; | ||||||
| import { EntityTags } from 'Models'; | import { EntityTags } from 'Models'; | ||||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||||
| @ -79,7 +79,7 @@ const ContainerPage = () => { | |||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { getEntityPermissionByFqn } = usePermissionProvider(); |   const { getEntityPermissionByFqn } = usePermissionProvider(); | ||||||
|   const { postFeed, deleteFeed, updateFeed } = useActivityFeedProvider(); |   const { postFeed, deleteFeed, updateFeed } = useActivityFeedProvider(); | ||||||
|   const { entityFQN: containerName, tab = EntityTabs.SCHEMA } = |   const { entityFQN: containerName, tab } = | ||||||
|     useParams<{ entityFQN: string; tab: EntityTabs }>(); |     useParams<{ entityFQN: string; tab: EntityTabs }>(); | ||||||
| 
 | 
 | ||||||
|   // Local states
 |   // Local states
 | ||||||
| @ -130,10 +130,10 @@ const ContainerPage = () => { | |||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const fetchContainerChildren = async (containerFQN: string) => { |   const fetchContainerChildren = async () => { | ||||||
|     setIsChildrenLoading(true); |     setIsChildrenLoading(true); | ||||||
|     try { |     try { | ||||||
|       const { children } = await getContainerByName(containerFQN, 'children'); |       const { children } = await getContainerByName(containerName, 'children'); | ||||||
|       setContainerChildrenData(children); |       setContainerChildrenData(children); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       showErrorToast(error as AxiosError); |       showErrorToast(error as AxiosError); | ||||||
| @ -218,6 +218,11 @@ const ContainerPage = () => { | |||||||
|     [AppState.userDetails, AppState.nonSecureUserDetails] |     [AppState.userDetails, AppState.nonSecureUserDetails] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|  |   const isDataModelEmpty = useMemo( | ||||||
|  |     () => isEmpty(containerData?.dataModel), | ||||||
|  |     [containerData] | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|   const getEntityFeedCount = () => { |   const getEntityFeedCount = () => { | ||||||
|     getFeedCounts(EntityType.CONTAINER, containerName, setFeedCount); |     getFeedCounts(EntityType.CONTAINER, containerName, setFeedCount); | ||||||
|   }; |   }; | ||||||
| @ -484,8 +489,13 @@ const ContainerPage = () => { | |||||||
|   const tabs = useMemo( |   const tabs = useMemo( | ||||||
|     () => [ |     () => [ | ||||||
|       { |       { | ||||||
|         label: <TabsLabel id={EntityTabs.SCHEMA} name={t('label.schema')} />, |         label: ( | ||||||
|         key: EntityTabs.SCHEMA, |           <TabsLabel | ||||||
|  |             id={isDataModelEmpty ? EntityTabs.CHILDREN : EntityTabs.SCHEMA} | ||||||
|  |             name={t(isDataModelEmpty ? 'label.children' : 'label.schema')} | ||||||
|  |           /> | ||||||
|  |         ), | ||||||
|  |         key: isDataModelEmpty ? EntityTabs.CHILDREN : EntityTabs.SCHEMA, | ||||||
|         children: ( |         children: ( | ||||||
|           <Row gutter={[0, 16]} wrap={false}> |           <Row gutter={[0, 16]} wrap={false}> | ||||||
|             <Col className="p-t-sm m-x-lg" flex="auto"> |             <Col className="p-t-sm m-x-lg" flex="auto"> | ||||||
| @ -505,15 +515,23 @@ const ContainerPage = () => { | |||||||
|                   onThreadLinkSelect={onThreadLinkSelect} |                   onThreadLinkSelect={onThreadLinkSelect} | ||||||
|                 /> |                 /> | ||||||
| 
 | 
 | ||||||
|                 <ContainerDataModel |                 {isDataModelEmpty ? ( | ||||||
|                   dataModel={containerData?.dataModel} |                   <ContainerChildren | ||||||
|                   entityFqn={containerName} |                     childrenList={containerChildrenData} | ||||||
|                   hasDescriptionEditAccess={hasEditDescriptionPermission} |                     fetchChildren={fetchContainerChildren} | ||||||
|                   hasTagEditAccess={hasEditTagsPermission} |                     isLoading={isChildrenLoading} | ||||||
|                   isReadOnly={Boolean(deleted)} |                   /> | ||||||
|                   onThreadLinkSelect={onThreadLinkSelect} |                 ) : ( | ||||||
|                   onUpdate={handleUpdateDataModel} |                   <ContainerDataModel | ||||||
|                 /> |                     dataModel={containerData?.dataModel} | ||||||
|  |                     entityFqn={containerName} | ||||||
|  |                     hasDescriptionEditAccess={hasEditDescriptionPermission} | ||||||
|  |                     hasTagEditAccess={hasEditTagsPermission} | ||||||
|  |                     isReadOnly={Boolean(deleted)} | ||||||
|  |                     onThreadLinkSelect={onThreadLinkSelect} | ||||||
|  |                     onUpdate={handleUpdateDataModel} | ||||||
|  |                   /> | ||||||
|  |                 )} | ||||||
|               </div> |               </div> | ||||||
|             </Col> |             </Col> | ||||||
|             <Col |             <Col | ||||||
| @ -550,6 +568,31 @@ const ContainerPage = () => { | |||||||
|           </Row> |           </Row> | ||||||
|         ), |         ), | ||||||
|       }, |       }, | ||||||
|  |       ...(isDataModelEmpty | ||||||
|  |         ? [] | ||||||
|  |         : [ | ||||||
|  |             { | ||||||
|  |               label: ( | ||||||
|  |                 <TabsLabel | ||||||
|  |                   id={EntityTabs.CHILDREN} | ||||||
|  |                   name={t('label.children')} | ||||||
|  |                 /> | ||||||
|  |               ), | ||||||
|  |               key: EntityTabs.CHILDREN, | ||||||
|  |               children: ( | ||||||
|  |                 <Row className="p-md" gutter={[0, 16]}> | ||||||
|  |                   <Col span={24}> | ||||||
|  |                     <ContainerChildren | ||||||
|  |                       childrenList={containerChildrenData} | ||||||
|  |                       fetchChildren={fetchContainerChildren} | ||||||
|  |                       isLoading={isChildrenLoading} | ||||||
|  |                     /> | ||||||
|  |                   </Col> | ||||||
|  |                 </Row> | ||||||
|  |               ), | ||||||
|  |             }, | ||||||
|  |           ]), | ||||||
|  | 
 | ||||||
|       { |       { | ||||||
|         label: ( |         label: ( | ||||||
|           <TabsLabel |           <TabsLabel | ||||||
| @ -569,23 +612,6 @@ const ContainerPage = () => { | |||||||
|           /> |           /> | ||||||
|         ), |         ), | ||||||
|       }, |       }, | ||||||
|       { |  | ||||||
|         label: ( |  | ||||||
|           <TabsLabel id={EntityTabs.CHILDREN} name={t('label.children')} /> |  | ||||||
|         ), |  | ||||||
|         key: EntityTabs.CHILDREN, |  | ||||||
|         children: ( |  | ||||||
|           <Row className="p-md" gutter={[0, 16]}> |  | ||||||
|             <Col span={24}> |  | ||||||
|               <ContainerChildren |  | ||||||
|                 childrenList={containerChildrenData} |  | ||||||
|                 isLoading={isChildrenLoading} |  | ||||||
|               /> |  | ||||||
|             </Col> |  | ||||||
|           </Row> |  | ||||||
|         ), |  | ||||||
|       }, |  | ||||||
| 
 |  | ||||||
|       { |       { | ||||||
|         label: <TabsLabel id={EntityTabs.LINEAGE} name={t('label.lineage')} />, |         label: <TabsLabel id={EntityTabs.LINEAGE} name={t('label.lineage')} />, | ||||||
|         key: EntityTabs.LINEAGE, |         key: EntityTabs.LINEAGE, | ||||||
| @ -619,6 +645,7 @@ const ContainerPage = () => { | |||||||
|       }, |       }, | ||||||
|     ], |     ], | ||||||
|     [ |     [ | ||||||
|  |       isDataModelEmpty, | ||||||
|       containerData, |       containerData, | ||||||
|       description, |       description, | ||||||
|       containerName, |       containerName, | ||||||
| @ -667,12 +694,6 @@ const ContainerPage = () => { | |||||||
|     fetchResourcePermission(containerName); |     fetchResourcePermission(containerName); | ||||||
|   }, [containerName]); |   }, [containerName]); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |  | ||||||
|     if (tab === EntityTabs.CHILDREN && hasViewPermission) { |  | ||||||
|       fetchContainerChildren(containerName); |  | ||||||
|     } |  | ||||||
|   }, [tab, containerName, hasViewPermission]); |  | ||||||
| 
 |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (hasViewPermission) { |     if (hasViewPermission) { | ||||||
|       getEntityFeedCount(); |       getEntityFeedCount(); | ||||||
| @ -723,7 +744,10 @@ const ContainerPage = () => { | |||||||
|         </Col> |         </Col> | ||||||
|         <Col span={24}> |         <Col span={24}> | ||||||
|           <Tabs |           <Tabs | ||||||
|             activeKey={tab ?? EntityTabs.DETAILS} |             activeKey={ | ||||||
|  |               tab ?? | ||||||
|  |               (isDataModelEmpty ? EntityTabs.CHILDREN : EntityTabs.SCHEMA) | ||||||
|  |             } | ||||||
|             className="entity-details-page-tabs" |             className="entity-details-page-tabs" | ||||||
|             data-testid="tabs" |             data-testid="tabs" | ||||||
|             items={tabs} |             items={tabs} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ashish Gupta
						Ashish Gupta