mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-29 19:35:56 +00:00
refactor(ui): task flow (#12248)
* refactor(ui): task flow * fix: task workflow * fix(ui): pass initial value on modal form based on task type * fix(ui): pass proper value in initial form values. --------- Co-authored-by: karanh37 <karanh37@gmail.com>
This commit is contained in:
parent
ba3a1e1ed6
commit
6139c59a87
@ -56,8 +56,6 @@ import { ReactComponent as TaskIcon } from '/assets/svg/ic-task.svg';
|
|||||||
export const ActivityFeedTab = ({
|
export const ActivityFeedTab = ({
|
||||||
fqn,
|
fqn,
|
||||||
owner,
|
owner,
|
||||||
tags,
|
|
||||||
description,
|
|
||||||
columns,
|
columns,
|
||||||
entityType,
|
entityType,
|
||||||
onUpdateEntityDetails,
|
onUpdateEntityDetails,
|
||||||
@ -385,20 +383,16 @@ export const ActivityFeedTab = ({
|
|||||||
{entityType === EntityType.TABLE ? (
|
{entityType === EntityType.TABLE ? (
|
||||||
<TaskTab
|
<TaskTab
|
||||||
columns={columns}
|
columns={columns}
|
||||||
description={description}
|
|
||||||
entityType={EntityType.TABLE}
|
entityType={EntityType.TABLE}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
tags={tags}
|
taskThread={selectedThread}
|
||||||
task={selectedThread}
|
|
||||||
onUpdateEntityDetails={onUpdateEntityDetails}
|
onUpdateEntityDetails={onUpdateEntityDetails}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TaskTab
|
<TaskTab
|
||||||
description={description}
|
|
||||||
entityType={isUserEntity ? entityTypeTask : entityType}
|
entityType={isUserEntity ? entityTypeTask : entityType}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
tags={tags}
|
taskThread={selectedThread}
|
||||||
task={selectedThread}
|
|
||||||
onUpdateEntityDetails={onUpdateEntityDetails}
|
onUpdateEntityDetails={onUpdateEntityDetails}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
import { EntityType } from 'enums/entity.enum';
|
import { EntityType } from 'enums/entity.enum';
|
||||||
import { Column } from 'generated/entity/data/table';
|
import { Column } from 'generated/entity/data/table';
|
||||||
import { EntityReference } from 'generated/entity/type';
|
import { EntityReference } from 'generated/entity/type';
|
||||||
import { TagLabel } from 'generated/type/tagLabel';
|
|
||||||
|
|
||||||
export type FeedKeys = 'all' | 'mentions' | 'tasks';
|
export type FeedKeys = 'all' | 'mentions' | 'tasks';
|
||||||
|
|
||||||
@ -28,8 +27,6 @@ export interface ActivityFeedTabBasicProps {
|
|||||||
onFeedUpdate: () => void;
|
onFeedUpdate: () => void;
|
||||||
onUpdateEntityDetails?: () => void;
|
onUpdateEntityDetails?: () => void;
|
||||||
owner?: EntityReference;
|
owner?: EntityReference;
|
||||||
tags?: TagLabel[];
|
|
||||||
description?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ActivityFeedTabProps = ActivityFeedTabBasicProps &
|
export type ActivityFeedTabProps = ActivityFeedTabBasicProps &
|
||||||
|
@ -29,7 +29,6 @@ import ActivityFeedEditor from 'components/ActivityFeed/ActivityFeedEditor/Activ
|
|||||||
import { useActivityFeedProvider } from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
import { useActivityFeedProvider } from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
||||||
import { OwnerLabel } from 'components/common/OwnerLabel/OwnerLabel.component';
|
import { OwnerLabel } from 'components/common/OwnerLabel/OwnerLabel.component';
|
||||||
import EntityPopOverCard from 'components/common/PopOverCard/EntityPopOverCard';
|
import EntityPopOverCard from 'components/common/PopOverCard/EntityPopOverCard';
|
||||||
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
|
|
||||||
import { TaskOperation } from 'constants/Feeds.constants';
|
import { TaskOperation } from 'constants/Feeds.constants';
|
||||||
import { TaskType } from 'generated/api/feed/createThread';
|
import { TaskType } from 'generated/api/feed/createThread';
|
||||||
import { TaskDetails, ThreadTaskStatus } from 'generated/entity/feed/thread';
|
import { TaskDetails, ThreadTaskStatus } from 'generated/entity/feed/thread';
|
||||||
@ -43,16 +42,14 @@ import {
|
|||||||
TaskActionMode,
|
TaskActionMode,
|
||||||
} from 'pages/TasksPage/TasksPage.interface';
|
} from 'pages/TasksPage/TasksPage.interface';
|
||||||
import { MenuInfo } from 'rc-menu/lib/interface';
|
import { MenuInfo } from 'rc-menu/lib/interface';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { updateTask } from 'rest/feedsAPI';
|
import { updateTask } from 'rest/feedsAPI';
|
||||||
import { getNameFromFQN } from 'utils/CommonUtils';
|
import { getNameFromFQN } from 'utils/CommonUtils';
|
||||||
import { ENTITY_LINK_SEPARATOR } from 'utils/EntityUtils';
|
import { getEntityFQN, prepareFeedLink } from 'utils/FeedUtils';
|
||||||
import { getEntityField, getEntityFQN, prepareFeedLink } from 'utils/FeedUtils';
|
|
||||||
import { getEntityLink } from 'utils/TableUtils';
|
import { getEntityLink } from 'utils/TableUtils';
|
||||||
import {
|
import {
|
||||||
getColumnObject,
|
|
||||||
isDescriptionTask,
|
isDescriptionTask,
|
||||||
isTagsTask,
|
isTagsTask,
|
||||||
TASK_ACTION_LIST,
|
TASK_ACTION_LIST,
|
||||||
@ -63,15 +60,13 @@ import { ReactComponent as TaskCloseIcon } from '/assets/svg/ic-close-task.svg';
|
|||||||
import { ReactComponent as TaskOpenIcon } from '/assets/svg/ic-open-task.svg';
|
import { ReactComponent as TaskOpenIcon } from '/assets/svg/ic-open-task.svg';
|
||||||
|
|
||||||
export const TaskTab = ({
|
export const TaskTab = ({
|
||||||
task,
|
taskThread,
|
||||||
owner,
|
owner,
|
||||||
entityType,
|
entityType,
|
||||||
tags,
|
|
||||||
description,
|
|
||||||
...rest
|
...rest
|
||||||
}: TaskTabProps) => {
|
}: TaskTabProps) => {
|
||||||
const { task: taskDetails } = task;
|
const { task: taskDetails } = taskThread;
|
||||||
const entityFQN = getEntityFQN(task.about) ?? '';
|
const entityFQN = getEntityFQN(taskThread.about) ?? '';
|
||||||
const entityCheck = !isUndefined(entityFQN) && !isUndefined(entityType);
|
const entityCheck = !isUndefined(entityFQN) && !isUndefined(entityType);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@ -90,27 +85,8 @@ export const TaskTab = ({
|
|||||||
[AppState.userDetails, AppState.nonSecureUserDetails]
|
[AppState.userDetails, AppState.nonSecureUserDetails]
|
||||||
);
|
);
|
||||||
|
|
||||||
const entityField = useMemo(() => {
|
|
||||||
return getEntityField(task.about);
|
|
||||||
}, [task]);
|
|
||||||
|
|
||||||
const columnObject = useMemo(() => {
|
|
||||||
// prepare column from entityField
|
|
||||||
const column = entityField?.split(ENTITY_LINK_SEPARATOR)?.slice(-2)?.[0];
|
|
||||||
|
|
||||||
// prepare column value by replacing double quotes
|
|
||||||
const columnValue = column?.replaceAll(/^"|"$/g, '') || '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get column name by spliting columnValue with FQN Separator
|
|
||||||
*/
|
|
||||||
const columnName = columnValue.split(FQN_SEPARATOR_CHAR).pop();
|
|
||||||
|
|
||||||
return getColumnObject(columnName ?? '', rest.columns || []);
|
|
||||||
}, [task, rest.columns]);
|
|
||||||
|
|
||||||
const isOwner = isEqual(owner?.id, currentUser?.id);
|
const isOwner = isEqual(owner?.id, currentUser?.id);
|
||||||
const isCreator = isEqual(task.createdBy, currentUser?.name);
|
const isCreator = isEqual(taskThread.createdBy, currentUser?.name);
|
||||||
|
|
||||||
const checkIfUserPartOfTeam = useCallback(
|
const checkIfUserPartOfTeam = useCallback(
|
||||||
(teamId: string): boolean => {
|
(teamId: string): boolean => {
|
||||||
@ -216,35 +192,13 @@ export const TaskTab = ({
|
|||||||
|
|
||||||
const hasTaskUpdateAccess = () => hasEditAccess() || isPartOfAssigneeTeam;
|
const hasTaskUpdateAccess = () => hasEditAccess() || isPartOfAssigneeTeam;
|
||||||
|
|
||||||
// prepare current tags for update tags task
|
|
||||||
const getCurrentTags = () => {
|
|
||||||
if (!isEmpty(columnObject) && entityField) {
|
|
||||||
return columnObject.tags ?? [];
|
|
||||||
} else {
|
|
||||||
return tags ?? [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// prepare current description for update description task
|
|
||||||
const currentDescription = () => {
|
|
||||||
if (entityField && !isEmpty(columnObject)) {
|
|
||||||
return columnObject.description || '';
|
|
||||||
} else {
|
|
||||||
return description || '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSave = (message: string) => {
|
const onSave = (message: string) => {
|
||||||
postFeed(message, task?.id ?? '').catch(() => {
|
postFeed(message, taskThread?.id ?? '').catch(() => {
|
||||||
// ignore since error is displayed in toast in the parent promise.
|
// ignore since error is displayed in toast in the parent promise.
|
||||||
// Added block for sonar code smell
|
// Added block for sonar code smell
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
form.setFieldValue('description', currentDescription());
|
|
||||||
}, [columnObject, entityField, currentDescription]);
|
|
||||||
|
|
||||||
const handleMenuItemClick: MenuProps['onClick'] = (info) => {
|
const handleMenuItemClick: MenuProps['onClick'] = (info) => {
|
||||||
if (info.key === TaskActionMode.EDIT) {
|
if (info.key === TaskActionMode.EDIT) {
|
||||||
setShowEditTaskModel(true);
|
setShowEditTaskModel(true);
|
||||||
@ -276,19 +230,26 @@ export const TaskTab = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parsedSuggestion = [
|
||||||
|
'RequestDescription',
|
||||||
|
'UpdateDescription',
|
||||||
|
].includes(taskDetails?.type ?? '')
|
||||||
|
? taskDetails?.suggestion
|
||||||
|
: JSON.parse(taskDetails?.suggestion || '[]');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space
|
<Space
|
||||||
className="m-t-sm items-end w-full"
|
className="m-t-sm items-end w-full"
|
||||||
data-testid="task-cta-buttons"
|
data-testid="task-cta-buttons"
|
||||||
size="small">
|
size="small">
|
||||||
{isCreator && (
|
{(isCreator || hasTaskUpdateAccess()) && (
|
||||||
<Button onClick={onTaskReject}>{t('label.close')}</Button>
|
<Button onClick={onTaskReject}>{t('label.close')}</Button>
|
||||||
)}
|
)}
|
||||||
{hasTaskUpdateAccess() ? (
|
{hasTaskUpdateAccess() ? (
|
||||||
<>
|
<>
|
||||||
{['RequestDescription', 'RequestTag'].includes(
|
{['RequestDescription', 'RequestTag'].includes(
|
||||||
taskDetails?.type ?? ''
|
taskDetails?.type ?? ''
|
||||||
) && isEmpty(taskDetails?.suggestion) ? (
|
) && isEmpty(parsedSuggestion) ? (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@ -328,6 +289,21 @@ export const TaskTab = ({
|
|||||||
isCreator,
|
isCreator,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const initialFormValue = useMemo(() => {
|
||||||
|
if (isTaskDescription) {
|
||||||
|
const description =
|
||||||
|
taskDetails?.suggestion ?? taskDetails?.oldValue ?? '';
|
||||||
|
|
||||||
|
return { description };
|
||||||
|
} else {
|
||||||
|
const updatedTags = JSON.parse(
|
||||||
|
taskDetails?.suggestion ?? taskDetails?.oldValue ?? '[]'
|
||||||
|
);
|
||||||
|
|
||||||
|
return { updatedTags };
|
||||||
|
}
|
||||||
|
}, [taskDetails, isTaskDescription]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="p-y-sm p-x-md" gutter={[0, 24]}>
|
<Row className="p-y-sm p-x-md" gutter={[0, 24]}>
|
||||||
<Col className="d-flex items-center" span={24}>
|
<Col className="d-flex items-center" span={24}>
|
||||||
@ -362,7 +338,7 @@ export const TaskTab = ({
|
|||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<OwnerLabel
|
<OwnerLabel
|
||||||
hasPermission={false}
|
hasPermission={false}
|
||||||
owner={{ name: task.createdBy, type: 'user', id: '' }}
|
owner={{ name: taskThread.createdBy, type: 'user', id: '' }}
|
||||||
onUpdate={noop}
|
onUpdate={noop}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -373,35 +349,32 @@ export const TaskTab = ({
|
|||||||
<DescriptionTask
|
<DescriptionTask
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isTaskActionEdit={false}
|
isTaskActionEdit={false}
|
||||||
suggestion={task.task?.suggestion ?? ''}
|
taskThread={taskThread}
|
||||||
taskDetail={task}
|
|
||||||
value={currentDescription()}
|
|
||||||
onChange={(value) => form.setFieldValue('description', value)}
|
onChange={(value) => form.setFieldValue('description', value)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isTaskTags && (
|
{isTaskTags && (
|
||||||
<TagsTask
|
<TagsTask
|
||||||
currentTags={getCurrentTags()}
|
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
isTaskActionEdit={false}
|
isTaskActionEdit={false}
|
||||||
task={taskDetails}
|
task={taskDetails}
|
||||||
value={JSON.parse(taskDetails?.suggestion ?? '[]')}
|
onChange={(value) => form.setFieldValue('updatedTags', value)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="m-l-lg">
|
<div className="m-l-lg">
|
||||||
{task?.posts?.map((reply) => (
|
{taskThread?.posts?.map((reply) => (
|
||||||
<ActivityFeedCardV1
|
<ActivityFeedCardV1
|
||||||
isPost
|
isPost
|
||||||
feed={task}
|
feed={taskThread}
|
||||||
hidePopover={false}
|
hidePopover={false}
|
||||||
key={reply.id}
|
key={reply.id}
|
||||||
post={reply}
|
post={reply}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{task.task?.status === ThreadTaskStatus.Open && (
|
{taskDetails?.status === ThreadTaskStatus.Open && (
|
||||||
<ActivityFeedEditor onSave={onSave} onTextChange={setComment} />
|
<ActivityFeedEditor onSave={onSave} onTextChange={setComment} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -414,16 +387,20 @@ export const TaskTab = ({
|
|||||||
open={showEditTaskModel}
|
open={showEditTaskModel}
|
||||||
title={`${t('label.edit-entity', {
|
title={`${t('label.edit-entity', {
|
||||||
entity: t('label.task-lowercase'),
|
entity: t('label.task-lowercase'),
|
||||||
})} #${taskDetails?.id} ${task.message}`}
|
})} #${taskDetails?.id} ${taskThread.message}`}
|
||||||
width={768}
|
width={768}
|
||||||
onCancel={() => setShowEditTaskModel(false)}
|
onCancel={() => setShowEditTaskModel(false)}
|
||||||
onOk={form.submit}>
|
onOk={form.submit}>
|
||||||
<Form form={form} layout="vertical" onFinish={onEditAndSuggest}>
|
<Form
|
||||||
|
form={form}
|
||||||
|
initialValues={initialFormValue}
|
||||||
|
layout="vertical"
|
||||||
|
onFinish={onEditAndSuggest}>
|
||||||
{isTaskTags ? (
|
{isTaskTags ? (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
data-testid="tags-label"
|
data-testid="tags-label"
|
||||||
label={t('label.tag-plural')}
|
label={t('label.tag-plural')}
|
||||||
name="updateTags"
|
name="updatedTags"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@ -431,12 +408,13 @@ export const TaskTab = ({
|
|||||||
fieldText: t('label.tag-plural'),
|
fieldText: t('label.tag-plural'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]}>
|
]}
|
||||||
|
trigger="onChange">
|
||||||
<TagsTask
|
<TagsTask
|
||||||
isTaskActionEdit
|
isTaskActionEdit
|
||||||
currentTags={getCurrentTags()}
|
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
task={taskDetails}
|
task={taskDetails}
|
||||||
|
onChange={(value) => form.setFieldValue('updatedTags', value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : (
|
) : (
|
||||||
@ -452,13 +430,11 @@ export const TaskTab = ({
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
valuePropName="suggestion">
|
trigger="onTextChange">
|
||||||
<DescriptionTask
|
<DescriptionTask
|
||||||
isTaskActionEdit
|
isTaskActionEdit
|
||||||
hasEditAccess={hasEditAccess()}
|
hasEditAccess={hasEditAccess()}
|
||||||
suggestion={task.task?.suggestion ?? ''}
|
taskThread={taskThread}
|
||||||
taskDetail={task}
|
|
||||||
value={currentDescription()}
|
|
||||||
onChange={(value) => form.setFieldValue('description', value)}
|
onChange={(value) => form.setFieldValue('description', value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
@ -14,14 +14,11 @@ import { EntityType } from 'enums/entity.enum';
|
|||||||
import { Column } from 'generated/entity/data/table';
|
import { Column } from 'generated/entity/data/table';
|
||||||
import { Thread } from 'generated/entity/feed/thread';
|
import { Thread } from 'generated/entity/feed/thread';
|
||||||
import { EntityReference } from 'generated/entity/type';
|
import { EntityReference } from 'generated/entity/type';
|
||||||
import { TagLabel } from 'generated/type/tagLabel';
|
|
||||||
|
|
||||||
export type TaskTabProps = {
|
export type TaskTabProps = {
|
||||||
task: Thread;
|
taskThread: Thread;
|
||||||
owner?: EntityReference;
|
owner?: EntityReference;
|
||||||
tags?: TagLabel[];
|
|
||||||
onUpdateEntityDetails?: () => void;
|
onUpdateEntityDetails?: () => void;
|
||||||
description?: string;
|
|
||||||
} & (
|
} & (
|
||||||
| TableTaskTabProps
|
| TableTaskTabProps
|
||||||
| { columns?: undefined; entityType: Exclude<EntityType, EntityType.TABLE> }
|
| { columns?: undefined; entityType: Exclude<EntityType, EntityType.TABLE> }
|
||||||
|
@ -556,11 +556,9 @@ const TableDetailsPageV1 = () => {
|
|||||||
<ActivityFeedProvider>
|
<ActivityFeedProvider>
|
||||||
<ActivityFeedTab
|
<ActivityFeedTab
|
||||||
columns={tableDetails?.columns}
|
columns={tableDetails?.columns}
|
||||||
description={tableDetails?.description}
|
|
||||||
entityType={EntityType.TABLE}
|
entityType={EntityType.TABLE}
|
||||||
fqn={tableDetails?.fullyQualifiedName ?? ''}
|
fqn={tableDetails?.fullyQualifiedName ?? ''}
|
||||||
owner={tableDetails?.owner}
|
owner={tableDetails?.owner}
|
||||||
tags={tableDetails?.tags}
|
|
||||||
onFeedUpdate={getEntityFeedCount}
|
onFeedUpdate={getEntityFeedCount}
|
||||||
onUpdateEntityDetails={fetchTableDetails}
|
onUpdateEntityDetails={fetchTableDetails}
|
||||||
/>
|
/>
|
||||||
|
@ -171,7 +171,7 @@ const UpdateTag = () => {
|
|||||||
}
|
}
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
title: message.trimEnd(),
|
title: message.trimEnd(),
|
||||||
updateTags: getTags(),
|
updatedTags: getTags(),
|
||||||
assignees: defaultAssignee,
|
assignees: defaultAssignee,
|
||||||
});
|
});
|
||||||
}, [entityData]);
|
}, [entityData]);
|
||||||
@ -244,7 +244,7 @@ const UpdateTag = () => {
|
|||||||
label={t('label.update-entity', {
|
label={t('label.update-entity', {
|
||||||
entity: t('label.tag-plural'),
|
entity: t('label.tag-plural'),
|
||||||
})}
|
})}
|
||||||
name="updateTags"
|
name="updatedTags"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
import DescriptionTask from './DescriptionTask';
|
import DescriptionTask from './DescriptionTask';
|
||||||
|
|
||||||
const mockProps = {
|
const mockProps = {
|
||||||
taskDetail: {
|
taskThread: {
|
||||||
id: '9542599e-f2f9-46d1-9fc0-d03620351a0d',
|
id: '9542599e-f2f9-46d1-9fc0-d03620351a0d',
|
||||||
type: 'Task',
|
type: 'Task',
|
||||||
href: 'http://localhost:8585/api/v1/feed/9542599e-f2f9-46d1-9fc0-d03620351a0d',
|
href: 'http://localhost:8585/api/v1/feed/9542599e-f2f9-46d1-9fc0-d03620351a0d',
|
||||||
@ -84,8 +84,8 @@ describe('Test Description Task Component', () => {
|
|||||||
render(
|
render(
|
||||||
<DescriptionTask
|
<DescriptionTask
|
||||||
{...mockProps}
|
{...mockProps}
|
||||||
taskDetail={{
|
taskThread={{
|
||||||
...mockProps.taskDetail,
|
...mockProps.taskThread,
|
||||||
task: {
|
task: {
|
||||||
id: 5,
|
id: 5,
|
||||||
assignees: [
|
assignees: [
|
||||||
@ -125,8 +125,8 @@ describe('Test Description Task Component', () => {
|
|||||||
render(
|
render(
|
||||||
<DescriptionTask
|
<DescriptionTask
|
||||||
{...mockProps}
|
{...mockProps}
|
||||||
taskDetail={{
|
taskThread={{
|
||||||
...mockProps.taskDetail,
|
...mockProps.taskThread,
|
||||||
task: {
|
task: {
|
||||||
id: 5,
|
id: 5,
|
||||||
assignees: [
|
assignees: [
|
||||||
|
@ -25,42 +25,30 @@ import { DescriptionTabs } from './DescriptionTabs';
|
|||||||
import { DiffView } from './DiffView';
|
import { DiffView } from './DiffView';
|
||||||
|
|
||||||
interface DescriptionTaskProps {
|
interface DescriptionTaskProps {
|
||||||
taskDetail: Thread;
|
taskThread: Thread;
|
||||||
isTaskActionEdit: boolean;
|
isTaskActionEdit: boolean;
|
||||||
hasEditAccess: boolean;
|
hasEditAccess: boolean;
|
||||||
suggestion: string;
|
|
||||||
value: string;
|
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DescriptionTask: FC<DescriptionTaskProps> = ({
|
const DescriptionTask: FC<DescriptionTaskProps> = ({
|
||||||
taskDetail,
|
taskThread,
|
||||||
isTaskActionEdit,
|
isTaskActionEdit,
|
||||||
hasEditAccess,
|
hasEditAccess,
|
||||||
suggestion,
|
|
||||||
value: currentDescription = '',
|
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { task } = taskThread;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isRequestDescription = isEqual(
|
const isRequestDescription = isEqual(task?.type, TaskType.RequestDescription);
|
||||||
taskDetail.task?.type,
|
|
||||||
TaskType.RequestDescription
|
|
||||||
);
|
|
||||||
|
|
||||||
const isUpdateDescription = isEqual(
|
const isUpdateDescription = isEqual(task?.type, TaskType.UpdateDescription);
|
||||||
taskDetail.task?.type,
|
|
||||||
TaskType.UpdateDescription
|
|
||||||
);
|
|
||||||
|
|
||||||
const isTaskClosed = isEqual(
|
const isTaskClosed = isEqual(task?.status, ThreadTaskStatus.Closed);
|
||||||
taskDetail.task?.status,
|
|
||||||
ThreadTaskStatus.Closed
|
|
||||||
);
|
|
||||||
|
|
||||||
const getDiffView = () => {
|
const getDiffView = () => {
|
||||||
const oldValue = taskDetail.task?.oldValue;
|
const oldValue = task?.oldValue;
|
||||||
const newValue = taskDetail.task?.newValue;
|
const newValue = task?.newValue;
|
||||||
if (!oldValue && !newValue) {
|
if (!oldValue && !newValue) {
|
||||||
return (
|
return (
|
||||||
<div className="tw-border tw-border-main tw-p-2 tw-rounded tw-my-1 tw-mb-3">
|
<div className="tw-border tw-border-main tw-p-2 tw-rounded tw-my-1 tw-mb-3">
|
||||||
@ -73,10 +61,7 @@ const DescriptionTask: FC<DescriptionTaskProps> = ({
|
|||||||
return (
|
return (
|
||||||
<DiffView
|
<DiffView
|
||||||
className="tw-border tw-border-main tw-p-2 tw-rounded tw-my-1 tw-mb-3"
|
className="tw-border tw-border-main tw-p-2 tw-rounded tw-my-1 tw-mb-3"
|
||||||
diffArr={getDescriptionDiff(
|
diffArr={getDescriptionDiff(oldValue ?? '', newValue ?? '')}
|
||||||
taskDetail?.task?.oldValue || '',
|
|
||||||
taskDetail?.task?.newValue || ''
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -87,8 +72,8 @@ const DescriptionTask: FC<DescriptionTaskProps> = ({
|
|||||||
* @returns Suggested description diff
|
* @returns Suggested description diff
|
||||||
*/
|
*/
|
||||||
const getSuggestedDescriptionDiff = () => {
|
const getSuggestedDescriptionDiff = () => {
|
||||||
const newDescription = taskDetail?.task?.suggestion;
|
const newDescription = task?.suggestion;
|
||||||
const oldDescription = taskDetail?.task?.oldValue;
|
const oldDescription = task?.oldValue;
|
||||||
|
|
||||||
const diffs = getDescriptionDiff(
|
const diffs = getDescriptionDiff(
|
||||||
oldDescription || '',
|
oldDescription || '',
|
||||||
@ -116,7 +101,7 @@ const DescriptionTask: FC<DescriptionTaskProps> = ({
|
|||||||
{isTaskActionEdit && hasEditAccess ? (
|
{isTaskActionEdit && hasEditAccess ? (
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
height="208px"
|
height="208px"
|
||||||
initialValue={suggestion}
|
initialValue={task?.suggestion ?? ''}
|
||||||
placeHolder={t('label.add-entity', {
|
placeHolder={t('label.add-entity', {
|
||||||
entity: t('label.description'),
|
entity: t('label.description'),
|
||||||
})}
|
})}
|
||||||
@ -135,8 +120,8 @@ const DescriptionTask: FC<DescriptionTaskProps> = ({
|
|||||||
<div data-testid="update-description">
|
<div data-testid="update-description">
|
||||||
{isTaskActionEdit && hasEditAccess ? (
|
{isTaskActionEdit && hasEditAccess ? (
|
||||||
<DescriptionTabs
|
<DescriptionTabs
|
||||||
suggestion={suggestion}
|
suggestion={task?.suggestion ?? ''}
|
||||||
value={currentDescription}
|
value={task?.oldValue ?? ''}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -48,7 +48,7 @@ describe('Test Description Tabs Component', () => {
|
|||||||
expect(await screen.findByText('New')).toBeInTheDocument();
|
expect(await screen.findByText('New')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should render the component relavant tab component', async () => {
|
it('Should render the component relevant tab component', async () => {
|
||||||
render(<TagsTabs {...mockProps} />);
|
render(<TagsTabs {...mockProps} />);
|
||||||
|
|
||||||
const tabs = await screen.findAllByRole('tab');
|
const tabs = await screen.findAllByRole('tab');
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { diffArrays } from 'diff';
|
import { diffArrays } from 'diff';
|
||||||
|
import { TagLabel } from 'generated/type/tagLabel';
|
||||||
import React, { FC, Fragment, useMemo } from 'react';
|
import React, { FC, Fragment, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@ -19,7 +20,6 @@ import {
|
|||||||
Thread,
|
Thread,
|
||||||
ThreadTaskStatus,
|
ThreadTaskStatus,
|
||||||
} from '../../../generated/entity/feed/thread';
|
} from '../../../generated/entity/feed/thread';
|
||||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
|
||||||
import { TagsDiffView } from './TagsDiffView';
|
import { TagsDiffView } from './TagsDiffView';
|
||||||
import { TagsTabs } from './TagsTabs';
|
import { TagsTabs } from './TagsTabs';
|
||||||
import TagSuggestion from './TagSuggestion';
|
import TagSuggestion from './TagSuggestion';
|
||||||
@ -28,18 +28,14 @@ interface TagsTaskProps {
|
|||||||
task: Thread['task'];
|
task: Thread['task'];
|
||||||
isTaskActionEdit: boolean;
|
isTaskActionEdit: boolean;
|
||||||
hasEditAccess: boolean;
|
hasEditAccess: boolean;
|
||||||
currentTags: TagLabel[];
|
onChange: (newTags: TagLabel[]) => void;
|
||||||
value?: TagLabel[];
|
|
||||||
onChange?: (newTags: TagLabel[]) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagsTask: FC<TagsTaskProps> = ({
|
const TagsTask: FC<TagsTaskProps> = ({
|
||||||
value = [],
|
|
||||||
onChange,
|
|
||||||
isTaskActionEdit,
|
isTaskActionEdit,
|
||||||
hasEditAccess,
|
hasEditAccess,
|
||||||
task,
|
task,
|
||||||
currentTags,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -105,7 +101,10 @@ const TagsTask: FC<TagsTaskProps> = ({
|
|||||||
{isRequestTag && (
|
{isRequestTag && (
|
||||||
<div data-testid="request-tags">
|
<div data-testid="request-tags">
|
||||||
{isTaskActionEdit && hasEditAccess ? (
|
{isTaskActionEdit && hasEditAccess ? (
|
||||||
<TagSuggestion value={value} onChange={onChange} />
|
<TagSuggestion
|
||||||
|
value={JSON.parse(suggestion ?? '[]')}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
suggestedTagsDiff
|
suggestedTagsDiff
|
||||||
)}
|
)}
|
||||||
@ -115,8 +114,8 @@ const TagsTask: FC<TagsTaskProps> = ({
|
|||||||
<div data-testid="update-tags">
|
<div data-testid="update-tags">
|
||||||
{isTaskActionEdit && hasEditAccess ? (
|
{isTaskActionEdit && hasEditAccess ? (
|
||||||
<TagsTabs
|
<TagsTabs
|
||||||
tags={currentTags}
|
tags={JSON.parse(oldValue ?? '[]')}
|
||||||
value={value}
|
value={JSON.parse(suggestion ?? '[]')}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -168,6 +168,10 @@ a[href].link-text-grey,
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.whitespace-pre-wrap {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user