Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 53 additions & 29 deletions datahub-web-react/src/app/tags/ManageTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ import { ModalButton } from '@components/components/Modal/Modal';

import OwnersSection from '@app/sharedV2/owners/OwnersSection';
import { useEntityRegistry } from '@src/app/useEntityRegistry';
import {
useBatchAddOwnersMutation,
useSetTagColorMutation,
useUpdateDescriptionMutation,
} from '@src/graphql/mutations.generated';
import { useGetTagQuery } from '@src/graphql/tag.generated';
import { useBatchAddOwnersMutation, useSetTagColorMutation } from '@src/graphql/mutations.generated';
import { useGetTagQuery, useUpdateTagMutation } from '@src/graphql/tag.generated';
import { EntityType, OwnerEntityType } from '@src/types.generated';

const FormSection = styled.div`
Expand Down Expand Up @@ -41,13 +37,17 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
});

const [setTagColorMutation] = useSetTagColorMutation();
const [updateDescriptionMutation] = useUpdateDescriptionMutation();
const [batchAddOwnersMutation] = useBatchAddOwnersMutation();
const [updateTagMutation] = useUpdateTagMutation();

// State to track values
const [colorValue, setColorValue] = useState('#1890ff');
const [originalColor, setOriginalColor] = useState('');

// Tag name state (editable)
const [tagName, setTagName] = useState('');
const [originalTagName, setOriginalTagName] = useState('');

// Tag name for display purposes only
const [tagDisplayName, setTagDisplayName] = useState('');

Expand All @@ -71,9 +71,12 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
setColorValue(tagColor);
setOriginalColor(tagColor);

// Get the tag name for display
// Get the tag name for display and editing
const displayName = entityRegistry.getDisplayName(EntityType.Tag, data.tag) || data.tag.name || '';
const tagNameValue = data.tag.properties?.name || data.tag.name || '';
setTagDisplayName(displayName);
setTagName(tagNameValue);
setOriginalTagName(tagNameValue);

// Get the description
const desc = data.tag.properties?.description || '';
Expand All @@ -91,20 +94,18 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
setColorValue(color);
};

const handleDescriptionChange: React.Dispatch<React.SetStateAction<string>> = (value) => {
if (typeof value === 'function') {
setDescription(value);
} else {
setDescription(value);
}
};

// Check if anything has changed
const hasChanges = () => {
return colorValue !== originalColor || description !== originalDescription || pendingOwners.length > 0;
return (
tagName !== originalTagName ||
colorValue !== originalColor ||
description !== originalDescription ||
pendingOwners.length > 0
);
};

const handleReset = () => {
setTagName(originalTagName);
setColorValue(originalColor);
setDescription(originalDescription);
setPendingOwners([]);
Expand All @@ -114,6 +115,16 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
// Save everything together
const handleSave = async () => {
try {
// Validate required fields
if (!tagName.trim()) {
message.error({
content: 'Tag name is required',
key: 'tagUpdate',
duration: 3,
});
return;
}

message.loading({ content: 'Saving changes...', key: 'tagUpdate' });

// Track if we made any successful changes
Expand All @@ -139,23 +150,25 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
}
}

// Update description if changed
if (description !== originalDescription) {
// Update tag name and/or description if changed
if (tagName !== originalTagName || description !== originalDescription) {
try {
await updateDescriptionMutation({
await updateTagMutation({
variables: {
urn: tagUrn,
input: {
resourceUrn: tagUrn,
description,
urn: tagUrn,
name: tagName,
description: description || undefined,
},
},
});
changesMade = true;
} catch (descError) {
console.error('Error updating description:', descError);
} catch (tagUpdateError) {
console.error('Error updating tag:', tagUpdateError);
throw new Error(
`Failed to update description: ${
descError instanceof Error ? descError.message : String(descError)
`Failed to update tag: ${
tagUpdateError instanceof Error ? tagUpdateError.message : String(tagUpdateError)
}`,
);
}
Expand Down Expand Up @@ -234,7 +247,7 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
color: 'violet',
variant: 'filled',
onClick: handleSave,
disabled: !hasChanges(),
disabled: !hasChanges() || !tagName.trim(),
buttonDataTestId: 'update-tag-button',
},
];
Expand All @@ -245,7 +258,7 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
}

// Dynamic modal title
const modalTitle = tagDisplayName ? `Edit Tag: ${tagDisplayName}` : 'Edit Tag';
const modalTitle = tagDisplayName ? `Edit Tag` : 'Edit Tag';

return (
<Modal
Expand All @@ -258,11 +271,22 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
dataTestId="edit-tag-modal"
>
<div>
<FormSection>
<Input
label="Name"
value={tagName}
setValue={setTagName}
placeholder="Enter tag name"
isRequired
data-testid="tag-name-field"
/>
</FormSection>

<FormSection>
<Input
label="Description"
value={description}
setValue={handleDescriptionChange}
setValue={setDescription}
placeholder="Tag description"
type="textarea"
data-testid="tag-description-field"
Expand Down
64 changes: 24 additions & 40 deletions datahub-web-react/src/app/tags/TagsTableColumns.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Icon, Text, colors, typography } from '@components';
import { Dropdown } from 'antd';
import { Icon, Menu, Text, colors } from '@components';
import React from 'react';
import Highlight from 'react-highlighter';
import { useHistory } from 'react-router';
Expand Down Expand Up @@ -46,15 +45,6 @@ const ColumnContainer = styled.div`
width: 100%;
`;

const MenuItem = styled.div`
display: flex;
padding: 5px 70px 5px 5px;
font-size: 14px;
font-weight: 400;
color: ${colors.gray[600]};
font-family: ${typography.fonts.body};
`;

const ColorDotContainer = styled.div`
display: flex;
align-items: center;
Expand Down Expand Up @@ -248,50 +238,44 @@ export const TagActionsColumn = React.memo(
onDelete: () => void;
canManageTags: boolean;
}) => {
const items = [
const menuItems = [
{
key: '0',
label: (
<MenuItem onClick={onEdit} data-testid="action-edit">
Edit
</MenuItem>
),
type: 'item' as const,
key: 'edit',
title: 'Edit',
icon: 'Edit' as const,
onClick: onEdit,
'data-testid': 'action-edit',
},
{
key: '1',
label: (
<MenuItem
onClick={() => {
navigator.clipboard.writeText(tagUrn);
}}
>
Copy Urn
</MenuItem>
),
type: 'item' as const,
key: 'copy-urn',
title: 'Copy URN',
icon: 'ContentCopy' as const,
onClick: () => {
navigator.clipboard.writeText(tagUrn);
},
},
...(canManageTags
? [
{
key: '2',
label: (
<MenuItem
onClick={onDelete}
data-testid="action-delete"
style={{ color: colors.red[500] }}
>
Delete
</MenuItem>
),
type: 'item' as const,
key: 'delete',
title: 'Delete',
icon: 'Delete' as const,
danger: true,
onClick: onDelete,
'data-testid': 'action-delete',
},
]
: []),
];

return (
<CardIcons>
<Dropdown menu={{ items }} trigger={['click']} data-testid={`${tagUrn}-actions-dropdown`}>
<Menu items={menuItems} trigger={['click']} data-testid={`${tagUrn}-actions-dropdown`}>
<Icon icon="MoreVert" size="md" data-testid={`${tagUrn}-actions`} />
</Dropdown>
</Menu>
</CardIcons>
);
},
Expand Down
Loading