diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Bots.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Bots.spec.js index 2ad0f5dd5f25..ff4e2facd838 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Bots.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Bots.spec.js @@ -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 diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.interface.ts new file mode 100644 index 000000000000..6ec313bf363b --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.interface.ts @@ -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; +} +export interface ClassificationDetailsRef { + refreshClassificationTags: () => void; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.tsx index 2c2448d271fa..99643ea9800d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ClassificationDetails/ClassificationDetails.tsx @@ -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'; + +const ClassificationDetails = forwardRef( + ( + { + currentClassification, + handleAfterDeleteAction, + isEditClassification, + classificationPermissions, + handleUpdateClassification, + handleEditTagClick, + deleteTags, + isAddingTag, + handleActionDeleteTag, + handleAddNewTagClick, + handleEditDescriptionClick, + handleCancelEditDescription, + disableEditButton, -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; -} - -function ClassificationDetails({ - currentClassification, - handleAfterDeleteAction, - isEditClassification, - classificationPermissions, - handleUpdateClassification, - handleEditTagClick, - deleteTags, - isAddingTag, - handleActionDeleteTag, - handleAddNewTagClick, - handleEditDescriptionClick, - handleCancelEditDescription, - disableEditButton, - isVersionView = false, -}: Readonly) { - const { permissions } = usePermissionProvider(); - const { t } = useTranslation(); - const { fqn: tagCategoryName } = useParams<{ fqn: string }>(); - const history = useHistory(); - const [tags, setTags] = useState([]); - const [isTagsLoading, setIsTagsLoading] = useState(false); - - const { - currentPage, - paging, - pageSize, - handlePageChange, - handlePageSizeChange, - handlePagingChange, - showPagination, - } = usePaging(); - - const fetchClassificationChildren = async ( - currentClassificationName: string, - paging?: Partial + isVersionView = false, + }: Readonly, + 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([]); + const [isTagsLoading, setIsTagsLoading] = useState(false); + + const { + currentPage, + paging, + pageSize, + handlePageChange, + handlePageSizeChange, + handlePagingChange, + showPagination, + } = usePaging(); + + const fetchClassificationChildren = async ( + currentClassificationName: string, + paging?: Partial + ) => { + 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]); - - const isTier = useMemo( - () => currentClassification?.name === 'Tier', - [currentClassification] - ); - - const createTagPermission = useMemo( - () => - checkPermission(Operation.Create, ResourceEntity.TAG, permissions) || - classificationPermissions.EditAll, - [permissions, classificationPermissions] - ); - - const editClassificationPermission = useMemo( - () => classificationPermissions.EditAll, - [classificationPermissions] - ); - - const isClassificationDisabled = useMemo( - () => currentClassification?.disabled ?? false, - [currentClassification?.disabled] - ); - - const handleUpdateDisplayName = async (data: { - name: string; - displayName: string; - }) => { - if ( - !isUndefined(currentClassification) && - !isUndefined(handleUpdateClassification) - ) { - return handleUpdateClassification({ - ...currentClassification, - ...data, - }); - } - }; - - const handleUpdateDescription = async (updatedHTML: string) => { - if ( - !isUndefined(currentClassification) && - !isUndefined(handleUpdateClassification) - ) { - handleUpdateClassification({ - ...currentClassification, - description: updatedHTML, - }); - } - }; - - const handleEnableDisableClassificationClick = useCallback(() => { - if ( - !isUndefined(currentClassification) && - !isUndefined(handleUpdateClassification) - ) { - handleUpdateClassification({ - ...currentClassification, - disabled: !isClassificationDisabled, - }); - } - }, [ - currentClassification, - handleUpdateClassification, - isClassificationDisabled, - ]); - - const handleUpdateMutuallyExclusive = async (value: boolean) => { - if ( - !isUndefined(currentClassification) && - !isUndefined(handleUpdateClassification) - ) { - handleUpdateClassification({ - ...currentClassification, - mutuallyExclusive: value, - }); - } - }; - - const editDescriptionPermission = useMemo( - () => - !isVersionView && - !isClassificationDisabled && - (classificationPermissions.EditAll || - classificationPermissions.EditDescription), - [classificationPermissions, isVersionView] - ); - - const isSystemClassification = useMemo( - () => currentClassification?.provider === ProviderType.System, - [currentClassification] - ); - - const headerBadge = useMemo( - () => - isSystemClassification ? ( - } - label={capitalize(currentClassification?.provider)} - /> - ) : null, - [isSystemClassification, currentClassification] - ); - - const createPermission = useMemo( - () => - !isVersionView && - (createTagPermission || classificationPermissions.EditAll), - [classificationPermissions, createTagPermission, isVersionView] - ); - - const deletePermission = useMemo( - () => classificationPermissions.Delete && !isSystemClassification, - [classificationPermissions, isSystemClassification] - ); - - const editDisplayNamePermission = useMemo( - () => - classificationPermissions.EditAll || - classificationPermissions.EditDisplayName, - [classificationPermissions] - ); - - 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 = useMemo( - () => - getTagsTableColumn({ + showErrorToast(errMsg); + 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) + ) + ); + }, [currentVersion, tagCategoryName]); + + const isTier = useMemo( + () => currentClassification?.name === 'Tier', + [currentClassification] + ); + + const createTagPermission = useMemo( + () => + checkPermission(Operation.Create, ResourceEntity.TAG, permissions) || + classificationPermissions.EditAll, + [permissions, classificationPermissions] + ); + + const editClassificationPermission = useMemo( + () => classificationPermissions.EditAll, + [classificationPermissions] + ); + + const isClassificationDisabled = useMemo( + () => currentClassification?.disabled ?? false, + [currentClassification?.disabled] + ); + + const handleUpdateDisplayName = async (data: { + name: string; + displayName: string; + }) => { + if ( + !isUndefined(currentClassification) && + !isUndefined(handleUpdateClassification) + ) { + return handleUpdateClassification({ + ...currentClassification, + ...data, + }); + } + }; + + const handleUpdateDescription = async (updatedHTML: string) => { + if ( + !isUndefined(currentClassification) && + !isUndefined(handleUpdateClassification) + ) { + handleUpdateClassification({ + ...currentClassification, + description: updatedHTML, + }); + } + }; + + const handleEnableDisableClassificationClick = useCallback(() => { + if ( + !isUndefined(currentClassification) && + !isUndefined(handleUpdateClassification) + ) { + handleUpdateClassification({ + ...currentClassification, + disabled: !isClassificationDisabled, + }); + } + }, [ + currentClassification, + handleUpdateClassification, + isClassificationDisabled, + ]); + + const handleUpdateMutuallyExclusive = async (value: boolean) => { + if ( + !isUndefined(currentClassification) && + !isUndefined(handleUpdateClassification) + ) { + handleUpdateClassification({ + ...currentClassification, + mutuallyExclusive: value, + }); + } + }; + + const editDescriptionPermission = useMemo( + () => + !isVersionView && + !isClassificationDisabled && + (classificationPermissions.EditAll || + classificationPermissions.EditDescription), + [classificationPermissions, isVersionView] + ); + + const isSystemClassification = useMemo( + () => currentClassification?.provider === ProviderType.System, + [currentClassification] + ); + + const headerBadge = useMemo( + () => + isSystemClassification ? ( + } + label={capitalize(currentClassification?.provider)} + /> + ) : null, + [isSystemClassification, currentClassification] + ); + + const createPermission = useMemo( + () => + !isVersionView && + (createTagPermission || classificationPermissions.EditAll), + [classificationPermissions, createTagPermission, isVersionView] + ); + + const deletePermission = useMemo( + () => classificationPermissions.Delete && !isSystemClassification, + [classificationPermissions, isSystemClassification] + ); + + const editDisplayNamePermission = useMemo( + () => + classificationPermissions.EditAll || + classificationPermissions.EditDisplayName, + [classificationPermissions] + ); + + 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 = 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, - ] - ); - - 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 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]); - - useEffect(() => { - if ( - currentClassification?.fullyQualifiedName && - !deleteTags?.state && - !isAddingTag - ) { - fetchClassificationChildren(currentClassification.fullyQualifiedName); - } - }, [ - currentClassification?.fullyQualifiedName, - pageSize, - deleteTags?.state, - isAddingTag, - ]); - - return ( -
- {currentClassification && ( - - - - } - isDisabled={isClassificationDisabled} - name={name ?? currentClassification.name} - serviceName="classification" - /> - + showDisableOption, + handleEnableDisableClassificationClick, + ] + ); + + 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 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]); + + useEffect(() => { + if (currentClassification?.fullyQualifiedName && !isAddingTag) { + fetchClassificationChildren(currentClassification.fullyQualifiedName); + } + }, [currentClassification?.fullyQualifiedName, pageSize]); + + useImperativeHandle(ref, () => ({ + refreshClassificationTags() { + if (currentClassification?.fullyQualifiedName) { + fetchClassificationChildren(currentClassification.fullyQualifiedName); + } + }, + })); + + return ( +
+ {currentClassification && ( + + + + } + isDisabled={isClassificationDisabled} + name={name ?? currentClassification.name} + serviceName="classification" + /> + + + + + {createPermission && ( + + + + )} - - - {createPermission && ( - + - - )} - - - - {showManageButton && ( - - )} - - - - - )} - -
- -
+ {showManageButton && ( + + )} + + + + + )} -
- - - {t('label.mutually-exclusive')} - - - {isVersionView ? ( - <> - : - + +
+ +
+ + + {t('label.mutually-exclusive')} + + + {isVersionView ? ( + <> + : + + + ) : ( + - - ) : ( - +
+ + + , + }} + pagination={false} + rowClassName={(record) => (record.disabled ? 'opacity-60' : '')} + rowKey="id" + size="small" + /> + + {showPagination && !isTagsLoading && ( + )} - - -
, - }} - pagination={false} - rowClassName={(record) => (record.disabled ? 'opacity-60' : '')} - rowKey="id" - size="small" - /> - - {showPagination && !isTagsLoading && ( - - )} - - - ); -} + ); + } +); export default ClassificationDetails; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.interface.ts index 8d65df3a34da..84d8546b5f40 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.interface.ts @@ -19,7 +19,7 @@ export interface EntityDeleteModalProp extends HTMLAttributes { entityName: string; entityType: string; loadingState: string; - bodyText?: string; + bodyText?: string | JSX.Element; softDelete?: boolean; visible: boolean; } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.tsx index 26b63c540893..57e70c10476a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityDeleteModal/EntityDeleteModal.tsx @@ -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}>
- - {bodyText || - t('message.delete-entity-permanently', { - entityType: getTitleCase(entityType), - })} - +
+ {bodyText || ( + + } + values={{ + entityName: entityName, + }} + /> + )} +
+ {deleteMessage ?? getDeleteMessage(entityName, entityType)} + {hardDeleteMessagePostFix} + + ), type: DeleteType.HARD_DELETE, isAllowed: true, }, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/RichTextEditor/rich-text-editor.less b/openmetadata-ui/src/main/resources/ui/src/components/common/RichTextEditor/rich-text-editor.less index 70b4e06c2c71..89376745936a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/RichTextEditor/rich-text-editor.less +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/RichTextEditor/rich-text-editor.less @@ -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; diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json index 9860e022e0b0..f989006b913a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json @@ -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}} 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.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json index 76d253528799..d39f72523c67 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json @@ -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}} 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.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json index bea243357587..f04cf2a08d47 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json @@ -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}}, 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.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json index 4b8ce4650d98..1fca563f9c74 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json @@ -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}} 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.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json index dc1790238b4e..92b3af7bb72f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json @@ -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}} 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": "パイプラインの説明", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json index fbe38bae767d..ffe8f326b7e0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json @@ -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}} 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.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json index 3c64a6dfd593..323d956a9dad 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json @@ -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}} его метаданные будут навсегда удалены из OpenMetadata.", "permanently-delete-metadata-and-dependents": "Безвозвратное удаление этого {{entityName}} удалит его метаданные, а также метаданные {{dependers}} из OpenMetadata навсегда.", "personal-access-token": "Personal Access Token", "pipeline-description-message": "Описание пайплайна.", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json index 24ed528a81b5..d00b5c9081b0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json @@ -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}}将永久从 OpenMetadata 中删除其元数据", "permanently-delete-metadata-and-dependents": "永久删除此{{entityName}}将永久从 OpenMetadata 中删除其元数据以及{{dependents}}的元数据", "personal-access-token": "Personal Access Token", "pipeline-description-message": "工作流的描述信息", diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TagsPage/TagsPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TagsPage/TagsPage.tsx index fb6204d19084..b4524a8581c5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TagsPage/TagsPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TagsPage/TagsPage.tsx @@ -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(''); const [isLoading, setIsLoading] = useState(false); const [isUpdateLoading, setIsUpdateLoading] = useState(false); + const classificationDetailsRef = useRef(null); const [deleteTags, setDeleteTags] = useState({ 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 ; } - if (error) { return ( @@ -723,6 +732,7 @@ const TagsPage = () => { handleUpdateClassification={handleUpdateClassification} isAddingTag={isAddingTag} isEditClassification={isEditClassification} + ref={classificationDetailsRef} /> )} diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx index 62649cbc8490..2e5554146c04 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx @@ -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 = ({ ); +export const getEntityDeleteMessage = (entity: string, dependents: string) => { + if (dependents) { + return t('message.permanently-delete-metadata-and-dependents', { + entityName: entity, + dependents, + }); + } else { + return ( + + } + 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.