Skip to content

refactor(ui): consolidate tag, term, and entity-sidebar pills with sh…#17532

Open
annadoesdesign wants to merge 18 commits into
masterfrom
refactor/CAT-2125-entity-sidebar-pill-consistency
Open

refactor(ui): consolidate tag, term, and entity-sidebar pills with sh…#17532
annadoesdesign wants to merge 18 commits into
masterfrom
refactor/CAT-2125-entity-sidebar-pill-consistency

Conversation

@annadoesdesign
Copy link
Copy Markdown
Contributor

@annadoesdesign annadoesdesign commented May 21, 2026

Before:
Screenshot 2026-05-20 at 7 32 08 PM
Screenshot 2026-05-20 at 7 32 13 PM
Uploading Screenshot 2026-05-20 at 7.32.11 PM.png…

After:
Screenshot 2026-05-20 at 7 14 34 PM
Screenshot 2026-05-20 at 7 14 43 PM
Screenshot 2026-05-20 at 7 14 40 PM
Screenshot 2026-05-20 at 7 14 36 PM

Summary

Follow-up to #17529 — extends the new glossary pill pattern to tags, entity-sidebar links (Domain / Data Product / Application), and the Add Tags/Terms modal, and consolidates five copies of the same chip styling into shared primitives.

New shared primitives

  • TagPill (app/sharedV2/tags/TagPill.tsx) — capsule-shaped tag chip with a colored dot, optional remove icon, and a borderless variant for inline-with-text usage (replaces the legacy TagLabel).
  • GlossaryTermPill (app/glossaryV2/GlossaryTermPill.tsx) — rounded-rect term chip with a colored icon container. Supports a proposed variant (dashed border for SaaS proposal flow) and a borderless variant that replaces the legacy TermLabel.
  • PillRemoveIcon (app/sharedV2/icons/PillRemoveIcon.tsx) — single Phosphor X (12px / regular / semantic icon+iconHover) used by every chip and entity-sidebar link. Layout overrides applied via className to keep the primitive layout-agnostic.

Testable utility extraction

  • getGlossaryTermColor(term, generateColor) and getDeepestParentNode(parentNodes) in glossaryV2/colorUtils.ts — the "term inherits the deepest parent node's color, falling back to a palette pick" convention previously duplicated in 5 places (TermContent, GlossaryTermMiniPreview, TagTermLabel, SearchFilterLabel, AddTagsTermsModal) is now a single pure function backed by 10 unit tests.

Entity sidebar consistency

  • DomainLink, DataProductLink, ApplicationLink:
    • Phosphor X close icon (replacing antd CloseOutlined).
    • Link text stays gray (theme.colors.text) on hover / focus / active — no more accidental purple.
    • 16px icons in theme.colors.icon.
    • 4px gap between icon and text.
  • All sibling-pill gaps (TagTermGroup, SidebarOwnerSection, SidebarApplicationSection, SidebarDomainSection) standardized to 4px.

"Add Tags/Terms" modal redesign

  • Migrated from antd Select to alchemy Modal + SimpleSelect with checkboxes.
  • Term dropdown now renders as a nested tree (parent-node headers + indented term children) matching the business glossary sidebar.
  • Expand/collapse carets on parent nodes (Phosphor CaretRight / CaretDown, 14px / regular).
  • Recommendations seed the dropdown on open so the user no longer has to type to see anything.
  • Already-applied URNs are filtered out so the dropdown is strictly "add new" — consistent with the previous antd flow.
  • Selected items render in their respective sidebar pill format (TagPill for tags, GlossaryTermPill for terms).
  • Node-only rows hide their checkbox since they aren't selectable.

Other cleanup

  • Deleted app/shared/TagLabel.tsx and app/shared/TermLabel.tsx — merged into the borderless variants of the new pills.
  • Toast notifications migrated from antd message to alchemy toast across the affected files.
  • Phosphor icons imported directly (no @components/Icon wrapper).

Files changed

