mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2026-01-08 05:26:19 +00:00
* Fixed modal css & text styling * fix unnecessary api calls * address comments * added locale files * change widget message & fix unnecessary api calls * address comments * fix tags page import * fix failing cyp test --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
parent
d79654e271
commit
824307dc9a
@ -50,7 +50,7 @@ const revokeToken = () => {
|
||||
// Verify the revoke text
|
||||
cy.get('[data-testid="body-text"]').should(
|
||||
'contain',
|
||||
'Are you sure you want to revoke access for JWT token?'
|
||||
'Are you sure you want to revoke access for JWT Token?'
|
||||
);
|
||||
interceptURL('PUT', `/api/v1/users/revokeToken`, 'revokeToken');
|
||||
// Click on confirm button
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 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 { Classification } from '../../generated/entity/classification/classification';
|
||||
import { Tag } from '../../generated/entity/classification/tag';
|
||||
import { DeleteTagsType } from '../../pages/TagsPage/TagsPage.interface';
|
||||
import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface';
|
||||
|
||||
export interface ClassificationDetailsProps {
|
||||
classificationPermissions: OperationPermission;
|
||||
isVersionView?: boolean;
|
||||
currentClassification?: Classification;
|
||||
deleteTags?: DeleteTagsType;
|
||||
isEditClassification?: boolean;
|
||||
isAddingTag?: boolean;
|
||||
disableEditButton?: boolean;
|
||||
handleAfterDeleteAction?: () => void;
|
||||
handleEditTagClick?: (selectedTag: Tag) => void;
|
||||
handleActionDeleteTag?: (record: Tag) => void;
|
||||
handleAddNewTagClick?: () => void;
|
||||
handleEditDescriptionClick?: () => void;
|
||||
handleCancelEditDescription?: () => void;
|
||||
handleUpdateClassification?: (
|
||||
updatedClassification: Classification
|
||||
) => Promise<void>;
|
||||
}
|
||||
export interface ClassificationDetailsRef {
|
||||
refreshClassificationTags: () => void;
|
||||
}
|
||||
@ -17,7 +17,14 @@ import { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { capitalize, isUndefined, toString } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { ReactComponent as IconTag } from '../../assets/svg/classification.svg';
|
||||
@ -30,23 +37,16 @@ import RichTextEditorPreviewer from '../../components/common/RichTextEditor/Rich
|
||||
import Table from '../../components/common/Table/Table';
|
||||
import EntityHeaderTitle from '../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component';
|
||||
import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider';
|
||||
import {
|
||||
OperationPermission,
|
||||
ResourceEntity,
|
||||
} from '../../components/PermissionProvider/PermissionProvider.interface';
|
||||
import { ResourceEntity } from '../../components/PermissionProvider/PermissionProvider.interface';
|
||||
import { DE_ACTIVE_COLOR } from '../../constants/constants';
|
||||
import { EntityField } from '../../constants/Feeds.constants';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import { ProviderType } from '../../generated/api/classification/createClassification';
|
||||
import {
|
||||
ChangeDescription,
|
||||
Classification,
|
||||
} from '../../generated/entity/classification/classification';
|
||||
import { ChangeDescription } from '../../generated/entity/classification/classification';
|
||||
import { Tag } from '../../generated/entity/classification/tag';
|
||||
import { Operation } from '../../generated/entity/policies/policy';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
import { usePaging } from '../../hooks/paging/usePaging';
|
||||
import { DeleteTagsType } from '../../pages/TagsPage/TagsPage.interface';
|
||||
import { getTags } from '../../rest/tagAPI';
|
||||
import {
|
||||
getClassificationExtraDropdownContent,
|
||||
@ -67,275 +67,272 @@ import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import ManageButton from '../common/EntityPageInfos/ManageButton/ManageButton';
|
||||
import NextPrevious from '../common/NextPrevious/NextPrevious';
|
||||
import { NextPreviousProps } from '../common/NextPrevious/NextPrevious.interface';
|
||||
import { ClassificationDetailsProps } from './ClassificationDetails.interface';
|
||||
|
||||
export interface ClassificationDetailsProps {
|
||||
classificationPermissions: OperationPermission;
|
||||
isVersionView?: boolean;
|
||||
currentClassification?: Classification;
|
||||
deleteTags?: DeleteTagsType;
|
||||
isEditClassification?: boolean;
|
||||
isAddingTag?: boolean;
|
||||
disableEditButton?: boolean;
|
||||
handleAfterDeleteAction?: () => void;
|
||||
handleEditTagClick?: (selectedTag: Tag) => void;
|
||||
handleActionDeleteTag?: (record: Tag) => void;
|
||||
handleAddNewTagClick?: () => void;
|
||||
handleEditDescriptionClick?: () => void;
|
||||
handleCancelEditDescription?: () => void;
|
||||
handleUpdateClassification?: (
|
||||
updatedClassification: Classification
|
||||
) => Promise<void>;
|
||||
}
|
||||
const ClassificationDetails = forwardRef(
|
||||
(
|
||||
{
|
||||
currentClassification,
|
||||
handleAfterDeleteAction,
|
||||
isEditClassification,
|
||||
classificationPermissions,
|
||||
handleUpdateClassification,
|
||||
handleEditTagClick,
|
||||
deleteTags,
|
||||
isAddingTag,
|
||||
handleActionDeleteTag,
|
||||
handleAddNewTagClick,
|
||||
handleEditDescriptionClick,
|
||||
handleCancelEditDescription,
|
||||
disableEditButton,
|
||||
|
||||
function ClassificationDetails({
|
||||
currentClassification,
|
||||
handleAfterDeleteAction,
|
||||
isEditClassification,
|
||||
classificationPermissions,
|
||||
handleUpdateClassification,
|
||||
handleEditTagClick,
|
||||
deleteTags,
|
||||
isAddingTag,
|
||||
handleActionDeleteTag,
|
||||
handleAddNewTagClick,
|
||||
handleEditDescriptionClick,
|
||||
handleCancelEditDescription,
|
||||
disableEditButton,
|
||||
isVersionView = false,
|
||||
}: Readonly<ClassificationDetailsProps>) {
|
||||
const { permissions } = usePermissionProvider();
|
||||
const { t } = useTranslation();
|
||||
const { fqn: tagCategoryName } = useParams<{ fqn: string }>();
|
||||
const history = useHistory();
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [isTagsLoading, setIsTagsLoading] = useState(false);
|
||||
|
||||
const {
|
||||
currentPage,
|
||||
paging,
|
||||
pageSize,
|
||||
handlePageChange,
|
||||
handlePageSizeChange,
|
||||
handlePagingChange,
|
||||
showPagination,
|
||||
} = usePaging();
|
||||
|
||||
const fetchClassificationChildren = async (
|
||||
currentClassificationName: string,
|
||||
paging?: Partial<Paging>
|
||||
isVersionView = false,
|
||||
}: Readonly<ClassificationDetailsProps>,
|
||||
ref
|
||||
) => {
|
||||
setIsTagsLoading(true);
|
||||
setTags([]);
|
||||
try {
|
||||
const { data, paging: tagPaging } = await getTags({
|
||||
arrQueryFields: ['usageCount'],
|
||||
parent: currentClassificationName,
|
||||
after: paging?.after,
|
||||
before: paging?.before,
|
||||
limit: pageSize,
|
||||
});
|
||||
setTags(data);
|
||||
handlePagingChange(tagPaging);
|
||||
} catch (error) {
|
||||
const errMsg = getErrorText(
|
||||
error as AxiosError,
|
||||
t('server.entity-fetch-error', { entity: t('label.tag-plural') })
|
||||
);
|
||||
showErrorToast(errMsg);
|
||||
const { permissions } = usePermissionProvider();
|
||||
const { t } = useTranslation();
|
||||
const { fqn: tagCategoryName } = useParams<{ fqn: string }>();
|
||||
const history = useHistory();
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [isTagsLoading, setIsTagsLoading] = useState(false);
|
||||
|
||||
const {
|
||||
currentPage,
|
||||
paging,
|
||||
pageSize,
|
||||
handlePageChange,
|
||||
handlePageSizeChange,
|
||||
handlePagingChange,
|
||||
showPagination,
|
||||
} = usePaging();
|
||||
|
||||
const fetchClassificationChildren = async (
|
||||
currentClassificationName: string,
|
||||
paging?: Partial<Paging>
|
||||
) => {
|
||||
setIsTagsLoading(true);
|
||||
setTags([]);
|
||||
} finally {
|
||||
setIsTagsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTagsPageChange: NextPreviousProps['pagingHandler'] = ({
|
||||
currentPage,
|
||||
cursorType,
|
||||
}) => {
|
||||
if (cursorType) {
|
||||
fetchClassificationChildren(
|
||||
currentClassification?.fullyQualifiedName ?? '',
|
||||
{
|
||||
[cursorType]: paging[cursorType],
|
||||
}
|
||||
);
|
||||
}
|
||||
handlePageChange(currentPage);
|
||||
};
|
||||
|
||||
const currentVersion = useMemo(
|
||||
() => currentClassification?.version ?? '0.1',
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const changeDescription = useMemo(
|
||||
() => currentClassification?.changeDescription ?? ({} as ChangeDescription),
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const versionHandler = useCallback(() => {
|
||||
isVersionView
|
||||
? history.push(getClassificationDetailsPath(tagCategoryName))
|
||||
: history.push(
|
||||
getClassificationVersionsPath(
|
||||
tagCategoryName,
|
||||
toString(currentVersion)
|
||||
)
|
||||
try {
|
||||
const { data, paging: tagPaging } = await getTags({
|
||||
arrQueryFields: ['usageCount'],
|
||||
parent: currentClassificationName,
|
||||
after: paging?.after,
|
||||
before: paging?.before,
|
||||
limit: pageSize,
|
||||
});
|
||||
setTags(data);
|
||||
handlePagingChange(tagPaging);
|
||||
} catch (error) {
|
||||
const errMsg = getErrorText(
|
||||
error as AxiosError,
|
||||
t('server.entity-fetch-error', { entity: t('label.tag-plural') })
|
||||
);
|
||||
}, [currentVersion, tagCategoryName]);
|
||||
showErrorToast(errMsg);
|
||||
setTags([]);
|
||||
} finally {
|
||||
setIsTagsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isTier = useMemo(
|
||||
() => currentClassification?.name === 'Tier',
|
||||
[currentClassification]
|
||||
);
|
||||
const handleTagsPageChange: NextPreviousProps['pagingHandler'] = ({
|
||||
currentPage,
|
||||
cursorType,
|
||||
}) => {
|
||||
if (cursorType) {
|
||||
fetchClassificationChildren(
|
||||
currentClassification?.fullyQualifiedName ?? '',
|
||||
{
|
||||
[cursorType]: paging[cursorType],
|
||||
}
|
||||
);
|
||||
}
|
||||
handlePageChange(currentPage);
|
||||
};
|
||||
|
||||
const createTagPermission = useMemo(
|
||||
() =>
|
||||
checkPermission(Operation.Create, ResourceEntity.TAG, permissions) ||
|
||||
classificationPermissions.EditAll,
|
||||
[permissions, classificationPermissions]
|
||||
);
|
||||
const currentVersion = useMemo(
|
||||
() => currentClassification?.version ?? '0.1',
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const editClassificationPermission = useMemo(
|
||||
() => classificationPermissions.EditAll,
|
||||
[classificationPermissions]
|
||||
);
|
||||
const changeDescription = useMemo(
|
||||
() =>
|
||||
currentClassification?.changeDescription ?? ({} as ChangeDescription),
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const isClassificationDisabled = useMemo(
|
||||
() => currentClassification?.disabled ?? false,
|
||||
[currentClassification?.disabled]
|
||||
);
|
||||
const versionHandler = useCallback(() => {
|
||||
isVersionView
|
||||
? history.push(getClassificationDetailsPath(tagCategoryName))
|
||||
: history.push(
|
||||
getClassificationVersionsPath(
|
||||
tagCategoryName,
|
||||
toString(currentVersion)
|
||||
)
|
||||
);
|
||||
}, [currentVersion, tagCategoryName]);
|
||||
|
||||
const handleUpdateDisplayName = async (data: {
|
||||
name: string;
|
||||
displayName: string;
|
||||
}) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
return handleUpdateClassification({
|
||||
...currentClassification,
|
||||
...data,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isTier = useMemo(
|
||||
() => currentClassification?.name === 'Tier',
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const handleUpdateDescription = async (updatedHTML: string) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
description: updatedHTML,
|
||||
});
|
||||
}
|
||||
};
|
||||
const createTagPermission = useMemo(
|
||||
() =>
|
||||
checkPermission(Operation.Create, ResourceEntity.TAG, permissions) ||
|
||||
classificationPermissions.EditAll,
|
||||
[permissions, classificationPermissions]
|
||||
);
|
||||
|
||||
const handleEnableDisableClassificationClick = useCallback(() => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
disabled: !isClassificationDisabled,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
currentClassification,
|
||||
handleUpdateClassification,
|
||||
isClassificationDisabled,
|
||||
]);
|
||||
const editClassificationPermission = useMemo(
|
||||
() => classificationPermissions.EditAll,
|
||||
[classificationPermissions]
|
||||
);
|
||||
|
||||
const handleUpdateMutuallyExclusive = async (value: boolean) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
mutuallyExclusive: value,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isClassificationDisabled = useMemo(
|
||||
() => currentClassification?.disabled ?? false,
|
||||
[currentClassification?.disabled]
|
||||
);
|
||||
|
||||
const editDescriptionPermission = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
!isClassificationDisabled &&
|
||||
(classificationPermissions.EditAll ||
|
||||
classificationPermissions.EditDescription),
|
||||
[classificationPermissions, isVersionView]
|
||||
);
|
||||
const handleUpdateDisplayName = async (data: {
|
||||
name: string;
|
||||
displayName: string;
|
||||
}) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
return handleUpdateClassification({
|
||||
...currentClassification,
|
||||
...data,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isSystemClassification = useMemo(
|
||||
() => currentClassification?.provider === ProviderType.System,
|
||||
[currentClassification]
|
||||
);
|
||||
const handleUpdateDescription = async (updatedHTML: string) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
description: updatedHTML,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const headerBadge = useMemo(
|
||||
() =>
|
||||
isSystemClassification ? (
|
||||
<AppBadge
|
||||
icon={<LockIcon height={12} />}
|
||||
label={capitalize(currentClassification?.provider)}
|
||||
/>
|
||||
) : null,
|
||||
[isSystemClassification, currentClassification]
|
||||
);
|
||||
const handleEnableDisableClassificationClick = useCallback(() => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
disabled: !isClassificationDisabled,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
currentClassification,
|
||||
handleUpdateClassification,
|
||||
isClassificationDisabled,
|
||||
]);
|
||||
|
||||
const createPermission = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
(createTagPermission || classificationPermissions.EditAll),
|
||||
[classificationPermissions, createTagPermission, isVersionView]
|
||||
);
|
||||
const handleUpdateMutuallyExclusive = async (value: boolean) => {
|
||||
if (
|
||||
!isUndefined(currentClassification) &&
|
||||
!isUndefined(handleUpdateClassification)
|
||||
) {
|
||||
handleUpdateClassification({
|
||||
...currentClassification,
|
||||
mutuallyExclusive: value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const deletePermission = useMemo(
|
||||
() => classificationPermissions.Delete && !isSystemClassification,
|
||||
[classificationPermissions, isSystemClassification]
|
||||
);
|
||||
const editDescriptionPermission = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
!isClassificationDisabled &&
|
||||
(classificationPermissions.EditAll ||
|
||||
classificationPermissions.EditDescription),
|
||||
[classificationPermissions, isVersionView]
|
||||
);
|
||||
|
||||
const editDisplayNamePermission = useMemo(
|
||||
() =>
|
||||
classificationPermissions.EditAll ||
|
||||
classificationPermissions.EditDisplayName,
|
||||
[classificationPermissions]
|
||||
);
|
||||
const isSystemClassification = useMemo(
|
||||
() => currentClassification?.provider === ProviderType.System,
|
||||
[currentClassification]
|
||||
);
|
||||
|
||||
const showDisableOption = useMemo(
|
||||
() => !isTier && isSystemClassification && editClassificationPermission,
|
||||
[isTier, isSystemClassification, editClassificationPermission]
|
||||
);
|
||||
const headerBadge = useMemo(
|
||||
() =>
|
||||
isSystemClassification ? (
|
||||
<AppBadge
|
||||
icon={<LockIcon height={12} />}
|
||||
label={capitalize(currentClassification?.provider)}
|
||||
/>
|
||||
) : null,
|
||||
[isSystemClassification, currentClassification]
|
||||
);
|
||||
|
||||
const showManageButton = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
(editDisplayNamePermission || deletePermission || showDisableOption),
|
||||
[
|
||||
editDisplayNamePermission,
|
||||
deletePermission,
|
||||
showDisableOption,
|
||||
isVersionView,
|
||||
]
|
||||
);
|
||||
const createPermission = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
(createTagPermission || classificationPermissions.EditAll),
|
||||
[classificationPermissions, createTagPermission, isVersionView]
|
||||
);
|
||||
|
||||
const addTagButtonToolTip = useMemo(() => {
|
||||
if (isClassificationDisabled) {
|
||||
return t('message.disabled-classification-actions-message');
|
||||
}
|
||||
if (!createPermission) {
|
||||
return t('message.no-permission-for-action');
|
||||
}
|
||||
const deletePermission = useMemo(
|
||||
() => classificationPermissions.Delete && !isSystemClassification,
|
||||
[classificationPermissions, isSystemClassification]
|
||||
);
|
||||
|
||||
return null;
|
||||
}, [createPermission, isClassificationDisabled]);
|
||||
const editDisplayNamePermission = useMemo(
|
||||
() =>
|
||||
classificationPermissions.EditAll ||
|
||||
classificationPermissions.EditDisplayName,
|
||||
[classificationPermissions]
|
||||
);
|
||||
|
||||
const tableColumn: ColumnsType<Tag> = useMemo(
|
||||
() =>
|
||||
getTagsTableColumn({
|
||||
const showDisableOption = useMemo(
|
||||
() => !isTier && isSystemClassification && editClassificationPermission,
|
||||
[isTier, isSystemClassification, editClassificationPermission]
|
||||
);
|
||||
|
||||
const showManageButton = useMemo(
|
||||
() =>
|
||||
!isVersionView &&
|
||||
(editDisplayNamePermission || deletePermission || showDisableOption),
|
||||
[
|
||||
editDisplayNamePermission,
|
||||
deletePermission,
|
||||
showDisableOption,
|
||||
isVersionView,
|
||||
]
|
||||
);
|
||||
|
||||
const addTagButtonToolTip = useMemo(() => {
|
||||
if (isClassificationDisabled) {
|
||||
return t('message.disabled-classification-actions-message');
|
||||
}
|
||||
if (!createPermission) {
|
||||
return t('message.no-permission-for-action');
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [createPermission, isClassificationDisabled]);
|
||||
|
||||
const tableColumn: ColumnsType<Tag> = useMemo(
|
||||
() =>
|
||||
getTagsTableColumn({
|
||||
isClassificationDisabled,
|
||||
classificationPermissions,
|
||||
deleteTags,
|
||||
disableEditButton,
|
||||
handleEditTagClick,
|
||||
handleActionDeleteTag,
|
||||
isVersionView,
|
||||
}),
|
||||
[
|
||||
isClassificationDisabled,
|
||||
classificationPermissions,
|
||||
deleteTags,
|
||||
@ -343,236 +340,227 @@ function ClassificationDetails({
|
||||
handleEditTagClick,
|
||||
handleActionDeleteTag,
|
||||
isVersionView,
|
||||
}),
|
||||
[
|
||||
isClassificationDisabled,
|
||||
classificationPermissions,
|
||||
deleteTags,
|
||||
disableEditButton,
|
||||
handleEditTagClick,
|
||||
handleActionDeleteTag,
|
||||
isVersionView,
|
||||
]
|
||||
);
|
||||
]
|
||||
);
|
||||
|
||||
const extraDropdownContent = useMemo(
|
||||
() =>
|
||||
getClassificationExtraDropdownContent(
|
||||
showDisableOption,
|
||||
const extraDropdownContent = useMemo(
|
||||
() =>
|
||||
getClassificationExtraDropdownContent(
|
||||
showDisableOption,
|
||||
isClassificationDisabled,
|
||||
handleEnableDisableClassificationClick
|
||||
),
|
||||
[
|
||||
isClassificationDisabled,
|
||||
handleEnableDisableClassificationClick
|
||||
),
|
||||
[
|
||||
isClassificationDisabled,
|
||||
showDisableOption,
|
||||
handleEnableDisableClassificationClick,
|
||||
]
|
||||
);
|
||||
showDisableOption,
|
||||
handleEnableDisableClassificationClick,
|
||||
]
|
||||
);
|
||||
|
||||
const name = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.NAME,
|
||||
currentClassification?.name
|
||||
)
|
||||
: currentClassification?.name;
|
||||
}, [currentClassification, changeDescription]);
|
||||
const name = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.NAME,
|
||||
currentClassification?.name
|
||||
)
|
||||
: currentClassification?.name;
|
||||
}, [currentClassification, changeDescription]);
|
||||
|
||||
const displayName = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.DISPLAYNAME,
|
||||
currentClassification?.displayName
|
||||
)
|
||||
: currentClassification?.displayName;
|
||||
}, [currentClassification, changeDescription]);
|
||||
const displayName = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.DISPLAYNAME,
|
||||
currentClassification?.displayName
|
||||
)
|
||||
: currentClassification?.displayName;
|
||||
}, [currentClassification, changeDescription]);
|
||||
|
||||
const description = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.DESCRIPTION,
|
||||
currentClassification?.description
|
||||
)
|
||||
: currentClassification?.description;
|
||||
}, [currentClassification, changeDescription]);
|
||||
const description = useMemo(() => {
|
||||
return isVersionView
|
||||
? getEntityVersionByField(
|
||||
changeDescription,
|
||||
EntityField.DESCRIPTION,
|
||||
currentClassification?.description
|
||||
)
|
||||
: currentClassification?.description;
|
||||
}, [currentClassification, changeDescription]);
|
||||
|
||||
const mutuallyExclusive = useMemo(() => {
|
||||
return isVersionView
|
||||
? getMutuallyExclusiveDiff(
|
||||
changeDescription,
|
||||
EntityField.MUTUALLY_EXCLUSIVE,
|
||||
toString(currentClassification?.mutuallyExclusive)
|
||||
)
|
||||
: '';
|
||||
}, [currentClassification, changeDescription]);
|
||||
const mutuallyExclusive = useMemo(() => {
|
||||
return isVersionView
|
||||
? getMutuallyExclusiveDiff(
|
||||
changeDescription,
|
||||
EntityField.MUTUALLY_EXCLUSIVE,
|
||||
toString(currentClassification?.mutuallyExclusive)
|
||||
)
|
||||
: '';
|
||||
}, [currentClassification, changeDescription]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
currentClassification?.fullyQualifiedName &&
|
||||
!deleteTags?.state &&
|
||||
!isAddingTag
|
||||
) {
|
||||
fetchClassificationChildren(currentClassification.fullyQualifiedName);
|
||||
}
|
||||
}, [
|
||||
currentClassification?.fullyQualifiedName,
|
||||
pageSize,
|
||||
deleteTags?.state,
|
||||
isAddingTag,
|
||||
]);
|
||||
useEffect(() => {
|
||||
if (currentClassification?.fullyQualifiedName && !isAddingTag) {
|
||||
fetchClassificationChildren(currentClassification.fullyQualifiedName);
|
||||
}
|
||||
}, [currentClassification?.fullyQualifiedName, pageSize]);
|
||||
|
||||
return (
|
||||
<div className="p-x-md" data-testid="tags-container">
|
||||
{currentClassification && (
|
||||
<Row data-testid="header" wrap={false}>
|
||||
<Col flex="auto">
|
||||
<EntityHeaderTitle
|
||||
badge={headerBadge}
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
displayName={displayName}
|
||||
icon={
|
||||
<IconTag className="h-9" style={{ color: DE_ACTIVE_COLOR }} />
|
||||
}
|
||||
isDisabled={isClassificationDisabled}
|
||||
name={name ?? currentClassification.name}
|
||||
serviceName="classification"
|
||||
/>
|
||||
</Col>
|
||||
useImperativeHandle(ref, () => ({
|
||||
refreshClassificationTags() {
|
||||
if (currentClassification?.fullyQualifiedName) {
|
||||
fetchClassificationChildren(currentClassification.fullyQualifiedName);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
<Col className="d-flex justify-end items-start" flex="270px">
|
||||
<Space>
|
||||
{createPermission && (
|
||||
<Tooltip title={addTagButtonToolTip}>
|
||||
<Button
|
||||
data-testid="add-new-tag-button"
|
||||
disabled={isClassificationDisabled}
|
||||
type="primary"
|
||||
onClick={handleAddNewTagClick}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.tag'),
|
||||
})}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<ButtonGroup size="small">
|
||||
<Button
|
||||
className="w-16 p-0"
|
||||
data-testid="version-button"
|
||||
icon={<Icon component={VersionIcon} />}
|
||||
onClick={versionHandler}>
|
||||
<Typography.Text>{currentVersion}</Typography.Text>
|
||||
</Button>
|
||||
{showManageButton && (
|
||||
<ManageButton
|
||||
isRecursiveDelete
|
||||
afterDeleteAction={handleAfterDeleteAction}
|
||||
allowRename={!isSystemClassification}
|
||||
allowSoftDelete={false}
|
||||
canDelete={deletePermission && !isClassificationDisabled}
|
||||
displayName={
|
||||
currentClassification.displayName ??
|
||||
currentClassification.name
|
||||
}
|
||||
editDisplayNamePermission={
|
||||
editDisplayNamePermission && !isClassificationDisabled
|
||||
}
|
||||
entityFQN={currentClassification.fullyQualifiedName}
|
||||
entityId={currentClassification.id}
|
||||
entityName={currentClassification.name}
|
||||
entityType={EntityType.CLASSIFICATION}
|
||||
extraDropdownContent={extraDropdownContent}
|
||||
onEditDisplayName={handleUpdateDisplayName}
|
||||
/>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<div className="m-b-sm m-t-xs" data-testid="description-container">
|
||||
<Description
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
description={description}
|
||||
entityName={getEntityName(currentClassification)}
|
||||
hasEditAccess={editDescriptionPermission}
|
||||
isEdit={isEditClassification}
|
||||
onCancel={handleCancelEditDescription}
|
||||
onDescriptionEdit={handleEditDescriptionClick}
|
||||
onDescriptionUpdate={handleUpdateDescription}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="m-b-md m-t-xs d-flex justify-end"
|
||||
data-testid="mutually-exclusive-container">
|
||||
<Space align="center" size="small">
|
||||
<Typography.Text
|
||||
className="text-grey-muted"
|
||||
data-testid="mutually-exclusive-classification-label">
|
||||
{t('label.mutually-exclusive')}
|
||||
</Typography.Text>
|
||||
|
||||
{isVersionView ? (
|
||||
<>
|
||||
<Typography.Text>:</Typography.Text>
|
||||
<RichTextEditorPreviewer
|
||||
className={classNames('font-medium', {
|
||||
return (
|
||||
<div className="p-x-md" data-testid="tags-container">
|
||||
{currentClassification && (
|
||||
<Row data-testid="header" wrap={false}>
|
||||
<Col flex="auto">
|
||||
<EntityHeaderTitle
|
||||
badge={headerBadge}
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
markdown={mutuallyExclusive}
|
||||
displayName={displayName}
|
||||
icon={
|
||||
<IconTag className="h-9" style={{ color: DE_ACTIVE_COLOR }} />
|
||||
}
|
||||
isDisabled={isClassificationDisabled}
|
||||
name={name ?? currentClassification.name}
|
||||
serviceName="classification"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Switch
|
||||
checked={currentClassification?.mutuallyExclusive}
|
||||
data-testid="mutually-exclusive-classification-button"
|
||||
disabled={isClassificationDisabled}
|
||||
onChange={handleUpdateMutuallyExclusive}
|
||||
</Col>
|
||||
|
||||
<Col className="d-flex justify-end items-start" flex="270px">
|
||||
<Space>
|
||||
{createPermission && (
|
||||
<Tooltip title={addTagButtonToolTip}>
|
||||
<Button
|
||||
data-testid="add-new-tag-button"
|
||||
disabled={isClassificationDisabled}
|
||||
type="primary"
|
||||
onClick={handleAddNewTagClick}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.tag'),
|
||||
})}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<ButtonGroup size="small">
|
||||
<Button
|
||||
className="w-16 p-0"
|
||||
data-testid="version-button"
|
||||
icon={<Icon component={VersionIcon} />}
|
||||
onClick={versionHandler}>
|
||||
<Typography.Text>{currentVersion}</Typography.Text>
|
||||
</Button>
|
||||
{showManageButton && (
|
||||
<ManageButton
|
||||
isRecursiveDelete
|
||||
afterDeleteAction={handleAfterDeleteAction}
|
||||
allowRename={!isSystemClassification}
|
||||
allowSoftDelete={false}
|
||||
canDelete={deletePermission && !isClassificationDisabled}
|
||||
displayName={
|
||||
currentClassification.displayName ??
|
||||
currentClassification.name
|
||||
}
|
||||
editDisplayNamePermission={
|
||||
editDisplayNamePermission && !isClassificationDisabled
|
||||
}
|
||||
entityFQN={currentClassification.fullyQualifiedName}
|
||||
entityId={currentClassification.id}
|
||||
entityName={currentClassification.name}
|
||||
entityType={EntityType.CLASSIFICATION}
|
||||
extraDropdownContent={extraDropdownContent}
|
||||
onEditDisplayName={handleUpdateDisplayName}
|
||||
/>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<div className="m-b-sm m-t-xs" data-testid="description-container">
|
||||
<Description
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
description={description}
|
||||
entityName={getEntityName(currentClassification)}
|
||||
hasEditAccess={editDescriptionPermission}
|
||||
isEdit={isEditClassification}
|
||||
onCancel={handleCancelEditDescription}
|
||||
onDescriptionEdit={handleEditDescriptionClick}
|
||||
onDescriptionUpdate={handleUpdateDescription}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="m-b-md m-t-xs d-flex justify-end"
|
||||
data-testid="mutually-exclusive-container">
|
||||
<Space align="center" size="small">
|
||||
<Typography.Text
|
||||
className="text-grey-muted"
|
||||
data-testid="mutually-exclusive-classification-label">
|
||||
{t('label.mutually-exclusive')}
|
||||
</Typography.Text>
|
||||
|
||||
{isVersionView ? (
|
||||
<>
|
||||
<Typography.Text>:</Typography.Text>
|
||||
<RichTextEditorPreviewer
|
||||
className={classNames('font-medium', {
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
markdown={mutuallyExclusive}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Switch
|
||||
checked={currentClassification?.mutuallyExclusive}
|
||||
data-testid="mutually-exclusive-classification-button"
|
||||
disabled={isClassificationDisabled}
|
||||
onChange={handleUpdateMutuallyExclusive}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Space className="w-full m-b-md" direction="vertical" size="large">
|
||||
<Table
|
||||
bordered
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
columns={tableColumn}
|
||||
data-testid="table"
|
||||
dataSource={tags}
|
||||
loading={isTagsLoading}
|
||||
locale={{
|
||||
emptyText: <ErrorPlaceHolder className="m-y-md" />,
|
||||
}}
|
||||
pagination={false}
|
||||
rowClassName={(record) => (record.disabled ? 'opacity-60' : '')}
|
||||
rowKey="id"
|
||||
size="small"
|
||||
/>
|
||||
|
||||
{showPagination && !isTagsLoading && (
|
||||
<NextPrevious
|
||||
currentPage={currentPage}
|
||||
pageSize={pageSize}
|
||||
paging={paging}
|
||||
pagingHandler={handleTagsPageChange}
|
||||
onShowSizeChange={handlePageSizeChange}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Space className="w-full m-b-md" direction="vertical" size="large">
|
||||
<Table
|
||||
bordered
|
||||
className={classNames({
|
||||
'opacity-60': isClassificationDisabled,
|
||||
})}
|
||||
columns={tableColumn}
|
||||
data-testid="table"
|
||||
dataSource={tags}
|
||||
loading={isTagsLoading}
|
||||
locale={{
|
||||
emptyText: <ErrorPlaceHolder className="m-y-md" />,
|
||||
}}
|
||||
pagination={false}
|
||||
rowClassName={(record) => (record.disabled ? 'opacity-60' : '')}
|
||||
rowKey="id"
|
||||
size="small"
|
||||
/>
|
||||
|
||||
{showPagination && !isTagsLoading && (
|
||||
<NextPrevious
|
||||
currentPage={currentPage}
|
||||
pageSize={pageSize}
|
||||
paging={paging}
|
||||
pagingHandler={handleTagsPageChange}
|
||||
onShowSizeChange={handlePageSizeChange}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ClassificationDetails;
|
||||
|
||||
@ -19,7 +19,7 @@ export interface EntityDeleteModalProp extends HTMLAttributes<HTMLDivElement> {
|
||||
entityName: string;
|
||||
entityType: string;
|
||||
loadingState: string;
|
||||
bodyText?: string;
|
||||
bodyText?: string | JSX.Element;
|
||||
softDelete?: boolean;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
@ -16,19 +16,18 @@ import { t } from 'i18next';
|
||||
import React, { ChangeEvent, useEffect, useMemo, useState } from 'react';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { LOADING_STATE } from '../../../enums/common.enum';
|
||||
import { getTitleCase } from '../../../utils/EntityUtils';
|
||||
import { Transi18next } from '../../../utils/CommonUtils';
|
||||
import { EntityDeleteModalProp } from './EntityDeleteModal.interface';
|
||||
|
||||
const EntityDeleteModal = ({
|
||||
loadingState = 'initial',
|
||||
className,
|
||||
entityName,
|
||||
entityType,
|
||||
onCancel,
|
||||
onConfirm,
|
||||
bodyText,
|
||||
softDelete = false,
|
||||
visible,
|
||||
bodyText,
|
||||
}: EntityDeleteModalProp) => {
|
||||
const [name, setName] = useState('');
|
||||
|
||||
@ -92,12 +91,19 @@ const EntityDeleteModal = ({
|
||||
}
|
||||
width={600}>
|
||||
<div data-testid="body-text">
|
||||
<Typography className="mb-2">
|
||||
{bodyText ||
|
||||
t('message.delete-entity-permanently', {
|
||||
entityType: getTitleCase(entityType),
|
||||
})}
|
||||
</Typography>
|
||||
<div className="mb-2">
|
||||
{bodyText || (
|
||||
<Transi18next
|
||||
i18nKey="message.permanently-delete-metadata"
|
||||
renderElement={
|
||||
<span data-testid="entityName" style={{ fontWeight: 500 }} />
|
||||
}
|
||||
values={{
|
||||
entityName: entityName,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Typography className="mb-2">
|
||||
<Trans
|
||||
i18nKey="label.type-to-confirm"
|
||||
|
||||
@ -90,9 +90,12 @@ const DeleteWidgetModal = ({
|
||||
},
|
||||
{
|
||||
title: `${t('label.permanently-delete')} ${entityType} “${entityName}”`,
|
||||
description: `${
|
||||
deleteMessage || getDeleteMessage(entityName, entityType)
|
||||
} ${hardDeleteMessagePostFix}`,
|
||||
description: (
|
||||
<>
|
||||
{deleteMessage ?? getDeleteMessage(entityName, entityType)}
|
||||
{hardDeleteMessagePostFix}
|
||||
</>
|
||||
),
|
||||
type: DeleteType.HARD_DELETE,
|
||||
isAllowed: true,
|
||||
},
|
||||
|
||||
@ -330,7 +330,7 @@ li.ProseMirror-selectednode:after {
|
||||
}
|
||||
|
||||
.toastui-editor-md-tab-container .toastui-editor-tabs {
|
||||
margin-left: 15px;
|
||||
margin-left: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -365,7 +365,6 @@ li.ProseMirror-selectednode:after {
|
||||
.toastui-editor-defaultUI-toolbar {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 0 25px;
|
||||
height: 45px;
|
||||
background-color: #f7f9fc;
|
||||
border-bottom: 1px solid #ebedf2;
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Das Passwort muss mindestens 8 und maximal 16 Zeichen lang sein und mindestens einen Großbuchstaben (A-Z), einen Kleinbuchstaben (a-z), eine Zahl und ein Sonderzeichen (z. B. !, %, @ oder #) enthalten.",
|
||||
"password-pattern-error": "Das Passwort muss mindestens 8 und maximal 16 Zeichen lang sein und mindestens einen Sonderbuchstaben, einen Großbuchstaben und einen Kleinbuchstaben enthalten.",
|
||||
"path-of-the-dbt-files-stored": "Pfad zum Ordner, in dem die dbt-Dateien gespeichert sind",
|
||||
"permanently-delete-metadata": "Das dauerhafte Löschen dieses {{entityName}} entfernt seine Metadaten dauerhaft aus OpenMetadata.",
|
||||
"permanently-delete-metadata": "Das dauerhafte Löschen dieses <0>{{entityName}}</0> entfernt seine Metadaten dauerhaft aus OpenMetadata.",
|
||||
"permanently-delete-metadata-and-dependents": "Das dauerhafte Löschen dieses {{entityName}} entfernt seine Metadaten sowie die Metadaten von {{dependents}} dauerhaft aus OpenMetadata.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Beschreibung der Pipeline.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Password must be a minimum of 8 and a maximum of 16 characters long and contain at least one uppercase character (A-Z), one lowercase character (a-z), one number, and one special character (such as !, %, @, or #)",
|
||||
"password-pattern-error": "Password must be of minimum 8 and maximum 16 characters, with one special , one upper, one lower case character",
|
||||
"path-of-the-dbt-files-stored": "Path of the folder where the dbt files are stored",
|
||||
"permanently-delete-metadata": "Permanently deleting this {{entityName}} will remove its metadata from OpenMetadata permanently.",
|
||||
"permanently-delete-metadata": "Permanently deleting this <0>{{entityName}}</0> will remove its metadata from OpenMetadata permanently.",
|
||||
"permanently-delete-metadata-and-dependents": "Permanently deleting this {{entityName}} will remove its metadata, as well as the metadata of {{dependents}} from OpenMetadata permanently.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Description of the pipeline.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Password must be a minimum of 8 and a maximum of 16 characters long and contain at least one uppercase character (A-Z), one lowercase character (a-z), one number, and one special character (such as !, %, @, or #)",
|
||||
"password-pattern-error": "La contraseña debe tener como mínimo 8 y como máximo 16 caracteres, con un caracter especial, una letra mayúscula, y una letra minúscula.",
|
||||
"path-of-the-dbt-files-stored": "Ruta de la carpeta donde se almacenan los archivos dbt",
|
||||
"permanently-delete-metadata": "Al eliminar permanentemente este {{entityName}}, se eliminaran sus metadatos de OpenMetadata permanentemente.",
|
||||
"permanently-delete-metadata": "Al eliminar permanentemente este <0>{{entityName}}</0>, se eliminaran sus metadatos de OpenMetadata permanentemente.",
|
||||
"permanently-delete-metadata-and-dependents": "Al eliminar permanentemente este {{entityName}}, se eliminaran sus metadatos, así como los metadatos de {{dependents}} de OpenMetadata permanentemente.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Descripción del pipeline.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Le mot de passe doit comporter au moins 8 caractères et au plus 16 caractères et doit contenir au moins une lettre majuscule (A-Z), une lettre minuscule (a-z), un chiffre et un caractère spécial (tel que !, %, @ ou #).",
|
||||
"password-pattern-error": "Le mot de passe doit comporter au moins 8 caractères et au plus 16 caractères, avec un caractère spécial, une lettre majuscule et une lettre minuscule.",
|
||||
"path-of-the-dbt-files-stored": "Chemin du dossier où sont situés les fichiers dbt.",
|
||||
"permanently-delete-metadata": "La suppression permanente de cette {{entityName}} supprimera ses métadonnées de façon permanente d'OpenMetadata.",
|
||||
"permanently-delete-metadata": "La suppression permanente de cette <0>{{entityName}}</0> supprimera ses métadonnées de façon permanente d'OpenMetadata.",
|
||||
"permanently-delete-metadata-and-dependents": "La suppression permanente de cette {{entityName}} supprimera ses métadonnées ainsi que les métadonnées de {{dependents}} de façon permanente d'OpenMetadata.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Description du pipeline.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Password must be a minimum of 8 and a maximum of 16 characters long and contain at least one uppercase character (A-Z), one lowercase character (a-z), one number, and one special character (such as !, %, @, or #)",
|
||||
"password-pattern-error": "パスワードは8~16の文字列で、1つの特殊文字、大文字1つ、小文字1つが含まれる必要があります。",
|
||||
"path-of-the-dbt-files-stored": "Path of the folder where the dbt files are stored",
|
||||
"permanently-delete-metadata": "Permanently deleting this {{entityName}} will remove its metadata from OpenMetadata permanently.",
|
||||
"permanently-delete-metadata": "Permanently deleting this <0>{{entityName}}</0> will remove its metadata from OpenMetadata permanently.",
|
||||
"permanently-delete-metadata-and-dependents": "Permanently deleting this {{entityName}} will remove its metadata, as well as the metadata of {{dependents}} from OpenMetadata permanently.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "パイプラインの説明",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "A senha deve ter no mínimo 8 e no máximo 16 caracteres e conter pelo menos uma letra maiúscula (A-Z), uma letra minúscula (a-z), um número e um caractere especial (como !, %, @ ou #)",
|
||||
"password-pattern-error": "A senha deve ter no mínimo 8 e no máximo 16 caracteres, com pelo menos um caractere especial, uma letra maiúscula e uma letra minúscula",
|
||||
"path-of-the-dbt-files-stored": "Caminho da pasta onde os arquivos dbt são armazenados",
|
||||
"permanently-delete-metadata": "Excluir permanentemente este(a) {{entityName}} removerá seus metadados do OpenMetadata permanentemente.",
|
||||
"permanently-delete-metadata": "Excluir permanentemente este(a) <0>{{entityName}}</0> removerá seus metadados do OpenMetadata permanentemente.",
|
||||
"permanently-delete-metadata-and-dependents": "Excluir permanentemente este(a) {{entityName}} removerá seus metadados, bem como os metadados de {{dependents}} do OpenMetadata permanentemente.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Descrição do pipeline.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "Пароль должен содержать не менее 8 и не более 16 символов и содержать как минимум один символ верхнего регистра (A-Z), один символ нижнего регистра (az), одну цифру и один специальный символ (например, !, %, @ или #). )",
|
||||
"password-pattern-error": "Пароль должен состоять минимум из 8 и максимум из 16 символов, включая один специальный, один верхний и один нижний регистр.",
|
||||
"path-of-the-dbt-files-stored": "Путь к папке, в которой хранятся файлы dbt",
|
||||
"permanently-delete-metadata": "При окончательном удалении этого объекта {{entityName}} его метаданные будут навсегда удалены из OpenMetadata.",
|
||||
"permanently-delete-metadata": "При окончательном удалении этого объекта <0>{{entityName}}</0> его метаданные будут навсегда удалены из OpenMetadata.",
|
||||
"permanently-delete-metadata-and-dependents": "Безвозвратное удаление этого {{entityName}} удалит его метаданные, а также метаданные {{dependers}} из OpenMetadata навсегда.",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "Описание пайплайна.",
|
||||
|
||||
@ -1519,7 +1519,7 @@
|
||||
"password-error-message": "密码必须为8到16个字符,至少包括一个大写字母(A-Z)、一个小写字母(a-z),和一个特殊字符(例如:!, %, @, or #)",
|
||||
"password-pattern-error": "密码必须为8到16个字符,至少包括一个特殊字符、一个大写字母、一个小写字母",
|
||||
"path-of-the-dbt-files-stored": "存储 dbt 文件的文件夹路径",
|
||||
"permanently-delete-metadata": "永久删除此{{entityName}}将永久从 OpenMetadata 中删除其元数据",
|
||||
"permanently-delete-metadata": "永久删除此<0>{{entityName}}</0>将永久从 OpenMetadata 中删除其元数据",
|
||||
"permanently-delete-metadata-and-dependents": "永久删除此{{entityName}}将永久从 OpenMetadata 中删除其元数据以及{{dependents}}的元数据",
|
||||
"personal-access-token": "Personal Access Token",
|
||||
"pipeline-description-message": "工作流的描述信息",
|
||||
|
||||
@ -16,11 +16,18 @@ import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { isUndefined, omit } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { ReactComponent as PlusIcon } from '../../assets/svg/plus-primary.svg';
|
||||
import ClassificationDetails from '../../components/ClassificationDetails/ClassificationDetails';
|
||||
import { ClassificationDetailsRef } from '../../components/ClassificationDetails/ClassificationDetails.interface';
|
||||
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||
import LeftPanelCard from '../../components/common/LeftPanelCard/LeftPanelCard';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
@ -82,6 +89,7 @@ const TagsPage = () => {
|
||||
const [error, setError] = useState<string>('');
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isUpdateLoading, setIsUpdateLoading] = useState<boolean>(false);
|
||||
const classificationDetailsRef = useRef<ClassificationDetailsRef>(null);
|
||||
|
||||
const [deleteTags, setDeleteTags] = useState<DeleteTagsType>({
|
||||
data: undefined,
|
||||
@ -278,6 +286,7 @@ const TagsPage = () => {
|
||||
})
|
||||
);
|
||||
}
|
||||
classificationDetailsRef.current?.refreshClassificationTags();
|
||||
} else {
|
||||
showErrorToast(
|
||||
t('server.delete-entity-error', {
|
||||
@ -391,6 +400,7 @@ const TagsPage = () => {
|
||||
return data;
|
||||
});
|
||||
});
|
||||
classificationDetailsRef.current?.refreshClassificationTags();
|
||||
} catch (error) {
|
||||
if (
|
||||
(error as AxiosError).response?.status === HTTP_STATUS_CODE.CONFLICT
|
||||
@ -693,7 +703,6 @@ const TagsPage = () => {
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorPlaceHolder>
|
||||
@ -723,6 +732,7 @@ const TagsPage = () => {
|
||||
handleUpdateClassification={handleUpdateClassification}
|
||||
isAddingTag={isAddingTag}
|
||||
isEditClassification={isEditClassification}
|
||||
ref={classificationDetailsRef}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ import { EntityReference } from '../generated/entity/teams/user';
|
||||
import { TagLabel } from '../generated/type/tagLabel';
|
||||
import { SearchSourceAlias } from '../interface/search.interface';
|
||||
import { getFeedCount } from '../rest/feedsAPI';
|
||||
import { getEntityFeedLink, getTitleCase } from './EntityUtils';
|
||||
import { getEntityFeedLink } from './EntityUtils';
|
||||
import Fqn from './Fqn';
|
||||
import { history } from './HistoryUtils';
|
||||
import { getSearchIndexTabPath } from './SearchIndexUtils';
|
||||
@ -498,19 +498,6 @@ export const getEntityPlaceHolder = (value: string, isDeleted?: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getEntityDeleteMessage = (entity: string, dependents: string) => {
|
||||
if (dependents) {
|
||||
return t('message.permanently-delete-metadata-and-dependents', {
|
||||
entityName: getTitleCase(entity),
|
||||
dependents,
|
||||
});
|
||||
} else {
|
||||
return t('message.permanently-delete-metadata', {
|
||||
entityName: getTitleCase(entity),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const replaceSpaceWith_ = (text: string) => {
|
||||
return text.replace(/\s/g, '_');
|
||||
};
|
||||
@ -730,6 +717,26 @@ export const Transi18next = ({
|
||||
</Trans>
|
||||
);
|
||||
|
||||
export const getEntityDeleteMessage = (entity: string, dependents: string) => {
|
||||
if (dependents) {
|
||||
return t('message.permanently-delete-metadata-and-dependents', {
|
||||
entityName: entity,
|
||||
dependents,
|
||||
});
|
||||
} else {
|
||||
return (
|
||||
<Transi18next
|
||||
i18nKey="message.permanently-delete-metadata"
|
||||
renderElement={
|
||||
<span className="font-medium" data-testid="entityName" />
|
||||
}
|
||||
values={{
|
||||
entityName: entity,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* It takes a state and an action, and returns a new state with the action merged into it
|
||||
* @param {S} state - S - The current state of the reducer.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user