Skip to content

Commit 97fff0d

Browse files
chore: Move more app layout code into the widgetized part (#3721)
Co-authored-by: Georgii Lobko <[email protected]>
1 parent 1b71d6c commit 97fff0d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+6478
-4290
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
{
168168
"path": "lib/components/internal/widget-exports.js",
169169
"brotli": false,
170-
"limit": "810 kB",
170+
"limit": "830 kB",
171171
"ignore": "react-dom"
172172
}
173173
],

pages/app-layout/runtime-drawers.page.tsx

Lines changed: 72 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -70,83 +70,85 @@ export default function WithDrawers() {
7070
breadcrumbs={<Breadcrumbs />}
7171
ref={appLayoutRef}
7272
content={
73-
<ContentLayout
74-
disableOverlap={true}
75-
header={
76-
<SpaceBetween size="m">
77-
<Header
78-
variant="h1"
79-
description="Sometimes you need custom drawers to get the job done."
80-
info={
81-
<Link
82-
data-testid="info-link-header"
83-
variant="info"
84-
onFollow={() => {
85-
setHelpPathSlug('header');
86-
setIsToolsOpen(true);
87-
appLayoutRef.current?.focusToolsClose();
88-
}}
89-
>
90-
Info
91-
</Link>
92-
}
93-
>
94-
Testing Custom Drawers!
95-
</Header>
73+
<div data-testid="app-layout-content-area">
74+
<ContentLayout
75+
disableOverlap={true}
76+
header={
77+
<SpaceBetween size="m">
78+
<Header
79+
variant="h1"
80+
description="Sometimes you need custom drawers to get the job done."
81+
info={
82+
<Link
83+
data-testid="info-link-header"
84+
variant="info"
85+
onFollow={() => {
86+
setHelpPathSlug('header');
87+
setIsToolsOpen(true);
88+
appLayoutRef.current?.focusToolsClose();
89+
}}
90+
>
91+
Info
92+
</Link>
93+
}
94+
>
95+
Testing Custom Drawers!
96+
</Header>
9697

97-
<SpaceBetween size="xs">
98-
<Toggle checked={hasTools} onChange={({ detail }) => setUrlParams({ hasTools: detail.checked })}>
99-
Use Tools
100-
</Toggle>
98+
<SpaceBetween size="xs">
99+
<Toggle checked={hasTools} onChange={({ detail }) => setUrlParams({ hasTools: detail.checked })}>
100+
Use Tools
101+
</Toggle>
101102

102-
<Toggle checked={hasDrawers} onChange={({ detail }) => setUrlParams({ hasDrawers: detail.checked })}>
103-
Use Drawers
104-
</Toggle>
103+
<Toggle checked={hasDrawers} onChange={({ detail }) => setUrlParams({ hasDrawers: detail.checked })}>
104+
Use Drawers
105+
</Toggle>
105106

106-
<Button
107-
onClick={() => awsuiPlugins.appLayout.openDrawer('circle4-global')}
108-
data-testid="open-drawer-button"
109-
>
110-
Open a drawer without a trigger
111-
</Button>
112-
<Button onClick={() => awsuiPlugins.appLayout.closeDrawer('circle4-global')}>
113-
Close a drawer without a trigger
114-
</Button>
107+
<Button
108+
onClick={() => awsuiPlugins.appLayout.openDrawer('circle4-global')}
109+
data-testid="open-drawer-button"
110+
>
111+
Open a drawer without a trigger
112+
</Button>
113+
<Button onClick={() => awsuiPlugins.appLayout.closeDrawer('circle4-global')}>
114+
Close a drawer without a trigger
115+
</Button>
115116

116-
<Button
117-
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle-global', 400)}
118-
data-testid="button-circle-global-resize"
119-
>
120-
Resize circle-global drawer to 400px
121-
</Button>
122-
<Button
123-
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle3-global', 500)}
124-
data-testid="button-circle3-global-resize"
125-
>
126-
Resize circle3-global drawer to 500px
127-
</Button>
117+
<Button
118+
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle-global', 400)}
119+
data-testid="button-circle-global-resize"
120+
>
121+
Resize circle-global drawer to 400px
122+
</Button>
123+
<Button
124+
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle3-global', 500)}
125+
data-testid="button-circle3-global-resize"
126+
>
127+
Resize circle3-global drawer to 500px
128+
</Button>
129+
</SpaceBetween>
128130
</SpaceBetween>
129-
</SpaceBetween>
130-
}
131-
>
132-
<Header
133-
info={
134-
<Link
135-
data-testid="info-link-content"
136-
variant="info"
137-
onFollow={() => {
138-
setHelpPathSlug('content');
139-
setIsToolsOpen(true);
140-
}}
141-
>
142-
Info
143-
</Link>
144131
}
145132
>
146-
Content
147-
</Header>
148-
<Containers />
149-
</ContentLayout>
133+
<Header
134+
info={
135+
<Link
136+
data-testid="info-link-content"
137+
variant="info"
138+
onFollow={() => {
139+
setHelpPathSlug('content');
140+
setIsToolsOpen(true);
141+
}}
142+
>
143+
Info
144+
</Link>
145+
}
146+
>
147+
Content
148+
</Header>
149+
<Containers />
150+
</ContentLayout>
151+
</div>
150152
}
151153
splitPanel={
152154
<SplitPanel header="Split panel header" i18nStrings={splitPaneli18nStrings}>

pages/app/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ interface GlobalFlags {
2222
appLayoutWidget?: boolean;
2323
appLayoutToolbar?: boolean;
2424
}
25+
// used for local dev / testing
26+
interface CustomFlags {
27+
appLayoutDelayedWidget?: boolean;
28+
}
2529
const awsuiVisualRefreshFlag = Symbol.for('awsui-visual-refresh-flag');
2630
const awsuiGlobalFlagsSymbol = Symbol.for('awsui-global-flags');
31+
const awsuiCustomFlagsSymbol = Symbol.for('awsui-custom-flags');
2732

2833
interface ExtendedWindow extends Window {
2934
[awsuiVisualRefreshFlag]?: () => boolean;
3035
[awsuiGlobalFlagsSymbol]?: GlobalFlags;
36+
[awsuiCustomFlagsSymbol]?: CustomFlags;
3137
}
3238
declare const window: ExtendedWindow;
3339

@@ -86,15 +92,21 @@ function App() {
8692
}
8793

8894
const history = createHashHistory();
89-
const { direction, visualRefresh, appLayoutWidget, appLayoutToolbar } = parseQuery(history.location.search);
95+
const { direction, visualRefresh, appLayoutWidget, appLayoutToolbar, appLayoutDelayedWidget } = parseQuery(
96+
history.location.search
97+
);
9098

9199
// The VR class needs to be set before any React rendering occurs.
92100
window[awsuiVisualRefreshFlag] = () => visualRefresh;
93101
if (!window[awsuiGlobalFlagsSymbol]) {
94102
window[awsuiGlobalFlagsSymbol] = {};
95103
}
104+
if (!window[awsuiCustomFlagsSymbol]) {
105+
window[awsuiCustomFlagsSymbol] = {};
106+
}
96107
window[awsuiGlobalFlagsSymbol].appLayoutWidget = appLayoutWidget;
97108
window[awsuiGlobalFlagsSymbol].appLayoutToolbar = appLayoutToolbar;
109+
window[awsuiCustomFlagsSymbol].appLayoutDelayedWidget = appLayoutDelayedWidget;
98110

99111
// Apply the direction value to the HTML element dir attribute
100112
document.documentElement.setAttribute('dir', direction);

src/app-layout-toolbar/__tests__/app-layout-toolbar.test.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
/* eslint simple-import-sort/imports: 0 */
43
import React, { useRef, useState } from 'react';
5-
import { render } from '@testing-library/react';
4+
import { render, waitFor } from '@testing-library/react';
5+
66
import { clearVisualRefreshState } from '@cloudscape-design/component-toolkit/internal/testing';
7+
78
import AppLayoutToolbar, { AppLayoutToolbarProps } from '../../../lib/components/app-layout-toolbar';
8-
import createWrapper from '../../../lib/components/test-utils/dom';
99
import BreadcrumbGroup from '../../../lib/components/breadcrumb-group';
10+
import createWrapper from '../../../lib/components/test-utils/dom';
1011

1112
function renderComponent(jsx: React.ReactElement) {
1213
const { container, rerender } = render(jsx);
@@ -35,7 +36,7 @@ describe('AppLayoutToolbar component', () => {
3536
);
3637
});
3738

38-
test('triggerless navigation', () => {
39+
test('triggerless navigation', async () => {
3940
const AppLayoutToolbarWrapper = () => {
4041
const [isNavigationOpen, setIsNavigationOpen] = useState(false);
4142
const appLayoutToolbarRef = useRef<AppLayoutToolbarProps.Ref>(null);
@@ -72,7 +73,9 @@ describe('AppLayoutToolbar component', () => {
7273
wrapper.find(`[data-testid="toggle-navigation"]`)!.click();
7374

7475
expect(wrapper.findOpenNavigationPanel()).toBeTruthy();
75-
expect(wrapper.findNavigationClose()!.getElement()).toHaveFocus();
76+
await waitFor(() => {
77+
expect(wrapper.findNavigationClose()!.getElement()).toHaveFocus();
78+
});
7679
});
7780

7881
test('triggerless drawers', () => {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { BasePageObject } from '@cloudscape-design/browser-test-tools/page-objects';
4+
import useBrowser from '@cloudscape-design/browser-test-tools/use-browser';
5+
6+
import { viewports } from './constants';
7+
import { getUrlParams } from './utils';
8+
9+
describe.each(['desktop', 'mobile'] as const)('%s', size => {
10+
test(
11+
'main content area layout should not shift after loading the widget part of the page',
12+
useBrowser(size === 'desktop' ? viewports.desktop : viewports.mobile, async browser => {
13+
const page = new BasePageObject(browser);
14+
await browser.url(
15+
`#/light/app-layout/runtime-drawers?${getUrlParams('refresh-toolbar', {
16+
appLayoutWidget: 'true',
17+
appLayoutDelayedWidget: 'true',
18+
})}`
19+
);
20+
// make sure the widget part has not loaded yet
21+
const { top: contentTopBefore, left: contentLeftBefore } = await page.getBoundingBox(
22+
`[data-awsui-app-layout-widget-loaded="false"] [data-testid="app-layout-content-area"]`
23+
);
24+
25+
const { top: contentTopAfter, left: contentLeftAfter } = await page.getBoundingBox(
26+
`[data-awsui-app-layout-widget-loaded="true"] [data-testid="app-layout-content-area"]`
27+
);
28+
29+
expect(contentTopBefore).toBe(contentTopAfter);
30+
expect(contentLeftBefore).toBe(contentLeftAfter);
31+
})
32+
);
33+
});

0 commit comments

Comments
 (0)