Skip to content

Commit

Permalink
fix: Support previous breadcrumbs versions in deduplication
Browse files Browse the repository at this point in the history
  • Loading branch information
just-boris committed Oct 24, 2024
1 parent 3279cb8 commit b12c7f3
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 12 deletions.
31 changes: 31 additions & 0 deletions src/app-layout/__tests__/global-breadcrumbs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,37 @@ describeEachAppLayout({ themes: ['refresh-toolbar'], sizes: ['desktop'] }, () =>
});
});

test('renders breadcrumbs locally again after app layout de-registers', async () => {
function DestructibleLayout() {
const [mounted, setMounted] = useState(true);
return mounted ? (
<AppLayout
content={
<button data-testid="unmount" onClick={() => setMounted(false)}>
Unmount
</button>
}
/>
) : null;
}

await renderAsync(
<>
<div data-testid="local-breadcrumbs">
<BreadcrumbGroup items={defaultBreadcrumbs} />
</div>

<DestructibleLayout />
</>
);
expect(wrapper.find('[data-testid="local-breadcrumbs"]')!.getElement()).toBeEmptyDOMElement();

wrapper.find('[data-testid="unmount"]')!.click();
await waitFor(() => {
expect(wrapper.find('[data-testid="local-breadcrumbs"]')!.getElement()).not.toBeEmptyDOMElement();
});
});

test('allows opt-out from this behavior', async () => {
render(
<AppLayout
Expand Down
8 changes: 5 additions & 3 deletions src/app-layout/visual-refresh-toolbar/toolbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,16 @@ export function AppLayoutToolbarImplementation({
{(breadcrumbs || discoveredBreadcrumbs) && (
<div className={clsx(styles['universal-toolbar-breadcrumbs'], testutilStyles.breadcrumbs)}>
<BreadcrumbsSlotContext.Provider value={{ isInToolbar: true }}>
{breadcrumbs ||
(discoveredBreadcrumbs && (
<div className={styles['breadcrumbs-own']}>{breadcrumbs}</div>
{discoveredBreadcrumbs && (
<div className={styles['breadcrumbs-discovered']}>
<BreadcrumbGroupImplementation
{...discoveredBreadcrumbs}
data-awsui-discovered-breadcrumbs={true}
__injectAnalyticsComponentMetadata={true}
/>
))}
</div>
)}
</BreadcrumbsSlotContext.Provider>
</div>
)}
Expand Down
5 changes: 5 additions & 0 deletions src/app-layout/visual-refresh-toolbar/toolbar/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
}
}

// backward compatibility before this commit: 7a4b7b3e3b1d50830383805a8f4ab6cd93c9701f
.breadcrumbs-own:not(:empty) + .breadcrumbs-discovered {
display: none;
}

.block-body-scroll {
overflow: hidden;
}
15 changes: 7 additions & 8 deletions src/internal/plugins/controllers/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import debounce from '../../debounce';

type ChangeCallback<T> = (props: T | null) => void;
type RegistrationCallback = (isRegistered: boolean) => void;

export interface BreadcrumbsGlobalRegistration<T> {
update(props: T): void;
Expand All @@ -11,18 +12,18 @@ export interface BreadcrumbsGlobalRegistration<T> {

export interface BreadcrumbsApiInternal<T> {
registerAppLayout: (changeCallback: ChangeCallback<T>) => (() => void) | void;
registerBreadcrumbs: (props: T, onRegistered: () => void) => BreadcrumbsGlobalRegistration<T>;
registerBreadcrumbs: (props: T, onRegistered: RegistrationCallback) => BreadcrumbsGlobalRegistration<T>;
getStateForTesting: () => {
appLayoutUpdateCallback: ChangeCallback<T> | null;
breadcrumbInstances: Array<{ props: T }>;
breadcrumbRegistrations: Array<() => void>;
breadcrumbRegistrations: Array<RegistrationCallback>;
};
}

export class BreadcrumbsController<T> {
#appLayoutUpdateCallback: ChangeCallback<T> | null = null;
#breadcrumbInstances: Array<{ props: T }> = [];
#breadcrumbRegistrations: Array<() => void> = [];
#breadcrumbRegistrations: Array<RegistrationCallback> = [];

#notifyAppLayout = debounce(() => {
if (!this.#appLayoutUpdateCallback) {
Expand All @@ -33,10 +34,7 @@ export class BreadcrumbsController<T> {
}, 0);

#notifyBreadcrumbs = debounce(() => {
if (!this.#appLayoutUpdateCallback) {
return;
}
this.#breadcrumbRegistrations.forEach(listener => listener());
this.#breadcrumbRegistrations.forEach(listener => listener(!!this.#appLayoutUpdateCallback));
}, 0);

registerAppLayout = (changeCallback: ChangeCallback<T>) => {
Expand All @@ -47,10 +45,11 @@ export class BreadcrumbsController<T> {
this.#notifyBreadcrumbs();
return () => {
this.#appLayoutUpdateCallback = null;
this.#notifyBreadcrumbs();
};
};

registerBreadcrumbs = (props: T, onRegistered: () => void): BreadcrumbsGlobalRegistration<T> => {
registerBreadcrumbs = (props: T, onRegistered: RegistrationCallback): BreadcrumbsGlobalRegistration<T> => {
const instance = { props: props };
this.#breadcrumbInstances.push(instance);
this.#breadcrumbRegistrations.push(onRegistered);
Expand Down
4 changes: 3 additions & 1 deletion src/internal/plugins/helpers/use-global-breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ function useSetGlobalBreadcrumbsImplementation({
if (isInToolbar || __disableGlobalization) {
return;
}
const registration = awsuiPluginsInternal.breadcrumbs.registerBreadcrumbs(props, () => setRegistered(true));
const registration = awsuiPluginsInternal.breadcrumbs.registerBreadcrumbs(props, isRegistered =>
setRegistered(isRegistered ?? true)
);
registrationRef.current = registration;

return () => {
Expand Down

0 comments on commit b12c7f3

Please sign in to comment.