Skip to content

Commit 8871661

Browse files
geroplona-agent
andauthored
Add minimal gitpod.io mode and redirect logging (#21271)
* Add minimal gitpod.io mode and redirect logging Task 1: Add redirect logging to Caddy proxy - New (enable_redirect_log) snippet that logs all 3xx responses - Captures source URL, destination, status code, and user agent - Added to http://, https://{GITPOD_DOMAIN}, and workspace blocks Task 2: Implement minimal gitpod.io mode in dashboard - Only active on exact "gitpod.io" domain - Controlled by ConfigCat flag "minimal_gitpod_io_mode" - localStorage override for testing: minimal_gitpod_io_mode=true/false - Handles redirects without booting full React app: - Website slugs -> www.gitpod.io - Hash-based workspace creation -> app.ona.com - Legacy URL formats -> app.ona.com - App routes and root path -> minimal login page - Unknown paths -> www.gitpod.io - Minimal login page shows Ona branding and "Continue with Ona" button Part of CLC-2206: Reduce Compute Engine costs Co-authored-by: Ona <no-reply@ona.com> * Fix ConfigCat client usage in minimal mode Use existing getExperimentsClient() wrapper instead of raw configcat-js API. Co-authored-by: Ona <no-reply@ona.com> * fix: use existing isGitpodIo function * Update minimal login page to match current PAYG layout - Two-panel layout: white left panel with login, gradient right panel with Ona branding - Gitpod orange logo on left panel - 'What do you want to get done today?' subtitle - Black outlined 'Continue with Ona' button - Sunset notice with links to Ona - Terms of service and privacy policy footer - Right panel with Ona wordmark, description, and 'Try Ona' button - Responsive: hides right panel on smaller screens Co-authored-by: Ona <no-reply@ona.com> * Extract minimal login page to external HTML file - Move inline HTML template to src/minimal-login.html for easier review - Add webpack config to import HTML as raw string - Add TypeScript declaration for HTML imports Co-authored-by: Ona <no-reply@ona.com> * Add HTML files to dashboard build sources Co-authored-by: Ona <no-reply@ona.com> * Fix minimal login page styling - Fix button styling: dark background with white text (matching current design) - Remove terms of service footer (no longer applicable) - Add ona-application.webp to public folder for the preview image Co-authored-by: Ona <no-reply@ona.com> --------- Co-authored-by: Ona <no-reply@ona.com>
1 parent fe795bf commit 8871661

7 files changed

Lines changed: 479 additions & 7 deletions

File tree

components/dashboard/BUILD.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ packages:
99
- "src/**/*.png"
1010
- "src/**/*.webp"
1111
- "src/**/*.json"
12+
- "src/**/*.html"
1213
- "typings/**"
1314
- package.json
1415
- tailwind.config.js

components/dashboard/craco.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ module.exports = {
4545
fullySpecified: false,
4646
},
4747
},
48+
{
49+
// Import HTML files as raw strings (for minimal-login.html)
50+
test: /minimal-login\.html$/,
51+
type: "asset/source",
52+
},
4853
],
4954
},
5055
plugins: [
92.5 KB
Loading

components/dashboard/src/index.tsx

Lines changed: 168 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,154 @@ import { PaymentContextProvider } from "./payment-context";
2626
import { ThemeContextProvider } from "./theme-context";
2727
import { UserContextProvider } from "./user-context";
2828
import { getURLHash, isGitpodIo, isWebsiteSlug } from "./utils";
29+
import { getExperimentsClient } from "./experiments/client";
30+
// Import the minimal login HTML template at build time
31+
import minimalLoginHtml from "./minimal-login.html";
2932

30-
const bootApp = () => {
31-
// gitpod.io specific boot logic
32-
if (isGitpodIo()) {
33-
// Redirect to www website for any website slugs
34-
if (isWebsiteSlug(window.location.pathname)) {
35-
window.location.host = "www.gitpod.io";
36-
return;
33+
const MINIMAL_MODE_STORAGE_KEY = "minimal_gitpod_io_mode";
34+
const MINIMAL_MODE_FLAG_NAME = "minimal_gitpod_io_mode";
35+
36+
/**
37+
* Check if we should use minimal gitpod.io mode.
38+
* Priority:
39+
* 1. localStorage override (for testing)
40+
* 2. ConfigCat feature flag
41+
*/
42+
async function shouldUseMinimalMode(): Promise<boolean> {
43+
// Check localStorage override first (sync, for testing)
44+
try {
45+
const localOverride = localStorage.getItem(MINIMAL_MODE_STORAGE_KEY);
46+
if (localOverride === "true") return true;
47+
if (localOverride === "false") return false;
48+
} catch {
49+
// localStorage might not be available
50+
}
51+
52+
// Check ConfigCat feature flag
53+
try {
54+
const client = getExperimentsClient();
55+
const value = await client.getValueAsync(MINIMAL_MODE_FLAG_NAME, false, {
56+
gitpodHost: window.location.host,
57+
});
58+
return value === true;
59+
} catch (error) {
60+
console.error("Failed to check minimal mode flag:", error);
61+
return false; // Fail safe: use full app
62+
}
63+
}
64+
65+
/**
66+
* Check if the pathname is a known app route that should show the minimal login page
67+
*/
68+
function isAppRoute(pathname: string): boolean {
69+
const appRoutes = [
70+
"/workspaces",
71+
"/new",
72+
"/start",
73+
"/settings",
74+
"/billing",
75+
"/members",
76+
"/sso",
77+
"/orgs",
78+
"/repositories",
79+
"/prebuilds",
80+
"/admin",
81+
"/login",
82+
"/oauth-approval",
83+
"/blocked",
84+
"/from-referrer",
85+
"/usage",
86+
"/insights",
87+
"/org-admin",
88+
"/quickstart",
89+
// Legacy routes that redirect in full app
90+
"/account",
91+
"/integrations",
92+
"/notifications",
93+
"/preferences",
94+
"/variables",
95+
"/tokens",
96+
"/keys",
97+
"/open",
98+
"/sorry",
99+
"/t/",
100+
"/projects/",
101+
"/user/",
102+
"/access-control",
103+
"/old-team-plans",
104+
"/teams",
105+
"/subscription",
106+
"/upgrade-subscription",
107+
"/plans",
108+
];
109+
110+
return appRoutes.some((route) => pathname === route || pathname.startsWith(route + "/"));
111+
}
112+
113+
/**
114+
* Handle requests in minimal gitpod.io mode.
115+
* This runs instead of the full React app when minimal mode is enabled.
116+
*/
117+
function handleMinimalGitpodIoMode(): void {
118+
const pathname = window.location.pathname;
119+
const search = window.location.search;
120+
const hash = window.location.hash;
121+
const hashContent = hash.replace(/^#\/?/, "");
122+
123+
// 1. Website slugs -> www.gitpod.io
124+
if (isWebsiteSlug(pathname)) {
125+
window.location.href = `https://www.gitpod.io${pathname}${search}`;
126+
return;
127+
}
128+
129+
// 2. Hash-based workspace creation -> app.ona.com
130+
if (hashContent !== "") {
131+
// Normalize github.dev to github.com first
132+
let normalizedHash = hash;
133+
if (/^#\/?((https:\/\/)?github\.dev\/)/i.test(hash)) {
134+
normalizedHash = hash.replace(/github\.dev\//gi, "github.com/");
37135
}
136+
window.location.href = `https://app.ona.com/${normalizedHash}`;
137+
return;
138+
}
139+
140+
// 3. Legacy URL formats (/github.com/..., /gitlab.com/..., /bitbucket.org/...)
141+
if (/^\/(github|gitlab|bitbucket)\.(com|org)\//.test(pathname)) {
142+
window.location.href = `https://app.ona.com/#${pathname.slice(1)}${search}`;
143+
return;
144+
}
145+
146+
// 4. App routes -> render minimal login page
147+
if (isAppRoute(pathname)) {
148+
renderMinimalLoginPage();
149+
return;
150+
}
151+
152+
// 5. Root path -> render minimal login page
153+
if (pathname === "/" || pathname === "") {
154+
renderMinimalLoginPage();
155+
return;
38156
}
39157

158+
// 6. Unknown paths -> www.gitpod.io (let website handle 404)
159+
window.location.href = `https://www.gitpod.io${pathname}${search}`;
160+
}
161+
162+
/**
163+
* Render a minimal static login page without React.
164+
* Loads the HTML from an external file for easier review and maintenance.
165+
*/
166+
function renderMinimalLoginPage(): void {
167+
// Replace the entire document with the minimal login page
168+
document.open();
169+
document.write(minimalLoginHtml);
170+
document.close();
171+
}
172+
173+
/**
174+
* Boot the full React application
175+
*/
176+
function bootFullApp(): void {
40177
// Normalize github.dev urls to github.com
41178
const hash = getURLHash();
42179
if (/^(https:\/\/)?github\.dev\//i.test(hash)) {
@@ -81,6 +218,30 @@ const bootApp = () => {
81218
</React.StrictMode>,
82219
document.getElementById("root"),
83220
);
221+
}
222+
223+
/**
224+
* Main boot function
225+
*/
226+
const bootApp = async () => {
227+
// Minimal gitpod.io mode - only on exact "gitpod.io" domain
228+
if (isGitpodIo()) {
229+
const minimalMode = await shouldUseMinimalMode();
230+
231+
if (minimalMode) {
232+
handleMinimalGitpodIoMode();
233+
return;
234+
}
235+
236+
// Not in minimal mode, but still handle website slugs
237+
if (isWebsiteSlug(window.location.pathname)) {
238+
window.location.host = "www.gitpod.io";
239+
return;
240+
}
241+
}
242+
243+
// Boot full React app
244+
bootFullApp();
84245
};
85246

86247
bootApp();

0 commit comments

Comments
 (0)