Skip to content

Commit 1bcfdb2

Browse files
authored
feat: Global breadcrumbs feature flag (#5113)
1 parent a8c4713 commit 1bcfdb2

10 files changed

Lines changed: 61 additions & 19 deletions

File tree

‎pages/app/index.tsx‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import styles from './styles.scss';
2626
interface GlobalFlags {
2727
appLayoutWidget?: boolean;
2828
appLayoutToolbar?: boolean;
29+
appLayoutHideToolbarBreadcrumbs?: boolean;
2930
oneTheme?: boolean;
3031
}
3132
// used for local dev / testing
@@ -99,9 +100,15 @@ function App() {
99100
}
100101

101102
const history = createHashHistory();
102-
const { direction, visualRefresh, theme, appLayoutWidget, appLayoutToolbar, appLayoutDelayedWidget } = parseQuery(
103-
history.location.search
104-
);
103+
const {
104+
direction,
105+
visualRefresh,
106+
theme,
107+
appLayoutWidget,
108+
appLayoutToolbar,
109+
appLayoutHideToolbarBreadcrumbs,
110+
appLayoutDelayedWidget,
111+
} = parseQuery(history.location.search);
105112
const oneTheme = theme === Theme.OneTheme;
106113
// core-update is an override on top of visual refresh, so it always requires the visual refresh base.
107114
const coreNew = theme === Theme.CoreUpdate;
@@ -117,6 +124,7 @@ if (!window[awsuiCustomFlagsSymbol]) {
117124
}
118125
window[awsuiGlobalFlagsSymbol].appLayoutWidget = appLayoutWidget;
119126
window[awsuiGlobalFlagsSymbol].appLayoutToolbar = appLayoutToolbar;
127+
window[awsuiGlobalFlagsSymbol].appLayoutHideToolbarBreadcrumbs = appLayoutHideToolbarBreadcrumbs;
120128
window[awsuiCustomFlagsSymbol].appLayoutDelayedWidget = appLayoutDelayedWidget;
121129
window[awsuiGlobalFlagsSymbol].oneTheme = oneTheme;
122130

‎src/app-layout/__tests__/__snapshots__/widget-contract-old.test.tsx.snap‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,11 @@ Map {
155155
"toolbar": 0,
156156
},
157157
},
158-
"breadcrumbsExternallyOwned": false,
159158
"featureNotificationsProps": {
160159
"drawer": null,
161160
"renderLatestFeaturePrompt": [Function],
162161
},
162+
"hideBreadcrumbsInToolbar": false,
163163
"reportOwnBreadcrumbsProps": [Function],
164164
"toolbarProps": {
165165
"activeDrawerId": null,
@@ -1017,11 +1017,11 @@ Map {
10171017
"toolbar": 0,
10181018
},
10191019
},
1020-
"breadcrumbsExternallyOwned": false,
10211020
"featureNotificationsProps": {
10221021
"drawer": null,
10231022
"renderLatestFeaturePrompt": [Function],
10241023
},
1024+
"hideBreadcrumbsInToolbar": false,
10251025
"reportOwnBreadcrumbsProps": [Function],
10261026
"toolbarProps": {
10271027
"activeDrawerId": null,
@@ -2081,11 +2081,11 @@ Map {
20812081
"toolbar": 0,
20822082
},
20832083
},
2084-
"breadcrumbsExternallyOwned": false,
20852084
"featureNotificationsProps": {
20862085
"drawer": null,
20872086
"renderLatestFeaturePrompt": [Function],
20882087
},
2088+
"hideBreadcrumbsInToolbar": false,
20892089
"reportOwnBreadcrumbsProps": [Function],
20902090
"toolbarProps": {
20912091
"activeDrawerId": "security",

‎src/app-layout/__tests__/__snapshots__/widget-contract-split-panel-old.test.tsx.snap‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,11 @@ Map {
155155
"toolbar": 0,
156156
},
157157
},
158-
"breadcrumbsExternallyOwned": false,
159158
"featureNotificationsProps": {
160159
"drawer": null,
161160
"renderLatestFeaturePrompt": [Function],
162161
},
162+
"hideBreadcrumbsInToolbar": false,
163163
"reportOwnBreadcrumbsProps": [Function],
164164
"toolbarProps": {
165165
"activeDrawerId": null,
@@ -1018,11 +1018,11 @@ Map {
10181018
"toolbar": 0,
10191019
},
10201020
},
1021-
"breadcrumbsExternallyOwned": false,
10221021
"featureNotificationsProps": {
10231022
"drawer": null,
10241023
"renderLatestFeaturePrompt": [Function],
10251024
},
1025+
"hideBreadcrumbsInToolbar": false,
10261026
"reportOwnBreadcrumbsProps": [Function],
10271027
"toolbarProps": {
10281028
"activeDrawerId": null,

‎src/app-layout/__tests__/runtime-breadcrumbs-widgetized.test.tsx‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import React from 'react';
44
import { act, cleanup, render, waitFor } from '@testing-library/react';
55

6+
import { setGlobalFlag } from '@cloudscape-design/component-toolkit/internal/testing';
7+
68
import AppLayout from '../../../lib/components/app-layout';
79
import BreadcrumbGroup, { BreadcrumbGroupProps } from '../../../lib/components/breadcrumb-group';
810
import { getFunnelNameSelector } from '../../../lib/components/internal/analytics/selectors';
@@ -363,4 +365,33 @@ describeEachAppLayout({ themes: ['refresh-toolbar'], sizes: ['desktop'] }, () =>
363365

364366
second.unregister();
365367
});
368+
369+
describe('with appLayoutHideToolbarBreadcrumbs flag', () => {
370+
const flagName = 'appLayoutHideToolbarBreadcrumbs';
371+
372+
beforeEach(() => setGlobalFlag(flagName, true));
373+
afterEach(() => setGlobalFlag(flagName, undefined));
374+
375+
test('marks breadcrumbs as externally owned on first render without a consumer', () => {
376+
render(<AppLayout breadcrumbs={<BreadcrumbGroup items={defaultItems} />} />);
377+
expectAppLayoutBreadcrumbsToBeExternallyOwned();
378+
expect(getAppLayoutBreadcrumbGroup()).toBeTruthy();
379+
});
380+
381+
test('keeps breadcrumbs externally owned after the consumer unregisters', async () => {
382+
const externalContainer = document.createElement('div');
383+
const { registration } = registerExternalContainer(externalContainer);
384+
render(<AppLayout breadcrumbs={<BreadcrumbGroup items={defaultItems} />} />);
385+
386+
await waitFor(() => expect(externalContainer).toHaveTextContent('Home / Resource'));
387+
act(() => registration.unregister());
388+
expectAppLayoutBreadcrumbsToBeExternallyOwned();
389+
});
390+
});
391+
392+
test('does not mark breadcrumbs as externally owned without the flag or a consumer', () => {
393+
render(<AppLayout breadcrumbs={<BreadcrumbGroup items={defaultItems} />} />);
394+
const breadcrumbsSection = getAppLayoutBreadcrumbsSection()?.getElement();
395+
expect(breadcrumbsSection).not.toHaveAttribute('data-awsui-external-breadcrumbs');
396+
});
366397
});

