Merge branch 'main' into sgunter/feat-preserve-email-on-feedback-form
This commit is contained in:
0
docs/WebSocket-Implementation-Tutorial.md
Normal file
0
docs/WebSocket-Implementation-Tutorial.md
Normal file
@@ -1,6 +1,7 @@
|
|||||||
import CourseCatalogMain from '@views/components/CourseCatalogMain';
|
import CourseCatalogMain from '@views/components/CourseCatalogMain';
|
||||||
import InjectedButton from '@views/components/injected/AddAllButton';
|
import InjectedButton from '@views/components/injected/AddAllButton';
|
||||||
import DaysCheckbox from '@views/components/injected/DaysCheckbox';
|
import DaysCheckbox from '@views/components/injected/DaysCheckbox';
|
||||||
|
import ShadedResults from '@views/components/injected/SearchResultShader';
|
||||||
import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport';
|
import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
@@ -30,3 +31,7 @@ if (support === SiteSupport.MY_UT) {
|
|||||||
if (support === SiteSupport.COURSE_CATALOG_SEARCH) {
|
if (support === SiteSupport.COURSE_CATALOG_SEARCH) {
|
||||||
renderComponent(DaysCheckbox);
|
renderComponent(DaysCheckbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (support === SiteSupport.COURSE_CATALOG_KWS) {
|
||||||
|
renderComponent(ShadedResults);
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,12 +27,10 @@ export default function HexColorEditor({ hexCode, setHexCode }: HexColorEditorPr
|
|||||||
const tagColor = pickFontColor(previewColor.slice(1) as `#${string}`);
|
const tagColor = pickFontColor(previewColor.slice(1) as `#${string}`);
|
||||||
|
|
||||||
const [localHexCode, setLocalHexCode] = React.useState(hexCode);
|
const [localHexCode, setLocalHexCode] = React.useState(hexCode);
|
||||||
const debouncedSetHexCode = useDebounce((value: string) => setHexCode(value), 500);
|
const debouncedSetHexCode = useDebounce(setHexCode, 500);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (hexCode !== localHexCode) {
|
setLocalHexCode(hexCode);
|
||||||
setLocalHexCode(hexCode);
|
|
||||||
}
|
|
||||||
}, [hexCode]);
|
}, [hexCode]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AppStoreLogo, ForkKnife, X as CloseIcon } from '@phosphor-icons/react';
|
import { AppStoreLogo, ForkKnife, X as CloseIcon } from '@phosphor-icons/react';
|
||||||
import { UT_DINING_APP_STORE_URL, UT_DINING_GOOGLE_PLAY_URL } from '@shared/util/appUrls';
|
import { UT_DINING_APP_STORE_URL } from '@shared/util/appUrls';
|
||||||
import { Button } from '@views/components/common/Button';
|
import { Button } from '@views/components/common/Button';
|
||||||
import Text from '@views/components/common/Text/Text';
|
import Text from '@views/components/common/Text/Text';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
*/
|
*/
|
||||||
const WHATSNEW_POPUP_VERSION = 2;
|
const WHATSNEW_POPUP_VERSION = 2;
|
||||||
|
|
||||||
const WHATSNEW_VIDEO_URL = 'https://cdn.longhorns.dev/whats-new-v2.1.2.mp4';
|
// const WHATSNEW_VIDEO_URL = 'https://cdn.longhorns.dev/whats-new-v2.1.2.mp4';
|
||||||
|
|
||||||
type Feature = {
|
type Feature = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -60,7 +60,7 @@ const NEW_FEATURES = [
|
|||||||
* @returns A JSX of WhatsNewPopupContent component.
|
* @returns A JSX of WhatsNewPopupContent component.
|
||||||
*/
|
*/
|
||||||
export default function WhatsNewPopupContent(): JSX.Element {
|
export default function WhatsNewPopupContent(): JSX.Element {
|
||||||
const [videoError, setVideoError] = useState(false);
|
const [videoError, _setVideoError] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex flex-row justify-between'>
|
<div className='w-full flex flex-row justify-between'>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
||||||
import { background } from '@shared/messages';
|
import { background } from '@shared/messages';
|
||||||
import { validateLoginStatus } from '@shared/util/checkLoginStatus';
|
|
||||||
import { Button } from '@views/components/common/Button';
|
import { Button } from '@views/components/common/Button';
|
||||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||||
import useSchedules from '@views/hooks/useSchedules';
|
import useSchedules from '@views/hooks/useSchedules';
|
||||||
@@ -43,6 +42,8 @@ export default function InjectedButton(): JSX.Element | null {
|
|||||||
await addCourseByURL(activeSchedule, a);
|
await addCourseByURL(activeSchedule, a);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// We'll allow the alert for this WIP feature
|
||||||
|
// eslint-disable-next-line no-alert
|
||||||
window.alert('Logged into UT Registrar.');
|
window.alert('Logged into UT Registrar.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
39
src/views/components/injected/SearchResultShader.tsx
Normal file
39
src/views/components/injected/SearchResultShader.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
// @TODO Get a better name for this class
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The existing search results (kws), only with alternate shading for easier readability
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export default function ShadedResults(): null {
|
||||||
|
useEffect(() => {
|
||||||
|
const table = document.getElementById('kw_results_table');
|
||||||
|
if (!table) {
|
||||||
|
console.error('Results table not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tbody = table.querySelector('tbody');
|
||||||
|
if (!tbody) {
|
||||||
|
console.error('Table tbody not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
#kw_results_table tbody tr:nth-child(even) {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
}
|
||||||
|
#kw_results_table tbody tr:nth-child(even) td {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
style.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -1,16 +1,13 @@
|
|||||||
// import addCourse from '@pages/background/lib/addCourse';
|
// import addCourse from '@pages/background/lib/addCourse';
|
||||||
import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
||||||
import { deleteAllSchedules } from '@pages/background/lib/deleteSchedule';
|
import { deleteAllSchedules } from '@pages/background/lib/deleteSchedule';
|
||||||
import exportSchedule from '@pages/background/lib/exportSchedule';
|
|
||||||
import importSchedule from '@pages/background/lib/importSchedule';
|
import importSchedule from '@pages/background/lib/importSchedule';
|
||||||
import { CalendarDots, Trash } from '@phosphor-icons/react';
|
import { CalendarDots, Trash } from '@phosphor-icons/react';
|
||||||
import { background } from '@shared/messages';
|
import { background } from '@shared/messages';
|
||||||
import { DevStore } from '@shared/storage/DevStore';
|
import { DevStore } from '@shared/storage/DevStore';
|
||||||
import { initSettings, OptionsStore } from '@shared/storage/OptionsStore';
|
import { initSettings, OptionsStore } from '@shared/storage/OptionsStore';
|
||||||
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
|
|
||||||
import { CRX_PAGES } from '@shared/types/CRXPages';
|
import { CRX_PAGES } from '@shared/types/CRXPages';
|
||||||
import MIMEType from '@shared/types/MIMEType';
|
import MIMEType from '@shared/types/MIMEType';
|
||||||
import { downloadBlob } from '@shared/util/downloadBlob';
|
|
||||||
// import { addCourseByUrl } from '@shared/util/courseUtils';
|
// import { addCourseByUrl } from '@shared/util/courseUtils';
|
||||||
// import { getCourseColors } from '@shared/util/colors';
|
// import { getCourseColors } from '@shared/util/colors';
|
||||||
// import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
|
// import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import WhatsNewPopupContent from '@views/components/common/WhatsNewPopup';
|
|||||||
import { useDialog } from '@views/contexts/DialogContext';
|
import { useDialog } from '@views/contexts/DialogContext';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { LogoIcon } from '../components/common/LogoIcon';
|
// import useChangelog from './useChangelog';
|
||||||
import useChangelog from './useChangelog';
|
|
||||||
|
|
||||||
const LDIconURL = new URL('/src/assets/LD-icon-new.png', import.meta.url).href;
|
const LDIconURL = new URL('/src/assets/LD-icon-new.png', import.meta.url).href;
|
||||||
|
|
||||||
@@ -17,8 +16,8 @@ const LDIconURL = new URL('/src/assets/LD-icon-new.png', import.meta.url).href;
|
|||||||
*/
|
*/
|
||||||
export default function useWhatsNewPopUp(): () => void {
|
export default function useWhatsNewPopUp(): () => void {
|
||||||
const showDialog = useDialog();
|
const showDialog = useDialog();
|
||||||
const showChangeLog = useChangelog();
|
// const showChangeLog = useChangelog();
|
||||||
const { version } = chrome.runtime.getManifest();
|
// const { version } = chrome.runtime.getManifest();
|
||||||
|
|
||||||
const showPopUp = () => {
|
const showPopUp = () => {
|
||||||
showDialog(close => ({
|
showDialog(close => ({
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const SiteSupport = {
|
|||||||
MY_UT: 'MY_UT',
|
MY_UT: 'MY_UT',
|
||||||
COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH',
|
COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH',
|
||||||
CLASSLIST: 'CLASSLIST',
|
CLASSLIST: 'CLASSLIST',
|
||||||
|
COURSE_CATALOG_KWS: 'COURSE_CATALOG_KWS',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +41,9 @@ export default function getSiteSupport(url: string): SiteSupportType | null {
|
|||||||
return SiteSupport.UT_PLANNER;
|
return SiteSupport.UT_PLANNER;
|
||||||
}
|
}
|
||||||
if (url.includes('utdirect.utexas.edu/apps/registrar/course_schedule')) {
|
if (url.includes('utdirect.utexas.edu/apps/registrar/course_schedule')) {
|
||||||
|
if (url.includes('kws_results')) {
|
||||||
|
return SiteSupport.COURSE_CATALOG_KWS;
|
||||||
|
}
|
||||||
if (url.includes('results')) {
|
if (url.includes('results')) {
|
||||||
return SiteSupport.COURSE_CATALOG_LIST;
|
return SiteSupport.COURSE_CATALOG_LIST;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user