fix(login): devLoginConfig() returns null when endpoint absent, not false
The Vite minifier was tree-shaking the dev-login button because
devLoginConfig() always returned {enabled: false} when the
/internal/dev-login-config endpoint 404'd (which is the case on
canvas, where the endpoint isn't mounted).
That meant my prior 'default ON' fix never took effect — the useEffect
unconditionally flipped state to false within microseconds of mount.
Real fix: return {enabled: null} on absence. Only flip OFF when
endpoint explicitly says enabled=false. Otherwise honor the source
default.
Confidence: high
Scope-risk: narrow
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
import { chromium } from "playwright";
|
||||||
|
const b = await chromium.launch({
|
||||||
|
headless: true,
|
||||||
|
args: [
|
||||||
|
"--host-resolver-rules=MAP canvas.flow-master.ai 65.21.71.186",
|
||||||
|
"--ignore-certificate-errors",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const p = await b.newPage({ viewport: { width: 1440, height: 900 } });
|
||||||
|
p.on("console", (m) => console.log("console", m.type(), m.text().slice(0, 200)));
|
||||||
|
p.on("pageerror", (e) => console.log("pageerror", e.message));
|
||||||
|
await p.goto("https://canvas.flow-master.ai/", { waitUntil: "networkidle" });
|
||||||
|
await p.waitForTimeout(2000);
|
||||||
|
console.log("--- DOM ---");
|
||||||
|
console.log(await p.evaluate(() => document.body.innerHTML.slice(0, 3000)));
|
||||||
|
console.log("--- visible text ---");
|
||||||
|
console.log(await p.evaluate(() => document.body.innerText));
|
||||||
|
console.log("--- buttons ---");
|
||||||
|
const buttons = await p.$$eval("button, a", (els) => els.map((e) => `${e.tagName} disabled=${e.disabled} "${(e.innerText || e.textContent || "").slice(0, 60)}"`));
|
||||||
|
buttons.forEach((b) => console.log(b));
|
||||||
|
await b.close();
|
||||||
+5
-4
@@ -210,17 +210,18 @@ export const api = {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
async devLoginConfig(signal?: AbortSignal): Promise<{ enabled: boolean }> {
|
async devLoginConfig(signal?: AbortSignal): Promise<{ enabled: boolean | null }> {
|
||||||
try {
|
try {
|
||||||
const init: RequestInit = { method: "GET", headers: { "Accept": "application/json" }, signal };
|
const init: RequestInit = { method: "GET", headers: { "Accept": "application/json" }, signal };
|
||||||
const r = await instrumentedFetch("GET", `${this.config.baseUrl}/internal/dev-login-config`, init);
|
const r = await instrumentedFetch("GET", `${this.config.baseUrl}/internal/dev-login-config`, init);
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
return await r.json() as { enabled: boolean };
|
const body = await r.json() as { enabled: boolean };
|
||||||
|
return { enabled: !!body.enabled };
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// swallow
|
// network/parse error — caller treats null as "no opinion"
|
||||||
}
|
}
|
||||||
return { enabled: false };
|
return { enabled: null };
|
||||||
},
|
},
|
||||||
|
|
||||||
async workItems(signal?: AbortSignal): Promise<WorkItem[]> {
|
async workItems(signal?: AbortSignal): Promise<WorkItem[]> {
|
||||||
|
|||||||
@@ -14,12 +14,10 @@ export default function Login() {
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// The dev-login button is intentionally on by default on canvas
|
// dev-login is on by default. Only the endpoint can flip it OFF.
|
||||||
// (the user explicitly asked for it as a documented exception until
|
|
||||||
// we cut over fully to SSO). The endpoint config only flips it OFF.
|
|
||||||
api.devLoginConfig()
|
api.devLoginConfig()
|
||||||
.then((cfg) => { if (cfg.enabled === false) setDevLoginEnabled(false); })
|
.then((cfg) => { if (cfg.enabled === false) setDevLoginEnabled(false); })
|
||||||
.catch(() => { /* endpoint not present — keep default ON */ });
|
.catch(() => { /* endpoint absent → keep ON */ });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user