‎src/app-layout/utils/feature-flags.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ export const useAppLayoutToolbarDesignEnabled = () => {
2323

2424
return isToolbarPublic || isToolbarPrivate;
2525
};
26+
27+
export const isAppLayoutHideToolbarBreadcrumbsEnabled = () => !!getGlobalFlag('appLayoutHideToolbarBreadcrumbs');

‎src/app-layout/visual-refresh-toolbar/interfaces.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export interface AppLayoutInternals {
9191
}
9292

9393
export interface AppLayoutWidgetizedState extends AppLayoutInternals {
94-
breadcrumbsExternallyOwned?: boolean;
94+
hideBreadcrumbsInToolbar?: boolean;
9595
reportOwnBreadcrumbsProps?: BreadcrumbsSlotContextType['reportOwnBreadcrumbsProps'];
9696
isNested: boolean;
9797
verticalOffsets: VerticalLayoutOutput;

‎src/app-layout/visual-refresh-toolbar/skeleton/toolbar-container.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,26 @@ export function ToolbarContainer({ children, hasAiDrawer }: ToolbarContainerProp
2828
interface ToolbarBreadcrumbsSectionProps {
2929
ownBreadcrumbs: React.ReactNode;
3030
discoveredBreadcrumbs?: BreadcrumbGroupProps | null;
31-
breadcrumbsExternallyOwned?: boolean;
31+
hideBreadcrumbsInToolbar?: boolean;
3232
reportOwnBreadcrumbsProps?: BreadcrumbsSlotContextType['reportOwnBreadcrumbsProps'];
3333
includeTestUtils?: boolean;
3434
}
3535

3636
export function ToolbarBreadcrumbsSection({
3737
ownBreadcrumbs,
3838
discoveredBreadcrumbs,
39-
breadcrumbsExternallyOwned,
39+
hideBreadcrumbsInToolbar,
4040
reportOwnBreadcrumbsProps,
4141
includeTestUtils = false,
4242
}: ToolbarBreadcrumbsSectionProps) {
4343
return (
4444
<div
4545
className={clsx(
4646
toolbarStyles['universal-toolbar-breadcrumbs'],
47-
breadcrumbsExternallyOwned && toolbarStyles['external-breadcrumbs'],
47+
hideBreadcrumbsInToolbar && toolbarStyles['external-breadcrumbs'],
4848
includeTestUtils && testutilStyles.breadcrumbs
4949
)}
50-
data-awsui-external-breadcrumbs={breadcrumbsExternallyOwned || undefined}
50+
data-awsui-external-breadcrumbs={hideBreadcrumbsInToolbar || undefined}
5151
>
5252
<BreadcrumbsSlot
5353
ownBreadcrumbs={ownBreadcrumbs}

‎src/app-layout/visual-refresh-toolbar/state/use-app-layout.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import globalVars from '../../../internal/styles/global-vars';
2424
import { getSplitPanelDefaultSize } from '../../../split-panel/utils/size-utils';
2525
import { AppLayoutProps } from '../../interfaces';
2626
import { SplitPanelProviderProps } from '../../split-panel';
27+
import { isAppLayoutHideToolbarBreadcrumbsEnabled } from '../../utils/feature-flags';
2728
import { MIN_DRAWER_SIZE, OnChangeParams, useDrawers } from '../../utils/use-drawers';
2829
import { useAsyncFocusControl, useMultipleFocusControl } from '../../utils/use-focus-control';
2930
import { useGlobalScrollPadding } from '../../utils/use-global-scroll-padding';
@@ -695,7 +696,7 @@ export const useAppLayout = (
695696
splitPanelInternals,
696697
widgetizedState: {
697698
...appLayoutInternals,
698-
breadcrumbsExternallyOwned: hasBreadcrumbsConsumer,
699+
hideBreadcrumbsInToolbar: hasBreadcrumbsConsumer || isAppLayoutHideToolbarBreadcrumbsEnabled(),
699700
reportOwnBreadcrumbsProps,
700701
aiDrawerExpandedMode: expandedDrawerId === activeAiDrawer?.id,
701702
isNested,

‎src/app-layout/visual-refresh-toolbar/toolbar/index.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,15 @@ export interface ToolbarProps {
6868

6969
export interface AppLayoutToolbarImplementationProps {
7070
appLayoutInternals: AppLayoutInternals;
71-
breadcrumbsExternallyOwned?: AppLayoutWidgetizedState['breadcrumbsExternallyOwned'];
71+
hideBreadcrumbsInToolbar?: AppLayoutWidgetizedState['hideBreadcrumbsInToolbar'];
7272
reportOwnBreadcrumbsProps?: AppLayoutWidgetizedState['reportOwnBreadcrumbsProps'];
7373
toolbarProps: ToolbarProps;
7474
featureNotificationsProps?: FeatureNotificationsProps;
7575
}
7676

7777
export function AppLayoutToolbarImplementation({
7878
appLayoutInternals,
79-
breadcrumbsExternallyOwned,
79+
hideBreadcrumbsInToolbar,
8080
reportOwnBreadcrumbsProps,
8181
// the value could be undefined if this component is loaded as a widget by a different app layout version
8282
// not testable in a single-version setup
@@ -235,7 +235,7 @@ export function AppLayoutToolbarImplementation({
235235
<ToolbarBreadcrumbsSection
236236
ownBreadcrumbs={appLayoutInternals.breadcrumbs}
237237
discoveredBreadcrumbs={appLayoutInternals.discoveredBreadcrumbs}
238-
breadcrumbsExternallyOwned={breadcrumbsExternallyOwned}
238+
hideBreadcrumbsInToolbar={hideBreadcrumbsInToolbar}
239239
reportOwnBreadcrumbsProps={reportOwnBreadcrumbsProps}
240240
includeTestUtils={true}
241241
/>

‎src/app-layout/visual-refresh-toolbar/widget-areas/before-main-slot.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export const BeforeMainSlotImplementationInternal = ({
5454
activeAiDrawer,
5555
bottomDrawerReportedSize,
5656
featureNotificationsProps,
57-
breadcrumbsExternallyOwned,
57+
hideBreadcrumbsInToolbar,
5858
reportOwnBreadcrumbsProps,
5959
} = appLayoutState.widgetizedState;
6060
const drawerExpandedMode = !!expandedDrawerId;
@@ -67,7 +67,7 @@ export const BeforeMainSlotImplementationInternal = ({
6767
{!!toolbarProps && !embeddedViewMode && !aiDrawerExpandedMode && (
6868
<AppLayoutToolbar
6969
appLayoutInternals={appLayoutState.appLayoutInternals}
70-
breadcrumbsExternallyOwned={breadcrumbsExternallyOwned}
70+
hideBreadcrumbsInToolbar={hideBreadcrumbsInToolbar}
7171
reportOwnBreadcrumbsProps={reportOwnBreadcrumbsProps}
7272
toolbarProps={toolbarProps}
7373
featureNotificationsProps={featureNotificationsProps}

0 commit comments

Comments
 (0)