Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aab5b53
Fix dark-mode status counts, tab counts, table header divider and ent…
shah-harshit Oct 16, 2026
e554ab0
Pin the Connections composer to the canvas edge and record the tinted…
shah-harshit Oct 16, 2026
ceecf80
Mark Classic mode as deprecated in the mode switchers and the admin s…
shah-harshit Oct 16, 2026
29045e6
Merge remote-tracking branch 'origin/main' into shah-harshit/automati…
shah-harshit Oct 16, 2026
c806882
Give Insights tab tiles and DQ pie cards consistent core Card padding
shah-harshit Oct 16, 2026
006ef1f
Move the status badge color map to IngestionStatusCount.constants.ts
shah-harshit Oct 16, 2026
d468089
Keep domain and data product avatars solid in both themes
shah-harshit Oct 16, 2026
10e4c4b
Drop the darker bands from the column detail drawer in dark mode
shah-harshit Oct 16, 2026
b7e24db
Render the contract result pill as a core Badge and fix the Beta tab …
shah-harshit Oct 16, 2026
eafd3ca
chore(playwright): auto-refresh impact-map.generated.json
github-actions[bot] Oct 16, 2026
e7bda40
Keep the empty test-status chart inside its card
shah-harshit Oct 16, 2026
8967169
Address review: keep HoverCard open on focus, keep DP contract link o…
shah-harshit Oct 16, 2026
513169e
fix(ui): converge Archive badge count after an async hard delete (#35…
Rohit0301 Oct 16, 2026
75357a6
Fixes #35473: Export and Bulk Edit only the filtered test cases (#35474)
TeddyCr Oct 16, 2026
8fd7219
Fixes open-metadata/openmetadata-collate#7447: forward aria-label on …
anuj-kumary Oct 16, 2026
6bfc93b
Fixes #35519: Stabilise flaky glossary Playwright specs (#35520)
anuj-kumary Oct 16, 2026
66196b0
fix(security): bump guava to 33.7.2-jre, hibernate-validator to 8.0.6…
karanh37 Oct 16, 2026
8ea088a
Fixes open-metadata/openmetadata-collate#4719: let a password reset l…
mohityadav766 Oct 16, 2026
2bb916b
Fixes #33865: Inline lineage editing via node and column menus (#34551)
chirag-madlani Oct 16, 2026
d21bb2a
Fixes #32000, #33553: Hand confidential OIDC browsers the identity pr…
mohityadav766 Oct 16, 2026
8b35e7e
Chore: Remove Delta Lake connector (#35299)
akashverma0786 Oct 16, 2026
3899674
Fixes #34689: record every Assets tab edit on the asset as its own PA…
manerow Oct 16, 2026
3024564
Fixes #34249: Add Neo4j database connector (#34250)
michaelgong428 Oct 16, 2026
a6e2051
fix(lineage): strip FQN quotes from schema/db/table names before appl…
zerafachris Oct 16, 2026
9270f59
Fix TagPage test mock, refresh ai-explore baseline, record Classic de…
shah-harshit Oct 16, 2026
e0fd5a1
chore(playwright): auto-refresh impact-map.generated.json
github-actions[bot] Oct 16, 2026
0baa93c
Update generated TypeScript types and dereferenced schemas
github-actions[bot] Oct 16, 2026
2b822f5
Merge origin/main and drop main commits replayed by a rebase
shah-harshit Oct 16, 2026
589a3e3
Merge remote-tracking branch 'origin/shah-harshit/automations-icons-f…
shah-harshit Oct 16, 2026
cdcd9bf
Reset bot-generated schema JSON and impact map to main
shah-harshit Oct 16, 2026
a3ecb4e
chore(playwright): auto-refresh impact-map.generated.json
github-actions[bot] Oct 16, 2026
a240db1
Merge origin/main into shah-harshit/automations-icons-fix
shah-harshit Oct 17, 2026
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
13 changes: 9 additions & 4 deletions .github/playwright/impact-map.generated.json
Original file line number Diff line number Diff line change
Expand Up @@ -6148,8 +6148,6 @@
"playwright/e2e/Features/StorageMetadataAgentForm.spec.ts",
"playwright/e2e/Features/Table.spec.ts",
"playwright/e2e/Features/TierWidget.spec.ts",
"playwright/e2e/Pages/DataContracts.spec.ts",
"playwright/e2e/Pages/DataContractsSemanticRules.spec.ts",
"playwright/e2e/Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts",
"playwright/e2e/Pages/TableCreationTime.spec.ts"
]
Expand Down Expand Up @@ -6218,6 +6216,15 @@
"playwright/e2e/Pages/ODCSImportExportPermissions.spec.ts"
]
},
{
"sources": [
"openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractLatestResultBadge/ContractLatestResultBadge.tsx"
],
"specs": [
"playwright/e2e/Pages/DataContracts.spec.ts",
"playwright/e2e/Pages/DataContractsSemanticRules.spec.ts"
]
},
{
"sources": [
"openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractQualityFormTab/ContractQualityFormTab.tsx"
Expand Down Expand Up @@ -6405,8 +6412,6 @@
],
"specs": [
"playwright/e2e/Features/DataAssetRulesEnabled.spec.ts",
"playwright/e2e/Pages/DataContracts.spec.ts",
"playwright/e2e/Pages/DataContractsSemanticRules.spec.ts",
"playwright/e2e/Pages/DataProductAndSubdomains.spec.ts",
"playwright/e2e/Pages/DomainAdvanced.spec.ts"
]
Expand Down
35 changes: 35 additions & 0 deletions docs/decisions/2026-10-16-classic-mode-is-deprecated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Classic mode is deprecated; the UI says so only where the mode is chosen

- **Status:** Accepted
- **Revisions:** v1 2026-10-16 (initial)
- **Deciders:** Pere Miquel Brull (product), Chirag Madlani (UI), Reethika (design)
- **Guard:** `AppModeSwitcher.test.tsx`, `InterfaceModeMenuItem.test.tsx`,
`DefaultAppModePage.test.tsx` (Deprecated badge and notice on the Classic option only)
- **Related:** open-metadata/openmetadata-collate#7533, #35609,
ADR:2026-10-12-dark-mode-targets-ai-mode-core-surfaces-only

## Context
AI mode is the go-forward interface, and Classic mode will be removed. Users and admins need
to hear that before it happens. Product asked that the product itself not be invasive about
it: the main channel is the release notes, and the UI should not nag every user on every page.

## Decision
- Classic mode is deprecated as of 2026-10. It stays fully supported until the release that
removes it, which the release notes will name.
- The UI marks Classic as *Deprecated* (core warning `Badge`), with a short notice and a link
to the release notes, only where the mode is chosen:
- the AI-shell mode switcher and the classic profile dropdown, on the Classic option once the
menu is open (a `HoverCard` on hover or keyboard focus). It is never on the always-visible
switcher trigger;
- the admin *Default App Mode* setting, as a hint under the Classic radio.
- The shipped copy promises the following, and the removal release must honour it: an
organization `defaultAppMode` or persona app mode still set to Classic is moved to AI, and a
user switching from Classic to AI keeps their settings.

## Consequences
New surfaces that offer a Classic/AI choice add the same badge and notice; nothing else
mentions the deprecation. The removal release owns the migration of Classic values to AI. If
product drops that migration, change the copy (`message.classic-mode-retiring-*`) in the same
release and amend this record. ADR:2026-10-12-dark-mode-targets-ai-mode-core-surfaces-only
already scopes dark mode to AI mode; once Classic is removed, its Classic carve-out no longer
applies.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Light featured icons stay tinted in dark mode

- **Status:** Accepted
- **Revisions:** v1 2026-10-16 (initial)
- **Deciders:** UI team, design
- **Guard:** `reviewer` for `featured-icon.tsx`
- **Related:** open-metadata/openmetadata-collate#7533, ADR:2026-10-12-dark-mode-targets-ai-mode-core-surfaces-only

## Context
`FeaturedIcon` with `theme="light"` switched to a solid fill (`bg-*-solid`, white glyph) under
`.dark-mode`, inherited from the UntitledUI port (#29412). The AI-mode Home topic cards draw a
tinted tile instead (`bg-utility-<c>-50` + `text-utility-<c>-600`), so AI Automations and other
pages read as heavier, louder blocks next to Home, and callers patched it locally
(`CriticalAnnouncementBanner`, `StatCard`, Collate `agentIconMap`).

## Decision
- `FeaturedIcon` `theme="light"` keeps a tinted tile in dark: `tw:dark:bg-utility-<c>-50
tw:dark:text-utility-<c>-600`. Light mode is unchanged.
- Domain and data product avatars (`getEntityAvatarProps`) are out of scope: users pick their
color, so they stay a solid fill in both themes until custom colors are revisited.

## Consequences
Tinted icon tiles come from the core component, so callers stop overriding colors to match Home.
A page that wants a solid tile in dark must pick a solid theme (`dark`, `modern`) rather than
`light`. Revisit only if design moves Home itself back to solid tiles, or when entity custom
colors are reworked.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ describe('HoverCard', () => {
expect(screen.queryByText('Profile')).toBeNull();
});

it('stays open while keyboard focus moves from the trigger into the card', () => {
renderCard({ openDelay: 0, closeDelay: 200 });

fireEvent.keyDown(document.body, { key: 'Tab' });
act(() => screen.getByText('Jane').focus());
advance(0);

act(() => screen.getByText('Profile').focus());
advance(500);

expect(screen.getByText('Profile')).toBeInTheDocument();

act(() => screen.getByText('Profile').blur());
advance(500);

expect(screen.queryByText('Profile')).toBeNull();
});

it('never opens when disabled', () => {
renderCard({ isDisabled: true, openDelay: 0 });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ export const HoverCard = ({
onHoverStart: () => schedule(true),
onHoverEnd: () => schedule(false),
});
// Focus moving from the trigger into the card (e.g. to a link inside it) must
// keep the card open; otherwise the trigger's blur closes it under the user.
const { focusWithinProps: cardFocusWithinProps } = useFocusWithin({
isDisabled,
onFocusWithinChange: (isFocused) => schedule(isFocused),
});
// Only keyboard focus opens the card; a mouse click that focuses the trigger
// is already covered by hover.
const { focusWithinProps } = useFocusWithin({
Expand Down Expand Up @@ -121,7 +127,7 @@ export const HoverCard = ({
triggerRef={triggerRef}
onOpenChange={setIsOpen}>
<div
{...cardHoverProps}
{...mergeProps(cardHoverProps, cardFocusWithinProps)}
className={cx(
'tw:rounded-xl tw:bg-overlay-surface tw:p-4 tw:shadow-lg tw:outline-1 tw:outline-secondary_alt',
className
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ const TableHeader = <T extends object>({
// Row border—using an "after" pseudo-element to avoid the border taking up space.
bordered &&
'tw:[&>tr>th]:after:pointer-events-none tw:[&>tr>th]:after:absolute tw:[&>tr>th]:after:inset-x-0 tw:[&>tr>th]:after:bottom-0 tw:[&>tr>th]:after:h-px tw:[&>tr>th]:after:bg-border-secondary tw:[&>tr>th]:focus-visible:after:bg-transparent',
// Dark: the 8% white divider resolves to the body-row surface under the darker
// header band, so the edge vanishes; border-primary keeps it visible.
bordered && 'tw:dark:[&>tr>th]:after:bg-border-primary',

typeof className === 'function' ? className(state) : className
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,18 @@ describe('BadgeWithButton tooltip', () => {

expect(screen.getAllByRole('button')).toHaveLength(1);
});

it('keeps its own text color when rendered as a link', () => {
render(
<Badge color="error" data-testid="linked-badge" href="/somewhere">
Failed
</Badge>
);

const badge = screen.getByTestId('linked-badge');

expect(badge.tagName).toBe('A');
expect(badge).toHaveClass('tw:text-utility-error-700', 'tw:no-underline');
expect(badge).not.toHaveClass('tw:text-inherit');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,10 @@ export const Badge = <T extends BadgeTypes>(props: BadgeProps<T>) => {
sizes[type][size],
colors.styles[color].root,
bordered && 'tw:outline-1 tw:-outline-offset-1',
// A linked badge must look identical to a non-linked one — no
// browser default underline/link color, and it must inherit the
// badge's own text color rather than react-aria-components' link styles.
href && 'tw:text-inherit tw:no-underline',
// A linked badge must look identical to a non-linked one: no underline,
// and the color root's text class sets its color. `tw:text-inherit` here
// would win the tailwind-merge conflict and drop that color.
href && 'tw:no-underline',
className
)}
data-testid={dataTestId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ const outlineBorders: Record<FeaturedIconColor, string> = {
};

const styles = sortCx({
// Dark: tinted tile (the home topic-card look), not a solid fill.
light: {
base: 'tw:rounded-full tw:dark:text-fg-white',
base: 'tw:rounded-full',
sizes: {
sm: 'tw:size-8',
md: 'tw:size-10',
Expand All @@ -39,14 +40,14 @@ const styles = sortCx({
},
colors: {
brand:
'tw:bg-brand-secondary tw:text-featured-icon-light-fg-brand tw:dark:bg-brand-solid',
'tw:bg-brand-secondary tw:text-featured-icon-light-fg-brand tw:dark:bg-utility-brand-50 tw:dark:text-utility-brand-600',
error:
'tw:bg-error-secondary tw:text-featured-icon-light-fg-error tw:dark:bg-error-solid',
gray: 'tw:bg-tertiary tw:text-featured-icon-light-fg-gray tw:dark:bg-secondary-solid',
'tw:bg-error-secondary tw:text-featured-icon-light-fg-error tw:dark:bg-utility-error-50 tw:dark:text-utility-error-600',
gray: 'tw:bg-tertiary tw:text-featured-icon-light-fg-gray tw:dark:bg-utility-gray-50 tw:dark:text-utility-gray-600',
success:
'tw:bg-success-secondary tw:text-featured-icon-light-fg-success tw:dark:bg-success-solid',
'tw:bg-success-secondary tw:text-featured-icon-light-fg-success tw:dark:bg-utility-success-50 tw:dark:text-utility-success-600',
warning:
'tw:bg-warning-secondary tw:text-featured-icon-light-fg-warning tw:dark:bg-warning-solid',
'tw:bg-warning-secondary tw:text-featured-icon-light-fg-warning tw:dark:bg-utility-warning-50 tw:dark:text-utility-warning-600',
},
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ jest.mock('react-i18next', () => ({
}));

jest.mock('@openmetadata/ui-core-components', () => ({
Badge: ({
children,
...props
}: React.PropsWithChildren<Record<string, unknown>>) =>
React.createElement('span', props, children),
HoverCard: ({
children,
content,
}: React.PropsWithChildren<{ content: React.ReactNode }>) =>
React.createElement(React.Fragment, null, children, content),
Box: ({
children,
...props
Expand Down Expand Up @@ -100,6 +110,7 @@ jest.mock('../../hooks/currentUserStore/useCurrentUserStore', () => ({
jest.mock('../../constants/appMode.constants', () => ({
AI_APP_MODE: 'ai',
DEFAULT_APP_MODE: 'default',
CLASSIC_MODE_RELEASE_NOTES_URL: 'https://docs.example/releases',
}));

const getTrigger = () => screen.getByTestId('app-mode-switcher-trigger');
Expand Down Expand Up @@ -220,4 +231,22 @@ describe('AppModeSwitcher', () => {
expect(container).not.toBeEmptyDOMElement();
expect(getTrigger()).toBeInTheDocument();
});

it('marks Classic as deprecated inside the switcher only', () => {
render(<AppModeSwitcher />);

expect(
screen.queryByTestId('classic-deprecated-badge')
).not.toBeInTheDocument();

fireEvent.click(getTrigger());

expect(screen.getByTestId('classic-deprecated-badge')).toHaveTextContent(
'label.deprecated'
);
expect(screen.getByTestId('classic-deprecation-card')).toBeInTheDocument();
expect(
screen.getByTestId('classic-deprecation-release-notes')
).toHaveAttribute('href', 'https://docs.example/releases');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
* limitations under the License.
*/

import { Box, Popover, Typography } from '@openmetadata/ui-core-components';
import {
Badge,
Box,
HoverCard,
Popover,
Typography,
} from '@openmetadata/ui-core-components';
import { Check, ChevronUp } from '@openmetadata/ui-core-components/icons';
import classNames from 'classnames';
import React, { useRef, useState } from 'react';
Expand All @@ -30,6 +36,7 @@
useIsAiMode,
writeAppMode,
} from '../../hooks/useAppMode';
import { ClassicDeprecationCard } from './ClassicDeprecationNotice';

const OPTION_ICON_BOX =
'tw:w-9 tw:h-9 tw:rounded-[10px] tw:bg-utility-blue-50 tw:border tw:border-utility-blue-100 tw:shrink-0';
Expand Down Expand Up @@ -183,35 +190,45 @@
{t('label.switch-interface')}
</p>

<button
className={classNames(
'tw:flex tw:items-center tw:gap-2.5 tw:w-full tw:p-2.5 tw:rounded-xl tw:cursor-pointer tw:transition tw:bg-surface tw:border tw:text-left',
{
'tw:bg-utility-blue-50 tw:border-utility-blue-200': !isAiMode,
'tw:border-transparent tw:hover:bg-utility-blue-50': isAiMode,
}
)}
data-testid="app-mode-option-classic"
type="button"
onClick={handleClassicClick}>
<Box align="center" className={OPTION_ICON_BOX} justify="center">
<AppModeClassicIcon height={23} width={23} />
</Box>
<Box className="tw:flex-1 tw:min-w-0" direction="col">
<Typography
className="tw:text-primary"
size="text-sm"
weight="semibold">
{t('label.classic')}
</Typography>
</Box>
{!isAiMode && (
<span className={BADGE_CLASS} data-testid="classic-current-badge">
<Check height={12} width={12} />
{t('label.current')}
</span>
)}
</button>
<HoverCard content={<ClassicDeprecationCard />} placement="right">
Comment thread
greptile-apps[bot] marked this conversation as resolved.
<button
className={classNames(
'tw:flex tw:items-center tw:gap-2.5 tw:w-full tw:p-2.5 tw:rounded-xl tw:cursor-pointer tw:transition tw:bg-surface tw:border tw:text-left',
{
'tw:bg-utility-blue-50 tw:border-utility-blue-200': !isAiMode,
'tw:border-transparent tw:hover:bg-utility-blue-50': isAiMode,
}
)}
data-testid="app-mode-option-classic"
type="button"
onClick={handleClassicClick}>
<Box align="center" className={OPTION_ICON_BOX} justify="center">
<AppModeClassicIcon height={23} width={23} />
</Box>
<Box align="center" className="tw:flex-1 tw:min-w-0" gap={2}>
<Typography
className="tw:text-primary"
size="text-sm"
weight="semibold">
{t('label.classic')}
</Typography>
<Badge
color="warning"
data-testid="classic-deprecated-badge"
size="sm">
{t('label.deprecated')}
</Badge>
</Box>
{!isAiMode && (
<span
className={BADGE_CLASS}
data-testid="classic-current-badge">
<Check height={12} width={12} />
{t('label.current')}
</span>
)}
</button>
</HoverCard>

<button
className={classNames(
Expand Down Expand Up @@ -256,7 +273,7 @@
className={classNames(
'tw:w-5 tw:h-5 tw:rounded-md tw:shrink-0 tw:transition',
{
'tw:bg-blue-600 tw:border-0': isRemembered,

Check warning on line 276 in openmetadata-ui/src/main/resources/ui/src/components/AppModeSwitcher/AppModeSwitcher.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Raw palette class "tw:bg-blue-600" is static — it does not flip in dark mode. Use the theme-adapting "utility-" variant (tw:bg-utility-blue-600) or a semantic token (bg-surface, text-tertiary, …). See docs/colors.md
'tw:bg-surface tw:border tw:border-utility-gray-400':
!isRemembered,
}
Expand Down
Loading
Loading