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:
Sachin Chaurasiya 2023-07-05 18:30:15 +05:30 committed by GitHub
parent ba3a1e1ed6
commit 6139c59a87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 87 additions and 137 deletions

View File

@ -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}
/> />
)} )}

View File

@ -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 &

View File

@ -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>

View File

@ -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> }

View File

@ -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}
/> />

View File

@ -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,

View File

@ -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: [

View File

@ -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}
/> />
) : ( ) : (

View File

@ -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');

View File

@ -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}
/> />
) : ( ) : (

View File

@ -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;