mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-27 03:10:04 +00:00
Fix custom property permission issue (#7126)
This commit is contained in:
parent
891603e72f
commit
77c40c97f2
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 { fireEvent, render } from '@testing-library/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
import { Type } from '../../generated/entity/type';
|
|
||||||
import { Tab } from '../common/TabsPane/TabsPane';
|
|
||||||
import CustomEntityDetail from './CustomEntityDetail';
|
|
||||||
|
|
||||||
const mockData = {
|
|
||||||
id: '32f81349-d7d7-4a6a-8fc7-d767f233b674',
|
|
||||||
name: 'table',
|
|
||||||
fullyQualifiedName: 'table',
|
|
||||||
displayName: 'table',
|
|
||||||
description:
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
'"This schema defines the Table entity. A Table organizes data in rows and columns and is defined by a Schema. OpenMetadata does not have a separate abstraction for Schema. Both Table and Schema are captured in this entity."',
|
|
||||||
category: 'entity',
|
|
||||||
nameSpace: 'data',
|
|
||||||
schema: '',
|
|
||||||
version: 0.1,
|
|
||||||
updatedAt: 1653626359971,
|
|
||||||
updatedBy: 'admin',
|
|
||||||
href: 'http://localhost:8585/api/v1/metadata/types/32f81349-d7d7-4a6a-8fc7-d767f233b674',
|
|
||||||
} as Type;
|
|
||||||
|
|
||||||
const mockPush = jest.fn();
|
|
||||||
|
|
||||||
const MOCK_HISTORY = {
|
|
||||||
push: mockPush,
|
|
||||||
};
|
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
|
||||||
useHistory: jest.fn().mockImplementation(() => MOCK_HISTORY),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('../../axiosAPIs/metadataTypeAPI', () => ({
|
|
||||||
getTypeByFQN: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation(() => Promise.resolve({ data: mockData })),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('../containers/PageContainer', () => {
|
|
||||||
return jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation(({ children }: { children: React.ReactNode }) => (
|
|
||||||
<div>{children}</div>
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.mock('../../constants/constants', () => ({
|
|
||||||
getAddCustomPropertyPath: jest.fn().mockReturnValue('/custom-entity/table'),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('../common/TabsPane/TabsPane', () =>
|
|
||||||
jest.fn().mockImplementation(({ setActiveTab, tabs }) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<nav
|
|
||||||
className="tw-flex tw-items-center tw-justify-between tw-gh-tabs-container tw-px-7"
|
|
||||||
data-testid="tabs"
|
|
||||||
id="tabs">
|
|
||||||
{tabs.map((tab: Tab) => (
|
|
||||||
<button
|
|
||||||
data-testid={tab.name}
|
|
||||||
key={tab.position}
|
|
||||||
onClick={() => setActiveTab?.(tab.position)}>
|
|
||||||
{tab.name}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.mock('../schema-editor/SchemaEditor', () =>
|
|
||||||
jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue(<div data-testid="schema-editor">Schema Editor</div>)
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.mock('./CustomPropertyTable', () => ({
|
|
||||||
CustomPropertyTable: jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue(
|
|
||||||
<div data-testid="CustomPropertyTable">CustomPropertyTable</div>
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('./LeftPanel', () => ({
|
|
||||||
LeftPanel: jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue(<div data-testid="LeftPanel">LeftPanel</div>),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('Test Custom Entity Detail Component', () => {
|
|
||||||
it('Should render custom entity component', async () => {
|
|
||||||
const { findByTestId } = render(
|
|
||||||
<CustomEntityDetail entityTypes={[mockData]} />,
|
|
||||||
{
|
|
||||||
wrapper: MemoryRouter,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const leftPanel = await findByTestId('LeftPanel');
|
|
||||||
const tabContainer = await findByTestId('tabs');
|
|
||||||
|
|
||||||
const schemaTab = await findByTestId('Schema');
|
|
||||||
const customPropertiesTab = await findByTestId('Custom Properties');
|
|
||||||
|
|
||||||
expect(leftPanel).toBeInTheDocument();
|
|
||||||
expect(tabContainer).toBeInTheDocument();
|
|
||||||
expect(schemaTab).toBeInTheDocument();
|
|
||||||
expect(customPropertiesTab).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should render custom fields table if active tab is Custom Fields', async () => {
|
|
||||||
const { findByTestId } = render(
|
|
||||||
<CustomEntityDetail entityTypes={[mockData]} />,
|
|
||||||
{
|
|
||||||
wrapper: MemoryRouter,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const leftPanel = await findByTestId('LeftPanel');
|
|
||||||
const tabContainer = await findByTestId('tabs');
|
|
||||||
|
|
||||||
expect(leftPanel).toBeInTheDocument();
|
|
||||||
expect(tabContainer).toBeInTheDocument();
|
|
||||||
|
|
||||||
const customPropertiesTab = await findByTestId('Custom Properties');
|
|
||||||
|
|
||||||
expect(customPropertiesTab).toBeInTheDocument();
|
|
||||||
|
|
||||||
fireEvent.click(customPropertiesTab);
|
|
||||||
|
|
||||||
expect(await findByTestId('CustomPropertyTable')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should call history.push method on click of Add field button', async () => {
|
|
||||||
const { findByTestId } = render(
|
|
||||||
<CustomEntityDetail entityTypes={[mockData]} />,
|
|
||||||
{
|
|
||||||
wrapper: MemoryRouter,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const tabContainer = await findByTestId('tabs');
|
|
||||||
|
|
||||||
expect(tabContainer).toBeInTheDocument();
|
|
||||||
|
|
||||||
const customPropertiesTab = await findByTestId('Custom Properties');
|
|
||||||
|
|
||||||
expect(customPropertiesTab).toBeInTheDocument();
|
|
||||||
|
|
||||||
fireEvent.click(customPropertiesTab);
|
|
||||||
|
|
||||||
expect(await findByTestId('CustomPropertyTable')).toBeInTheDocument();
|
|
||||||
|
|
||||||
const addFieldButton = await findByTestId('add-field-button');
|
|
||||||
|
|
||||||
expect(addFieldButton).toBeInTheDocument();
|
|
||||||
|
|
||||||
fireEvent.click(addFieldButton);
|
|
||||||
|
|
||||||
expect(mockPush).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,181 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 { AxiosError } from 'axios';
|
|
||||||
import { compare } from 'fast-json-patch';
|
|
||||||
import { isEmpty } from 'lodash';
|
|
||||||
import React, { FC, useEffect, useState } from 'react';
|
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
import { getTypeByFQN, updateType } from '../../axiosAPIs/metadataTypeAPI';
|
|
||||||
import { getAddCustomPropertyPath } from '../../constants/constants';
|
|
||||||
import { Type } from '../../generated/entity/type';
|
|
||||||
import jsonData from '../../jsons/en';
|
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
|
||||||
import { Button } from '../buttons/Button/Button';
|
|
||||||
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
|
|
||||||
import TabsPane from '../common/TabsPane/TabsPane';
|
|
||||||
import PageContainer from '../containers/PageContainer';
|
|
||||||
import PageLayout from '../containers/PageLayout';
|
|
||||||
import SchemaEditor from '../schema-editor/SchemaEditor';
|
|
||||||
import { CustomPropertyTable } from './CustomPropertyTable';
|
|
||||||
import { LeftPanel } from './LeftPanel';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
entityTypes: Array<Type>;
|
|
||||||
entityTypeFQN?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CustomEntityDetail: FC<Props> = ({ entityTypes, entityTypeFQN }) => {
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<number>(1);
|
|
||||||
const [selectedEntityType, setSelectedEntityType] = useState<Type>(
|
|
||||||
{} as Type
|
|
||||||
);
|
|
||||||
const [selectedEntityTypeDetail, setSelectedEntityTypeDetail] =
|
|
||||||
useState<Type>({} as Type);
|
|
||||||
|
|
||||||
const fetchTypeDetail = (typeFQN: string) => {
|
|
||||||
getTypeByFQN(typeFQN)
|
|
||||||
.then((res) => {
|
|
||||||
setSelectedEntityTypeDetail(res);
|
|
||||||
})
|
|
||||||
.catch((err: AxiosError) => showErrorToast(err));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTabChange = (tab: number) => {
|
|
||||||
setActiveTab(tab);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEntityTypeSelect = (entityType: Type) => {
|
|
||||||
setSelectedEntityType(entityType);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddProperty = () => {
|
|
||||||
const path = getAddCustomPropertyPath(
|
|
||||||
selectedEntityTypeDetail.fullyQualifiedName as string
|
|
||||||
);
|
|
||||||
history.push(path);
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaCheck = activeTab === 2 && !isEmpty(selectedEntityTypeDetail);
|
|
||||||
const schemaValue = selectedEntityTypeDetail.schema || '{}';
|
|
||||||
|
|
||||||
const customPropertiesCheck =
|
|
||||||
activeTab === 1 && !isEmpty(selectedEntityTypeDetail);
|
|
||||||
const customProperties = selectedEntityTypeDetail.customProperties || [];
|
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{
|
|
||||||
name: 'Custom Properties',
|
|
||||||
isProtected: false,
|
|
||||||
position: 1,
|
|
||||||
count: customProperties.length,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Schema',
|
|
||||||
isProtected: false,
|
|
||||||
position: 2,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const componentCheck = Boolean(entityTypes.length);
|
|
||||||
|
|
||||||
const updateEntityType = (properties: Type['customProperties']) => {
|
|
||||||
const patch = compare(selectedEntityTypeDetail, {
|
|
||||||
...selectedEntityTypeDetail,
|
|
||||||
customProperties: properties,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateType(selectedEntityTypeDetail.id as string, patch)
|
|
||||||
.then((res) => {
|
|
||||||
const { customProperties: properties } = res;
|
|
||||||
|
|
||||||
setSelectedEntityTypeDetail((prev) => ({
|
|
||||||
...prev,
|
|
||||||
customProperties: properties,
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
.catch((err: AxiosError) => showErrorToast(err));
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (entityTypes.length) {
|
|
||||||
const entityType =
|
|
||||||
entityTypes.find((type) => type.fullyQualifiedName === entityTypeFQN) ||
|
|
||||||
entityTypes[0];
|
|
||||||
onEntityTypeSelect(entityType);
|
|
||||||
}
|
|
||||||
}, [entityTypes, entityTypeFQN]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isEmpty(selectedEntityType)) {
|
|
||||||
fetchTypeDetail(selectedEntityType.fullyQualifiedName as string);
|
|
||||||
}
|
|
||||||
}, [selectedEntityType]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer>
|
|
||||||
{componentCheck ? (
|
|
||||||
<PageLayout
|
|
||||||
leftPanel={
|
|
||||||
<LeftPanel
|
|
||||||
selectedType={selectedEntityTypeDetail}
|
|
||||||
typeList={entityTypes}
|
|
||||||
/>
|
|
||||||
}>
|
|
||||||
<TabsPane
|
|
||||||
activeTab={activeTab}
|
|
||||||
setActiveTab={onTabChange}
|
|
||||||
tabs={tabs}
|
|
||||||
/>
|
|
||||||
<div className="tw-mt-4">
|
|
||||||
{schemaCheck && (
|
|
||||||
<div data-testid="entity-schema">
|
|
||||||
<SchemaEditor
|
|
||||||
className="tw-border tw-border-main tw-rounded-md tw-py-4"
|
|
||||||
editorClass="custom-entity-schema"
|
|
||||||
value={JSON.parse(schemaValue)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{customPropertiesCheck && (
|
|
||||||
<div data-testid="entity-custom-fields">
|
|
||||||
<div className="tw-flex tw-justify-end">
|
|
||||||
<Button
|
|
||||||
className="tw-mb-4 tw-py-1 tw-px-2 tw-rounded"
|
|
||||||
data-testid="add-field-button"
|
|
||||||
size="custom"
|
|
||||||
theme="primary"
|
|
||||||
onClick={() => handleAddProperty()}>
|
|
||||||
Add Property
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<CustomPropertyTable
|
|
||||||
customProperties={customProperties}
|
|
||||||
updateEntityType={updateEntityType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</PageLayout>
|
|
||||||
) : (
|
|
||||||
<ErrorPlaceHolder>
|
|
||||||
{jsonData['message']['no-custom-entity']}
|
|
||||||
</ErrorPlaceHolder>
|
|
||||||
)}
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CustomEntityDetail;
|
|
@ -60,6 +60,7 @@ const mockProperties = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const mockProp = {
|
const mockProp = {
|
||||||
|
hasAccess: true,
|
||||||
customProperties: mockProperties,
|
customProperties: mockProperties,
|
||||||
updateEntityType: mockUpdateEntityType,
|
updateEntityType: mockUpdateEntityType,
|
||||||
};
|
};
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Tooltip } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isEmpty, uniqueId } from 'lodash';
|
import { isEmpty, uniqueId } from 'lodash';
|
||||||
import React, { FC, Fragment, useState } from 'react';
|
import React, { FC, Fragment, useState } from 'react';
|
||||||
|
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
|
||||||
import { CustomProperty, Type } from '../../generated/entity/type';
|
import { CustomProperty, Type } from '../../generated/entity/type';
|
||||||
import { getEntityName, isEven } from '../../utils/CommonUtils';
|
import { getEntityName, isEven } from '../../utils/CommonUtils';
|
||||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||||
@ -22,6 +24,7 @@ import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
|
|||||||
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
|
|
||||||
interface CustomPropertyTableProp {
|
interface CustomPropertyTableProp {
|
||||||
|
hasAccess: boolean;
|
||||||
customProperties: CustomProperty[];
|
customProperties: CustomProperty[];
|
||||||
updateEntityType: (customProperties: Type['customProperties']) => void;
|
updateEntityType: (customProperties: Type['customProperties']) => void;
|
||||||
}
|
}
|
||||||
@ -31,6 +34,7 @@ type Operation = 'delete' | 'update' | 'no-operation';
|
|||||||
export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
|
export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
|
||||||
customProperties,
|
customProperties,
|
||||||
updateEntityType,
|
updateEntityType,
|
||||||
|
hasAccess,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedProperty, setSelectedProperty] = useState<CustomProperty>(
|
const [selectedProperty, setSelectedProperty] = useState<CustomProperty>(
|
||||||
{} as CustomProperty
|
{} as CustomProperty
|
||||||
@ -120,9 +124,12 @@ export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
|
|||||||
</td>
|
</td>
|
||||||
<td className="tableBody-cell">
|
<td className="tableBody-cell">
|
||||||
<div className="tw-flex">
|
<div className="tw-flex">
|
||||||
|
<Tooltip
|
||||||
|
title={hasAccess ? 'Edit' : NO_PERMISSION_FOR_ACTION}>
|
||||||
<button
|
<button
|
||||||
className="tw-cursor-pointer"
|
className="tw-cursor-pointer"
|
||||||
data-testid="edit-button"
|
data-testid="edit-button"
|
||||||
|
disabled={!hasAccess}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedProperty(property);
|
setSelectedProperty(property);
|
||||||
setOperation('update');
|
setOperation('update');
|
||||||
@ -134,9 +141,13 @@ export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
|
|||||||
width="16px"
|
width="16px"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
title={hasAccess ? 'Delete' : NO_PERMISSION_FOR_ACTION}>
|
||||||
<button
|
<button
|
||||||
className="tw-cursor-pointer tw-ml-4"
|
className="tw-cursor-pointer tw-ml-4"
|
||||||
data-testid="delete-button"
|
data-testid="delete-button"
|
||||||
|
disabled={!hasAccess}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedProperty(property);
|
setSelectedProperty(property);
|
||||||
setOperation('delete');
|
setOperation('delete');
|
||||||
@ -148,6 +159,7 @@ export const CustomPropertyTable: FC<CustomPropertyTableProp> = ({
|
|||||||
width="16px"
|
width="16px"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Col, Empty, Row } from 'antd';
|
import { Col, Empty, Row, Tooltip } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { isEmpty, isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { getTypeByFQN, updateType } from '../../axiosAPIs/metadataTypeAPI';
|
import { getTypeByFQN, updateType } from '../../axiosAPIs/metadataTypeAPI';
|
||||||
@ -24,15 +24,20 @@ import TabsPane from '../../components/common/TabsPane/TabsPane';
|
|||||||
import { CustomPropertyTable } from '../../components/CustomEntityDetail/CustomPropertyTable';
|
import { CustomPropertyTable } from '../../components/CustomEntityDetail/CustomPropertyTable';
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider';
|
import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider';
|
||||||
|
import {
|
||||||
|
OperationPermission,
|
||||||
|
ResourceEntity,
|
||||||
|
} from '../../components/PermissionProvider/PermissionProvider.interface';
|
||||||
import SchemaEditor from '../../components/schema-editor/SchemaEditor';
|
import SchemaEditor from '../../components/schema-editor/SchemaEditor';
|
||||||
import { getAddCustomPropertyPath } from '../../constants/constants';
|
import { getAddCustomPropertyPath } from '../../constants/constants';
|
||||||
import { customAttributesPath } from '../../constants/globalSettings.constants';
|
import { customAttributesPath } from '../../constants/globalSettings.constants';
|
||||||
import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
|
import {
|
||||||
import { Operation } from '../../generated/entity/policies/policy';
|
NO_PERMISSION_FOR_ACTION,
|
||||||
|
NO_PERMISSION_TO_VIEW,
|
||||||
|
} from '../../constants/HelperTextUtil';
|
||||||
import { Type } from '../../generated/entity/type';
|
import { Type } from '../../generated/entity/type';
|
||||||
import jsonData from '../../jsons/en';
|
import jsonData from '../../jsons/en';
|
||||||
import { getResourceEntityFromCustomProperty } from '../../utils/CustomPropertyUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
import { checkPermission } from '../../utils/PermissionsUtils';
|
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import './CustomPropertiesPageV1.less';
|
import './CustomPropertiesPageV1.less';
|
||||||
|
|
||||||
@ -49,18 +54,32 @@ const CustomEntityDetailV1 = () => {
|
|||||||
const tabAttributePath =
|
const tabAttributePath =
|
||||||
customAttributesPath[tab as keyof typeof customAttributesPath];
|
customAttributesPath[tab as keyof typeof customAttributesPath];
|
||||||
|
|
||||||
const { permissions } = usePermissionProvider();
|
const { getEntityPermission } = usePermissionProvider();
|
||||||
|
|
||||||
const viewPermission = useMemo(() => {
|
const [propertyPermission, setPropertyPermission] =
|
||||||
return (
|
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
|
||||||
!isEmpty(permissions) &&
|
|
||||||
checkPermission(
|
const fetchPermission = async () => {
|
||||||
Operation.ViewAll,
|
try {
|
||||||
getResourceEntityFromCustomProperty(tab),
|
const response = await getEntityPermission(
|
||||||
permissions
|
ResourceEntity.TYPE,
|
||||||
)
|
selectedEntityTypeDetail.id as string
|
||||||
|
);
|
||||||
|
setPropertyPermission(response);
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast(error as AxiosError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewPermission = useMemo(
|
||||||
|
() => propertyPermission.ViewAll,
|
||||||
|
[propertyPermission, tab]
|
||||||
|
);
|
||||||
|
|
||||||
|
const editPermission = useMemo(
|
||||||
|
() => propertyPermission.EditAll,
|
||||||
|
[propertyPermission, tab]
|
||||||
);
|
);
|
||||||
}, [permissions, tab]);
|
|
||||||
|
|
||||||
const fetchTypeDetail = async (typeFQN: string) => {
|
const fetchTypeDetail = async (typeFQN: string) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -126,6 +145,12 @@ const CustomEntityDetailV1 = () => {
|
|||||||
}
|
}
|
||||||
}, [tab]);
|
}, [tab]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEntityTypeDetail?.id) {
|
||||||
|
fetchPermission();
|
||||||
|
}
|
||||||
|
}, [selectedEntityTypeDetail]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
@ -163,17 +188,22 @@ const CustomEntityDetailV1 = () => {
|
|||||||
{activeTab === 1 && (
|
{activeTab === 1 && (
|
||||||
<div data-testid="entity-custom-fields">
|
<div data-testid="entity-custom-fields">
|
||||||
<div className="tw-flex tw-justify-end">
|
<div className="tw-flex tw-justify-end">
|
||||||
|
<Tooltip
|
||||||
|
title={editPermission ? 'Add' : NO_PERMISSION_FOR_ACTION}>
|
||||||
<Button
|
<Button
|
||||||
className="tw-mb-4 tw-py-1 tw-px-2 tw-rounded"
|
className="tw-mb-4 tw-py-1 tw-px-2 tw-rounded"
|
||||||
data-testid="add-field-button"
|
data-testid="add-field-button"
|
||||||
|
disabled={!editPermission}
|
||||||
size="custom"
|
size="custom"
|
||||||
theme="primary"
|
theme="primary"
|
||||||
onClick={() => handleAddProperty()}>
|
onClick={() => handleAddProperty()}>
|
||||||
Add Property
|
Add Property
|
||||||
</Button>
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<CustomPropertyTable
|
<CustomPropertyTable
|
||||||
customProperties={selectedEntityTypeDetail.customProperties || []}
|
customProperties={selectedEntityTypeDetail.customProperties || []}
|
||||||
|
hasAccess={editPermission}
|
||||||
updateEntityType={updateEntityType}
|
updateEntityType={updateEntityType}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -466,14 +466,9 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
|
|||||||
)}
|
)}
|
||||||
path={ROUTES.BOTS_PROFILE}
|
path={ROUTES.BOTS_PROFILE}
|
||||||
/>
|
/>
|
||||||
<AdminProtectedRoute
|
<Route
|
||||||
exact
|
exact
|
||||||
component={AddCustomProperty}
|
component={AddCustomProperty}
|
||||||
hasPermission={checkPermission(
|
|
||||||
Operation.Create,
|
|
||||||
ResourceEntity.TYPE,
|
|
||||||
permissions
|
|
||||||
)}
|
|
||||||
path={ROUTES.ADD_CUSTOM_PROPERTY}
|
path={ROUTES.ADD_CUSTOM_PROPERTY}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
|
@ -267,7 +267,7 @@ const GlobalSettingRouter = () => {
|
|||||||
component={CustomPropertiesPageV1}
|
component={CustomPropertiesPageV1}
|
||||||
hasPermission={checkPermission(
|
hasPermission={checkPermission(
|
||||||
Operation.ViewAll,
|
Operation.ViewAll,
|
||||||
ResourceEntity.ALL,
|
ResourceEntity.TYPE,
|
||||||
permissions
|
permissions
|
||||||
)}
|
)}
|
||||||
path={getSettingCategoryPath(
|
path={getSettingCategoryPath(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user