@aws/nx-plugin 0.62.0 → 0.62.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE-THIRD-PARTY +30 -3
  2. package/package.json +3 -4
  3. package/src/infra/app/__snapshots__/generator.spec.ts.snap +2 -2
  4. package/src/mcp-server/schema.d.ts +7 -2
  5. package/src/mcp-server/schema.js +2 -2
  6. package/src/mcp-server/schema.js.map +1 -1
  7. package/src/mcp-server/tools/create-workspace-command.js +8 -2
  8. package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
  9. package/src/mcp-server/tools/general-guidance.js +4 -1
  10. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  11. package/src/mcp-server/tools/generator-guide.js +7 -4
  12. package/src/mcp-server/tools/generator-guide.js.map +1 -1
  13. package/src/mcp-server/tools/list-generators.js +4 -1
  14. package/src/mcp-server/tools/list-generators.js.map +1 -1
  15. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +1 -1
  16. package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +1 -1
  17. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +2 -2
  18. package/src/ts/mcp-server/files/resources/sample-guidance.ts.template +1 -1
  19. package/src/ts/mcp-server/files/tools/add.ts.template +6 -4
  20. package/src/ts/mcp-server/generator.js +1 -5
  21. package/src/ts/mcp-server/generator.js.map +1 -1
  22. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +35 -20
  23. package/src/ts/nx-plugin/files/mcp-server/schema.ts.template +1 -1
  24. package/src/ts/nx-plugin/files/mcp-server/tools/create-workspace-command.ts.template +7 -5
  25. package/src/ts/nx-plugin/files/mcp-server/tools/general-guidance.ts.template +5 -3
  26. package/src/ts/nx-plugin/files/mcp-server/tools/generator-guide.ts.template +9 -7
  27. package/src/ts/nx-plugin/files/mcp-server/tools/list-generators.ts.template +6 -4
  28. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +883 -85
  29. package/src/ts/react-website/app/files/app/{src → cloudscape/src}/app.tsx.template +1 -1
  30. package/src/ts/react-website/app/files/app/cloudscape/src/components/alert.tsx.template +3 -0
  31. package/src/ts/react-website/app/files/app/cloudscape/src/components/spinner.tsx.template +3 -0
  32. package/src/ts/react-website/app/files/app/{src → common/src}/config.ts.template +1 -1
  33. package/src/ts/react-website/app/files/app/none/src/app.tsx.template +8 -0
  34. package/src/ts/react-website/app/files/app/none/src/components/AppLayout/index.tsx.template +124 -0
  35. package/src/ts/react-website/app/files/app/none/src/components/alert.tsx.template +14 -0
  36. package/src/ts/react-website/app/files/app/none/src/components/spinner.tsx.template +7 -0
  37. package/src/ts/react-website/app/files/app/none/src/main.tsx.template +31 -0
  38. package/src/ts/react-website/app/files/app/none/src/styles.css.template +201 -0
  39. package/src/ts/react-website/app/files/tanstack-router/common/src/routeTree.gen.ts.template +59 -0
  40. package/src/ts/react-website/app/files/tanstack-router/none/src/routes/index.tsx.template +14 -0
  41. package/src/ts/react-website/app/generator.d.ts +2 -0
  42. package/src/ts/react-website/app/generator.js +30 -16
  43. package/src/ts/react-website/app/generator.js.map +1 -1
  44. package/src/ts/react-website/app/schema.d.ts +2 -1
  45. package/src/ts/react-website/app/schema.json +22 -0
  46. package/src/ts/react-website/cognito-auth/__snapshots__/generator.spec.ts.snap +348 -185
  47. package/src/ts/react-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +15 -15
  48. package/src/ts/react-website/cognito-auth/generator.js +14 -40
  49. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  50. package/src/ts/react-website/cognito-auth/utils.d.ts +7 -0
  51. package/src/ts/react-website/cognito-auth/utils.js +92 -0
  52. package/src/ts/react-website/cognito-auth/utils.js.map +1 -0
  53. package/src/ts/react-website/runtime-config/__snapshots__/generator.spec.ts.snap +1 -1
  54. package/src/ts/react-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +1 -1
  55. package/src/utils/versions.d.ts +9 -10
  56. package/src/utils/versions.js +9 -12
  57. package/src/utils/versions.js.map +1 -1
  58. package/src/ts/react-website/app/files/tanstack-router/src/routeTree.gen.ts.template +0 -111
  59. /package/src/ts/react-website/app/files/app/{src → cloudscape/src}/components/AppLayout/index.tsx.template +0 -0
  60. /package/src/ts/react-website/app/files/app/{src → cloudscape/src}/hooks/useAppLayout.tsx.template +0 -0
  61. /package/src/ts/react-website/app/files/app/{src → cloudscape/src}/main.tsx.template +0 -0
  62. /package/src/ts/react-website/app/files/app/{src → cloudscape/src}/styles.css.template +0 -0
  63. /package/src/ts/react-website/app/files/app/{README.md.template → common/README.md.template} +0 -0
  64. /package/src/ts/react-website/app/files/tanstack-router/{src → cloudscape/src}/routes/index.tsx.template +0 -0
  65. /package/src/ts/react-website/app/files/tanstack-router/{src → common/src}/routes/__root.tsx.template +0 -0
