feat(ui/glossary): Keep the same tab selected when browsing Glossary (#9469)

This commit is contained in:
Sumit Patil 2023-12-21 13:24:33 +05:30 committed by GitHub
parent bf813d1d24
commit 50be329492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 3 deletions

View File

@ -180,6 +180,7 @@ function EntityDropdown(props: Props) {
)} )}
{menuItems.has(EntityMenuItems.ADD_TERM) && ( {menuItems.has(EntityMenuItems.ADD_TERM) && (
<StyledMenuItem <StyledMenuItem
data-testid="entity-menu-add-term-button"
key="2" key="2"
disabled={!canCreateGlossaryEntity} disabled={!canCreateGlossaryEntity}
onClick={() => setIsCreateTermModalVisible(true)} onClick={() => setIsCreateTermModalVisible(true)}

View File

@ -39,6 +39,7 @@ export const EntityTabs = <T,>({ tabs, selectedTab }: Props) => {
return ( return (
<UnborderedTabs <UnborderedTabs
data-testid="entity-tab-headers-test-id"
animated={false} animated={false}
activeKey={selectedTab?.name || ''} activeKey={selectedTab?.name || ''}
size="large" size="large"

View File

@ -134,6 +134,22 @@ export function useIsOnTab(tabName: string): boolean {
return false; return false;
} }
export function useGlossaryActiveTabPath(): string {
const { pathname, search } = useLocation();
const trimmedPathName = pathname.endsWith('/') ? pathname.slice(0, pathname.length - 1) : pathname;
// Match against the regex
const match = trimmedPathName.match(ENTITY_TAB_NAME_REGEX_PATTERN);
if (match && match[1]) {
const selectedTabPath = match[1] + (search || ''); // Include all query parameters
return selectedTabPath;
}
// No match found!
return "";
}
export function formatDateString(time: number) { export function formatDateString(time: number) {
const date = new Date(time); const date = new Date(time);
return date.toLocaleDateString('en-US'); return date.toLocaleDateString('en-US');

View File

@ -166,7 +166,7 @@ function NodeItem(props: Props) {
))} ))}
{!hideTerms && {!hideTerms &&
(childTerms as GlossaryTerm[]).map((child) => ( (childTerms as GlossaryTerm[]).map((child) => (
<TermItem term={child} isSelecting={isSelecting} selectTerm={selectTerm} /> <TermItem term={child} isSelecting={isSelecting} selectTerm={selectTerm} includeActiveTabPath />
))} ))}
</ChildrenWrapper> </ChildrenWrapper>
)} )}

View File

