Skip to content

Commit 9adafc3

Browse files
authored
Merge branch 'main' into visionv2
2 parents 244ef89 + 84cf73e commit 9adafc3

File tree

3 files changed

+75
-45
lines changed

3 files changed

+75
-45
lines changed

.github/chatmodes/fixer.chatmode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ You MUST check task output readiness before debugging, testing, or declaring wor
2424
- Frontend: Vite provides HMR; changes in the frontend are picked up automatically without restarting the task.
2525
- Backend: Quart was started with --reload; Python changes trigger an automatic restart.
2626
- If watchers seem stuck or output stops updating, stop the tasks and run the "Development" task again.
27-
- To interact with a running application, use the Playwright MCP server
27+
- To interact with a running application, use the Playwright MCP server. If testing login, you will need to navigate to 'localhost' instead of '127.0.0.1' since that's the URL allowed by the Entra application.
2828

2929
## Running Python scripts
3030

app/frontend/src/index.tsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { createHashRouter, RouterProvider } from "react-router-dom";
44
import { I18nextProvider } from "react-i18next";
55
import { HelmetProvider } from "react-helmet-async";
66
import { initializeIcons } from "@fluentui/react";
7+
import { MsalProvider } from "@azure/msal-react";
8+
import { AuthenticationResult, EventType, PublicClientApplication } from "@azure/msal-browser";
79

810
import "./index.css";
911

1012
import Chat from "./pages/chat/Chat";
1113
import LayoutWrapper from "./layoutWrapper";
1214
import i18next from "./i18n/config";
15+
import { msalConfig, useLogin } from "./authConfig";
1316

1417
initializeIcons();
1518

@@ -34,12 +37,54 @@ const router = createHashRouter([
3437
}
3538
]);
3639

37-
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
38-
<React.StrictMode>
39-
<I18nextProvider i18n={i18next}>
40-
<HelmetProvider>
41-
<RouterProvider router={router} />
42-
</HelmetProvider>
43-
</I18nextProvider>
44-
</React.StrictMode>
45-
);
40+
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
41+
42+
// Bootstrap the app once; conditionally wrap with MsalProvider when login is enabled
43+
(async () => {
44+
let msalInstance: PublicClientApplication | undefined;
45+
46+
if (useLogin) {
47+
msalInstance = new PublicClientApplication(msalConfig);
48+
try {
49+
await msalInstance.initialize();
50+
51+
// Default active account to the first one if none is set
52+
if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) {
53+
msalInstance.setActiveAccount(msalInstance.getAllAccounts()[0]);
54+
}
55+
56+
// Keep active account in sync on login success
57+
msalInstance.addEventCallback(event => {
58+
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) {
59+
const result = event.payload as AuthenticationResult;
60+
if (result.account) {
61+
msalInstance!.setActiveAccount(result.account);
62+
}
63+
}
64+
});
65+
} catch (e) {
66+
// Non-fatal: render the app even if MSAL initialization fails
67+
// eslint-disable-next-line no-console
68+
console.error("MSAL initialize failed", e);
69+
msalInstance = undefined;
70+
}
71+
}
72+
73+
const appTree = (
74+
<React.StrictMode>
75+
<I18nextProvider i18n={i18next}>
76+
<HelmetProvider>
77+
{useLogin && msalInstance ? (
78+
<MsalProvider instance={msalInstance}>
79+
<RouterProvider router={router} />
80+
</MsalProvider>
81+
) : (
82+
<RouterProvider router={router} />
83+
)}
84+
</HelmetProvider>
85+
</I18nextProvider>
86+
</React.StrictMode>
87+
);
88+
89+
root.render(appTree);
90+
})();

app/frontend/src/layoutWrapper.tsx

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,33 @@
1-
import { AccountInfo, EventType, PublicClientApplication } from "@azure/msal-browser";
2-
import { checkLoggedIn, msalConfig, useLogin } from "./authConfig";
3-
import { useEffect, useState } from "react";
4-
import { MsalProvider } from "@azure/msal-react";
1+
import { useEffect, useRef, useState } from "react";
2+
import { useMsal } from "@azure/msal-react";
3+
import { useLogin, checkLoggedIn } from "./authConfig";
54
import { LoginContext } from "./loginContext";
65
import Layout from "./pages/layout/Layout";
76

87
const LayoutWrapper = () => {
98
const [loggedIn, setLoggedIn] = useState(false);
109
if (useLogin) {
11-
var msalInstance = new PublicClientApplication(msalConfig);
12-
13-
// Default to using the first account if no account is active on page load
14-
if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) {
15-
// Account selection logic is app dependent. Adjust as needed for different use cases.
16-
msalInstance.setActiveAccount(msalInstance.getActiveAccount());
17-
}
18-
19-
// Listen for sign-in event and set active account
20-
msalInstance.addEventCallback(event => {
21-
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) {
22-
const account = event.payload as AccountInfo;
23-
msalInstance.setActiveAccount(account);
24-
}
25-
});
26-
10+
const { instance } = useMsal();
11+
// Keep track of the mounted state to avoid setting state in an unmounted component
12+
const mounted = useRef<boolean>(true);
2713
useEffect(() => {
28-
const fetchLoggedIn = async () => {
29-
setLoggedIn(await checkLoggedIn(msalInstance));
14+
mounted.current = true;
15+
checkLoggedIn(instance)
16+
.then(isLoggedIn => {
17+
if (mounted.current) setLoggedIn(isLoggedIn);
18+
})
19+
.catch(e => {
20+
console.error("checkLoggedIn failed", e);
21+
});
22+
return () => {
23+
mounted.current = false;
3024
};
31-
32-
fetchLoggedIn();
33-
}, []);
25+
}, [instance]);
3426

3527
return (
36-
<MsalProvider instance={msalInstance}>
37-
<LoginContext.Provider
38-
value={{
39-
loggedIn,
40-
setLoggedIn
41-
}}
42-
>
43-
<Layout />
44-
</LoginContext.Provider>
45-
</MsalProvider>
28+
<LoginContext.Provider value={{ loggedIn, setLoggedIn }}>
29+
<Layout />
30+
</LoginContext.Provider>
4631
);
4732
} else {
4833
return (

0 commit comments

Comments
 (0)