After Width: | Height: | Size: 96 KiB |
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.0963 0H7.09861C6.04891 0 5.19486 0.963391 5.19486 2.14765V4.72486H5.19435V5.92971H5.19486V7.86843C5.19486 9.05261 6.04888 10.0161 7.09861 10.0161H10.051V10.0163H11.119V10.016H12.8351L15.5037 12.8041C15.6044 12.9093 15.7346 12.9646 15.8666 12.9646C15.9388 12.9646 16.0116 12.9481 16.0803 12.9141C16.2748 12.8183 16.4005 12.6015 16.4005 12.3621V9.98863C17.3062 9.82384 18 8.93581 18 7.86839V2.14765C18 0.963431 17.146 0 16.0963 0ZM16.9319 7.86843C16.9319 8.38822 16.557 8.81115 16.0963 8.81115H15.8665C15.5715 8.81115 15.3324 9.08088 15.3324 9.4136V10.983L13.4073 8.97154C13.3085 8.86838 13.179 8.81107 13.0444 8.81107H7.09861C6.63785 8.81107 6.26295 8.38818 6.26295 7.86835V2.14765C6.26295 1.62786 6.63782 1.20492 7.09861 1.20492H16.0963C16.557 1.20492 16.9319 1.62782 16.9319 2.14765V7.86843ZM1.90375 4.72486H4.14845V5.92971H1.90375C1.44295 5.92971 1.06808 6.35265 1.06808 6.87244V11.3274C1.06808 11.8472 1.44295 12.2701 1.90375 12.2701C2.19867 12.2701 2.43777 12.5399 2.43777 12.8726V14.0866L4.16398 12.4154C4.26083 12.3217 4.38416 12.2701 4.51178 12.2701H9.21533C9.67609 12.2701 10.051 11.8472 10.051 11.3274V11.1962H11.119V11.3274C11.119 12.5116 10.265 13.4751 9.2153 13.4751H4.70946L2.25148 15.8547C2.15276 15.9503 2.02887 16 1.90361 16C1.82809 16 1.75201 15.982 1.68071 15.945C1.49115 15.8467 1.36969 15.6329 1.36969 15.3976V13.3891C0.579023 13.128 0 12.3026 0 11.3274V6.87244C0 5.68821 0.853981 4.72478 1.90375 4.72486ZM11 3.5C11 3.224 11.224 3 11.5 3C11.776 3 12 3.224 12 3.5V4.5H13C13.276 4.5 13.5 4.724 13.5 5C13.5 5.276 13.276 5.5 13 5.5H12V6.5C12 6.776 11.776 7 11.5 7C11.224 7 11 6.776 11 6.5V5.5H10C9.724 5.5 9.5 5.276 9.5 5C9.5 4.724 9.724 4.5 10 4.5H11V3.5Z" fill="#7147E8"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.09861 0H16.0963C17.146 0 18 0.843002 18 1.87919V6.88484C18 7.81883 17.3062 8.59586 16.4005 8.74005V10.8168C16.4005 11.0263 16.2748 11.216 16.0803 11.2999C16.0116 11.3295 15.9388 11.344 15.8666 11.344C15.7346 11.344 15.6044 11.2956 15.5037 11.2036L12.8351 8.76403H11.119V8.76422H10.051V8.76407H7.09861C6.04888 8.76407 5.19486 7.92103 5.19486 6.88487V5.18849H5.19435V4.13426H5.19486V1.87919C5.19486 0.842967 6.04891 0 7.09861 0ZM16.0963 7.70976C16.557 7.70976 16.9319 7.33969 16.9319 6.88487V1.87919C16.9319 1.42434 16.557 1.05431 16.0963 1.05431H7.09861C6.63782 1.05431 6.26295 1.42438 6.26295 1.87919V6.8848C6.26295 7.33965 6.63785 7.70969 7.09861 7.70969H13.0444C13.179 7.70969 13.3085 7.75984 13.4073 7.8501L15.3324 9.61012V8.2369C15.3324 7.94577 15.5715 7.70976 15.8665 7.70976H16.0963Z" fill="#7147E8"/>
|
||||||
|
<path d="M4.14845 4.13426H1.90375C0.853981 4.13419 0 4.97719 0 6.01338V9.91148C0 10.7648 0.579023 11.487 1.36969 11.7154V13.4729C1.36969 13.6788 1.49115 13.8659 1.68071 13.9518C1.75201 13.9842 1.82809 14 1.90361 14C2.02887 14 2.15276 13.9565 2.25148 13.8729L4.70946 11.7907H9.2153C10.265 11.7907 11.119 10.9477 11.119 9.91148V9.79664H10.051V9.91148C10.051 10.3663 9.67609 10.7364 9.21533 10.7364H4.51178C4.38416 10.7364 4.26083 10.7814 4.16398 10.8635L2.43777 12.3258V11.2635C2.43777 10.9724 2.19867 10.7364 1.90375 10.7364C1.44295 10.7364 1.06808 10.3663 1.06808 9.91148V6.01338C1.06808 5.55857 1.44295 5.18849 1.90375 5.18849H4.14845V4.13426Z" fill="#7147E8"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="442" viewBox="0 0 512 442" fill="none">
|
||||||
|
<path d="M481.508 175.336L68.4144 3.92596C51.0114 -3.29604 31.3504 -0.11904 17.1054 12.213C2.8604 24.547 -3.0976 43.551 1.5584 61.808L38.3274 206H218.353C226.637 206 233.354 212.716 233.354 221.001C233.354 229.285 226.638 236.002 218.353 236.002H38.3274L1.5584 380.193C-3.0976 398.451 2.8594 417.455 17.1054 429.788C31.3794 442.145 51.0424 445.283 68.4154 438.075L481.509 266.666C500.317 258.862 512 241.364 512 221.001C512 200.638 500.317 183.139 481.508 175.336Z" fill="#7147E8"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 589 B |
@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="442" viewBox="0 0 512 442" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="442" viewBox="0 0 512 442" fill="none">
|
||||||
<path d="M481.508 175.336L68.4144 3.92596C51.0114 -3.29604 31.3504 -0.11904 17.1054 12.213C2.8604 24.547 -3.0976 43.551 1.5584 61.808L38.3274 206H218.353C226.637 206 233.354 212.716 233.354 221.001C233.354 229.285 226.638 236.002 218.353 236.002H38.3274L1.5584 380.193C-3.0976 398.451 2.8594 417.455 17.1054 429.788C31.3794 442.145 51.0424 445.283 68.4154 438.075L481.509 266.666C500.317 258.862 512 241.364 512 221.001C512 200.638 500.317 183.139 481.508 175.336Z" fill="#ffffff"/>
|
<path d="M481.508 175.336L68.4144 3.92596C51.0114 -3.29604 31.3504 -0.11904 17.1054 12.213C2.8604 24.547 -3.0976 43.551 1.5584 61.808L38.3274 206H218.353C226.637 206 233.354 212.716 233.354 221.001C233.354 229.285 226.638 236.002 218.353 236.002H38.3274L1.5584 380.193C-3.0976 398.451 2.8594 417.455 17.1054 429.788C31.3794 442.145 51.0424 445.283 68.4154 438.075L481.509 266.666C500.317 258.862 512 241.364 512 221.001C512 200.638 500.317 183.139 481.508 175.336Z" fill="#DBD1F9"/>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 589 B |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.916 8.15268C12.916 8.44395 12.6799 8.68002 12.3887 8.68002C12.0975 8.68002 11.8613 8.44395 11.8613 8.15268C11.8613 7.86154 12.0975 7.62534 12.3887 7.62534C12.6799 7.62534 12.916 7.86154 12.916 8.15268Z" fill="#6b7280"/>
|
||||||
|
<path d="M12.388 2.54181C11.3176 2.54181 10.4492 3.40808 10.4492 4.48062V4.48131C10.4492 4.77245 10.6853 5.00838 10.9766 5.00838C11.2678 5.00838 11.5039 4.7719 11.5039 4.48062C11.5039 3.9931 11.8982 3.5965 12.3887 3.5965C12.8765 3.5965 13.2734 3.99338 13.2734 4.48131C13.2734 4.9691 12.8765 5.36598 12.3887 5.36598C12.0974 5.36598 11.8614 5.60219 11.8614 5.89333V6.45816C11.8614 6.74944 12.0974 6.9855 12.3887 6.9855C12.6799 6.9855 12.9161 6.74944 12.9161 6.45816V6.34789C13.73 6.11758 14.3281 5.3679 14.3281 4.48131C14.3281 3.41179 13.4581 2.54181 12.388 2.54181V2.54181Z" fill="#6b7280"/>
|
||||||
|
<path d="M5.0603 13.4583C5.71564 12.9479 6.13834 12.1523 6.13834 11.2593C6.13834 9.72276 4.88809 8.47266 3.35152 8.47266C1.81494 8.47266 0.564835 9.72276 0.564835 11.2593C0.564835 12.1523 0.987534 12.9479 1.64273 13.4583C0.717957 14.0084 0 15.0474 0 16.343V17.4727C0 17.7639 0.236069 18 0.527344 18H6.17583C6.46696 18 6.70317 17.7639 6.70317 17.4727V16.343C6.70317 15.0477 5.98535 14.0085 5.0603 13.4583ZM1.61952 11.2593C1.61952 10.3044 2.39653 9.52734 3.35165 9.52734C4.30664 9.52734 5.08365 10.3044 5.08365 11.2593C5.08365 12.2145 4.30664 12.9915 3.35165 12.9915C2.39653 12.9915 1.61952 12.2145 1.61952 11.2593ZM5.64848 16.9453H1.05469V16.343C1.05469 15.0743 2.08109 14.0462 3.35152 14.0462C4.62016 14.0462 5.64835 15.0726 5.64835 16.343V16.9453H5.64848Z" fill="#6b7280"/>
|
||||||
|
<path d="M15.7783 0H9.00017C7.77299 0 6.77832 0.992889 6.77832 2.22185V12.389C6.77832 12.8204 7.27298 13.0726 7.62207 12.8109L9.74078 11.2218H15.7783C17.0055 11.2218 18.0002 10.229 18.0002 9V2.22185C18.0002 0.994675 17.0073 0 15.7783 0V0ZM16.9455 9C16.9455 9.64517 16.4238 10.1672 15.7783 10.1672H9.565C9.45088 10.1672 9.33992 10.2042 9.2486 10.2726L7.83301 11.3343V2.22185C7.83301 1.57668 8.35472 1.05469 9.00017 1.05469H15.7783C16.4235 1.05469 16.9455 1.5764 16.9455 2.22185V9Z" fill="#6b7280"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -12,11 +12,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AxiosResponse } from 'axios';
|
import { AxiosResponse } from 'axios';
|
||||||
|
import { isUndefined } from 'lodash';
|
||||||
import { Post } from 'Models';
|
import { Post } from 'Models';
|
||||||
|
import { FeedFilter } from '../enums/mydata.enum';
|
||||||
import { CreateThread } from '../generated/api/feed/createThread';
|
import { CreateThread } from '../generated/api/feed/createThread';
|
||||||
import APIClient from './index';
|
import APIClient from './index';
|
||||||
import { FeedFilter } from '../enums/mydata.enum';
|
|
||||||
import { isUndefined } from 'lodash';
|
|
||||||
|
|
||||||
export const getAllFeeds: Function = (
|
export const getAllFeeds: Function = (
|
||||||
entityLink?: string
|
entityLink?: string
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { FC, HTMLAttributes, useRef, useState } from 'react';
|
import React, { FC, HTMLAttributes, useRef, useState } from 'react';
|
||||||
import { getBackendFormat, HTMLToMarkdown } from '../../../utils/FeedUtils';
|
import { getBackendFormat, HTMLToMarkdown } from '../../../utils/FeedUtils';
|
||||||
import SVGIcons from '../../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import PopOver from '../../common/popover/PopOver';
|
import PopOver from '../../common/popover/PopOver';
|
||||||
import FeedEditor from '../../FeedEditor/FeedEditor';
|
import FeedEditor from '../../FeedEditor/FeedEditor';
|
||||||
@ -23,6 +23,7 @@ interface ActivityFeedEditorProp extends HTMLAttributes<HTMLDivElement> {
|
|||||||
onSave?: (value: string) => void;
|
onSave?: (value: string) => void;
|
||||||
buttonClass?: string;
|
buttonClass?: string;
|
||||||
placeHolder?: string;
|
placeHolder?: string;
|
||||||
|
defaultValue?: string;
|
||||||
}
|
}
|
||||||
type EditorContentRef = {
|
type EditorContentRef = {
|
||||||
getEditorValue: () => string;
|
getEditorValue: () => string;
|
||||||
@ -34,6 +35,7 @@ const ActivityFeedEditor: FC<ActivityFeedEditorProp> = ({
|
|||||||
buttonClass = '',
|
buttonClass = '',
|
||||||
onSave,
|
onSave,
|
||||||
placeHolder,
|
placeHolder,
|
||||||
|
defaultValue,
|
||||||
}) => {
|
}) => {
|
||||||
const editorRef = useRef<EditorContentRef>();
|
const editorRef = useRef<EditorContentRef>();
|
||||||
const [editorValue, setEditorValue] = useState<string>('');
|
const [editorValue, setEditorValue] = useState<string>('');
|
||||||
@ -54,6 +56,7 @@ const ActivityFeedEditor: FC<ActivityFeedEditorProp> = ({
|
|||||||
return (
|
return (
|
||||||
<div className={classNames('tw-relative', className)}>
|
<div className={classNames('tw-relative', className)}>
|
||||||
<FeedEditor
|
<FeedEditor
|
||||||
|
defaultValue={defaultValue}
|
||||||
placeHolder={placeHolder}
|
placeHolder={placeHolder}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
onChangeHandler={onChangeHandler}
|
onChangeHandler={onChangeHandler}
|
||||||
@ -71,15 +74,22 @@ const ActivityFeedEditor: FC<ActivityFeedEditorProp> = ({
|
|||||||
trigger="mouseenter">
|
trigger="mouseenter">
|
||||||
<Button
|
<Button
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'tw-bg-gray-400 tw-py-0.5 tw-px-1 tw-rounded',
|
'tw-py-0.5 tw-px-1 tw-rounded tw-bg-none',
|
||||||
buttonClass
|
buttonClass
|
||||||
)}
|
)}
|
||||||
disabled={editorValue.length === 0}
|
disabled={editorValue.length === 0}
|
||||||
size="custom"
|
size="custom"
|
||||||
theme={editorValue.length > 0 ? 'primary' : 'default'}
|
variant="text"
|
||||||
variant="contained"
|
|
||||||
onClick={onSaveHandler}>
|
onClick={onSaveHandler}>
|
||||||
<SVGIcons alt="paper-plane" icon="icon-paper-plane" width="18px" />
|
<SVGIcons
|
||||||
|
alt="paper-plane"
|
||||||
|
icon={
|
||||||
|
editorValue.length > 0
|
||||||
|
? Icons.PAPER_PLANE_PRIMARY
|
||||||
|
: Icons.PAPER_PLANE
|
||||||
|
}
|
||||||
|
width="18px"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PopOver>
|
</PopOver>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,11 +28,13 @@ import ActivityFeedCard, {
|
|||||||
} from '../ActivityFeedCard/ActivityFeedCard';
|
} from '../ActivityFeedCard/ActivityFeedCard';
|
||||||
import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor';
|
import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor';
|
||||||
import ActivityFeedPanel from '../ActivityFeedPanel/ActivityFeedPanel';
|
import ActivityFeedPanel from '../ActivityFeedPanel/ActivityFeedPanel';
|
||||||
|
import NoFeedPlaceholder from '../NoFeedPlaceholder/NoFeedPlaceholder';
|
||||||
|
|
||||||
interface ActivityFeedListProp extends HTMLAttributes<HTMLDivElement> {
|
interface ActivityFeedListProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
feedList: EntityThread[];
|
feedList: EntityThread[];
|
||||||
withSidePanel?: boolean;
|
withSidePanel?: boolean;
|
||||||
isEntityFeed?: boolean;
|
isEntityFeed?: boolean;
|
||||||
|
entityName?: string;
|
||||||
postFeedHandler?: (value: string, id: string) => void;
|
postFeedHandler?: (value: string, id: string) => void;
|
||||||
}
|
}
|
||||||
interface FeedListSeparatorProp extends HTMLAttributes<HTMLDivElement> {
|
interface FeedListSeparatorProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
@ -61,7 +63,7 @@ export const FeedListSeparator: FC<FeedListSeparatorProp> = ({
|
|||||||
<div className="tw-flex tw-justify-center">
|
<div className="tw-flex tw-justify-center">
|
||||||
<hr className="tw-absolute tw-top-3 tw-border-b tw-border-main tw-w-full tw-z-0" />
|
<hr className="tw-absolute tw-top-3 tw-border-b tw-border-main tw-w-full tw-z-0" />
|
||||||
{relativeDay ? (
|
{relativeDay ? (
|
||||||
<span className="tw-bg-white tw-px-4 tw-py-px tw-border tw-border-primary tw-rounded tw-z-10 tw-text-primary tw-font-medium">
|
<span className="tw-bg-white tw-px-4 tw-py-px tw-border tw-border-grey-muted tw-rounded tw-z-10 tw-text-grey-muted tw-font-medium">
|
||||||
{relativeDay}
|
{relativeDay}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
@ -91,8 +93,8 @@ const FeedListBody: FC<FeedListBodyProp> = ({
|
|||||||
from: feed.createdBy,
|
from: feed.createdBy,
|
||||||
};
|
};
|
||||||
const postLength = feed.posts.length;
|
const postLength = feed.posts.length;
|
||||||
const replies = feed.postsCount;
|
const replies = feed.postsCount - 1;
|
||||||
const repliedUsers = feed.posts.map((f) => f.from);
|
const repliedUsers = feed.posts.map((f) => f.from).slice(1, 3);
|
||||||
const lastPost = feed.posts[postLength - 1];
|
const lastPost = feed.posts[postLength - 1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -105,15 +107,11 @@ const FeedListBody: FC<FeedListBodyProp> = ({
|
|||||||
/>
|
/>
|
||||||
{postLength > 0 ? (
|
{postLength > 0 ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ActivityFeedCard
|
|
||||||
className="tw-mb-6 tw-ml-9"
|
|
||||||
feed={lastPost}
|
|
||||||
isEntityFeed={isEntityFeed}
|
|
||||||
/>
|
|
||||||
<div className="tw-mb-6">
|
<div className="tw-mb-6">
|
||||||
<div className="tw-ml-9 tw-flex tw-mb-6">
|
<div className="tw-ml-9 tw-flex tw-mb-6">
|
||||||
<FeedFooter
|
<FeedFooter
|
||||||
isFooterVisible
|
isFooterVisible
|
||||||
|
className="tw--mt-4"
|
||||||
lastReplyTimeStamp={lastPost?.postTs}
|
lastReplyTimeStamp={lastPost?.postTs}
|
||||||
repliedUsers={repliedUsers}
|
repliedUsers={repliedUsers}
|
||||||
replies={replies}
|
replies={replies}
|
||||||
@ -124,23 +122,27 @@ const FeedListBody: FC<FeedListBodyProp> = ({
|
|||||||
onViewMore();
|
onViewMore();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="tw-mx-1.5 tw-mt-1 tw-inline-block tw-text-gray-400">
|
|
||||||
|
|
|
||||||
</span>
|
|
||||||
<p
|
|
||||||
className="link-text tw-text-xs tw-mt-1.5 tw-underline"
|
|
||||||
onClick={() => onThreadIdSelect(feed.id)}>
|
|
||||||
Reply
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{selctedThreadId === feed.id ? (
|
|
||||||
<ActivityFeedEditor
|
|
||||||
buttonClass="tw-mr-4"
|
|
||||||
className="tw-ml-5 tw-mr-2"
|
|
||||||
onSave={postFeed}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
<ActivityFeedCard
|
||||||
|
className="tw-mb-6 tw-ml-9"
|
||||||
|
feed={lastPost}
|
||||||
|
isEntityFeed={isEntityFeed}
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
className="link-text tw-text-xs tw-underline tw-ml-9 tw-pl-9 tw--mt-4 tw-mb-6"
|
||||||
|
onClick={() => {
|
||||||
|
onThreadIdSelect(feed.id);
|
||||||
|
}}>
|
||||||
|
Reply
|
||||||
|
</p>
|
||||||
|
{selctedThreadId === feed.id ? (
|
||||||
|
<ActivityFeedEditor
|
||||||
|
buttonClass="tw-mr-4"
|
||||||
|
className="tw-ml-5 tw-mr-2"
|
||||||
|
onSave={postFeed}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<p
|
<p
|
||||||
@ -165,6 +167,7 @@ const ActivityFeedList: FC<ActivityFeedListProp> = ({
|
|||||||
withSidePanel = false,
|
withSidePanel = false,
|
||||||
isEntityFeed = false,
|
isEntityFeed = false,
|
||||||
postFeedHandler,
|
postFeedHandler,
|
||||||
|
entityName,
|
||||||
}) => {
|
}) => {
|
||||||
const { updatedFeedList, relativeDays } =
|
const { updatedFeedList, relativeDays } =
|
||||||
getFeedListWithRelativeDays(feedList);
|
getFeedListWithRelativeDays(feedList);
|
||||||
@ -256,11 +259,17 @@ const ActivityFeedList: FC<ActivityFeedListProp> = ({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<FeedListSeparator
|
{entityName ? (
|
||||||
className="tw-relative tw-mt-1 tw-mb-3.5 tw-pb-5"
|
<NoFeedPlaceholder entityName={entityName} />
|
||||||
relativeDay=""
|
) : (
|
||||||
/>
|
<Fragment>
|
||||||
<>No conversations found. Try changing the filter.</>
|
<FeedListSeparator
|
||||||
|
className="tw-relative tw-mt-1 tw-mb-3.5 tw-pb-5"
|
||||||
|
relativeDay=""
|
||||||
|
/>
|
||||||
|
<>No conversations found. Try changing the filter.</>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,6 +38,7 @@ interface FeedPanelHeaderProp
|
|||||||
extends HTMLAttributes<HTMLHeadingElement>,
|
extends HTMLAttributes<HTMLHeadingElement>,
|
||||||
Pick<ActivityFeedPanelProp, 'onCancel'> {
|
Pick<ActivityFeedPanelProp, 'onCancel'> {
|
||||||
entityField: string;
|
entityField: string;
|
||||||
|
noun?: string;
|
||||||
}
|
}
|
||||||
interface FeedPanelOverlayProp
|
interface FeedPanelOverlayProp
|
||||||
extends HTMLAttributes<HTMLButtonElement>,
|
extends HTMLAttributes<HTMLButtonElement>,
|
||||||
@ -51,12 +52,14 @@ export const FeedPanelHeader: FC<FeedPanelHeaderProp> = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
entityField,
|
entityField,
|
||||||
className,
|
className,
|
||||||
|
noun,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<header className={className}>
|
<header className={className}>
|
||||||
<div className="tw-flex tw-justify-between tw-py-3">
|
<div className="tw-flex tw-justify-between tw-py-3">
|
||||||
<p>
|
<p>
|
||||||
Thread on <span className="tw-heading">{entityField}</span>
|
{noun ? noun : 'Conversation'} on{' '}
|
||||||
|
<span className="tw-heading">{entityField}</span>
|
||||||
</p>
|
</p>
|
||||||
<svg
|
<svg
|
||||||
className="tw-w-5 tw-h-5 tw-ml-1 tw-cursor-pointer"
|
className="tw-w-5 tw-h-5 tw-ml-1 tw-cursor-pointer"
|
||||||
@ -114,7 +117,7 @@ const FeedPanelBody: FC<FeedPanelBodyProp> = ({
|
|||||||
{repliesLength > 0 ? (
|
{repliesLength > 0 ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="tw-mb-3 tw-flex">
|
<div className="tw-mb-3 tw-flex">
|
||||||
<span>{getReplyText(repliesLength)}</span>
|
<span>{getReplyText(repliesLength, 'reply', 'replies')}</span>
|
||||||
<span className="tw-flex-auto tw-self-center tw-ml-1.5">
|
<span className="tw-flex-auto tw-self-center tw-ml-1.5">
|
||||||
<hr />
|
<hr />
|
||||||
</span>
|
</span>
|
||||||
|
@ -89,8 +89,10 @@ const ActivityThreadList: FC<ActivityThreadListProp> = ({
|
|||||||
from: thread.createdBy,
|
from: thread.createdBy,
|
||||||
};
|
};
|
||||||
const postLength = thread.posts.length;
|
const postLength = thread.posts.length;
|
||||||
const replies = thread.postsCount;
|
const replies = thread.postsCount - 1;
|
||||||
const repliedUsers = thread.posts.map((f) => f.from);
|
const repliedUsers = thread.posts
|
||||||
|
.map((f) => f.from)
|
||||||
|
.slice(1, 3);
|
||||||
const lastPost = thread.posts[postLength - 1];
|
const lastPost = thread.posts[postLength - 1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -103,31 +105,31 @@ const ActivityThreadList: FC<ActivityThreadListProp> = ({
|
|||||||
/>
|
/>
|
||||||
{postLength > 0 ? (
|
{postLength > 0 ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ActivityFeedCard
|
|
||||||
isEntityFeed
|
|
||||||
className="tw-mb-6 tw-ml-9"
|
|
||||||
feed={lastPost}
|
|
||||||
/>
|
|
||||||
<div className="tw-mb-6">
|
<div className="tw-mb-6">
|
||||||
<div className="tw-ml-9 tw-flex tw-mb-6">
|
<div className="tw-ml-9 tw-flex tw-mb-6">
|
||||||
<FeedFooter
|
<FeedFooter
|
||||||
isFooterVisible
|
isFooterVisible
|
||||||
|
className="tw--mt-4"
|
||||||
lastReplyTimeStamp={lastPost?.postTs}
|
lastReplyTimeStamp={lastPost?.postTs}
|
||||||
repliedUsers={repliedUsers}
|
repliedUsers={repliedUsers}
|
||||||
replies={replies}
|
replies={replies}
|
||||||
threadId={thread.id}
|
threadId={thread.id}
|
||||||
onThreadSelect={() => onThreadSelect(thread.id)}
|
onThreadSelect={() => onThreadSelect(thread.id)}
|
||||||
/>
|
/>
|
||||||
<span className="tw-mx-1.5 tw-mt-1 tw-inline-block tw-text-gray-400">
|
|
||||||
|
|
|
||||||
</span>
|
|
||||||
<p
|
|
||||||
className="link-text tw-text-xs tw-mt-1.5 tw-underline"
|
|
||||||
onClick={() => onThreadIdSelect(thread.id)}>
|
|
||||||
Reply
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ActivityFeedCard
|
||||||
|
isEntityFeed
|
||||||
|
className="tw-mb-6 tw-ml-9"
|
||||||
|
feed={lastPost}
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
className="link-text tw-text-xs tw-underline tw-ml-9 tw-pl-9 tw--mt-4 tw-mb-6"
|
||||||
|
onClick={() => {
|
||||||
|
onThreadIdSelect(thread.id);
|
||||||
|
}}>
|
||||||
|
Reply
|
||||||
|
</p>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<p
|
<p
|
||||||
@ -185,7 +187,7 @@ const ActivityThread: FC<ActivityThreadProp> = ({
|
|||||||
{repliesLength > 0 ? (
|
{repliesLength > 0 ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="tw-mb-3 tw-flex">
|
<div className="tw-mb-3 tw-flex">
|
||||||
<span>{getReplyText(repliesLength)}</span>
|
<span>{getReplyText(repliesLength, 'reply', 'replies')}</span>
|
||||||
<span className="tw-flex-auto tw-self-center tw-ml-1.5">
|
<span className="tw-flex-auto tw-self-center tw-ml-1.5">
|
||||||
<hr />
|
<hr />
|
||||||
</span>
|
</span>
|
||||||
@ -304,6 +306,7 @@ const ActivityThreadPanel: FC<ActivityThreadPanelProp> = ({
|
|||||||
<FeedPanelHeader
|
<FeedPanelHeader
|
||||||
className="tw-px-4 tw-shadow-sm"
|
className="tw-px-4 tw-shadow-sm"
|
||||||
entityField={entityField as string}
|
entityField={entityField as string}
|
||||||
|
noun="Conversations"
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
/>
|
/>
|
||||||
{!isUndefined(selectedThread) ? (
|
{!isUndefined(selectedThread) ? (
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 classNames from 'classnames';
|
||||||
|
import React, { FC, HTMLAttributes } from 'react';
|
||||||
|
import EditorImg from '../../../assets/img/feedEditor.png';
|
||||||
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
|
|
||||||
|
interface NoFeedPlaceholderProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
entityName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoFeedPlaceholder: FC<NoFeedPlaceholderProp> = ({
|
||||||
|
className,
|
||||||
|
entityName,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('tw-mt-10 tw-text-base tw-font-medium', className)}>
|
||||||
|
<span>{`There is no activity on the "${entityName}" yet. Start a conversation by clicking
|
||||||
|
on the `}</span>
|
||||||
|
<span>
|
||||||
|
<SVGIcons alt="comments" icon={Icons.COMMENT_PLUS} width="20px" />
|
||||||
|
</span>
|
||||||
|
<span>{` to collaborate with other users.`}</span>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
alt="editor-image"
|
||||||
|
className="tw-rounded tw-mt-2 tw-block tw-m-auto"
|
||||||
|
loading="lazy"
|
||||||
|
src={EditorImg}
|
||||||
|
width="600px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NoFeedPlaceholder;
|
@ -17,9 +17,10 @@ import { EntityTags } from 'Models';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { getTeamDetailsPath } from '../../constants/constants';
|
import { getTeamDetailsPath } from '../../constants/constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import { Dashboard } from '../../generated/entity/data/dashboard';
|
import { Dashboard } from '../../generated/entity/data/dashboard';
|
||||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||||
import { User } from '../../generated/entity/teams/user';
|
import { EntityReference, User } from '../../generated/entity/teams/user';
|
||||||
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
||||||
import { useAuth } from '../../hooks/authHooks';
|
import { useAuth } from '../../hooks/authHooks';
|
||||||
import {
|
import {
|
||||||
@ -28,6 +29,8 @@ import {
|
|||||||
getUserTeams,
|
getUserTeams,
|
||||||
isEven,
|
isEven,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
|
import { getEntityFeedLink } from '../../utils/EntityUtils';
|
||||||
|
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||||
@ -43,6 +46,7 @@ import PageContainer from '../containers/PageContainer';
|
|||||||
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
||||||
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
||||||
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
|
import RequestDescriptionModal from '../Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import TagsContainer from '../tags-container/tags-container';
|
import TagsContainer from '../tags-container/tags-container';
|
||||||
import Tags from '../tags/tags';
|
import Tags from '../tags/tags';
|
||||||
import { ChartType, DashboardDetailsProps } from './DashboardDetails.interface';
|
import { ChartType, DashboardDetailsProps } from './DashboardDetails.interface';
|
||||||
@ -86,6 +90,7 @@ const DashboardDetails = ({
|
|||||||
feedCount,
|
feedCount,
|
||||||
entityFieldThreadCount,
|
entityFieldThreadCount,
|
||||||
createThread,
|
createThread,
|
||||||
|
dashboardFQN,
|
||||||
}: DashboardDetailsProps) => {
|
}: DashboardDetailsProps) => {
|
||||||
const { isAuthDisabled } = useAuth();
|
const { isAuthDisabled } = useAuth();
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
@ -102,6 +107,14 @@ const DashboardDetails = ({
|
|||||||
const [tagList, setTagList] = useState<Array<string>>([]);
|
const [tagList, setTagList] = useState<Array<string>>([]);
|
||||||
const [isTagLoading, setIsTagLoading] = useState<boolean>(false);
|
const [isTagLoading, setIsTagLoading] = useState<boolean>(false);
|
||||||
const [threadLink, setThreadLink] = useState<string>('');
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
const hasEditAccess = () => {
|
const hasEditAccess = () => {
|
||||||
if (owner?.type === 'user') {
|
if (owner?.type === 'user') {
|
||||||
return owner.id === getCurrentUserId();
|
return owner.id === getCurrentUserId();
|
||||||
@ -365,7 +378,9 @@ const DashboardDetails = ({
|
|||||||
'tags',
|
'tags',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={dashboardFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.DASHBOARD}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
followHandler={followDashboard}
|
followHandler={followDashboard}
|
||||||
followers={followersCount}
|
followers={followersCount}
|
||||||
@ -400,7 +415,9 @@ const DashboardDetails = ({
|
|||||||
'description',
|
'description',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={dashboardFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.DASHBOARD}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
isReadOnly={deleted}
|
isReadOnly={deleted}
|
||||||
@ -408,6 +425,7 @@ const DashboardDetails = ({
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -566,15 +584,6 @@ const DashboardDetails = ({
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{threadLink ? (
|
|
||||||
<ActivityThreadPanel
|
|
||||||
createThread={createThread}
|
|
||||||
open={Boolean(threadLink)}
|
|
||||||
postFeedHandler={postFeedHandler}
|
|
||||||
threadLink={threadLink}
|
|
||||||
onCancel={onThreadPanelClose}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTab === 2 && (
|
{activeTab === 2 && (
|
||||||
@ -586,6 +595,7 @@ const DashboardDetails = ({
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={entityName}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
@ -632,6 +642,28 @@ const DashboardDetails = ({
|
|||||||
onSave={onChartUpdate}
|
onSave={onChartUpdate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(owner as EntityReference)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
EntityType.DASHBOARD,
|
||||||
|
dashboardFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,7 @@ export interface ChartType extends Chart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardDetailsProps {
|
export interface DashboardDetailsProps {
|
||||||
|
dashboardFQN: string;
|
||||||
version: string;
|
version: string;
|
||||||
isNodeLoading: LoadingNodeState;
|
isNodeLoading: LoadingNodeState;
|
||||||
lineageLeafNodes: LeafNodes;
|
lineageLeafNodes: LeafNodes;
|
||||||
|
@ -77,6 +77,7 @@ const DashboardDetailsProps = {
|
|||||||
feedCount: 0,
|
feedCount: 0,
|
||||||
entityFieldThreadCount: [],
|
entityFieldThreadCount: [],
|
||||||
createThread: jest.fn(),
|
createThread: jest.fn(),
|
||||||
|
dashboardFQN: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../ManageTab/ManageTab.component', () => {
|
jest.mock('../ManageTab/ManageTab.component', () => {
|
||||||
|
@ -17,6 +17,7 @@ import { ColumnJoins, EntityTags, ExtraInfo } from 'Models';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { getTeamDetailsPath, ROUTES } from '../../constants/constants';
|
import { getTeamDetailsPath, ROUTES } from '../../constants/constants';
|
||||||
import { CSMode } from '../../enums/codemirror.enum';
|
import { CSMode } from '../../enums/codemirror.enum';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import {
|
import {
|
||||||
JoinedWith,
|
JoinedWith,
|
||||||
Table,
|
Table,
|
||||||
@ -32,6 +33,8 @@ import {
|
|||||||
getTableFQNFromColumnFQN,
|
getTableFQNFromColumnFQN,
|
||||||
getUserTeams,
|
getUserTeams,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
|
import { getEntityFeedLink } from '../../utils/EntityUtils';
|
||||||
|
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import { getTagsWithoutTier, getUsagePercentile } from '../../utils/TableUtils';
|
import { getTagsWithoutTier, getUsagePercentile } from '../../utils/TableUtils';
|
||||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
@ -43,6 +46,7 @@ import PageContainer from '../containers/PageContainer';
|
|||||||
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
||||||
import FrequentlyJoinedTables from '../FrequentlyJoinedTables/FrequentlyJoinedTables.component';
|
import FrequentlyJoinedTables from '../FrequentlyJoinedTables/FrequentlyJoinedTables.component';
|
||||||
import ManageTab from '../ManageTab/ManageTab.component';
|
import ManageTab from '../ManageTab/ManageTab.component';
|
||||||
|
import RequestDescriptionModal from '../Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import SampleDataTable, {
|
import SampleDataTable, {
|
||||||
SampleColumns,
|
SampleColumns,
|
||||||
} from '../SampleDataTable/SampleDataTable.component';
|
} from '../SampleDataTable/SampleDataTable.component';
|
||||||
@ -111,6 +115,14 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [threadLink, setThreadLink] = useState<string>('');
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
|
|
||||||
const setUsageDetails = (
|
const setUsageDetails = (
|
||||||
usageSummary: TypeUsedToReturnUsageDetailsOfAnEntity
|
usageSummary: TypeUsedToReturnUsageDetailsOfAnEntity
|
||||||
@ -476,7 +488,9 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
'description',
|
'description',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={datasetFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.TABLE}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
isReadOnly={deleted}
|
isReadOnly={deleted}
|
||||||
@ -484,6 +498,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -505,11 +520,13 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
'columns',
|
'columns',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={datasetFQN}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isReadOnly={deleted}
|
isReadOnly={deleted}
|
||||||
joins={tableJoinData.columnJoins as ColumnJoins[]}
|
joins={tableJoinData.columnJoins as ColumnJoins[]}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
sampleData={sampleData}
|
sampleData={sampleData}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onUpdate={onColumnsUpdate}
|
onUpdate={onColumnsUpdate}
|
||||||
/>
|
/>
|
||||||
@ -524,6 +541,19 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
onCancel={onThreadPanelClose}
|
onCancel={onThreadPanelClose}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(owner)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
EntityType.TABLE,
|
||||||
|
datasetFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{activeTab === 2 && (
|
{activeTab === 2 && (
|
||||||
@ -535,6 +565,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={entityName}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
|
@ -118,7 +118,10 @@ jest.mock('../ActivityFeed/ActivityFeedList/ActivityFeedList.tsx', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx', () => {
|
jest.mock('../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx', () => {
|
||||||
return jest.fn().mockReturnValue(<p>FeedCards</p>);
|
return jest.fn().mockReturnValue(<p>Conversations</p>);
|
||||||
|
});
|
||||||
|
jest.mock('../ActivityFeed/ActivityFeedEditor/ActivityFeedEditor.tsx', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>FeedEditor</p>);
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('../../utils/CommonUtils', () => ({
|
jest.mock('../../utils/CommonUtils', () => ({
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { cloneDeep, isUndefined, lowerCase } from 'lodash';
|
import { cloneDeep, isNil, isUndefined, lowerCase } from 'lodash';
|
||||||
import { EntityFieldThreads, EntityTags } from 'Models';
|
import { EntityFieldThreads, EntityTags } from 'Models';
|
||||||
import React, { Fragment, useEffect, useState } from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useExpanded, useTable } from 'react-table';
|
import { useExpanded, useTable } from 'react-table';
|
||||||
import { getTableDetailsPath } from '../../constants/constants';
|
import { getTableDetailsPath } from '../../constants/constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
ColumnJoins,
|
ColumnJoins,
|
||||||
@ -32,7 +33,8 @@ import {
|
|||||||
getTableFQNFromColumnFQN,
|
getTableFQNFromColumnFQN,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getFieldThreadElement } from '../../utils/FeedElementUtils';
|
import { getFieldThreadElement } from '../../utils/FeedElementUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import { getThreadValue } from '../../utils/FeedUtils';
|
||||||
|
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||||
import {
|
import {
|
||||||
getConstraintIcon,
|
getConstraintIcon,
|
||||||
getDataTypeString,
|
getDataTypeString,
|
||||||
@ -54,9 +56,11 @@ type Props = {
|
|||||||
columnName: string;
|
columnName: string;
|
||||||
hasEditAccess: boolean;
|
hasEditAccess: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
|
entityFqn?: string;
|
||||||
entityFieldThreads?: EntityFieldThreads[];
|
entityFieldThreads?: EntityFieldThreads[];
|
||||||
onUpdate?: (columns: Table['columns']) => void;
|
onUpdate?: (columns: Table['columns']) => void;
|
||||||
onThreadLinkSelect?: (value: string) => void;
|
onThreadLinkSelect?: (value: string) => void;
|
||||||
|
onEntityFieldSelect?: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const EntityTable = ({
|
const EntityTable = ({
|
||||||
@ -69,6 +73,8 @@ const EntityTable = ({
|
|||||||
entityFieldThreads,
|
entityFieldThreads,
|
||||||
isReadOnly = false,
|
isReadOnly = false,
|
||||||
onThreadLinkSelect,
|
onThreadLinkSelect,
|
||||||
|
onEntityFieldSelect,
|
||||||
|
entityFqn,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const columns = React.useMemo(
|
const columns = React.useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -465,7 +471,11 @@ const EntityTable = ({
|
|||||||
cell.row.cells[0].value,
|
cell.row.cells[0].value,
|
||||||
'tags',
|
'tags',
|
||||||
entityFieldThreads as EntityFieldThreads[],
|
entityFieldThreads as EntityFieldThreads[],
|
||||||
onThreadLinkSelect
|
onThreadLinkSelect,
|
||||||
|
EntityType.TABLE,
|
||||||
|
entityFqn,
|
||||||
|
`columns/${cell.row.cells[0].value}/tags`,
|
||||||
|
Boolean(cell.value.length)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -485,39 +495,70 @@ const EntityTable = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="tw-no-description">
|
<span className="tw-no-description">
|
||||||
No description added
|
No description added{' '}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{getFieldThreadElement(
|
|
||||||
cell.row.cells[0].value,
|
|
||||||
'description',
|
|
||||||
entityFieldThreads as EntityFieldThreads[],
|
|
||||||
onThreadLinkSelect
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{!isReadOnly ? (
|
{!isReadOnly ? (
|
||||||
<NonAdminAction
|
<Fragment>
|
||||||
html={getHtmlForNonAdminAction(
|
<NonAdminAction
|
||||||
Boolean(owner)
|
html={getHtmlForNonAdminAction(
|
||||||
|
Boolean(owner)
|
||||||
|
)}
|
||||||
|
isOwner={hasEditAccess}
|
||||||
|
permission={Operation.UpdateDescription}
|
||||||
|
position="top">
|
||||||
|
<button
|
||||||
|
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
||||||
|
onClick={() => {
|
||||||
|
if (!isReadOnly) {
|
||||||
|
handleEditColumn(
|
||||||
|
row.original,
|
||||||
|
row.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="edit"
|
||||||
|
icon="icon-edit"
|
||||||
|
title="Edit"
|
||||||
|
width="10px"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</NonAdminAction>
|
||||||
|
{isNil(
|
||||||
|
getThreadValue(
|
||||||
|
cell.row.cells[0].value,
|
||||||
|
'description',
|
||||||
|
entityFieldThreads as EntityFieldThreads[]
|
||||||
|
)
|
||||||
|
) && !cell.value ? (
|
||||||
|
<button
|
||||||
|
className="focus:tw-outline-none tw-ml-1 tw-opacity-0 group-hover:tw-opacity-100"
|
||||||
|
data-testid="request-description"
|
||||||
|
onClick={() =>
|
||||||
|
onEntityFieldSelect?.(
|
||||||
|
`columns/${cell.row.cells[0].value}/description`
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="request-description"
|
||||||
|
icon={Icons.REQUEST}
|
||||||
|
width="20px"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
{getFieldThreadElement(
|
||||||
|
cell.row.cells[0].value,
|
||||||
|
'description',
|
||||||
|
entityFieldThreads as EntityFieldThreads[],
|
||||||
|
onThreadLinkSelect,
|
||||||
|
EntityType.TABLE,
|
||||||
|
entityFqn,
|
||||||
|
`columns/${cell.row.cells[0].value}/description`,
|
||||||
|
Boolean(cell.value)
|
||||||
)}
|
)}
|
||||||
isOwner={hasEditAccess}
|
</Fragment>
|
||||||
permission={Operation.UpdateDescription}
|
|
||||||
position="top">
|
|
||||||
<button
|
|
||||||
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
|
||||||
onClick={() => {
|
|
||||||
if (!isReadOnly) {
|
|
||||||
handleEditColumn(row.original, row.id);
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<SVGIcons
|
|
||||||
alt="edit"
|
|
||||||
icon="icon-edit"
|
|
||||||
title="Edit"
|
|
||||||
width="10px"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</NonAdminAction>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,6 +21,7 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import ReactQuill, { Quill } from 'react-quill';
|
import ReactQuill, { Quill } from 'react-quill';
|
||||||
|
import { EditorPlaceHolder } from '../../constants/feed.constants';
|
||||||
import { HTMLToMarkdown, matcher } from '../../utils/FeedUtils';
|
import { HTMLToMarkdown, matcher } from '../../utils/FeedUtils';
|
||||||
import { insertMention, insertRef } from '../../utils/QuillUtils';
|
import { insertMention, insertRef } from '../../utils/QuillUtils';
|
||||||
import { editorRef } from '../common/rich-text-editor/RichTextEditor.interface';
|
import { editorRef } from '../common/rich-text-editor/RichTextEditor.interface';
|
||||||
@ -71,10 +72,10 @@ const modules = {
|
|||||||
|
|
||||||
const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
||||||
(
|
(
|
||||||
{ className, editorClass, placeHolder, onChangeHandler }: FeedEditorProp,
|
{ className, editorClass, onChangeHandler, defaultValue }: FeedEditorProp,
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const [value, setValue] = useState<string>('');
|
const [value, setValue] = useState<string>(defaultValue ?? '');
|
||||||
|
|
||||||
const handleOnChange = (value: string) => {
|
const handleOnChange = (value: string) => {
|
||||||
setValue(value);
|
setValue(value);
|
||||||
@ -97,7 +98,7 @@ const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
|||||||
<ReactQuill
|
<ReactQuill
|
||||||
className={classNames('editor-container', editorClass)}
|
className={classNames('editor-container', editorClass)}
|
||||||
modules={modules}
|
modules={modules}
|
||||||
placeholder={placeHolder ?? 'Enter a reply'}
|
placeholder={EditorPlaceHolder}
|
||||||
theme="snow"
|
theme="snow"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleOnChange}
|
onChange={handleOnChange}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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 classNames from 'classnames';
|
||||||
|
import React, { FC, HTMLAttributes } from 'react';
|
||||||
|
import AppState from '../../../AppState';
|
||||||
|
import { CreateThread } from '../../../generated/api/feed/createThread';
|
||||||
|
import ActivityFeedEditor from '../../ActivityFeed/ActivityFeedEditor/ActivityFeedEditor';
|
||||||
|
|
||||||
|
interface RequestDescriptionModalProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
header: string;
|
||||||
|
threadLink: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
headerClassName?: string;
|
||||||
|
bodyClassName?: string;
|
||||||
|
onCancel: () => void;
|
||||||
|
createThread: (data: CreateThread) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RequestDescriptionModal: FC<RequestDescriptionModalProp> = ({
|
||||||
|
header,
|
||||||
|
headerClassName,
|
||||||
|
onCancel,
|
||||||
|
createThread,
|
||||||
|
threadLink,
|
||||||
|
defaultValue,
|
||||||
|
}) => {
|
||||||
|
const onPostThread = (value: string) => {
|
||||||
|
const currentUser = AppState.userDetails?.name ?? AppState.users[0]?.name;
|
||||||
|
const data = {
|
||||||
|
message: value,
|
||||||
|
from: currentUser,
|
||||||
|
about: threadLink,
|
||||||
|
};
|
||||||
|
createThread(data);
|
||||||
|
onCancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<dialog className="tw-modal" data-testid="modal-container">
|
||||||
|
<div className="tw-modal-backdrop" onClick={onCancel} />
|
||||||
|
<div className="tw-modal-container tw-w-2/4 tw-pb-0 tw-pt-2">
|
||||||
|
<div className={classNames('tw-modal-header tw-pb-2', headerClassName)}>
|
||||||
|
<p className="tw-modal-title" data-testid="modal-header">
|
||||||
|
{header}
|
||||||
|
</p>
|
||||||
|
<div className="tw-flex">
|
||||||
|
<svg
|
||||||
|
className="tw-w-6 tw-h-6 tw-ml-1 tw-cursor-pointer"
|
||||||
|
data-testid="closeWhatsNew"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
onClick={onCancel}>
|
||||||
|
<path
|
||||||
|
d="M6 18L18 6M6 6l12 12"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="1"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classNames('tw-px-0 tw-py-3')} data-testid="body-text">
|
||||||
|
<ActivityFeedEditor
|
||||||
|
buttonClass="tw-mr-4 tw-pb-3"
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
onSave={onPostThread}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RequestDescriptionModal;
|
@ -22,10 +22,10 @@ import {
|
|||||||
import { SearchResponse } from 'Models';
|
import { SearchResponse } from 'Models';
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { FeedFilter } from '../../enums/mydata.enum';
|
||||||
import { User } from '../../generated/entity/teams/user';
|
import { User } from '../../generated/entity/teams/user';
|
||||||
import { formatDataResponse } from '../../utils/APIUtils';
|
import { formatDataResponse } from '../../utils/APIUtils';
|
||||||
import MyDataPage from './MyData.component';
|
import MyDataPage from './MyData.component';
|
||||||
import { FeedFilter } from '../../enums/mydata.enum';
|
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
data: {
|
data: {
|
||||||
|
@ -13,13 +13,15 @@
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
|
import { isNil } from 'lodash';
|
||||||
import { EntityFieldThreads, EntityTags } from 'Models';
|
import { EntityFieldThreads, EntityTags } from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { getTeamDetailsPath } from '../../constants/constants';
|
import { getTeamDetailsPath } from '../../constants/constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import { Pipeline, Task } from '../../generated/entity/data/pipeline';
|
import { Pipeline, Task } from '../../generated/entity/data/pipeline';
|
||||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||||
import { User } from '../../generated/entity/teams/user';
|
import { EntityReference, User } from '../../generated/entity/teams/user';
|
||||||
import { LabelType, State } from '../../generated/type/tagLabel';
|
import { LabelType, State } from '../../generated/type/tagLabel';
|
||||||
import { useAuth } from '../../hooks/authHooks';
|
import { useAuth } from '../../hooks/authHooks';
|
||||||
import {
|
import {
|
||||||
@ -28,9 +30,13 @@ import {
|
|||||||
getUserTeams,
|
getUserTeams,
|
||||||
isEven,
|
isEven,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getFieldThreadElement } from '../../utils/FeedElementUtils';
|
import { getEntityFeedLink } from '../../utils/EntityUtils';
|
||||||
|
import {
|
||||||
|
getDefaultValue,
|
||||||
|
getFieldThreadElement,
|
||||||
|
} from '../../utils/FeedElementUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||||
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||||
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
@ -43,6 +49,7 @@ import PageContainer from '../containers/PageContainer';
|
|||||||
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
||||||
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
||||||
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
|
import RequestDescriptionModal from '../Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import { PipeLineDetailsProp } from './PipelineDetails.interface';
|
import { PipeLineDetailsProp } from './PipelineDetails.interface';
|
||||||
|
|
||||||
const PipelineDetails = ({
|
const PipelineDetails = ({
|
||||||
@ -83,6 +90,7 @@ const PipelineDetails = ({
|
|||||||
feedCount,
|
feedCount,
|
||||||
entityFieldThreadCount,
|
entityFieldThreadCount,
|
||||||
createThread,
|
createThread,
|
||||||
|
pipelineFQN,
|
||||||
}: PipeLineDetailsProp) => {
|
}: PipeLineDetailsProp) => {
|
||||||
const { isAuthDisabled } = useAuth();
|
const { isAuthDisabled } = useAuth();
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
@ -95,6 +103,15 @@ const PipelineDetails = ({
|
|||||||
|
|
||||||
const [threadLink, setThreadLink] = useState<string>('');
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
|
|
||||||
const hasEditAccess = () => {
|
const hasEditAccess = () => {
|
||||||
if (owner?.type === 'user') {
|
if (owner?.type === 'user') {
|
||||||
return owner.id === getCurrentUserId();
|
return owner.id === getCurrentUserId();
|
||||||
@ -311,7 +328,9 @@ const PipelineDetails = ({
|
|||||||
'tags',
|
'tags',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={pipelineFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.PIPELINE}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
followHandler={followPipeline}
|
followHandler={followPipeline}
|
||||||
followers={followersCount}
|
followers={followersCount}
|
||||||
@ -345,7 +364,9 @@ const PipelineDetails = ({
|
|||||||
'description',
|
'description',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={pipelineFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.PIPELINE}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
isReadOnly={deleted}
|
isReadOnly={deleted}
|
||||||
@ -353,6 +374,7 @@ const PipelineDetails = ({
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -403,40 +425,74 @@ const PipelineDetails = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="tw-no-description">
|
<span className="tw-no-description">
|
||||||
No description added
|
No description added{' '}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{getFieldThreadElement(
|
|
||||||
task.name,
|
|
||||||
'description',
|
|
||||||
getEntityFieldThreadCounts(
|
|
||||||
'tasks',
|
|
||||||
entityFieldThreadCount
|
|
||||||
) as EntityFieldThreads[],
|
|
||||||
onThreadLinkSelect
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{!deleted && (
|
{!deleted && (
|
||||||
<NonAdminAction
|
<Fragment>
|
||||||
html={getHtmlForNonAdminAction(
|
<NonAdminAction
|
||||||
Boolean(owner)
|
html={getHtmlForNonAdminAction(
|
||||||
|
Boolean(owner)
|
||||||
|
)}
|
||||||
|
isOwner={hasEditAccess()}
|
||||||
|
permission={Operation.UpdateDescription}
|
||||||
|
position="top">
|
||||||
|
<button
|
||||||
|
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
||||||
|
onClick={() =>
|
||||||
|
handleUpdateTask(task, index)
|
||||||
|
}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="edit"
|
||||||
|
icon="icon-edit"
|
||||||
|
title="Edit"
|
||||||
|
width="10px"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</NonAdminAction>
|
||||||
|
{!isNil(
|
||||||
|
getFieldThreadElement(
|
||||||
|
task.name,
|
||||||
|
'description',
|
||||||
|
getEntityFieldThreadCounts(
|
||||||
|
'tasks',
|
||||||
|
entityFieldThreadCount
|
||||||
|
) as EntityFieldThreads[],
|
||||||
|
onThreadLinkSelect
|
||||||
|
)
|
||||||
|
) &&
|
||||||
|
onEntityFieldSelect &&
|
||||||
|
!task.description ? (
|
||||||
|
<button
|
||||||
|
className="focus:tw-outline-none tw-ml-1 tw-opacity-0 group-hover:tw-opacity-100 tw--mt-2"
|
||||||
|
data-testid="request-description"
|
||||||
|
onClick={() =>
|
||||||
|
onEntityFieldSelect?.(
|
||||||
|
`tasks/${task.name}/description`
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="request-description"
|
||||||
|
icon={Icons.REQUEST}
|
||||||
|
width="20px"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
{getFieldThreadElement(
|
||||||
|
task.name,
|
||||||
|
'description',
|
||||||
|
getEntityFieldThreadCounts(
|
||||||
|
'tasks',
|
||||||
|
entityFieldThreadCount
|
||||||
|
) as EntityFieldThreads[],
|
||||||
|
onThreadLinkSelect,
|
||||||
|
EntityType.PIPELINE,
|
||||||
|
pipelineFQN,
|
||||||
|
`tasks/${task.name}/description`,
|
||||||
|
Boolean(task.description)
|
||||||
)}
|
)}
|
||||||
isOwner={hasEditAccess()}
|
</Fragment>
|
||||||
permission={Operation.UpdateDescription}
|
|
||||||
position="top">
|
|
||||||
<button
|
|
||||||
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
|
||||||
onClick={() =>
|
|
||||||
handleUpdateTask(task, index)
|
|
||||||
}>
|
|
||||||
<SVGIcons
|
|
||||||
alt="edit"
|
|
||||||
icon="icon-edit"
|
|
||||||
title="Edit"
|
|
||||||
width="10px"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</NonAdminAction>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -453,15 +509,6 @@ const PipelineDetails = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{threadLink ? (
|
|
||||||
<ActivityThreadPanel
|
|
||||||
createThread={createThread}
|
|
||||||
open={Boolean(threadLink)}
|
|
||||||
postFeedHandler={postFeedHandler}
|
|
||||||
threadLink={threadLink}
|
|
||||||
onCancel={onThreadPanelClose}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTab === 2 && (
|
{activeTab === 2 && (
|
||||||
@ -473,6 +520,7 @@ const PipelineDetails = ({
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={entityName}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
@ -519,6 +567,28 @@ const PipelineDetails = ({
|
|||||||
onSave={onTaskUpdate}
|
onSave={onTaskUpdate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(owner as EntityReference)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
EntityType.PIPELINE,
|
||||||
|
pipelineFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@ import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrum
|
|||||||
import { Edge, EdgeData } from '../EntityLineage/EntityLineage.interface';
|
import { Edge, EdgeData } from '../EntityLineage/EntityLineage.interface';
|
||||||
|
|
||||||
export interface PipeLineDetailsProp {
|
export interface PipeLineDetailsProp {
|
||||||
|
pipelineFQN: string;
|
||||||
version: string;
|
version: string;
|
||||||
isNodeLoading: LoadingNodeState;
|
isNodeLoading: LoadingNodeState;
|
||||||
lineageLeafNodes: LeafNodes;
|
lineageLeafNodes: LeafNodes;
|
||||||
|
@ -30,8 +30,10 @@ type Props = {
|
|||||||
columnName: string;
|
columnName: string;
|
||||||
hasEditAccess?: boolean;
|
hasEditAccess?: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
|
entityFqn?: string;
|
||||||
entityFieldThreads?: EntityFieldThreads[];
|
entityFieldThreads?: EntityFieldThreads[];
|
||||||
onThreadLinkSelect?: (value: string) => void;
|
onThreadLinkSelect?: (value: string) => void;
|
||||||
|
onEntityFieldSelect?: (value: string) => void;
|
||||||
onUpdate?: (columns: Table['columns']) => void;
|
onUpdate?: (columns: Table['columns']) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,7 +46,9 @@ const SchemaTab: FunctionComponent<Props> = ({
|
|||||||
owner,
|
owner,
|
||||||
entityFieldThreads,
|
entityFieldThreads,
|
||||||
onThreadLinkSelect,
|
onThreadLinkSelect,
|
||||||
|
onEntityFieldSelect,
|
||||||
isReadOnly = false,
|
isReadOnly = false,
|
||||||
|
entityFqn,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
|
|
||||||
@ -70,12 +74,14 @@ const SchemaTab: FunctionComponent<Props> = ({
|
|||||||
<EntityTable
|
<EntityTable
|
||||||
columnName={columnName}
|
columnName={columnName}
|
||||||
entityFieldThreads={entityFieldThreads}
|
entityFieldThreads={entityFieldThreads}
|
||||||
|
entityFqn={entityFqn}
|
||||||
hasEditAccess={Boolean(hasEditAccess)}
|
hasEditAccess={Boolean(hasEditAccess)}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
joins={joins}
|
joins={joins}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
searchText={lowerCase(searchText)}
|
searchText={lowerCase(searchText)}
|
||||||
tableColumns={columns}
|
tableColumns={columns}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onUpdate={onUpdate}
|
onUpdate={onUpdate}
|
||||||
/>
|
/>
|
||||||
|
@ -14,11 +14,14 @@
|
|||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { getTeamDetailsPath } from '../../constants/constants';
|
import { getTeamDetailsPath } from '../../constants/constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import { Topic } from '../../generated/entity/data/topic';
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
import { User } from '../../generated/entity/teams/user';
|
import { EntityReference, User } from '../../generated/entity/teams/user';
|
||||||
import { LabelType, State } from '../../generated/type/tagLabel';
|
import { LabelType, State } from '../../generated/type/tagLabel';
|
||||||
import { useAuth } from '../../hooks/authHooks';
|
import { useAuth } from '../../hooks/authHooks';
|
||||||
import { getCurrentUserId, getUserTeams } from '../../utils/CommonUtils';
|
import { getCurrentUserId, getUserTeams } from '../../utils/CommonUtils';
|
||||||
|
import { getEntityFeedLink } from '../../utils/EntityUtils';
|
||||||
|
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import { bytesToSize } from '../../utils/StringsUtils';
|
import { bytesToSize } from '../../utils/StringsUtils';
|
||||||
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||||
@ -29,6 +32,7 @@ import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
|||||||
import TabsPane from '../common/TabsPane/TabsPane';
|
import TabsPane from '../common/TabsPane/TabsPane';
|
||||||
import PageContainer from '../containers/PageContainer';
|
import PageContainer from '../containers/PageContainer';
|
||||||
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
||||||
|
import RequestDescriptionModal from '../Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import SchemaEditor from '../schema-editor/SchemaEditor';
|
import SchemaEditor from '../schema-editor/SchemaEditor';
|
||||||
import { TopicDetailsProps } from './TopicDetails.interface';
|
import { TopicDetailsProps } from './TopicDetails.interface';
|
||||||
|
|
||||||
@ -65,12 +69,22 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
feedCount,
|
feedCount,
|
||||||
entityFieldThreadCount,
|
entityFieldThreadCount,
|
||||||
createThread,
|
createThread,
|
||||||
|
topicFQN,
|
||||||
}: TopicDetailsProps) => {
|
}: TopicDetailsProps) => {
|
||||||
const { isAuthDisabled } = useAuth();
|
const { isAuthDisabled } = useAuth();
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
const [followersCount, setFollowersCount] = useState(0);
|
const [followersCount, setFollowersCount] = useState(0);
|
||||||
const [isFollowing, setIsFollowing] = useState(false);
|
const [isFollowing, setIsFollowing] = useState(false);
|
||||||
const [threadLink, setThreadLink] = useState<string>('');
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
|
|
||||||
const hasEditAccess = () => {
|
const hasEditAccess = () => {
|
||||||
if (owner?.type === 'user') {
|
if (owner?.type === 'user') {
|
||||||
return owner.id === getCurrentUserId();
|
return owner.id === getCurrentUserId();
|
||||||
@ -309,7 +323,9 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
'tags',
|
'tags',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={topicFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.TOPIC}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
followHandler={followTopic}
|
followHandler={followTopic}
|
||||||
followers={followersCount}
|
followers={followersCount}
|
||||||
@ -343,7 +359,9 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
'description',
|
'description',
|
||||||
entityFieldThreadCount
|
entityFieldThreadCount
|
||||||
)}
|
)}
|
||||||
|
entityFqn={topicFQN}
|
||||||
entityName={entityName}
|
entityName={entityName}
|
||||||
|
entityType={EntityType.TOPIC}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
isReadOnly={deleted}
|
isReadOnly={deleted}
|
||||||
@ -351,6 +369,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -359,15 +378,6 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
<div className="tw-my-4 tw-border tw-border-main tw-rounded-md tw-py-4">
|
<div className="tw-my-4 tw-border tw-border-main tw-rounded-md tw-py-4">
|
||||||
<SchemaEditor value={schemaText} />
|
<SchemaEditor value={schemaText} />
|
||||||
</div>
|
</div>
|
||||||
{threadLink ? (
|
|
||||||
<ActivityThreadPanel
|
|
||||||
createThread={createThread}
|
|
||||||
open={Boolean(threadLink)}
|
|
||||||
postFeedHandler={postFeedHandler}
|
|
||||||
threadLink={threadLink}
|
|
||||||
onCancel={onThreadPanelClose}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTab === 2 && (
|
{activeTab === 2 && (
|
||||||
@ -379,6 +389,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={entityName}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
@ -402,6 +413,28 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(owner as EntityReference)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
EntityType.TOPIC,
|
||||||
|
topicFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
@ -24,6 +24,7 @@ import { TagLabel } from '../../generated/type/tagLabel';
|
|||||||
import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface';
|
import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface';
|
||||||
|
|
||||||
export interface TopicDetailsProps {
|
export interface TopicDetailsProps {
|
||||||
|
topicFQN: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
schemaText: string;
|
schemaText: string;
|
||||||
schemaType: string;
|
schemaType: string;
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
import { EntityFieldThreads } from 'Models';
|
import { EntityFieldThreads } from 'Models';
|
||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { Table } from '../../../generated/entity/data/table';
|
import { Table } from '../../../generated/entity/data/table';
|
||||||
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
|
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
|
||||||
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
||||||
import SVGIcons from '../../../utils/SvgUtils';
|
import { getEntityFeedLink } from '../../../utils/EntityUtils';
|
||||||
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
import NonAdminAction from '../non-admin-action/NonAdminAction';
|
import NonAdminAction from '../non-admin-action/NonAdminAction';
|
||||||
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
||||||
@ -32,12 +33,15 @@ type Props = {
|
|||||||
description: string;
|
description: string;
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
|
entityType?: string;
|
||||||
|
entityFqn?: string;
|
||||||
entityFieldThreads?: EntityFieldThreads[];
|
entityFieldThreads?: EntityFieldThreads[];
|
||||||
onThreadLinkSelect?: (value: string) => void;
|
onThreadLinkSelect?: (value: string) => void;
|
||||||
onDescriptionEdit?: () => void;
|
onDescriptionEdit?: () => void;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
onDescriptionUpdate?: (value: string) => void;
|
onDescriptionUpdate?: (value: string) => void;
|
||||||
onSuggest?: (value: string) => void;
|
onSuggest?: (value: string) => void;
|
||||||
|
onEntityFieldSelect?: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Description = ({
|
const Description = ({
|
||||||
@ -54,6 +58,9 @@ const Description = ({
|
|||||||
entityName,
|
entityName,
|
||||||
entityFieldThreads,
|
entityFieldThreads,
|
||||||
onThreadLinkSelect,
|
onThreadLinkSelect,
|
||||||
|
onEntityFieldSelect,
|
||||||
|
entityType,
|
||||||
|
entityFqn,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const descriptionThread = entityFieldThreads?.[0];
|
const descriptionThread = entityFieldThreads?.[0];
|
||||||
|
|
||||||
@ -78,19 +85,9 @@ const Description = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="tw-no-description tw-p-2">
|
<span className="tw-no-description tw-p-2">
|
||||||
No description added
|
No description added{' '}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!isUndefined(descriptionThread) ? (
|
|
||||||
<p
|
|
||||||
className="tw-text-right link-text"
|
|
||||||
onClick={() =>
|
|
||||||
onThreadLinkSelect?.(descriptionThread.entityLink)
|
|
||||||
}>
|
|
||||||
<i className="far fa-comment" /> {descriptionThread.count}{' '}
|
|
||||||
threads
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
{isEdit && (
|
{isEdit && (
|
||||||
<ModalWithMarkdownEditor
|
<ModalWithMarkdownEditor
|
||||||
@ -105,7 +102,7 @@ const Description = ({
|
|||||||
{!isReadOnly ? (
|
{!isReadOnly ? (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'tw-w-5 tw-min-w-max',
|
'tw-w-5 tw-min-w-max tw-flex',
|
||||||
description?.trim() ? 'tw-pt-4' : 'tw-pt-2.5'
|
description?.trim() ? 'tw-pt-4' : 'tw-pt-2.5'
|
||||||
)}>
|
)}>
|
||||||
<NonAdminAction
|
<NonAdminAction
|
||||||
@ -125,6 +122,50 @@ const Description = ({
|
|||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</NonAdminAction>
|
</NonAdminAction>
|
||||||
|
{isUndefined(descriptionThread) &&
|
||||||
|
onEntityFieldSelect &&
|
||||||
|
!description?.trim() ? (
|
||||||
|
<button
|
||||||
|
className="focus:tw-outline-none tw-ml-1 tw-opacity-0 hover:tw-opacity-100 tw--mt-6"
|
||||||
|
data-testid="request-description"
|
||||||
|
onClick={() => onEntityFieldSelect?.('description')}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="request-description"
|
||||||
|
icon={Icons.REQUEST}
|
||||||
|
width="20px"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
{!isUndefined(descriptionThread) ? (
|
||||||
|
<p
|
||||||
|
className="link-text tw-ml-1 tw-w-8 tw-h-8 tw-flex-none"
|
||||||
|
onClick={() =>
|
||||||
|
onThreadLinkSelect?.(descriptionThread.entityLink)
|
||||||
|
}>
|
||||||
|
<span className="tw-flex">
|
||||||
|
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />{' '}
|
||||||
|
<span className="tw-ml-1"> {descriptionThread.count}</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<Fragment>
|
||||||
|
{description?.trim() && onThreadLinkSelect ? (
|
||||||
|
<p
|
||||||
|
className="link-text tw-flex-none tw-ml-2"
|
||||||
|
onClick={() =>
|
||||||
|
onThreadLinkSelect?.(
|
||||||
|
getEntityFeedLink(entityType, entityFqn, 'description')
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="comments"
|
||||||
|
icon={Icons.COMMENT_PLUS}
|
||||||
|
width="20px"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,8 +20,8 @@ import { Operation } from '../../../generated/entity/policies/accessControl/rule
|
|||||||
import { User } from '../../../generated/entity/teams/user';
|
import { User } from '../../../generated/entity/teams/user';
|
||||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||||
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
||||||
import { getInfoElements } from '../../../utils/EntityUtils';
|
import { getEntityFeedLink, getInfoElements } from '../../../utils/EntityUtils';
|
||||||
import SVGIcons from '../../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
import { getFollowerDetail } from '../../../utils/TableUtils';
|
import { getFollowerDetail } from '../../../utils/TableUtils';
|
||||||
import { getTagCategories, getTaglist } from '../../../utils/TagsUtils';
|
import { getTagCategories, getTaglist } from '../../../utils/TagsUtils';
|
||||||
import TagsContainer from '../../tags-container/tags-container';
|
import TagsContainer from '../../tags-container/tags-container';
|
||||||
@ -46,6 +46,8 @@ type Props = {
|
|||||||
hasEditAccess?: boolean;
|
hasEditAccess?: boolean;
|
||||||
followersList: Array<User>;
|
followersList: Array<User>;
|
||||||
entityName: string;
|
entityName: string;
|
||||||
|
entityType?: string;
|
||||||
|
entityFqn?: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
isVersionSelected?: boolean;
|
isVersionSelected?: boolean;
|
||||||
entityFieldThreads?: EntityFieldThreads[];
|
entityFieldThreads?: EntityFieldThreads[];
|
||||||
@ -75,6 +77,8 @@ const EntityPageInfo = ({
|
|||||||
versionHandler,
|
versionHandler,
|
||||||
entityFieldThreads,
|
entityFieldThreads,
|
||||||
onThreadLinkSelect,
|
onThreadLinkSelect,
|
||||||
|
entityFqn,
|
||||||
|
entityType,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const tagThread = entityFieldThreads?.[0];
|
const tagThread = entityFieldThreads?.[0];
|
||||||
const [isEditable, setIsEditable] = useState<boolean>(false);
|
const [isEditable, setIsEditable] = useState<boolean>(false);
|
||||||
@ -407,11 +411,28 @@ const EntityPageInfo = ({
|
|||||||
</NonAdminAction>
|
</NonAdminAction>
|
||||||
{!isUndefined(tagThread) ? (
|
{!isUndefined(tagThread) ? (
|
||||||
<p
|
<p
|
||||||
className="tw-text-right link-text tw-ml-1"
|
className="link-text tw-ml-1 tw-w-8 tw-h-8 tw-flex-none"
|
||||||
onClick={() => onThreadLinkSelect?.(tagThread.entityLink)}>
|
onClick={() => onThreadLinkSelect?.(tagThread.entityLink)}>
|
||||||
<i className="far fa-comment" /> {tagThread.count} threads
|
<span className="tw-flex">
|
||||||
|
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />
|
||||||
|
<span className="tw-ml-1">{tagThread.count}</span>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : (
|
||||||
|
<p
|
||||||
|
className="link-text tw-self-start tw-w-8 tw-h-8 tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 tw-flex-none"
|
||||||
|
onClick={() =>
|
||||||
|
onThreadLinkSelect?.(
|
||||||
|
getEntityFeedLink(entityType, entityFqn, 'tags')
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<SVGIcons
|
||||||
|
alt="comments"
|
||||||
|
icon={Icons.COMMENT_PLUS}
|
||||||
|
width="20px"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,3 +20,11 @@ export const hashtagRegEx = /\[#(.+?)?\]\((.+?)?\)/g;
|
|||||||
export const linkRegEx = /\((.+?\/\/.+?)\/(.+?)\/(.+?)\)/;
|
export const linkRegEx = /\((.+?\/\/.+?)\/(.+?)\/(.+?)\)/;
|
||||||
export const entityLinkRegEx = /<#E\/([^<>]+?)\/([^<>]+?)>/g;
|
export const entityLinkRegEx = /<#E\/([^<>]+?)\/([^<>]+?)>/g;
|
||||||
export const entityRegex = /<#E\/([^<>]+?)\/([^<>]+?)\|(\[(.+?)?\]\((.+?)?\))>/;
|
export const entityRegex = /<#E\/([^<>]+?)\/([^<>]+?)\|(\[(.+?)?\]\((.+?)?\))>/;
|
||||||
|
|
||||||
|
export const entityUrlMap = {
|
||||||
|
team: 'teams',
|
||||||
|
user: 'user',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditorPlaceHolder = `Use @mention to tag a user or a team.
|
||||||
|
Use #mention to tag a data asset.`;
|
||||||
|
@ -141,6 +141,14 @@ const DashboardDetailsPage = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCount(getEntityFeedLink(EntityType.DASHBOARD, dashboardFQN)).then(
|
||||||
|
(res: AxiosResponse) => {
|
||||||
|
setFeedCount(res.data.totalCount);
|
||||||
|
setEntityFieldThreadCount(res.data.counts);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dashboardDetailsTabs[activeTab - 1].path !== tab) {
|
if (dashboardDetailsTabs[activeTab - 1].path !== tab) {
|
||||||
@ -347,6 +355,7 @@ const DashboardDetailsPage = () => {
|
|||||||
setCurrentVersion(version);
|
setCurrentVersion(version);
|
||||||
setDashboardDetails(res.data);
|
setDashboardDetails(res.data);
|
||||||
setDescription(description);
|
setDescription(description);
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -401,6 +410,7 @@ const DashboardDetailsPage = () => {
|
|||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setTags(getTagsWithoutTier(res.data.tags));
|
setTags(getTagsWithoutTier(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -422,6 +432,7 @@ const DashboardDetailsPage = () => {
|
|||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setOwner(res.data.owner);
|
setOwner(res.data.owner);
|
||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
@ -540,27 +551,20 @@ const DashboardDetailsPage = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEntityFeedCount = () => {
|
|
||||||
getFeedCount(getEntityFeedLink(EntityType.DASHBOARD, dashboardFQN)).then(
|
|
||||||
(res: AxiosResponse) => {
|
|
||||||
setFeedCount(res.data.totalCount);
|
|
||||||
setEntityFieldThreadCount(res.data.counts);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const createThread = (data: CreateThread) => {
|
const createThread = (data: CreateThread) => {
|
||||||
postThread(data)
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setEntityThread((pre) => [...pre, res.data]);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
body: 'Thread is created successfully',
|
body: 'Conversation created successfully',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while creating thread',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -595,6 +599,7 @@ const DashboardDetailsPage = () => {
|
|||||||
charts={charts}
|
charts={charts}
|
||||||
createThread={createThread}
|
createThread={createThread}
|
||||||
dashboardDetails={dashboardDetails}
|
dashboardDetails={dashboardDetails}
|
||||||
|
dashboardFQN={dashboardFQN}
|
||||||
dashboardTags={tags}
|
dashboardTags={tags}
|
||||||
dashboardUrl={dashboardUrl}
|
dashboardUrl={dashboardUrl}
|
||||||
deleted={deleted}
|
deleted={deleted}
|
||||||
|
@ -574,15 +574,16 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
|||||||
postThread(data)
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setEntityThread((pre) => [...pre, res.data]);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
body: 'Thread is created successfully',
|
body: 'Conversation created successfully',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while creating thread',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -144,6 +144,15 @@ const PipelineDetailsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCount(getEntityFeedLink(EntityType.PIPELINE, pipelineFQN)).then(
|
||||||
|
(res: AxiosResponse) => {
|
||||||
|
setFeedCount(res.data.totalCount);
|
||||||
|
setEntityFieldThreadCount(res.data.counts);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pipelineDetailsTabs[activeTab - 1].path !== tab) {
|
if (pipelineDetailsTabs[activeTab - 1].path !== tab) {
|
||||||
setActiveTab(getCurrentPipelineTab(tab));
|
setActiveTab(getCurrentPipelineTab(tab));
|
||||||
@ -331,6 +340,7 @@ const PipelineDetailsPage = () => {
|
|||||||
setCurrentVersion(version);
|
setCurrentVersion(version);
|
||||||
setPipelineDetails(res.data);
|
setPipelineDetails(res.data);
|
||||||
setDescription(description);
|
setDescription(description);
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -350,6 +360,7 @@ const PipelineDetailsPage = () => {
|
|||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setOwner(res.data.owner);
|
setOwner(res.data.owner);
|
||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
@ -370,6 +381,7 @@ const PipelineDetailsPage = () => {
|
|||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setTags(getTagsWithoutTier(res.data.tags));
|
setTags(getTagsWithoutTier(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -384,6 +396,7 @@ const PipelineDetailsPage = () => {
|
|||||||
const onTaskUpdate = (jsonPatch: Array<Operation>) => {
|
const onTaskUpdate = (jsonPatch: Array<Operation>) => {
|
||||||
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
||||||
setTasks(res.data.tasks || []);
|
setTasks(res.data.tasks || []);
|
||||||
|
getEntityFeedCount();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -483,27 +496,20 @@ const PipelineDetailsPage = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEntityFeedCount = () => {
|
|
||||||
getFeedCount(getEntityFeedLink(EntityType.PIPELINE, pipelineFQN)).then(
|
|
||||||
(res: AxiosResponse) => {
|
|
||||||
setFeedCount(res.data.totalCount);
|
|
||||||
setEntityFieldThreadCount(res.data.counts);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const createThread = (data: CreateThread) => {
|
const createThread = (data: CreateThread) => {
|
||||||
postThread(data)
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setEntityThread((pre) => [...pre, res.data]);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
body: 'Thread is created successfully',
|
body: 'Conversation created successfully',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while creating thread',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -552,6 +558,7 @@ const PipelineDetailsPage = () => {
|
|||||||
loadNodeHandler={loadNodeHandler}
|
loadNodeHandler={loadNodeHandler}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
pipelineDetails={pipelineDetails}
|
pipelineDetails={pipelineDetails}
|
||||||
|
pipelineFQN={pipelineFQN}
|
||||||
pipelineTags={tags}
|
pipelineTags={tags}
|
||||||
pipelineUrl={pipelineUrl}
|
pipelineUrl={pipelineUrl}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
|
@ -115,6 +115,15 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCount(getEntityFeedLink(EntityType.TOPIC, topicFQN)).then(
|
||||||
|
(res: AxiosResponse) => {
|
||||||
|
setFeedCount(res.data.totalCount);
|
||||||
|
setEntityFieldThreadCount(res.data.counts);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const fetchActivityFeed = () => {
|
const fetchActivityFeed = () => {
|
||||||
setIsentityThreadLoading(true);
|
setIsentityThreadLoading(true);
|
||||||
getAllFeeds(getEntityFeedLink(EntityType.TOPIC, topicFQN))
|
getAllFeeds(getEntityFeedLink(EntityType.TOPIC, topicFQN))
|
||||||
@ -273,6 +282,7 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
setCurrentVersion(version);
|
setCurrentVersion(version);
|
||||||
setTopicDetails(res.data);
|
setTopicDetails(res.data);
|
||||||
setDescription(description);
|
setDescription(description);
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -292,6 +302,7 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setOwner(res.data.owner);
|
setOwner(res.data.owner);
|
||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
@ -312,6 +323,7 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
setTier(getTierTags(res.data.tags));
|
setTier(getTierTags(res.data.tags));
|
||||||
setCurrentVersion(res.data.version);
|
setCurrentVersion(res.data.version);
|
||||||
setTags(getTagsWithoutTier(res.data.tags));
|
setTags(getTagsWithoutTier(res.data.tags));
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -359,27 +371,20 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEntityFeedCount = () => {
|
|
||||||
getFeedCount(getEntityFeedLink(EntityType.TOPIC, topicFQN)).then(
|
|
||||||
(res: AxiosResponse) => {
|
|
||||||
setFeedCount(res.data.totalCount);
|
|
||||||
setEntityFieldThreadCount(res.data.counts);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const createThread = (data: CreateThread) => {
|
const createThread = (data: CreateThread) => {
|
||||||
postThread(data)
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setEntityThread((pre) => [...pre, res.data]);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
body: 'Thread is created successfully',
|
body: 'Conversation created successfully',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while creating thread',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -429,6 +434,7 @@ const TopicDetailsPage: FunctionComponent = () => {
|
|||||||
tagUpdateHandler={onTagUpdate}
|
tagUpdateHandler={onTagUpdate}
|
||||||
tier={tier as TagLabel}
|
tier={tier as TagLabel}
|
||||||
topicDetails={topicDetails}
|
topicDetails={topicDetails}
|
||||||
|
topicFQN={topicFQN}
|
||||||
topicTags={tags}
|
topicTags={tags}
|
||||||
unfollowTopicHandler={unfollowTopic}
|
unfollowTopicHandler={unfollowTopic}
|
||||||
users={AppState.users}
|
users={AppState.users}
|
||||||
|
@ -16,7 +16,12 @@ import classNames from 'classnames';
|
|||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { isNil } from 'lodash';
|
import { isNil } from 'lodash';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { EntityThread, ExtraInfo, Paging } from 'Models';
|
import {
|
||||||
|
EntityFieldThreadCount,
|
||||||
|
EntityThread,
|
||||||
|
ExtraInfo,
|
||||||
|
Paging,
|
||||||
|
} from 'Models';
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||||
import { default as AppState, default as appState } from '../../AppState';
|
import { default as AppState, default as appState } from '../../AppState';
|
||||||
@ -28,9 +33,11 @@ import {
|
|||||||
getAllFeeds,
|
getAllFeeds,
|
||||||
getFeedCount,
|
getFeedCount,
|
||||||
postFeedById,
|
postFeedById,
|
||||||
|
postThread,
|
||||||
} from '../../axiosAPIs/feedsAPI';
|
} from '../../axiosAPIs/feedsAPI';
|
||||||
import { getDatabaseTables } from '../../axiosAPIs/tableAPI';
|
import { getDatabaseTables } from '../../axiosAPIs/tableAPI';
|
||||||
import ActivityFeedList from '../../components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
import ActivityFeedList from '../../components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
|
import ActivityThreadPanel from '../../components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
import Description from '../../components/common/description/Description';
|
import Description from '../../components/common/description/Description';
|
||||||
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||||
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
||||||
@ -41,6 +48,7 @@ import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/t
|
|||||||
import PageContainer from '../../components/containers/PageContainer';
|
import PageContainer from '../../components/containers/PageContainer';
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
import ManageTabComponent from '../../components/ManageTab/ManageTab.component';
|
import ManageTabComponent from '../../components/ManageTab/ManageTab.component';
|
||||||
|
import RequestDescriptionModal from '../../components/Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import Tags from '../../components/tags/tags';
|
import Tags from '../../components/tags/tags';
|
||||||
import {
|
import {
|
||||||
getDatabaseDetailsPath,
|
getDatabaseDetailsPath,
|
||||||
@ -52,8 +60,10 @@ import {
|
|||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
|
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
|
||||||
import { ServiceCategory } from '../../enums/service.enum';
|
import { ServiceCategory } from '../../enums/service.enum';
|
||||||
|
import { CreateThread } from '../../generated/api/feed/createThread';
|
||||||
import { Database } from '../../generated/entity/data/database';
|
import { Database } from '../../generated/entity/data/database';
|
||||||
import { Table } from '../../generated/entity/data/table';
|
import { Table } from '../../generated/entity/data/table';
|
||||||
|
import { EntityReference } from '../../generated/entity/teams/user';
|
||||||
import useToastContext from '../../hooks/useToastContext';
|
import useToastContext from '../../hooks/useToastContext';
|
||||||
import {
|
import {
|
||||||
getEntityMissingError,
|
getEntityMissingError,
|
||||||
@ -65,6 +75,8 @@ import {
|
|||||||
getCurrentDatabaseDetailsTab,
|
getCurrentDatabaseDetailsTab,
|
||||||
} from '../../utils/DatabaseDetailsUtils';
|
} from '../../utils/DatabaseDetailsUtils';
|
||||||
import { getEntityFeedLink, getInfoElements } from '../../utils/EntityUtils';
|
import { getEntityFeedLink, getInfoElements } from '../../utils/EntityUtils';
|
||||||
|
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||||
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
||||||
import { getOwnerFromId, getUsagePercentile } from '../../utils/TableUtils';
|
import { getOwnerFromId, getUsagePercentile } from '../../utils/TableUtils';
|
||||||
import { getTableTags } from '../../utils/TagsUtils';
|
import { getTableTags } from '../../utils/TagsUtils';
|
||||||
@ -100,6 +112,12 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
const [isentityThreadLoading, setIsentityThreadLoading] =
|
const [isentityThreadLoading, setIsentityThreadLoading] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
const [feedCount, setFeedCount] = useState<number>(0);
|
const [feedCount, setFeedCount] = useState<number>(0);
|
||||||
|
const [entityFieldThreadCount, setEntityFieldThreadCount] = useState<
|
||||||
|
EntityFieldThreadCount[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const isMounting = useRef(true);
|
const isMounting = useRef(true);
|
||||||
@ -187,6 +205,35 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onThreadLinkSelect = (link: string) => {
|
||||||
|
setThreadLink(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onThreadPanelClose = () => {
|
||||||
|
setThreadLink('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCount(getEntityFeedLink(EntityType.DATABASE, databaseFQN))
|
||||||
|
.then((res: AxiosResponse) => {
|
||||||
|
setFeedCount(res.data.totalCount);
|
||||||
|
setEntityFieldThreadCount(res.data.counts);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
showToast({
|
||||||
|
variant: 'error',
|
||||||
|
body: 'Error while fetching feed count',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getDetailsByFQN = () => {
|
const getDetailsByFQN = () => {
|
||||||
getDatabaseDetailsByFQN(databaseFQN, ['owner'])
|
getDatabaseDetailsByFQN(databaseFQN, ['owner'])
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
@ -260,6 +307,7 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
setDatabase(updatedDatabaseDetails);
|
setDatabase(updatedDatabaseDetails);
|
||||||
setDescription(updatedHTML);
|
setDescription(updatedHTML);
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg =
|
const errMsg =
|
||||||
@ -367,15 +415,21 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const getEntityFeedCount = () => {
|
|
||||||
getFeedCount(getEntityFeedLink(EntityType.DATABASE, databaseFQN))
|
const createThread = (data: CreateThread) => {
|
||||||
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setFeedCount(res.data.totalCount);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
|
showToast({
|
||||||
|
variant: 'success',
|
||||||
|
body: 'Conversation created successfully',
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while fetching feed count',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -448,11 +502,19 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
<Description
|
<Description
|
||||||
blurWithBodyBG
|
blurWithBodyBG
|
||||||
description={description}
|
description={description}
|
||||||
|
entityFieldThreads={getEntityFieldThreadCounts(
|
||||||
|
'description',
|
||||||
|
entityFieldThreadCount
|
||||||
|
)}
|
||||||
|
entityFqn={databaseFQN}
|
||||||
entityName={databaseName}
|
entityName={databaseName}
|
||||||
|
entityType={EntityType.DATABASE}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="tw-mt-4 tw-flex tw-flex-col tw-flex-grow">
|
<div className="tw-mt-4 tw-flex tw-flex-col tw-flex-grow">
|
||||||
@ -605,6 +667,7 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={databaseName}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
@ -625,6 +688,30 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(
|
||||||
|
database?.owner as EntityReference
|
||||||
|
)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
EntityType.DATABASE,
|
||||||
|
databaseFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
)}
|
)}
|
||||||
|
@ -15,7 +15,13 @@ import { AxiosError, AxiosResponse } from 'axios';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { isNil, isUndefined } from 'lodash';
|
import { isNil, isUndefined } from 'lodash';
|
||||||
import { EntityThread, ExtraInfo, Paging, ServicesData } from 'Models';
|
import {
|
||||||
|
EntityFieldThreadCount,
|
||||||
|
EntityThread,
|
||||||
|
ExtraInfo,
|
||||||
|
Paging,
|
||||||
|
ServicesData,
|
||||||
|
} from 'Models';
|
||||||
import React, { Fragment, FunctionComponent, useEffect, useState } from 'react';
|
import React, { Fragment, FunctionComponent, useEffect, useState } from 'react';
|
||||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||||
import AppState from '../../AppState';
|
import AppState from '../../AppState';
|
||||||
@ -32,11 +38,13 @@ import {
|
|||||||
getAllFeeds,
|
getAllFeeds,
|
||||||
getFeedCount,
|
getFeedCount,
|
||||||
postFeedById,
|
postFeedById,
|
||||||
|
postThread,
|
||||||
} from '../../axiosAPIs/feedsAPI';
|
} from '../../axiosAPIs/feedsAPI';
|
||||||
import { getPipelines } from '../../axiosAPIs/pipelineAPI';
|
import { getPipelines } from '../../axiosAPIs/pipelineAPI';
|
||||||
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
|
import { getServiceByFQN, updateService } from '../../axiosAPIs/serviceAPI';
|
||||||
import { getTopics } from '../../axiosAPIs/topicsAPI';
|
import { getTopics } from '../../axiosAPIs/topicsAPI';
|
||||||
import ActivityFeedList from '../../components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
import ActivityFeedList from '../../components/ActivityFeed/ActivityFeedList/ActivityFeedList';
|
||||||
|
import ActivityThreadPanel from '../../components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
import Description from '../../components/common/description/Description';
|
import Description from '../../components/common/description/Description';
|
||||||
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||||
import IngestionError from '../../components/common/error/IngestionError';
|
import IngestionError from '../../components/common/error/IngestionError';
|
||||||
@ -49,6 +57,7 @@ import PageContainer from '../../components/containers/PageContainer';
|
|||||||
import Ingestion from '../../components/Ingestion/Ingestion.component';
|
import Ingestion from '../../components/Ingestion/Ingestion.component';
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
import ManageTabComponent from '../../components/ManageTab/ManageTab.component';
|
import ManageTabComponent from '../../components/ManageTab/ManageTab.component';
|
||||||
|
import RequestDescriptionModal from '../../components/Modals/RequestDescriptionModal/RequestDescriptionModal';
|
||||||
import ServiceConfig from '../../components/ServiceConfig/ServiceConfig';
|
import ServiceConfig from '../../components/ServiceConfig/ServiceConfig';
|
||||||
import Tags from '../../components/tags/tags';
|
import Tags from '../../components/tags/tags';
|
||||||
import {
|
import {
|
||||||
@ -59,6 +68,7 @@ import {
|
|||||||
import { TabSpecificField } from '../../enums/entity.enum';
|
import { TabSpecificField } from '../../enums/entity.enum';
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
import { SearchIndex } from '../../enums/search.enum';
|
||||||
import { ServiceCategory } from '../../enums/service.enum';
|
import { ServiceCategory } from '../../enums/service.enum';
|
||||||
|
import { CreateThread } from '../../generated/api/feed/createThread';
|
||||||
import { Dashboard } from '../../generated/entity/data/dashboard';
|
import { Dashboard } from '../../generated/entity/data/dashboard';
|
||||||
import { Database } from '../../generated/entity/data/database';
|
import { Database } from '../../generated/entity/data/database';
|
||||||
import { Pipeline } from '../../generated/entity/data/pipeline';
|
import { Pipeline } from '../../generated/entity/data/pipeline';
|
||||||
@ -81,6 +91,8 @@ import {
|
|||||||
isEven,
|
isEven,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getEntityFeedLink, getInfoElements } from '../../utils/EntityUtils';
|
import { getEntityFeedLink, getInfoElements } from '../../utils/EntityUtils';
|
||||||
|
import { getDefaultValue } from '../../utils/FeedElementUtils';
|
||||||
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import {
|
import {
|
||||||
getCurrentServiceTab,
|
getCurrentServiceTab,
|
||||||
getIsIngestionEnable,
|
getIsIngestionEnable,
|
||||||
@ -130,6 +142,19 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
const [isentityThreadLoading, setIsentityThreadLoading] =
|
const [isentityThreadLoading, setIsentityThreadLoading] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
const [feedCount, setFeedCount] = useState<number>(0);
|
const [feedCount, setFeedCount] = useState<number>(0);
|
||||||
|
const [entityFieldThreadCount, setEntityFieldThreadCount] = useState<
|
||||||
|
EntityFieldThreadCount[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [selectedField, setSelectedField] = useState<string>('');
|
||||||
|
|
||||||
|
const onEntityFieldSelect = (value: string) => {
|
||||||
|
setSelectedField(value);
|
||||||
|
};
|
||||||
|
const closeRequestModal = () => {
|
||||||
|
setSelectedField('');
|
||||||
|
};
|
||||||
|
|
||||||
const getCountLabel = () => {
|
const getCountLabel = () => {
|
||||||
switch (serviceName) {
|
switch (serviceName) {
|
||||||
@ -239,6 +264,28 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onThreadLinkSelect = (link: string) => {
|
||||||
|
setThreadLink(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onThreadPanelClose = () => {
|
||||||
|
setThreadLink('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getEntityFeedCount = () => {
|
||||||
|
getFeedCount(getEntityFeedLink(serviceCategory.slice(0, -1), serviceFQN))
|
||||||
|
.then((res: AxiosResponse) => {
|
||||||
|
setFeedCount(res.data.totalCount);
|
||||||
|
setEntityFieldThreadCount(res.data.counts);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
showToast({
|
||||||
|
variant: 'error',
|
||||||
|
body: 'Error while fetching feed count',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getSchemaFromType = (type: AirflowPipeline['pipelineType']) => {
|
const getSchemaFromType = (type: AirflowPipeline['pipelineType']) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PipelineType.Metadata:
|
case PipelineType.Metadata:
|
||||||
@ -254,7 +301,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
|
|
||||||
const getAllIngestionWorkflows = (paging?: string) => {
|
const getAllIngestionWorkflows = (paging?: string) => {
|
||||||
setIsloading(true);
|
setIsloading(true);
|
||||||
getAirflowPipelines(['owner, tags, status'], serviceFQN, '', paging)
|
getAirflowPipelines(['owner'], serviceFQN, '', paging)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data.data) {
|
if (res.data.data) {
|
||||||
setIngestions(res.data.data);
|
setIngestions(res.data.data);
|
||||||
@ -753,10 +800,12 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
|
|
||||||
const onDescriptionUpdate = (updatedHTML: string) => {
|
const onDescriptionUpdate = (updatedHTML: string) => {
|
||||||
if (description !== updatedHTML && !isUndefined(serviceDetails)) {
|
if (description !== updatedHTML && !isUndefined(serviceDetails)) {
|
||||||
const { id } = serviceDetails;
|
const { id, ...restDetails } = serviceDetails;
|
||||||
|
|
||||||
const updatedServiceDetails = {
|
const updatedServiceDetails = {
|
||||||
...serviceDetails,
|
databaseConnection: restDetails.databaseConnection,
|
||||||
|
name: restDetails.name,
|
||||||
|
serviceType: restDetails.serviceType,
|
||||||
description: updatedHTML,
|
description: updatedHTML,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -765,6 +814,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
setDescription(updatedHTML);
|
setDescription(updatedHTML);
|
||||||
setServiceDetails(updatedServiceDetails);
|
setServiceDetails(updatedServiceDetails);
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
|
getEntityFeedCount();
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
const errMsg = err.message || 'Something went wrong!';
|
const errMsg = err.message || 'Something went wrong!';
|
||||||
@ -865,15 +915,20 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEntityFeedCount = () => {
|
const createThread = (data: CreateThread) => {
|
||||||
getFeedCount(getEntityFeedLink(serviceCategory.slice(0, -1), serviceFQN))
|
postThread(data)
|
||||||
.then((res: AxiosResponse) => {
|
.then((res: AxiosResponse) => {
|
||||||
setFeedCount(res.data.totalCount);
|
setEntityThread((pre) => [...pre, res.data]);
|
||||||
|
getEntityFeedCount();
|
||||||
|
showToast({
|
||||||
|
variant: 'success',
|
||||||
|
body: 'Conversation created successfully',
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
showToast({
|
showToast({
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
body: 'Error while fetching feed count',
|
body: 'Error while creating the conversation',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -922,11 +977,19 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
<Description
|
<Description
|
||||||
blurWithBodyBG
|
blurWithBodyBG
|
||||||
description={description || ''}
|
description={description || ''}
|
||||||
|
entityFieldThreads={getEntityFieldThreadCounts(
|
||||||
|
'description',
|
||||||
|
entityFieldThreadCount
|
||||||
|
)}
|
||||||
|
entityFqn={serviceFQN}
|
||||||
entityName={serviceFQN}
|
entityName={serviceFQN}
|
||||||
|
entityType={serviceCategory.slice(0, -1)}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onDescriptionEdit={onDescriptionEdit}
|
onDescriptionEdit={onDescriptionEdit}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onEntityFieldSelect={onEntityFieldSelect}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1017,6 +1080,7 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
isEntityFeed
|
isEntityFeed
|
||||||
withSidePanel
|
withSidePanel
|
||||||
className=""
|
className=""
|
||||||
|
entityName={serviceFQN}
|
||||||
feedList={entityThread}
|
feedList={entityThread}
|
||||||
isLoading={isentityThreadLoading}
|
isLoading={isentityThreadLoading}
|
||||||
postFeedHandler={postFeedHandler}
|
postFeedHandler={postFeedHandler}
|
||||||
@ -1075,6 +1139,30 @@ const ServicePage: FunctionComponent = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeedHandler}
|
||||||
|
threadLink={threadLink}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{selectedField ? (
|
||||||
|
<RequestDescriptionModal
|
||||||
|
createThread={createThread}
|
||||||
|
defaultValue={getDefaultValue(
|
||||||
|
serviceDetails?.owner as EntityReference
|
||||||
|
)}
|
||||||
|
header="Request description"
|
||||||
|
threadLink={getEntityFeedLink(
|
||||||
|
serviceCategory.slice(0, -1),
|
||||||
|
serviceFQN,
|
||||||
|
selectedField
|
||||||
|
)}
|
||||||
|
onCancel={closeRequestModal}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
)}
|
)}
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
mockFeedData,
|
mockFeedData,
|
||||||
mockSearchData as exploreSearchData,
|
mockSearchData as exploreSearchData,
|
||||||
} from '../../constants/mockTourData.constants';
|
} from '../../constants/mockTourData.constants';
|
||||||
|
import { FeedFilter } from '../../enums/mydata.enum';
|
||||||
import { CurrentTourPageType } from '../../enums/tour.enum';
|
import { CurrentTourPageType } from '../../enums/tour.enum';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@ -39,7 +40,6 @@ import {
|
|||||||
import { TagLabel } from '../../generated/type/tagLabel';
|
import { TagLabel } from '../../generated/type/tagLabel';
|
||||||
import { useTour } from '../../hooks/useTour';
|
import { useTour } from '../../hooks/useTour';
|
||||||
import { getSteps } from '../../utils/TourUtils';
|
import { getSteps } from '../../utils/TourUtils';
|
||||||
import { FeedFilter } from '../../enums/mydata.enum';
|
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
data: { hits: { hits: [] } },
|
data: { hits: { hits: [] } },
|
||||||
|
@ -471,9 +471,10 @@ export const getInfoElements = (data: ExtraInfo) => {
|
|||||||
|
|
||||||
export const getEntityFeedLink: Function = (
|
export const getEntityFeedLink: Function = (
|
||||||
type: string,
|
type: string,
|
||||||
fqn: string
|
fqn: string,
|
||||||
|
field?: string
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
if (isUndefined(type) || isUndefined(fqn)) return undefined;
|
if (isUndefined(type) || isUndefined(fqn)) return undefined;
|
||||||
|
|
||||||
return `<#E/${type}/${fqn}>`;
|
return `<#E/${type}/${fqn}${field ? `/${field}` : ''}>`;
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ import {
|
|||||||
FieldChange,
|
FieldChange,
|
||||||
} from '../generated/entity/services/databaseService';
|
} from '../generated/entity/services/databaseService';
|
||||||
import { TagLabel } from '../generated/type/tagLabel';
|
import { TagLabel } from '../generated/type/tagLabel';
|
||||||
import { Paragraph, UnOrderedList } from './MarkdownUtils';
|
import { Paragraph, Span, UnOrderedList } from './MarkdownUtils';
|
||||||
import { isValidJSONString } from './StringsUtils';
|
import { isValidJSONString } from './StringsUtils';
|
||||||
import { getEntityLink, getOwnerFromId } from './TableUtils';
|
import { getEntityLink, getOwnerFromId } from './TableUtils';
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ import { getEntityLink, getOwnerFromId } from './TableUtils';
|
|||||||
const parseMarkdown = (
|
const parseMarkdown = (
|
||||||
content: string,
|
content: string,
|
||||||
className: string,
|
className: string,
|
||||||
isNewLine: boolean
|
_isNewLine: boolean
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<Markdown
|
<Markdown
|
||||||
@ -68,7 +68,12 @@ const parseMarkdown = (
|
|||||||
component: Paragraph,
|
component: Paragraph,
|
||||||
props: {
|
props: {
|
||||||
className: `${className}`,
|
className: `${className}`,
|
||||||
isNewLine,
|
},
|
||||||
|
},
|
||||||
|
span: {
|
||||||
|
component: Span,
|
||||||
|
props: {
|
||||||
|
className: `${className}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -11,16 +11,23 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty, isUndefined } from 'lodash';
|
||||||
import { EntityFieldThreads } from 'Models';
|
import { EntityFieldThreads } from 'Models';
|
||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
import { EntityReference } from '../generated/entity/teams/user';
|
||||||
|
import { getEntityFeedLink } from './EntityUtils';
|
||||||
import { getThreadField } from './FeedUtils';
|
import { getThreadField } from './FeedUtils';
|
||||||
|
import SVGIcons, { Icons } from './SvgUtils';
|
||||||
|
|
||||||
export const getFieldThreadElement = (
|
export const getFieldThreadElement = (
|
||||||
columnName: string,
|
columnName: string,
|
||||||
columnField: string,
|
columnField: string,
|
||||||
entityFieldThreads: EntityFieldThreads[],
|
entityFieldThreads: EntityFieldThreads[],
|
||||||
onThreadLinkSelect?: (value: string) => void
|
onThreadLinkSelect?: (value: string) => void,
|
||||||
|
entityType?: string,
|
||||||
|
entityFqn?: string,
|
||||||
|
entityField?: string,
|
||||||
|
flag = true
|
||||||
) => {
|
) => {
|
||||||
let threadValue: EntityFieldThreads = {} as EntityFieldThreads;
|
let threadValue: EntityFieldThreads = {} as EntityFieldThreads;
|
||||||
|
|
||||||
@ -33,13 +40,46 @@ export const getFieldThreadElement = (
|
|||||||
|
|
||||||
return !isEmpty(threadValue) ? (
|
return !isEmpty(threadValue) ? (
|
||||||
<p
|
<p
|
||||||
className="tw-text-right link-text"
|
className="link-text tw-w-8 tw-h-8 tw-flex-none"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onThreadLinkSelect?.(threadValue.entityLink);
|
onThreadLinkSelect?.(threadValue.entityLink);
|
||||||
}}>
|
}}>
|
||||||
<i className="far fa-comment" /> {threadValue.count} threads
|
<span className="tw-flex">
|
||||||
|
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />
|
||||||
|
<span className="tw-ml-1">{threadValue.count}</span>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
) : null;
|
) : (
|
||||||
|
<Fragment>
|
||||||
|
{entityType && entityFqn && entityField && flag ? (
|
||||||
|
<p
|
||||||
|
className="link-text tw-self-start tw-w-8 tw-h-8 tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 tw-flex-none"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
onThreadLinkSelect?.(
|
||||||
|
getEntityFeedLink(entityType, entityFqn, entityField)
|
||||||
|
);
|
||||||
|
}}>
|
||||||
|
<SVGIcons alt="comments" icon={Icons.COMMENT_PLUS} width="20px" />
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDefaultValue = (owner: EntityReference) => {
|
||||||
|
const message = 'Can you add a description?';
|
||||||
|
if (isUndefined(owner)) {
|
||||||
|
return `${message}`;
|
||||||
|
} else {
|
||||||
|
const name = owner.name;
|
||||||
|
const displayName = owner.displayName;
|
||||||
|
const entityType = owner.type;
|
||||||
|
const mention = `<a href=${`${document.location.protocol}//${document.location.host}/${entityType}/${name}`}>@${displayName}</a>`;
|
||||||
|
|
||||||
|
return `${mention} ${message}`;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
entityLinkRegEx,
|
entityLinkRegEx,
|
||||||
entityRegex,
|
entityRegex,
|
||||||
EntityRegEx,
|
EntityRegEx,
|
||||||
|
entityUrlMap,
|
||||||
hashtagRegEx,
|
hashtagRegEx,
|
||||||
linkRegEx,
|
linkRegEx,
|
||||||
mentionRegEx,
|
mentionRegEx,
|
||||||
@ -78,11 +79,15 @@ export const HTMLToMarkdown = new TurndownService({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getReplyText = (count: number) => {
|
export const getReplyText = (
|
||||||
if (count === 0) return 'Reply in thread';
|
count: number,
|
||||||
if (count === 1) return `${count} Reply`;
|
singular?: string,
|
||||||
|
plural?: string
|
||||||
|
) => {
|
||||||
|
if (count === 0) return 'Reply in conversation';
|
||||||
|
if (count === 1) return `${count} ${singular ? singular : 'older reply'}`;
|
||||||
|
|
||||||
return `${count} Replies`;
|
return `${count} ${plural ? plural : 'older replies'}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getEntityFieldThreadCounts = (
|
export const getEntityFieldThreadCounts = (
|
||||||
@ -109,6 +114,23 @@ export const getThreadField = (value: string, separator = '/') => {
|
|||||||
return value.split(separator).slice(-2);
|
return value.split(separator).slice(-2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getThreadValue = (
|
||||||
|
columnName: string,
|
||||||
|
columnField: string,
|
||||||
|
entityFieldThreads: EntityFieldThreads[]
|
||||||
|
) => {
|
||||||
|
let threadValue;
|
||||||
|
|
||||||
|
entityFieldThreads?.forEach((thread) => {
|
||||||
|
const threadField = getThreadField(thread.entityField);
|
||||||
|
if (threadField[0] === columnName && threadField[1] === columnField) {
|
||||||
|
threadValue = thread;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return threadValue;
|
||||||
|
};
|
||||||
|
|
||||||
export async function suggestions(searchTerm: string, mentionChar: string) {
|
export async function suggestions(searchTerm: string, mentionChar: string) {
|
||||||
if (mentionChar === '@') {
|
if (mentionChar === '@') {
|
||||||
let atValues = [];
|
let atValues = [];
|
||||||
@ -117,10 +139,14 @@ export async function suggestions(searchTerm: string, mentionChar: string) {
|
|||||||
const hits = data.data.hits.hits;
|
const hits = data.data.hits.hits;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
atValues = hits.map((hit: any) => {
|
atValues = hits.map((hit: any) => {
|
||||||
|
const entityType = hit._source.entity_type;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: hit._id,
|
id: hit._id,
|
||||||
value: `@${hit._source.display_name}`,
|
value: `@${hit._source.display_name}`,
|
||||||
link: `${document.location.protocol}//${document.location.host}/${hit._source.entity_type}/${hit._source.name}`,
|
link: `${document.location.protocol}//${document.location.host}/${
|
||||||
|
entityUrlMap[entityType as keyof typeof entityUrlMap]
|
||||||
|
}/${hit._source.name}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -128,10 +154,14 @@ export async function suggestions(searchTerm: string, mentionChar: string) {
|
|||||||
const hits = data.data.suggest['table-suggest'][0]['options'];
|
const hits = data.data.suggest['table-suggest'][0]['options'];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
atValues = hits.map((hit: any) => {
|
atValues = hits.map((hit: any) => {
|
||||||
|
const entityType = hit._source.entity_type;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: hit._id,
|
id: hit._id,
|
||||||
value: `@${hit._source.display_name}`,
|
value: `@${hit._source.display_name}`,
|
||||||
link: `${document.location.protocol}//${document.location.host}/${hit._source.entity_type}/${hit._source.name}`,
|
link: `${document.location.protocol}//${document.location.host}/${
|
||||||
|
entityUrlMap[entityType as keyof typeof entityUrlMap]
|
||||||
|
}/${hit._source.name}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -202,10 +232,12 @@ export const getBackendFormat = (message: string) => {
|
|||||||
const hashtagList = [...new Set(getHashTagList(message) ?? [])];
|
const hashtagList = [...new Set(getHashTagList(message) ?? [])];
|
||||||
const mentionDetails = mentionList.map((m) => getEntityDetail(m) ?? []);
|
const mentionDetails = mentionList.map((m) => getEntityDetail(m) ?? []);
|
||||||
const hashtagDetails = hashtagList.map((h) => getEntityDetail(h) ?? []);
|
const hashtagDetails = hashtagList.map((h) => getEntityDetail(h) ?? []);
|
||||||
|
const urlEntries = Object.entries(entityUrlMap);
|
||||||
|
|
||||||
mentionList.forEach((m, i) => {
|
mentionList.forEach((m, i) => {
|
||||||
const updatedDetails = mentionDetails[i].slice(-2);
|
const updatedDetails = mentionDetails[i].slice(-2);
|
||||||
const entityLink = `<#E/${updatedDetails[0]}/${updatedDetails[1]}|${m}>`;
|
const entityType = urlEntries.find((e) => e[1] === updatedDetails[0])?.[0];
|
||||||
|
const entityLink = `<#E/${entityType}/${updatedDetails[1]}|${m}>`;
|
||||||
updatedMessage = updatedMessage.replaceAll(m, entityLink);
|
updatedMessage = updatedMessage.replaceAll(m, entityLink);
|
||||||
});
|
});
|
||||||
hashtagList.forEach((h, i) => {
|
hashtagList.forEach((h, i) => {
|
||||||
|
@ -15,8 +15,11 @@ import React, { FC, HTMLAttributes } from 'react';
|
|||||||
|
|
||||||
export const Paragraph: FC<
|
export const Paragraph: FC<
|
||||||
HTMLAttributes<HTMLParagraphElement> & { isNewLine: boolean }
|
HTMLAttributes<HTMLParagraphElement> & { isNewLine: boolean }
|
||||||
> = ({ children, isNewLine = true, ...props }) =>
|
> = ({ children, ...props }) => <p {...props}>{children}</p>;
|
||||||
isNewLine ? <p {...props}>{children}</p> : <span {...props}>{children}</span>;
|
|
||||||
|
export const Span: FC<
|
||||||
|
HTMLAttributes<HTMLSpanElement> & { isNewLine: boolean }
|
||||||
|
> = ({ children, ...props }) => <span {...props}>{children}</span>;
|
||||||
|
|
||||||
export const UnOrderedList: FC<HTMLAttributes<HTMLUListElement>> = ({
|
export const UnOrderedList: FC<HTMLAttributes<HTMLUListElement>> = ({
|
||||||
children,
|
children,
|
||||||
|
@ -18,6 +18,7 @@ import IconGithub from '../assets/img/icon-github.png';
|
|||||||
import IconGoogle from '../assets/img/icon-google.png';
|
import IconGoogle from '../assets/img/icon-google.png';
|
||||||
import IconOkta from '../assets/img/icon-okta.png';
|
import IconOkta from '../assets/img/icon-okta.png';
|
||||||
import IconWelcomePopper from '../assets/img/welcome-popper-icon.png';
|
import IconWelcomePopper from '../assets/img/welcome-popper-icon.png';
|
||||||
|
import IconCommentPlus from '../assets/svg/add-chat.svg';
|
||||||
import IconAnnouncementWhite from '../assets/svg/announcements-white.svg';
|
import IconAnnouncementWhite from '../assets/svg/announcements-white.svg';
|
||||||
import IconAnnouncement from '../assets/svg/announcements.svg';
|
import IconAnnouncement from '../assets/svg/announcements.svg';
|
||||||
import IconAPI from '../assets/svg/api.svg';
|
import IconAPI from '../assets/svg/api.svg';
|
||||||
@ -25,6 +26,7 @@ import IconArrowDownPrimary from '../assets/svg/arrow-down-primary.svg';
|
|||||||
import IconArrowRightPrimary from '../assets/svg/arrow-right-primary.svg';
|
import IconArrowRightPrimary from '../assets/svg/arrow-right-primary.svg';
|
||||||
import IconSuccess from '../assets/svg/check.svg';
|
import IconSuccess from '../assets/svg/check.svg';
|
||||||
import IconCheckboxPrimary from '../assets/svg/checkbox-primary.svg';
|
import IconCheckboxPrimary from '../assets/svg/checkbox-primary.svg';
|
||||||
|
import IconComments from '../assets/svg/comment.svg';
|
||||||
import IconConfigColor from '../assets/svg/config-color.svg';
|
import IconConfigColor from '../assets/svg/config-color.svg';
|
||||||
import IconConfig from '../assets/svg/config.svg';
|
import IconConfig from '../assets/svg/config.svg';
|
||||||
import IconControlMinus from '../assets/svg/control-minus.svg';
|
import IconControlMinus from '../assets/svg/control-minus.svg';
|
||||||
@ -95,6 +97,7 @@ import LogoMonogram from '../assets/svg/logo-monogram.svg';
|
|||||||
import Logo from '../assets/svg/logo.svg';
|
import Logo from '../assets/svg/logo.svg';
|
||||||
import IconManageColor from '../assets/svg/manage-color.svg';
|
import IconManageColor from '../assets/svg/manage-color.svg';
|
||||||
import IconMinus from '../assets/svg/minus.svg';
|
import IconMinus from '../assets/svg/minus.svg';
|
||||||
|
import IconPaperPlanePrimary from '../assets/svg/paper-plane-primary.svg';
|
||||||
import IconPaperPlane from '../assets/svg/paper-plane.svg';
|
import IconPaperPlane from '../assets/svg/paper-plane.svg';
|
||||||
import IconPipelineGrey from '../assets/svg/pipeline-grey.svg';
|
import IconPipelineGrey from '../assets/svg/pipeline-grey.svg';
|
||||||
import IconPipeline from '../assets/svg/pipeline.svg';
|
import IconPipeline from '../assets/svg/pipeline.svg';
|
||||||
@ -102,6 +105,7 @@ import IconPlus from '../assets/svg/plus.svg';
|
|||||||
import IconProfilerColor from '../assets/svg/profiler-color.svg';
|
import IconProfilerColor from '../assets/svg/profiler-color.svg';
|
||||||
import IconProfiler from '../assets/svg/profiler.svg';
|
import IconProfiler from '../assets/svg/profiler.svg';
|
||||||
import IconHelpCircle from '../assets/svg/question-circle.svg';
|
import IconHelpCircle from '../assets/svg/question-circle.svg';
|
||||||
|
import IconRequest from '../assets/svg/request-icon.svg';
|
||||||
import IconSampleDataColor from '../assets/svg/sample-data-colored.svg';
|
import IconSampleDataColor from '../assets/svg/sample-data-colored.svg';
|
||||||
import IconSampleData from '../assets/svg/sample-data.svg';
|
import IconSampleData from '../assets/svg/sample-data.svg';
|
||||||
import IconSchemaColor from '../assets/svg/schema-color.svg';
|
import IconSchemaColor from '../assets/svg/schema-color.svg';
|
||||||
@ -238,6 +242,7 @@ export const Icons = {
|
|||||||
CONTROLMINUS: 'icon-control-minus',
|
CONTROLMINUS: 'icon-control-minus',
|
||||||
EDITLINEAGECOLOR: 'icon-edit-lineage-color',
|
EDITLINEAGECOLOR: 'icon-edit-lineage-color',
|
||||||
EDITLINEAGE: 'icon-edit-lineage',
|
EDITLINEAGE: 'icon-edit-lineage',
|
||||||
|
REQUEST: 'icon-request',
|
||||||
CHECKBOX_PRIMARY: 'icon-checkbox-primary',
|
CHECKBOX_PRIMARY: 'icon-checkbox-primary',
|
||||||
ARROW_RIGHT_PRIMARY: 'icon-arrow-right-primary',
|
ARROW_RIGHT_PRIMARY: 'icon-arrow-right-primary',
|
||||||
ARROW_DOWN_PRIMARY: 'icon-arrow-down-primary',
|
ARROW_DOWN_PRIMARY: 'icon-arrow-down-primary',
|
||||||
@ -247,6 +252,9 @@ export const Icons = {
|
|||||||
ICON_UP: 'icon-up',
|
ICON_UP: 'icon-up',
|
||||||
ICON_DOWN: 'icon-down',
|
ICON_DOWN: 'icon-down',
|
||||||
PAPER_PLANE: 'icon-paper-plane',
|
PAPER_PLANE: 'icon-paper-plane',
|
||||||
|
PAPER_PLANE_PRIMARY: 'icon-paper-plane-primary',
|
||||||
|
COMMENT: 'icon-comment',
|
||||||
|
COMMENT_PLUS: 'icon-comment-plus',
|
||||||
};
|
};
|
||||||
|
|
||||||
const SVGIcons: FunctionComponent<Props> = ({
|
const SVGIcons: FunctionComponent<Props> = ({
|
||||||
@ -694,6 +702,10 @@ const SVGIcons: FunctionComponent<Props> = ({
|
|||||||
case Icons.ANNOUNCEMENT:
|
case Icons.ANNOUNCEMENT:
|
||||||
IconComponent = IconAnnouncement;
|
IconComponent = IconAnnouncement;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Icons.REQUEST:
|
||||||
|
IconComponent = IconRequest;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Icons.ANNOUNCEMENT_WHITE:
|
case Icons.ANNOUNCEMENT_WHITE:
|
||||||
IconComponent = IconAnnouncementWhite;
|
IconComponent = IconAnnouncementWhite;
|
||||||
@ -714,6 +726,18 @@ const SVGIcons: FunctionComponent<Props> = ({
|
|||||||
case Icons.PAPER_PLANE:
|
case Icons.PAPER_PLANE:
|
||||||
IconComponent = IconPaperPlane;
|
IconComponent = IconPaperPlane;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Icons.PAPER_PLANE_PRIMARY:
|
||||||
|
IconComponent = IconPaperPlanePrimary;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Icons.COMMENT:
|
||||||
|
IconComponent = IconComments;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Icons.COMMENT_PLUS:
|
||||||
|
IconComponent = IconCommentPlus;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|