@ -5,6 +5,7 @@ import { useEntityRegistry } from '../../useEntityRegistry';
import { ANTD_GRAY } from '../../entity/shared/constants'; import { ANTD_GRAY } from '../../entity/shared/constants';
import { ChildGlossaryTermFragment } from '../../../graphql/glossaryNode.generated'; import { ChildGlossaryTermFragment } from '../../../graphql/glossaryNode.generated';
import { useGlossaryEntityData } from '../../entity/shared/GlossaryEntityContext'; import { useGlossaryEntityData } from '../../entity/shared/GlossaryEntityContext';
import { useGlossaryActiveTabPath } from '../../entity/shared/containers/profile/utils';
const TermWrapper = styled.div` const TermWrapper = styled.div`
font-weight: normal; font-weight: normal;
@ -47,13 +48,15 @@ interface Props {
term: ChildGlossaryTermFragment; term: ChildGlossaryTermFragment;
isSelecting?: boolean; isSelecting?: boolean;
selectTerm?: (urn: string, displayName: string) => void; selectTerm?: (urn: string, displayName: string) => void;
includeActiveTabPath?: boolean;
} }
function TermItem(props: Props) { function TermItem(props: Props) {
const { term, isSelecting, selectTerm } = props; const { term, isSelecting, selectTerm, includeActiveTabPath } = props;
const { entityData } = useGlossaryEntityData(); const { entityData } = useGlossaryEntityData();
const entityRegistry = useEntityRegistry(); const entityRegistry = useEntityRegistry();
const activeTabPath = useGlossaryActiveTabPath();
function handleSelectTerm() { function handleSelectTerm() {
if (selectTerm) { if (selectTerm) {
@ -68,7 +71,9 @@ function TermItem(props: Props) {
<TermWrapper> <TermWrapper>
{!isSelecting && ( {!isSelecting && (
<TermLink <TermLink
to={`${entityRegistry.getEntityUrl(term.type, term.urn)}`} to={`${entityRegistry.getEntityUrl(term.type, term.urn)}${
includeActiveTabPath ? `/${activeTabPath}` : ''
}`}
isSelected={entityData?.urn === term.urn} isSelected={entityData?.urn === term.urn}
> >
{entityRegistry.getDisplayName(term.type, isOnEntityPage ? entityData : term)} {entityRegistry.getDisplayName(term.type, isOnEntityPage ? entityData : term)}

View File

@ -1,4 +1,5 @@
const glossaryTerm = "CypressGlosssaryNavigationTerm"; const glossaryTerm = "CypressGlosssaryNavigationTerm";
const glossarySecondTerm = "CypressGlossarySecondTerm";
const glossaryTermGroup = "CypressGlosssaryNavigationGroup"; const glossaryTermGroup = "CypressGlosssaryNavigationGroup";
const glossaryParentGroup = "CypressNode"; const glossaryParentGroup = "CypressNode";
@ -30,6 +31,39 @@ describe("glossary sidebar navigation test", () => {
cy.get('[data-testid="glossary-browser-sidebar"]').contains(glossaryTermGroup).click().wait(3000); cy.get('[data-testid="glossary-browser-sidebar"]').contains(glossaryTermGroup).click().wait(3000);
cy.get('*[class^="GlossaryEntitiesList"]').contains(glossaryTerm).should("be.visible"); cy.get('*[class^="GlossaryEntitiesList"]').contains(glossaryTerm).should("be.visible");
// Create another term and move it to the same term group
cy.clickOptionWithText(glossaryTermGroup);
cy.openThreeDotDropdown();
cy.clickOptionWithTestId("entity-menu-add-term-button");
// Wait for the create term modal to be visible
cy.waitTextVisible("Create Glossary Term");
cy.enterTextInTestId("create-glossary-entity-modal-name", glossarySecondTerm);
cy.clickOptionWithTestId("glossary-entity-modal-create-button");
// Wait for the new term to be visible in the sidebar
cy.clickOptionWithText(glossarySecondTerm).wait(3000);
// Move the term to the created term group
cy.openThreeDotDropdown();
cy.clickOptionWithTestId("entity-menu-move-button");
cy.get('[data-testid="move-glossary-entity-modal"]').contains(glossaryTermGroup).click({ force: true });
cy.get('[data-testid="move-glossary-entity-modal"]').contains(glossaryTermGroup).should("be.visible");
cy.clickOptionWithTestId("glossary-entity-modal-move-button");
cy.waitTextVisible("Moved Glossary Term!");
// Ensure the new term is under the parent term group in the navigation sidebar
cy.get('[data-testid="glossary-browser-sidebar"]').contains(glossaryTermGroup).click();
cy.get('*[class^="GlossaryEntitiesList"]').contains(glossarySecondTerm).should("be.visible");
// Switch between terms and ensure the "Properties" tab is active
cy.clickOptionWithText(glossaryTerm);
cy.get('[data-testid="entity-tab-headers-test-id"]').contains("Properties").click({ force: true });
cy.get('[data-node-key="Properties"]').contains("Properties").should("have.attr", "aria-selected", "true");
cy.clickOptionWithText(glossarySecondTerm);
cy.get('[data-node-key="Properties"]').contains("Properties").should("have.attr", "aria-selected", "true");
// Move a term group from the root level to be under a parent term group // Move a term group from the root level to be under a parent term group
cy.goToGlossaryList(); cy.goToGlossaryList();
cy.clickOptionWithText(glossaryTermGroup); cy.clickOptionWithText(glossaryTermGroup);
@ -52,6 +86,10 @@ describe("glossary sidebar navigation test", () => {
cy.clickOptionWithText(glossaryTerm).wait(3000); cy.clickOptionWithText(glossaryTerm).wait(3000);
cy.deleteFromDropdown(); cy.deleteFromDropdown();
cy.waitTextVisible("Deleted Glossary Term!"); cy.waitTextVisible("Deleted Glossary Term!");
cy.clickOptionWithText(glossaryTermGroup);
cy.clickOptionWithText(glossarySecondTerm).wait(3000);
cy.deleteFromDropdown();
cy.waitTextVisible("Deleted Glossary Term!");
cy.clickOptionWithText(glossaryParentGroup); cy.clickOptionWithText(glossaryParentGroup);
cy.clickOptionWithText(glossaryTermGroup).wait(3000); cy.clickOptionWithText(glossaryTermGroup).wait(3000);
cy.deleteFromDropdown(); cy.deleteFromDropdown();