mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 07:35:24 +00:00
fix: keep plugins loaded after signing in from the login screen
This commit is contained in:
1 parent
8043d6dbdd
commit
4423c4c8ef
3 files changed
+48
-12
No files matched your search
+1
-10
@@ -134,10 +134,6 @@ function App() {
|
|||||||
const [authUsername, setAuthUsername] = useState(stored?.username ?? "");
|
const [authUsername, setAuthUsername] = useState(stored?.username ?? "");
|
||||||
const [verifyRetryCount, setVerifyRetryCount] = useState(0);
|
const [verifyRetryCount, setVerifyRetryCount] = useState(0);
|
||||||
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
// Track whether fading-in came from a fresh login (vs. session verification on page load).
|
|
||||||
// When session-verified, Auth must not mount during the transition — it would trigger
|
|
||||||
// silent OIDC redirect and cause an infinite refresh loop.
|
|
||||||
const fadingInFromLoginRef = useRef(false);
|
|
||||||
// Dedupes concurrent handleLogout() calls within the same tick -- see
|
// Dedupes concurrent handleLogout() calls within the same tick -- see
|
||||||
// handleLogout for why phase state alone isn't sufficient for this.
|
// handleLogout for why phase state alone isn't sufficient for this.
|
||||||
const loggingOutRef = useRef(false);
|
const loggingOutRef = useRef(false);
|
||||||
@@ -175,7 +171,6 @@ function App() {
|
|||||||
// Non-fatal: WebSocket connections will fall back to cookie auth
|
// Non-fatal: WebSocket connections will fall back to cookie auth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fadingInFromLoginRef.current = false;
|
|
||||||
setPhase("loading-app");
|
setPhase("loading-app");
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
startPluginRuntime()
|
startPluginRuntime()
|
||||||
@@ -241,7 +236,6 @@ function App() {
|
|||||||
loggingOutRef.current = false;
|
loggingOutRef.current = false;
|
||||||
clearDesktopManualLogout();
|
clearDesktopManualLogout();
|
||||||
setAuthUsername(u);
|
setAuthUsername(u);
|
||||||
fadingInFromLoginRef.current = true;
|
|
||||||
setPhase("loading-app");
|
setPhase("loading-app");
|
||||||
void (async () => {
|
void (async () => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@@ -299,10 +293,7 @@ function App() {
|
|||||||
|
|
||||||
const showApp =
|
const showApp =
|
||||||
phase === "idle-app" || phase === "fading-in" || phase === "fading-out";
|
phase === "idle-app" || phase === "fading-in" || phase === "fading-out";
|
||||||
const showAuth =
|
const showAuth = phase === "idle-auth" || phase === "fading-out";
|
||||||
phase === "idle-auth" ||
|
|
||||||
(phase === "fading-in" && fadingInFromLoginRef.current) ||
|
|
||||||
phase === "fading-out";
|
|
||||||
const appOpacity = phase === "idle-app" ? 1 : 0;
|
const appOpacity = phase === "idle-app" ? 1 : 0;
|
||||||
const authOpacity = phase === "idle-auth" ? 1 : 0;
|
const authOpacity = phase === "idle-auth" ? 1 : 0;
|
||||||
|
|
||||||
|
|||||||
@@ -442,13 +442,20 @@ export async function startPreLoginPlugins(): Promise<void> {
|
|||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (list.length === 0) return;
|
if (list.length === 0 || started) return;
|
||||||
setPluginLocaleResolver((namespace, _language, file) => {
|
setPluginLocaleResolver((namespace, _language, file) => {
|
||||||
const summary = getPluginRecord(namespace)?.summary;
|
const summary = getPluginRecord(namespace)?.summary;
|
||||||
if (!summary) return Promise.resolve(null);
|
if (!summary) return Promise.resolve(null);
|
||||||
return currentDeps().loadLocale(summary, file);
|
return currentDeps().loadLocale(summary, file);
|
||||||
});
|
});
|
||||||
await syncPlugins(list);
|
await enqueue(async () => {
|
||||||
|
// Once signed in the full sync owns the list, and reconciling this
|
||||||
|
// subset would unload everything else. Auth remounts during the
|
||||||
|
// post-login fade, so this runs after sign-in every time.
|
||||||
|
if (started) return;
|
||||||
|
await reconcile(list);
|
||||||
|
markPluginsSettled();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
isPluginFrontendActive,
|
isPluginFrontendActive,
|
||||||
orderForActivation,
|
orderForActivation,
|
||||||
resetPluginLoader,
|
resetPluginLoader,
|
||||||
|
startPluginRuntime,
|
||||||
|
startPreLoginPlugins,
|
||||||
syncPlugins,
|
syncPlugins,
|
||||||
} from "@/plugin-host/loader";
|
} from "@/plugin-host/loader";
|
||||||
import {
|
import {
|
||||||
@@ -208,6 +210,42 @@ describe("plugin loader", () => {
|
|||||||
expect(railIds()).not.toContain("headless-panel");
|
expect(railIds()).not.toContain("headless-panel");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps every plugin when the pre-login list lands after sign-in", async () => {
|
||||||
|
modules.login = railPlugin("login");
|
||||||
|
modules.alpha = railPlugin("alpha");
|
||||||
|
plugins = [summary("login"), summary("alpha")];
|
||||||
|
|
||||||
|
let releasePreLogin: (value: Response) => void = () => {};
|
||||||
|
vi.spyOn(globalThis, "fetch").mockImplementation(
|
||||||
|
() =>
|
||||||
|
new Promise<Response>((resolve) => {
|
||||||
|
releasePreLogin = resolve;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const preLogin = startPreLoginPlugins();
|
||||||
|
await startPluginRuntime();
|
||||||
|
releasePreLogin(new Response(JSON.stringify([summary("login")])));
|
||||||
|
await preLogin;
|
||||||
|
|
||||||
|
expect(isPluginFrontendActive("login")).toBe(true);
|
||||||
|
expect(isPluginFrontendActive("alpha")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores a pre-login load started after sign-in", async () => {
|
||||||
|
modules.login = railPlugin("login");
|
||||||
|
modules.alpha = railPlugin("alpha");
|
||||||
|
plugins = [summary("login"), summary("alpha")];
|
||||||
|
vi.spyOn(globalThis, "fetch").mockImplementation(
|
||||||
|
async () => new Response(JSON.stringify([summary("login")])),
|
||||||
|
);
|
||||||
|
|
||||||
|
await startPluginRuntime();
|
||||||
|
await startPreLoginPlugins();
|
||||||
|
|
||||||
|
expect(isPluginFrontendActive("alpha")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("settles even when the plugin list cannot be fetched", async () => {
|
it("settles even when the plugin list cannot be fetched", async () => {
|
||||||
vi.spyOn(console, "error").mockImplementation(() => {});
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
||||||
configurePluginLoader({
|
configurePluginLoader({
|
||||||
|
|||||||
Reference in new issue
Block a user