@aws/nx-plugin 0.0.0
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.
- package/README.md +63 -0
- package/generators.json +52 -0
- package/package.json +27 -0
- package/src/cloudscape-website/app/README.md +253 -0
- package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +539 -0
- package/src/cloudscape-website/app/files/app/src/config.ts.template +4 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +132 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +8 -0
- package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +18 -0
- package/src/cloudscape-website/app/files/app/src/main.tsx.template +22 -0
- package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +25 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +317 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +4 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/static-website.ts.template +237 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +301 -0
- package/src/cloudscape-website/app/files/e2e/cypress/src/e2e/app.cy.ts.template +13 -0
- package/src/cloudscape-website/app/files/e2e/cypress/src/support/app.po.ts.template +1 -0
- package/src/cloudscape-website/app/files/e2e/playwright/src/example.spec.ts.template +6 -0
- package/src/cloudscape-website/app/generator.d.ts +4 -0
- package/src/cloudscape-website/app/generator.js +177 -0
- package/src/cloudscape-website/app/generator.js.map +1 -0
- package/src/cloudscape-website/app/schema.d.js +6 -0
- package/src/cloudscape-website/app/schema.d.js.map +1 -0
- package/src/cloudscape-website/app/schema.d.ts +35 -0
- package/src/cloudscape-website/app/schema.json +189 -0
- package/src/cloudscape-website/cognito-auth/README.md +172 -0
- package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +238 -0
- package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +50 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +4 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +69 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +70 -0
- package/src/cloudscape-website/cognito-auth/generator.d.ts +4 -0
- package/src/cloudscape-website/cognito-auth/generator.js +100 -0
- package/src/cloudscape-website/cognito-auth/generator.js.map +1 -0
- package/src/cloudscape-website/cognito-auth/schema.d.js +6 -0
- package/src/cloudscape-website/cognito-auth/schema.d.js.map +1 -0
- package/src/cloudscape-website/cognito-auth/schema.d.ts +4 -0
- package/src/cloudscape-website/cognito-auth/schema.json +36 -0
- package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +112 -0
- package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +46 -0
- package/src/cloudscape-website/runtime-config/generator.d.ts +4 -0
- package/src/cloudscape-website/runtime-config/generator.js +74 -0
- package/src/cloudscape-website/runtime-config/generator.js.map +1 -0
- package/src/cloudscape-website/runtime-config/schema.d.js +6 -0
- package/src/cloudscape-website/runtime-config/schema.d.js.map +1 -0
- package/src/cloudscape-website/runtime-config/schema.d.ts +3 -0
- package/src/cloudscape-website/runtime-config/schema.json +19 -0
- package/src/gitlab/files/.gitlab-ci.yml.template +26 -0
- package/src/gitlab/generator.d.ts +4 -0
- package/src/gitlab/generator.js +26 -0
- package/src/gitlab/generator.js.map +1 -0
- package/src/gitlab/schema.d.js +6 -0
- package/src/gitlab/schema.d.js.map +1 -0
- package/src/gitlab/schema.d.ts +5 -0
- package/src/gitlab/schema.json +52 -0
- package/src/index.d.ts +0 -0
- package/src/index.js +3 -0
- package/src/index.js.map +1 -0
- package/src/infra/app/README.md +175 -0
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +864 -0
- package/src/infra/app/files/cdk.json +67 -0
- package/src/infra/app/files/src/main.ts.template +37 -0
- package/src/infra/app/files/src/stacks/application-stack.ts.template +10 -0
- package/src/infra/app/generator.d.ts +4 -0
- package/src/infra/app/generator.js +75 -0
- package/src/infra/app/generator.js.map +1 -0
- package/src/infra/app/schema.d.js +6 -0
- package/src/infra/app/schema.d.js.map +1 -0
- package/src/infra/app/schema.d.ts +6 -0
- package/src/infra/app/schema.json +35 -0
- package/src/trpc/backend/README.md +549 -0
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +110 -0
- package/src/trpc/backend/files/backend/src/index.ts.template +1 -0
- package/src/trpc/backend/files/backend/src/lambdas/index.ts.template +1 -0
- package/src/trpc/backend/files/backend/src/lambdas/middleware.ts.template +146 -0
- package/src/trpc/backend/files/backend/src/lambdas/router.ts.template +36 -0
- package/src/trpc/backend/files/common/constructs/src/__apiNameKebabCase__/index.ts.template +64 -0
- package/src/trpc/backend/files/schema/src/index.ts.template +7 -0
- package/src/trpc/backend/generator.d.ts +4 -0
- package/src/trpc/backend/generator.js +128 -0
- package/src/trpc/backend/generator.js.map +1 -0
- package/src/trpc/backend/schema.d.js +6 -0
- package/src/trpc/backend/schema.d.js.map +1 -0
- package/src/trpc/backend/schema.d.ts +8 -0
- package/src/trpc/backend/schema.json +44 -0
- package/src/trpc/react/README.md +320 -0
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +98 -0
- package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +34 -0
- package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +5 -0
- package/src/trpc/react/generator.d.ts +4 -0
- package/src/trpc/react/generator.js +81 -0
- package/src/trpc/react/generator.js.map +1 -0
- package/src/trpc/react/schema.d.js +6 -0
- package/src/trpc/react/schema.d.js.map +1 -0
- package/src/trpc/react/schema.d.ts +5 -0
- package/src/trpc/react/schema.json +32 -0
- package/src/ts/cjs-to-esm/generator.d.ts +8 -0
- package/src/ts/cjs-to-esm/generator.js +201 -0
- package/src/ts/cjs-to-esm/generator.js.map +1 -0
- package/src/ts/cjs-to-esm/schema.d.js +6 -0
- package/src/ts/cjs-to-esm/schema.d.js.map +1 -0
- package/src/ts/cjs-to-esm/schema.d.ts +5 -0
- package/src/ts/cjs-to-esm/schema.json +28 -0
- package/src/ts/lib/README.md +149 -0
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +260 -0
- package/src/ts/lib/eslint.d.ts +3 -0
- package/src/ts/lib/eslint.js +41 -0
- package/src/ts/lib/eslint.js.map +1 -0
- package/src/ts/lib/files/src/index.ts.template +3 -0
- package/src/ts/lib/generator.d.ts +21 -0
- package/src/ts/lib/generator.js +61 -0
- package/src/ts/lib/generator.js.map +1 -0
- package/src/ts/lib/schema.d.js +6 -0
- package/src/ts/lib/schema.d.js.map +1 -0
- package/src/ts/lib/schema.d.ts +13 -0
- package/src/ts/lib/schema.json +46 -0
- package/src/ts/lib/ts-project-utils.d.ts +6 -0
- package/src/ts/lib/ts-project-utils.js +107 -0
- package/src/ts/lib/ts-project-utils.js.map +1 -0
- package/src/ts/lib/types.d.ts +10 -0
- package/src/ts/lib/types.js +6 -0
- package/src/ts/lib/types.js.map +1 -0
- package/src/ts/lib/vitest.d.ts +3 -0
- package/src/ts/lib/vitest.js +67 -0
- package/src/ts/lib/vitest.js.map +1 -0
- package/src/utils/files/common/constructs/src/index.ts.template +1 -0
- package/src/utils/files/common/constructs/src/runtime-config/index.ts.template +1 -0
- package/src/utils/files/common/constructs/src/runtime-config/runtime-config.ts.template +33 -0
- package/src/utils/files/common/types/src/index.ts.template +1 -0
- package/src/utils/files/common/types/src/runtime-config.ts.template +13 -0
- package/src/utils/npm-scope.d.ts +7 -0
- package/src/utils/npm-scope.js +37 -0
- package/src/utils/npm-scope.js.map +1 -0
- package/src/utils/paths.d.ts +3 -0
- package/src/utils/paths.js +32 -0
- package/src/utils/paths.js.map +1 -0
- package/src/utils/shared-constructs.d.ts +7 -0
- package/src/utils/shared-constructs.js +72 -0
- package/src/utils/shared-constructs.js.map +1 -0
- package/src/utils/versions.d.ts +31 -0
- package/src/utils/versions.js +49 -0
- package/src/utils/versions.js.map +1 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`cloudscape-website generator > should configure TypeScript correctly > tsconfig.json 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"allowJs": false,
|
|
7
|
+
"allowSyntheticDefaultImports": true,
|
|
8
|
+
"esModuleInterop": false,
|
|
9
|
+
"jsx": "react-jsx",
|
|
10
|
+
"module": "Preserve",
|
|
11
|
+
"moduleResolution": "Bundler",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"types": [
|
|
14
|
+
"vite/client",
|
|
15
|
+
"vitest",
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
"extends": "../tsconfig.base.json",
|
|
19
|
+
"files": [],
|
|
20
|
+
"include": [],
|
|
21
|
+
"references": [
|
|
22
|
+
{
|
|
23
|
+
"path": "./tsconfig.app.json",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"path": "./tsconfig.spec.json",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
exports[`cloudscape-website generator > should configure vite correctly > vite.config.ts 1`] = `
|
|
33
|
+
"/// <reference types='vitest' />
|
|
34
|
+
import { defineConfig } from 'vite';
|
|
35
|
+
import react from '@vitejs/plugin-react';
|
|
36
|
+
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
37
|
+
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
define: {
|
|
40
|
+
global: {},
|
|
41
|
+
},
|
|
42
|
+
root: __dirname,
|
|
43
|
+
cacheDir: '../node_modules/.vite/test-app',
|
|
44
|
+
server: {
|
|
45
|
+
port: 4200,
|
|
46
|
+
host: 'localhost',
|
|
47
|
+
},
|
|
48
|
+
preview: {
|
|
49
|
+
port: 4300,
|
|
50
|
+
host: 'localhost',
|
|
51
|
+
},
|
|
52
|
+
plugins: [react(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
|
53
|
+
build: {
|
|
54
|
+
outDir: '../dist/test-app',
|
|
55
|
+
emptyOutDir: true,
|
|
56
|
+
reportCompressedSize: true,
|
|
57
|
+
commonjsOptions: {
|
|
58
|
+
transformMixedEsModules: true,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
test: {
|
|
62
|
+
watch: false,
|
|
63
|
+
globals: true,
|
|
64
|
+
environment: 'jsdom',
|
|
65
|
+
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
66
|
+
reporters: ['default'],
|
|
67
|
+
coverage: {
|
|
68
|
+
reportsDirectory: '../coverage/test-app',
|
|
69
|
+
provider: 'v8',
|
|
70
|
+
},
|
|
71
|
+
passWithNoTests: true,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
"
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
exports[`cloudscape-website generator > should generate base files and structure > app-layout.tsx 1`] = `
|
|
78
|
+
"/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
79
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
80
|
+
import { useCognitoAuthContext } from '@aws-northstar/ui';
|
|
81
|
+
import getBreadcrumbs from '@aws-northstar/ui/components/AppLayout/utils/getBreadcrumbs';
|
|
82
|
+
import NavHeader from '@aws-northstar/ui/components/AppLayout/components/NavHeader';
|
|
83
|
+
import * as React from 'react';
|
|
84
|
+
import { createContext, useCallback, useEffect, useState } from 'react';
|
|
85
|
+
import { NavItems } from './navitems';
|
|
86
|
+
import Config from '../../config';
|
|
87
|
+
import Routes from '../Routes';
|
|
88
|
+
|
|
89
|
+
import {
|
|
90
|
+
BreadcrumbGroup,
|
|
91
|
+
BreadcrumbGroupProps,
|
|
92
|
+
SideNavigation,
|
|
93
|
+
} from '@cloudscape-design/components';
|
|
94
|
+
import AppLayout, {
|
|
95
|
+
AppLayoutProps,
|
|
96
|
+
} from '@cloudscape-design/components/app-layout';
|
|
97
|
+
import { useLocation, useNavigate } from 'react-router-dom';
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Context for updating/retrieving the AppLayout.
|
|
101
|
+
*/
|
|
102
|
+
export const AppLayoutContext = createContext({
|
|
103
|
+
appLayoutProps: {},
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
105
|
+
setAppLayoutProps: (_: AppLayoutProps) => {},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Defines the App layout and contains logic for routing.
|
|
110
|
+
*/
|
|
111
|
+
const App: React.FC = () => {
|
|
112
|
+
const [username, setUsername] = useState<string | undefined>();
|
|
113
|
+
const [email, setEmail] = useState<string | undefined>();
|
|
114
|
+
const { getAuthenticatedUser } = useCognitoAuthContext();
|
|
115
|
+
|
|
116
|
+
const navigate = useNavigate();
|
|
117
|
+
const [activeHref, setActiveHref] = useState('/');
|
|
118
|
+
const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
|
|
119
|
+
BreadcrumbGroupProps.Item[]
|
|
120
|
+
>([{ text: '/', href: '/' }]);
|
|
121
|
+
const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
|
|
122
|
+
const location = useLocation();
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
const authUser = getAuthenticatedUser();
|
|
126
|
+
setUsername(authUser?.getUsername());
|
|
127
|
+
|
|
128
|
+
authUser?.getSession(() => {
|
|
129
|
+
authUser.getUserAttributes((_, attributes) => {
|
|
130
|
+
setEmail(attributes?.find((a) => a.Name === 'email')?.Value);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}, [getAuthenticatedUser, setUsername, setEmail]);
|
|
134
|
+
|
|
135
|
+
const setAppLayoutPropsSafe = useCallback(
|
|
136
|
+
(props: AppLayoutProps) => {
|
|
137
|
+
JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
|
|
138
|
+
setAppLayoutProps(props);
|
|
139
|
+
},
|
|
140
|
+
[appLayoutProps]
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
setActiveHref(location.pathname);
|
|
145
|
+
const breadcrumbs = getBreadcrumbs(location.pathname, location.search, '/');
|
|
146
|
+
setActiveBreadcrumbs(breadcrumbs);
|
|
147
|
+
}, [location]);
|
|
148
|
+
|
|
149
|
+
const onNavigate = useCallback(
|
|
150
|
+
(e: CustomEvent<{ href: string; external?: boolean }>) => {
|
|
151
|
+
if (!e.detail.external) {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
setAppLayoutPropsSafe({
|
|
154
|
+
contentType: undefined,
|
|
155
|
+
splitPanelOpen: false,
|
|
156
|
+
splitPanelSize: undefined,
|
|
157
|
+
splitPanelPreferences: undefined,
|
|
158
|
+
});
|
|
159
|
+
navigate(e.detail.href);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
[navigate, setAppLayoutPropsSafe]
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<AppLayoutContext.Provider
|
|
167
|
+
value={{ appLayoutProps, setAppLayoutProps: setAppLayoutPropsSafe }}
|
|
168
|
+
>
|
|
169
|
+
<NavHeader
|
|
170
|
+
title={Config.applicationName}
|
|
171
|
+
logo={Config.logo}
|
|
172
|
+
user={
|
|
173
|
+
username
|
|
174
|
+
? {
|
|
175
|
+
username,
|
|
176
|
+
email,
|
|
177
|
+
}
|
|
178
|
+
: undefined
|
|
179
|
+
}
|
|
180
|
+
onSignout={() =>
|
|
181
|
+
new Promise(() => {
|
|
182
|
+
getAuthenticatedUser()?.signOut();
|
|
183
|
+
window.location.href = '/';
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
/>
|
|
187
|
+
<AppLayout
|
|
188
|
+
breadcrumbs={
|
|
189
|
+
<BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
|
|
190
|
+
}
|
|
191
|
+
toolsHide
|
|
192
|
+
navigation={
|
|
193
|
+
<SideNavigation
|
|
194
|
+
header={{ text: Config.applicationName, href: '/' }}
|
|
195
|
+
activeHref={activeHref}
|
|
196
|
+
onFollow={onNavigate}
|
|
197
|
+
items={NavItems}
|
|
198
|
+
/>
|
|
199
|
+
}
|
|
200
|
+
content={<Routes />}
|
|
201
|
+
splitPanelOpen={false}
|
|
202
|
+
splitPanelPreferences={{ position: 'bottom' }}
|
|
203
|
+
{...appLayoutProps}
|
|
204
|
+
/>
|
|
205
|
+
</AppLayoutContext.Provider>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default App;
|
|
210
|
+
"
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
exports[`cloudscape-website generator > should generate base files and structure > config.ts 1`] = `
|
|
214
|
+
"export default {
|
|
215
|
+
applicationName: 'test-app',
|
|
216
|
+
logo: 'data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMjQ4YmFlIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZT0iIzI0OGJhZSI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+Cg08dGl0bGU+aW9uaWNvbnMtdjVfbG9nb3M8L3RpdGxlPgoNPHBhdGggZD0iTTQxMC42NiwxODAuNzJoMHEtNy42Ny0yLjYyLTE1LjQ1LTQuODgsMS4yOS01LjI1LDIuMzgtMTAuNTZjMTEuNy01Ni45LDQuMDUtMTAyLjc0LTIyLjA2LTExNy44My0yNS0xNC40OC02NiwuNjEtMTA3LjM2LDM2LjY5cS02LjEsNS4zNC0xMS45NSwxMS0zLjktMy43Ni04LTcuMzZjLTQzLjM1LTM4LjU4LTg2LjgtNTQuODMtMTEyLjg4LTM5LjY5LTI1LDE0LjUxLTMyLjQzLDU3LjYtMjEuOSwxMTEuNTNxMS41OCw4LDMuNTUsMTUuOTNjLTYuMTUsMS43NS0xMi4wOSwzLjYyLTE3Ljc3LDUuNkM0OC40NiwxOTguOSwxNiwyMjYuNzMsMTYsMjU1LjU5YzAsMjkuODIsMzQuODQsNTkuNzIsODcuNzcsNzcuODVxNi40NCwyLjE5LDEzLDQuMDdRMTE0LjY0LDM0NiwxMTMsMzU0LjY4Yy0xMCw1My0yLjIsOTUuMDcsMjIuNzUsMTA5LjQ5LDI1Ljc3LDE0Ljg5LDY5LS40MSwxMTEuMTQtMzcuMzFxNS00LjM4LDEwLTkuMjUsNi4zMiw2LjExLDEzLDExLjg2YzQwLjgsMzUuMTgsODEuMDksNDkuMzksMTA2LDM0LjkzLDI1Ljc1LTE0Ljk0LDM0LjEyLTYwLjE0LDIzLjI1LTExNS4xM3EtMS4yNS02LjMtMi44OC0xMi44Niw0LjU2LTEuMzUsOC45My0yLjc5YzU1LTE4LjI3LDkwLjgzLTQ3LjgxLDkwLjgzLTc4QzQ5NiwyMjYuNjIsNDYyLjUsMTk4LjYxLDQxMC42NiwxODAuNzJabS0xMjktODEuMDhjMzUuNDMtMzAuOTEsNjguNTUtNDMuMTEsODMuNjUtMzQuMzloMGMxNi4wNyw5LjI5LDIyLjMyLDQ2Ljc1LDEyLjIyLDk1Ljg4cS0xLDQuOC0yLjE2LDkuNTdhNDg3LjgzLDQ4Ny44MywwLDAsMC02NC4xOC0xMC4xNiw0ODEuMjcsNDgxLjI3LDAsMCwwLTQwLjU3LTUwLjc1UTI3NiwxMDQuNTcsMjgxLjY0LDk5LjY0Wk0xNTcuNzMsMjgwLjI1cTYuNTEsMTIuNiwxMy42MSwyNC44OSw3LjIzLDEyLjU0LDE1LjA3LDI0LjcxYTQzNS4yOCw0MzUuMjgsMCwwLDEtNDQuMjQtNy4xM0MxNDYuNDEsMzA5LDE1MS42MywyOTQuNzUsMTU3LjczLDI4MC4yNVptMC00OC4zM2MtNi0xNC4xOS0xMS4wOC0yOC4xNS0xNS4yNS00MS42MywxMy43LTMuMDcsMjguMy01LjU4LDQzLjUyLTcuNDhxLTcuNjUsMTEuOTQtMTQuNzIsMjQuMjNUMTU3LjcsMjMxLjkyWm0xMC45LDI0LjE3cTkuNDgtMTkuNzcsMjAuNDItMzguNzhoMHExMC45My0xOSwyMy4yNy0zNy4xM2MxNC4yOC0xLjA4LDI4LjkyLTEuNjUsNDMuNzEtMS42NXMyOS41Mi41Nyw0My43OSwxLjY2cTEyLjIxLDE4LjA5LDIzLjEzLDM3dDIwLjY5LDM4LjZRMzM0LDI3NS42MywzMjMsMjk0LjczaDBxLTEwLjkxLDE5LTIzLDM3LjI0Yy0xNC4yNSwxLTI5LDEuNTUtNDQsMS41NXMtMjkuNDctLjQ3LTQzLjQ2LTEuMzhxLTEyLjQzLTE4LjE5LTIzLjQ2LTM3LjI5VDE2OC42LDI1Ni4wOVpNMzQwLjc1LDMwNXE3LjI1LTEyLjU4LDEzLjkyLTI1LjQ5aDBhNDQwLjQxLDQ0MC40MSwwLDAsMSwxNi4xMiw0Mi4zMkE0MzQuNDQsNDM0LjQ0LDAsMCwxLDMyNiwzMjkuNDhRMzMzLjYyLDMxNy4zOSwzNDAuNzUsMzA1Wm0xMy43Mi03My4wN3EtNi42NC0xMi42NS0xMy44MS0yNWgwcS03LTEyLjE4LTE0LjU5LTI0LjA2YzE1LjMxLDEuOTQsMzAsNC41Miw0My43Nyw3LjY3QTQzOS44OSw0MzkuODksMCwwLDEsMzU0LjQ3LDIzMS45M1pNMjU2LjIzLDEyNC40OGgwYTQzOS43NSw0MzkuNzUsMCwwLDEsMjguMjUsMzQuMThxLTI4LjM1LTEuMzUtNTYuNzQsMEMyMzcuMDcsMTQ2LjMyLDI0Ni42MiwxMzQuODcsMjU2LjIzLDEyNC40OFpNMTQ1LjY2LDY1Ljg2YzE2LjA2LTkuMzIsNTEuNTcsNCw4OSwzNy4yNywyLjM5LDIuMTMsNC44LDQuMzYsNy4yLDYuNjdBNDkxLjM3LDQ5MS4zNywwLDAsMCwyMDEsMTYwLjUxYTQ5OS4xMiw0OTkuMTIsMCwwLDAtNjQuMDYsMTBxLTEuODMtNy4zNi0zLjMtMTQuODJoMEMxMjQuNTksMTA5LjQ2LDEzMC41OCw3NC42MSwxNDUuNjYsNjUuODZaTTEyMi4yNSwzMTcuNzFxLTYtMS43MS0xMS44NS0zLjcxYy0yMy40LTgtNDIuNzMtMTguNDQtNTYtMjkuODFDNDIuNTIsMjc0LDM2LjUsMjYzLjgzLDM2LjUsMjU1LjU5YzAtMTcuNTEsMjYuMDYtMzkuODUsNjkuNTItNTVxOC4xOS0yLjg1LDE2LjUyLTUuMjFhNDkzLjU0LDQ5My41NCwwLDAsMCwyMy40LDYwLjc1QTUwMi40Niw1MDIuNDYsMCwwLDAsMTIyLjI1LDMxNy43MVptMTExLjEzLDkzLjY3Yy0xOC42MywxNi4zMi0zNy4yOSwyNy44OS01My43NCwzMy43MmgwYy0xNC43OCw1LjIzLTI2LjU1LDUuMzgtMzMuNjYsMS4yNy0xNS4xNC04Ljc1LTIxLjQ0LTQyLjU0LTEyLjg1LTg3Ljg2cTEuNTMtOCwzLjUtMTZhNDgwLjg1LDQ4MC44NSwwLDAsMCw2NC42OSw5LjM5LDUwMS4yLDUwMS4yLDAsMCwwLDQxLjIsNTFDMjM5LjU0LDQwNS44MywyMzYuNDksNDA4LjY1LDIzMy4zOCw0MTEuMzhabTIzLjQyLTIzLjIyYy05LjcyLTEwLjUxLTE5LjQyLTIyLjE0LTI4Ljg4LTM0LjY0cTEzLjc5LjU0LDI4LjA4LjU0YzkuNzgsMCwxOS40Ni0uMjEsMjktLjY0QTQzOS4zMyw0MzkuMzMsMCwwLDEsMjU2LjgsMzg4LjE2Wm0xMjQuNTIsMjguNTljLTIuODYsMTUuNDQtOC42MSwyNS43NC0xNS43MiwyOS44Ni0xNS4xMyw4Ljc4LTQ3LjQ4LTIuNjMtODIuMzYtMzIuNzItNC0zLjQ0LTgtNy4xMy0xMi4wNy0xMWE0ODQuNTQsNDg0LjU0LDAsMCwwLDQwLjIzLTUxLjIsNDc3Ljg0LDQ3Ny44NCwwLDAsMCw2NS0xMC4wNXExLjQ3LDUuOTQsMi42LDExLjY0aDBDMzgzLjgxLDM3Ny41OCwzODQuNSwzOTkuNTYsMzgxLjMyLDQxNi43NVptMTcuNC0xMDIuNjRoMGMtMi42Mi44Ny01LjMyLDEuNzEtOC4wNiwyLjUzYTQ4My4yNiw0ODMuMjYsMCwwLDAtMjQuMzEtNjAuOTQsNDgxLjUyLDQ4MS41MiwwLDAsMCwyMy4zNi02MC4wNmM0LjkxLDEuNDMsOS42OCwyLjkzLDE0LjI3LDQuNTIsNDQuNDIsMTUuMzIsNzEuNTIsMzgsNzEuNTIsNTUuNDNDNDc1LjUsMjc0LjE5LDQ0Ni4yMywyOTguMzMsMzk4LjcyLDMxNC4xMVoiLz4KDTxwYXRoIGQ9Ik0yNTYsMjk4LjU1YTQzLDQzLDAsMSwwLTQyLjg2LTQzQTQyLjkxLDQyLjkxLDAsMCwwLDI1NiwyOTguNTVaIi8+Cg08L2c+Cg08L3N2Zz4=',
|
|
217
|
+
};
|
|
218
|
+
"
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
exports[`cloudscape-website generator > should generate base files and structure > main.tsx 1`] = `
|
|
222
|
+
"/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
223
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
224
|
+
import { NorthStarThemeProvider } from '@aws-northstar/ui';
|
|
225
|
+
import React from 'react';
|
|
226
|
+
import { createRoot } from 'react-dom/client';
|
|
227
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
228
|
+
import { I18nProvider } from '@cloudscape-design/components/i18n';
|
|
229
|
+
import messages from '@cloudscape-design/components/i18n/messages/all.en';
|
|
230
|
+
import App from './layouts/App';
|
|
231
|
+
|
|
232
|
+
const root = document.getElementById('root');
|
|
233
|
+
root &&
|
|
234
|
+
createRoot(root).render(
|
|
235
|
+
<React.StrictMode>
|
|
236
|
+
<NorthStarThemeProvider>
|
|
237
|
+
<I18nProvider locale="en" messages={[messages]}>
|
|
238
|
+
<BrowserRouter>
|
|
239
|
+
<App />
|
|
240
|
+
</BrowserRouter>
|
|
241
|
+
</I18nProvider>
|
|
242
|
+
</NorthStarThemeProvider>
|
|
243
|
+
</React.StrictMode>
|
|
244
|
+
);
|
|
245
|
+
"
|
|
246
|
+
`;
|
|
247
|
+
|
|
248
|
+
exports[`cloudscape-website generator > should generate shared constructs > common/constructs-index.ts 1`] = `
|
|
249
|
+
"/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
250
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
251
|
+
export * from './cloudfront-web-acl.js';
|
|
252
|
+
export * from './static-website.js';
|
|
253
|
+
"
|
|
254
|
+
`;
|
|
255
|
+
|
|
256
|
+
exports[`cloudscape-website generator > should generate shared constructs > static-website.ts 1`] = `
|
|
257
|
+
"/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
258
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
259
|
+
import * as url from 'url';
|
|
260
|
+
import { PDKNag } from '@aws/pdk/pdk-nag';
|
|
261
|
+
import { CfnOutput, RemovalPolicy, Stack } from 'aws-cdk-lib';
|
|
262
|
+
import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
263
|
+
import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
264
|
+
import {
|
|
265
|
+
BlockPublicAccess,
|
|
266
|
+
Bucket,
|
|
267
|
+
BucketEncryption,
|
|
268
|
+
IBucket,
|
|
269
|
+
ObjectOwnership,
|
|
270
|
+
} from 'aws-cdk-lib/aws-s3';
|
|
271
|
+
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
|
|
272
|
+
import { NagSuppressions } from 'cdk-nag';
|
|
273
|
+
import { Construct } from 'constructs';
|
|
274
|
+
import { CloudfrontWebAcl } from './cloudfront-web-acl.js';
|
|
275
|
+
import { RuntimeConfig } from '../runtime-config/index.js';
|
|
276
|
+
|
|
277
|
+
const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
|
|
281
|
+
*
|
|
282
|
+
* This construct configures a webAcl containing rules that are generally applicable to web applications. This
|
|
283
|
+
* provides protection against exploitation of a wide range of vulnerabilities, including some of the high risk
|
|
284
|
+
* and commonly occurring vulnerabilities described in OWASP publications such as OWASP Top 10.
|
|
285
|
+
*
|
|
286
|
+
*/
|
|
287
|
+
export class StaticWebsite extends Construct {
|
|
288
|
+
public readonly websiteBucket: IBucket;
|
|
289
|
+
public readonly cloudFrontDistribution: Distribution;
|
|
290
|
+
public readonly bucketDeployment: BucketDeployment;
|
|
291
|
+
|
|
292
|
+
constructor(scope: Construct, id: string) {
|
|
293
|
+
super(scope, id);
|
|
294
|
+
|
|
295
|
+
this.node.setContext(
|
|
296
|
+
'@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
|
|
297
|
+
true
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
|
|
301
|
+
versioned: false,
|
|
302
|
+
enforceSSL: true,
|
|
303
|
+
autoDeleteObjects: true,
|
|
304
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
305
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
306
|
+
objectOwnership: ObjectOwnership.OBJECT_WRITER,
|
|
307
|
+
publicReadAccess: false,
|
|
308
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// S3 Bucket to hold website files
|
|
312
|
+
this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
|
|
313
|
+
versioned: true,
|
|
314
|
+
enforceSSL: true,
|
|
315
|
+
autoDeleteObjects: true,
|
|
316
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
317
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
318
|
+
objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
|
|
319
|
+
publicReadAccess: false,
|
|
320
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
321
|
+
serverAccessLogsPrefix: 'website-access-logs',
|
|
322
|
+
serverAccessLogsBucket: accessLogsBucket,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Web ACL
|
|
326
|
+
const webAclArn = new CloudfrontWebAcl(this, 'WebsiteAcl').webAclArn;
|
|
327
|
+
|
|
328
|
+
// Cloudfront Distribution
|
|
329
|
+
const logBucket = new Bucket(this, 'DistributionLogBucket', {
|
|
330
|
+
enforceSSL: true,
|
|
331
|
+
autoDeleteObjects: true,
|
|
332
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
333
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
334
|
+
objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
|
|
335
|
+
publicReadAccess: false,
|
|
336
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
337
|
+
serverAccessLogsPrefix: 'distribution-access-logs',
|
|
338
|
+
serverAccessLogsBucket: accessLogsBucket,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const defaultRootObject = 'index.html';
|
|
342
|
+
this.cloudFrontDistribution = new Distribution(
|
|
343
|
+
this,
|
|
344
|
+
'CloudfrontDistribution',
|
|
345
|
+
{
|
|
346
|
+
webAclId: webAclArn,
|
|
347
|
+
enableLogging: true,
|
|
348
|
+
logBucket: logBucket,
|
|
349
|
+
defaultBehavior: {
|
|
350
|
+
origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
|
|
351
|
+
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
352
|
+
},
|
|
353
|
+
defaultRootObject,
|
|
354
|
+
errorResponses: [
|
|
355
|
+
{
|
|
356
|
+
httpStatus: 404, // We need to redirect "key not found errors" to index.html for single page apps
|
|
357
|
+
responseHttpStatus: 200,
|
|
358
|
+
responsePagePath: \`/\${defaultRootObject}\`,
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Deploy Website
|
|
365
|
+
const runtimeConfig = RuntimeConfig.ensure(this).config;
|
|
366
|
+
this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
|
|
367
|
+
sources: [
|
|
368
|
+
Source.asset(
|
|
369
|
+
url.fileURLToPath(
|
|
370
|
+
new URL('../../../../../dist/test-app', import.meta.url)
|
|
371
|
+
)
|
|
372
|
+
),
|
|
373
|
+
...(Object.keys(runtimeConfig).length > 0
|
|
374
|
+
? [Source.jsonData(DEFAULT_RUNTIME_CONFIG_FILENAME, runtimeConfig)]
|
|
375
|
+
: []),
|
|
376
|
+
],
|
|
377
|
+
destinationBucket: this.websiteBucket,
|
|
378
|
+
// Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
|
|
379
|
+
distribution: this.cloudFrontDistribution,
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
new CfnOutput(this, 'DistributionDomainName', {
|
|
383
|
+
value: this.cloudFrontDistribution.domainName,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
this.suppressCDKNagViolations();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private suppressCDKNagViolations = () => {
|
|
390
|
+
const stack = Stack.of(this);
|
|
391
|
+
|
|
392
|
+
NagSuppressions.addResourceSuppressions(
|
|
393
|
+
this,
|
|
394
|
+
[
|
|
395
|
+
{
|
|
396
|
+
id: 'AwsPrototyping-CloudFrontDistributionGeoRestrictions',
|
|
397
|
+
reason:
|
|
398
|
+
'Suppressed to allow unrestricted access. Not recommended in production.',
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
true
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
[
|
|
405
|
+
'AwsSolutions-CFR4',
|
|
406
|
+
'AwsPrototyping-CloudFrontDistributionHttpsViewerNoOutdatedSSL',
|
|
407
|
+
].forEach((RuleId) => {
|
|
408
|
+
NagSuppressions.addResourceSuppressions(this.cloudFrontDistribution, [
|
|
409
|
+
{
|
|
410
|
+
id: RuleId,
|
|
411
|
+
reason:
|
|
412
|
+
'Certificate is not mandatory therefore the Cloudfront certificate will be used.',
|
|
413
|
+
},
|
|
414
|
+
]);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
['AwsSolutions-L1', 'AwsPrototyping-LambdaLatestVersion'].forEach(
|
|
418
|
+
(RuleId) => {
|
|
419
|
+
NagSuppressions.addResourceSuppressions(
|
|
420
|
+
this,
|
|
421
|
+
[
|
|
422
|
+
{
|
|
423
|
+
id: RuleId,
|
|
424
|
+
reason:
|
|
425
|
+
'Latest runtime cannot be configured. CDK will need to upgrade the BucketDeployment construct accordingly.',
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
true
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
|
|
434
|
+
(RuleId) => {
|
|
435
|
+
NagSuppressions.addResourceSuppressions(
|
|
436
|
+
this,
|
|
437
|
+
[
|
|
438
|
+
{
|
|
439
|
+
id: RuleId,
|
|
440
|
+
reason:
|
|
441
|
+
'All Policies have been scoped to a Bucket. Given Buckets can contain arbitrary content, wildcard resources with bucket scope are required.',
|
|
442
|
+
appliesTo: [
|
|
443
|
+
{
|
|
444
|
+
regex: '/^Action::s3:.*$/g',
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
regex: \`/^Resource::.*$/g\`,
|
|
448
|
+
},
|
|
449
|
+
],
|
|
450
|
+
},
|
|
451
|
+
],
|
|
452
|
+
true
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
['AwsSolutions-IAM4', 'AwsPrototyping-IAMNoManagedPolicies'].forEach(
|
|
458
|
+
(RuleId) => {
|
|
459
|
+
NagSuppressions.addResourceSuppressions(
|
|
460
|
+
this,
|
|
461
|
+
[
|
|
462
|
+
{
|
|
463
|
+
id: RuleId,
|
|
464
|
+
reason:
|
|
465
|
+
'Buckets can contain arbitrary content, therefore wildcard resources under a bucket are required.',
|
|
466
|
+
appliesTo: [
|
|
467
|
+
{
|
|
468
|
+
regex: \`/^Policy::arn:\${PDKNag.getStackPartitionRegex(
|
|
469
|
+
stack
|
|
470
|
+
)}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole$/g\`,
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
true
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
['AwsSolutions-S1', 'AwsPrototyping-S3BucketLoggingEnabled'].forEach(
|
|
481
|
+
(RuleId) => {
|
|
482
|
+
NagSuppressions.addResourceSuppressions(
|
|
483
|
+
this,
|
|
484
|
+
[
|
|
485
|
+
{
|
|
486
|
+
id: RuleId,
|
|
487
|
+
reason: 'Access Log buckets should not have s3 bucket logging',
|
|
488
|
+
},
|
|
489
|
+
],
|
|
490
|
+
true
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
"
|
|
497
|
+
`;
|
|
498
|
+
|
|
499
|
+
exports[`cloudscape-website generator > should handle custom directory option > custom-dir-main.tsx 1`] = `
|
|
500
|
+
"/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
501
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
502
|
+
import { NorthStarThemeProvider } from '@aws-northstar/ui';
|
|
503
|
+
import React from 'react';
|
|
504
|
+
import { createRoot } from 'react-dom/client';
|
|
505
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
506
|
+
import { I18nProvider } from '@cloudscape-design/components/i18n';
|
|
507
|
+
import messages from '@cloudscape-design/components/i18n/messages/all.en';
|
|
508
|
+
import App from './layouts/App';
|
|
509
|
+
|
|
510
|
+
const root = document.getElementById('root');
|
|
511
|
+
root &&
|
|
512
|
+
createRoot(root).render(
|
|
513
|
+
<React.StrictMode>
|
|
514
|
+
<NorthStarThemeProvider>
|
|
515
|
+
<I18nProvider locale="en" messages={[messages]}>
|
|
516
|
+
<BrowserRouter>
|
|
517
|
+
<App />
|
|
518
|
+
</BrowserRouter>
|
|
519
|
+
</I18nProvider>
|
|
520
|
+
</NorthStarThemeProvider>
|
|
521
|
+
</React.StrictMode>
|
|
522
|
+
);
|
|
523
|
+
"
|
|
524
|
+
`;
|
|
525
|
+
|
|
526
|
+
exports[`cloudscape-website generator > should handle npm scope prefix correctly > scoped-dependencies 1`] = `
|
|
527
|
+
{
|
|
528
|
+
"@aws-northstar/ui": "^1.1.13",
|
|
529
|
+
"@aws/pdk": "^0.25.7",
|
|
530
|
+
"@cloudscape-design/board-components": "^3.0.84",
|
|
531
|
+
"@cloudscape-design/components": "^3.0.823",
|
|
532
|
+
"aws-cdk-lib": "^2.166.0",
|
|
533
|
+
"cdk-nag": "^2.32.2",
|
|
534
|
+
"constructs": "^10.4.2",
|
|
535
|
+
"react": "18.3.1",
|
|
536
|
+
"react-dom": "18.3.1",
|
|
537
|
+
"react-router-dom": "^6.28.0",
|
|
538
|
+
}
|
|
539
|
+
`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
"applicationName": "<%= name %>",
|
|
3
|
+
"logo": "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMjQ4YmFlIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZT0iIzI0OGJhZSI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+Cg08dGl0bGU+aW9uaWNvbnMtdjVfbG9nb3M8L3RpdGxlPgoNPHBhdGggZD0iTTQxMC42NiwxODAuNzJoMHEtNy42Ny0yLjYyLTE1LjQ1LTQuODgsMS4yOS01LjI1LDIuMzgtMTAuNTZjMTEuNy01Ni45LDQuMDUtMTAyLjc0LTIyLjA2LTExNy44My0yNS0xNC40OC02NiwuNjEtMTA3LjM2LDM2LjY5cS02LjEsNS4zNC0xMS45NSwxMS0zLjktMy43Ni04LTcuMzZjLTQzLjM1LTM4LjU4LTg2LjgtNTQuODMtMTEyLjg4LTM5LjY5LTI1LDE0LjUxLTMyLjQzLDU3LjYtMjEuOSwxMTEuNTNxMS41OCw4LDMuNTUsMTUuOTNjLTYuMTUsMS43NS0xMi4wOSwzLjYyLTE3Ljc3LDUuNkM0OC40NiwxOTguOSwxNiwyMjYuNzMsMTYsMjU1LjU5YzAsMjkuODIsMzQuODQsNTkuNzIsODcuNzcsNzcuODVxNi40NCwyLjE5LDEzLDQuMDdRMTE0LjY0LDM0NiwxMTMsMzU0LjY4Yy0xMCw1My0yLjIsOTUuMDcsMjIuNzUsMTA5LjQ5LDI1Ljc3LDE0Ljg5LDY5LS40MSwxMTEuMTQtMzcuMzFxNS00LjM4LDEwLTkuMjUsNi4zMiw2LjExLDEzLDExLjg2YzQwLjgsMzUuMTgsODEuMDksNDkuMzksMTA2LDM0LjkzLDI1Ljc1LTE0Ljk0LDM0LjEyLTYwLjE0LDIzLjI1LTExNS4xM3EtMS4yNS02LjMtMi44OC0xMi44Niw0LjU2LTEuMzUsOC45My0yLjc5YzU1LTE4LjI3LDkwLjgzLTQ3LjgxLDkwLjgzLTc4QzQ5NiwyMjYuNjIsNDYyLjUsMTk4LjYxLDQxMC42NiwxODAuNzJabS0xMjktODEuMDhjMzUuNDMtMzAuOTEsNjguNTUtNDMuMTEsODMuNjUtMzQuMzloMGMxNi4wNyw5LjI5LDIyLjMyLDQ2Ljc1LDEyLjIyLDk1Ljg4cS0xLDQuOC0yLjE2LDkuNTdhNDg3LjgzLDQ4Ny44MywwLDAsMC02NC4xOC0xMC4xNiw0ODEuMjcsNDgxLjI3LDAsMCwwLTQwLjU3LTUwLjc1UTI3NiwxMDQuNTcsMjgxLjY0LDk5LjY0Wk0xNTcuNzMsMjgwLjI1cTYuNTEsMTIuNiwxMy42MSwyNC44OSw3LjIzLDEyLjU0LDE1LjA3LDI0LjcxYTQzNS4yOCw0MzUuMjgsMCwwLDEtNDQuMjQtNy4xM0MxNDYuNDEsMzA5LDE1MS42MywyOTQuNzUsMTU3LjczLDI4MC4yNVptMC00OC4zM2MtNi0xNC4xOS0xMS4wOC0yOC4xNS0xNS4yNS00MS42MywxMy43LTMuMDcsMjguMy01LjU4LDQzLjUyLTcuNDhxLTcuNjUsMTEuOTQtMTQuNzIsMjQuMjNUMTU3LjcsMjMxLjkyWm0xMC45LDI0LjE3cTkuNDgtMTkuNzcsMjAuNDItMzguNzhoMHExMC45My0xOSwyMy4yNy0zNy4xM2MxNC4yOC0xLjA4LDI4LjkyLTEuNjUsNDMuNzEtMS42NXMyOS41Mi41Nyw0My43OSwxLjY2cTEyLjIxLDE4LjA5LDIzLjEzLDM3dDIwLjY5LDM4LjZRMzM0LDI3NS42MywzMjMsMjk0LjczaDBxLTEwLjkxLDE5LTIzLDM3LjI0Yy0xNC4yNSwxLTI5LDEuNTUtNDQsMS41NXMtMjkuNDctLjQ3LTQzLjQ2LTEuMzhxLTEyLjQzLTE4LjE5LTIzLjQ2LTM3LjI5VDE2OC42LDI1Ni4wOVpNMzQwLjc1LDMwNXE3LjI1LTEyLjU4LDEzLjkyLTI1LjQ5aDBhNDQwLjQxLDQ0MC40MSwwLDAsMSwxNi4xMiw0Mi4zMkE0MzQuNDQsNDM0LjQ0LDAsMCwxLDMyNiwzMjkuNDhRMzMzLjYyLDMxNy4zOSwzNDAuNzUsMzA1Wm0xMy43Mi03My4wN3EtNi42NC0xMi42NS0xMy44MS0yNWgwcS03LTEyLjE4LTE0LjU5LTI0LjA2YzE1LjMxLDEuOTQsMzAsNC41Miw0My43Nyw3LjY3QTQzOS44OSw0MzkuODksMCwwLDEsMzU0LjQ3LDIzMS45M1pNMjU2LjIzLDEyNC40OGgwYTQzOS43NSw0MzkuNzUsMCwwLDEsMjguMjUsMzQuMThxLTI4LjM1LTEuMzUtNTYuNzQsMEMyMzcuMDcsMTQ2LjMyLDI0Ni42MiwxMzQuODcsMjU2LjIzLDEyNC40OFpNMTQ1LjY2LDY1Ljg2YzE2LjA2LTkuMzIsNTEuNTcsNCw4OSwzNy4yNywyLjM5LDIuMTMsNC44LDQuMzYsNy4yLDYuNjdBNDkxLjM3LDQ5MS4zNywwLDAsMCwyMDEsMTYwLjUxYTQ5OS4xMiw0OTkuMTIsMCwwLDAtNjQuMDYsMTBxLTEuODMtNy4zNi0zLjMtMTQuODJoMEMxMjQuNTksMTA5LjQ2LDEzMC41OCw3NC42MSwxNDUuNjYsNjUuODZaTTEyMi4yNSwzMTcuNzFxLTYtMS43MS0xMS44NS0zLjcxYy0yMy40LTgtNDIuNzMtMTguNDQtNTYtMjkuODFDNDIuNTIsMjc0LDM2LjUsMjYzLjgzLDM2LjUsMjU1LjU5YzAtMTcuNTEsMjYuMDYtMzkuODUsNjkuNTItNTVxOC4xOS0yLjg1LDE2LjUyLTUuMjFhNDkzLjU0LDQ5My41NCwwLDAsMCwyMy40LDYwLjc1QTUwMi40Niw1MDIuNDYsMCwwLDAsMTIyLjI1LDMxNy43MVptMTExLjEzLDkzLjY3Yy0xOC42MywxNi4zMi0zNy4yOSwyNy44OS01My43NCwzMy43MmgwYy0xNC43OCw1LjIzLTI2LjU1LDUuMzgtMzMuNjYsMS4yNy0xNS4xNC04Ljc1LTIxLjQ0LTQyLjU0LTEyLjg1LTg3Ljg2cTEuNTMtOCwzLjUtMTZhNDgwLjg1LDQ4MC44NSwwLDAsMCw2NC42OSw5LjM5LDUwMS4yLDUwMS4yLDAsMCwwLDQxLjIsNTFDMjM5LjU0LDQwNS44MywyMzYuNDksNDA4LjY1LDIzMy4zOCw0MTEuMzhabTIzLjQyLTIzLjIyYy05LjcyLTEwLjUxLTE5LjQyLTIyLjE0LTI4Ljg4LTM0LjY0cTEzLjc5LjU0LDI4LjA4LjU0YzkuNzgsMCwxOS40Ni0uMjEsMjktLjY0QTQzOS4zMyw0MzkuMzMsMCwwLDEsMjU2LjgsMzg4LjE2Wm0xMjQuNTIsMjguNTljLTIuODYsMTUuNDQtOC42MSwyNS43NC0xNS43MiwyOS44Ni0xNS4xMyw4Ljc4LTQ3LjQ4LTIuNjMtODIuMzYtMzIuNzItNC0zLjQ0LTgtNy4xMy0xMi4wNy0xMWE0ODQuNTQsNDg0LjU0LDAsMCwwLDQwLjIzLTUxLjIsNDc3Ljg0LDQ3Ny44NCwwLDAsMCw2NS0xMC4wNXExLjQ3LDUuOTQsMi42LDExLjY0aDBDMzgzLjgxLDM3Ny41OCwzODQuNSwzOTkuNTYsMzgxLjMyLDQxNi43NVptMTcuNC0xMDIuNjRoMGMtMi42Mi44Ny01LjMyLDEuNzEtOC4wNiwyLjUzYTQ4My4yNiw0ODMuMjYsMCwwLDAtMjQuMzEtNjAuOTQsNDgxLjUyLDQ4MS41MiwwLDAsMCwyMy4zNi02MC4wNmM0LjkxLDEuNDMsOS42OCwyLjkzLDE0LjI3LDQuNTIsNDQuNDIsMTUuMzIsNzEuNTIsMzgsNzEuNTIsNTUuNDNDNDc1LjUsMjc0LjE5LDQ0Ni4yMywyOTguMzMsMzk4LjcyLDMxNC4xMVoiLz4KDTxwYXRoIGQ9Ik0yNTYsMjk4LjU1YTQzLDQzLDAsMSwwLTQyLjg2LTQzQTQyLjkxLDQyLjkxLDAsMCwwLDI1NiwyOTguNTVaIi8+Cg08L2c+Cg08L3N2Zz4="
|
|
4
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import { useCognitoAuthContext } from "@aws-northstar/ui";
|
|
4
|
+
import getBreadcrumbs from "@aws-northstar/ui/components/AppLayout/utils/getBreadcrumbs";
|
|
5
|
+
import NavHeader from "@aws-northstar/ui/components/AppLayout/components/NavHeader";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { createContext, useCallback, useEffect, useState } from "react";
|
|
8
|
+
import { NavItems } from "./navitems";
|
|
9
|
+
import Config from "../../config";
|
|
10
|
+
import Routes from "../Routes";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
BreadcrumbGroup,
|
|
14
|
+
BreadcrumbGroupProps,
|
|
15
|
+
SideNavigation,
|
|
16
|
+
} from "@cloudscape-design/components";
|
|
17
|
+
import AppLayout, {
|
|
18
|
+
AppLayoutProps,
|
|
19
|
+
} from "@cloudscape-design/components/app-layout";
|
|
20
|
+
import { useLocation, useNavigate } from "react-router-dom";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Context for updating/retrieving the AppLayout.
|
|
24
|
+
*/
|
|
25
|
+
export const AppLayoutContext = createContext({
|
|
26
|
+
appLayoutProps: {},
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
28
|
+
setAppLayoutProps: (_: AppLayoutProps) => {},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Defines the App layout and contains logic for routing.
|
|
33
|
+
*/
|
|
34
|
+
const App: React.FC = () => {
|
|
35
|
+
const [username, setUsername] = useState<string | undefined>();
|
|
36
|
+
const [email, setEmail] = useState<string | undefined>();
|
|
37
|
+
const { getAuthenticatedUser } = useCognitoAuthContext();
|
|
38
|
+
|
|
39
|
+
const navigate = useNavigate();
|
|
40
|
+
const [activeHref, setActiveHref] = useState("/");
|
|
41
|
+
const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
|
|
42
|
+
BreadcrumbGroupProps.Item[]
|
|
43
|
+
>([{ text: "/", href: "/" }]);
|
|
44
|
+
const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
|
|
45
|
+
const location = useLocation();
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const authUser = getAuthenticatedUser();
|
|
49
|
+
setUsername(authUser?.getUsername());
|
|
50
|
+
|
|
51
|
+
authUser?.getSession(() => {
|
|
52
|
+
authUser.getUserAttributes((_, attributes) => {
|
|
53
|
+
setEmail(attributes?.find((a) => a.Name === "email")?.Value);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}, [getAuthenticatedUser, setUsername, setEmail]);
|
|
57
|
+
|
|
58
|
+
const setAppLayoutPropsSafe = useCallback(
|
|
59
|
+
(props: AppLayoutProps) => {
|
|
60
|
+
JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
|
|
61
|
+
setAppLayoutProps(props);
|
|
62
|
+
},
|
|
63
|
+
[appLayoutProps],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
setActiveHref(location.pathname);
|
|
68
|
+
const breadcrumbs = getBreadcrumbs(location.pathname, location.search, "/");
|
|
69
|
+
setActiveBreadcrumbs(breadcrumbs);
|
|
70
|
+
}, [location]);
|
|
71
|
+
|
|
72
|
+
const onNavigate = useCallback(
|
|
73
|
+
(e: CustomEvent<{ href: string; external?: boolean }>) => {
|
|
74
|
+
if (!e.detail.external) {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
setAppLayoutPropsSafe({
|
|
77
|
+
contentType: undefined,
|
|
78
|
+
splitPanelOpen: false,
|
|
79
|
+
splitPanelSize: undefined,
|
|
80
|
+
splitPanelPreferences: undefined,
|
|
81
|
+
});
|
|
82
|
+
navigate(e.detail.href);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[navigate, setAppLayoutPropsSafe],
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<AppLayoutContext.Provider
|
|
90
|
+
value={{ appLayoutProps, setAppLayoutProps: setAppLayoutPropsSafe }}
|
|
91
|
+
>
|
|
92
|
+
<NavHeader
|
|
93
|
+
title={Config.applicationName}
|
|
94
|
+
logo={Config.logo}
|
|
95
|
+
user={
|
|
96
|
+
username
|
|
97
|
+
? {
|
|
98
|
+
username,
|
|
99
|
+
email,
|
|
100
|
+
}
|
|
101
|
+
: undefined
|
|
102
|
+
}
|
|
103
|
+
onSignout={() =>
|
|
104
|
+
new Promise(() => {
|
|
105
|
+
getAuthenticatedUser()?.signOut();
|
|
106
|
+
window.location.href = "/";
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
/>
|
|
110
|
+
<AppLayout
|
|
111
|
+
breadcrumbs={
|
|
112
|
+
<BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
|
|
113
|
+
}
|
|
114
|
+
toolsHide
|
|
115
|
+
navigation={
|
|
116
|
+
<SideNavigation
|
|
117
|
+
header={{ text: Config.applicationName, href: "/" }}
|
|
118
|
+
activeHref={activeHref}
|
|
119
|
+
onFollow={onNavigate}
|
|
120
|
+
items={NavItems}
|
|
121
|
+
/>
|
|
122
|
+
}
|
|
123
|
+
content={<Routes />}
|
|
124
|
+
splitPanelOpen={false}
|
|
125
|
+
splitPanelPreferences={{ position: 'bottom' }}
|
|
126
|
+
{...appLayoutProps}
|
|
127
|
+
/>
|
|
128
|
+
</AppLayoutContext.Provider>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export default App;
|