feat: rebuild Process Studio into multi-phase Process Creation Wizard\n\n- Replace toy Studio.tsx with proper Wizard.tsx canvas\n- Build 6-step flow: Intake -> Analyze -> Generate -> Validate -> Draft saved -> Publish\n- Implement incremental EA2 writes via wizardApi.ts (flow, batch apply)\n- Use localStorage for draft recovery across reloads\n- Apply industrial-blueprint UI styling matching core doctrine\n- Add Vitest tests for Wizard components and API wrappers
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled

This commit is contained in:
2026-06-14 03:47:26 +04:00
parent b2c1e57c86
commit 4bc7ae228a
27 changed files with 2274 additions and 275 deletions
+141
View File
@@ -0,0 +1,141 @@
import { useState, useEffect } from "react";
import { useApp } from "../state/store";
import { api } from "../lib/api";
import { Bot } from "../components/icons";
export default function Login() {
const setScene = useApp((s) => s.setScene);
const loginAs = useApp((s) => s.loginAs);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const [devLoginEnabled, setDevLoginEnabled] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// Check if dev login is enabled
api.devLoginConfig().then((cfg) => setDevLoginEnabled(cfg.enabled));
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email) return;
setLoading(true);
setError(null);
try {
await loginAs(email, password || undefined);
setScene("landing");
} catch (err) {
setError((err as Error).message);
} finally {
setLoading(false);
}
};
const handleDevLogin = async () => {
if (!email) {
setError("Email required for dev-login");
return;
}
setLoading(true);
setError(null);
try {
await loginAs(email, undefined);
setScene("landing");
} catch (err) {
setError((err as Error).message);
} finally {
setLoading(false);
}
};
const handleSSO = () => {
window.location.href = "/api/v1/auth/microsoft/login";
};
return (
<div className="login-page">
<div className="login-card">
<div className="login-head">
<span className="brand-mark"></span>
<h1>FLOWMASTER AUTHENTICATION</h1>
<div className="login-sub">MISSION CONTROL VERIFICATION REQUIRED</div>
</div>
{error && <div className="login-error">{error}</div>}
<form className="login-form" onSubmit={handleSubmit}>
<div className="login-field">
<label htmlFor="email">OPERATOR_ID (EMAIL)</label>
<input
id="email"
type="email"
className="login-input"
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={loading}
autoComplete="email"
placeholder="e.g. j.doe@flow-master.ai"
required
/>
</div>
<div className="login-field">
<label htmlFor="password">PASSPHRASE</label>
<input
id="password"
type="password"
className="login-input"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={loading}
autoComplete="current-password"
/>
</div>
<div className="login-row">
<label className="login-checkbox">
<input
type="checkbox"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
disabled={loading}
/>
<span>Remember me</span>
</label>
<a href="#" className="login-link">Recover access</a>
</div>
<div className="login-actions">
<button type="submit" className="btn btn-primary btn-lg" disabled={loading || !email}>
{loading ? "VERIFYING..." : "SIGN IN"}
</button>
</div>
</form>
<div className="login-divider">
<span>OR</span>
</div>
<div className="login-sso-actions">
<button type="button" className="sso-btn" onClick={handleSSO} disabled={loading}>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 21 21">
<rect x="1" y="1" width="9" height="9" fill="#f25022"/>
<rect x="11" y="1" width="9" height="9" fill="#7fba00"/>
<rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
<rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
</svg>
CONTINUE WITH MICROSOFT
</button>
{devLoginEnabled && (
<button type="button" className="dev-login-btn" onClick={handleDevLogin} disabled={loading || !email}>
<Bot size={14} /> SIGN IN AS DEVELOPER (DEV-LOGIN)
</button>
)}
</div>
</div>
</div>
);
}