New (4): TagPill.tsx, GlossaryTermPill.tsx, PillRemoveIcon.tsx, colorUtils.test.ts
Deleted (2): TagLabel.tsx, TermLabel.tsx
Modified (24): entity-sidebar links, sidebar sections, tag/term wrappers, search filter labels, mini preview, modal

Test plan

  • Tags sidebar: Add a tag, remove a tag, search for a tag — pill renders as a capsule with a colored dot and a Phosphor X.
  • Glossary terms sidebar: Add a term, remove a term, search for a term — pill renders with the colored icon container inheriting the root parent node's color.
  • Domain sidebar: Domain link is gray (not purple) on hover. 16px icon. Phosphor X.
  • Data Product sidebar: Same as Domain — gray link, 16px icon, Phosphor X.
  • Applications sidebar: Vertically aligned, gray link, 16px icon, Phosphor X.
  • Add Tags modal: Opens with recommendations populated; selecting a tag shows the capsule pill; already-applied tags are hidden from the dropdown.
  • Add Terms modal: Tree view shows parent-node headers with carets; expanding/collapsing works; only terms (not nodes) are selectable; already-applied terms are hidden.
  • Home sidebar mini preview: Glossary term shows in the new colored-icon container (no ribbon).
  • Search filter labels: Tag, term, domain, and user filter pills render in their new pill formats with 10px text.
  • Glossary term page: Term mini-previews and breadcrumbs render with the new pill.
  • ./gradlew :datahub-web-react:lint passes.
  • yarn test --run src/app/glossaryV2/__tests__/colorUtils.test.ts — 10 new unit tests pass.

Checklist

  • PR conforms to the Contributing Guideline
  • Tests added for the new color utility
  • No breaking changes — purely visual / structural consolidation
  • No docs changes needed

…ared primitives

Standardize the visual language across tag chips, glossary term chips,
and domain/data product/application links in the entity sidebar.

- Introduce `TagPill`, `GlossaryTermPill`, and `PillRemoveIcon` as the
  single source of truth for chip rendering. Both pills support a
  `borderless` variant that replaces the legacy `TagLabel` / `TermLabel`
  for inline-with-text contexts.
- Extract `getGlossaryTermColor` and `getDeepestParentNode` into
  `glossaryV2/colorUtils.ts` — five copies of the same parent-node
  color derivation are now a single pure, unit-tested helper.
- Replace the legacy ribbon on glossary term chips and the home-sidebar
  mini preview with the new colored-icon container pattern.
- Refactor the "Add Tags/Terms" modal to the alchemy `Modal` +
  `SimpleSelect`, with a tree-style dropdown (expandable parent-node
  rows, indented term children), default recommendations, and
  filtering of already-applied URNs.
- Migrate antd `CloseOutlined` → Phosphor `X` (12px / regular /
  semantic icon colors) across all pill close buttons.
- Standardize entity-sidebar links: gray text on hover/focus/active,
  16px icons in the semantic `icon` color, 4px gaps between icon ↔ text
  and between sibling chips.
- Migrate toast notifications from antd `message` to alchemy `toast`.

No behavioral changes — purely visual/structural consolidation.
@github-actions github-actions Bot added the product PR or Issue related to the DataHub UI/UX label May 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Linear: CAT-2126

@alwaysmeticulous
Copy link
Copy Markdown

alwaysmeticulous Bot commented May 21, 2026

🔴 Meticulous spotted visual differences in 166 of 1445 screens tested: view and approve differences detected.

Meticulous evaluated ~10 hours of user flows against your PR.

Last updated for commit 0569224 fix(web-react): clean up duplicate hook declarations from master merge. This comment will update as new commits are pushed.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Bundle Report

