mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-26 09:55:52 +00:00
fix import export permissions (#17482)
This commit is contained in:
parent
c47a46ad78
commit
4c49f098bd
@ -120,6 +120,21 @@ const GlossaryHeader = ({
|
|||||||
[globalPermissions]
|
[globalPermissions]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const importExportPermissions = useMemo(
|
||||||
|
() =>
|
||||||
|
checkPermission(
|
||||||
|
Operation.All,
|
||||||
|
ResourceEntity.GLOSSARY_TERM,
|
||||||
|
globalPermissions
|
||||||
|
) ||
|
||||||
|
checkPermission(
|
||||||
|
Operation.EditAll,
|
||||||
|
ResourceEntity.GLOSSARY_TERM,
|
||||||
|
globalPermissions
|
||||||
|
),
|
||||||
|
[globalPermissions]
|
||||||
|
);
|
||||||
|
|
||||||
// To fetch the latest glossary data
|
// To fetch the latest glossary data
|
||||||
// necessary to handle back click functionality to work properly in version page
|
// necessary to handle back click functionality to work properly in version page
|
||||||
const fetchCurrentGlossaryInfo = async () => {
|
const fetchCurrentGlossaryInfo = async () => {
|
||||||
@ -298,7 +313,7 @@ const GlossaryHeader = ({
|
|||||||
}, [selectedData]);
|
}, [selectedData]);
|
||||||
|
|
||||||
const manageButtonContent: ItemType[] = [
|
const manageButtonContent: ItemType[] = [
|
||||||
...(isGlossary
|
...(isGlossary && importExportPermissions
|
||||||
? ([
|
? ([
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
|
@ -23,6 +23,25 @@ import { DEFAULT_ENTITY_PERMISSION } from '../../../utils/PermissionsUtils';
|
|||||||
import { QueryVoteType } from '../../Database/TableQueries/TableQueries.interface';
|
import { QueryVoteType } from '../../Database/TableQueries/TableQueries.interface';
|
||||||
import GlossaryHeader from './GlossaryHeader.component';
|
import GlossaryHeader from './GlossaryHeader.component';
|
||||||
|
|
||||||
|
const glossaryTermPermission = {
|
||||||
|
All: true,
|
||||||
|
Create: true,
|
||||||
|
Delete: true,
|
||||||
|
ViewAll: true,
|
||||||
|
EditAll: true,
|
||||||
|
EditDescription: true,
|
||||||
|
EditDisplayName: true,
|
||||||
|
EditCustomFields: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../../../context/PermissionProvider/PermissionProvider', () => ({
|
||||||
|
usePermissionProvider: jest.fn().mockImplementation(() => ({
|
||||||
|
permissions: {
|
||||||
|
glossaryTerm: glossaryTermPermission,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
useHistory: jest.fn(),
|
useHistory: jest.fn(),
|
||||||
useParams: jest.fn().mockReturnValue({
|
useParams: jest.fn().mockReturnValue({
|
||||||
@ -195,6 +214,24 @@ describe('GlossaryHeader component', () => {
|
|||||||
expect(screen.queryByText('label.style')).not.toBeInTheDocument();
|
expect(screen.queryByText('label.style')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not render import and export dropdown menu items if no permission', async () => {
|
||||||
|
glossaryTermPermission.All = false;
|
||||||
|
glossaryTermPermission.EditAll = false;
|
||||||
|
render(
|
||||||
|
<GlossaryHeader
|
||||||
|
isGlossary
|
||||||
|
permissions={DEFAULT_ENTITY_PERMISSION}
|
||||||
|
selectedData={{ displayName: 'glossaryTest' } as Glossary}
|
||||||
|
updateVote={mockOnUpdateVote}
|
||||||
|
onAddGlossaryTerm={mockOnDelete}
|
||||||
|
onDelete={mockOnDelete}
|
||||||
|
onUpdate={mockOnUpdate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByTestId('manage-button')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should render changeParentHierarchy and style dropdown menu items only for glossaryTerm', async () => {
|
it('should render changeParentHierarchy and style dropdown menu items only for glossaryTerm', async () => {
|
||||||
render(
|
render(
|
||||||
<GlossaryHeader
|
<GlossaryHeader
|
||||||
|
@ -74,9 +74,11 @@ export const EntityImport = ({
|
|||||||
setUploading(true);
|
setUploading(true);
|
||||||
const response = await onImport(entityName, result);
|
const response = await onImport(entityName, result);
|
||||||
|
|
||||||
setCsvImportResult(response);
|
if (response) {
|
||||||
setCsvFileResult(result);
|
setCsvImportResult(response);
|
||||||
setActiveStep(2);
|
setCsvFileResult(result);
|
||||||
|
setActiveStep(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setCsvImportResult(undefined);
|
setCsvImportResult(undefined);
|
||||||
|
@ -17,6 +17,7 @@ import i18next from 'i18next';
|
|||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ReactComponent as GlossaryTermIcon } from '../assets/svg/book.svg';
|
||||||
import { ReactComponent as IconChart } from '../assets/svg/chart.svg';
|
import { ReactComponent as IconChart } from '../assets/svg/chart.svg';
|
||||||
import { ReactComponent as IconDashboard } from '../assets/svg/dashboard-grey.svg';
|
import { ReactComponent as IconDashboard } from '../assets/svg/dashboard-grey.svg';
|
||||||
import { ReactComponent as IconApiCollection } from '../assets/svg/ic-api-collection-default.svg';
|
import { ReactComponent as IconApiCollection } from '../assets/svg/ic-api-collection-default.svg';
|
||||||
@ -26,7 +27,6 @@ import { ReactComponent as IconContainer } from '../assets/svg/ic-storage.svg';
|
|||||||
import { ReactComponent as IconStoredProcedure } from '../assets/svg/ic-stored-procedure.svg';
|
import { ReactComponent as IconStoredProcedure } from '../assets/svg/ic-stored-procedure.svg';
|
||||||
import { ReactComponent as IconMlModal } from '../assets/svg/mlmodal.svg';
|
import { ReactComponent as IconMlModal } from '../assets/svg/mlmodal.svg';
|
||||||
import { ReactComponent as IconPipeline } from '../assets/svg/pipeline-grey.svg';
|
import { ReactComponent as IconPipeline } from '../assets/svg/pipeline-grey.svg';
|
||||||
import { ReactComponent as IconTable } from '../assets/svg/table-grey.svg';
|
|
||||||
import { ReactComponent as IconTag } from '../assets/svg/tag-grey.svg';
|
import { ReactComponent as IconTag } from '../assets/svg/tag-grey.svg';
|
||||||
import { ReactComponent as IconTopic } from '../assets/svg/topic-grey.svg';
|
import { ReactComponent as IconTopic } from '../assets/svg/topic-grey.svg';
|
||||||
import {
|
import {
|
||||||
@ -124,7 +124,7 @@ export const getGroupLabel = (index: string) => {
|
|||||||
break;
|
break;
|
||||||
case SearchIndex.GLOSSARY_TERM:
|
case SearchIndex.GLOSSARY_TERM:
|
||||||
label = i18next.t('label.glossary-term-plural');
|
label = i18next.t('label.glossary-term-plural');
|
||||||
GroupIcon = IconTable;
|
GroupIcon = GlossaryTermIcon;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SearchIndex.TAG:
|
case SearchIndex.TAG:
|
||||||
@ -219,11 +219,18 @@ export const getSuggestionElement = (
|
|||||||
FqnPart.Service,
|
FqnPart.Service,
|
||||||
])}-${name}`.replaceAll(`"`, '');
|
])}-${name}`.replaceAll(`"`, '');
|
||||||
|
|
||||||
const displayText =
|
let displayText =
|
||||||
database && schema
|
database && schema
|
||||||
? `${database}${FQN_SEPARATOR_CHAR}${schema}${FQN_SEPARATOR_CHAR}${name}`
|
? `${database}${FQN_SEPARATOR_CHAR}${schema}${FQN_SEPARATOR_CHAR}${name}`
|
||||||
: searchClassBase.getEntityName(entitySource);
|
: searchClassBase.getEntityName(entitySource);
|
||||||
|
|
||||||
|
if (index === SearchIndex.GLOSSARY_TERM) {
|
||||||
|
// Show Fqn for Glossary Term. Adding this to avoid confusion for nested terms
|
||||||
|
displayText =
|
||||||
|
entitySource.fullyQualifiedName ??
|
||||||
|
searchClassBase.getEntityName(entitySource);
|
||||||
|
}
|
||||||
|
|
||||||
const retn = (
|
const retn = (
|
||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
|
@ -51,6 +51,7 @@ export const showErrorToast = (
|
|||||||
if (isString(error)) {
|
if (isString(error)) {
|
||||||
errorMessage = error.toString();
|
errorMessage = error.toString();
|
||||||
} else {
|
} else {
|
||||||
|
const method = error.config?.method?.toUpperCase();
|
||||||
const fallback =
|
const fallback =
|
||||||
fallbackText && fallbackText.length > 0
|
fallbackText && fallbackText.length > 0
|
||||||
? fallbackText
|
? fallbackText
|
||||||
@ -62,7 +63,8 @@ export const showErrorToast = (
|
|||||||
if (
|
if (
|
||||||
error &&
|
error &&
|
||||||
(error.response?.status === ClientErrors.UNAUTHORIZED ||
|
(error.response?.status === ClientErrors.UNAUTHORIZED ||
|
||||||
error.response?.status === ClientErrors.FORBIDDEN) &&
|
(error.response?.status === ClientErrors.FORBIDDEN &&
|
||||||
|
method === 'GET')) &&
|
||||||
!errorMessage.includes('principal domain')
|
!errorMessage.includes('principal domain')
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user