mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-01 19:18:05 +00:00
✨ UI : Add custom properties support for all entities (#6350)
* ✨ UI : Add custom properties support for all entities
* Add custom properties for topic entity
* use async await pattern
* Add custom property support for dashboard entity
* Add custom property support for pipeline entity
* minor fix
* Fix unit test
* Add custom property support for ml model entity
* Fix unit test
* Add unit tests
* Add extension
* Fix formatting
* Addressing review comment
* Addressing review comments
This commit is contained in:
parent
c6efe8c142
commit
b9eaeb8aeb
@ -53,6 +53,8 @@ import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||
import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
|
||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
|
||||
@ -112,6 +114,7 @@ const DashboardDetails = ({
|
||||
fetchFeedHandler,
|
||||
updateThreadHandler,
|
||||
entityFieldTaskCount,
|
||||
onExtensionUpdate,
|
||||
}: DashboardDetailsProps) => {
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [followersCount, setFollowersCount] = useState(0);
|
||||
@ -192,6 +195,11 @@ const DashboardDetails = ({
|
||||
isProtected: false,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
isProtected: false,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
icon: {
|
||||
@ -202,7 +210,7 @@ const DashboardDetails = ({
|
||||
},
|
||||
isProtected: true,
|
||||
protectedState: !owner || hasEditAccess(),
|
||||
position: 4,
|
||||
position: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@ -739,6 +747,15 @@ const DashboardDetails = ({
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 4 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
dashboardDetails as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.DASHBOARD}
|
||||
handleExtentionUpdate={onExtensionUpdate}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 5 && (
|
||||
<div>
|
||||
<ManageTabComponent
|
||||
allowDelete
|
||||
|
||||
@ -92,4 +92,5 @@ export interface DashboardDetailsProps {
|
||||
postFeedHandler: (value: string, id: string) => void;
|
||||
deletePostHandler: (threadId: string, postId: string) => void;
|
||||
updateThreadHandler: ThreadUpdatedFunc;
|
||||
onExtensionUpdate: (updatedDashboard: Dashboard) => void;
|
||||
}
|
||||
|
||||
@ -118,6 +118,7 @@ const DashboardDetailsProps = {
|
||||
paging: {} as Paging,
|
||||
fetchFeedHandler: jest.fn(),
|
||||
updateThreadHandler: jest.fn(),
|
||||
onExtensionUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
const mockObserve = jest.fn();
|
||||
@ -336,7 +337,7 @@ describe('Test DashboardDetails component', () => {
|
||||
|
||||
it('Check if active tab is manage', async () => {
|
||||
const { container } = render(
|
||||
<DashboardDetails {...DashboardDetailsProps} activeTab={4} />,
|
||||
<DashboardDetails {...DashboardDetailsProps} activeTab={5} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
@ -346,6 +347,21 @@ describe('Test DashboardDetails component', () => {
|
||||
expect(manage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<DashboardDetails {...DashboardDetailsProps} activeTab={4} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const customProperties = await findByTestId(
|
||||
container,
|
||||
'custom-properties-table'
|
||||
);
|
||||
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
const { container } = render(
|
||||
<DashboardDetails {...DashboardDetailsProps} activeTab={4} />,
|
||||
|
||||
@ -57,6 +57,8 @@ import {
|
||||
} from '../../utils/TableUtils';
|
||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
@ -75,7 +77,6 @@ import SchemaTab from '../SchemaTab/SchemaTab.component';
|
||||
import TableProfiler from '../TableProfiler/TableProfiler.component';
|
||||
import TableProfilerGraph from '../TableProfiler/TableProfilerGraph.component';
|
||||
import TableQueries from '../TableQueries/TableQueries';
|
||||
import { CustomPropertyTable } from './CustomPropertyTable/CustomPropertyTable';
|
||||
import { DatasetDetailsProps } from './DatasetDetails.interface';
|
||||
|
||||
const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
@ -295,12 +296,6 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
icon: {
|
||||
alt: 'custom_properties',
|
||||
name: 'custom_properties-light-grey',
|
||||
title: 'custom_properties',
|
||||
selectedName: 'custom_properties-primery',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 9,
|
||||
},
|
||||
@ -842,8 +837,11 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
)}
|
||||
{activeTab === 9 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
tableDetails as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.TABLE}
|
||||
handleExtentionUpdate={handleExtentionUpdate}
|
||||
tableDetails={tableDetails}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 10 && (
|
||||
|
||||
@ -350,6 +350,21 @@ describe('Test MyDataDetailsPage page', () => {
|
||||
expect(manage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={9} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const customProperties = await findByTestId(
|
||||
container,
|
||||
'custom-properties-table'
|
||||
);
|
||||
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={9} />,
|
||||
|
||||
@ -152,6 +152,7 @@ const mockProp = {
|
||||
lineageLeafNodes: {} as LeafNodes,
|
||||
isNodeLoading: { id: undefined, state: false },
|
||||
},
|
||||
onExtensionUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('../ManageTab/ManageTab.component', () => {
|
||||
@ -254,7 +255,7 @@ describe('Test MlModel entity detail component', () => {
|
||||
|
||||
it('Should render manage component for manage tab', async () => {
|
||||
const { container } = render(
|
||||
<MlModelDetailComponent {...mockProp} activeTab={4} />,
|
||||
<MlModelDetailComponent {...mockProp} activeTab={5} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
@ -266,4 +267,19 @@ describe('Test MlModel entity detail component', () => {
|
||||
expect(detailContainer).toBeInTheDocument();
|
||||
expect(manageTab).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<MlModelDetailComponent {...mockProp} activeTab={4} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const customProperties = await findByTestId(
|
||||
container,
|
||||
'custom-properties-table'
|
||||
);
|
||||
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@ -45,6 +45,8 @@ import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
||||
import { getEntityName, getEntityPlaceHolder } from '../../utils/CommonUtils';
|
||||
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
||||
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
|
||||
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
@ -75,6 +77,7 @@ interface MlModelDetailProp extends HTMLAttributes<HTMLDivElement> {
|
||||
lineageLeafNodes: LeafNodes;
|
||||
isNodeLoading: LoadingNodeState;
|
||||
};
|
||||
onExtensionUpdate: (updatedMlModel: Mlmodel) => void;
|
||||
}
|
||||
|
||||
const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
@ -88,6 +91,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
settingsUpdateHandler,
|
||||
updateMlModelFeatures,
|
||||
lineageTabData,
|
||||
onExtensionUpdate,
|
||||
}) => {
|
||||
const [followersCount, setFollowersCount] = useState<number>(0);
|
||||
const [isFollowing, setIsFollowing] = useState<boolean>(false);
|
||||
@ -213,6 +217,11 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
isProtected: false,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
isProtected: false,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
icon: {
|
||||
@ -223,7 +232,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
},
|
||||
isProtected: false,
|
||||
protectedState: !mlModelDetail.owner || hasEditAccess(),
|
||||
position: 4,
|
||||
position: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@ -536,6 +545,15 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 4 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
mlModelDetail as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.MLMODEL}
|
||||
handleExtentionUpdate={onExtensionUpdate}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 5 && (
|
||||
<div>
|
||||
<ManageTabComponent
|
||||
allowDelete
|
||||
|
||||
@ -43,6 +43,8 @@ import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
@ -100,6 +102,7 @@ const PipelineDetails = ({
|
||||
pipelineStatus,
|
||||
updateThreadHandler,
|
||||
entityFieldTaskCount,
|
||||
onExtensionUpdate,
|
||||
}: PipeLineDetailsProp) => {
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [followersCount, setFollowersCount] = useState(0);
|
||||
@ -186,6 +189,11 @@ const PipelineDetails = ({
|
||||
isProtected: false,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
isProtected: false,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
icon: {
|
||||
@ -196,7 +204,7 @@ const PipelineDetails = ({
|
||||
},
|
||||
isProtected: true,
|
||||
protectedState: !owner || hasEditAccess(),
|
||||
position: 4,
|
||||
position: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@ -524,6 +532,15 @@ const PipelineDetails = ({
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 4 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
pipelineDetails as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.PIPELINE}
|
||||
handleExtentionUpdate={onExtensionUpdate}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 5 && (
|
||||
<div>
|
||||
<ManageTabComponent
|
||||
allowDelete
|
||||
|
||||
@ -79,4 +79,5 @@ export interface PipeLineDetailsProp {
|
||||
postFeedHandler: (value: string, id: string) => void;
|
||||
deletePostHandler: (threadId: string, postId: string) => void;
|
||||
updateThreadHandler: ThreadUpdatedFunc;
|
||||
onExtensionUpdate: (updatedPipeline: Pipeline) => void;
|
||||
}
|
||||
|
||||
@ -125,6 +125,7 @@ const PipelineDetailsProps = {
|
||||
pipelineStatus: [],
|
||||
isPipelineStatusLoading: false,
|
||||
updateThreadHandler: jest.fn(),
|
||||
onExtensionUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
const mockObserve = jest.fn();
|
||||
@ -274,7 +275,7 @@ describe('Test PipelineDetails component', () => {
|
||||
|
||||
it('Check if active tab is manage', async () => {
|
||||
const { container } = render(
|
||||
<PipelineDetails {...PipelineDetailsProps} activeTab={4} />,
|
||||
<PipelineDetails {...PipelineDetailsProps} activeTab={5} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
@ -284,6 +285,21 @@ describe('Test PipelineDetails component', () => {
|
||||
expect(manage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<PipelineDetails {...PipelineDetailsProps} activeTab={4} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const customProperties = await findByTestId(
|
||||
container,
|
||||
'custom-properties-table'
|
||||
);
|
||||
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
const { container } = render(
|
||||
<PipelineDetails {...PipelineDetailsProps} activeTab={4} />,
|
||||
|
||||
@ -44,6 +44,8 @@ import { bytesToSize } from '../../utils/StringsUtils';
|
||||
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
@ -97,6 +99,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
||||
updateThreadHandler,
|
||||
entityFieldTaskCount,
|
||||
lineageTabData,
|
||||
onExtensionUpdate,
|
||||
}: TopicDetailsProps) => {
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [followersCount, setFollowersCount] = useState(0);
|
||||
@ -221,6 +224,11 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
||||
isProtected: false,
|
||||
position: 5,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
isProtected: false,
|
||||
position: 6,
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
icon: {
|
||||
@ -231,7 +239,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
||||
},
|
||||
isProtected: true,
|
||||
protectedState: !owner || hasEditAccess(),
|
||||
position: 6,
|
||||
position: 7,
|
||||
},
|
||||
];
|
||||
const extraInfo: Array<ExtraInfo> = [
|
||||
@ -557,6 +565,15 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 6 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
topicDetails as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.TOPIC}
|
||||
handleExtentionUpdate={onExtensionUpdate}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 7 && (
|
||||
<div>
|
||||
<ManageTabComponent
|
||||
allowDelete
|
||||
|
||||
@ -84,4 +84,5 @@ export interface TopicDetailsProps {
|
||||
lineageLeafNodes: LeafNodes;
|
||||
isNodeLoading: LoadingNodeState;
|
||||
};
|
||||
onExtensionUpdate: (updatedTopic: Topic) => void;
|
||||
}
|
||||
|
||||
@ -111,6 +111,7 @@ const TopicDetailsProps = {
|
||||
lineageLeafNodes: {} as LeafNodes,
|
||||
isNodeLoading: { id: undefined, state: false },
|
||||
},
|
||||
onExtensionUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
const mockObserve = jest.fn();
|
||||
@ -240,7 +241,7 @@ describe('Test TopicDetails component', () => {
|
||||
|
||||
it('Check if active tab is manage', async () => {
|
||||
const { container } = render(
|
||||
<TopicDetails {...TopicDetailsProps} activeTab={6} />,
|
||||
<TopicDetails {...TopicDetailsProps} activeTab={7} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
@ -263,6 +264,21 @@ describe('Test TopicDetails component', () => {
|
||||
expect(detailContainer).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<TopicDetails {...TopicDetailsProps} activeTab={6} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const customProperties = await findByTestId(
|
||||
container,
|
||||
'custom-properties-table'
|
||||
);
|
||||
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
const { container } = render(
|
||||
<TopicDetails {...TopicDetailsProps} activeTab={4} />,
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EntityType } from '../../../enums/entity.enum';
|
||||
import { Dashboard } from '../../../generated/entity/data/dashboard';
|
||||
import { Mlmodel } from '../../../generated/entity/data/mlmodel';
|
||||
import { Pipeline } from '../../../generated/entity/data/pipeline';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { Topic } from '../../../generated/entity/data/topic';
|
||||
|
||||
export type EntityDetails = Table & Topic & Dashboard & Pipeline & Mlmodel;
|
||||
|
||||
export interface CustomPropertyProps {
|
||||
entityDetails: EntityDetails;
|
||||
entityType: EntityType;
|
||||
handleExtentionUpdate: (updatedTable: EntityDetails) => void;
|
||||
}
|
||||
@ -14,7 +14,12 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { getTypeByFQN } from '../../../axiosAPIs/metadataTypeAPI';
|
||||
import { EntityType } from '../../../enums/entity.enum';
|
||||
import { Dashboard } from '../../../generated/entity/data/dashboard';
|
||||
import { Mlmodel } from '../../../generated/entity/data/mlmodel';
|
||||
import { Pipeline } from '../../../generated/entity/data/pipeline';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { Topic } from '../../../generated/entity/data/topic';
|
||||
import { CustomPropertyTable } from './CustomPropertyTable';
|
||||
|
||||
const mockCustomProperties = [
|
||||
@ -53,12 +58,13 @@ jest.mock('../../../axiosAPIs/metadataTypeAPI', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
const mockTableDetails = {} as Table;
|
||||
const mockTableDetails = {} as Table & Topic & Dashboard & Pipeline & Mlmodel;
|
||||
const handleExtentionUpdate = jest.fn();
|
||||
|
||||
const mockProp = {
|
||||
tableDetails: mockTableDetails,
|
||||
entityDetails: mockTableDetails,
|
||||
handleExtentionUpdate,
|
||||
entityType: EntityType.TABLE,
|
||||
};
|
||||
|
||||
describe('Test CustomProperty Table Component', () => {
|
||||
@ -16,25 +16,21 @@ import classNames from 'classnames';
|
||||
import { uniqueId } from 'lodash';
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
import { getTypeByFQN } from '../../../axiosAPIs/metadataTypeAPI';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { Type } from '../../../generated/entity/type';
|
||||
import { isEven } from '../../../utils/CommonUtils';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import { CustomPropertyProps } from './CustomPropertyTable.interface';
|
||||
import { PropertyValue } from './PropertyValue';
|
||||
|
||||
interface Props {
|
||||
tableDetails: Table;
|
||||
handleExtentionUpdate: (updatedTable: Table) => void;
|
||||
}
|
||||
|
||||
export const CustomPropertyTable: FC<Props> = ({
|
||||
tableDetails,
|
||||
export const CustomPropertyTable: FC<CustomPropertyProps> = ({
|
||||
entityDetails,
|
||||
handleExtentionUpdate,
|
||||
entityType,
|
||||
}) => {
|
||||
const [entityTypeDetail, setEntityTypeDetail] = useState<Type>({} as Type);
|
||||
|
||||
const fetchTypeDetail = () => {
|
||||
getTypeByFQN('table')
|
||||
getTypeByFQN(entityType)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityTypeDetail(res.data);
|
||||
})
|
||||
@ -43,10 +39,12 @@ export const CustomPropertyTable: FC<Props> = ({
|
||||
|
||||
const customProperties = entityTypeDetail.customProperties || [];
|
||||
|
||||
const extension = tableDetails.extension;
|
||||
const extension = entityDetails.extension;
|
||||
|
||||
const onExtensionUpdate = (updatedExtension: Table['extension']) => {
|
||||
handleExtentionUpdate({ ...tableDetails, extension: updatedExtension });
|
||||
const onExtensionUpdate = (
|
||||
updatedExtension: CustomPropertyProps['entityDetails']['extension']
|
||||
) => {
|
||||
handleExtentionUpdate({ ...entityDetails, extension: updatedExtension });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -16,8 +16,8 @@ import React, { FC, Fragment, useState } from 'react';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { EntityReference } from '../../../generated/type/entityReference';
|
||||
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
|
||||
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
||||
import { PropertyInput } from './PropertyInput';
|
||||
|
||||
interface Props {
|
||||
@ -746,6 +746,27 @@ const DashboardDetailsPage = () => {
|
||||
updateThreadData(threadId, postId, isThread, data, setEntityThread);
|
||||
};
|
||||
|
||||
const handleExtentionUpdate = async (updatedDashboard: Dashboard) => {
|
||||
try {
|
||||
const { data } = await saveUpdatedDashboardData(updatedDashboard);
|
||||
|
||||
if (data) {
|
||||
const { version, owner: ownerValue, tags } = data;
|
||||
setCurrentVersion(version);
|
||||
setDashboardDetails(data);
|
||||
setOwner(ownerValue);
|
||||
setTier(getTierTags(tags));
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['update-entity-error'];
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['update-entity-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTabSpecificData(dashboardDetailsTabs[activeTab - 1].field);
|
||||
}, [activeTab]);
|
||||
@ -816,6 +837,7 @@ const DashboardDetailsPage = () => {
|
||||
updateThreadHandler={updateThreadHandler}
|
||||
version={currentVersion as string}
|
||||
versionHandler={versionHandler}
|
||||
onExtensionUpdate={handleExtentionUpdate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -356,6 +356,23 @@ const MlModelPage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleExtentionUpdate = async (updatedMlModel: Mlmodel) => {
|
||||
try {
|
||||
const { data } = await saveUpdatedMlModelData(updatedMlModel);
|
||||
|
||||
if (data) {
|
||||
setMlModelDetail(data);
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['update-entity-error'];
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['update-entity-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getMlModelDetail = () => {
|
||||
if (!isNil(mlModelDetail) && !isEmpty(mlModelDetail)) {
|
||||
return (
|
||||
@ -379,6 +396,7 @@ const MlModelPage = () => {
|
||||
tagUpdateHandler={onTagUpdate}
|
||||
unfollowMlModelHandler={unfollowMlModel}
|
||||
updateMlModelFeatures={updateMlModelFeatures}
|
||||
onExtensionUpdate={handleExtentionUpdate}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
||||
@ -687,6 +687,27 @@ const PipelineDetailsPage = () => {
|
||||
updateThreadData(threadId, postId, isThread, data, setEntityThread);
|
||||
};
|
||||
|
||||
const handleExtentionUpdate = async (updatedPipeline: Pipeline) => {
|
||||
try {
|
||||
const { data } = await saveUpdatedPipelineData(updatedPipeline);
|
||||
|
||||
if (data) {
|
||||
const { version, owner: ownerValue, tags } = data;
|
||||
setCurrentVersion(version);
|
||||
setPipelineDetails(data);
|
||||
setOwner(ownerValue);
|
||||
setTier(getTierTags(tags));
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['update-entity-error'];
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['update-entity-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTabSpecificData(pipelineDetailsTabs[activeTab - 1].field);
|
||||
}, [activeTab]);
|
||||
@ -757,6 +778,7 @@ const PipelineDetailsPage = () => {
|
||||
updateThreadHandler={updateThreadHandler}
|
||||
version={currentVersion as string}
|
||||
versionHandler={versionHandler}
|
||||
onExtensionUpdate={handleExtentionUpdate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -359,7 +359,12 @@ const TopicDetailsPage: FunctionComponent = () => {
|
||||
|
||||
const fetchTopicDetail = (topicFQN: string) => {
|
||||
setLoading(true);
|
||||
getTopicByFqn(topicFQN, ['owner', 'followers', 'tags'])
|
||||
getTopicByFqn(topicFQN, [
|
||||
TabSpecificField.OWNER,
|
||||
TabSpecificField.FOLLOWERS,
|
||||
TabSpecificField.TAGS,
|
||||
TabSpecificField.EXTENSION,
|
||||
])
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.data) {
|
||||
const {
|
||||
@ -668,6 +673,27 @@ const TopicDetailsPage: FunctionComponent = () => {
|
||||
updateThreadData(threadId, postId, isThread, data, setEntityThread);
|
||||
};
|
||||
|
||||
const handleExtentionUpdate = async (updatedTopic: Topic) => {
|
||||
try {
|
||||
const { data } = await saveUpdatedTopicData(updatedTopic);
|
||||
|
||||
if (data) {
|
||||
const { version, owner: ownerValue, tags } = data;
|
||||
setCurrentVersion(version);
|
||||
setTopicDetails(data);
|
||||
setOwner(ownerValue);
|
||||
setTier(getTierTags(tags));
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['update-entity-error'];
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['update-entity-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (topicDetailsTabs[activeTab - 1].path !== tab) {
|
||||
setActiveTab(getCurrentTopicTab(tab));
|
||||
@ -743,6 +769,7 @@ const TopicDetailsPage: FunctionComponent = () => {
|
||||
updateThreadHandler={updateThreadHandler}
|
||||
version={currentVersion}
|
||||
versionHandler={versionHandler}
|
||||
onExtensionUpdate={handleExtentionUpdate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
import { TabSpecificField } from '../enums/entity.enum';
|
||||
|
||||
export const defaultFields = `${TabSpecificField.OWNER}, ${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS},
|
||||
${TabSpecificField.USAGE_SUMMARY}, ${TabSpecificField.CHARTS}`;
|
||||
${TabSpecificField.USAGE_SUMMARY}, ${TabSpecificField.CHARTS},${TabSpecificField.EXTENSION}`;
|
||||
|
||||
export const dashboardDetailsTabs = [
|
||||
{
|
||||
@ -31,6 +31,10 @@ export const dashboardDetailsTabs = [
|
||||
path: 'lineage',
|
||||
field: TabSpecificField.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
path: 'custom_properties',
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
path: 'manage',
|
||||
@ -50,11 +54,16 @@ export const getCurrentDashboardTab = (tab: string) => {
|
||||
|
||||
break;
|
||||
|
||||
case 'manage':
|
||||
case 'custom_properties':
|
||||
currentTab = 4;
|
||||
|
||||
break;
|
||||
|
||||
case 'manage':
|
||||
currentTab = 5;
|
||||
|
||||
break;
|
||||
|
||||
case 'details':
|
||||
default:
|
||||
currentTab = 1;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
import { TabSpecificField } from '../enums/entity.enum';
|
||||
|
||||
export const defaultFields = `${TabSpecificField.USAGE_SUMMARY},
|
||||
${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, ${TabSpecificField.DASHBOARD} `;
|
||||
${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, ${TabSpecificField.DASHBOARD} ,${TabSpecificField.EXTENSION}`;
|
||||
|
||||
export const mlModelTabs = [
|
||||
{
|
||||
@ -30,6 +30,10 @@ export const mlModelTabs = [
|
||||
path: 'lineage',
|
||||
field: TabSpecificField.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
path: 'custom_properties',
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
path: 'manage',
|
||||
@ -47,9 +51,13 @@ export const getCurrentMlModelTab = (tab: string) => {
|
||||
currentTab = 3;
|
||||
|
||||
break;
|
||||
case 'manage':
|
||||
case 'custom_properties':
|
||||
currentTab = 4;
|
||||
|
||||
break;
|
||||
case 'manage':
|
||||
currentTab = 5;
|
||||
|
||||
break;
|
||||
case 'features':
|
||||
currentTab = 1;
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
import { Icons } from './SvgUtils';
|
||||
|
||||
export const defaultFields = `${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
|
||||
${TabSpecificField.TASKS}, ${TabSpecificField.PIPELINE_STATUS}`;
|
||||
${TabSpecificField.TASKS}, ${TabSpecificField.PIPELINE_STATUS},${TabSpecificField.EXTENSION}`;
|
||||
|
||||
export const pipelineDetailsTabs = [
|
||||
{
|
||||
@ -37,6 +37,10 @@ export const pipelineDetailsTabs = [
|
||||
path: 'lineage',
|
||||
field: TabSpecificField.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
path: 'custom_properties',
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
path: 'manage',
|
||||
@ -54,10 +58,14 @@ export const getCurrentPipelineTab = (tab: string) => {
|
||||
case 'lineage':
|
||||
currentTab = 3;
|
||||
|
||||
break;
|
||||
case 'custom_properties':
|
||||
currentTab = 4;
|
||||
|
||||
break;
|
||||
|
||||
case 'manage':
|
||||
currentTab = 4;
|
||||
currentTab = 5;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
@ -37,6 +37,10 @@ export const topicDetailsTabs = [
|
||||
path: 'lineage',
|
||||
field: TabSpecificField.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: 'Custom Properties',
|
||||
path: 'custom_properties',
|
||||
},
|
||||
{
|
||||
name: 'Manage',
|
||||
path: 'manage',
|
||||
@ -62,9 +66,13 @@ export const getCurrentTopicTab = (tab: string) => {
|
||||
currentTab = 5;
|
||||
|
||||
break;
|
||||
case 'manage':
|
||||
case 'custom_properties':
|
||||
currentTab = 6;
|
||||
|
||||
break;
|
||||
case 'manage':
|
||||
currentTab = 7;
|
||||
|
||||
break;
|
||||
|
||||
case 'schema':
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user