perf: reduce startup work and fix grade analytics bar chart animation

Batch settings storage writes, tier plugin startup, lazy-load heavy UI
chunks, and optimize global search indexing. Stop tweening bar height in
grade analytics to prevent invalid negative SVG rect values.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-17 10:50:26 +09:30
parent 62ed702e64
commit d10fca6c0f
41 changed files with 919 additions and 537 deletions
+76 -66
View File
@@ -16,10 +16,12 @@ import { updateAllColors } from "./colors/Manager";
import { delay } from "@/seqta/utils/delay";
let cachedUserInfo: any = null;
let userInfoFetchPromise: Promise<any> | null = null;
let userInfoCacheListenersAttached = false;
export function invalidateCachedUserInfo(): void {
cachedUserInfo = null;
userInfoFetchPromise = null;
}
function attachUserInfoCacheInvalidation(): void {
@@ -48,44 +50,61 @@ export async function getUserInfo(options?: { validateSession?: boolean }) {
return cachedUserInfo;
}
try {
const response = await fetch(`${location.origin}/seqta/student/login`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({
mode: "normal",
query: null,
redirect_url: location.origin,
}),
});
if (!response.ok) {
throw new Error(`Failed to get user info: HTTP ${response.status}`);
}
const payload = (await response.json()).payload;
if (
cachedUserInfo &&
options?.validateSession &&
payload?.id != null &&
cachedUserInfo.id != null &&
payload.id !== cachedUserInfo.id
) {
console.warn(
"[BetterSEQTA+] Session user changed; invalidating cached user info",
);
invalidateCachedUserInfo();
}
cachedUserInfo = payload;
return cachedUserInfo;
} catch (error) {
console.error("[BetterSEQTA+] Failed to get user info:", error);
throw error;
if (userInfoFetchPromise && !options?.validateSession) {
return userInfoFetchPromise;
}
const fetchUserInfo = async () => {
try {
const response = await fetch(`${location.origin}/seqta/student/login`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({
mode: "normal",
query: null,
redirect_url: location.origin,
}),
});
if (!response.ok) {
throw new Error(`Failed to get user info: HTTP ${response.status}`);
}
const payload = (await response.json()).payload;
if (
cachedUserInfo &&
options?.validateSession &&
payload?.id != null &&
cachedUserInfo.id != null &&
payload.id !== cachedUserInfo.id
) {
console.warn(
"[BetterSEQTA+] Session user changed; invalidating cached user info",
);
invalidateCachedUserInfo();
}
cachedUserInfo = payload;
return cachedUserInfo;
} catch (error) {
console.error("[BetterSEQTA+] Failed to get user info:", error);
throw error;
} finally {
if (!options?.validateSession) {
userInfoFetchPromise = null;
}
}
};
if (options?.validateSession) {
return fetchUserInfo();
}
userInfoFetchPromise = fetchUserInfo();
return userInfoFetchPromise;
}
export async function AddBetterSEQTAElements() {
@@ -115,11 +134,7 @@ export async function AddBetterSEQTAElements() {
menuList.insertBefore(fragment, menuList.firstChild);
try {
await Promise.all([
appendBackgroundToUI(),
handleUserInfo(),
handleStudentData(),
]);
await Promise.all([appendBackgroundToUI(), handleUserInfoAndStudentData()]);
} catch (error) {
console.error("[BetterSEQTA+] Failed to initialize UI elements:", error);
}
@@ -149,11 +164,26 @@ function createHomeButton(fragment: DocumentFragment, _: HTMLElement) {
);
}
async function handleUserInfo() {
async function handleUserInfoAndStudentData() {
try {
updateUserInfo(await getUserInfo());
const [userInfo, studentResponse] = await Promise.all([
getUserInfo(),
fetch(`${location.origin}/seqta/student/load/message/people`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ mode: "student" }),
}),
]);
updateUserInfo(userInfo);
await updateStudentInfo((await studentResponse.json()).payload, userInfo);
} catch (error) {
console.error("[BetterSEQTA+] Failed to handle user info:", error);
console.error(
"[BetterSEQTA+] Failed to handle user info and student data:",
error,
);
}
}
@@ -209,27 +239,7 @@ function updateUserInfo(info: {
.appendChild(document.getElementsByClassName("logout")[0]);
}
async function handleStudentData() {
try {
const response = await fetch(
`${location.origin}/seqta/student/load/message/people`,
{
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ mode: "student" }),
},
);
await updateStudentInfo((await response.json()).payload);
} catch (error) {
console.error("[BetterSEQTA+] Failed to handle student data:", error);
}
}
async function updateStudentInfo(students: any) {
const info = await getUserInfo();
async function updateStudentInfo(students: any, info: Awaited<ReturnType<typeof getUserInfo>>) {
const index = students.findIndex(
(person: any) =>
person.firstname == info.userDesc.split(" ")[0] &&
+9 -8
View File
@@ -1,26 +1,27 @@
import renderSvelte from "@/interface/main";
import Store from "@/interface/pages/store.svelte";
import { unmount } from "svelte";
let remove: () => void;
export function OpenStorePage() {
remove = renderStore();
export async function OpenStorePage(): Promise<void> {
remove = await renderStore();
}
export function renderStore() {
export async function renderStore() {
const [{ default: renderSvelte }, { default: Store }] = await Promise.all([
import("@/interface/main"),
import("@/interface/pages/store.svelte"),
]);
const container = document.querySelector("#container");
if (!container) {
throw new Error("Container not found");
}
// Avoid stacking multiple store roots if opened repeatedly without close.
document.getElementById("store")?.remove();
const child = document.createElement("div");
child.id = "store";
container!.appendChild(child);
container.appendChild(child);
const shadow = child.attachShadow({ mode: "open" });
const app = renderSvelte(Store, shadow);