From 430cecc954ec732a51a579f4e6c17cd32756a374 Mon Sep 17 00:00:00 2001 From: Oksamies Date: Wed, 13 Nov 2024 23:04:16 +0200 Subject: [PATCH] Add beta-switch package --- apps/cyberstorm-remix/app/root.tsx | 26 +++ .../cyberstorm/navigation/Navigation.tsx | 1 + .../cyberstorm-static/scripts/beta-switch.js | 74 ++++++++ packages/beta-switch/.gitignore | 3 + packages/beta-switch/README.md | 8 + packages/beta-switch/package.json | 16 ++ packages/beta-switch/src/index.ts | 88 +++++++++ packages/beta-switch/tsconfig.json | 29 +++ tools/ts-dev-proxy/nginx.conf | 176 +++++------------- 9 files changed, 288 insertions(+), 133 deletions(-) create mode 100644 apps/cyberstorm-remix/public/cyberstorm-static/scripts/beta-switch.js create mode 100644 packages/beta-switch/.gitignore create mode 100644 packages/beta-switch/README.md create mode 100644 packages/beta-switch/package.json create mode 100644 packages/beta-switch/src/index.ts create mode 100644 packages/beta-switch/tsconfig.json diff --git a/apps/cyberstorm-remix/app/root.tsx b/apps/cyberstorm-remix/app/root.tsx index e51f376c2..04dc1e8ab 100644 --- a/apps/cyberstorm-remix/app/root.tsx +++ b/apps/cyberstorm-remix/app/root.tsx @@ -231,6 +231,7 @@ function Root() { {shouldShowAds ? : null} + ); @@ -357,3 +358,28 @@ function AdsInit() { return <>; } + +// Temporary solution for adding the beta button +// REMIX TODO: Move to dynamic html +function BetaButtonInit() { + const isHydrated = useHydrated(); + const startsHydrated = useRef(isHydrated); + + // This will be loaded 2 times in development because of: + // https://react.dev/reference/react/StrictMode + // If strict mode is removed from the entry.client.tsx, this should only run once + useEffect(() => { + if (!startsHydrated.current && isHydrated) return; + if (typeof window !== "undefined") { + const $script = document.createElement("script"); + $script.src = "/cyberstorm-static/scripts/beta-switch.js"; + $script.setAttribute("async", "true"); + + document.body.append($script); + + return () => $script.remove(); + } + }, []); + + return <>; +} diff --git a/apps/cyberstorm-remix/cyberstorm/navigation/Navigation.tsx b/apps/cyberstorm-remix/cyberstorm/navigation/Navigation.tsx index 5a02413db..dfa68ccb9 100644 --- a/apps/cyberstorm-remix/cyberstorm/navigation/Navigation.tsx +++ b/apps/cyberstorm-remix/cyberstorm/navigation/Navigation.tsx @@ -66,6 +66,7 @@ export function Navigation(props: {
+
{ + const regExecuted = new RegExp(regPath).exec(window.location.pathname); + const found = regExecuted !== null && regExecuted.length < 2; + if (!betaIsAvailable && found) { + betaIsAvailable = true; + } + }, betaIsAvailable); + if (betaIsAvailable) { + const switchButton = document.createElement("button"); + if (window.location.hostname === legacy.hostname) { + switchButton.setAttribute( + "style", + "display:flex;align-items:center;gap:10px;color:#FFF;font-family:Lato;font-size:15px;font-style:normal;font-weight:400;line-height:normal;fill:#FFF;background:transparent;border-width:0px;" + ); + } else { + switchButton.setAttribute( + "style", + "display:flex;height:30px;padding: 0px 12px;justify-content:center;align-items:center;gap:12px;color:#F5F5F6;font-family:Inter;font-size:12px;font-style:normal;font-weight:700;line-height:normal;fill:#49B5F7;background:transparent;" + ); + } + switchButton.onclick = async () => { + checkBetaRedirect(); + }; + switchButton.innerHTML = ` Switch to ${ + window.location.hostname === legacy.hostname ? "beta" : "legacy" + }`; + const el = document.querySelector("#nimbusBeta"); + if (el) { + el.appendChild(switchButton); + } else { + console.error( + "Couldn't insert beta switch, because the container element doesn't exist" + ); + } + } +} +async function insertSwitchButtonListener() { + insertSwitchButton(); + document.removeEventListener("DOMContentLoaded", insertSwitchButtonListener); +} +if ( + document.readyState === "complete" || + document.readyState === "interactive" +) { + insertSwitchButton(); +} else { + document.addEventListener("DOMContentLoaded", insertSwitchButtonListener); +} diff --git a/packages/beta-switch/.gitignore b/packages/beta-switch/.gitignore new file mode 100644 index 000000000..b67fef920 --- /dev/null +++ b/packages/beta-switch/.gitignore @@ -0,0 +1,3 @@ +/dist/ +/node_modules/ +/tsconfig.tsbuildinfo diff --git a/packages/beta-switch/README.md b/packages/beta-switch/README.md new file mode 100644 index 000000000..d4b0a342e --- /dev/null +++ b/packages/beta-switch/README.md @@ -0,0 +1,8 @@ +# beta-switch +For switching between two sites running in the same domain + + +## Scripts + +- `yarn run build`: Builds the project +- `yarn run dev`: Builds the project & watches files for changes, triggering a rebuild diff --git a/packages/beta-switch/package.json b/packages/beta-switch/package.json new file mode 100644 index 000000000..651426d5a --- /dev/null +++ b/packages/beta-switch/package.json @@ -0,0 +1,16 @@ +{ + "name": "@thunderstore/beta-switch", + "version": "0.1.0", + "description": "Small thing for switching between two projects running in the same domain", + "repository": "https://github.com/thunderstore-io/thunderstore-ui/tree/master/packages/beta-switch", + "main": "dist/thunderstore-beta-switch.cjs.js", + "module": "dist/thunderstore-beta-switch.esm.js", + "types": "dist/thunderstore-beta-switch.cjs.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "tsc", + "dev": "tsc --watch" + } +} diff --git a/packages/beta-switch/src/index.ts b/packages/beta-switch/src/index.ts new file mode 100644 index 000000000..b7ceb5007 --- /dev/null +++ b/packages/beta-switch/src/index.ts @@ -0,0 +1,88 @@ +const enabledPages = ["/communities", "c/[^/]+/?$"]; + +const legacy = { + protocol: "https://", + hostname: "thunderstore.io", + port: "", +}; + +const beta = { + protocol: "https://", + hostname: "new.thunderstore.io", + port: "", +}; + +async function checkBetaRedirect() { + let switchProject = legacy; + + if (window.location.hostname === beta.hostname) { + switchProject = legacy; + } else if (window.location.hostname === legacy.hostname) { + switchProject = beta; + } + + // Don't include the search params as those differ in projects and are not handled gracefully + window.location.replace( + `${switchProject.protocol}${switchProject.hostname}${ + switchProject.port !== "" ? ":" : "" + }${switchProject.port}${window.location.pathname}` + ); +} + +async function insertSwitchButton() { + let betaIsAvailable = false; + enabledPages.forEach((regPath) => { + const regExecuted = new RegExp(regPath).exec(window.location.pathname); + const found = regExecuted !== null && regExecuted.length < 2; + if (!betaIsAvailable && found) { + betaIsAvailable = true; + } + }, betaIsAvailable); + + if (betaIsAvailable) { + const switchButton = document.createElement("button"); + + if (window.location.hostname === legacy.hostname) { + switchButton.setAttribute( + "style", + "display:flex;align-items:center;gap:10px;color:#FFF;font-family:Lato;font-size:15px;font-style:normal;font-weight:400;line-height:normal;fill:#FFF;background:transparent;border-width:0px;" + ); + } else { + switchButton.setAttribute( + "style", + "display:flex;height:30px;padding: 0px 12px;justify-content:center;align-items:center;gap:12px;color:#F5F5F6;font-family:Inter;font-size:12px;font-style:normal;font-weight:700;line-height:normal;fill:#49B5F7;background:transparent;" + ); + } + switchButton.onclick = async () => { + checkBetaRedirect(); + }; + + switchButton.innerHTML = ` Switch to ${ + window.location.hostname === legacy.hostname ? "beta" : "legacy" + }`; + + const el = document.querySelector("#nimbusBeta"); + if (el) { + el.appendChild(switchButton); + } else { + console.error( + "Couldn't insert beta switch, because the container element doesn't exist" + ); + } + } +} + +async function insertSwitchButtonListener() { + insertSwitchButton(); + document.removeEventListener("DOMContentLoaded", insertSwitchButtonListener); +} + +// Run above code +if ( + document.readyState === "complete" || + document.readyState === "interactive" +) { + insertSwitchButton(); +} else { + document.addEventListener("DOMContentLoaded", insertSwitchButtonListener); +} diff --git a/packages/beta-switch/tsconfig.json b/packages/beta-switch/tsconfig.json new file mode 100644 index 000000000..51e494b37 --- /dev/null +++ b/packages/beta-switch/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "node", + "removeComments": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true, + "composite": true, + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["./src/**/*.tsx", "./src/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/tools/ts-dev-proxy/nginx.conf b/tools/ts-dev-proxy/nginx.conf index 5b57fd4a9..6dfed98b1 100644 --- a/tools/ts-dev-proxy/nginx.conf +++ b/tools/ts-dev-proxy/nginx.conf @@ -8,6 +8,7 @@ events { http { server { listen 80; + server_name thunderstore.temp gzip on; gzip_proxied any; gzip_disable "msie6"; @@ -28,139 +29,63 @@ http { gzip_min_length 256; gunzip on; - location = /communities { - proxy_pass http://host.docker.internal:3000/communities; - proxy_set_header Host thunderstore.temp; - proxy_set_header X-Forwarded-For $remote_addr; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location = /site.webmanifest { - proxy_pass http://host.docker.internal:3000/site.webmanifest; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location = /favicon-32x32.png { - proxy_pass http://host.docker.internal:3000/favicon-32x32.png; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location = /favicon-16x16.png { - proxy_pass http://host.docker.internal:3000/favicon-16x16.png; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location = /android-chrome-192x192.png { - proxy_pass http://host.docker.internal:3000/android-chrome-192x192.png; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /teams { - proxy_pass http://host.docker.internal:3000/teams; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /c { - proxy_pass http://host.docker.internal:3000/c; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /settings { - proxy_pass http://host.docker.internal:3000/settings; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /tools { - proxy_pass http://host.docker.internal:3000/tools; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /package/create/docs { - proxy_pass http://host.docker.internal:3000/package/create/docs; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - # location /u { - # proxy_pass http://host.docker.internal:3000/u; - # } - - # location /developers { - # proxy_pass http://host.docker.internal:3000/developers; - # } - - location /__remix/healthz { - proxy_pass http://host.docker.internal:3000/healthz; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - # For when running built remix - location /__remix/ { - proxy_pass http://host.docker.internal:3000/__remix/; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - # For when running dev remix - location /node_modules/ { - proxy_pass http://host.docker.internal:3000/node_modules/; + location / { + proxy_pass http://host.docker.internal:81; + proxy_http_version 1.1; proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; + # proxy_ssl_name thunderstore.io; + # proxy_ssl_server_name on; + # add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } - location /app/ { - proxy_pass http://host.docker.internal:3000/app/; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; + location /gateway/healthz { + access_log off; + return 200 "healthy\\n"; } + } - location /@vite/ { - proxy_pass http://host.docker.internal:3000/@vite/; - proxy_set_header Host thunderstore.temp; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } +server { + listen 80; + server_name new.thunderstore.temp + gzip on; + gzip_proxied any; + gzip_disable "msie6"; + gzip_types + text/css + text/javascript + text/xml + text/plain + text/x-component + application/javascript + application/json + application/xml + application/rss+xml + font/truetype + font/opentype + application/vnd.ms-fontobject + image/svg+xml; + gzip_min_length 256; + gunzip on; - location /@fs/ { - proxy_pass http://host.docker.internal:3000/@fs/; - proxy_set_header Host thunderstore.temp; + location / { + proxy_pass http://host.docker.internal:3000/; + # proxy_set_header Host new.thunderstore.temp; + # proxy_set_header X-Forwarded-For $remote_addr; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } location /@id/__x00__sentry-release-injection-file { proxy_pass http://host.docker.internal:3000/@id/__x00__sentry-release-injection-file; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } location /@id/__x00__virtual:remix/browser-manifest { proxy_pass http://host.docker.internal:3000/@id/__x00__virtual:remix/browser-manifest; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } @@ -170,7 +95,7 @@ http { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } @@ -180,7 +105,7 @@ http { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } @@ -190,7 +115,7 @@ http { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } @@ -200,24 +125,9 @@ http { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; - proxy_set_header Host thunderstore.temp; + proxy_set_header Host new.thunderstore.temp; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers *; } - - location / { - proxy_pass http://host.docker.internal:81; - proxy_http_version 1.1; - proxy_set_header Host thunderstore.temp; - # proxy_ssl_name thunderstore.io; - # proxy_ssl_server_name on; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Headers *; - } - - location /gateway/healthz { - access_log off; - return 200 "healthy\\n"; - } } }