fix: gate unfinished surfaces honestly (oracle round 2)
- Login.tsx: dev-login gated by VITE_ENABLE_DEV_LOGIN (defaults on, set to 'false' in production builds). SSO button probes /microsoft/login and shows 'NOT CONFIGURED' or 'NOT WIRED' state with disabled action instead of looking like a working primary login. - Hub.tsx: 'Queue'/'Selected work' renamed 'Available workflows' / 'Workflow detail' + footnote that a real work-item queue replaces it when the EA2 hub queue is wired. No more semantic overclaim. - Landing.tsx: Attendance Map chip gated by VITE_ENABLE_GEO_PREVIEW (default on) and labelled 'preview' so it can be hidden in prod builds. - flowCuration.ts: extend the dev-artefact filter to drop engineering names (EA2 *, SDX *, *runtime reference*, *demo*, *test*) so Pi and the hubs only ever expose buyer-appropriate flows. - All 29 unit tests + 26 dogfood QA assertions still green.
This commit is contained in:
@@ -21,6 +21,11 @@ const DEV_ARTEFACT_PATTERNS = [
|
|||||||
/\bsmoke[_\s]?test\b/i,
|
/\bsmoke[_\s]?test\b/i,
|
||||||
/\bprobe\b/i,
|
/\bprobe\b/i,
|
||||||
/\bfixture\b/i,
|
/\bfixture\b/i,
|
||||||
|
/\bea2\b/i,
|
||||||
|
/\bsdx\b/i,
|
||||||
|
/\bruntime reference\b/i,
|
||||||
|
/\bdemo\b/i,
|
||||||
|
/\btest\b/i,
|
||||||
];
|
];
|
||||||
|
|
||||||
const NON_BUSINESS_SOURCE_CONTEXTS = new Set([
|
const NON_BUSINESS_SOURCE_CONTEXTS = new Set([
|
||||||
|
|||||||
+5
-4
@@ -163,11 +163,11 @@ export default function Hub({ hub }: { hub: HubKey }) {
|
|||||||
|
|
||||||
<div className="hub-split">
|
<div className="hub-split">
|
||||||
<section className="hub-queue">
|
<section className="hub-queue">
|
||||||
<div className="hub-section-label">{spec.title.split(" ")[0].toUpperCase()} QUEUE</div>
|
<div className="hub-section-label">AVAILABLE WORKFLOWS</div>
|
||||||
{flows === null && <div className="hub-empty">Loading…</div>}
|
{flows === null && <div className="hub-empty">Loading…</div>}
|
||||||
{flows !== null && visible.length === 0 && (
|
{flows !== null && visible.length === 0 && (
|
||||||
<div className="hub-empty">
|
<div className="hub-empty">
|
||||||
Nothing in the queue yet. Open the <button className="link-inline" onClick={() => setScene("studio")}>Process Studio</button> to publish a process.
|
No workflows published for this function yet. Open the <button className="link-inline" onClick={() => setScene("studio")}>Process Studio</button> to add one.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ul className="hub-queue-list">
|
<ul className="hub-queue-list">
|
||||||
@@ -183,11 +183,12 @@ export default function Hub({ hub }: { hub: HubKey }) {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
<p className="hub-queue-foot">A live work-item queue will replace this list once the EA2 hub queue endpoint is wired.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="hub-selected">
|
<section className="hub-selected">
|
||||||
<div className="hub-section-label">SELECTED WORK</div>
|
<div className="hub-section-label">WORKFLOW DETAIL</div>
|
||||||
{!selected && <div className="hub-empty">Select a row on the left.</div>}
|
{!selected && <div className="hub-empty">Select a workflow on the left.</div>}
|
||||||
{selected && (
|
{selected && (
|
||||||
<div className="hub-flow-card">
|
<div className="hub-flow-card">
|
||||||
<div className="hub-flow-title"><Branch size={11} /> {selected.display_name}</div>
|
<div className="hub-flow-title"><Branch size={11} /> {selected.display_name}</div>
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ export default function Landing() {
|
|||||||
<button className="hub-chip" onClick={() => setScene("hub-procurement")}>Procurement Hub</button>
|
<button className="hub-chip" onClick={() => setScene("hub-procurement")}>Procurement Hub</button>
|
||||||
<button className="hub-chip" onClick={() => setScene("hub-hr")}>People Hub</button>
|
<button className="hub-chip" onClick={() => setScene("hub-hr")}>People Hub</button>
|
||||||
<button className="hub-chip" onClick={() => setScene("hub-it")}>IT Hub</button>
|
<button className="hub-chip" onClick={() => setScene("hub-it")}>IT Hub</button>
|
||||||
<button className="hub-chip" onClick={() => setScene("geo-attendance")}>Attendance Map</button>
|
{(import.meta.env.VITE_ENABLE_GEO_PREVIEW ?? "true") !== "false" && (
|
||||||
|
<button className="hub-chip" onClick={() => setScene("geo-attendance")}>Attendance Map · preview</button>
|
||||||
|
)}
|
||||||
<button className="hub-chip" onClick={() => setScene("agent")}>Command Assistant</button>
|
<button className="hub-chip" onClick={() => setScene("agent")}>Command Assistant</button>
|
||||||
<button className="hub-chip" onClick={() => setScene("chat")}>Team Chat</button>
|
<button className="hub-chip" onClick={() => setScene("chat")}>Team Chat</button>
|
||||||
<button className="hub-chip" onClick={() => setScene("explainer")}>What is FlowMaster?</button>
|
<button className="hub-chip" onClick={() => setScene("explainer")}>What is FlowMaster?</button>
|
||||||
|
|||||||
+26
-8
@@ -9,16 +9,28 @@ export default function Login() {
|
|||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [rememberMe, setRememberMe] = useState(false);
|
const [rememberMe, setRememberMe] = useState(false);
|
||||||
const [devLoginEnabled, setDevLoginEnabled] = useState(true);
|
const buildAllowsDev = (import.meta.env.VITE_ENABLE_DEV_LOGIN ?? "true") !== "false";
|
||||||
|
const [devLoginEnabled, setDevLoginEnabled] = useState(buildAllowsDev);
|
||||||
|
const [ssoState, setSsoState] = useState<"unknown" | "ready" | "not-configured" | "not-wired">("unknown");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// dev-login is on by default. Only the endpoint can flip it OFF.
|
if (!buildAllowsDev) {
|
||||||
api.devLoginConfig()
|
setDevLoginEnabled(false);
|
||||||
.then((cfg) => { if (cfg.enabled === false) setDevLoginEnabled(false); })
|
} else {
|
||||||
.catch(() => { /* endpoint absent → keep ON */ });
|
api.devLoginConfig()
|
||||||
}, []);
|
.then((cfg) => { if (cfg.enabled === false) setDevLoginEnabled(false); })
|
||||||
|
.catch(() => { /* endpoint absent → keep state */ });
|
||||||
|
}
|
||||||
|
fetch("/api/v1/auth/microsoft/login", { method: "GET", redirect: "manual" })
|
||||||
|
.then((r) => {
|
||||||
|
if (r.status >= 300 && r.status < 400) setSsoState("ready");
|
||||||
|
else if (r.status === 503) setSsoState("not-configured");
|
||||||
|
else setSsoState("not-wired");
|
||||||
|
})
|
||||||
|
.catch(() => setSsoState("not-wired"));
|
||||||
|
}, [buildAllowsDev]);
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -142,14 +154,20 @@ export default function Login() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="login-sso-actions">
|
<div className="login-sso-actions">
|
||||||
<button type="button" className="sso-btn" onClick={handleSSO} disabled={loading}>
|
<button
|
||||||
|
type="button"
|
||||||
|
className="sso-btn"
|
||||||
|
onClick={handleSSO}
|
||||||
|
disabled={loading || ssoState === "not-configured" || ssoState === "not-wired"}
|
||||||
|
title={ssoState === "not-configured" ? "Microsoft sign-in is not yet configured for this tenant" : ssoState === "not-wired" ? "Microsoft sign-in is not wired to this environment yet" : "Sign in with Microsoft"}
|
||||||
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 21 21">
|
<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="1" y="1" width="9" height="9" fill="#f25022"/>
|
||||||
<rect x="11" y="1" width="9" height="9" fill="#7fba00"/>
|
<rect x="11" y="1" width="9" height="9" fill="#7fba00"/>
|
||||||
<rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
|
<rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
|
||||||
<rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
|
<rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
|
||||||
</svg>
|
</svg>
|
||||||
CONTINUE WITH MICROSOFT
|
{ssoState === "not-configured" ? "MICROSOFT SIGN-IN · NOT CONFIGURED" : ssoState === "not-wired" ? "MICROSOFT SIGN-IN · NOT WIRED" : "CONTINUE WITH MICROSOFT"}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{devLoginEnabled && (
|
{devLoginEnabled && (
|
||||||
|
|||||||
Reference in New Issue
Block a user