From 3847ef4269e8edaf43f9d510e9b58bdbbbcb1e14 Mon Sep 17 00:00:00 2001 From: StroepWafel <109832156+StroepWafel@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:11:00 +1030 Subject: [PATCH] hopefully fix the issues --- src/css/injected.scss | 13 ++-- .../globalSearch/src/indexing/actions.ts | 59 ++++++++++++++- .../globalSearch/src/indexing/indexer.ts | 27 ++++--- .../src/indexing/jobs/assignments.ts | 73 ++++++++++++------- .../src/indexing/jobs/messages.ts | 31 ++++---- .../src/indexing/jobs/notifications.ts | 32 ++++---- src/plugins/core/dynamicLoader.ts | 12 ++- 7 files changed, 176 insertions(+), 71 deletions(-) diff --git a/src/css/injected.scss b/src/css/injected.scss index b5e6018f..adeca69e 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -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 { diff --git a/src/plugins/built-in/globalSearch/src/indexing/actions.ts b/src/plugins/built-in/globalSearch/src/indexing/actions.ts index ddf28387..2838e49e 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/actions.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/actions.ts @@ -59,7 +59,9 @@ export const actionMap: Record> = { }) as ActionHandler, 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> = { 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, diff --git a/src/plugins/built-in/globalSearch/src/indexing/indexer.ts b/src/plugins/built-in/globalSearch/src/indexing/indexer.ts index de00fff7..58ad9a86 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/indexer.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/indexer.ts @@ -396,18 +396,25 @@ export async function runIndexing(): Promise { 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")); } diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts index 9bd06eb7..d14d8712 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts @@ -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>(); - // 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", diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts index f3faf700..6a142c43 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts @@ -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: { diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts index ecae38f8..452bffa4 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts @@ -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: { diff --git a/src/plugins/core/dynamicLoader.ts b/src/plugins/core/dynamicLoader.ts index 75e32222..fd76b0e8 100644 --- a/src/plugins/core/dynamicLoader.ts +++ b/src/plugins/core/dynamicLoader.ts @@ -47,7 +47,17 @@ export function createLazyPlugin