mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-17 03:38:18 +00:00
✨ Feat : Show entity card in popover on hover of entity links in activity feed (#5526)
* ✨ Feat : Show entity card in popover on hover of entity links in activity feed
* Style Changes
This commit is contained in:
parent
b1fbbe737f
commit
acc6b92505
@ -1,14 +1,14 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_10007_14856)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.03841 2.87877C4.83519 2.70366 4.8855 2.37817 5.14049 2.29486C5.72618 2.1035 6.35123 2 7 2C10.3084 2 13 4.69156 13 8C13 11.3084 10.3084 14 7 14C3.69156 14 1 11.3084 1 8C1 6.93759 1.27755 5.93879 1.76395 5.07231C1.87427 4.87577 2.14026 4.84902 2.2997 5.00831V5.00831C2.41698 5.12548 2.43682 5.30744 2.35684 5.45265C1.94028 6.20891 1.70313 7.07728 1.70313 8C1.70313 10.9207 4.07928 13.2969 7 13.2969C9.92072 13.2969 12.2969 10.9207 12.2969 8C12.2969 5.07928 9.92072 2.70313 7 2.70313C6.44331 2.70313 5.90639 2.78945 5.40195 2.94941C5.27636 2.98924 5.13822 2.96477 5.03841 2.87877V2.87877Z" fill="white" stroke="white" stroke-width="0.1"/>
|
||||
<path d="M4.9454 4.05714H3.65968V5.34286C3.65968 5.48429 3.54397 5.6 3.40254 5.6C3.26111 5.6 3.1454 5.48429 3.1454 5.34286V4.05714H1.85968C1.71825 4.05714 1.60254 3.94143 1.60254 3.8C1.60254 3.65857 1.71825 3.54286 1.85968 3.54286H3.1454V2.25714C3.1454 2.11571 3.26111 2 3.40254 2C3.54397 2 3.65968 2.11571 3.65968 2.25714V3.54286H4.9454C5.08682 3.54286 5.20254 3.65857 5.20254 3.8C5.20254 3.94143 5.08682 4.05714 4.9454 4.05714Z" fill="white" stroke="white" stroke-width="0.3"/>
|
||||
<path d="M8.75563 7.27118C8.99092 7.03589 9.30376 6.90625 9.63655 6.90625C9.96925 6.90625 10.2821 7.03589 10.5177 7.27136C10.655 7.4086 10.8775 7.40851 11.0148 7.27118C11.152 7.13385 11.1519 6.91119 11.0146 6.77396C10.6465 6.40591 10.157 6.20312 9.63655 6.20312C9.11598 6.20312 8.62654 6.40591 8.25841 6.77396L8.25822 6.77414C8.1209 6.91147 8.12099 7.13394 8.25832 7.27127C8.39565 7.4086 8.6183 7.40842 8.75563 7.27118V7.27118Z" fill="white" stroke="white" stroke-width="0.1"/>
|
||||
<path d="M3.4821 7.27118C3.71748 7.03589 4.03032 6.90625 4.36302 6.90625C4.69582 6.90625 5.00865 7.03589 5.24422 7.27136C5.38155 7.4086 5.60411 7.40851 5.74135 7.27118C5.87859 7.13385 5.87849 6.91119 5.74117 6.77396C5.37303 6.40591 4.88359 6.20312 4.36302 6.20312C3.84254 6.20312 3.3531 6.40591 2.98497 6.77396L2.98479 6.77414C2.84746 6.91147 2.84755 7.13394 2.98488 7.27127C3.12221 7.4086 3.34486 7.40842 3.4821 7.27118Z" fill="white" stroke="white" stroke-width="0.1"/>
|
||||
<path d="M10.2901 8.29297H3.70486C3.53515 8.29297 3.39746 8.43058 3.39746 8.60037C3.39746 10.5886 5.00922 12.2004 6.99746 12.2004C8.9857 12.2004 10.5975 10.5886 10.5975 8.60037C10.5975 8.43058 10.4598 8.29297 10.2901 8.29297V8.29297ZM6.99746 11.5856C5.44102 11.5856 4.17964 10.4017 4.02779 8.90777H9.96713C9.81528 10.4016 8.55406 11.5856 6.99746 11.5856Z" fill="white" stroke="white" stroke-width="0.1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.03841 2.87877C4.83519 2.70366 4.8855 2.37817 5.14049 2.29486C5.72618 2.1035 6.35123 2 7 2C10.3084 2 13 4.69156 13 8C13 11.3084 10.3084 14 7 14C3.69156 14 1 11.3084 1 8C1 6.93759 1.27755 5.93879 1.76395 5.07231C1.87427 4.87577 2.14026 4.84902 2.2997 5.00831V5.00831C2.41698 5.12548 2.43682 5.30744 2.35684 5.45265C1.94028 6.20891 1.70313 7.07728 1.70313 8C1.70313 10.9207 4.07928 13.2969 7 13.2969C9.92072 13.2969 12.2969 10.9207 12.2969 8C12.2969 5.07928 9.92072 2.70313 7 2.70313C6.44331 2.70313 5.90639 2.78945 5.40195 2.94941C5.27636 2.98924 5.13822 2.96477 5.03841 2.87877V2.87877Z" fill="#37352f" stroke="#37352f" stroke-width="0.1"/>
|
||||
<path d="M4.9454 4.05714H3.65968V5.34286C3.65968 5.48429 3.54397 5.6 3.40254 5.6C3.26111 5.6 3.1454 5.48429 3.1454 5.34286V4.05714H1.85968C1.71825 4.05714 1.60254 3.94143 1.60254 3.8C1.60254 3.65857 1.71825 3.54286 1.85968 3.54286H3.1454V2.25714C3.1454 2.11571 3.26111 2 3.40254 2C3.54397 2 3.65968 2.11571 3.65968 2.25714V3.54286H4.9454C5.08682 3.54286 5.20254 3.65857 5.20254 3.8C5.20254 3.94143 5.08682 4.05714 4.9454 4.05714Z" fill="#37352f" stroke="#37352f" stroke-width="0.3"/>
|
||||
<path d="M8.75563 7.27118C8.99092 7.03589 9.30376 6.90625 9.63655 6.90625C9.96925 6.90625 10.2821 7.03589 10.5177 7.27136C10.655 7.4086 10.8775 7.40851 11.0148 7.27118C11.152 7.13385 11.1519 6.91119 11.0146 6.77396C10.6465 6.40591 10.157 6.20312 9.63655 6.20312C9.11598 6.20312 8.62654 6.40591 8.25841 6.77396L8.25822 6.77414C8.1209 6.91147 8.12099 7.13394 8.25832 7.27127C8.39565 7.4086 8.6183 7.40842 8.75563 7.27118V7.27118Z" fill="#37352f" stroke="#37352f" stroke-width="0.1"/>
|
||||
<path d="M3.4821 7.27118C3.71748 7.03589 4.03032 6.90625 4.36302 6.90625C4.69582 6.90625 5.00865 7.03589 5.24422 7.27136C5.38155 7.4086 5.60411 7.40851 5.74135 7.27118C5.87859 7.13385 5.87849 6.91119 5.74117 6.77396C5.37303 6.40591 4.88359 6.20312 4.36302 6.20312C3.84254 6.20312 3.3531 6.40591 2.98497 6.77396L2.98479 6.77414C2.84746 6.91147 2.84755 7.13394 2.98488 7.27127C3.12221 7.4086 3.34486 7.40842 3.4821 7.27118Z" fill="#37352f" stroke="#37352f" stroke-width="0.1"/>
|
||||
<path d="M10.2901 8.29297H3.70486C3.53515 8.29297 3.39746 8.43058 3.39746 8.60037C3.39746 10.5886 5.00922 12.2004 6.99746 12.2004C8.9857 12.2004 10.5975 10.5886 10.5975 8.60037C10.5975 8.43058 10.4598 8.29297 10.2901 8.29297V8.29297ZM6.99746 11.5856C5.44102 11.5856 4.17964 10.4017 4.02779 8.90777H9.96713C9.81528 10.4016 8.55406 11.5856 6.99746 11.5856Z" fill="#37352f" stroke="#37352f" stroke-width="0.1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_10007_14856">
|
||||
<rect width="14" height="14" fill="white" transform="translate(0 0.986328)"/>
|
||||
<rect width="14" height="14" fill="#37352f" transform="translate(0 0.986328)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.8 KiB |
@ -1,3 +1,3 @@
|
||||
<svg width="12" height="10" viewBox="0 0 12 10" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.25 9.82969C11.1105 9.82969 10.979 9.75192 10.9146 9.623C10.2203 8.23831 9.56287 6.92766 6 6.84259V9.45576C6 9.6044 5.91178 9.73874 5.77547 9.79828C5.63916 9.85783 5.47997 9.83147 5.37047 9.73032L0.495469 5.24308C0.418594 5.17268 0.375 5.07294 0.375 4.96851C0.375 4.86409 0.418594 4.76435 0.495469 4.69386L5.37047 0.206615C5.47997 0.105465 5.63963 0.0795694 5.77547 0.138651C5.91178 0.198294 6 0.332631 6 0.481271V3.10322C11.1939 3.23176 11.625 6.05779 11.625 9.45576C11.625 9.62917 11.5053 9.77968 11.3361 9.81988C11.3075 9.82642 11.2786 9.82969 11.25 9.82969ZM1.30294 4.96851L5.25 8.60159V6.46426C5.25 6.25757 5.41772 6.09033 5.625 6.09033C8.7345 6.09033 10.0583 6.9558 10.8351 7.99619C10.6597 5.44435 9.76762 3.8467 5.625 3.8467C5.41772 3.8467 5.25 3.67946 5.25 3.47277V1.33544L1.30294 4.96851Z" fill="#ffffff"/>
|
||||
<svg width="12" height="10" viewBox="0 0 12 10" fill="#37352f" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.25 9.82969C11.1105 9.82969 10.979 9.75192 10.9146 9.623C10.2203 8.23831 9.56287 6.92766 6 6.84259V9.45576C6 9.6044 5.91178 9.73874 5.77547 9.79828C5.63916 9.85783 5.47997 9.83147 5.37047 9.73032L0.495469 5.24308C0.418594 5.17268 0.375 5.07294 0.375 4.96851C0.375 4.86409 0.418594 4.76435 0.495469 4.69386L5.37047 0.206615C5.47997 0.105465 5.63963 0.0795694 5.77547 0.138651C5.91178 0.198294 6 0.332631 6 0.481271V3.10322C11.1939 3.23176 11.625 6.05779 11.625 9.45576C11.625 9.62917 11.5053 9.77968 11.3361 9.81988C11.3075 9.82642 11.2786 9.82969 11.25 9.82969ZM1.30294 4.96851L5.25 8.60159V6.46426C5.25 6.25757 5.41772 6.09033 5.625 6.09033C8.7345 6.09033 10.0583 6.9558 10.8351 7.99619C10.6597 5.44435 9.76762 3.8467 5.625 3.8467C5.41772 3.8467 5.25 3.67946 5.25 3.47277V1.33544L1.30294 4.96851Z" fill="#37352f"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 934 B After Width: | Height: | Size: 934 B |
@ -1,6 +1,6 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.4922 3.40625H9.73438V3.05469C9.73438 2.47313 9.26124 2 8.67969 2H5.86719C5.28563 2 4.8125 2.47313 4.8125 3.05469V3.40625H3.05469C2.47313 3.40625 2 3.87938 2 4.46094C2 4.928 2.30527 5.32487 2.72668 5.46315L3.35375 13.0329C3.39891 13.5752 3.86059 14 4.40478 14H10.1421C10.6863 14 11.148 13.5752 11.1932 13.0327L11.8202 5.46312C12.2416 5.32487 12.5469 4.928 12.5469 4.46094C12.5469 3.87938 12.0737 3.40625 11.4922 3.40625ZM5.51562 3.05469C5.51562 2.86084 5.67334 2.70312 5.86719 2.70312H8.67969C8.87354 2.70312 9.03125 2.86084 9.03125 3.05469V3.40625H5.51562V3.05469ZM10.4924 12.9745C10.4774 13.1553 10.3235 13.2969 10.1421 13.2969H4.40478C4.2234 13.2969 4.06951 13.1553 4.05448 12.9747L3.43658 5.51562H11.1103L10.4924 12.9745ZM11.4922 4.8125H3.05469C2.86084 4.8125 2.70312 4.65479 2.70312 4.46094C2.70312 4.26709 2.86084 4.10938 3.05469 4.10938H11.4922C11.686 4.10938 11.8438 4.26709 11.8438 4.46094C11.8438 4.65479 11.686 4.8125 11.4922 4.8125Z" fill="white"/>
|
||||
<path d="M5.99251 12.2205L5.64095 6.54857C5.62893 6.35477 5.46118 6.20737 5.26832 6.21944C5.07451 6.23146 4.92716 6.39829 4.93916 6.59207L5.29072 12.264C5.30228 12.4504 5.45706 12.5938 5.64128 12.5938C5.84488 12.5938 6.005 12.4223 5.99251 12.2205Z" fill="white"/>
|
||||
<path d="M7.39941 6.21875C7.20526 6.21875 7.04785 6.37616 7.04785 6.57031V12.2422C7.04785 12.4363 7.20526 12.5938 7.39941 12.5938C7.59357 12.5938 7.75098 12.4363 7.75098 12.2422V6.57031C7.75098 6.37616 7.59357 6.21875 7.39941 6.21875Z" fill="white"/>
|
||||
<path d="M9.53054 6.21944C9.33718 6.20741 9.16991 6.35476 9.15791 6.54857L8.80635 12.2204C8.79437 12.4142 8.94172 12.581 9.1355 12.5931C9.3294 12.6051 9.49613 12.4576 9.50813 12.2639L9.85969 6.59207C9.87169 6.39826 9.72434 6.23144 9.53054 6.21944Z" fill="white"/>
|
||||
<path d="M11.4922 3.40625H9.73438V3.05469C9.73438 2.47313 9.26124 2 8.67969 2H5.86719C5.28563 2 4.8125 2.47313 4.8125 3.05469V3.40625H3.05469C2.47313 3.40625 2 3.87938 2 4.46094C2 4.928 2.30527 5.32487 2.72668 5.46315L3.35375 13.0329C3.39891 13.5752 3.86059 14 4.40478 14H10.1421C10.6863 14 11.148 13.5752 11.1932 13.0327L11.8202 5.46312C12.2416 5.32487 12.5469 4.928 12.5469 4.46094C12.5469 3.87938 12.0737 3.40625 11.4922 3.40625ZM5.51562 3.05469C5.51562 2.86084 5.67334 2.70312 5.86719 2.70312H8.67969C8.87354 2.70312 9.03125 2.86084 9.03125 3.05469V3.40625H5.51562V3.05469ZM10.4924 12.9745C10.4774 13.1553 10.3235 13.2969 10.1421 13.2969H4.40478C4.2234 13.2969 4.06951 13.1553 4.05448 12.9747L3.43658 5.51562H11.1103L10.4924 12.9745ZM11.4922 4.8125H3.05469C2.86084 4.8125 2.70312 4.65479 2.70312 4.46094C2.70312 4.26709 2.86084 4.10938 3.05469 4.10938H11.4922C11.686 4.10938 11.8438 4.26709 11.8438 4.46094C11.8438 4.65479 11.686 4.8125 11.4922 4.8125Z" fill="#37352f"/>
|
||||
<path d="M5.99251 12.2205L5.64095 6.54857C5.62893 6.35477 5.46118 6.20737 5.26832 6.21944C5.07451 6.23146 4.92716 6.39829 4.93916 6.59207L5.29072 12.264C5.30228 12.4504 5.45706 12.5938 5.64128 12.5938C5.84488 12.5938 6.005 12.4223 5.99251 12.2205Z" fill="#37352f"/>
|
||||
<path d="M7.39941 6.21875C7.20526 6.21875 7.04785 6.37616 7.04785 6.57031V12.2422C7.04785 12.4363 7.20526 12.5938 7.39941 12.5938C7.59357 12.5938 7.75098 12.4363 7.75098 12.2422V6.57031C7.75098 6.37616 7.59357 6.21875 7.39941 6.21875Z" fill="#37352f"/>
|
||||
<path d="M9.53054 6.21944C9.33718 6.20741 9.16991 6.35476 9.15791 6.54857L8.80635 12.2204C8.79437 12.4142 8.94172 12.581 9.1355 12.5931C9.3294 12.6051 9.49613 12.4576 9.50813 12.2639L9.85969 6.59207C9.87169 6.39826 9.72434 6.23144 9.53054 6.21944Z" fill="#37352f"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -26,6 +26,7 @@ import {
|
||||
getEntityFQN,
|
||||
getEntityType,
|
||||
} from '../../../utils/FeedUtils';
|
||||
import UserPopOverCard from '../../common/PopOverCard/UserPopOverCard';
|
||||
import ProfilePicture from '../../common/ProfilePicture/ProfilePicture';
|
||||
import { ActivityFeedCardProp } from './ActivityFeedCard.interface';
|
||||
import FeedCardBody from './FeedCardBody/FeedCardBody';
|
||||
@ -117,11 +118,10 @@ const ActivityFeedCard: FC<ActivityFeedCardProp> = ({
|
||||
}, [feed]);
|
||||
|
||||
return (
|
||||
<div className={classNames(className)}>
|
||||
<div className={classNames(className, 'hover:tw-bg-gray-100')}>
|
||||
<Popover
|
||||
destroyTooltipOnHide
|
||||
align={{ targetOffset: [0, -20] }}
|
||||
color="#434850"
|
||||
content={
|
||||
<PopoverContent
|
||||
isAuthor={isAuthor}
|
||||
@ -142,11 +142,11 @@ const ActivityFeedCard: FC<ActivityFeedCardProp> = ({
|
||||
zIndex={9999}
|
||||
onVisibleChange={handleVisibleChange}>
|
||||
<div className="tw-flex">
|
||||
<Popover content={<></>} trigger="click">
|
||||
<UserPopOverCard userName={feedDetail.from}>
|
||||
<span className="tw-cursor-pointer" data-testid="authorAvatar">
|
||||
<ProfilePicture id="" name={feedDetail.from} width="28" />
|
||||
<ProfilePicture id="" name={feedDetail.from} width="32" />
|
||||
</span>
|
||||
</Popover>
|
||||
</UserPopOverCard>
|
||||
<div className="tw-flex tw-flex-col">
|
||||
<FeedCardHeader
|
||||
createdBy={feedDetail.from}
|
||||
|
@ -27,7 +27,7 @@ const FeedCardBody: FC<FeedBodyProp> = ({
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classNames('tw-group', className)}>
|
||||
<div className="tw-mt-2">
|
||||
<div className="tw-mt-0.5 feed-meesage">
|
||||
<RichTextEditorPreviewer
|
||||
className="activity-feed-card-text"
|
||||
enableSeeMoreVariant={false}
|
||||
|
@ -40,6 +40,8 @@ jest.mock('../../../../utils/CommonUtils', () => ({
|
||||
|
||||
jest.mock('../../../../utils/TableUtils', () => ({
|
||||
getEntityLink: jest.fn(),
|
||||
getTierTags: jest.fn(),
|
||||
getTagsWithoutTier: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../utils/TimeUtils', () => ({
|
||||
|
@ -11,36 +11,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { isUndefined } from 'lodash';
|
||||
import React, { FC, Fragment, useState } from 'react';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import React, { FC, Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AppState from '../../../../AppState';
|
||||
import { getUserByName } from '../../../../axiosAPIs/userAPI';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../../../constants/char.constants';
|
||||
import { getUserPath, TERM_ADMIN } from '../../../../constants/constants';
|
||||
import {
|
||||
EntityType,
|
||||
FqnPart,
|
||||
TabSpecificField,
|
||||
} from '../../../../enums/entity.enum';
|
||||
import { User } from '../../../../generated/entity/teams/user';
|
||||
import { EntityReference } from '../../../../generated/type/entityReference';
|
||||
import {
|
||||
getEntityName,
|
||||
getNonDeletedTeams,
|
||||
getPartialNameFromFQN,
|
||||
getPartialNameFromTableFQN,
|
||||
} from '../../../../utils/CommonUtils';
|
||||
import { getEntityFieldDisplay } from '../../../../utils/FeedUtils';
|
||||
import SVGIcons, { Icons } from '../../../../utils/SvgUtils';
|
||||
import { getEntityLink } from '../../../../utils/TableUtils';
|
||||
import { getDayTimeByTimeStamp } from '../../../../utils/TimeUtils';
|
||||
import { Button } from '../../../buttons/Button/Button';
|
||||
import PopOver from '../../../common/popover/PopOver';
|
||||
import ProfilePicture from '../../../common/ProfilePicture/ProfilePicture';
|
||||
import Loader from '../../../Loader/Loader';
|
||||
import EntityPopOverCard from '../../../common/PopOverCard/EntityPopOverCard';
|
||||
import UserPopOverCard from '../../../common/PopOverCard/UserPopOverCard';
|
||||
import { FeedHeaderProp } from '../ActivityFeedCard.interface';
|
||||
import './FeedCardHeader.style.css';
|
||||
|
||||
@ -53,122 +43,6 @@ const FeedCardHeader: FC<FeedHeaderProp> = ({
|
||||
entityField,
|
||||
isEntityFeed,
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
const [userData, setUserData] = useState<User>({} as User);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isError, setIsError] = useState(false);
|
||||
|
||||
const onClickHandler = () => {
|
||||
getUserByName(createdBy, 'profile,roles,teams,follows,owns')
|
||||
.then((res: AxiosResponse) => {
|
||||
setUserData(res.data);
|
||||
})
|
||||
.catch(() => {
|
||||
setIsError(true);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
const onTitleClickHandler = (path: string) => {
|
||||
history.push(path);
|
||||
};
|
||||
|
||||
const getUserData = () => {
|
||||
const name = userData.name ?? '';
|
||||
const displayName = getEntityName(userData as unknown as EntityReference);
|
||||
const teams = getNonDeletedTeams(userData.teams ?? []);
|
||||
const roles = userData.roles;
|
||||
const isAdmin = userData?.isAdmin;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{isError ? (
|
||||
<p>Error while getting user data.</p>
|
||||
) : (
|
||||
<div>
|
||||
{isLoading ? (
|
||||
<Loader size="small" />
|
||||
) : (
|
||||
<div>
|
||||
<div className="tw-flex">
|
||||
<div className="tw-mr-2">
|
||||
<ProfilePicture id="" name={createdBy} width="24" />
|
||||
</div>
|
||||
<div className="tw-self-center">
|
||||
<Button
|
||||
style={{ padding: '0px' }}
|
||||
theme="primary"
|
||||
variant="link"
|
||||
onClick={() => onTitleClickHandler(getUserPath(name))}>
|
||||
<span className="tw-font-medium tw-mr-2">
|
||||
{displayName}
|
||||
</span>
|
||||
</Button>
|
||||
{displayName !== name ? (
|
||||
<span className="tw-text-grey-muted">{name}</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tw-text-left">
|
||||
{teams?.length || roles?.length ? (
|
||||
<hr className="tw-my-2 tw--mx-3" />
|
||||
) : null}
|
||||
{teams?.length ? (
|
||||
<p className="tw-mt-2">
|
||||
<SVGIcons
|
||||
alt="icon"
|
||||
className="tw-w-4"
|
||||
icon={Icons.TEAMS_GREY}
|
||||
/>
|
||||
<span className="tw-mr-2 tw-ml-1 tw-align-middle tw-font-medium">
|
||||
Teams
|
||||
</span>
|
||||
<span className="tw-flex tw-flex-wrap tw-mt-1">
|
||||
{teams.map((team, i) => (
|
||||
<span
|
||||
className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs"
|
||||
key={i}>
|
||||
{team?.displayName ?? team?.name}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
</p>
|
||||
) : null}
|
||||
{roles?.length ? (
|
||||
<p className="tw-mt-2">
|
||||
<SVGIcons
|
||||
alt="icon"
|
||||
className="tw-w-4"
|
||||
icon={Icons.USERS}
|
||||
/>
|
||||
<span className="tw-mr-2 tw-ml-1 tw-align-middle tw-font-medium">
|
||||
Roles
|
||||
</span>
|
||||
<span className="tw-flex tw-flex-wrap tw-mt-1">
|
||||
{isAdmin && (
|
||||
<span className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs">
|
||||
{TERM_ADMIN}
|
||||
</span>
|
||||
)}
|
||||
{roles.map((role, i) => (
|
||||
<span
|
||||
className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs"
|
||||
key={i}>
|
||||
{role?.displayName ?? role?.name}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const entityDisplayName = () => {
|
||||
let displayName;
|
||||
if (entityType === EntityType.TABLE) {
|
||||
@ -186,6 +60,7 @@ const FeedCardHeader: FC<FeedHeaderProp> = ({
|
||||
EntityType.MESSAGING_SERVICE,
|
||||
EntityType.PIPELINE_SERVICE,
|
||||
EntityType.TYPE,
|
||||
EntityType.MLMODEL,
|
||||
].includes(entityType as EntityType)
|
||||
) {
|
||||
displayName = getPartialNameFromFQN(entityFQN, ['service']);
|
||||
@ -238,14 +113,11 @@ const FeedCardHeader: FC<FeedHeaderProp> = ({
|
||||
<span data-testid="entityType">{entityType} </span>
|
||||
<Link data-testid="entitylink" to={prepareFeedLink()}>
|
||||
<button className="tw-text-info" disabled={AppState.isTourOpen}>
|
||||
<PopOver
|
||||
disabled={AppState.isTourOpen}
|
||||
position="top"
|
||||
size="small"
|
||||
title={entityFQN}
|
||||
trigger="mouseenter">
|
||||
<EntityPopOverCard
|
||||
entityFQN={entityFQN}
|
||||
entityType={entityType}>
|
||||
<span>{entityDisplayName()}</span>
|
||||
</PopOver>
|
||||
</EntityPopOverCard>
|
||||
</button>
|
||||
</Link>
|
||||
</Fragment>
|
||||
@ -260,18 +132,10 @@ const FeedCardHeader: FC<FeedHeaderProp> = ({
|
||||
return (
|
||||
<div className={classNames('tw-flex', className)}>
|
||||
<div className="tw-flex tw-m-0 tw-pl-2 tw-leading-4">
|
||||
<PopOver
|
||||
hideDelay={500}
|
||||
html={getUserData()}
|
||||
position="top"
|
||||
theme="light"
|
||||
trigger="click">
|
||||
<span
|
||||
className="thread-author tw-cursor-pointer"
|
||||
onClick={onClickHandler}>
|
||||
{createdBy}
|
||||
</span>
|
||||
</PopOver>
|
||||
<UserPopOverCard userName={createdBy}>
|
||||
<span className="thread-author tw-cursor-pointer">{createdBy}</span>
|
||||
</UserPopOverCard>
|
||||
|
||||
{getFeedLinkElement()}
|
||||
<span
|
||||
className="tw-text-grey-muted tw-pl-2 tw-text-xs tw--mb-0.5"
|
||||
|
@ -102,6 +102,7 @@ const FeedListBody: FC<FeedListBodyProp> = ({
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="ant-card-feed"
|
||||
key={`${index} - card`}
|
||||
style={{
|
||||
border: '1px rgb(221, 227, 234) solid',
|
||||
|
@ -66,6 +66,7 @@ const ActivityThreadList: FC<ActivityThreadListProp> = ({
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
<Card
|
||||
className="ant-card-feed"
|
||||
key={`${index} - card`}
|
||||
style={{
|
||||
border: '1px rgb(221, 227, 234) solid',
|
||||
|
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Popover } from 'antd';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { EntityTags } from 'Models';
|
||||
import React, { FC, HTMLAttributes, useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AppState from '../../../AppState';
|
||||
import { getDashboardByFqn } from '../../../axiosAPIs/dashboardAPI';
|
||||
import {
|
||||
getDatabaseDetailsByFQN,
|
||||
getDatabaseSchemaDetailsByFQN,
|
||||
} from '../../../axiosAPIs/databaseAPI';
|
||||
import { getMlModelByFQN } from '../../../axiosAPIs/mlModelAPI';
|
||||
import { getPipelineByFqn } from '../../../axiosAPIs/pipelineAPI';
|
||||
import { getTableDetailsByFQN } from '../../../axiosAPIs/tableAPI';
|
||||
import { getTopicByFqn } from '../../../axiosAPIs/topicsAPI';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
|
||||
import { EntityType } from '../../../enums/entity.enum';
|
||||
import { Dashboard } from '../../../generated/entity/data/dashboard';
|
||||
import { Database } from '../../../generated/entity/data/database';
|
||||
import { DatabaseSchema } from '../../../generated/entity/data/databaseSchema';
|
||||
import { Mlmodel } from '../../../generated/entity/data/mlmodel';
|
||||
import { Pipeline } from '../../../generated/entity/data/pipeline';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { Topic } from '../../../generated/entity/data/topic';
|
||||
import { getEntityName } from '../../../utils/CommonUtils';
|
||||
import {
|
||||
getEntityLink,
|
||||
getTagsWithoutTier,
|
||||
getTierTags,
|
||||
} from '../../../utils/TableUtils';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import ProfilePicture from '../ProfilePicture/ProfilePicture';
|
||||
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
||||
|
||||
export type EntityData = Table &
|
||||
Topic &
|
||||
Dashboard &
|
||||
Pipeline &
|
||||
Mlmodel &
|
||||
Database &
|
||||
DatabaseSchema;
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
entityType: string;
|
||||
entityFQN: string;
|
||||
}
|
||||
|
||||
const EntityPopOverCard: FC<Props> = ({ children, entityType, entityFQN }) => {
|
||||
const [entityData, setEntityData] = useState<EntityData>({} as EntityData);
|
||||
|
||||
const entityTier = useMemo(() => {
|
||||
const tierFQN = getTierTags(entityData.tags || [])?.tagFQN;
|
||||
|
||||
return tierFQN?.split(FQN_SEPARATOR_CHAR)[1];
|
||||
}, [entityData.tags]);
|
||||
|
||||
const entityTags = useMemo(() => {
|
||||
const tags: EntityTags[] = getTagsWithoutTier(entityData.tags || []) || [];
|
||||
|
||||
return tags.map((tag) => `#${tag.tagFQN}`);
|
||||
}, [entityData.tags]);
|
||||
|
||||
const getData = () => {
|
||||
const fields = 'tags,owner';
|
||||
|
||||
switch (entityType) {
|
||||
case EntityType.TABLE:
|
||||
getTableDetailsByFQN(entityFQN, fields)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.TOPIC:
|
||||
getTopicByFqn(entityFQN, fields)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.DASHBOARD:
|
||||
getDashboardByFqn(entityFQN, fields)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.PIPELINE:
|
||||
getPipelineByFqn(entityFQN, fields)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.MLMODEL:
|
||||
getMlModelByFQN(entityFQN, fields)
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.DATABASE:
|
||||
getDatabaseDetailsByFQN(entityFQN, 'owner')
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
case EntityType.DATABASE_SCHEMA:
|
||||
getDatabaseSchemaDetailsByFQN(entityFQN, 'owner')
|
||||
.then((res: AxiosResponse) => {
|
||||
setEntityData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const PopoverTitle = () => {
|
||||
return (
|
||||
<Link data-testid="entitylink" to={getEntityLink(entityType, entityFQN)}>
|
||||
<button className="tw-text-info" disabled={AppState.isTourOpen}>
|
||||
<span>{entityFQN}</span>
|
||||
</button>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const PopoverContent = () => {
|
||||
return (
|
||||
<div className="tw-w-80">
|
||||
<div className="tw-flex">
|
||||
<div data-testid="owner">
|
||||
<span>
|
||||
{entityData.owner ? (
|
||||
<span className="tw-flex">
|
||||
<span className="tw-text-grey-muted">Owner:</span>{' '}
|
||||
<span className="tw-flex tw-ml-1">
|
||||
<ProfilePicture
|
||||
displayName={getEntityName(entityData.owner)}
|
||||
id=""
|
||||
name={getEntityName(entityData.owner)}
|
||||
width="20"
|
||||
/>
|
||||
<span className="tw-ml-1">
|
||||
{getEntityName(entityData.owner)}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<span className="tw-text-grey-muted">No Owner</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="tw-mx-1.5 tw-inline-block tw-text-gray-400">|</span>
|
||||
<div data-testid="tier">
|
||||
{entityTier ? (
|
||||
entityTier
|
||||
) : (
|
||||
<span className="tw-text-grey-muted">No Tier</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="description-text tw-mt-1"
|
||||
data-testid="description-text">
|
||||
{entityData.description ? (
|
||||
<RichTextEditorPreviewer
|
||||
enableSeeMoreVariant={false}
|
||||
markdown={entityData.description}
|
||||
/>
|
||||
) : (
|
||||
<span className="tw-no-description">No description</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{entityData.tags ? (
|
||||
<div
|
||||
className="tw-mt-2 tw-flex tw-flex-wrap tw-gap-1"
|
||||
data-testid="tags">
|
||||
{entityTags.map((tag) => (
|
||||
<span
|
||||
className="tw-border tw-border-main tw-px-1 tw-rounded tw-text-xs"
|
||||
key={uniqueId()}>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover
|
||||
destroyTooltipOnHide
|
||||
align={{ targetOffset: [0, -10] }}
|
||||
content={<PopoverContent />}
|
||||
overlayClassName="ant-popover-card"
|
||||
title={<PopoverTitle />}
|
||||
trigger="hover"
|
||||
zIndex={9999}>
|
||||
<div onMouseOver={getData}>{children}</div>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default EntityPopOverCard;
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Popover } from 'antd';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import React, { FC, Fragment, HTMLAttributes, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { getUserByName } from '../../../axiosAPIs/userAPI';
|
||||
import { getUserPath, TERM_ADMIN } from '../../../constants/constants';
|
||||
import { User } from '../../../generated/entity/teams/user';
|
||||
import { EntityReference } from '../../../generated/type/entityReference';
|
||||
import { getEntityName, getNonDeletedTeams } from '../../../utils/CommonUtils';
|
||||
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import Loader from '../../Loader/Loader';
|
||||
import ProfilePicture from '../ProfilePicture/ProfilePicture';
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
userName: string;
|
||||
}
|
||||
|
||||
const UserPopOverCard: FC<Props> = ({ children, userName }) => {
|
||||
const history = useHistory();
|
||||
const [userData, setUserData] = useState<User>({} as User);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
|
||||
const getData = () => {
|
||||
getUserByName(userName, 'profile,roles,teams,follows,owns')
|
||||
.then((res: AxiosResponse) => {
|
||||
setUserData(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
showErrorToast(err);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
const onTitleClickHandler = (path: string) => {
|
||||
history.push(path);
|
||||
};
|
||||
|
||||
const UserTeams = () => {
|
||||
const teams = getNonDeletedTeams(userData.teams ?? []);
|
||||
|
||||
return teams?.length ? (
|
||||
<p className="tw-mt-2">
|
||||
<SVGIcons alt="icon" className="tw-w-4" icon={Icons.TEAMS_GREY} />
|
||||
<span className="tw-mr-2 tw-ml-1 tw-align-middle tw-font-medium">
|
||||
Teams
|
||||
</span>
|
||||
<span className="tw-flex tw-flex-wrap tw-mt-1">
|
||||
{teams.map((team, i) => (
|
||||
<span
|
||||
className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs"
|
||||
key={i}>
|
||||
{team?.displayName ?? team?.name}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
</p>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const UserRoles = () => {
|
||||
const roles = userData.roles;
|
||||
const isAdmin = userData?.isAdmin;
|
||||
|
||||
return roles?.length ? (
|
||||
<p className="tw-mt-2">
|
||||
<SVGIcons alt="icon" className="tw-w-4" icon={Icons.USERS} />
|
||||
<span className="tw-mr-2 tw-ml-1 tw-align-middle tw-font-medium">
|
||||
Roles
|
||||
</span>
|
||||
<span className="tw-flex tw-flex-wrap tw-mt-1">
|
||||
{isAdmin && (
|
||||
<span className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs">
|
||||
{TERM_ADMIN}
|
||||
</span>
|
||||
)}
|
||||
{roles.map((role, i) => (
|
||||
<span
|
||||
className="tw-bg-gray-200 tw-rounded tw-px-1 tw-text-grey-body tw-m-0.5 tw-text-xs"
|
||||
key={i}>
|
||||
{role?.displayName ?? role?.name}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
</p>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const PopoverTitle = () => {
|
||||
const name = userData.name ?? '';
|
||||
const displayName = getEntityName(userData as unknown as EntityReference);
|
||||
|
||||
return (
|
||||
<div className="tw-flex">
|
||||
<div className="tw-mr-2">
|
||||
<ProfilePicture id="" name={userName} width="24" />
|
||||
</div>
|
||||
<div className="tw-self-center">
|
||||
<button
|
||||
className="tw-text-info"
|
||||
onClick={() => onTitleClickHandler(getUserPath(name))}>
|
||||
<span className="tw-font-medium tw-mr-2">{displayName}</span>
|
||||
</button>
|
||||
{displayName !== name ? (
|
||||
<span className="tw-text-grey-muted">{name}</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PopoverContent = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
{isLoading ? (
|
||||
<Loader size="small" />
|
||||
) : (
|
||||
<div className="tw-w-80">
|
||||
<UserTeams />
|
||||
<UserRoles />
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover
|
||||
destroyTooltipOnHide
|
||||
align={{ targetOffset: [0, -10] }}
|
||||
content={<PopoverContent />}
|
||||
overlayClassName="ant-popover-card"
|
||||
title={<PopoverTitle />}
|
||||
trigger="hover"
|
||||
zIndex={9999}>
|
||||
<div onMouseOver={getData}>{children}</div>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserPopOverCard;
|
@ -920,6 +920,10 @@ body .profiler-graph .recharts-active-dot circle {
|
||||
grid-template-columns: 200px auto 200px;
|
||||
}
|
||||
|
||||
.feed-meesage > div > p:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 2px 3px;
|
||||
border-radius: 4px;
|
||||
@ -971,6 +975,10 @@ code {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.ant-card-feed > .ant-card-body {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.ant-card-head-title {
|
||||
padding: 8px 0px;
|
||||
}
|
||||
@ -1077,15 +1085,24 @@ code {
|
||||
}
|
||||
|
||||
.ant-popover-feed > .ant-popover-content > .ant-popover-arrow,
|
||||
.ant-popover-card > .ant-popover-content > .ant-popover-arrow,
|
||||
.ant-popover-feed-reactions > .ant-popover-content > .ant-popover-arrow {
|
||||
display: none;
|
||||
}
|
||||
.ant-popover-feed > .ant-popover-content > .ant-popover-inner,
|
||||
.ant-popover-card > .ant-popover-content > .ant-popover-inner,
|
||||
.ant-popover-feed-reactions > .ant-popover-content > .ant-popover-inner {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #dde3ea;
|
||||
}
|
||||
|
||||
.ant-popover-card
|
||||
> .ant-popover-content
|
||||
> .ant-popover-inner
|
||||
> .ant-popover-title {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* Feed popover CSS end */
|
||||
|
||||
.data-box {
|
||||
|
Loading…
x
Reference in New Issue
Block a user