From cb42e5700356e33560433182ba7b9759cd670b81 Mon Sep 17 00:00:00 2001 From: James Talton Date: Wed, 1 Sep 2021 13:14:08 -0400 Subject: [PATCH] Webpack (#824) * initial webpack support Signed-off-by: James Talton * webpack work Signed-off-by: James Talton * fix Signed-off-by: James Talton * cleanup Signed-off-by: James Talton * fix Signed-off-by: James Talton * cleanup Signed-off-by: James Talton * work Signed-off-by: James Talton * fix Signed-off-by: James Talton * fixes Signed-off-by: James Talton * work Signed-off-by: James Talton * work Signed-off-by: James Talton * hot module replacement Signed-off-by: James Talton * proxies Signed-off-by: James Talton * types Signed-off-by: James Talton * tsconfig Signed-off-by: James Talton * fix Signed-off-by: James Talton * work Signed-off-by: James Talton * hot reload fix Signed-off-by: James Talton * update packages Signed-off-by: James Talton * fixes Signed-off-by: James Talton * fix Signed-off-by: James Talton * updates Signed-off-by: James Talton * work Signed-off-by: James Talton * webpack working Signed-off-by: James Talton * fix output directory Signed-off-by: James Talton * eslint fix Signed-off-by: James Talton * fix Signed-off-by: James Talton * fix Signed-off-by: James Talton * fixes Signed-off-by: James Talton * fix file serve Signed-off-by: James Talton * fix test Signed-off-by: James Talton * fix production paths Signed-off-by: James Talton * cleanup Signed-off-by: James Talton --- .gitignore | 1 - .npmrc | 1 + .../resources/package.json | 34 - .../resources/tsconfig.json | 8 - Dockerfile.prow | 30 +- backend/package.json | 25 +- backend/src/app.ts | 5 +- backend/src/lib/cors.ts | 6 +- backend/src/lib/main.ts | 5 +- backend/src/lib/request-retry.ts | 6 + backend/src/routes/serve.ts | 80 +- frontend/babel.config.json | 4 + frontend/jest.config.js | 12 +- frontend/package.json | 154 +- frontend/public/index.html | 2 +- frontend/src/atoms.tsx | 4 +- frontend/src/components/AcmDataForm.tsx | 33 +- frontend/src/components/BulkActionModel.tsx | 2 +- .../src/components/DropdownActionModal.tsx | 2 +- frontend/src/components/ErrorPage.tsx | 2 +- frontend/src/components/Rbac.tsx | 2 +- frontend/src/{css.mock.js => file.mock.js} | 4 +- frontend/src/index.tsx | 1 + frontend/src/lib/bare-metal-assets.ts | 8 +- frontend/src/lib/create-cluster.ts | 2 +- frontend/src/lib/delete-cluster.ts | 2 +- frontend/src/lib/delete-resources.ts | 2 +- frontend/src/lib/delete-submariner.ts | 8 +- frontend/src/lib/import-cluster.ts | 6 +- frontend/src/lib/nock-util.ts | 4 +- frontend/src/lib/patch-cluster.ts | 2 +- frontend/src/lib/rbac-util.ts | 2 +- frontend/src/lib/search.ts | 2 +- frontend/src/lib/test-metadata.ts | 2 +- frontend/src/lib/useQuery.tsx | 4 +- .../src/resources}/agent-cluster-install.ts | 0 .../src => frontend/src/resources}/agent.ts | 0 .../src/resources}/ansible-job.ts | 0 .../src/resources}/bare-metal-asset.ts | 0 .../certificate-signing-requests.ts | 0 .../src/resources}/cluster-claim.ts | 3 +- .../src/resources}/cluster-curator.ts | 3 +- .../src/resources}/cluster-deployment.ts | 4 +- .../src/resources}/cluster-image-set.ts | 0 .../resources}/cluster-management-add-on.ts | 0 .../src/resources}/cluster-pool.ts | 4 +- .../src/resources}/cluster-provision.ts | 0 .../src/resources}/configmap.ts | 0 .../src/resources}/discovered-cluster.ts | 0 .../src/resources}/discovery-config.ts | 0 .../src/resources}/feature-gate.ts | 0 .../src => frontend/src/resources}/index.ts | 0 .../src/resources}/infra-environment.ts | 0 .../src/resources}/install-config.ts | 0 .../resources}/klusterlet-add-on-config.ts | 0 .../src/resources}/machine-pool.ts | 0 .../src/resources}/managed-cluster-add-on.ts | 2 +- .../src/resources}/managed-cluster-info.ts | 4 +- .../resources}/managed-cluster-set-binding.ts | 0 .../src/resources}/managed-cluster-set.ts | 2 +- .../src/resources}/managed-cluster.tsx | 4 +- .../src/resources}/managedclusteraction.ts | 0 .../src/resources}/multi-cluster-hub.ts | 0 .../src/resources}/namespace.ts | 0 .../src => frontend/src/resources}/pod.ts | 0 .../src/resources}/policy-report.ts | 2 +- .../src => frontend/src/resources}/project.ts | 0 .../src/resources}/provider-connection.ts | 0 .../src => frontend/src/resources}/rbac.ts | 0 .../src/resources}/resource.ts | 2 +- .../src => frontend/src/resources}/secret.tsx | 0 .../resources}/self-subject-access-review.ts | 0 .../src => frontend/src/resources}/status.ts | 0 .../src/resources}/submariner-config.ts | 0 .../src/resources}/utils/get-addons.ts | 0 .../src/resources}/utils/get-cluster.test.ts | 0 .../src/resources}/utils/get-cluster.ts | 2 +- .../src/resources}/utils/index.ts | 0 .../src/resources}/utils/resource-request.ts | 3 +- .../src/resources}/utils/utils.ts | 0 .../routes/Credentials/Credentials.test.tsx | 2 +- .../src/routes/Credentials/Credentials.tsx | 8 +- .../Credentials/CredentialsForm.test.tsx | 2 +- .../routes/Credentials/CredentialsForm.tsx | 2 +- .../Automations/AnsibleAutomations.test.tsx | 2 +- .../Automations/AnsibleAutomations.tsx | 3 +- .../AnsibleAutomationsForm.test.tsx | 4 +- .../Automations/AnsibleAutomationsForm.tsx | 2 +- .../BareMetalAssets/BareMetalAsset.test.tsx | 2 +- .../BareMetalAssets/BareMetalAssetsPage.tsx | 2 +- .../CreateBareMetalAsset.test.tsx | 2 +- .../BareMetalAssets/CreateBareMetalAsset.tsx | 2 +- .../ClusterPools/ClusterPools.test.tsx | 2 +- .../Clusters/ClusterPools/ClusterPools.tsx | 3 +- .../CreateClusterPool.test.tsx | 2 +- .../controlData/ControlData.js | 3 + .../components/ClusterClaimModal.tsx | 2 +- .../components/ScaleClusterPoolModal.tsx | 2 +- .../components/UpdateReleaseImageModal.tsx | 2 +- .../ClusterSetAccessManagement.tsx | 2 +- .../ClusterSetClusterPools.tsx | 2 +- .../ClusterSetClusters/ClusterSetClusters.tsx | 2 +- .../ClusterSetDetails.test.tsx | 2 +- .../ClusterSetDetails/ClusterSetDetails.tsx | 2 +- .../InstallSubmarinerForm.tsx | 2 +- .../ClusterSetManageResources.test.tsx | 2 +- .../ClusterSetManageResources.tsx | 2 +- .../ClusterSetOverview/ClusterSetOverview.tsx | 2 +- .../ClusterSetSubmariner.tsx | 2 +- .../Clusters/ClusterSets/ClusterSets.tsx | 3 +- .../CreateClusterSetModal.tsx | 2 +- .../ClusterSetActionDropdown.test.tsx | 2 +- .../components/ClusterSetActionDropdown.tsx | 2 +- .../components/ClusterStatuses.tsx | 2 +- .../components/EditSubmarinerConfigModal.tsx | 2 +- .../ManagedClusterSetBindingModal.tsx | 2 +- .../components/MultiClusterNetworkStatus.tsx | 2 +- .../components/useCanJoinClusterSets.tsx | 2 +- .../ClusterSets/components/useClusters.tsx | 2 +- .../DiscoveredClusters/DiscoveredClusters.tsx | 11 +- .../DiscoveryComponents/test-utils.tsx | 2 +- .../DiscoveryConfig/DiscoveryConfig.tsx | 3 +- .../ClusterDetails/ClusterDetails.test.tsx | 2 +- .../ClusterDetails/ClusterDetails.tsx | 2 +- .../ClusterMachinePools.test.tsx | 2 +- .../ClusterMachinePools.tsx | 2 +- .../components/ScaleMachinePoolModal.tsx | 2 +- .../ClusterNodes/ClusterNodes.tsx | 2 +- .../ClusterOverview/ClusterOverview.tsx | 2 +- .../ClusterSettings/ClusterSettings.tsx | 2 +- .../CreateCluster/CreateCluster.test.tsx | 15 +- .../CreateCluster/CreateCluster.tsx | 8 +- .../WrappedImportBareMetalAssetsButton.js | 3 +- .../assisted-installer/DetailsForm.tsx | 2 +- .../assisted-installer/NetworkForm.tsx | 2 +- .../CreateCluster/controlData/ControlData.js | 3 + .../controlData/ControlDataAI.js | 1 + .../controlData/ControlDataAWS.js | 2 + .../controlData/ControlDataAZR.js | 2 + .../controlData/ControlDataBMC.js | 5 +- .../controlData/ControlDataGCP.js | 2 + .../controlData/ControlDataHelpers.js | 6 +- .../controlData/ControlDataOST.js | 2 + .../controlData/ControlDataVMW.js | 2 + .../CreateCluster/controlData/Logos.js | 3 + .../ImportCluster/ImportCluster.test.tsx | 2 +- .../ImportCluster/ImportCluster.tsx | 4 +- .../ManagedClusters/ManagedClusters.test.tsx | 2 +- .../ManagedClusters/ManagedClusters.tsx | 23 +- .../ManagedClusters/components/AddCluster.tsx | 2 +- .../BatchChannelSelectModal.test.tsx | 2 +- .../components/BatchChannelSelectModal.tsx | 2 +- .../components/BatchUpgradeModal.test.tsx | 2 +- .../components/BatchUpgradeModal.tsx | 2 +- .../components/ClusterActionDropdown.test.tsx | 2 +- .../components/ClusterActionDropdown.tsx | 4 +- .../components/ClusterDestroy.test.tsx | 2 +- .../components/ClusterDestroy.tsx | 2 +- .../components/ClusterPolicySidebar.test.tsx | 2 +- .../components/ClusterPolicySidebar.tsx | 2 +- ...Icons.js => ClusterPolicySidebarIcons.tsx} | 0 .../components/ClusterStatusMessageAlert.tsx | 2 +- .../components/DistributionField.test.tsx | 2 +- .../components/DistributionField.tsx | 2 +- .../DownloadConfigurationDropdown.old.tsx | 2 +- .../DownloadConfigurationDropdown.tsx | 2 +- .../components/EditLabels.test.tsx | 2 +- .../ManagedClusters/components/EditLabels.tsx | 2 +- .../components/HiveNotification.test.tsx | 2 +- .../components/HiveNotification.tsx | 9 +- .../components/ImportCommand.test.tsx | 2 +- .../components/ImportCommand.tsx | 2 +- .../components/LoginCredentials.test.tsx | 18 +- .../components/LoginCredentials.tsx | 2 +- .../components/ProgressStepBar.test.tsx | 2 +- .../components/ProgressStepBar.tsx | 2 +- .../components/ScaleClusterAlert.tsx | 2 +- .../components/StatusField.tsx | 2 +- .../components/StatusSummaryCount.test.tsx | 2 +- .../cim/CusterDeploymentCredentials.tsx | 2 +- .../components/cim/EditAICluster.tsx | 2 +- .../components/useAllClusters.tsx | 2 +- .../InfraEnvironments/CreateInfraEnv.tsx | 2 +- .../Details/InfraEnvironmentDetailsPage.tsx | 2 +- .../InfraEnvironmentsPage.tsx | 2 +- frontend/src/setupTests.ts | 8 + frontend/src/typings.d.ts | 1 + frontend/tsconfig.dev.json | 6 + frontend/tsconfig.json | 2 +- frontend/webpack.config.ts | 139 + frontend/webpack.tsconfig.json | 7 + package.json | 46 +- tsconfig.json | 16 +- util/copyright-check.ts | 39 +- util/copyright-fix.ts | 45 +- yarn.lock | 8683 +++++------------ 196 files changed, 2980 insertions(+), 6820 deletions(-) create mode 100644 .npmrc delete mode 100644 @open-cluster-management/resources/package.json delete mode 100644 @open-cluster-management/resources/tsconfig.json create mode 100644 frontend/babel.config.json rename frontend/src/{css.mock.js => file.mock.js} (67%) rename {@open-cluster-management/resources/src => frontend/src/resources}/agent-cluster-install.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/agent.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/ansible-job.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/bare-metal-asset.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/certificate-signing-requests.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-claim.ts (79%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-curator.ts (95%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-deployment.ts (95%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-image-set.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-management-add-on.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-pool.ts (91%) rename {@open-cluster-management/resources/src => frontend/src/resources}/cluster-provision.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/configmap.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/discovered-cluster.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/discovery-config.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/feature-gate.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/index.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/infra-environment.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/install-config.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/klusterlet-add-on-config.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/machine-pool.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managed-cluster-add-on.ts (93%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managed-cluster-info.ts (94%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managed-cluster-set-binding.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managed-cluster-set.ts (94%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managed-cluster.tsx (92%) rename {@open-cluster-management/resources/src => frontend/src/resources}/managedclusteraction.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/multi-cluster-hub.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/namespace.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/pod.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/policy-report.ts (89%) rename {@open-cluster-management/resources/src => frontend/src/resources}/project.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/provider-connection.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/rbac.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/resource.ts (96%) rename {@open-cluster-management/resources/src => frontend/src/resources}/secret.tsx (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/self-subject-access-review.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/status.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/submariner-config.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/get-addons.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/get-cluster.test.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/get-cluster.ts (99%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/index.ts (100%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/resource-request.ts (99%) rename {@open-cluster-management/resources/src => frontend/src/resources}/utils/utils.ts (100%) rename frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/{ClusterPolicySidebarIcons.js => ClusterPolicySidebarIcons.tsx} (100%) create mode 100644 frontend/tsconfig.dev.json create mode 100644 frontend/webpack.config.ts create mode 100644 frontend/webpack.tsconfig.json diff --git a/.gitignore b/.gitignore index abb1d573786..a9d5eac339a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ **/certs/ **/node_modules/ **/coverage/ -**/lib/ **/dist/ **/build/ **/.eslintcache diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..d1cdf2f06be --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict = true \ No newline at end of file diff --git a/@open-cluster-management/resources/package.json b/@open-cluster-management/resources/package.json deleted file mode 100644 index 1509767e8eb..00000000000 --- a/@open-cluster-management/resources/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@open-cluster-management/resources", - "version": "1.0.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "private": "true", - "files": [ - "lib", - "src" - ], - "scripts": { - "build": "tsc", - "watch": "tsc --watch --preserveWatchOutput", - "test": "tsc --noEmit", - "lint": "echo no lint", - "check": "prettier --check src", - "check:fix": "prettier --write src" - }, - "devDependencies": { - "@kubernetes/client-node": "^0.15.0", - "@types/node": "^16.4.5", - "prettier": "^2.3.2", - "typescript": "4.3.5" - }, - "dependencies": { - "openshift-assisted-ui-lib": "1.5.32" - }, - "prettier": { - "printWidth": 120, - "tabWidth": 4, - "semi": false, - "singleQuote": true - } -} diff --git a/@open-cluster-management/resources/tsconfig.json b/@open-cluster-management/resources/tsconfig.json deleted file mode 100644 index 5b2918cde15..00000000000 --- a/@open-cluster-management/resources/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src" - }, - "include": ["src/**/*"] -} diff --git a/Dockerfile.prow b/Dockerfile.prow index aeecbbb3ebe..e8aef7dadbf 100644 --- a/Dockerfile.prow +++ b/Dockerfile.prow @@ -1,19 +1,33 @@ # Copyright Contributors to the Open Cluster Management project - -FROM registry.ci.openshift.org/open-cluster-management/builder:nodejs14-linux as builder +FROM registry.ci.openshift.org/open-cluster-management/builder:nodejs14-linux as packages WORKDIR /app -COPY . . +COPY package.json yarn.lock ./ +COPY ./backend/package.json /app/backend/package.json +COPY ./frontend/package.json /app/frontend/package.json + +FROM packages as builder RUN yarn install --frozen-lockfile --ignore-optional + +FROM packages as production +RUN yarn install --production --frozen-lockfile --ignore-optional + +FROM builder as backend +COPY ./backend ./backend +WORKDIR /app/backend +RUN yarn run build + +FROM builder as frontend +COPY ./frontend ./frontend +WORKDIR /app/frontend RUN yarn run build -RUN rm -rf node_modules && yarn install --frozen-lockfile --production --ignore-optional FROM registry.access.redhat.com/ubi8/ubi-minimal COPY --from=builder /usr/bin/node /usr/bin/node WORKDIR /app ENV NODE_ENV production -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/backend/node_modules ./backend/node_modules -COPY --from=builder /app/backend/build ./backend -COPY --from=builder /app/frontend/build ./public +COPY --from=production /app/node_modules ./node_modules +COPY --from=production /app/backend/node_modules ./backend/node_modules +COPY --from=backend /app/backend/build ./backend +COPY --from=frontend /app/frontend/build ./public USER 1001 CMD ["node", "backend/lib/main.js"] diff --git a/backend/package.json b/backend/package.json index 1a7aa717605..243330cb9d9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,8 +2,13 @@ "name": "@open-cluster-management/console-backend", "version": "0.0.1", "private": true, + "engines": { + "npm": "please-use-yarn", + "yarn": ">= 1.17.3", + "node": ">= 14" + }, "scripts": { - "watch": "yarn run start", + "watch": "echo", "postinstall": "[ ! -d ./certs ] && yarn run generate-certs || true", "build": "tsc --sourceMap false --declaration false", "clean": "rm -rf coverage build", @@ -28,21 +33,21 @@ "devDependencies": { "@types/dotenv": "^8.2.0", "@types/eslint": "^7.28.0", - "@types/jest": "^26.0.24", - "@types/node": "^16.4.3", + "@types/jest": "^27.0.0", + "@types/node": "^16.6.0", "@types/node-fetch": "^2.5.12", - "@types/pino": "^6.3.10", + "@types/pino": "^6.3.11", "@types/prettier": "^2.3.2", "@types/raw-body": "^2.3.0", - "@typescript-eslint/eslint-plugin": "^4.28.5", - "@typescript-eslint/parser": "^4.28.5", - "eslint": "^7.31.0", - "jest": "^26.x.x", + "@typescript-eslint/eslint-plugin": "^4.29.1", + "@typescript-eslint/parser": "^4.29.1", + "eslint": "^7.32.0", + "jest": "^27.x.x", "nock": "^13.1.1", "pino-zen": "^1.0.20", "prettier": "^2.3.2", - "ts-jest": "^26.x.x", - "ts-node": "^10.1.0", + "ts-jest": "^27.x.x", + "ts-node": "^10.2.0", "ts-node-dev": "^1.1.8", "typescript": "^4.3.5" }, diff --git a/backend/src/app.ts b/backend/src/app.ts index e60de878b05..f95f49d6a9f 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -38,12 +38,12 @@ router.get(`/logout/`, logout) router.get(`/events`, events) router.post(`/proxy/search`, search) router.get(`/authenticated`, authenticated) -router.get(`/*`, serve) router.post(`/ansibletower`, ansibleTower) +router.get(`/*`, serve) export async function requestHandler(req: Http2ServerRequest, res: Http2ServerResponse): Promise { if (process.env.NODE_ENV !== 'production') { - cors(req, res) + if (cors(req, res)) return await delay(req, res) } @@ -76,6 +76,7 @@ export function start(): Promise { export async function stop(): Promise { if (process.env.NODE_ENV === 'development') { setTimeout(() => { + logger.warn('process stop timeout. exiting...') process.exit(1) }, 0.5 * 1000).unref() } diff --git a/backend/src/lib/cors.ts b/backend/src/lib/cors.ts index 987c6b0a368..26736450b57 100644 --- a/backend/src/lib/cors.ts +++ b/backend/src/lib/cors.ts @@ -3,7 +3,7 @@ import { Http2ServerRequest, Http2ServerResponse } from 'http2' -export function cors(req: Http2ServerRequest, res: Http2ServerResponse): void { +export function cors(req: Http2ServerRequest, res: Http2ServerResponse): boolean { if (process.env.NODE_ENV !== 'production') { if (req.headers['origin']) { res.setHeader('Access-Control-Allow-Origin', req.headers['origin']) @@ -18,7 +18,9 @@ export function cors(req: Http2ServerRequest, res: Http2ServerResponse): void { if (req.headers['access-control-request-headers']) { res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']) } - return res.writeHead(200).end() + res.writeHead(200).end() + return true } } + return false } diff --git a/backend/src/lib/main.ts b/backend/src/lib/main.ts index 6b292589d73..9e6eba475d4 100644 --- a/backend/src/lib/main.ts +++ b/backend/src/lib/main.ts @@ -40,8 +40,9 @@ process.on('SIGTERM', () => { }) process.on('uncaughtException', (err) => { - logger.error({ msg: `process uncaughtException`, error: err.message }) - console.log(err.stack) + // console.error(err) + // logger.error({ msg: `process uncaughtException`, error: err.message }) + // console.log(err.stack) }) process.on('multipleResolves', (type, _promise, reason) => { diff --git a/backend/src/lib/request-retry.ts b/backend/src/lib/request-retry.ts index 799789e28db..4571fd382fa 100644 --- a/backend/src/lib/request-retry.ts +++ b/backend/src/lib/request-retry.ts @@ -107,6 +107,12 @@ export function requestRetry(options: { options.onResponse(response) } }) + .on('error', (err) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any + if ((err as any).code !== 'ABORT_ERR') { + throw err + } + }) .on('timeout', () => { // Emitted when the underlying socket times out from inactivity. // This only notifies that the socket has been idle. diff --git a/backend/src/routes/serve.ts b/backend/src/routes/serve.ts index 46d42bd935a..02bc3844d3d 100644 --- a/backend/src/routes/serve.ts +++ b/backend/src/routes/serve.ts @@ -1,15 +1,14 @@ /* Copyright Contributors to the Open Cluster Management project */ -import { createReadStream } from 'fs' +import { createReadStream, Stats } from 'fs' +import { stat } from 'fs/promises' import { constants, Http2ServerRequest, Http2ServerResponse } from 'http2' import { extname } from 'path' import { pipeline } from 'stream' -import { parseCookies } from '../lib/cookies' import { logger } from '../lib/logger' -import { redirect } from '../lib/respond' const cacheControl = process.env.NODE_ENV === 'production' ? 'public, max-age=604800' : 'no-store' -export function serve(req: Http2ServerRequest, res: Http2ServerResponse): void { +export async function serve(req: Http2ServerRequest, res: Http2ServerResponse): Promise { try { let url = req.url @@ -41,15 +40,50 @@ export function serve(req: Http2ServerRequest, res: Http2ServerResponse): void { logger.debug('unknown content type', `ext=${ext}`) return res.writeHead(404).end() } + + const filePath = './public' + url + let stats: Stats + try { + stats = await stat(filePath) + } catch { + return res.writeHead(404).end() + } + + if (/\bbr\b/.test(acceptEncoding)) { + try { + const brStats = await stat(filePath + '.br') + const readStream = createReadStream('./public' + url + '.br', { autoClose: true }) + readStream + .on('open', () => { + res.writeHead(200, { + [constants.HTTP2_HEADER_CONTENT_ENCODING]: 'br', + [constants.HTTP2_HEADER_CONTENT_TYPE]: contentType, + [constants.HTTP2_HEADER_CONTENT_LENGTH]: brStats.size.toString(), + }) + }) + .on('error', (err) => { + // logger.error(err) + res.writeHead(404).end() + }) + pipeline(readStream, res as unknown as NodeJS.WritableStream, (err) => { + // if (err) logger.error(err) + }) + return + } catch { + // Do nothing + } + } + if (/\bgzip\b/.test(acceptEncoding)) { try { + const gzStats = await stat(filePath + '.gz') const readStream = createReadStream('./public' + url + '.gz', { autoClose: true }) readStream .on('open', () => { res.writeHead(200, { [constants.HTTP2_HEADER_CONTENT_ENCODING]: 'gzip', [constants.HTTP2_HEADER_CONTENT_TYPE]: contentType, - // [constants.HTTP2_HEADER_CONTENT_LENGTH]: stats.size.toString(), + [constants.HTTP2_HEADER_CONTENT_LENGTH]: gzStats.size.toString(), }) }) .on('error', (err) => { @@ -59,27 +93,27 @@ export function serve(req: Http2ServerRequest, res: Http2ServerResponse): void { pipeline(readStream, res as unknown as NodeJS.WritableStream, (err) => { // if (err) logger.error(err) }) - } catch (err) { - logger.error(err) - return res.writeHead(404).end() + return + } catch { + // Do nothing } - } else { - const readStream = createReadStream('./public' + url, { autoClose: true }) - readStream - .on('open', () => { - res.writeHead(200, { - [constants.HTTP2_HEADER_CONTENT_TYPE]: contentType, - }) - }) - .on('error', (err) => { - // logger.error(err) - res.writeHead(404).end() + } + + const readStream = createReadStream('./public' + url, { autoClose: true }) + readStream + .on('open', () => { + res.writeHead(200, { + [constants.HTTP2_HEADER_CONTENT_TYPE]: contentType, + [constants.HTTP2_HEADER_CONTENT_LENGTH]: stats.size.toString(), }) - pipeline(readStream, res as unknown as NodeJS.WritableStream, (err) => { - // if (err) logger.error(err) }) - } - return + .on('error', (err) => { + // logger.error(err) + res.writeHead(404).end() + }) + pipeline(readStream, res as unknown as NodeJS.WritableStream, (err) => { + // if (err) logger.error(err) + }) } catch (err) { logger.error(err) return res.writeHead(404).end() diff --git a/frontend/babel.config.json b/frontend/babel.config.json new file mode 100644 index 00000000000..b08e4535bf6 --- /dev/null +++ b/frontend/babel.config.json @@ -0,0 +1,4 @@ +// https://babeljs.io/docs/en/configuration +{ + "presets": ["@babel/env", "@babel/react", "@babel/preset-typescript"] +} diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 240a346a125..c392d8bb327 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -3,13 +3,21 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'jsdom', + automock: false, rootDir: './src', testResultsProcessor: 'jest-sonar-reporter', setupFilesAfterEnv: ['/setupTests.ts'], moduleNameMapper: { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/css.mock.js', - '\\.(css|less)$': '/css.mock.js', + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/file.mock.js', + '\\.(css|less)$': 'identity-obj-proxy', + 'monaco-editor': '/../../node_modules/react-monaco-editor', }, watchPathIgnorePatterns: ['/../node_modules', '/../.eslintcache', '/../coverage'], moduleFileExtensions: ['js', 'json', 'jsx', 'node', 'ts', 'tsx'], + transform: { + '^.+\\.jsx?$': 'babel-jest', + '^.+\\.hbs$': 'jest-raw-loader', + '\\.(css|less)$': 'jest-raw-loader', + }, + coverageReporters: ['text', 'text-summary', 'html', 'lcov'], } diff --git a/frontend/package.json b/frontend/package.json index cab9d5178ed..89f3c22766d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,85 +2,135 @@ "name": "@open-cluster-management/console-frontend", "version": "0.0.1", "private": true, - "homepage": "/multicloud/", - "proxy": "https://localhost:4000", + "engines": { + "npm": "please-use-yarn", + "yarn": ">= 1.17.3", + "node": ">= 14" + }, + "scripts": { + "start": "TS_NODE_PROJECT=webpack.tsconfig.json webpack serve --mode development --stats-children", + "build": "TS_NODE_PROJECT=webpack.tsconfig.json webpack --mode production", + "watch": "echo", + "test": "jest --runInBand", + "lint": "eslint src --ext .ts,.tsx --max-warnings=0", + "lint:fix": "eslint src --ext .ts,.tsx --fix", + "check": "prettier --check src", + "check:fix": "prettier --write src", + "update": "rm -rf package-lock.json node_modules && npx npm-check-updates -u -t minor && yarn install && yarn audit fix && npm dedup && yarn test && yarn run lint:fix && yarn run lint && yarn run check:fix", + "clean": "rm -rf coverage build" + }, "devDependencies": { - "@kubernetes/client-node": "^0.15.0", - "@open-cluster-management/resources": "^1.0.0", - "@open-cluster-management/ui-components": "^1.3.0", + "@babel/core": "^7.15.0", + "@babel/preset-env": "^7.15.0", + "@babel/preset-react": "^7.14.5", + "@babel/preset-typescript": "^7.15.0", + "@kubernetes/client-node": "^0.15.1", + "@open-cluster-management/ui-components": "^1.4.0", "@patternfly/react-code-editor": "^4.1.25", "@patternfly/react-core": "^4.135.5", - "@patternfly/react-table": "^4.29.5", "@patternfly/react-icons": "^4.10.11", + "@patternfly/react-table": "^4.29.5", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.0-rc.3", "@redhat-cloud-services/rule-components": "^3.2.1", "@reduxjs/toolkit": "1.5.x", "@sentry/browser": "5.19.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", - "@types/get-value": "^3.0.1", - "@types/jest": "^26.0.23", - "@types/lodash": "^4.14.170", - "@types/node": "^14.17.4", - "@types/react": "^17.0.13", - "@types/react-dom": "^17.0.8", - "@types/react-router-dom": "^5.1.7", + "@types/compression-webpack-plugin": "^6.0.6", + "@types/copy-webpack-plugin": "^8.0.1", + "@types/css-minimizer-webpack-plugin": "^3.0.2", + "@types/get-value": "^3.0.2", + "@types/jest": "^27.0.0", + "@types/lodash": "^4.14.172", + "@types/mini-css-extract-plugin": "^2.2.0", + "@types/node": "^16.6.0", + "@types/react": "^17.0.17", + "@types/react-dom": "^17.0.9", + "@types/react-router-dom": "^5.1.8", + "@types/testing-library__jest-dom": "^5.14.1", + "@types/validator": "^13.6.3", + "@types/webpack-dev-server": "^4.0.0", "axios": "^0.19.2", - "babel-jest": "^26.6.3", + "babel-jest": "^27.0.6", + "babel-loader": "^8.2.2", + "browserify-fs": "^1.0.0", + "buffer": "^6.0.3", + "bundle-loader": "^0.5.6", + "compression-webpack-plugin": "^8.0.1", + "copy-webpack-plugin": "^9.0.1", + "crypto-browserify": "^3.12.0", + "css-loader": "^6.2.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "eslint-plugin-jest": "^24.4.0", "eslint-plugin-react": "^7.24.0", + "eslint-plugin-react-hooks": "^4.2.0", + "file-loader": "^6.2.0", "handlebars": "^4.7.7", + "handlebars-loader": "^1.7.1", + "html-webpack-plugin": "^5.3.2", "i18next": "^20.3.2", "i18next-browser-languagedetector": "^6.1.2", "i18next-http-backend": "^1.2.6", - "jest-environment-jsdom-sixteen": "^1.0.3", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.0.6", + "jest-fetch-mock": "^3.0.3", "jest-raw-loader": "1.0.1", "jest-sonar-reporter": "^2.0.0", "jest-watch-typeahead": "^0.6.4", + "json-loader": "^0.5.7", "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.2.1", "moment": "^2.29.1", "monaco-editor": "^0.25.2", "monaco-editor-webpack-plugin": "^4.0.0", "nock": "^13.1.1", + "node-util": "^0.0.1", "openshift-assisted-ui-lib": "1.5.32", + "path-browserify": "^1.0.1", "prettier": "^2.3.2", + "process": "^0.11.10", "raw-loader": "^4.0.2", "react": "^17.0.2", - "react-app-rewired": "^2.1.8", "react-dom": "^17.0.2", + "react-hot-loader": "^4.13.0", "react-i18next": "^11.11.1", "react-monaco-editor": "0.36.0", "react-redux": "^7.2.0", + "react-refresh": "^0.10.0", + "react-refresh-typescript": "^2.0.2", "react-router-dom": "^5.2.0", - "react-scripts": "4.0.3", "react-tagsinput": "3.19.x", "recoil": "^0.3.1", "redux": "^4.0.5", "redux-thunk": "^2.3.0", "reselect": "^4.0.0", + "stream-browserify": "^3.0.0", + "style-loader": "^3.2.1", "swr": "^0.5.6", "temptifly": "^0.4.8", - "ts-jest": "^26.5.6", - "typescript": "^4.2.4", + "ts-import-plugin": "^1.6.7", + "ts-jest": "^27.0.4", + "ts-loader": "^9.2.5", + "tsconfig-paths": "^3.10.1", + "type-fest": "^2.1.0", + "typescript": "^4.3.5", "uuid": "8.1.0", + "v8-compile-cache": "^2.3.0", + "validator": "^13.6.0", + "webpack": "^5.51.1", + "webpack-cli": "^4.8.0", + "webpack-dev-server": "^4.0.0", + "whatwg-fetch": "^3.6.2", "yaml": "^1.10.2", "yup": "^0.28.3" }, - "scripts": { - "watch": "yarn run start", - "start": "react-app-rewired start", - "build": "react-app-rewired --max_old_space_size=8192 build && cd build && gzip * -k -r --best", - "test": "react-app-rewired test --all --watchAll=false --ci --runInBand --coverage --reporters=default --coverageReporters=lcov --coverageReporters=html --coverageReporters=text --coverageReporters=text-summary --collectCoverageFrom=!**/*.d.ts --env=jest-environment-jsdom-sixteen --testResultsProcessor jest-sonar-reporter", - "test:watch": "react-app-rewired test", - "lint": "eslint src --ext .ts,.tsx --max-warnings=0", - "lint:fix": "eslint src --ext .ts,.tsx --fix", - "check": "prettier --check src", - "check:fix": "prettier --write src", - "update": "rm -rf package-lock.json node_modules && npx npm-check-updates -u -t minor && yarn install && yarn audit fix && npm dedup && yarn test && yarn run lint:fix && yarn run lint && yarn run check:fix", - "clean": "rm -rf coverage build" - }, "eslintConfig": { + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json" + }, "extends": [ - "react-app", "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jest/recommended" @@ -88,12 +138,9 @@ "plugins": [ "react", "@typescript-eslint", - "jest" + "jest", + "react-hooks" ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "./tsconfig.json" - }, "rules": { "@typescript-eslint/no-non-null-assertion": "off", "react/react-in-jsx-scope": "off", @@ -136,34 +183,6 @@ "last 1 safari version" ] }, - "jest": { - "collectCoverageFrom": [ - "src/**/*.{ts,tsx}", - "!src/**/*.d.ts", - "!/node_modules/" - ], - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coverageReporters": [ - "text", - "text-summary", - "html", - "lcov" - ], - "moduleNameMapper": { - "monaco-editor": "/../node_modules/react-monaco-editor" - }, - "watchPathIgnorePatterns": [ - "node_modules", - "coverage" - ] - }, "prettier": { "printWidth": 120, "tabWidth": 4, @@ -171,7 +190,6 @@ "singleQuote": true }, "dependencies": { - "@types/validator": "^13.6.3", - "validator": "^13.6.0" + "@types/js-yaml": "^4.0.3" } } diff --git a/frontend/public/index.html b/frontend/public/index.html index e4f9cb693e5..0a64617c72e 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -4,7 +4,7 @@ - + Red Hat Advanced Cluster Management for Kubernetes