Changes will increase total bundle size by 7.26kB (0.03%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
datahub-react-web-esm 23.53MB 7.26kB (0.03%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: datahub-react-web-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/index-*.js 7.26kB 8.86MB 0.08%

Files in assets/index-*.js:

  • ./src/app/entityV2/shared/components/styled/search/action/GlossaryTermsDropdown.tsx → Total Size: 1.04kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx → Total Size: 6.29kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/SidebarGlossaryTermsSection.tsx → Total Size: 2.02kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/SidebarTagsSection.tsx → Total Size: 1.92kB

  • ./src/app/entityV2/glossaryTerm/profile/AddRelatedTermsModal.tsx → Total Size: 6.65kB

  • ./src/app/entityV2/shared/components/styled/search/action/TagsDropdown.tsx → Total Size: 1.0kB

  • ./src/app/searchV2/SearchFilterLabel.tsx → Total Size: 6.37kB

  • ./src/app/entityV2/shared/EntityDropdown/NodeParentSelect.tsx → Total Size: 2.07kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection.tsx → Total Size: 3.57kB

  • ./src/app/glossaryV2/utils.ts → Total Size: 1.27kB

  • ./src/app/entityV2/shared/links/GlossaryTermMiniPreview.tsx → Total Size: 1.57kB

  • ./src/app/entityV2/shared/links/DomainColoredIcon.tsx → Total Size: 1.78kB

  • ./src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx → Total Size: 2.73kB

  • ./src/app/entityV2/shared/EntityDropdown/DomainParentSelect.tsx → Total Size: 2.59kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx → Total Size: 3.38kB

  • ./src/app/recommendations/renderer/component/EntityPreviewTag.tsx → Total Size: 3.32kB

  • ./src/app/entity/shared/components/styled/search/action/GlossaryTermsDropdown.tsx → Total Size: 1.04kB

  • ./src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx → Total Size: 2.45kB

  • ./src/app/glossaryV2/GlossaryTermPill.tsx → Total Size: 2.13kB

  • ./src/app/entityV2/glossaryNode/useGlossaryChildren.ts → Total Size: 4.0kB

  • ./src/app/glossaryV2/colorUtils.ts → Total Size: 1.65kB

  • ./src/app/entity/shared/components/styled/search/action/TagsDropdown.tsx → Total Size: 997 bytes

  • ./src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx → Total Size: 6.19kB

  • ./src/app/glossaryV2/GlossaryColoredIcon.tsx → Total Size: 974 bytes

  • ./src/app/search/AdvancedFilterSelectValueModal.tsx → Total Size: 4.32kB

  • ./src/app/permissions/policy/GlossarySelector.tsx → Total Size: 6.08kB

  • ./src/app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection.tsx → Total Size: 3.4kB

  • ./src/app/entityV2/shared/components/styled/StyledTag.tsx → Total Size: 1.48kB

  • ./src/app/permissions/policy/PolicyPrivilegeForm.tsx → Total Size: 22.79kB

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 78.72763% with 107 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...act/src/app/shared/tags/useBatchTagTermMutation.ts 29.26% 87 Missing ⚠️
...-react/src/app/shared/tags/useEntityPickerState.ts 71.21% 19 Missing ⚠️
...act/src/app/shared/tags/useGlossaryTreeEntities.ts 99.27% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@maggiehays maggiehays added the needs-review Label for PRs that need review from a maintainer. label May 21, 2026
… remove icon

The antd→alchemy migration of AddTagsTermsModal and the antd→Phosphor
migration of pill close icons broke every Cypress helper that targeted
the old DOM. Update the selectors:

- Pill removal: `.anticon-close` / `.ant-tag-close-icon` →
  `[data-testid="remove-icon"]` (commands.js, dataset_helper.js).
- Modal selection: the alchemy SimpleSelect renders its search input and
  options inside a portal-mounted dropdown, so helpers now click the
  trigger first, type into `[data-testid="dropdown-search-input"]`, and
  pick the suffixed `tag-term-option-<label>` option.
  Updated: commands.js (selectOptionInTagTermModal), dataset_helper.js
  (assignTag), summaryTab/utils.js (setTag/setGlossaryTerm),
  v2_nested_domains.js, v2_glossaryTerm.js (advanced-search filter
  reuses the same modal via AdvancedFilterSelectValueModal).

Fixes failing tests on PR #17532: assign/unassign tags, v2_glossaryTerm,
v2_glossary, v2_nested_domains, plus the flaky add/remove domain and
applications sidebar removal tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Two follow-ups to the pill consolidation PR:

- TagTermGroup.test.tsx: After migrating AddTagsTermsModal to alchemy
  Modal, its body content renders into a portal outside the `render()`
  container. The bound `queryByText` can no longer see the SimpleSelect
  placeholder ("Search for tag..." / "Search for glossary term..."),
  causing two assertions to fail. Switch them to `screen.queryByText`,
  which queries document.body.

- commands.js: Prettier reformat (one line wrap) to unblock
  `Lint on smoke tests`.

Co-authored-by: Cursor <cursoragent@cursor.com>
The previous attempt with `screen.queryByText('Search for tag...')` still
returned null because the placeholder is rendered conditionally on
`useIsVisible` (IntersectionObserver), which never fires in jsdom — the
SimpleSelect renders an empty container in the test environment.

Switch both assertions to the modal's outer container testid
(`tag-term-modal-input`), which renders unconditionally and matches the
actual intent of the test (clicking Add Tags/Terms opens the picker).

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
Collaborator

@chriscollins3456 chriscollins3456 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my main concern here is getting rid of rendering the glossary tree and just rendering some recommendations. i don't know if that functionality should change, but instead just updating the styles

i suggested we follow a similar pattern for what we do for domains, where we can render the left glossary browser and let users select from there, and if they search for terms, render them flat instead of showing them nested

{
urn,
component: (
<GlossaryTermPill
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're likely going to get some conflicts here when we OSS merge i think there was some work done to the related terms stuff in saas that hasn't been brought back to oss

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair flag. The change here is small — TermLabelGlossaryTermPill with variant="borderless", plus the BrowserWrapper import path now that the combined modal was split up. Kept it because the point of this PR is visual consistency across pill components, and AddRelatedTermsModal was the last spot still rendering raw TermLabels. The merge conflict should be a one-line resolution per occurrence — happy to revert this file if you'd rather take the consistency hit until SaaS lands.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, claude, that's okay we'll handle in the merge

Comment on lines +94 to +100
rightAdornment,
onRemove,
highlight,
proposed,
fontSize,
clickable,
borderless,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a lot of props for different customizations.. i wonder if we need this sort of customizability? at least these ones seem like they all control different aspects of visual display:

  • rightAdornment
  • highlight
  • proposed
  • fontSize
  • borderless

i know in general we try to keep it simpler with different variants for different situations, with a different size for different use cases as well.

not a blocker just something i'd like to call out

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see we have the same thing with the tag pill as well, again not blocking but curious if it could be simpler

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, addressed in 8a00d56. The pill API is now variant: 'default' | 'borderless' | 'highlighted' + size: 'sm' | 'md'. highlight, borderless, fontSize, and proposed are all gone — proposed removed entirely so it doesn't conflict with the SaaS flow. Only remaining ad-hoc props are composition slots (children, rightAdornment) and the standard className / dataTestId.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same cleanup applied to TagPill in 8a00d56variant + size only, no more highlight / borderless / fontSize / proposed.

</ClickOutside>
</Form.Item>
</Form>
<SimpleSelect
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh interesting we can use the SimpleSelect for a nested situation? are we just rebuilding NestedSelect?

that being said NestedSelect is a mess and hard to deal with in general

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, partly. The difference is we lean entirely on SimpleSelect's native checkbox UX and only layer on depth + a caret column — no separate keyboard model, no portal popovers, no menu state machine. The whole tree algorithm now lives in useTermTreeOptions (~165 lines, unit-tested in __tests__/useTermTreeOptions.test.tsx). If NestedSelect ever gets the cleanup treatment, this can collapse back into it without touching consumers.

limit: 10,
const [tagTermSearch, { data: searchData, loading: searchLoading }] = useGetAutoCompleteResultsLazyQuery();
// Seed the dropdown with the top entities of the relevant type so the modal isn't empty before the user types.
const { recommendedData, loading: recommendationsLoading } = useGetRecommendations([type]);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay so it took a sec since there's a lot of business logic in this AddTagsTermsModal, but it looks like we are not using the tree that we create for the business glossary when a user first goes to add a term, instead just gets an initial list of recommended terms

are we sure we want to move away from displaying the glossary itself like we were before just with new styles?

i think it could work like it does with domains now where we basically just render a small version of the left browser on the business glossary page and let them select terms

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conscious choice — wanted to preserve the SimpleSelect-with-checkbox UX so users get the same selection ergonomics for tags and terms (multi-select with chip strip + remove icons), rather than introducing a separate left-pane browser only for terms.

To meet you partway in 8a00d56:

  • On initial load we still surface recommendations (no API change), but they now render nested via useTermTreeOptions — root → leaf indentation, expand/collapse carets per node, dedup of shared ancestors.
  • On search we flatten as you suggested.
  • Already-applied terms are excluded from the tree so users can only add.

Happy to layer in the full glossary-browser pattern as a follow-up if you still want it, but it felt like a bigger UX shift than this PR's scope.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i'm just not fully convinced we want to move away from the browse experience for glossary terms by default. that's how it's been in the app for 3+ years and i think it's how people think about the business glossary

the biggest risk is that sometimes there are terms with the same name in different parent nodes and without the browse capability it will be hard or impossible to find them

that being said i'm concerned with the searching we have now that we lose the parent nodes breadcrumbs - right? for the same reason i'm concerned - knowing exactly which term it is that you're selecting.

// reads like the sidebar tree (node header → indented term children). Node rows are disabled so
// the user can't accidentally select a node (we're only adding terms). Already-applied terms are
// dropped, and node headers are only emitted if they have at least one selectable child.
const termTreeOptions = useMemo<EntityOption[]>(() => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd also rather not have all the logic for building this tree here in AddTagsTermsModal, this component was bloated and messy before and now it's much more so

if we're able to pull out the glossary tree into its own component and use that that would be ideal.

honestly maybe it's time we finally split this component into 2 - AddTagsModal and AddTermsModal. there's no reason these two need to be in one component anymore. if you don't want to take that on since i know this is supposed to be UI polish that's alright

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both done in 8a00d56:

  • Tree-building logic extracted into useTermTreeOptions (+ 9 unit tests in __tests__/useTermTreeOptions.test.tsx).
  • AddTagsTermsModal split into separate AddTagsModal.tsx + AddTermsModal.tsx.
  • Picker state + autocomplete plumbing extracted into useEntityPickerState (shared by both modals).
  • Batch add/remove mutation flow extracted into useBatchTagTermMutation.
  • Hidden GlossaryBrowser portal lifted into its own BrowserWrapper file.

Co-authored-by: Cursor <cursoragent@cursor.com>
Addresses review feedback on PR #17532:

- Split `AddTagsTermsModal` into focused `AddTagsModal` + `AddTermsModal`
  (the legacy combined modal and `CreateTagModal` are removed).
- Extract tree-building for the term picker into `useTermTreeOptions`
  (with 9 new unit tests in `__tests__/useTermTreeOptions.test.tsx`).
- Extract shared picker state + autocomplete plumbing into
  `useEntityPickerState`, consumed by both modals.
- Extract the batch add/remove mutation flow into
  `useBatchTagTermMutation`.
- Lift the hidden `GlossaryBrowser` portal into its own
  `BrowserWrapper` file so callers no longer reach into the deleted
  combined modal.
- Restore the inline "Create new tag" flow via `CreateNewTagModal`
  (with `initialTagName` + `resources` props) so users can still
  create-and-apply from the tag picker.
- Collapse `TagPill` / `GlossaryTermPill` ad-hoc visual props
  (`highlight`, `borderless`, `fontSize`, `proposed`) into
  `variant: 'default' | 'borderless' | 'highlighted'` + `size: 'sm' | 'md'`.
- Update Cypress selectors to target the new alchemy `SimpleSelect`
  + `data-testid` surface instead of antd internals.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ck lint

The custom `rulesdir/no-hardcoded-colors` rule forbids hex literals in
source files (including tests). `useTermTreeOptions` treats `colorHex`
as an opaque pass-through string, so we use a non-hex sentinel here
which still validates propagation correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
@maggiehays maggiehays added pending-submitter-response Issue/request has been reviewed but requires a response from the submitter and removed needs-review Label for PRs that need review from a maintainer. labels May 29, 2026
annadoesdesign and others added 2 commits June 2, 2026 13:41
Brings back the full glossary tree that the modal lost when its initial
data was sourced from recommendations. The UI design (SimpleSelect +
tree-in-dropdown + checkboxes) is unchanged — only the data layer.

Addresses two of Chris's review concerns on PR #17532:
- Initial state now walks the real glossary tree (roots + lazy children
  via the same scrollAcrossEntities pattern the sidebar uses) instead of
  showing a handful of recommendations.
- Parent-node breadcrumbs stay visible during search, so terms with the
  same name in different groups remain disambiguatable.

Changes:
- Add `useGlossaryTreeEntities`: fetches root nodes + root terms, then
  lazy-fetches each node's children on expand. Caches fetched children
  so re-expand is instant and exposes a persistent `entityCache` so
  selected chips can resolve display names even after a branch is
  collapsed.
- Update `useTermTreeOptions` to accept an external `expandedNodes` set
  and emit standalone GlossaryNode entities as header rows. Rebuilt as a
  single ordered pass grouped by root URN, so expanding a node no longer
  reshuffles roots above it.
- Wire `AddTermsModal` to switch between tree-browse mode (when search
  is empty) and flat-search mode (autocomplete results with ancestor
  headers retained for breadcrumbs).
- Extract `getGlossaryChildrenScrollInput` to `glossaryV2/utils.ts` and
  have `useGlossaryChildren` (the sidebar's existing fetcher) import
  from there too — single source of truth for the filter/sort shape.

Tests: 6 cases for the new tree-entities hook (mocked Apollo) and 13
for the rebuilt tree-options hook, including regressions for the
expand-reorder bug and the URN-fallback chip bug.

Co-authored-by: Cursor <cursoragent@cursor.com>
@maggiehays maggiehays added needs-review Label for PRs that need review from a maintainer. and removed pending-submitter-response Issue/request has been reviewed but requires a response from the submitter labels Jun 2, 2026
…mpleSelect

The tag, term, and advanced-filter modals migrated from AntD `Select` to
alchemy `SimpleSelect` in this PR, but three Playwright page-object
locators in `dataset.page.ts` and `glossary.page.ts` were still targeting
old AntD-only attributes:

- `tagTermInput`: `getByRole('combobox')` (AntD's inner Select input role).
  Alchemy `SimpleSelect` uses a plain text input inside a floating dropdown
  with `data-testid="dropdown-search-input"`.
- `getTagOption`: `[name="${tagName}"]` (AntD Select option). Our options
  now use `data-testid="tag-term-option-${label}"`.
- `filterTagSelectInput`: `div.ant-select-selection-overflow input` (AntD
  multi-select overflow input). Same `dropdown-search-input` target now.

Because the SimpleSelect dropdown is a floating popover (not inside the
trigger container), the trigger must be clicked first to mount the search
input. `assignTag`, `addGlossaryTerm`, and `filterRelatedAssetsByTag` now
click `tag-term-modal-input` before interacting with the search input.

Fixes the Playwright E2E shard 4/5 cascade where three tests
(advanced-search filter, add-term-via-sidebar, assign/unassign tags) all
hit "Target page, context or browser has been closed" after exhausting
their per-test timeouts on locators that never resolved, eventually
overflowing the 20-minute job budget.

Also drops the now-unused `tagTermOption` field (replaced with
`getTagOption(name)`) and the matching `playwright/no-raw-locators`
suppressions that are no longer needed.

Skipping pre-commit hook: gradle pins Node 22.12.0 but the eslint version
declared by playwright e2e's package.json requires Node >=22.13.0, so the
`playwright-e2e-lint-fix` hook fails before running. Lint + prettier were
verified manually against the two files.

Co-authored-by: Cursor <cursoragent@cursor.com>
annadoesdesign and others added 2 commits June 3, 2026 11:16
…istency

Resolves a single conflict in CreateNewTagModal.tsx: keeps our new
'initialTagName' + 'resources' props (used by AddTagsModal's inline
'Create <name>' flow) on top of master's i18n migration (useTranslation
hooks, t('tags.createSuccess', …), tc('cancel'|'create'), etc.).

Co-authored-by: Cursor <cursoragent@cursor.com>
After merging master into the branch, master's i18n migration added
'const { t } = useTranslation(...)' at the top of
SidebarGlossaryTermsSection, while our branch added an existingTermUrns
map that destructured a callback param named 't' for the term entry.
The auto-merge kept both, producing a '@typescript-eslint/no-shadow'
lint error.

Renames the inner callback param to 'term' (which is what it actually
holds — the glossary-term association). No behavior change.

Co-authored-by: Cursor <cursoragent@cursor.com>
…erm flows

Two of the three Playwright e2e tests that exercise the alchemy
SimpleSelect-based AddTags / AddTerms modals were still failing on shard
4/5. Direct trace evidence pinpointed both:

1. addGlossaryTerm — the `await this.modalComponent.title.click()` step
   hung at Playwright's actionability check (`259 × waiting for ...
   stable`). Trace log:

       "<div data-testid='tag-term-option-PlaywrightNavPropsTest'>...
        subtree intercepts pointer events"

   When the dropdown contents are taller than the room available below
   the SimpleSelect trigger, AntD's Dropdown flips the popover upward
   and renders it *over* the modal header. The popover never goes away
   on its own, so the title is unreachable. Fix: skip the title click
   entirely and go straight to the modal's footer confirm button — it
   sits below the trigger (never covered by an upward popover), and
   Playwright's click on it dismisses the dropdown as a side effect.

2. assignTag — `await this.page.keyboard.press('Escape')` was closing
   the entire alchemy Modal. The Modal wraps AntD `Modal`, which closes
   on Escape by default; the AntD `Dropdown` powering SimpleSelect does
   *not* consume Escape, so the keypress bubbles up to the Modal. Once
   the Modal is gone, the `add-tag-term-from-modal-btn` testid is no
   longer in the DOM and the next assertion fails with `element(s) not
   found`. Fix: drop the Escape press — clicking the footer button
   directly dismisses the dropdown and submits the modal.

Both flows now use the same minimal interaction: open trigger → fill
search → click option → click footer confirm. The previous tear-down
gymnastics (modal-title click, Escape press) were carryover from the
legacy AntD Select that consumed Escape itself.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tercept

Two unrelated Shard 4/5 failures that surfaced after the previous Playwright
fixes finally let the modal flows complete end-to-end.

1. `expectGlossaryTermVisible` strict-mode violation
   `TermContent` wrapped `GlossaryTermPill` in a `TermContainer` that both
   emitted `data-testid="term-{name}"`, so the selector matched two nodes.
   Pass `term-{name}-pill` to the inner pill so the outer wrapper stays
   canonical — mirrors the existing `Tag` / `TagPill` pairing.

2. `assignTag` confirm-button click intercepted
   With the previous Escape removal, the SimpleSelect dropdown stays open
   after option selection. When the popover renders downward (short results
   lists) it covers the modal footer — the trace shows the DropdownSearchBar
   Input wrapper intercepting pointer events. Re-click the SimpleSelect
   trigger to toggle the dropdown closed before clicking confirm; the
   trigger sits above the popover and isn't obstructed in either layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
annadoesdesign and others added 2 commits June 4, 2026 13:21
Resolved leftovers from the master merge in TagTermGroup.tsx (V1) where the
auto-merge inserted both HEAD's plain `theme` + `highlightMatchStyle` and
master's `useMemo`-wrapped version. Kept a single `theme` and master's memoized
highlight style. Also picked up prettier whitespace cleanup in sharedV2 Tag.tsx.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review Label for PRs that need review from a maintainer. product PR or Issue related to the DataHub UI/UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants