hopefully fix the issues

This commit is contained in:
StroepWafel
2026-01-22 17:11:00 +10:30
parent f0d0068a2e
commit 3847ef4269
7 changed files with 176 additions and 71 deletions
+7 -6
View File
@@ -1,5 +1,6 @@
@use "sass:meta";
@import url("https://fonts.googleapis.com/css?family=Rubik:300,400,500,600");
// Removed Google Fonts import - Firefox blocks external resources
// Using system font stack instead: Rubik -> system-ui -> sans-serif
@include meta.load-css("injected/sidebar-animation.scss");
@include meta.load-css("injected/theme.scss");
@@ -9,7 +10,7 @@
background: var(--better-main) !important;
--navy: #1a1a1a !important;
--auto-background: var(--better-pale, var(--background-secondary)) !important;
font-family: Rubik, sans-serif !important;
font-family: Rubik, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
}
::view-transition-old(root),
@@ -36,7 +37,7 @@ body,
.legacy-root option,
.legacy-root .input,
html {
font-family: Rubik, sans-serif !important;
font-family: Rubik, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
}
/* Ensure native select dropdowns are readable on Windows */
@@ -58,7 +59,7 @@ select {
background: var(--auto-background) !important;
}
:root * {
font-family: Rubik, sans-serif !important;
font-family: Rubik, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
--theme-fg-parts: white;
}
.extension-editor {
@@ -307,7 +308,7 @@ select {
.material-icons {
font-size: 0px !important;
font-family: Rubik, sans-serif !important;
font-family: Rubik, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
&::before {
font-size: 18px !important;
content: "Search" !important;
@@ -423,7 +424,7 @@ ul.magicDelete > li.deleting {
background: var(--better-main) !important;
color: var(--text-color);
border-right: none;
font-family: Rubik, sans-serif !important;
font-family: Rubik, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
}
#menu li > label > svg,
#menu section > label > svg {
@@ -59,7 +59,9 @@ export const actionMap: Record<string, ActionHandler<any>> = {
}) as ActionHandler<any>,
assessment: (async (item: IndexItem & { metadata: AssessmentMetadata }) => {
if (item.metadata.isMessageBased) {
console.debug("[Assessment Action] Navigating to assessment:", item.id, item.metadata);
if (item.metadata?.isMessageBased) {
window.location.hash = `#?page=/messages`;
await waitForElm('[class*="Viewer__Viewer___"] > div', true, 20);
@@ -69,7 +71,60 @@ export const actionMap: Record<string, ActionHandler<any>> = {
selected: new Set([item.metadata.messageId]),
});
} else {
window.location.hash = `#?page=/assessments&id=${item.metadata.assessmentId}`;
// Use the correct URL format: /assessments/{programmeId}:{metaclassId}&item={assessmentId}
// Convert to numbers to handle string/number inconsistencies
let programmeId = item.metadata?.programmeId;
let metaclassId = item.metadata?.metaclassId;
let assessmentId = item.metadata?.assessmentId;
// Fallback: try to extract assessmentId from item ID if metadata is missing
if (!assessmentId && item.id && item.id.startsWith('assignment-')) {
const extractedId = item.id.replace('assignment-', '');
assessmentId = Number(extractedId) || extractedId;
console.debug("[Assessment Action] Extracted assessmentId from item ID:", assessmentId);
}
// Convert to numbers for consistency
programmeId = Number(programmeId) || programmeId;
metaclassId = Number(metaclassId) || metaclassId;
assessmentId = Number(assessmentId) || assessmentId;
// Check if values exist (including 0, which is a valid ID)
const hasProgrammeId = programmeId !== undefined && programmeId !== null && programmeId !== '';
const hasMetaclassId = metaclassId !== undefined && metaclassId !== null && metaclassId !== '';
const hasAssessmentId = assessmentId !== undefined && assessmentId !== null && assessmentId !== '';
if (hasProgrammeId && hasMetaclassId && hasAssessmentId) {
const url = `#?page=/assessments/${programmeId}:${metaclassId}&item=${assessmentId}`;
console.debug("[Assessment Action] Navigating to:", url, {
programmeId,
metaclassId,
assessmentId,
rawMetadata: item.metadata,
});
window.location.hash = url;
} else {
// Fallback: try to navigate to assessments page if metadata is incomplete
console.warn("[Assessment Action] Missing required metadata:", {
programmeId,
metaclassId,
assessmentId,
hasProgrammeId,
hasMetaclassId,
hasAssessmentId,
fullMetadata: item.metadata,
itemId: item.id,
itemKeys: Object.keys(item),
});
// If we at least have an assessmentId, try to navigate to the general assessments page
// The user can then find it manually
if (hasAssessmentId) {
console.info("[Assessment Action] Attempting to navigate to assessments page with item filter");
window.location.hash = `#?page=/assessments/upcoming&item=${assessmentId}`;
} else {
window.location.hash = `#?page=/assessments/upcoming`;
}
}
}
}) as ActionHandler<any>,
@@ -396,18 +396,25 @@ export async function runIndexing(): Promise<void> {
stopHeartbeat();
allItemsInPrimaryStores = await loadAllStoredItems();
allItemsInPrimaryStores.forEach(item => {
const jobDef = jobs[item.category] || Object.values(jobs).find(j => j.id === item.category) || jobs[item.renderComponentId];
if (jobDef) {
const renderComponent = renderComponentMap[jobDef.renderComponentId];
if (renderComponent) {
item.renderComponent = renderComponent;
}
} else if (renderComponentMap[item.renderComponentId]) {
item.renderComponent = renderComponentMap[item.renderComponentId];
// Create new objects to avoid XrayWrapper issues in Firefox
const itemsWithComponents = allItemsInPrimaryStores.map(item => {
try {
const jobDef = jobs[item.category] || Object.values(jobs).find(j => j.id === item.category) || jobs[item.renderComponentId];
let renderComponent = item.renderComponent;
if (jobDef) {
renderComponent = renderComponentMap[jobDef.renderComponentId] || renderComponent;
} else if (renderComponentMap[item.renderComponentId]) {
renderComponent = renderComponentMap[item.renderComponentId];
}
// Create a new object instead of modifying the existing one
return { ...item, renderComponent };
} catch (error) {
// Fallback: return item as-is if modification fails (Firefox XrayWrapper)
console.warn("[Indexer] Failed to add render component to item (Firefox XrayWrapper):", error);
return item;
}
});
loadDynamicItems(allItemsInPrimaryStores);
loadDynamicItems(itemsWithComponents);
window.dispatchEvent(new Event("dynamic-items-updated"));
}
@@ -46,10 +46,27 @@ const fetchPastAssessments = async (student: number = 69, subjects: any[]) => {
programme: subject.programme,
});
if (res.payload && Array.isArray(res.payload)) {
// Past assessments API returns data in payload.tasks, not payload directly
if (res.payload && res.payload.tasks && Array.isArray(res.payload.tasks)) {
res.payload.tasks.forEach((assessment: any) => {
if (assessment && assessment.id) {
// Ensure programme and metaclass are included from the subject
map[assessment.id] = {
...assessment,
programme: assessment.programme || assessment.programmeID || subject.programme,
metaclass: assessment.metaclass || assessment.metaclassID || subject.metaclass,
};
}
});
} else if (res.payload && Array.isArray(res.payload)) {
// Fallback: some APIs might return array directly
res.payload.forEach((assessment: any) => {
if (assessment && assessment.id) {
map[assessment.id] = assessment;
map[assessment.id] = {
...assessment,
programme: assessment.programme || assessment.programmeID || subject.programme,
metaclass: assessment.metaclass || assessment.metaclassID || subject.metaclass,
};
}
});
}
@@ -139,7 +156,13 @@ export const assignmentsJob: Job = {
upcoming.forEach((a: any) => {
if (a && a.id) {
allAssessments.set(a.id, { ...a, isUpcoming: true });
// Normalize field names - handle both programme/programmeID and metaclass/metaclassID
allAssessments.set(a.id, {
...a,
programme: a.programme || a.programmeID,
metaclass: a.metaclass || a.metaclassID,
isUpcoming: true,
});
}
});
@@ -161,22 +184,10 @@ export const assignmentsJob: Job = {
const assessmentArray = Array.from(allAssessments.values());
const batchSize = 15; // Increased batch size for better performance
// Only fetch details for upcoming assignments to reduce API calls
const upcomingAssessments = assessmentArray.filter(a => a.isUpcoming);
// Skip fetching assessment details - the API endpoint doesn't exist or returns 404
// Details are optional and not critical for search functionality
const detailPromises = new Map<string, Promise<string | null>>();
// Pre-fetch details for upcoming assessments only (most important)
for (const assessment of upcomingAssessments.slice(0, 20)) {
if (assessment.metaclass && assessment.programme) {
const id = `assignment-${assessment.id}`;
detailPromises.set(id, fetchAssessmentDetails(
assessment.id,
assessment.metaclass,
assessment.programme,
));
}
}
// Process all assessments
for (let i = 0; i < assessmentArray.length; i += batchSize) {
const batch = assessmentArray.slice(i, i + batchSize);
@@ -191,16 +202,27 @@ export const assignmentsJob: Job = {
processedIds.add(id);
// Only fetch details for upcoming assignments (already pre-fetched)
let description = "";
const detailPromise = detailPromises.get(id);
if (detailPromise) {
description = (await detailPromise) || "";
}
// Skip fetching details - API endpoint doesn't exist
const description = "";
const subjectName = assessment.subject || assessment.code || "Unknown Subject";
const dueDate = assessment.due ? new Date(assessment.due).getTime() : null;
// Normalize programme and metaclass IDs - handle both camelCase and PascalCase
const programmeId = assessment.programme || assessment.programmeID;
const metaclassId = assessment.metaclass || assessment.metaclassID;
// Validate that we have the required IDs for navigation
if (!programmeId || !metaclassId || !assessment.id) {
console.warn(`[Assignments job] Skipping assignment ${assessment.id} - missing required IDs:`, {
programmeId,
metaclassId,
assessmentId: assessment.id,
assessment,
});
return null;
}
const item: IndexItem = {
id,
text: assessment.title || assessment.name || "Untitled Assignment",
@@ -212,11 +234,12 @@ export const assignmentsJob: Job = {
subject: subjectName,
subjectCode: assessment.code,
dueDate: assessment.due,
programmeId: assessment.programme,
metaclassId: assessment.metaclass,
programmeId: Number(programmeId) || programmeId, // Ensure it's a number
metaclassId: Number(metaclassId) || metaclassId, // Ensure it's a number
submitted: assessment.submitted || false,
isUpcoming: assessment.isUpcoming || false,
term: assessment.term,
timestamp: assessment.due || new Date().toISOString(), // Required by AssessmentMetadata interface
},
actionId: "assessment",
renderComponentId: "assessment",
@@ -604,22 +604,27 @@ export const messagesJob: Job = {
if (processedItems.length > 0) {
try {
const currentItems = await loadAllStoredItems();
currentItems.forEach((item) => {
const jobDef =
jobs[item.category] ||
Object.values(jobs).find((j) => j.id === item.category) ||
jobs[item.renderComponentId];
if (jobDef) {
const renderComponent =
renderComponentMap[jobDef.renderComponentId];
if (renderComponent) {
item.renderComponent = renderComponent;
// Create new objects to avoid XrayWrapper issues in Firefox
const itemsWithComponents = currentItems.map((item) => {
try {
const jobDef =
jobs[item.category] ||
Object.values(jobs).find((j) => j.id === item.category) ||
jobs[item.renderComponentId];
let renderComponent = item.renderComponent;
if (jobDef) {
renderComponent = renderComponentMap[jobDef.renderComponentId] || renderComponent;
} else if (renderComponentMap[item.renderComponentId]) {
renderComponent = renderComponentMap[item.renderComponentId];
}
} else if (renderComponentMap[item.renderComponentId]) {
item.renderComponent = renderComponentMap[item.renderComponentId];
// Create a new object instead of modifying the existing one
return { ...item, renderComponent };
} catch (error) {
// Fallback: return item as-is if modification fails (Firefox XrayWrapper)
return item;
}
});
loadDynamicItems(currentItems);
loadDynamicItems(itemsWithComponents);
window.dispatchEvent(
new CustomEvent("dynamic-items-updated", {
detail: {
@@ -372,23 +372,27 @@ export const notificationsJob: Job = {
if (items.length > 0) {
try {
const currentItems = await loadAllStoredItems();
currentItems.forEach((item) => {
const jobDef =
jobs[item.category] ||
Object.values(jobs).find((j) => j.id === item.category) ||
jobs[item.renderComponentId];
if (jobDef) {
const renderComponent =
renderComponentMap[jobDef.renderComponentId];
if (renderComponent) {
item.renderComponent = renderComponent;
// Create new objects to avoid XrayWrapper issues in Firefox
const itemsWithComponents = currentItems.map((item) => {
try {
const jobDef =
jobs[item.category] ||
Object.values(jobs).find((j) => j.id === item.category) ||
jobs[item.renderComponentId];
let renderComponent = item.renderComponent;
if (jobDef) {
renderComponent = renderComponentMap[jobDef.renderComponentId] || renderComponent;
} else if (renderComponentMap[item.renderComponentId]) {
renderComponent = renderComponentMap[item.renderComponentId];
}
} else if (renderComponentMap[item.renderComponentId]) {
item.renderComponent =
renderComponentMap[item.renderComponentId];
// Create a new object instead of modifying the existing one
return { ...item, renderComponent };
} catch (error) {
// Fallback: return item as-is if modification fails (Firefox XrayWrapper)
return item;
}
});
loadDynamicItems(currentItems);
loadDynamicItems(itemsWithComponents);
window.dispatchEvent(
new CustomEvent("dynamic-items-updated", {
detail: {
+11 -1
View File
@@ -47,7 +47,17 @@ export function createLazyPlugin<T extends PluginSettings = PluginSettings, S =
// Execute the actual plugin's run function
return await actualPlugin.run(api);
} catch (error) {
} catch (error: any) {
// Handle Firefox MIME type errors gracefully
if (error?.message?.includes("MIME type") || error?.message?.includes("NS_ERROR_CORRUPTED_CONTENT")) {
console.error(
`[BetterSEQTA+] Failed to load plugin "${lazyPlugin.id}" due to Firefox module loading restrictions. ` +
`This may be a build configuration issue. Error:`,
error
);
// Don't throw - allow the extension to continue functioning without this plugin
return;
}
console.error(`[BetterSEQTA+] Failed to dynamically load plugin "${lazyPlugin.id}":`, error);
throw error;
}