diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaSelectableList/PersonaSelectableList.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaSelectableList/PersonaSelectableList.component.tsx index b228c3ad0da..11d2b27a525 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaSelectableList/PersonaSelectableList.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaSelectableList/PersonaSelectableList.component.tsx @@ -28,6 +28,7 @@ import { getEntityName, getEntityReferenceListFromEntities, } from '../../../../utils/EntityUtils'; +import { TagRenderer } from '../../../common/TagRenderer/TagRenderer'; import { PersonaSelectableListProps } from './PersonaSelectableList.interface'; export const PersonaListItemRenderer = (props: EntityReference) => { @@ -210,6 +211,7 @@ export const PersonaSelectableList = ({ popupClassName="persona-custom-dropdown-class" ref={dropdownRef as any} style={{ width: '100%' }} + tagRender={TagRenderer} onChange={(selectedIds) => { const selectedPersonasList = selectOptions.filter((persona) => selectedIds.includes(persona.id) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx index 16dc4db3f3b..997b782504c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx @@ -21,6 +21,7 @@ import { TeamHierarchy } from '../../../../generated/entity/teams/teamHierarchy' import { getTeamsHierarchy } from '../../../../rest/teamsAPI'; import { getEntityName } from '../../../../utils/EntityUtils'; import { showErrorToast } from '../../../../utils/ToastUtils'; +import { TagRenderer } from '../../../common/TagRenderer/TagRenderer'; import { TeamsSelectableProps } from './TeamsSelectable.interface'; const TeamsSelectableNew = forwardRef( @@ -124,6 +125,7 @@ const TeamsSelectableNew = forwardRef( ref={ref as any} showCheckedStrategy={TreeSelect.SHOW_CHILD} style={{ width: '100%' }} + tagRender={TagRenderer} treeData={teamsTree} treeLine={{ showLeafIcon }} treeNodeFilterProp="title" diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileRoles/UserProfileRoles.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileRoles/UserProfileRoles.component.tsx index 58dbd869340..47deeacb5b1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileRoles/UserProfileRoles.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileRoles/UserProfileRoles.component.tsx @@ -231,7 +231,7 @@ const UserProfileRoles = ({ dropdownMatchSelectWidth={false} filterOption={handleSearchFilterOption} loading={isLoading} - maxTagCount={4} + maxTagCount={3} maxTagPlaceholder={(omittedValues) => ( {t('label.plus-count-more', { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileTeams/UserProfileTeams.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileTeams/UserProfileTeams.component.tsx index c1a8734fb2c..bd478789d26 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileTeams/UserProfileTeams.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileTeams/UserProfileTeams.component.tsx @@ -151,7 +151,7 @@ const UserProfileTeams = ({ {icon} - + {getEntityName(item)} @@ -73,7 +75,7 @@ const Chip = ({ return ( {(isExpanded ? data : data.slice(0, USER_DATA_SIZE)).map(getChipElement)} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/Chip/chip.less b/openmetadata-ui/src/main/resources/ui/src/components/common/Chip/chip.less index b85d2bd309e..ead02c0a216 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/Chip/chip.less +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/Chip/chip.less @@ -11,26 +11,31 @@ * limitations under the License. */ @import (reference) url('../../../styles/variables.less'); +.chip-container { + width: 180px; -.chip-tag-link { - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: @text-color; - &:hover { - color: @blue-9; - text-decoration: none; + .chip-tag-link { + font-weight: 400; + font-size: 14px; + line-height: 20px; + color: @text-color; + &:hover { + color: @blue-9; + text-decoration: none; + } + overflow: hidden; + text-overflow: ellipsis; } -} -.chip-text { - color: @blue-9; - &:hover { + .chip-text { color: @blue-9; - } - &::after { - animation: none !important; - display: none !important; + &:hover { + color: @blue-9; + } + &::after { + animation: none !important; + display: none !important; + } } } .no-data-chip-placeholder { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainLabel/DomainLabelNew.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainLabel/DomainLabelNew.tsx index 702df444410..04eaf156a6d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainLabel/DomainLabelNew.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainLabel/DomainLabelNew.tsx @@ -134,7 +134,8 @@ export const DomainLabelNew = ({ domain, domainDisplayName, showDomainHeading, - 'chip-tag-link' + 'chip-tag-link', + true )} {inheritedIcon && (
{inheritedIcon}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableList/DomainSelectableListNew.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableList/DomainSelectableListNew.component.tsx index 18797b144d2..e7c0171c461 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableList/DomainSelectableListNew.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableList/DomainSelectableListNew.component.tsx @@ -91,7 +91,7 @@ const DomainSelectableListNew = ({ } }; - const [popoverHeight, setPopoverHeight] = useState(136); + const [popoverHeight, setPopoverHeight] = useState(156); const dropdownRef = useRef(null); useEffect(() => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableTree/DomainSelectableTreeNew.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableTree/DomainSelectableTreeNew.tsx index ccb5e51d42d..ec2270d7dac 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableTree/DomainSelectableTreeNew.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/DomainSelectableTree/DomainSelectableTreeNew.tsx @@ -37,6 +37,7 @@ import { getEntityReferenceFromEntity } from '../../../utils/EntityUtils'; import { findItemByFqn } from '../../../utils/GlossaryUtils'; import { showErrorToast } from '../../../utils/ToastUtils'; import Loader from '../Loader/Loader'; +import { TagRenderer } from '../TagRenderer/TagRenderer'; import './domain-selectable.less'; import { DomainSelectableTreeProps, @@ -227,7 +228,7 @@ const DomainSelectablTreeNew: FC = ({ className="custom-domain-edit-select" dropdownRender={() => treeContent} dropdownStyle={{ maxHeight: '200px' }} - maxTagCount={2} + maxTagCount={3} maxTagPlaceholder={(omittedValues) => ( {t('label.plus-count-more', { count: omittedValues.length })} @@ -241,7 +242,7 @@ const DomainSelectablTreeNew: FC = ({ placeholder="Select a domain" popupClassName="domain-custom-dropdown-class" ref={dropdownRef as any} - style={{}} + tagRender={TagRenderer} value={ selectedDomains ?.map((domain) => domain.fullyQualifiedName) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/PopOverCard/EntityPopOverCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/PopOverCard/EntityPopOverCard.tsx index 180bcaa2cec..7e628e3360b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/PopOverCard/EntityPopOverCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/PopOverCard/EntityPopOverCard.tsx @@ -262,7 +262,7 @@ const EntityPopOverCard: FC = ({ }) => { return ( { + const mockOnClose = jest.fn(); + const defaultProps = { + label: 'Test Label', + value: 'test-value', + closable: true, + onClose: mockOnClose, + disabled: false, + onMouseDown: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should render the label', () => { + render(); + + expect(screen.getByText('Test Label')).toBeInTheDocument(); + }); + + it('should truncate long labels and add ellipsis', () => { + const longLabel = 'test persona test test persona 5'; + render(); + + expect(screen.getByText('test persona...')).toBeInTheDocument(); + expect(screen.getByTitle(longLabel)).toBeInTheDocument(); + }); + + it('should render close button when closable is true', () => { + render(); + + expect(screen.getByRole('button')).toBeInTheDocument(); + }); + + it('should call onClose when close button is clicked', () => { + render(); + + const closeButton = screen.getByRole('button'); + fireEvent.click(closeButton); + + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/TagRenderer/TagRenderer.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/TagRenderer/TagRenderer.tsx new file mode 100644 index 00000000000..7465ef5d086 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/TagRenderer/TagRenderer.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2025 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 { CloseOutlined } from '@ant-design/icons'; +import type { CustomTagProps } from 'rc-select/lib/BaseSelect'; +import React from 'react'; + +export const TagRenderer = (props: CustomTagProps) => { + const { label, closable, onClose } = props; + const displayLabel = + typeof label === 'string' && label.length > 12 + ? `${label.substring(0, 12)}...` + : label; + + return ( + + {displayLabel} + {closable && ( + + )} + + ); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx index a356b1ccff1..61b4d97d346 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx @@ -229,23 +229,39 @@ export const renderDomainLink = ( domain: EntityReference, domainDisplayName: ReactNode, showDomainHeading: boolean, - textClassName?: string -) => ( - - - {isUndefined(domainDisplayName) - ? getEntityName(domain) - : domainDisplayName} - - -); + textClassName?: string, + trimLink?: boolean +) => { + const displayName = isUndefined(domainDisplayName) + ? getEntityName(domain) + : domainDisplayName; + + return ( + + + {trimLink ? ( + + {displayName} + + ) : ( + <>{displayName} + )} + + + ); +}; export const initializeDomainEntityRef = ( domains: EntityReference[],