mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-18 03:41:09 +00:00
Refactor : UI Pipeline details page (#1102)
* Refactor : UI Pipeline details page * addressing review comment
This commit is contained in:
parent
6d6fdd3de5
commit
f6125a9683
@ -131,11 +131,11 @@ const DashboardDetails = ({
|
|||||||
|
|
||||||
const onDescriptionUpdate = (updatedHTML: string) => {
|
const onDescriptionUpdate = (updatedHTML: string) => {
|
||||||
if (description !== updatedHTML) {
|
if (description !== updatedHTML) {
|
||||||
const updatedTopicDetails = {
|
const updatedDashboardDetails = {
|
||||||
...dashboardDetails,
|
...dashboardDetails,
|
||||||
description: updatedHTML,
|
description: updatedHTML,
|
||||||
};
|
};
|
||||||
descriptionUpdateHandler(updatedTopicDetails);
|
descriptionUpdateHandler(updatedDashboardDetails);
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
} else {
|
} else {
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
@ -157,7 +157,7 @@ const DashboardDetails = ({
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: dashboardDetails.tags;
|
: dashboardDetails.tags;
|
||||||
const updatedTopicDetails = {
|
const updatedDashboardDetails = {
|
||||||
...dashboardDetails,
|
...dashboardDetails,
|
||||||
owner: newOwner
|
owner: newOwner
|
||||||
? {
|
? {
|
||||||
@ -168,7 +168,7 @@ const DashboardDetails = ({
|
|||||||
tags: tierTag,
|
tags: tierTag,
|
||||||
};
|
};
|
||||||
|
|
||||||
return settingsUpdateHandler(updatedTopicDetails);
|
return settingsUpdateHandler(updatedDashboardDetails);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
@ -190,8 +190,8 @@ const DashboardDetails = ({
|
|||||||
tagFQN: tag,
|
tagFQN: tag,
|
||||||
}));
|
}));
|
||||||
const updatedTags = [...prevTags, ...newTags];
|
const updatedTags = [...prevTags, ...newTags];
|
||||||
const updatedTopic = { ...dashboardDetails, tags: updatedTags };
|
const updatedDashboard = { ...dashboardDetails, tags: updatedTags };
|
||||||
tagUpdateHandler(updatedTopic);
|
tagUpdateHandler(updatedDashboard);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const followDashboard = () => {
|
const followDashboard = () => {
|
||||||
|
|||||||
@ -1,90 +1,63 @@
|
|||||||
import { AxiosResponse } from 'axios';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { EntityTags, TableDetail } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import AppState from '../../AppState';
|
import { getTeamDetailsPath } from '../../constants/constants';
|
||||||
import { getLineageByFQN } from '../../axiosAPIs/lineageAPI';
|
|
||||||
import {
|
|
||||||
addFollower,
|
|
||||||
getPipelineByFqn,
|
|
||||||
patchPipelineDetails,
|
|
||||||
removeFollower,
|
|
||||||
} from '../../axiosAPIs/pipelineAPI';
|
|
||||||
import { getServiceById } from '../../axiosAPIs/serviceAPI';
|
|
||||||
import Description from '../../components/common/description/Description';
|
|
||||||
import EntityPageInfo from '../../components/common/entityPageInfo/EntityPageInfo';
|
|
||||||
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
|
||||||
import TabsPane from '../../components/common/TabsPane/TabsPane';
|
|
||||||
import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface';
|
|
||||||
import PageContainer from '../../components/containers/PageContainer';
|
|
||||||
import Entitylineage from '../../components/EntityLineage/EntityLineage.component';
|
|
||||||
import Loader from '../../components/Loader/Loader';
|
|
||||||
import ManageTab from '../../components/ManageTab/ManageTab.component';
|
|
||||||
import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
|
||||||
import {
|
|
||||||
getServiceDetailsPath,
|
|
||||||
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 { User } from '../../generated/entity/teams/user';
|
import { User } from '../../generated/entity/teams/user';
|
||||||
import { EntityLineage } from '../../generated/type/entityLineage';
|
import { LabelType, State } from '../../generated/type/tagLabel';
|
||||||
import { TagLabel } from '../../generated/type/tagLabel';
|
|
||||||
import { useAuth } from '../../hooks/authHooks';
|
import { useAuth } from '../../hooks/authHooks';
|
||||||
import {
|
import {
|
||||||
addToRecentViewed,
|
|
||||||
getCurrentUserId,
|
getCurrentUserId,
|
||||||
getUserTeams,
|
getUserTeams,
|
||||||
isEven,
|
isEven,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import {
|
import { getTagsWithoutTier } from '../../utils/TableUtils';
|
||||||
getOwnerFromId,
|
import Description from '../common/description/Description';
|
||||||
getTagsWithoutTier,
|
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||||
getTierFromTableTags,
|
import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
} from '../../utils/TableUtils';
|
import TabsPane from '../common/TabsPane/TabsPane';
|
||||||
import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
|
import PageContainer from '../containers/PageContainer';
|
||||||
|
import Entitylineage from '../EntityLineage/EntityLineage.component';
|
||||||
const MyPipelinePage = () => {
|
import ManageTabComponent from '../ManageTab/ManageTab.component';
|
||||||
const USERId = getCurrentUserId();
|
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||||
|
import { PipeLineDetailsProp } from './PipelineDetails.interface';
|
||||||
|
|
||||||
|
const PipelineDetails = ({
|
||||||
|
entityName,
|
||||||
|
owner,
|
||||||
|
tagList,
|
||||||
|
tier,
|
||||||
|
slashedPipelineName,
|
||||||
|
pipelineTags,
|
||||||
|
activeTab,
|
||||||
|
pipelineUrl,
|
||||||
|
pipelineDetails,
|
||||||
|
serviceType,
|
||||||
|
setActiveTabHandler,
|
||||||
|
description,
|
||||||
|
descriptionUpdateHandler,
|
||||||
|
entityLineage,
|
||||||
|
followers,
|
||||||
|
users,
|
||||||
|
followPipelineHandler,
|
||||||
|
unfollowPipelineHandler,
|
||||||
|
tagUpdateHandler,
|
||||||
|
settingsUpdateHandler,
|
||||||
|
tasks,
|
||||||
|
taskUpdateHandler,
|
||||||
|
}: PipeLineDetailsProp) => {
|
||||||
const { isAuthDisabled } = useAuth();
|
const { isAuthDisabled } = useAuth();
|
||||||
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
const [tagList, setTagList] = useState<Array<string>>([]);
|
const [followersCount, setFollowersCount] = useState(0);
|
||||||
const { pipelineFQN } = useParams() as Record<string, string>;
|
|
||||||
const [pipelineDetails, setPipelineDetails] = useState<Pipeline>(
|
|
||||||
{} as Pipeline
|
|
||||||
);
|
|
||||||
const [pipelineId, setPipelineId] = useState<string>('');
|
|
||||||
const [isLoading, setLoading] = useState<boolean>(false);
|
|
||||||
const [description, setDescription] = useState<string>('');
|
|
||||||
const [followers, setFollowers] = useState<Array<User>>([]);
|
|
||||||
const [followersCount, setFollowersCount] = useState<number>(0);
|
|
||||||
const [isFollowing, setIsFollowing] = useState(false);
|
const [isFollowing, setIsFollowing] = useState(false);
|
||||||
const [owner, setOwner] = useState<TableDetail['owner']>();
|
|
||||||
const [tier, setTier] = useState<string>();
|
|
||||||
const [tags, setTags] = useState<Array<EntityTags>>([]);
|
|
||||||
const [activeTab, setActiveTab] = useState<number>(1);
|
|
||||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
|
||||||
const [tasks, setTasks] = useState<Task[]>([]);
|
|
||||||
const [pipelineUrl, setPipelineUrl] = useState<string>('');
|
|
||||||
const [displayName, setDisplayName] = useState<string>('');
|
|
||||||
const [serviceType, setServiceType] = useState<string>('');
|
|
||||||
const [slashedPipelineName, setSlashedPipelineName] = useState<
|
|
||||||
TitleBreadcrumbProps['titleLinks']
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const [editTask, setEditTask] = useState<{
|
const [editTask, setEditTask] = useState<{
|
||||||
task: Task;
|
task: Task;
|
||||||
index: number;
|
index: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const [entityLineage, setEntityLineage] = useState<EntityLineage>(
|
|
||||||
{} as EntityLineage
|
|
||||||
);
|
|
||||||
const hasEditAccess = () => {
|
const hasEditAccess = () => {
|
||||||
if (owner?.type === 'user') {
|
if (owner?.type === 'user') {
|
||||||
return owner.id === getCurrentUserId();
|
return owner.id === getCurrentUserId();
|
||||||
@ -92,6 +65,12 @@ const MyPipelinePage = () => {
|
|||||||
return getUserTeams().some((team) => team.id === owner?.id);
|
return getUserTeams().some((team) => team.id === owner?.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const setFollowersData = (followers: Array<User>) => {
|
||||||
|
setIsFollowing(
|
||||||
|
followers.some(({ id }: { id: string }) => id === getCurrentUserId())
|
||||||
|
);
|
||||||
|
setFollowersCount(followers?.length);
|
||||||
|
};
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
name: 'Details',
|
name: 'Details',
|
||||||
@ -141,191 +120,11 @@ const MyPipelinePage = () => {
|
|||||||
{
|
{
|
||||||
key: `${serviceType} Url`,
|
key: `${serviceType} Url`,
|
||||||
value: pipelineUrl,
|
value: pipelineUrl,
|
||||||
placeholderText: displayName,
|
placeholderText: entityName,
|
||||||
isLink: true,
|
isLink: true,
|
||||||
openInNewTab: true,
|
openInNewTab: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const fetchTags = () => {
|
|
||||||
getTagCategories().then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
setTagList(getTaglist(res.data));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setFollowersData = (followers: Array<User>) => {
|
|
||||||
// need to check if already following or not with logedIn user id
|
|
||||||
setIsFollowing(followers.some(({ id }: { id: string }) => id === USERId));
|
|
||||||
setFollowersCount(followers?.length);
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchPipelineDetail = (pipelineFQN: string) => {
|
|
||||||
setLoading(true);
|
|
||||||
getPipelineByFqn(pipelineFQN, [
|
|
||||||
'owner',
|
|
||||||
'service',
|
|
||||||
'followers',
|
|
||||||
'tags',
|
|
||||||
'tasks',
|
|
||||||
]).then((res: AxiosResponse) => {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
description,
|
|
||||||
followers,
|
|
||||||
fullyQualifiedName,
|
|
||||||
service,
|
|
||||||
tags,
|
|
||||||
owner,
|
|
||||||
displayName,
|
|
||||||
tasks,
|
|
||||||
pipelineUrl,
|
|
||||||
} = res.data;
|
|
||||||
setDisplayName(displayName);
|
|
||||||
setPipelineDetails(res.data);
|
|
||||||
setPipelineId(id);
|
|
||||||
setDescription(description ?? '');
|
|
||||||
setFollowers(followers);
|
|
||||||
setFollowersData(followers);
|
|
||||||
setOwner(getOwnerFromId(owner?.id));
|
|
||||||
setTier(getTierFromTableTags(tags));
|
|
||||||
setTags(getTagsWithoutTier(tags));
|
|
||||||
getServiceById('pipelineServices', service?.id).then(
|
|
||||||
(serviceRes: AxiosResponse) => {
|
|
||||||
setServiceType(serviceRes.data.serviceType);
|
|
||||||
setSlashedPipelineName([
|
|
||||||
{
|
|
||||||
name: serviceRes.data.name,
|
|
||||||
url: serviceRes.data.name
|
|
||||||
? getServiceDetailsPath(
|
|
||||||
serviceRes.data.name,
|
|
||||||
serviceRes.data.serviceType
|
|
||||||
)
|
|
||||||
: '',
|
|
||||||
imgSrc: serviceRes.data.serviceType
|
|
||||||
? serviceTypeLogo(serviceRes.data.serviceType)
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: displayName,
|
|
||||||
url: '',
|
|
||||||
activeTitle: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
addToRecentViewed({
|
|
||||||
entityType: EntityType.PIPELINE,
|
|
||||||
fqn: fullyQualifiedName,
|
|
||||||
serviceType: serviceRes.data.serviceType,
|
|
||||||
timestamp: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
setPipelineUrl(pipelineUrl);
|
|
||||||
setTasks(tasks);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const followPipeline = (): void => {
|
|
||||||
if (isFollowing) {
|
|
||||||
removeFollower(pipelineId, USERId).then((res: AxiosResponse) => {
|
|
||||||
const { followers } = res.data;
|
|
||||||
setFollowers(followers);
|
|
||||||
setFollowersCount((preValu) => preValu - 1);
|
|
||||||
setIsFollowing(false);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addFollower(pipelineId, USERId).then((res: AxiosResponse) => {
|
|
||||||
const { followers } = res.data;
|
|
||||||
setFollowers(followers);
|
|
||||||
setFollowersCount((preValu) => preValu + 1);
|
|
||||||
setIsFollowing(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDescriptionUpdate = (updatedHTML: string) => {
|
|
||||||
const updatedPipeline = { ...pipelineDetails, description: updatedHTML };
|
|
||||||
|
|
||||||
const jsonPatch = compare(pipelineDetails, updatedPipeline);
|
|
||||||
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
|
||||||
setDescription(res.data.description);
|
|
||||||
});
|
|
||||||
setIsEdit(false);
|
|
||||||
};
|
|
||||||
const onDescriptionEdit = (): void => {
|
|
||||||
setIsEdit(true);
|
|
||||||
};
|
|
||||||
const onCancel = () => {
|
|
||||||
setIsEdit(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSettingsUpdate = (
|
|
||||||
newOwner?: TableDetail['owner'],
|
|
||||||
newTier?: TableDetail['tier']
|
|
||||||
): Promise<void> => {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
if (newOwner || newTier) {
|
|
||||||
const tierTag: TableDetail['tags'] = newTier
|
|
||||||
? [
|
|
||||||
...getTagsWithoutTier(pipelineDetails.tags as EntityTags[]),
|
|
||||||
{ tagFQN: newTier, labelType: 'Manual', state: 'Confirmed' },
|
|
||||||
]
|
|
||||||
: (pipelineDetails.tags as EntityTags[]);
|
|
||||||
const updatedPipeline = {
|
|
||||||
...pipelineDetails,
|
|
||||||
owner: newOwner
|
|
||||||
? { ...pipelineDetails.owner, ...newOwner }
|
|
||||||
: pipelineDetails.owner,
|
|
||||||
tags: tierTag,
|
|
||||||
};
|
|
||||||
const jsonPatch = compare(pipelineDetails, updatedPipeline);
|
|
||||||
patchPipelineDetails(pipelineId, jsonPatch)
|
|
||||||
.then((res: AxiosResponse) => {
|
|
||||||
setPipelineDetails(res.data);
|
|
||||||
setOwner(getOwnerFromId(res.data.owner?.id));
|
|
||||||
setTier(getTierFromTableTags(res.data.tags));
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch(() => reject());
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTagUpdate = (selectedTags?: Array<string>) => {
|
|
||||||
if (selectedTags) {
|
|
||||||
const prevTags = pipelineDetails?.tags?.filter((tag) =>
|
|
||||||
selectedTags.includes(tag?.tagFQN as string)
|
|
||||||
);
|
|
||||||
const newTags: Array<EntityTags> = selectedTags
|
|
||||||
.filter((tag) => {
|
|
||||||
return !prevTags?.map((prevTag) => prevTag.tagFQN).includes(tag);
|
|
||||||
})
|
|
||||||
.map((tag) => ({
|
|
||||||
labelType: 'Manual',
|
|
||||||
state: 'Confirmed',
|
|
||||||
tagFQN: tag,
|
|
||||||
}));
|
|
||||||
const updatedTags = [...(prevTags as TagLabel[]), ...newTags];
|
|
||||||
const updatedPipeline = { ...pipelineDetails, tags: updatedTags };
|
|
||||||
const jsonPatch = compare(pipelineDetails, updatedPipeline);
|
|
||||||
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
|
||||||
setTier(getTierFromTableTags(res.data.tags));
|
|
||||||
setTags(getTagsWithoutTier(res.data.tags));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateTask = (task: Task, index: number) => {
|
|
||||||
setEditTask({ task, index });
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeEditTaskModal = (): void => {
|
|
||||||
setEditTask(undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTaskUpdate = (taskDescription: string) => {
|
const onTaskUpdate = (taskDescription: string) => {
|
||||||
if (editTask) {
|
if (editTask) {
|
||||||
@ -339,42 +138,120 @@ const MyPipelinePage = () => {
|
|||||||
|
|
||||||
const updatedPipeline = { ...pipelineDetails, tasks: updatedTasks };
|
const updatedPipeline = { ...pipelineDetails, tasks: updatedTasks };
|
||||||
const jsonPatch = compare(pipelineDetails, updatedPipeline);
|
const jsonPatch = compare(pipelineDetails, updatedPipeline);
|
||||||
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
taskUpdateHandler(jsonPatch);
|
||||||
setTasks(res.data.tasks || []);
|
|
||||||
});
|
|
||||||
setEditTask(undefined);
|
setEditTask(undefined);
|
||||||
} else {
|
} else {
|
||||||
setEditTask(undefined);
|
setEditTask(undefined);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleUpdateTask = (task: Task, index: number) => {
|
||||||
fetchPipelineDetail(pipelineFQN);
|
setEditTask({ task, index });
|
||||||
setActiveTab(1);
|
};
|
||||||
getLineageByFQN(pipelineFQN, EntityType.PIPELINE).then(
|
|
||||||
(res: AxiosResponse) => setEntityLineage(res.data)
|
const closeEditTaskModal = (): void => {
|
||||||
);
|
setEditTask(undefined);
|
||||||
}, [pipelineFQN]);
|
};
|
||||||
|
|
||||||
|
const onSettingsUpdate = (newOwner?: Pipeline['owner'], newTier?: string) => {
|
||||||
|
if (newOwner || newTier) {
|
||||||
|
const tierTag: Pipeline['tags'] = newTier
|
||||||
|
? [
|
||||||
|
...getTagsWithoutTier(pipelineDetails.tags as Array<EntityTags>),
|
||||||
|
{
|
||||||
|
tagFQN: newTier,
|
||||||
|
labelType: LabelType.Manual,
|
||||||
|
state: State.Confirmed,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: pipelineDetails.tags;
|
||||||
|
const updatedPipelineDetails = {
|
||||||
|
...pipelineDetails,
|
||||||
|
owner: newOwner
|
||||||
|
? {
|
||||||
|
...pipelineDetails.owner,
|
||||||
|
...newOwner,
|
||||||
|
}
|
||||||
|
: pipelineDetails.owner,
|
||||||
|
tags: tierTag,
|
||||||
|
};
|
||||||
|
|
||||||
|
return settingsUpdateHandler(updatedPipelineDetails);
|
||||||
|
} else {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTagUpdate = (selectedTags?: Array<string>) => {
|
||||||
|
if (selectedTags) {
|
||||||
|
const prevTags =
|
||||||
|
pipelineDetails?.tags?.filter((tag) =>
|
||||||
|
selectedTags.includes(tag?.tagFQN as string)
|
||||||
|
) || [];
|
||||||
|
const newTags = selectedTags
|
||||||
|
.filter((tag) => {
|
||||||
|
return !prevTags?.map((prevTag) => prevTag.tagFQN).includes(tag);
|
||||||
|
})
|
||||||
|
.map((tag) => ({
|
||||||
|
labelType: LabelType.Manual,
|
||||||
|
state: State.Confirmed,
|
||||||
|
tagFQN: tag,
|
||||||
|
}));
|
||||||
|
const updatedTags = [...prevTags, ...newTags];
|
||||||
|
const updatedPipeline = { ...pipelineDetails, tags: updatedTags };
|
||||||
|
tagUpdateHandler(updatedPipeline);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDescriptionEdit = (): void => {
|
||||||
|
setIsEdit(true);
|
||||||
|
};
|
||||||
|
const onCancel = () => {
|
||||||
|
setIsEdit(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDescriptionUpdate = (updatedHTML: string) => {
|
||||||
|
if (description !== updatedHTML) {
|
||||||
|
const updatedPipelineDetails = {
|
||||||
|
...pipelineDetails,
|
||||||
|
description: updatedHTML,
|
||||||
|
};
|
||||||
|
descriptionUpdateHandler(updatedPipelineDetails);
|
||||||
|
setIsEdit(false);
|
||||||
|
} else {
|
||||||
|
setIsEdit(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const followPipeline = () => {
|
||||||
|
if (isFollowing) {
|
||||||
|
setFollowersCount((preValu) => preValu - 1);
|
||||||
|
setIsFollowing(false);
|
||||||
|
unfollowPipelineHandler();
|
||||||
|
} else {
|
||||||
|
setFollowersCount((preValu) => preValu + 1);
|
||||||
|
setIsFollowing(true);
|
||||||
|
followPipelineHandler();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAuthDisabled && AppState.users.length && followers.length) {
|
if (isAuthDisabled && users.length && followers.length) {
|
||||||
setFollowersData(followers);
|
setFollowersData(followers);
|
||||||
}
|
}
|
||||||
}, [AppState.users, followers]);
|
}, [users, followers]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTags();
|
setFollowersData(followers);
|
||||||
}, []);
|
}, [followers]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
{isLoading ? (
|
|
||||||
<Loader />
|
|
||||||
) : (
|
|
||||||
<div className="tw-px-4 tw-w-full tw-h-full tw-flex tw-flex-col">
|
<div className="tw-px-4 tw-w-full tw-h-full tw-flex tw-flex-col">
|
||||||
<EntityPageInfo
|
<EntityPageInfo
|
||||||
isTagEditable
|
isTagEditable
|
||||||
entityName={displayName}
|
entityName={entityName}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
followers={followersCount}
|
followers={followersCount}
|
||||||
followersList={followers}
|
followersList={followers}
|
||||||
@ -383,7 +260,7 @@ const MyPipelinePage = () => {
|
|||||||
isFollowing={isFollowing}
|
isFollowing={isFollowing}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
tagList={tagList}
|
tagList={tagList}
|
||||||
tags={tags}
|
tags={pipelineTags}
|
||||||
tagsHandler={onTagUpdate}
|
tagsHandler={onTagUpdate}
|
||||||
tier={tier || ''}
|
tier={tier || ''}
|
||||||
titleLinks={slashedPipelineName}
|
titleLinks={slashedPipelineName}
|
||||||
@ -391,7 +268,7 @@ const MyPipelinePage = () => {
|
|||||||
<div className="tw-mt-1 tw-flex tw-flex-col tw-flex-grow">
|
<div className="tw-mt-1 tw-flex tw-flex-col tw-flex-grow">
|
||||||
<TabsPane
|
<TabsPane
|
||||||
activeTab={activeTab}
|
activeTab={activeTab}
|
||||||
setActiveTab={setActiveTab}
|
setActiveTab={setActiveTabHandler}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -402,7 +279,7 @@ const MyPipelinePage = () => {
|
|||||||
<div className="tw-col-span-full">
|
<div className="tw-col-span-full">
|
||||||
<Description
|
<Description
|
||||||
description={description}
|
description={description}
|
||||||
entityName={displayName}
|
entityName={entityName}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
@ -487,7 +364,7 @@ const MyPipelinePage = () => {
|
|||||||
)}
|
)}
|
||||||
{activeTab === 3 && (
|
{activeTab === 3 && (
|
||||||
<div className="tw-mt-4">
|
<div className="tw-mt-4">
|
||||||
<ManageTab
|
<ManageTabComponent
|
||||||
currentTier={tier}
|
currentTier={tier}
|
||||||
currentUser={owner?.id}
|
currentUser={owner?.id}
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
@ -498,7 +375,7 @@ const MyPipelinePage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</PageContainer>
|
||||||
{editTask && (
|
{editTask && (
|
||||||
<ModalWithMarkdownEditor
|
<ModalWithMarkdownEditor
|
||||||
header={`Edit Task: "${editTask.task.displayName}"`}
|
header={`Edit Task: "${editTask.task.displayName}"`}
|
||||||
@ -508,8 +385,8 @@ const MyPipelinePage = () => {
|
|||||||
onSave={onTaskUpdate}
|
onSave={onTaskUpdate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</PageContainer>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MyPipelinePage;
|
export default PipelineDetails;
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
import { EntityTags, TableDetail } from 'Models';
|
||||||
|
import { Pipeline, Task } from '../../generated/entity/data/pipeline';
|
||||||
|
import { User } from '../../generated/entity/teams/user';
|
||||||
|
import { EntityLineage } from '../../generated/type/entityLineage';
|
||||||
|
import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface';
|
||||||
|
|
||||||
|
export interface PipeLineDetailsProp {
|
||||||
|
serviceType: string;
|
||||||
|
pipelineUrl: string;
|
||||||
|
entityName: string;
|
||||||
|
tagList: Array<string>;
|
||||||
|
users: Array<User>;
|
||||||
|
pipelineDetails: Pipeline;
|
||||||
|
activeTab: number;
|
||||||
|
owner: TableDetail['owner'];
|
||||||
|
description: string;
|
||||||
|
tier: string;
|
||||||
|
followers: Array<User>;
|
||||||
|
pipelineTags: Array<EntityTags>;
|
||||||
|
slashedPipelineName: TitleBreadcrumbProps['titleLinks'];
|
||||||
|
entityLineage: EntityLineage;
|
||||||
|
tasks: Task[];
|
||||||
|
setActiveTabHandler: (value: number) => void;
|
||||||
|
followPipelineHandler: () => void;
|
||||||
|
unfollowPipelineHandler: () => void;
|
||||||
|
settingsUpdateHandler: (updatedPipeline: Pipeline) => Promise<void>;
|
||||||
|
descriptionUpdateHandler: (updatedPipeline: Pipeline) => void;
|
||||||
|
tagUpdateHandler: (updatedPipeline: Pipeline) => void;
|
||||||
|
taskUpdateHandler: (patch: Array<Operation>) => void;
|
||||||
|
}
|
||||||
@ -0,0 +1,243 @@
|
|||||||
|
import { AxiosResponse } from 'axios';
|
||||||
|
import { compare, Operation } from 'fast-json-patch';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { EntityTags, TableDetail } from 'Models';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import AppState from '../../AppState';
|
||||||
|
import { getLineageByFQN } from '../../axiosAPIs/lineageAPI';
|
||||||
|
import {
|
||||||
|
addFollower,
|
||||||
|
getPipelineByFqn,
|
||||||
|
patchPipelineDetails,
|
||||||
|
removeFollower,
|
||||||
|
} from '../../axiosAPIs/pipelineAPI';
|
||||||
|
import { getServiceById } from '../../axiosAPIs/serviceAPI';
|
||||||
|
import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface';
|
||||||
|
import Loader from '../../components/Loader/Loader';
|
||||||
|
import PipelineDetails from '../../components/PipelineDetails/PipelineDetails.component';
|
||||||
|
import { getServiceDetailsPath } from '../../constants/constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
|
import { Pipeline, Task } from '../../generated/entity/data/pipeline';
|
||||||
|
import { User } from '../../generated/entity/teams/user';
|
||||||
|
import { EntityLineage } from '../../generated/type/entityLineage';
|
||||||
|
import { addToRecentViewed, getCurrentUserId } from '../../utils/CommonUtils';
|
||||||
|
import { serviceTypeLogo } from '../../utils/ServiceUtils';
|
||||||
|
import {
|
||||||
|
getOwnerFromId,
|
||||||
|
getTagsWithoutTier,
|
||||||
|
getTierFromTableTags,
|
||||||
|
} from '../../utils/TableUtils';
|
||||||
|
import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
|
||||||
|
|
||||||
|
const PipelineDetailsPage = () => {
|
||||||
|
const USERId = getCurrentUserId();
|
||||||
|
|
||||||
|
const [tagList, setTagList] = useState<Array<string>>([]);
|
||||||
|
const { pipelineFQN } = useParams() as Record<string, string>;
|
||||||
|
const [pipelineDetails, setPipelineDetails] = useState<Pipeline>(
|
||||||
|
{} as Pipeline
|
||||||
|
);
|
||||||
|
const [pipelineId, setPipelineId] = useState<string>('');
|
||||||
|
const [isLoading, setLoading] = useState<boolean>(false);
|
||||||
|
const [description, setDescription] = useState<string>('');
|
||||||
|
const [followers, setFollowers] = useState<Array<User>>([]);
|
||||||
|
const [owner, setOwner] = useState<TableDetail['owner']>();
|
||||||
|
const [tier, setTier] = useState<string>();
|
||||||
|
const [tags, setTags] = useState<Array<EntityTags>>([]);
|
||||||
|
const [activeTab, setActiveTab] = useState<number>(1);
|
||||||
|
const [tasks, setTasks] = useState<Task[]>([]);
|
||||||
|
const [pipelineUrl, setPipelineUrl] = useState<string>('');
|
||||||
|
const [displayName, setDisplayName] = useState<string>('');
|
||||||
|
const [serviceType, setServiceType] = useState<string>('');
|
||||||
|
const [slashedPipelineName, setSlashedPipelineName] = useState<
|
||||||
|
TitleBreadcrumbProps['titleLinks']
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [entityLineage, setEntityLineage] = useState<EntityLineage>(
|
||||||
|
{} as EntityLineage
|
||||||
|
);
|
||||||
|
const activeTabHandler = (tabValue: number) => {
|
||||||
|
setActiveTab(tabValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveUpdatedPipelineData = (
|
||||||
|
updatedData: Pipeline
|
||||||
|
): Promise<AxiosResponse> => {
|
||||||
|
const jsonPatch = compare(pipelineDetails, updatedData);
|
||||||
|
|
||||||
|
return patchPipelineDetails(
|
||||||
|
pipelineId,
|
||||||
|
jsonPatch
|
||||||
|
) as unknown as Promise<AxiosResponse>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchTags = () => {
|
||||||
|
getTagCategories().then((res) => {
|
||||||
|
if (res.data) {
|
||||||
|
setTagList(getTaglist(res.data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPipelineDetail = (pipelineFQN: string) => {
|
||||||
|
setLoading(true);
|
||||||
|
getPipelineByFqn(pipelineFQN, [
|
||||||
|
'owner',
|
||||||
|
'service',
|
||||||
|
'followers',
|
||||||
|
'tags',
|
||||||
|
'tasks',
|
||||||
|
]).then((res: AxiosResponse) => {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
description,
|
||||||
|
followers,
|
||||||
|
fullyQualifiedName,
|
||||||
|
service,
|
||||||
|
tags,
|
||||||
|
owner,
|
||||||
|
displayName,
|
||||||
|
tasks,
|
||||||
|
pipelineUrl,
|
||||||
|
} = res.data;
|
||||||
|
setDisplayName(displayName);
|
||||||
|
setPipelineDetails(res.data);
|
||||||
|
setPipelineId(id);
|
||||||
|
setDescription(description ?? '');
|
||||||
|
setFollowers(followers);
|
||||||
|
setOwner(getOwnerFromId(owner?.id));
|
||||||
|
setTier(getTierFromTableTags(tags));
|
||||||
|
setTags(getTagsWithoutTier(tags));
|
||||||
|
getServiceById('pipelineServices', service?.id).then(
|
||||||
|
(serviceRes: AxiosResponse) => {
|
||||||
|
setServiceType(serviceRes.data.serviceType);
|
||||||
|
setSlashedPipelineName([
|
||||||
|
{
|
||||||
|
name: serviceRes.data.name,
|
||||||
|
url: serviceRes.data.name
|
||||||
|
? getServiceDetailsPath(
|
||||||
|
serviceRes.data.name,
|
||||||
|
serviceRes.data.serviceType
|
||||||
|
)
|
||||||
|
: '',
|
||||||
|
imgSrc: serviceRes.data.serviceType
|
||||||
|
? serviceTypeLogo(serviceRes.data.serviceType)
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: displayName,
|
||||||
|
url: '',
|
||||||
|
activeTitle: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
addToRecentViewed({
|
||||||
|
entityType: EntityType.PIPELINE,
|
||||||
|
fqn: fullyQualifiedName,
|
||||||
|
serviceType: serviceRes.data.serviceType,
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setPipelineUrl(pipelineUrl);
|
||||||
|
setTasks(tasks);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const followPipeline = () => {
|
||||||
|
addFollower(pipelineId, USERId).then((res: AxiosResponse) => {
|
||||||
|
const { followers } = res.data;
|
||||||
|
setFollowers(followers);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const unfollowPipeline = () => {
|
||||||
|
removeFollower(pipelineId, USERId).then((res: AxiosResponse) => {
|
||||||
|
const { followers } = res.data;
|
||||||
|
|
||||||
|
setFollowers(followers);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const descriptionUpdateHandler = (updatedPipeline: Pipeline) => {
|
||||||
|
saveUpdatedPipelineData(updatedPipeline).then((res: AxiosResponse) => {
|
||||||
|
const { description } = res.data;
|
||||||
|
setPipelineDetails(res.data);
|
||||||
|
setDescription(description);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const settingsUpdateHandler = (updatedPipeline: Pipeline): Promise<void> => {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
saveUpdatedPipelineData(updatedPipeline)
|
||||||
|
.then((res) => {
|
||||||
|
setPipelineDetails(res.data);
|
||||||
|
setOwner(getOwnerFromId(res.data.owner?.id));
|
||||||
|
setTier(getTierFromTableTags(res.data.tags));
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(() => reject());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTagUpdate = (updatedPipeline: Pipeline) => {
|
||||||
|
saveUpdatedPipelineData(updatedPipeline).then((res: AxiosResponse) => {
|
||||||
|
setTier(getTierFromTableTags(res.data.tags));
|
||||||
|
setTags(getTagsWithoutTier(res.data.tags));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTaskUpdate = (jsonPatch: Array<Operation>) => {
|
||||||
|
patchPipelineDetails(pipelineId, jsonPatch).then((res: AxiosResponse) => {
|
||||||
|
setTasks(res.data.tasks || []);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchPipelineDetail(pipelineFQN);
|
||||||
|
setActiveTab(1);
|
||||||
|
getLineageByFQN(pipelineFQN, EntityType.PIPELINE).then(
|
||||||
|
(res: AxiosResponse) => setEntityLineage(res.data)
|
||||||
|
);
|
||||||
|
}, [pipelineFQN]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchTags();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isLoading ? (
|
||||||
|
<Loader />
|
||||||
|
) : (
|
||||||
|
<PipelineDetails
|
||||||
|
activeTab={activeTab}
|
||||||
|
description={description}
|
||||||
|
descriptionUpdateHandler={descriptionUpdateHandler}
|
||||||
|
entityLineage={entityLineage}
|
||||||
|
entityName={displayName}
|
||||||
|
followers={followers}
|
||||||
|
followPipelineHandler={followPipeline}
|
||||||
|
owner={owner}
|
||||||
|
pipelineDetails={pipelineDetails}
|
||||||
|
pipelineTags={tags}
|
||||||
|
pipelineUrl={pipelineUrl}
|
||||||
|
serviceType={serviceType}
|
||||||
|
setActiveTabHandler={activeTabHandler}
|
||||||
|
settingsUpdateHandler={settingsUpdateHandler}
|
||||||
|
slashedPipelineName={slashedPipelineName}
|
||||||
|
tagList={tagList}
|
||||||
|
tagUpdateHandler={onTagUpdate}
|
||||||
|
tasks={tasks}
|
||||||
|
taskUpdateHandler={onTaskUpdate}
|
||||||
|
tier={tier as string}
|
||||||
|
unfollowPipelineHandler={unfollowPipeline}
|
||||||
|
users={AppState.users}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default observer(PipelineDetailsPage);
|
||||||
@ -27,7 +27,7 @@ import DatasetDetailsPage from '../pages/DatasetDetailsPage/DatasetDetailsPage.c
|
|||||||
import EntityVersionPage from '../pages/EntityVersionPage/EntityVersionPage.component';
|
import EntityVersionPage from '../pages/EntityVersionPage/EntityVersionPage.component';
|
||||||
import ExplorePage from '../pages/explore/ExplorePage.component';
|
import ExplorePage from '../pages/explore/ExplorePage.component';
|
||||||
import MyDataPage from '../pages/MyDataPage/MyDataPage.component';
|
import MyDataPage from '../pages/MyDataPage/MyDataPage.component';
|
||||||
import MyPipelinePage from '../pages/Pipeline-details';
|
import PipelineDetailsPage from '../pages/PipelineDetails/PipelineDetailsPage.component';
|
||||||
import ReportsPage from '../pages/reports';
|
import ReportsPage from '../pages/reports';
|
||||||
import Scorecard from '../pages/scorecard';
|
import Scorecard from '../pages/scorecard';
|
||||||
import ServicePage from '../pages/service';
|
import ServicePage from '../pages/service';
|
||||||
@ -76,7 +76,7 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
|
|||||||
/>
|
/>
|
||||||
<Route component={TopicDetailsPage} path={ROUTES.TOPIC_DETAILS} />
|
<Route component={TopicDetailsPage} path={ROUTES.TOPIC_DETAILS} />
|
||||||
<Route component={DashboardDetailsPage} path={ROUTES.DASHBOARD_DETAILS} />
|
<Route component={DashboardDetailsPage} path={ROUTES.DASHBOARD_DETAILS} />
|
||||||
<Route component={MyPipelinePage} path={ROUTES.PIPELINE_DETAILS} />
|
<Route component={PipelineDetailsPage} path={ROUTES.PIPELINE_DETAILS} />
|
||||||
<Route component={Onboarding} path={ROUTES.ONBOARDING} />
|
<Route component={Onboarding} path={ROUTES.ONBOARDING} />
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user