@@ -2,8 +2,8 @@
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- import { SupportedStyles } from '@nx/react';
6
5
  import { IacProviderOption } from '../../../utils/iac';
6
+ import { UxProviderOption } from '../../../utils/ux';
7
7
 
8
8
  export interface TsReactWebsiteGeneratorSchema {
9
9
  name: string;
@@ -11,5 +11,6 @@ export interface TsReactWebsiteGeneratorSchema {
11
11
  skipInstall?: boolean;
12
12
  enableTanstackRouter?: boolean;
13
13
  enableTailwind?: boolean;
14
+ uxProvider?: UxProviderOption;
14
15
  iacProvider: IacProviderOption;
15
16
  }
@@ -30,6 +30,28 @@
30
30
  "default": "packages",
31
31
  "x-prompt": "What directory would you like to store your application in?"
32
32
  },
33
+ "uxProvider": {
34
+ "type": "string",
35
+ "description": "The preferred UX provider.",
36
+ "enum": ["None", "Cloudscape"],
37
+ "x-priority": "important",
38
+ "default": "Cloudscape",
39
+ "x-prompt": {
40
+ "message": "Which UX provider should we scaffold for this app?",
41
+ "type": "list",
42
+ "items": [
43
+ {
44
+ "value": "None",
45
+ "label": "None (plain React/Vite without a UI kit)"
46
+ },
47
+ {
48
+ "value": "Cloudscape",
49
+ "label": "Cloudscape (AWS-first components with ready-made layouts)"
50
+ }
51
+ ],
52
+ "default": "None"
53
+ }
54
+ },
33
55
  "enableTailwind": {
34
56
  "description": "Enable TailwindCSS for utility-first styling.",
35
57
  "type": "boolean",
@@ -1,9 +1,344 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
+ exports[`cognito-auth generator (uxProvider=Cloudscape) > should update AppLayout > app-layout-with-auth 1`] = `
4
+ "import { useAuth } from 'react-oidc-context';
5
+ import * as React from 'react';
6
+ import { createContext, useCallback, useEffect, useState } from 'react';
7
+ import { NavItems } from './navitems';
8
+ import Config from '../../config';
9
+
10
+ import {
11
+ BreadcrumbGroup,
12
+ BreadcrumbGroupProps,
13
+ SideNavigation,
14
+ TopNavigation,
15
+ } from '@cloudscape-design/components';
16
+
17
+ import CloudscapeAppLayout, {
18
+ AppLayoutProps,
19
+ } from '@cloudscape-design/components/app-layout';
20
+
21
+ import { matchByPath, useLocation, useNavigate } from '@tanstack/react-router';
22
+ import { Outlet } from '@tanstack/react-router';
23
+
24
+ const getBreadcrumbs = (
25
+ pathName: string,
26
+ search: string,
27
+ defaultBreadcrumb: string,
28
+ availableRoutes?: string[],
29
+ ) => {
30
+ const segments = [
31
+ defaultBreadcrumb,
32
+ ...pathName.split('/').filter((segment) => segment !== ''),
33
+ ];
34
+
35
+ return segments.map((segment, i) => {
36
+ const href =
37
+ i === 0
38
+ ? '/'
39
+ : \`/\${segments
40
+ .slice(1, i + 1)
41
+ .join('/')
42
+ .replace('//', '/')}\`;
43
+
44
+ const matched =
45
+ !availableRoutes || availableRoutes.find((r) => matchByPath(r, href, {}));
46
+
47
+ return {
48
+ href: matched ? \`\${href}\${search}\` : '#',
49
+ text: segment,
50
+ };
51
+ });
52
+ };
53
+
54
+ export interface AppLayoutContext {
55
+ appLayoutProps: AppLayoutProps;
56
+ setAppLayoutProps: (props: AppLayoutProps) => void;
57
+ displayHelpPanel: (helpContent: React.ReactNode) => void;
58
+ }
59
+
60
+ /**
61
+ * Context for updating/retrieving the AppLayout.
62
+ */
63
+ export const AppLayoutContext = createContext({
64
+ appLayoutProps: {},
65
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
66
+ setAppLayoutProps: (_: AppLayoutProps) => {},
67
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
68
+ displayHelpPanel: (_: React.ReactNode) => {},
69
+ });
70
+
71
+ /**
72
+ * Defines the App layout and contains logic for routing.
73
+ */
74
+ const AppLayout: React.FC = () => {
75
+ const { user, removeUser, signoutRedirect, clearStaleState } = useAuth();
76
+ const navigate = useNavigate();
77
+ const appLayout = React.useRef<AppLayoutProps.Ref>(null);
78
+ const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
79
+ BreadcrumbGroupProps.Item[]
80
+ >([{ text: '/', href: '/' }]);
81
+ const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
82
+ const { pathname, search } = useLocation();
83
+ const setAppLayoutPropsSafe = useCallback(
84
+ (props: AppLayoutProps) => {
85
+ JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
86
+ setAppLayoutProps(props);
87
+ },
88
+ [appLayoutProps],
89
+ );
90
+ useEffect(() => {
91
+ const breadcrumbs = getBreadcrumbs(
92
+ pathname,
93
+ Object.entries(search).reduce((p, [k, v]) => p + \`\${k}=\${v}\`, ''),
94
+ '/',
95
+ );
96
+ setActiveBreadcrumbs(breadcrumbs);
97
+ }, [pathname, search]);
98
+ const onNavigate = useCallback(
99
+ (
100
+ e: CustomEvent<{
101
+ href: string;
102
+ external?: boolean;
103
+ }>,
104
+ ) => {
105
+ if (!e.detail.external) {
106
+ e.preventDefault();
107
+ setAppLayoutPropsSafe({
108
+ contentType: undefined,
109
+ });
110
+ navigate({ to: e.detail.href });
111
+ }
112
+ },
113
+ [navigate, setAppLayoutPropsSafe],
114
+ );
115
+ return (
116
+ <AppLayoutContext.Provider
117
+ value={{
118
+ appLayoutProps,
119
+ setAppLayoutProps: setAppLayoutPropsSafe,
120
+ displayHelpPanel: (helpContent: React.ReactNode) => {
121
+ setAppLayoutPropsSafe({ tools: helpContent, toolsHide: false });
122
+ appLayout.current?.openTools();
123
+ },
124
+ }}
125
+ >
126
+ <TopNavigation
127
+ identity={{
128
+ href: '/',
129
+ title: Config.applicationName,
130
+ logo: {
131
+ src: Config.logo,
132
+ },
133
+ }}
134
+ utilities={[
135
+ {
136
+ type: 'menu-dropdown',
137
+ text: \`\${user?.profile?.['cognito:username']}\`,
138
+ iconName: 'user-profile-active',
139
+ onItemClick: (e) => {
140
+ if (e.detail.id === 'signout') {
141
+ removeUser();
142
+ signoutRedirect({
143
+ post_logout_redirect_uri: window.location.origin,
144
+ extraQueryParams: {
145
+ redirect_uri: window.location.origin,
146
+ response_type: 'code',
147
+ },
148
+ });
149
+ clearStaleState();
150
+ }
151
+ },
152
+ items: [{ id: 'signout', text: 'Sign out' }],
153
+ },
154
+ ]}
155
+ />
156
+ <CloudscapeAppLayout
157
+ ref={appLayout}
158
+ breadcrumbs={
159
+ <BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
160
+ }
161
+ toolsHide
162
+ navigation={
163
+ <SideNavigation
164
+ header={{ text: Config.applicationName, href: '/' }}
165
+ activeHref={pathname}
166
+ onFollow={onNavigate}
167
+ items={NavItems}
168
+ />
169
+ }
170
+ content={<Outlet />}
171
+ {...appLayoutProps}
172
+ />
173
+ </AppLayoutContext.Provider>
174
+ );
175
+ };
176
+
177
+ export default AppLayout;
178
+ "
179
+ `;
180
+
181
+ exports[`cognito-auth generator (uxProvider=None) > should update AppLayout > app-layout-with-auth 1`] = `
182
+ "import { useAuth } from 'react-oidc-context';
183
+ import * as React from 'react';
184
+
185
+ import { useEffect, useMemo, useState } from 'react';
186
+
187
+ import Config from '../../config';
188
+ import { Link, useLocation, useMatchRoute } from '@tanstack/react-router';
189
+
190
+ const getBreadcrumbs = (
191
+ matchRoute: ReturnType<typeof useMatchRoute>,
192
+ pathName: string,
193
+ search: string,
194
+ defaultBreadcrumb: string,
195
+ availableRoutes?: string[],
196
+ ) => {
197
+ const segments = [
198
+ defaultBreadcrumb,
199
+ ...pathName.split('/').filter((segment) => segment !== ''),
200
+ ];
201
+
202
+ return segments.map((segment, i) => {
203
+ const href =
204
+ i === 0
205
+ ? '/'
206
+ : \`/\${segments
207
+ .slice(1, i + 1)
208
+ .join('/')
209
+ .replace('//', '/')}\`;
210
+
211
+ const matched =
212
+ !availableRoutes || availableRoutes.find((r) => matchRoute({ to: href }));
213
+
214
+ return {
215
+ href: matched ? \`\${href}\${search}\` : '#',
216
+ text: segment,
217
+ };
218
+ });
219
+ };
220
+
221
+ /**
222
+ * Defines the App layout and contains logic for routing.
223
+ */
224
+ const AppLayout: React.FC<React.PropsWithChildren> = ({ children }) => {
225
+ const { user, removeUser, signoutRedirect, clearStaleState } = useAuth();
226
+ const { user, removeUser, signoutRedirect, clearStaleState } = useAuth();
227
+ const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
228
+ {
229
+ href: string;
230
+ text: string;
231
+ }[]
232
+ >([{ text: '/', href: '/' }]);
233
+ const matchRoute = useMatchRoute();
234
+ const { pathname, search } = useLocation();
235
+ const navItems = useMemo(() => [{ to: '/', label: 'Home' }], []);
236
+ useEffect(() => {
237
+ const breadcrumbs = getBreadcrumbs(
238
+ matchRoute,
239
+ pathname,
240
+ Object.entries(search).reduce((p, [k, v]) => p + \`\${k}=\${v}\`, ''),
241
+ 'Home',
242
+ );
243
+ setActiveBreadcrumbs(breadcrumbs);
244
+ }, [matchRoute, pathname, search]);
245
+ return (
246
+ <div className="app-shell">
247
+ <header className="app-header">
248
+ <div className="app-header-inner">
249
+ <div className="brand">
250
+ <a href="/">
251
+ <img
252
+ src={Config.logo}
253
+ alt={\`\${Config.applicationName} logo\`}
254
+ className="brand-logo"
255
+ />
256
+ <span className="brand-name">{Config.applicationName}</span>
257
+ </a>
258
+ </div>
259
+
260
+ <nav className="app-nav">
261
+ {navItems.map((item) => (
262
+ <Link
263
+ key={item.to}
264
+ to={item.to}
265
+ className={pathname === item.to ? 'active' : undefined}
266
+ >
267
+ {item.label}
268
+ </Link>
269
+ ))}
270
+ </nav>
271
+ <div className="user-greeting">
272
+ <span>Hi, {\`\${user?.profile?.['cognito:username']}\`}</span>
273
+ <button
274
+ type="button"
275
+ className="signout-link"
276
+ onClick={() => {
277
+ removeUser();
278
+ signoutRedirect({
279
+ post_logout_redirect_uri: window.location.origin,
280
+ extraQueryParams: {
281
+ redirect_uri: window.location.origin,
282
+ response_type: 'code',
283
+ },
284
+ });
285
+ clearStaleState();
286
+ }}
287
+ >
288
+ Sign out
289
+ </button>
290
+ </div>
291
+ <div className="user-greeting">
292
+ <span>Hi, {\`\${user?.profile?.['cognito:username']}\`}</span>
293
+ <button
294
+ type="button"
295
+ className="signout-link"
296
+ onClick={() => {
297
+ removeUser();
298
+ signoutRedirect({
299
+ post_logout_redirect_uri: window.location.origin,
300
+ extraQueryParams: {
301
+ redirect_uri: window.location.origin,
302
+ response_type: 'code',
303
+ },
304
+ });
305
+ clearStaleState();
306
+ }}
307
+ >
308
+ Sign out
309
+ </button>
310
+ </div>
311
+ </div>
312
+ </header>
313
+ <main className="app-main">
314
+ <nav className="breadcrumbs" aria-label="Breadcrumb">
315
+ {activeBreadcrumbs.map((crumb, index) => (
316
+ <span className="breadcrumb-segment" key={crumb.href || index}>
317
+ {index > 0 && <span className="breadcrumb-separator">/</span>}
318
+ {index === activeBreadcrumbs.length - 1 ? (
319
+ <span className="breadcrumb-current">{crumb.text}</span>
320
+ ) : (
321
+ <Link to={crumb.href}>{crumb.text}</Link>
322
+ )}
323
+ </span>
324
+ ))}
325
+ </nav>
326
+
327
+ <section className="card">{children}</section>
328
+ </main>
329
+ </div>
330
+ );
331
+ };
332
+
333
+ export default AppLayout;
334
+ "
335
+ `;
336
+
3
337
  exports[`cognito-auth generator > should generate files > cognito-auth-component 1`] = `
4
338
  "import React, { PropsWithChildren, useEffect } from 'react';
5
339
  import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
6
- import { Alert, Spinner } from '@cloudscape-design/components';
340
+ import { Alert } from '../alert';
341
+ import { Spinner } from '../spinner';
7
342
  import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
8
343
 
9
344
  /**
@@ -22,7 +357,9 @@ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
22
357
  }
23
358
  return (
24
359
  <Alert type="error" header="Runtime config configuration error">
25
- The cognitoProps have not been configured in the runtime-config.json.
360
+ <p>
361
+ The cognitoProps have not been configured in the runtime-config.json.
362
+ </p>
26
363
  </Alert>
27
364
  );
28
365
  }
@@ -53,16 +390,20 @@ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
53
390
 
54
391
  if (auth.isAuthenticated) {
55
392
  return children;
56
- } else if (auth.error) {
393
+ }
394
+
395
+ if (auth.error) {
57
396
  return (
58
397
  <Alert type="error" header="Configuration error">
59
- Error contacting Cognito. Please check your runtime-config.json is
60
- configured with the correct endpoints.
398
+ <p>
399
+ Error contacting Cognito. Please check your runtime-config.json is
400
+ configured with the correct endpoints.
401
+ </p>
61
402
  </Alert>
62
403
  );
63
- } else {
64
- return <Spinner />;
65
404
  }
405
+
406
+ return <Spinner />;
66
407
  };
67
408
 
68
409
  export default CognitoAuth;
@@ -264,184 +605,6 @@ export class UserIdentity extends Construct {
264
605
 
265
606
  exports[`cognito-auth generator > should not be able to run the generator multiple times 1`] = `[Error: This generator has already been run on test-project.]`;
266
607
 
267
- exports[`cognito-auth generator > should update AppLayout > app-layout-with-auth 1`] = `
268
- "import { useAuth } from 'react-oidc-context';
269
- import * as React from 'react';
270
- import { createContext, useCallback, useEffect, useState } from 'react';
271
- import { NavItems } from './navitems';
272
- import Config from '../../config';
273
-
274
- import {
275
- BreadcrumbGroup,
276
- BreadcrumbGroupProps,
277
- SideNavigation,
278
- TopNavigation,
279
- } from '@cloudscape-design/components';
280
-
281
- import CloudscapeAppLayout, {
282
- AppLayoutProps,
283
- } from '@cloudscape-design/components/app-layout';
284
-
285
- import { matchByPath, useLocation, useNavigate } from '@tanstack/react-router';
286
- import { Outlet } from '@tanstack/react-router';
287
-
288
- const getBreadcrumbs = (
289
- pathName: string,
290
- search: string,
291
- defaultBreadcrumb: string,
292
- availableRoutes?: string[],
293
- ) => {
294
- const segments = [
295
- defaultBreadcrumb,
296
- ...pathName.split('/').filter((segment) => segment !== ''),
297
- ];
298
-
299
- return segments.map((segment, i) => {
300
- const href =
301
- i === 0
302
- ? '/'
303
- : \`/\${segments
304
- .slice(1, i + 1)
305
- .join('/')
306
- .replace('//', '/')}\`;
307
-
308
- const matched =
309
- !availableRoutes || availableRoutes.find((r) => matchByPath(r, href, {}));
310
-
311
- return {
312
- href: matched ? \`\${href}\${search}\` : '#',
313
- text: segment,
314
- };
315
- });
316
- };
317
-
318
- export interface AppLayoutContext {
319
- appLayoutProps: AppLayoutProps;
320
- setAppLayoutProps: (props: AppLayoutProps) => void;
321
- displayHelpPanel: (helpContent: React.ReactNode) => void;
322
- }
323
-
324
- /**
325
- * Context for updating/retrieving the AppLayout.
326
- */
327
- export const AppLayoutContext = createContext({
328
- appLayoutProps: {},
329
- // eslint-disable-next-line @typescript-eslint/no-empty-function
330
- setAppLayoutProps: (_: AppLayoutProps) => {},
331
- // eslint-disable-next-line @typescript-eslint/no-empty-function
332
- displayHelpPanel: (_: React.ReactNode) => {},
333
- });
334
-
335
- /**
336
- * Defines the App layout and contains logic for routing.
337
- */
338
- const AppLayout: React.FC = () => {
339
- const { user, removeUser, signoutRedirect, clearStaleState } = useAuth();
340
- const navigate = useNavigate();
341
- const appLayout = React.useRef<AppLayoutProps.Ref>(null);
342
- const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
343
- BreadcrumbGroupProps.Item[]
344
- >([{ text: '/', href: '/' }]);
345
- const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
346
- const { pathname, search } = useLocation();
347
- const setAppLayoutPropsSafe = useCallback(
348
- (props: AppLayoutProps) => {
349
- JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
350
- setAppLayoutProps(props);
351
- },
352
- [appLayoutProps],
353
- );
354
- useEffect(() => {
355
- const breadcrumbs = getBreadcrumbs(
356
- pathname,
357
- Object.entries(search).reduce((p, [k, v]) => p + \`\${k}=\${v}\`, ''),
358
- '/',
359
- );
360
- setActiveBreadcrumbs(breadcrumbs);
361
- }, [pathname, search]);
362
- const onNavigate = useCallback(
363
- (
364
- e: CustomEvent<{
365
- href: string;
366
- external?: boolean;
367
- }>,
368
- ) => {
369
- if (!e.detail.external) {
370
- e.preventDefault();
371
- setAppLayoutPropsSafe({
372
- contentType: undefined,
373
- });
374
- navigate({ to: e.detail.href });
375
- }
376
- },
377
- [navigate, setAppLayoutPropsSafe],
378
- );
379
- return (
380
- <AppLayoutContext.Provider
381
- value={{
382
- appLayoutProps,
383
- setAppLayoutProps: setAppLayoutPropsSafe,
384
- displayHelpPanel: (helpContent: React.ReactNode) => {
385
- setAppLayoutPropsSafe({ tools: helpContent, toolsHide: false });
386
- appLayout.current?.openTools();
387
- },
388
- }}
389
- >
390
- <TopNavigation
391
- identity={{
392
- href: '/',
393
- title: Config.applicationName,
394
- logo: {
395
- src: Config.logo,
396
- },
397
- }}
398
- utilities={[
399
- {
400
- type: 'menu-dropdown',
401
- text: \`\${user?.profile?.['cognito:username']}\`,
402
- iconName: 'user-profile-active',
403
- onItemClick: (e) => {
404
- if (e.detail.id === 'signout') {
405
- removeUser();
406
- signoutRedirect({
407
- post_logout_redirect_uri: window.location.origin,
408
- extraQueryParams: {
409
- redirect_uri: window.location.origin,
410
- response_type: 'code',
411
- },
412
- });
413
- clearStaleState();
414
- }
415
- },
416
- items: [{ id: 'signout', text: 'Sign out' }],
417
- },
418
- ]}
419
- />
420
- <CloudscapeAppLayout
421
- ref={appLayout}
422
- breadcrumbs={
423
- <BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
424
- }
425
- toolsHide
426
- navigation={
427
- <SideNavigation
428
- header={{ text: Config.applicationName, href: '/' }}
429
- activeHref={pathname}
430
- onFollow={onNavigate}
431
- items={NavItems}
432
- />
433
- }
434
- content={<Outlet />}
435
- {...appLayoutProps}
436
- />
437
- </AppLayoutContext.Provider>
438
- );
439
- };
440
-
441
- export default AppLayout;
442
- "
443
- `;
444
-
445
608
  exports[`cognito-auth generator > should update main.tsx when RuntimeConfigProvider exists > main-tsx-with-runtime-config 1`] = `
446
609
  "import CognitoAuth from './components/CognitoAuth';
447
610
  import RuntimeConfigProvider from './components/RuntimeConfig';
@@ -1,6 +1,7 @@
1
1
  import React, { PropsWithChildren, useEffect } from 'react';
2
2
  import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
3
- import { Alert, Spinner } from '@cloudscape-design/components';
3
+ import { Alert } from '../alert';
4
+ import { Spinner } from '../spinner';
4
5
  import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
5
6
 
6
7
  /**
@@ -15,16 +16,11 @@ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
15
16
  if (!cognitoProps) {
16
17
  if (import.meta.env.MODE === 'serve-local') {
17
18
  // In serve-local mode with no cognitoProps available, we skip login
18
- return (
19
- <AuthProvider>{children}</AuthProvider>
20
- );
19
+ return <AuthProvider>{children}</AuthProvider>;
21
20
  }
22
21
  return (
23
- <Alert
24
- type="error"
25
- header="Runtime config configuration error"
26
- >
27
- The cognitoProps have not been configured in the runtime-config.json.
22
+ <Alert type="error" header="Runtime config configuration error">
23
+ <p>The cognitoProps have not been configured in the runtime-config.json.</p>
28
24
  </Alert>
29
25
  );
30
26
  }
@@ -51,20 +47,24 @@ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
51
47
  if (!auth.isAuthenticated && !auth.isLoading) {
52
48
  auth.signinRedirect();
53
49
  }
54
- }, [auth])
50
+ }, [auth]);
55
51
 
56
52
  if (auth.isAuthenticated) {
57
53
  return children;
58
- } else if (auth.error) {
54
+ }
55
+
56
+ if (auth.error) {
59
57
  return (
60
58
  <Alert type="error" header="Configuration error">
61
- Error contacting Cognito. Please check your runtime-config.json is
62
- configured with the correct endpoints.
59
+ <p>
60
+ Error contacting Cognito. Please check your runtime-config.json is configured
61
+ with the correct endpoints.
62
+ </p>
63
63
  </Alert>
64
64
  );
65
- } else {
66
- return <Spinner />;
67
65
  }
66
+
67
+ return <Spinner />;
68
68
  };
69
69
 
70
70
  export default CognitoAuth;