mirror of
https://github.com/datahub-project/datahub.git
synced 2025-08-20 23:28:01 +00:00
fix(ui/navBar): Fix logic to display manage tags link (#13564)
Co-authored-by: v-tarasevich-blitz-brain <v.tarasevich@blitz-brain.com>
This commit is contained in:
parent
ae234d671e
commit
416c2093d1
@ -50,7 +50,9 @@ const ButtonsContainer = styled.div`
|
||||
|
||||
export interface ModalButton extends ButtonProps {
|
||||
text: string;
|
||||
key?: string;
|
||||
onClick: () => void;
|
||||
buttonDataTestId?: string;
|
||||
}
|
||||
|
||||
export interface ModalProps {
|
||||
@ -78,6 +80,7 @@ export function Modal({
|
||||
onCancel={onCancel}
|
||||
closeIcon={<Icon icon="X" source="phosphor" />}
|
||||
hasChildren={!!children}
|
||||
data-testid={dataTestId}
|
||||
title={
|
||||
<HeaderContainer hasChildren={!!children}>
|
||||
<Heading type="h1" color="gray" colorLevel={600} weight="bold" size="lg">
|
||||
@ -93,10 +96,10 @@ export function Modal({
|
||||
footer={
|
||||
!!buttons.length && (
|
||||
<ButtonsContainer>
|
||||
{buttons.map(({ text, variant, onClick, ...buttonProps }, index) => (
|
||||
{buttons.map(({ text, variant, onClick, key, buttonDataTestId, ...buttonProps }, index) => (
|
||||
<Button
|
||||
key={text}
|
||||
data-testid={dataTestId && `${dataTestId}-${variant}-${index}`}
|
||||
key={key || text}
|
||||
data-testid={buttonDataTestId ?? (dataTestId && `${dataTestId}-${variant}-${index}`)}
|
||||
variant={variant}
|
||||
onClick={onClick}
|
||||
{...buttonProps}
|
||||
|
@ -94,6 +94,9 @@ export const NavSidebar = () => {
|
||||
const showStructuredProperties =
|
||||
config?.featureFlags?.showManageStructuredProperties &&
|
||||
(me.platformPrivileges?.manageStructuredProperties || me.platformPrivileges?.viewStructuredPropertiesPage);
|
||||
const showManageTags =
|
||||
config?.featureFlags?.showManageTags &&
|
||||
(me.platformPrivileges?.manageTags || me.platformPrivileges?.viewManageTags);
|
||||
|
||||
const showDataSources =
|
||||
config.managedIngestionConfig.enabled &&
|
||||
@ -151,6 +154,7 @@ export const NavSidebar = () => {
|
||||
icon: <Tag />,
|
||||
selectedIcon: <Tag weight="fill" />,
|
||||
link: PageRoutes.MANAGE_TAGS,
|
||||
isHidden: !showManageTags,
|
||||
},
|
||||
{
|
||||
type: NavBarMenuItemTypes.Item,
|
||||
|
@ -66,7 +66,7 @@ export const NoPageFound = () => {
|
||||
<Number>4</Number>
|
||||
</NumberContainer>
|
||||
</PageNotFoundTextContainer>
|
||||
<SubTitle>The page your requested was not found,</SubTitle>
|
||||
<SubTitle>The page you requested was not found,</SubTitle>
|
||||
<Button onClick={goToHomepage}>Back to Home</Button>
|
||||
</PageNotFoundContainer>
|
||||
</MainContainer>
|
||||
|
@ -2,10 +2,11 @@ import { Modal } from '@components';
|
||||
import { message } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { ModalButton } from '@components/components/Modal/Modal';
|
||||
|
||||
import { useEnterKeyListener } from '@app/shared/useEnterKeyListener';
|
||||
import OwnersSection, { PendingOwner } from '@app/sharedV2/owners/OwnersSection';
|
||||
import TagDetailsSection from '@app/tags/CreateNewTagModal/TagDetailsSection';
|
||||
import { ModalButton } from '@app/tags/CreateNewTagModal/types';
|
||||
|
||||
import { useBatchAddOwnersMutation, useSetTagColorMutation } from '@graphql/mutations.generated';
|
||||
import { useCreateTagMutation } from '@graphql/tag.generated';
|
||||
@ -120,6 +121,7 @@ const CreateNewTagModal: React.FC<CreateNewTagModalProps> = ({ onClose, open })
|
||||
color: 'violet',
|
||||
variant: 'text',
|
||||
onClick: onClose,
|
||||
buttonDataTestId: 'create-tag-modal-cancel-button',
|
||||
},
|
||||
{
|
||||
text: 'Create',
|
||||
@ -129,6 +131,7 @@ const CreateNewTagModal: React.FC<CreateNewTagModalProps> = ({ onClose, open })
|
||||
onClick: onOk,
|
||||
disabled: !tagName || isLoading,
|
||||
isLoading,
|
||||
buttonDataTestId: 'create-tag-modal-create-button',
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -59,6 +59,7 @@ const TagDetailsSection: React.FC<TagDetailsProps> = ({
|
||||
value={tagName}
|
||||
setValue={handleTagNameChange}
|
||||
placeholder="Enter tag name"
|
||||
data-testid="tag-name-field"
|
||||
required
|
||||
/>
|
||||
</FormSection>
|
||||
@ -69,6 +70,7 @@ const TagDetailsSection: React.FC<TagDetailsProps> = ({
|
||||
value={tagDescription}
|
||||
setValue={handleDescriptionChange}
|
||||
placeholder="Add a description for your new tag"
|
||||
data-testid="tag-description-field"
|
||||
type="textarea"
|
||||
/>
|
||||
</FormSection>
|
||||
|
@ -1,14 +1,3 @@
|
||||
// Interface for modal buttons matching the expected ButtonProps
|
||||
export interface ModalButton {
|
||||
text: string;
|
||||
color: 'violet' | 'white' | 'black' | 'green' | 'red' | 'blue' | 'yellow' | 'gray';
|
||||
variant: 'text' | 'filled' | 'outline';
|
||||
onClick: () => void;
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
// Common styled components
|
||||
export const FormSection = {
|
||||
marginBottom: '16px',
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { ButtonProps, ColorPicker, Input, Modal } from '@components';
|
||||
import { ColorPicker, Input, Modal } from '@components';
|
||||
import { message } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { ModalButton } from '@components/components/Modal/Modal';
|
||||
|
||||
import OwnersSection from '@app/sharedV2/owners/OwnersSection';
|
||||
import { useEntityRegistry } from '@src/app/useEntityRegistry';
|
||||
import {
|
||||
@ -24,12 +26,6 @@ interface Props {
|
||||
isModalOpen?: boolean;
|
||||
}
|
||||
|
||||
// Define a compatible interface for modal buttons
|
||||
interface ModalButton extends ButtonProps {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
// Interface for pending owner
|
||||
interface PendingOwner {
|
||||
ownerUrn: string;
|
||||
@ -239,6 +235,7 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
|
||||
variant: 'filled',
|
||||
onClick: handleSave,
|
||||
disabled: !hasChanges(),
|
||||
buttonDataTestId: 'update-tag-button',
|
||||
},
|
||||
];
|
||||
|
||||
@ -251,7 +248,15 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
|
||||
const modalTitle = tagDisplayName ? `Edit Tag: ${tagDisplayName}` : 'Edit Tag';
|
||||
|
||||
return (
|
||||
<Modal title={modalTitle} onCancel={onClose} buttons={buttons} open={isModalOpen} centered width={400}>
|
||||
<Modal
|
||||
title={modalTitle}
|
||||
onCancel={onClose}
|
||||
buttons={buttons}
|
||||
open={isModalOpen}
|
||||
centered
|
||||
width={400}
|
||||
dataTestId="edit-tag-modal"
|
||||
>
|
||||
<div>
|
||||
<FormSection>
|
||||
<Input
|
||||
@ -260,6 +265,7 @@ const ManageTag = ({ tagUrn, onClose, onSave, isModalOpen = false }: Props) => {
|
||||
setValue={handleDescriptionChange}
|
||||
placeholder="Tag description"
|
||||
type="textarea"
|
||||
data-testid="tag-description-field"
|
||||
/>
|
||||
</FormSection>
|
||||
|
||||
|
@ -145,6 +145,7 @@ const ManageTags = () => {
|
||||
size="md"
|
||||
color="violet"
|
||||
icon={{ icon: 'Plus', source: 'phosphor' }}
|
||||
data-testid="add-tag-button"
|
||||
>
|
||||
Create Tag
|
||||
</Button>
|
||||
|
@ -233,6 +233,7 @@ const TagsTable = ({ searchQuery, searchData, loading: propLoading, networkStatu
|
||||
color: 'red',
|
||||
variant: 'filled',
|
||||
onClick: handleDeleteTag,
|
||||
buttonDataTestId: 'delete-tag-button',
|
||||
},
|
||||
]}
|
||||
>
|
||||
|
@ -290,7 +290,7 @@ export const TagActionsColumn = React.memo(
|
||||
return (
|
||||
<CardIcons>
|
||||
<Dropdown menu={{ items }} trigger={['click']} data-testid={`${tagUrn}-actions-dropdown`}>
|
||||
<Icon icon="MoreVert" size="md" />
|
||||
<Icon icon="MoreVert" size="md" data-testid={`${tagUrn}-actions`} />
|
||||
</Dropdown>
|
||||
</CardIcons>
|
||||
);
|
||||
|
@ -1,6 +1,10 @@
|
||||
describe("manage tags", () => {
|
||||
it("Manage Tags Page - Verify search bar placeholder", () => {
|
||||
beforeEach(() => {
|
||||
cy.setIsThemeV2Enabled(false);
|
||||
cy.login();
|
||||
});
|
||||
|
||||
it("Manage Tags Page - Verify search bar placeholder", () => {
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="tag-search-input"]').should(
|
||||
"have.attr",
|
||||
@ -8,8 +12,8 @@ describe("manage tags", () => {
|
||||
"Search tags...",
|
||||
);
|
||||
});
|
||||
|
||||
it("Manage Tags Page - Verify Title, Search, and Results", () => {
|
||||
cy.login();
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="page-title"]').should("contain.text", "Manage Tags");
|
||||
cy.get('[data-testid="urn:li:tag:Cypress-name"]').should(
|
||||
@ -22,15 +26,15 @@ describe("manage tags", () => {
|
||||
"Cypress",
|
||||
);
|
||||
});
|
||||
|
||||
it("Manage Tags Page - Verify search not exists", () => {
|
||||
cy.login();
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="page-title"]').should("contain.text", "Manage Tags");
|
||||
cy.get('[data-testid="urn:li:tag:Cypress-name"]').should(
|
||||
"contain.text",
|
||||
"Cypress",
|
||||
);
|
||||
cy.get('[data-testid="tag-search-input"]').type("test");
|
||||
cy.get('[data-testid="tag-search-input"]').type("invalidvalue");
|
||||
cy.get('[data-testid="tags-not-found"]').should(
|
||||
"contain.text",
|
||||
"No tags found for your search query",
|
||||
|
@ -0,0 +1,53 @@
|
||||
export default class DatasetHelper {
|
||||
static openDataset(urn, name) {
|
||||
cy.goToDataset(urn, name);
|
||||
}
|
||||
|
||||
static assignTag(name) {
|
||||
cy.get("#entity-profile-tags").within(() => {
|
||||
cy.clickOptionWithTestId("AddRoundedIcon");
|
||||
});
|
||||
|
||||
cy.getWithTestId("tag-term-modal-input").within(() => {
|
||||
cy.get("input").focus({ force: true }).type(name);
|
||||
});
|
||||
|
||||
cy.get(`[name="${name}"]`).click();
|
||||
cy.clickOptionWithTestId("add-tag-term-from-modal-btn");
|
||||
cy.waitTextVisible("Added Tags!");
|
||||
}
|
||||
|
||||
static ensureTagIsAssigned(name) {
|
||||
cy.getWithTestId(`tag-${name}`).should("be.visible");
|
||||
}
|
||||
|
||||
static unassignTag(name) {
|
||||
cy.getWithTestId(`tag-${name}`).within(() => {
|
||||
cy.get(".ant-tag-close-icon").click();
|
||||
});
|
||||
|
||||
cy.get(".ant-modal-confirm-confirm").within(() => {
|
||||
cy.get(".ant-btn-primary").click();
|
||||
});
|
||||
|
||||
cy.waitTextVisible("Removed Tag!");
|
||||
}
|
||||
|
||||
static ensureTagIsNotAssigned(name) {
|
||||
cy.getWithTestId(`tag-${name}`).should("not.exist");
|
||||
}
|
||||
|
||||
static searchByTag(tagName) {
|
||||
cy.visit(
|
||||
`/search?filter_tags___false___EQUAL___0=urn%3Ali%3Atag%3A${tagName}&page=1&query=%2A&unionType=0`,
|
||||
);
|
||||
}
|
||||
|
||||
static ensureEntityIsInSearchResults(urn) {
|
||||
cy.getWithTestId(`preview-${urn}`).should("be.visible");
|
||||
}
|
||||
|
||||
static ensureEntityIsNotInSearchResults(urn) {
|
||||
cy.getWithTestId(`preview-${urn}`).should("not.exist");
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
export default class TagsPageHelper {
|
||||
static openPage() {
|
||||
cy.visit("/tags");
|
||||
}
|
||||
|
||||
static getTagUrn(name) {
|
||||
return `urn:li:tag:${name}`;
|
||||
}
|
||||
|
||||
static create(name, description, shouldBeSuccessfullyCreated = true) {
|
||||
cy.clickOptionWithTestId("add-tag-button");
|
||||
cy.getWithTestId("tag-name-field").within(() =>
|
||||
cy.get("input").focus().type(name),
|
||||
);
|
||||
cy.getWithTestId("tag-description-field").within(() =>
|
||||
cy.get("input").focus().type(description),
|
||||
);
|
||||
cy.clickOptionWithTestId("create-tag-modal-create-button");
|
||||
|
||||
if (shouldBeSuccessfullyCreated) {
|
||||
cy.waitTextVisible(`Tag "${name}" successfully created`);
|
||||
} else {
|
||||
cy.waitTextVisible("Failed to create tag. An unexpected error occurred");
|
||||
cy.clickOptionWithTestId("create-tag-modal-cancel-button");
|
||||
}
|
||||
}
|
||||
|
||||
static remove(name) {
|
||||
cy.getWithTestId("tag-search-input").focus().type(name, { delay: 0 });
|
||||
cy.clickOptionWithTestId(`${TagsPageHelper.getTagUrn(name)}-actions`);
|
||||
cy.clickOptionWithTestId("action-delete");
|
||||
cy.clickOptionWithTestId("delete-tag-button");
|
||||
cy.getWithTestId("tag-search-input").clear();
|
||||
}
|
||||
|
||||
static edit(name, newDescription) {
|
||||
cy.getWithTestId("tag-search-input").focus().type(name, { delay: 0 });
|
||||
cy.clickOptionWithTestId(`${TagsPageHelper.getTagUrn(name)}-actions`);
|
||||
cy.clickOptionWithTestId("action-edit");
|
||||
|
||||
cy.getWithTestId("edit-tag-modal").within(() => {
|
||||
cy.getWithTestId("tag-description-field").within(() =>
|
||||
cy.get("input").focus().clear().type(newDescription),
|
||||
);
|
||||
});
|
||||
|
||||
cy.clickOptionWithTestId("update-tag-button");
|
||||
cy.getWithTestId("tag-search-input").clear();
|
||||
}
|
||||
|
||||
static ensureTagIsInTable(name, description) {
|
||||
cy.getWithTestId("tag-search-input").focus().type(name, { delay: 0 });
|
||||
cy.getWithTestId(`${TagsPageHelper.getTagUrn(name)}-name`).should(
|
||||
"contain",
|
||||
name,
|
||||
);
|
||||
cy.getWithTestId(`${TagsPageHelper.getTagUrn(name)}-description`).should(
|
||||
"contain",
|
||||
description,
|
||||
);
|
||||
cy.getWithTestId("tag-search-input").clear();
|
||||
}
|
||||
|
||||
static ensureTagIsNotInTable(name) {
|
||||
cy.getWithTestId("tag-search-input").focus().type(name, { delay: 0 });
|
||||
cy.getWithTestId(`${TagsPageHelper.getTagUrn(name)}-name`).should(
|
||||
"not.exist",
|
||||
);
|
||||
cy.getWithTestId("tag-search-input").clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
import DatasetHelper from "./helpers/dataset_helper";
|
||||
import TagsPageHelper from "./helpers/tags_page_helper";
|
||||
|
||||
const test_id = `manage_tagsV2_${new Date().getTime()}`;
|
||||
|
||||
const SAMPLE_DATASET_URN =
|
||||
"urn:li:dataset:(urn:li:dataPlatform:hive,SampleCypressHiveDataset,PROD)";
|
||||
const SAMPLE_DATASET_NAME = "SampleCypressHiveDataset";
|
||||
|
||||
describe("tags", () => {
|
||||
beforeEach(() => {
|
||||
cy.setIsThemeV2Enabled(true);
|
||||
cy.login();
|
||||
});
|
||||
|
||||
it("verify search bar placeholder", () => {
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="tag-search-input"]').should(
|
||||
"have.attr",
|
||||
"placeholder",
|
||||
"Search tags...",
|
||||
);
|
||||
});
|
||||
|
||||
it("verify title, search, and results", () => {
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="page-title"]').should("contain.text", "Manage Tags");
|
||||
cy.get('[data-testid="urn:li:tag:Cypress-name"]').should(
|
||||
"contain.text",
|
||||
"Cypress",
|
||||
);
|
||||
cy.get('[data-testid="tag-search-input"]').type("Cypress");
|
||||
cy.get('[data-testid="urn:li:tag:Cypress-name"]').should(
|
||||
"contain.text",
|
||||
"Cypress",
|
||||
);
|
||||
});
|
||||
|
||||
it("verify search not exists", () => {
|
||||
cy.visit("/tags");
|
||||
cy.get('[data-testid="page-title"]').should("contain.text", "Manage Tags");
|
||||
cy.get('[data-testid="urn:li:tag:Cypress-name"]').should(
|
||||
"contain.text",
|
||||
"Cypress",
|
||||
);
|
||||
cy.get('[data-testid="tag-search-input"]').type("invalidvalue");
|
||||
cy.get('[data-testid="tags-not-found"]').should(
|
||||
"contain.text",
|
||||
"No tags found for your search query",
|
||||
);
|
||||
});
|
||||
|
||||
it("should allow to create/edit/remove tags on tags page", () => {
|
||||
const tagName = `tag_${test_id}_tags_page`;
|
||||
const tagDescription = `${tagName} description`;
|
||||
|
||||
TagsPageHelper.openPage();
|
||||
TagsPageHelper.create(tagName, tagDescription);
|
||||
TagsPageHelper.ensureTagIsInTable(tagName, tagDescription);
|
||||
// ensure that we can't to create tag with the same name
|
||||
TagsPageHelper.create(tagName, tagDescription, false);
|
||||
TagsPageHelper.edit(tagName, `${tagDescription} edited`);
|
||||
TagsPageHelper.ensureTagIsInTable(tagName, `${tagDescription} edited`);
|
||||
TagsPageHelper.remove(tagName);
|
||||
TagsPageHelper.ensureTagIsNotInTable(tagName);
|
||||
});
|
||||
|
||||
it("should allow to assign/unassign tags on a dataset", () => {
|
||||
const tagName = `tag_${test_id}_dataset`;
|
||||
const tagDescription = `${tagName} description`;
|
||||
|
||||
TagsPageHelper.openPage();
|
||||
TagsPageHelper.create(tagName, tagDescription);
|
||||
|
||||
DatasetHelper.openDataset(SAMPLE_DATASET_URN, SAMPLE_DATASET_NAME);
|
||||
DatasetHelper.assignTag(tagName);
|
||||
DatasetHelper.ensureTagIsAssigned(tagName);
|
||||
|
||||
DatasetHelper.searchByTag(tagName);
|
||||
DatasetHelper.ensureEntityIsInSearchResults(SAMPLE_DATASET_URN);
|
||||
|
||||
DatasetHelper.openDataset(SAMPLE_DATASET_URN, SAMPLE_DATASET_NAME);
|
||||
DatasetHelper.unassignTag(tagName);
|
||||
DatasetHelper.ensureTagIsNotAssigned(tagName);
|
||||
|
||||
DatasetHelper.searchByTag(tagName);
|
||||
DatasetHelper.ensureEntityIsNotInSearchResults(SAMPLE_DATASET_URN);
|
||||
|
||||
TagsPageHelper.openPage();
|
||||
TagsPageHelper.remove(tagName);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user