Compare commits
54 Commits
v2.1.1
...
derek/wall
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a67a32e4f | ||
|
|
549c52a39f | ||
|
|
36007b9d1a | ||
| cee5f0284f | |||
|
|
e8a8b8e1ae | ||
|
|
c21cbd77f0 | ||
| 99a035e29d | |||
|
|
64baa6d290 | ||
|
|
46fe591fa7 | ||
|
|
8f7e1bc0af | ||
|
|
9fc1098ef7 | ||
|
|
ae094416fc | ||
|
|
2e7dac1e3e | ||
|
|
7bea23a655 | ||
|
|
3d28869e92 | ||
|
|
f0f1f0b365 | ||
| be861b823c | |||
|
|
95de8df372 | ||
| 5994ded8be | |||
|
|
7b401add15 | ||
|
|
2d92dd47f0 | ||
|
|
eb8141ee8c | ||
|
|
2a50f5580d | ||
|
|
65bfb1d129 | ||
|
|
234f3d627d | ||
|
|
be1dccfcb9 | ||
|
|
454e5e807a | ||
|
|
29d20d5c5a | ||
|
|
e29546c727 | ||
|
|
5a89be6238 | ||
|
|
cfb5faa09b | ||
| 37471efb74 | |||
|
|
7a4f40a765 | ||
|
|
d11d55db66 | ||
|
|
76b6aa7c15 | ||
|
|
70d4fecad6 | ||
|
|
c3fa91752c | ||
|
|
7c2beef193 | ||
|
|
630d0d80d2 | ||
|
|
695743104c | ||
|
|
d014244b28 | ||
|
|
5cd56259f7 | ||
|
|
fa9f78b46e | ||
|
|
4a5f67f0fd | ||
|
|
3bed9cc27f | ||
|
|
0dcae25b93 | ||
|
|
ca734dcd39 | ||
|
|
9448072112 | ||
|
|
b1e98ca9d7 | ||
|
|
f036d409e6 | ||
|
|
5493c63f18 | ||
|
|
6c3139bf0f | ||
|
|
28ebb69612 | ||
|
|
008cb40cb8 |
@@ -7,3 +7,6 @@ insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
|
||||
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
SENTRY_ORG=longhorn-developers
|
||||
SENTRY_PROJECT=ut-registration-plus
|
||||
SENTRY_AUTH_TOKEN=
|
||||
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,9 +1,10 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: '[BUG] '
|
||||
labels: 'bug'
|
||||
title: "[BUG] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Pre-submission Checklist**
|
||||
|
||||
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,9 +1,10 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: '[FEATURE] '
|
||||
labels: 'feature'
|
||||
title: "[FEATURE] "
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Pre-submission Checklist**
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/updating-build-dependencies.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/updating-build-dependencies.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: Updating Build Dependencies
|
||||
about: Updating Build Dependencies
|
||||
title: ''
|
||||
labels: build, dependencies
|
||||
assignees: doprz, Razboy20
|
||||
|
||||
---
|
||||
|
||||
- [ ] Updated Nix Flake
|
||||
- [ ] Update Dockerfile
|
||||
- [ ] Update Docs
|
||||
21
.github/dependabot.yml
vendored
Normal file
21
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
day: 'monday'
|
||||
time: '09:00'
|
||||
timezone: 'America/Chicago'
|
||||
groups:
|
||||
minor-and-patch-updates:
|
||||
update-types:
|
||||
- 'minor'
|
||||
- 'patch'
|
||||
major-updates:
|
||||
update-types:
|
||||
- 'major'
|
||||
|
||||
ignore:
|
||||
- dependency-name: '@crxjs/vite-plugin'
|
||||
- dependency-name: '@unocss/vite'
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -211,3 +211,5 @@ sketch
|
||||
package-lock.json
|
||||
storybook-static/
|
||||
package/
|
||||
|
||||
.direnv/
|
||||
|
||||
660
CHANGELOG.md
660
CHANGELOG.md
@@ -1,346 +1,390 @@
|
||||
## [2.2.2](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.2.1...v2.2.2) (2025-10-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add nix flake ([#593](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/593)) ([7b401ad](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7b401add1565ff401bad99745ff9e53b9a7f899f))
|
||||
* automatically select new or duplicated schedules ([#583](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/583)) ([#589](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/589)) ([2a50f55](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a50f5580d3dbeb0d66546c23cf29bbb37d80da2))
|
||||
* **env:** add SENTRY env vars ([8f7e1bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8f7e1bc0af6336549068e02b80df21d4e8f4ef9c))
|
||||
* export schedule button add to calendar ([#594](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/594)) ([5994ded](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5994ded8be876cb55174d27d3fdb0832b21a0ff9))
|
||||
* search result shading ([#617](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/617)) ([be861b8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be861b823cb2cb7f6f4a1f266351eec3fc1c2f99))
|
||||
* show warning for courses of different semesters ([#570](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/570)) ([2e7dac1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2e7dac1e3eba757231ac07ac966231c08c703a16))
|
||||
* support summer grades, fix summer course parser ([#596](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/596)) ([2d92dd4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d92dd47f00a44b7d48e92a8ffba94480e4e73f9))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix or ignore various eslint warning ([#609](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/609)) ([95de8df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95de8df37243b6d59625df515a60442f11b7a9d3))
|
||||
* limit height of schedule list dropdown in the extension popup ([#543](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/543)) ([eb8141e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eb8141ee8c3d32bce901457178d50781b78f86dd))
|
||||
* whitespace wrapping in semester warning ([#629](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/629)) ([46fe591](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46fe591fa72ef017eea7cfb8aa37d12d8f223926))
|
||||
## [2.2.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.2.0...v2.2.1) (2025-06-04)
|
||||
|
||||
### Features
|
||||
|
||||
* add dining app promo ([#598](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/598)) ([be1dccf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be1dccfcb9d052c6b291b50cc53418d6bb645beb))
|
||||
* inside jokes005 ([#590](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/590)) ([37471ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37471efb740c7a5828cf3b54bac70954694359d7))
|
||||
* **release:** v2.2.1 ([234f3d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/234f3d627d603adf8555b4d0e93106d198918169))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* course columns on calendar ([#587](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/587)) ([cfb5faa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cfb5faa09bb0788e270d100f1f36536a53bcff75))
|
||||
* hide sentry instrumentation on debug builds ([#604](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/604)) ([454e5e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/454e5e807af29ae0384cc3a3b8b691df5edc69d1))
|
||||
## [2.2.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.1...v2.2.0) (2025-04-06)
|
||||
|
||||
### Features
|
||||
|
||||
* auto create empty schedule when deleted all schedules ([#552](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/552)) ([7c2beef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7c2beef1930fbc887e8ec1aea789016b3150cd21))
|
||||
* ensure unique splash text on schedule change ([#554](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/554)) ([9448072](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94480721124e052426c1f3236e8605c7088df79c))
|
||||
* implement a What's New prompt ([#539](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/539)) ([f036d40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f036d409e60a39fd1d3cb2f0db53a6056615f336))
|
||||
* persist sidebar toggle state ([#569](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/569)) ([6957431](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/695743104c57951ba1957258c60c843f8fae793f))
|
||||
* recruitment banner for designer ([#578](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/578)) ([70d4fec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/70d4fecad61ec3cd3ba839de302fd851e075d073))
|
||||
* **release:** v2.2.0 ([7a4f40a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a4f40a765d704bf32a3b515d695916ed84f9397))
|
||||
* rework start time to checkboxes ([#553](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/553)) ([ca734dc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca734dcd39a433cfd2e930ea04adeba959b32c36))
|
||||
* sticky calendar header and days ([#568](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/568)) ([fa9f78b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa9f78b46e3a2270a44d4cc0691195a7c695cb93))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ics calendar export dates ([#535](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/535)) ([4a5f67f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4a5f67f0fda9f0ef57f821e4b7a55d63f099f579))
|
||||
* include logo in screenshot, fix screenshots on small/zoomed windows ([#579](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/579)) ([76b6aa7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/76b6aa7c150299dfcfa4b3dc00ce2de32f90f75c))
|
||||
* merge course labels across pages ([#541](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/541)) ([6c3139b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6c3139bf0f324c9a7be826b6c24e8bf142fc53b1))
|
||||
* **schedule:** truncate long schedule names in popup ([#564](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/564)) ([3bed9cc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3bed9cc27febfe795af0766a913c4845e74cc2da))
|
||||
## [2.1.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.0...v2.1.1) (2025-03-03)
|
||||
|
||||
### Features
|
||||
|
||||
- add isDeveloper ([c6452c4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6452c4f2b174487e6f51ad546ca1c3f8b4dbc1f))
|
||||
- map page ([#390](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/390)) ([2184774](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/218477404fdeacda7b39cd233e4e1e65995935d4))
|
||||
* add isDeveloper ([c6452c4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6452c4f2b174487e6f51ad546ca1c3f8b4dbc1f))
|
||||
* map page ([#390](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/390)) ([2184774](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/218477404fdeacda7b39cd233e4e1e65995935d4))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- import schedule file upload button ([#515](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/515)) ([766c0bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/766c0bc1b4a75f8146a922cb2eca8871032c1dc9))
|
||||
|
||||
* import schedule file upload button ([#515](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/515)) ([766c0bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/766c0bc1b4a75f8146a922cb2eca8871032c1dc9))
|
||||
## [2.1.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.2...v2.1.0) (2025-02-20)
|
||||
|
||||
### Features
|
||||
|
||||
- add 'new search' link to the course catalog page ([#456](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/456)) ([ca5e4c1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca5e4c13d31aeb603660972536712ea161c6f870))
|
||||
- add 404 page ([#426](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/426)) ([46c76b1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46c76b1703ea2344c3330c4cfa82560663be1c4c))
|
||||
- add CacheStore for GitHub stats and use names instead of usernames ([#405](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/405)) ([b732a80](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b732a80eaa6f6cbf5b627ffc31ab321de3a8e8f4))
|
||||
- add eslint-plugin-tsdoc ([#430](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/430)) ([e987fbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e987fbbe8e733de6767d62811c2d4d6eaccf2d24))
|
||||
- add explanation to grade distribution ([#325](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/325)) ([9ad3239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ad32390d13e1d413ca01b1bc45d02c695bc23dd))
|
||||
- add open calendar button ([#457](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/457)) ([93733e3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93733e37214f00543479e77209ca03864776a1a6))
|
||||
- add spacing system ([#474](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/474)) ([e61ab56](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e61ab565c35a197609d205adcaac9c7ffe0fc6da))
|
||||
- **build:** add Docker support ([#322](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/322)) ([a5e921f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e921fd75109a50f17d05c9682e73ba246f3dd1))
|
||||
- **build:** add vite-build-logger ([#507](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/507)) ([1aa4e8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1aa4e8c5fb2d1aea308e4cccea3e2818a9c946ec))
|
||||
- **build:** refactor gulpfile to use gulp-execa ([#323](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/323)) ([db04bbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db04bbb52e4ab19730dd66f417e68ab013ce2f79))
|
||||
- export/import functionality (backup/restore/share with friends) + a new input component ([#433](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/433)) ([7dbffc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dbffc6eef346747042f1596da627ad0a2fcae1a))
|
||||
- injected button - add all courses from MyUT AND passing URL to handler ([#291](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/291)) ([c41467c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c41467c6176d31f70cd3ecdcf56eeb73696c6c23))
|
||||
- modify Course Block text style and time and location text ([#409](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/409)) ([0d51cae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d51cae4c8b27201b09c0898f4d7a6e7abb3c100))
|
||||
- **settings:** add option to always open calendar in new tab ([#488](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/488)) ([009de62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/009de628285ce9c6571e492f8e3f52cdeeed4459))
|
||||
- **settings:** allow disabling of auto-loading courses ([#489](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/489)) ([b74c698](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b74c698866c1074ce2236ede549c94555667e6a5))
|
||||
- **ui:** add schedule list icons ([#500](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/500)) ([f0b257a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f0b257aa124a8fff0bb31e3396715aecb09948d5))
|
||||
- **ui:** added shadows to popup buttons and course blocks ([#378](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/378)) ([a20332e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a20332e53da9bda873fabb8395afe6ff6303799c))
|
||||
- **ui:** calendar header redesign ([#479](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/479)) ([9c766c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9c766c26959673389e372c3a440c1a73d5887b1d))
|
||||
- **ui:** calendar sidebar redesign ([#464](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/464)) ([843cb5b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/843cb5b4430885527592feee33656dfae50c95c2))
|
||||
- **ui:** change icons to phosphor-icons [#467](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/467) ([#469](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/469)) ([37bd7e7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37bd7e79d9202d55c7d0f566518526b0aed53c68))
|
||||
- **ui:** change red text when instructor not found ([#483](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/483)) ([52347fd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52347fd56dff95190915d9f375dbebe1383e76c8))
|
||||
- **ui:** color picker final touches ([#491](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/491)) ([c2328e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2328e461ea0a846f399a22bc525540da2796dcd))
|
||||
- **ui:** course color picker ([#382](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/382)) ([1f635d2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1f635d2515fc403ad7f08fc3a244a17d262e3f7b))
|
||||
- **ui:** course unique number copy button ([#490](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/490)) ([501f506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/501f50667725aa1515391869b133908b8383d868))
|
||||
- **ui:** Modify Calendar Footer design and Unscheduled courses ([#503](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/503)) ([b171f01](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b171f01d01f47c75e7df5e5c8e4e7b15b7397c52))
|
||||
- **ui:** redesign grade distribution tooltip ([#485](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/485)) ([a61bddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a61bddf0e8a76c89d4963d9e580fb063309bee92))
|
||||
- **ui:** update button variants following figma ([#482](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/482)) ([0aa469a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0aa469af81e7912a6b26ee1b80c5920f677b5fbd))
|
||||
- **ui:** update popup and course blocks ([#506](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/506)) ([ee4c6ce](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee4c6ce6999ad35821b9be5d657790f2dee017b3))
|
||||
- **ui:** update theme colors [#466](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/466) ([#473](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/473)) ([0d73b13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d73b13b288bf8b18444f26455da24c2f4acedf6))
|
||||
- update SWE list ([aa29bcf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aa29bcf9fe4bad7812336d55d7575a6032aea91c))
|
||||
- update text styles ([#468](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/468)) ([918f4e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/918f4e419cf5fa71bda1112597e9a373daca69ea)), closes [#465](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/465)
|
||||
- validate login passed to background and implemented into add all injected button ([#443](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/443)) ([cd05e5e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd05e5e7fcaa02dab30f230c178f189d8052a7c9))
|
||||
* add 'new search' link to the course catalog page ([#456](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/456)) ([ca5e4c1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca5e4c13d31aeb603660972536712ea161c6f870))
|
||||
* add 404 page ([#426](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/426)) ([46c76b1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46c76b1703ea2344c3330c4cfa82560663be1c4c))
|
||||
* add CacheStore for GitHub stats and use names instead of usernames ([#405](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/405)) ([b732a80](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b732a80eaa6f6cbf5b627ffc31ab321de3a8e8f4))
|
||||
* add eslint-plugin-tsdoc ([#430](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/430)) ([e987fbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e987fbbe8e733de6767d62811c2d4d6eaccf2d24))
|
||||
* add explanation to grade distribution ([#325](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/325)) ([9ad3239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ad32390d13e1d413ca01b1bc45d02c695bc23dd))
|
||||
* add open calendar button ([#457](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/457)) ([93733e3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93733e37214f00543479e77209ca03864776a1a6))
|
||||
* add spacing system ([#474](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/474)) ([e61ab56](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e61ab565c35a197609d205adcaac9c7ffe0fc6da))
|
||||
* **build:** add Docker support ([#322](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/322)) ([a5e921f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e921fd75109a50f17d05c9682e73ba246f3dd1))
|
||||
* **build:** add vite-build-logger ([#507](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/507)) ([1aa4e8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1aa4e8c5fb2d1aea308e4cccea3e2818a9c946ec))
|
||||
* **build:** refactor gulpfile to use gulp-execa ([#323](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/323)) ([db04bbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db04bbb52e4ab19730dd66f417e68ab013ce2f79))
|
||||
* export/import functionality (backup/restore/share with friends) + a new input component ([#433](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/433)) ([7dbffc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dbffc6eef346747042f1596da627ad0a2fcae1a))
|
||||
* injected button - add all courses from MyUT AND passing URL to handler ([#291](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/291)) ([c41467c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c41467c6176d31f70cd3ecdcf56eeb73696c6c23))
|
||||
* modify Course Block text style and time and location text ([#409](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/409)) ([0d51cae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d51cae4c8b27201b09c0898f4d7a6e7abb3c100))
|
||||
* **settings:** add option to always open calendar in new tab ([#488](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/488)) ([009de62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/009de628285ce9c6571e492f8e3f52cdeeed4459))
|
||||
* **settings:** allow disabling of auto-loading courses ([#489](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/489)) ([b74c698](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b74c698866c1074ce2236ede549c94555667e6a5))
|
||||
* **ui:** add schedule list icons ([#500](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/500)) ([f0b257a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f0b257aa124a8fff0bb31e3396715aecb09948d5))
|
||||
* **ui:** added shadows to popup buttons and course blocks ([#378](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/378)) ([a20332e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a20332e53da9bda873fabb8395afe6ff6303799c))
|
||||
* **ui:** calendar header redesign ([#479](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/479)) ([9c766c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9c766c26959673389e372c3a440c1a73d5887b1d))
|
||||
* **ui:** calendar sidebar redesign ([#464](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/464)) ([843cb5b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/843cb5b4430885527592feee33656dfae50c95c2))
|
||||
* **ui:** change icons to phosphor-icons [#467](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/467) ([#469](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/469)) ([37bd7e7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37bd7e79d9202d55c7d0f566518526b0aed53c68))
|
||||
* **ui:** change red text when instructor not found ([#483](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/483)) ([52347fd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52347fd56dff95190915d9f375dbebe1383e76c8))
|
||||
* **ui:** color picker final touches ([#491](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/491)) ([c2328e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2328e461ea0a846f399a22bc525540da2796dcd))
|
||||
* **ui:** course color picker ([#382](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/382)) ([1f635d2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1f635d2515fc403ad7f08fc3a244a17d262e3f7b))
|
||||
* **ui:** course unique number copy button ([#490](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/490)) ([501f506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/501f50667725aa1515391869b133908b8383d868))
|
||||
* **ui:** Modify Calendar Footer design and Unscheduled courses ([#503](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/503)) ([b171f01](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b171f01d01f47c75e7df5e5c8e4e7b15b7397c52))
|
||||
* **ui:** redesign grade distribution tooltip ([#485](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/485)) ([a61bddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a61bddf0e8a76c89d4963d9e580fb063309bee92))
|
||||
* **ui:** update button variants following figma ([#482](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/482)) ([0aa469a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0aa469af81e7912a6b26ee1b80c5920f677b5fbd))
|
||||
* **ui:** update popup and course blocks ([#506](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/506)) ([ee4c6ce](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee4c6ce6999ad35821b9be5d657790f2dee017b3))
|
||||
* **ui:** update theme colors [#466](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/466) ([#473](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/473)) ([0d73b13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d73b13b288bf8b18444f26455da24c2f4acedf6))
|
||||
* update SWE list ([aa29bcf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aa29bcf9fe4bad7812336d55d7575a6032aea91c))
|
||||
* update text styles ([#468](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/468)) ([918f4e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/918f4e419cf5fa71bda1112597e9a373daca69ea)), closes [#465](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/465)
|
||||
* validate login passed to background and implemented into add all injected button ([#443](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/443)) ([cd05e5e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd05e5e7fcaa02dab30f230c178f189d8052a7c9))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 4th attempt for: now able to delete schedule even if active ([#435](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/435)) ([2425679](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/24256798ba7b877dd170d77ce4970b13b8a69a68))
|
||||
- instructor formatting errors ([#425](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/425)) ([8b92208](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b922082a79ebdbf50a09f37ecb9dfea1be6e1f3))
|
||||
- place hours and courses under schedule name ([#388](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/388)) ([7dd9369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dd93690d6dbd206cb50442f42ec85d6bbfc1da8))
|
||||
- transition added ([#381](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/381)) ([598bafe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/598bafe67f47ad57b3801a425e61f86093ba2be8))
|
||||
- **ui:** fix longstanding drag-and-drop duplication issue ([#502](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/502)) ([4752f58](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4752f5860a96e08a1177c0ddf57a0fa269d89072))
|
||||
- **ui:** reduce left side grade distribution margin/padding ([#427](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/427)) ([91fa78e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91fa78e2d0532a73e24ecc013d2ba6c0f62c1fcd))
|
||||
- **ui:** stop import button dropdown from squishing ([#504](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/504)) ([846070e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/846070ebb5e13e0fc0df94666dbce75194100049))
|
||||
- updated text when time/location not provided ([#289](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/289)) ([ebcc0aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ebcc0aa76a89f0d1a9e90cfc50d70f017c9bed42))
|
||||
|
||||
* 4th attempt for: now able to delete schedule even if active ([#435](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/435)) ([2425679](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/24256798ba7b877dd170d77ce4970b13b8a69a68))
|
||||
* instructor formatting errors ([#425](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/425)) ([8b92208](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b922082a79ebdbf50a09f37ecb9dfea1be6e1f3))
|
||||
* place hours and courses under schedule name ([#388](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/388)) ([7dd9369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dd93690d6dbd206cb50442f42ec85d6bbfc1da8))
|
||||
* transition added ([#381](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/381)) ([598bafe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/598bafe67f47ad57b3801a425e61f86093ba2be8))
|
||||
* **ui:** fix longstanding drag-and-drop duplication issue ([#502](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/502)) ([4752f58](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4752f5860a96e08a1177c0ddf57a0fa269d89072))
|
||||
* **ui:** reduce left side grade distribution margin/padding ([#427](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/427)) ([91fa78e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91fa78e2d0532a73e24ecc013d2ba6c0f62c1fcd))
|
||||
* **ui:** stop import button dropdown from squishing ([#504](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/504)) ([846070e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/846070ebb5e13e0fc0df94666dbce75194100049))
|
||||
* updated text when time/location not provided ([#289](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/289)) ([ebcc0aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ebcc0aa76a89f0d1a9e90cfc50d70f017c9bed42))
|
||||
## [2.0.2](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.1...v2.0.2) (2024-11-05)
|
||||
|
||||
### Features
|
||||
|
||||
- add core curriculum chips to injected popup ([#372](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/372)) ([6f1afc5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6f1afc5b25441c6a1fbfdf57b3c8b5b74e36f5a0))
|
||||
- Add linkedin social to calendar ([#368](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/368)) ([b6eccac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b6eccaca6a2cdba9b57d2f49f064ae8504bbd5cb))
|
||||
- add more relevant links to the From the Team section ([#380](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/380)) ([643ea13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/643ea1320798aabb7783d267f5e6fd7c00fc2e3f))
|
||||
- bold course number in grade distribution chart, change text to ut-black ([#406](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/406)) ([638ee88](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/638ee88c96510a779c157b524903caaeffc9ef19))
|
||||
- disable/some actions when no instructor ([#319](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/319)) ([839f9c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/839f9c6d6afd4a1eae1a0bdf8893ab2e19b9fdff))
|
||||
- **ui:** changed popup close icon to ut-black ([#394](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/394)) ([0077ae7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0077ae70d22f24549c4c3b243188d19adbfbac14)), closes [#333F48](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/333F48)
|
||||
- update senior swe admins ([#326](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/326)) ([b967240](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b967240f8fbb7a790a78f4aa256f0a77a491abb8))
|
||||
- update useful links ([#367](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/367)) ([cef99c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cef99c2d72d3a2800f8a918d01cb116f8795d0c8))
|
||||
- use "copy of" for duplicated schedules and place them under the original schedule [#358](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/358) ([#397](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/397)) ([94744e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94744e01b94819fb4f5d64616ea56857b906c2dd))
|
||||
* add core curriculum chips to injected popup ([#372](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/372)) ([6f1afc5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6f1afc5b25441c6a1fbfdf57b3c8b5b74e36f5a0))
|
||||
* Add linkedin social to calendar ([#368](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/368)) ([b6eccac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b6eccaca6a2cdba9b57d2f49f064ae8504bbd5cb))
|
||||
* add more relevant links to the From the Team section ([#380](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/380)) ([643ea13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/643ea1320798aabb7783d267f5e6fd7c00fc2e3f))
|
||||
* bold course number in grade distribution chart, change text to ut-black ([#406](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/406)) ([638ee88](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/638ee88c96510a779c157b524903caaeffc9ef19))
|
||||
* disable/some actions when no instructor ([#319](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/319)) ([839f9c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/839f9c6d6afd4a1eae1a0bdf8893ab2e19b9fdff))
|
||||
* **ui:** changed popup close icon to ut-black ([#394](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/394)) ([0077ae7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0077ae70d22f24549c4c3b243188d19adbfbac14)), closes [#333F48](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/333F48)
|
||||
* update senior swe admins ([#326](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/326)) ([b967240](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b967240f8fbb7a790a78f4aa256f0a77a491abb8))
|
||||
* update useful links ([#367](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/367)) ([cef99c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cef99c2d72d3a2800f8a918d01cb116f8795d0c8))
|
||||
* use "copy of" for duplicated schedules and place them under the original schedule [#358](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/358) ([#397](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/397)) ([94744e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94744e01b94819fb4f5d64616ea56857b906c2dd))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- added descending sort for commits on contributor section in settings page ([#365](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/365)) ([a715bbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a715bbd933a87742e7bce3a44e8ba1bd419ad5eb)), closes [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363)
|
||||
- change schedule total courses text color to UTRP black ([#369](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/369)) ([b00bf6c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b00bf6c180f1c6c3a61c5ef855e160ddf4af3ea4))
|
||||
- changed the font-weight of h1-course ([#370](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/370)) ([4f609ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f609aeec797c1f99f0a57e5aeef7b82756ea4bc)), closes [#347](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/347)
|
||||
- ensure input elements take full width of parent ([#364](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/364)) ([c2007ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2007ef090aab3bbfcb8bca1ebc476255d09cb90))
|
||||
- remove screenshot padding class for png download for [#344](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/344) ([#376](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/376)) ([768ac77](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/768ac776ed4d5ca2113a032a93c2dc7432915aa1)), closes [#334](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/334)
|
||||
- sentry issues ([#389](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/389)) ([2d0804f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d0804f90e5d7a9ff83f7fd5c5acfdc7c1b1cc84))
|
||||
- typo in settings page ([#386](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/386)) ([d357735](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3577358d0d1fb60f2c776ae4b01e255fcf9109e))
|
||||
- **ui:** add space before/after forward slash in "ASYNC/OTHER" text ([#366](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/366)) ([86792eb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/86792eb56f04b615f7d52b2f417b88f4cb9a82ec))
|
||||
- **ui:** duplicate schedule warning ([#295](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/295)) ([7346720](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/73467208947e0116ce8538052ee75dea1d8038f9))
|
||||
- **ui:** main popup now shows 0 for empty schedule ([#395](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/395)) ([8de88d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8de88d6ad7d4c2b5c3aa08e1efc59f7226b40c6b))
|
||||
- **ui:** multiple instructors are formatted properly, displays last name only, and are capitalized in all course blocks ([#342](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/342)) ([#403](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/403)) ([50e88fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/50e88fa015e0290fbe0dab8a19f8fcdbc4dd02b0))
|
||||
- **ui:** placeholder text for no instructor course [#400](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/400) ([#402](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/402)) ([b3ae91d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b3ae91d8f3cebb89e5e5cea7f1200d28326afb4d))
|
||||
|
||||
* added descending sort for commits on contributor section in settings page ([#365](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/365)) ([a715bbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a715bbd933a87742e7bce3a44e8ba1bd419ad5eb)), closes [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363)
|
||||
* change schedule total courses text color to UTRP black ([#369](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/369)) ([b00bf6c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b00bf6c180f1c6c3a61c5ef855e160ddf4af3ea4))
|
||||
* changed the font-weight of h1-course ([#370](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/370)) ([4f609ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f609aeec797c1f99f0a57e5aeef7b82756ea4bc)), closes [#347](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/347)
|
||||
* ensure input elements take full width of parent ([#364](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/364)) ([c2007ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2007ef090aab3bbfcb8bca1ebc476255d09cb90))
|
||||
* remove screenshot padding class for png download for [#344](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/344) ([#376](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/376)) ([768ac77](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/768ac776ed4d5ca2113a032a93c2dc7432915aa1)), closes [#334](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/334)
|
||||
* sentry issues ([#389](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/389)) ([2d0804f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d0804f90e5d7a9ff83f7fd5c5acfdc7c1b1cc84))
|
||||
* typo in settings page ([#386](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/386)) ([d357735](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3577358d0d1fb60f2c776ae4b01e255fcf9109e))
|
||||
* **ui:** add space before/after forward slash in "ASYNC/OTHER" text ([#366](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/366)) ([86792eb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/86792eb56f04b615f7d52b2f417b88f4cb9a82ec))
|
||||
* **ui:** duplicate schedule warning ([#295](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/295)) ([7346720](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/73467208947e0116ce8538052ee75dea1d8038f9))
|
||||
* **ui:** main popup now shows 0 for empty schedule ([#395](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/395)) ([8de88d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8de88d6ad7d4c2b5c3aa08e1efc59f7226b40c6b))
|
||||
* **ui:** multiple instructors are formatted properly, displays last name only, and are capitalized in all course blocks ([#342](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/342)) ([#403](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/403)) ([50e88fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/50e88fa015e0290fbe0dab8a19f8fcdbc4dd02b0))
|
||||
* **ui:** placeholder text for no instructor course [#400](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/400) ([#402](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/402)) ([b3ae91d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b3ae91d8f3cebb89e5e5cea7f1200d28326afb4d))
|
||||
## [2.0.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.0...v2.0.1) (2024-10-17)
|
||||
|
||||
### Features
|
||||
|
||||
- spring 2024 instructors db ([#317](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/317)) ([79dd29c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79dd29cfc9e849b09e7d91bd0eed51c1c93b3352))
|
||||
* spring 2024 instructors db ([#317](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/317)) ([79dd29c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79dd29cfc9e849b09e7d91bd0eed51c1c93b3352))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- add a little error checking to settings ([#315](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/315)) ([e261641](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e261641e5985d8bd5047d8a0be5d1caae844e40f))
|
||||
- gulp zip ([#314](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/314)) ([05f00b2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/05f00b23d26b90f564710db4364426e90c8d6831))
|
||||
- migration loop ([aeff5e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aeff5e09a238503293c3882d97d40270da1e4883))
|
||||
- show calendar in active window ([#312](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/312)) ([ceba38b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ceba38b1ac74ec9e6630222183bd466a8d12c27d))
|
||||
|
||||
* add a little error checking to settings ([#315](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/315)) ([e261641](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e261641e5985d8bd5047d8a0be5d1caae844e40f))
|
||||
* gulp zip ([#314](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/314)) ([05f00b2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/05f00b23d26b90f564710db4364426e90c8d6831))
|
||||
* migration loop ([aeff5e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aeff5e09a238503293c3882d97d40270da1e4883))
|
||||
* show calendar in active window ([#312](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/312)) ([ceba38b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ceba38b1ac74ec9e6630222183bd466a8d12c27d))
|
||||
## [2.0.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/b4e8c7589e53f1064d70703459cc6d66fae1b04c...v2.0.0) (2024-10-15)
|
||||
|
||||
### Features
|
||||
|
||||
- abhinavchadaga/course-catalog-popup ([#128](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/128)) ([745f9dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/745f9dd6fb96ccc0eace7189b87abf9a38f03828))
|
||||
- abhinavchadaga/reusable-popup-prompt ([#148](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/148)) ([44af9e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/44af9e16e4bf3b92c9a4fa0e779197f4f9ecb237))
|
||||
- actually sum for duplicate semesters (different uniques) ([#202](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/202)) ([d3f64ec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3f64ec79eb64ebe72ae28991127dbe521823842))
|
||||
- add button to the rows, use new ConflictsWithWarning component ([bec2649](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bec2649fc1244bffb5cb03809db62cc0ea477260))
|
||||
- add buttons with icons in tailwind ([93b65ac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93b65ac2edef3fc728305cc51d1a32ecf5073274))
|
||||
- add cal save buttons (no functionality) ([53e7c7f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/53e7c7fedaf1f268d2d7d06ff1a5df9e2af2306d))
|
||||
- add Calendar Component ([e0212d5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e0212d510928e5e95d3ba75e391c34714f1bb035))
|
||||
- add Calendar schedules component (clicking on storybook not working) ([d1a336e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1a336e903f09b04b89f11ba7ede2f7d26e0ac3c))
|
||||
- add CalendarHeader and its Storybook, need to resize ([23276e5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23276e5c7c907261b1d02e9006d8021d99b43984))
|
||||
- add check-path-alias custom ESLint rule ([#123](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/123)) ([208103d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/208103d7081abcf5b31bf36335320aaf7d213464))
|
||||
- add chrome.storage api mocks for storybook use ([#141](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/141)) ([3839bff](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3839bff29ef6f0ecfad1e975e685df9a64d96c92))
|
||||
- add CSS for calendarCell div ([6cdcf49](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6cdcf4930d9868c0ed45820f66102d89a644cfb6))
|
||||
- add CSS for hourLine div ([0ba6153](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ba61534cbfc83408cb64eb1145ecacef1ee8f04))
|
||||
- add CSS for timeLabelContainer div ([56f6456](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56f6456ce85f77edb9d6fa64ecb82a8388feec41))
|
||||
- add custom ESLint rule restrict-import-depth ([#110](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/110)) ([8c069b7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8c069b7ad339ed8db97bb5e3e6e88ab8d332489b))
|
||||
- add downloadBlob util ([2af351e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2af351efa85264da5abeee27fbd091d4ce637041))
|
||||
- add empty settings component - waiting on design ([9d0f210](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d0f2105481cc3d5affdb4bd69d428379ea92de3))
|
||||
- add ImportantLinks Component ([5dbee6f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5dbee6f0c39e620c3b65a5e0156fd59ec8217ca7))
|
||||
- add List component ([e6b4049](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e6b40494031ca88894b2f918bb18448b70124481))
|
||||
- add MIMEType ([0c76052](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c760524781556cf089f1885dc4ff3fd567bfc2b))
|
||||
- add new db powered by UT_Grade_Parser ([#163](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/163)) ([60d1f48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60d1f48bd95132f0517258f017a7644d8aff5101))
|
||||
- add react-loading-skeleton package ([#244](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/244)) ([b4dd91a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4dd91ad2595d9583a60530c2c2ff6d829d2d5e5))
|
||||
- add skeleton loader for course description + distribution ([#267](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/267)) ([c2cab40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2cab407f3a07c1d3073e936c9d23cb1cecc9cb9))
|
||||
- add story for CalendarGridCell ([fd91c3b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fd91c3b12ef5670563e689d190be75ef1f695d1c))
|
||||
- add Storybook story ([cb3cb5d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cb3cb5d5fc18a68ca5a825f97b808b535aa1fe29))
|
||||
- add tailwind version of Button component ([28d93b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28d93b3c25e1cbca3baea992a299d626ca823570))
|
||||
- add tickmarks to day div ([8b9cb06](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b9cb065c28b5dd38b7e1681839a81f55691a3c6))
|
||||
- add time column to Calendar Component ([9d68211](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d6821127e7ff9bf63cef659932ee7408de4c969))
|
||||
- add timeAndGrid div ([95e0544](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95e0544b7301d382439b74038fb1b3e25dfe6d30))
|
||||
- added flag ;-; ([#195](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/195)) ([9b4d61c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9b4d61c2b0d8806b5d4a10296c1cc1266ac4229f))
|
||||
- added scrapedAt property ([#149](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/149)) ([8e181b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e181b3010dfe25ea1e4b4ba181cbe9944d6e92e))
|
||||
- additional changes to [#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201) ([#224](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/224)) ([bc354f3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc354f3798a02e6ebc3c66a8b5eee553c25a19d4))
|
||||
- aesthetically pleasing squishier course blocks when compressed ([#232](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/232)) ([438c82b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/438c82bfb5db0f570b261d15368a05447939b0fb))
|
||||
- align day labels and add to grid ([1bb6191](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1bb6191244f40220a9af66cced4fe8f0c1e546a0))
|
||||
- alignment on calendar and header ([#109](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/109)) ([07ec5ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/07ec5abc3e1b40b801b7c977d21399b31222a4d3))
|
||||
- async course adding and async/other course block adjustments ([#273](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/273)) ([668c8d0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/668c8d00756a5e3e3daaade46380967c74eec1ae))
|
||||
- async text hiding on Calendar's Bottom Bar when there are no async courses ([#152](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/152)) ([0dff122](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0dff12232c29415fa7bc5ac3771393a406ab738d))
|
||||
- basic CalendarCourseMeeting component laid out - missing Text and Right Icon ([da9e7aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da9e7aac4135afa5184e4949c36a288ef6ab62a7))
|
||||
- Best Practices ([#102](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/102)) ([5eb7be2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5eb7be246cd2a1db27c7ca777d81074ae7bb3b82))
|
||||
- beta builds ([#187](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/187)) ([8a5e12e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8a5e12ec63539ae7199f0f1561f642cb9cf19302))
|
||||
- better discord icon ([#205](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/205)) ([a3f5e0f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a3f5e0f27ffdfcb4e3ddd47140979aca379f9f42))
|
||||
- bold red refresh error ([#220](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/220)) ([229a8a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/229a8a29e8d04dfbe15de200ceffc53b4f758413))
|
||||
- bottom bar for the calendar page ([#91](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/91)) ([0f730d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f730d6c50462c9f7d0428ebb379742305212ef6))
|
||||
- build without errors ([babc925](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/babc925967b01f1064b8d8e067e7bc792dd57b0a))
|
||||
- calendar components 3rd attempt at merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([4faca8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4faca8c43befe19c9b05ff4f3afba420e016bb59))
|
||||
- Calendar Components 3rd Attempt at Merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([ab2cd68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ab2cd688fae616742b39c0637291a65e508e23bd))
|
||||
- calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([00e0019](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/00e00197efb807d420196f2b030fc4dc71e9cd42))
|
||||
- calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([a41cb3e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a41cb3ed8711eff9a2fbbe435e867c073904f452))
|
||||
- calendar grid and grid cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([bfeb239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bfeb2398aacf9a1fba892737b6ef0286acbc326f))
|
||||
- Calendar Grid and Grid Cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([dd2f696](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dd2f696f8de2c0b291e917ef4d4cb2171b76712c))
|
||||
- calendar header formatting and data displaying ([#160](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/160)) ([5cce1c7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5cce1c79fc2b50843426ed290a1b53849375e4eb))
|
||||
- calendar matchings ([#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173)) ([791a42b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/791a42bcd49478024b6f1a237a2d2a9f6211749e))
|
||||
- Calendar Schedule component finished, fix: list didn't allow updates when adding a new schedule ([#115](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/115)) ([a99a557](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a99a55788a0b9791ff048c8bbbaad5bada47c41f))
|
||||
- calendar-course-cell-color-picker ([#157](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/157)) ([df18491](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df1849180de2c793c10e3a49d2c862d236456ec2))
|
||||
- can open tabs, updated injected popup heading. basically done ([35fab34](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35fab3444582b436f63c7b16a26ebd5989c4bf3e))
|
||||
- change Chip to tailwind css. Fixed eslint for ConflictsWithWarning ([3568b8e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3568b8eb5ee9ce3fe17f77f5641c0583bacc17a4))
|
||||
- check-path-alias autofix ([#124](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/124)) ([265652c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/265652c4200a56b1ae62e6e94e0609fb4604c188))
|
||||
- chrome extension works ([35f3c72](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35f3c7225049d760c6061ed827aa796514291e62))
|
||||
- color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([471e55d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/471e55dcea1ae439658d00ed41570e2f218f0c3d))
|
||||
- Conventional Commits ([#103](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/103)) ([fe599df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fe599dfe7514ead880596d3b75c8370bde796e09))
|
||||
- convert all LabelsAndDetails Components to Tailwind ([9e0f9df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9e0f9df9de1a5c99657ddcef3b2eb101dd825b84))
|
||||
- course color generation ([#179](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/179)) ([5ed81e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ed81e4be99a8b7f3c68a3ba70358e4cbe5cc613))
|
||||
- course colors ([#175](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/175)) ([dc77cc2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc77cc27da7ab521e290a8c9ba810573e677b6b8))
|
||||
- Course Flag Tooltips ([#178](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/178)) ([ba2bc60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ba2bc60add2b87ccd4e9894c454d7a8d8382f0dd))
|
||||
- course-catalog-injected-popup ([#98](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/98)) ([89d03f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/89d03f4244d324915cadadaf75a827221525d43f))
|
||||
- CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([58d7df4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58d7df499ca9a8dfd4dc3aa47bc9d76837f21bf7))
|
||||
- CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([fa1d737](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa1d7374bcafbe19673dc31f33b3f8075e45f37a))
|
||||
- create empty Popup story ([ad83ba4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad83ba4cdc67f86096d0cbc2cb6659aa9be98a0b))
|
||||
- Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([ccea0f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ccea0f4bd1e8d66dc0717d92c9e970040d9fbe9e))
|
||||
- Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([1b51d65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1b51d65c89a4b544f4f2a9c60106e14300f9a3b0))
|
||||
- Derek vinson/calendar header ([#94](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/94)) ([12d09b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12d09b54cbf840993d17323b96cf274ec24c67ce))
|
||||
- Derek/disable updating ([#239](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/239)) ([0ab83ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ab83efd47d75fb6c278994c7dc8a6d22b4b6b83))
|
||||
- Derek/export png ([#95](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/95)) ([58c2b46](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58c2b4634a9d065ca156d27c4af69a504b7c2d2d))
|
||||
- DialogProvider component ([#198](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/198)) ([d1b921a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1b921a5b000693d7f3dabaf84d8b9580c361941))
|
||||
- dividers in calendar bottom bar ([#120](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/120)) ([eba5d9f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eba5d9f508576d2648bd2501e5d5aaff32592566))
|
||||
- **docs:** add extra acknowledgements ([e2cbfa3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e2cbfa3f48cb0b10a43134cf9784a44b13aa542d))
|
||||
- drag only on vertical axis ([34a6449](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/34a644952995d4aedd18d11d327bd8589f5b2610))
|
||||
- early iteration of non-virtual list ([677aa62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/677aa624d7fb2bbb922aaf8806abe979c3399e4e))
|
||||
- enable TS strict mode ([#168](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/168)) ([efed1c0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/efed1c0edbf93987c551952a03c9c4b3c461d819))
|
||||
- experimental toggle for icons, left off for now ([#237](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/237)) ([f34dd95](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f34dd95d7765322b6cecb2e817a46e0549d929a5))
|
||||
- fall 2023 grades ([#226](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/226)) ([863d980](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863d980b2d1c706b1fc648f1a0de2a31515e339e))
|
||||
- finally fix grid JSX.Element generation ([e49fc29](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e49fc295ba40a37f9bf59686adbd8b4f523cd9c6))
|
||||
- finish ScheduleTotalHoursAndCourses ([12f680d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12f680d7e9aef826281c8f769825408dc6f9f9de))
|
||||
- fix icons on PopupMain and convert to tailwind ([#108](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/108)) ([87799d8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/87799d8f02aa5986025982f768639afdb1b0267a))
|
||||
- fix save as button dividers ([#153](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/153)) ([7986549](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7986549fdd40834a85bedbfd0862cdb21c9ae657))
|
||||
- grades by professor ([#225](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/225)) ([78d749a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78d749a8a96f63c32663b464e5b663f932c28ed0))
|
||||
- html2canvas -> htmlToImage and fix derick's bugs ([bda0282](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bda02826b14b96fd65a6f24218950e510c5aa3d8))
|
||||
- icon added successfully ([3b588c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3b588c20394523ddf90456e1ca58546e5b820c74))
|
||||
- implement Chip component ([23e881f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23e881f14cc80100d8f8deef6a25daaa72d83f07))
|
||||
- implement flatten course schedule helper function ([e54f488](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e54f488b170d5a9af646c1ac82e8b33579fef61d))
|
||||
- implemented ConflictsWithWarning ([93f3a30](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93f3a307b4acce6cc55fc411f1ea2d7576006b00))
|
||||
- implemented InfoCard ([21b6430](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/21b643000d884442e025534802be6bb1f6ba68e2))
|
||||
- Initial Splash Text Commit ([#208](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/208)) ([0534f60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0534f607a51f1dd0905f6f45f08519cba65ea05a))
|
||||
- limit schedules to 10 ([#272](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/272)) ([290b841](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/290b8415170bca631e5d71b08d88db80b02163f0))
|
||||
- link to your registered courses ([#228](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/228)) ([f83e012](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f83e012d62e268d95dce19a30e54e34f3779142b))
|
||||
- list reordering ([#154](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/154)) ([038ebaa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/038ebaa2689c14bc9906afb542ef62c21cb13177))
|
||||
- listed versioning for beta builds ([#192](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/192)) ([0c42979](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c429794230a91c4fd949715b7eea210ac18fee3))
|
||||
- lowercase instructor! ([#268](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/268)) ([9ec05ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ec05ef764b2451c05e2d084d92074fb1e984268))
|
||||
- made List more extensible ([cd34601](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd34601379d5cd2b53d967afbc954178834823b9))
|
||||
- match calendar designs & add functionality ([#176](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/176)) ([8027c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8027c3d1bf228053acbad3e232b030c9ddbaca6a))
|
||||
- migrate styles to TailwindCSS ([7e2f5ea](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7e2f5eaed7d782bc886545f7241e0891d55cfae0))
|
||||
- migration update showing ([#293](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/293)) ([aede681](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aede681d4bb5b01723eb9d68527f4e64991adfab))
|
||||
- missed one chip toggle there ([#245](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/245)) ([5ca24da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ca24dab82509d34cf43af4359940476159d052f))
|
||||
- newer grades and parameterized queries ([#238](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/238)) ([75ad416](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/75ad4167b6639bbcf58e2dc6dafc80ed4656a899))
|
||||
- one single exclamation mark did all that ([#235](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/235)) ([be87e41](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be87e4181430e0df41683be5c9d0a1ce992b2c61))
|
||||
- open an injected course page on course block click in popup main ([#146](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/146)) ([2709484](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27094846f70feb8d83c8d464ab0fa8dcd99b3e71))
|
||||
- pad unique ids to 5 digits ([#170](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/170)) ([b4ad687](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4ad6870bfc88f68bdd7f87fe1d94c23d0a02b95))
|
||||
- parallelize initializeDB.ts promises ([9f1dcc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9f1dcc667df9857e3d0469fe7112a9f985aad490))
|
||||
- popout icon for ccip in calendar ([#221](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/221)) ([6812d68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6812d685d08902f7b3d9d2e5293350c8170c6f06))
|
||||
- popup schedule select ([#126](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/126)) ([7f2a589](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7f2a5893d4dd82a0f077dca6dfd28e79f929766f))
|
||||
- PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([9accd17](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9accd17bd418f8c9334e80b0f7e38673092ba208))
|
||||
- PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([f045b40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f045b400a56569f7353eb00ecd0d081b68660fc5))
|
||||
- proper injected styles ([#164](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/164)) ([e919e96](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e919e96c53bc9bec7db3d09693d1ff0684b56e87))
|
||||
- readme animation ([#281](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/281)) ([da6d86c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da6d86c785f92f70f52ef0b4cab3dc14e0bd9790))
|
||||
- refactor all components in common ([e544312](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e5443122b422266a126de497b475020e298b2f1c))
|
||||
- refactor all components in injected ([0c44849](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c44849e15333c3a5cbdf8972eb31ada0e830b0a))
|
||||
- refactor calendar ([28f1924](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28f192472b7f244253b6a0b5339491b9740880f7))
|
||||
- Refactor database initialization code ([5e98f45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5e98f45210346f0e7bb69af5cf25e336c76416ca))
|
||||
- release notes ([#283](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/283)) ([bd17e33](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bd17e3353792df70ca2e33c8b7a32b5fb9acc7d2))
|
||||
- report issue popup ([#261](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/261)) ([65ff6bf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/65ff6bfbbfc6b696621628e448865155d0405f7f))
|
||||
- rerouted directory to syllabus when click on professor name ([#211](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/211)) ([8959e0d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8959e0d9f7fdd82125f391f1ec51aa390ba9450d))
|
||||
- sam's jokes ([#278](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/278)) ([895cd31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/895cd31d8eb40e7e99fc0969b543e95bd070f6b7))
|
||||
- save as PNG functionality ([ad18fbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad18fbd16235be0c75121b527867fac708670300))
|
||||
- schedule list item action menu ([#230](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/230)) ([15fc369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/15fc3699cfda3ad56e5a262bd37dca166e2685dd))
|
||||
- screenshot whole page, hide certain elements, screenshot fixed size ([#180](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/180)) ([7d4c5d7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7d4c5d7be8b266b5f3caf2135c4f3fecb96d75be))
|
||||
- settings page ([#260](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/260)) ([7a5c3a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a5c3a2e62c3a726735f9fe921f9e08d4092d0f9))
|
||||
- show async courses in the bottom bar ([#204](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/204)) ([227de53](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/227de53e8453804f0791f269dae64ec388136390))
|
||||
- some small changes for colors and font ([#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201)) ([bae1da4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bae1da43d3373e12d593682e9fb69e19557b5749))
|
||||
- splash text additions before v2 release ([#296](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/296)) ([e774f31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e774f316e3f92c03e79274a55f1f729178c9a14a))
|
||||
- splash text has arrived! ([#246](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/246)) ([9971435](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9971435716dec11e954dc26c14bf7d1505563d0d))
|
||||
- Storybook for Vite ([#52](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/52)) ([9cc299c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9cc299ced6132644a5c2375b95a8a16a3482601b))
|
||||
- swe title updates ([#310](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/310)) ([4629626](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4629626a31934c491758ddca874e5018d9c22e57))
|
||||
- switch button ([#229](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/229)) ([abae7a5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/abae7a5c22ab944262d66ae897298b008a03c5f1))
|
||||
- temporary removal of waitlist etc ([#236](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/236)) ([d424ccc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d424ccce49ba05305b24cb61aeb4ffeada5bab33))
|
||||
- UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([85c7f78](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/85c7f7817c58f13f6a4e8bec13a45f6412ad87db))
|
||||
- UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([6521a4b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6521a4b2a90af06e182c779f2fc7cb1a3b1e55c1))
|
||||
- unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([2d67b12](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d67b1218ff852c59901b77909615c5f54794a67))
|
||||
- unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([945e09b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/945e09b49e4ffa9bd4b02442f6567bb99831923e))
|
||||
- update admin titles ([4cf8c3f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4cf8c3f9645cd8fda07244413cdc406105b12fec))
|
||||
- update badge count when schedule changes ([#150](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/150)) ([a5e9e3c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e9e3c2145d61d8cc5788eb50fa19718e6d13bf))
|
||||
- update Button to v2 design ([863521f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863521fb3bb268131bd3f369064ae10a442b4fbc))
|
||||
- update dialog component to headlessui ([#159](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/159)) ([442be8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/442be8cbee06ec403467b100d8d5300dd4a7ea72))
|
||||
- update with TailwindCSS ([f3a8a7d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f3a8a7db560a6b28f96a2e976c8ed33af97fe77a))
|
||||
- updated calendar page and recruitment banner links ([#219](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/219)) ([a2303ee](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a2303ee35f10aba5fa7ff5e307d0092a39f18830))
|
||||
- updated divider component ([#99](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/99)) ([8ab60c9](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8ab60c9f018143df594e7bfd0d321666289cc28c))
|
||||
- updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([8b8433d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b8433deaf8fe66f917fd66fb56cb0a748bc6e6e))
|
||||
- updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([bb727f7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb727f70bea5a4c2ff5dba7e9b4428c0c84de7b2))
|
||||
- updating joke styling and updating jokes array ([#277](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/277)) ([0da27e2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0da27e2c46e9fc32efb80808715053c1f9f5165a))
|
||||
- use display: grid for calendarGrid ([b535a6e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b535a6eb32ac1091c8b5309ca3cfb6bab0b62526))
|
||||
- use downloadBlob util ([#186](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/186)) ([2dfb10e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2dfb10e57b51a08fcde2dc6638a81b5ec9bbc7ab))
|
||||
- use filter() instead of pop() ([063349d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/063349d96d0ad008fa0dc1f0a8c7a27cf3f108ce))
|
||||
- use React-icons ([8df9ea5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8df9ea55a9f0bcb04c90314cb311bba9d1ebf2e3))
|
||||
- UTRP v2 migration ([#292](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/292)) ([d22237d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d22237d561ddf6a2f8ed699ca4c11088a8b408e8))
|
||||
- working PNG and CAL downloads ([#119](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/119)) ([d9ee23c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d9ee23c5bbe27240a0e2849aae2eae81d7960bb5))
|
||||
* abhinavchadaga/course-catalog-popup ([#128](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/128)) ([745f9dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/745f9dd6fb96ccc0eace7189b87abf9a38f03828))
|
||||
* abhinavchadaga/reusable-popup-prompt ([#148](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/148)) ([44af9e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/44af9e16e4bf3b92c9a4fa0e779197f4f9ecb237))
|
||||
* actually sum for duplicate semesters (different uniques) ([#202](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/202)) ([d3f64ec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3f64ec79eb64ebe72ae28991127dbe521823842))
|
||||
* add button to the rows, use new ConflictsWithWarning component ([bec2649](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bec2649fc1244bffb5cb03809db62cc0ea477260))
|
||||
* add buttons with icons in tailwind ([93b65ac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93b65ac2edef3fc728305cc51d1a32ecf5073274))
|
||||
* add cal save buttons (no functionality) ([53e7c7f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/53e7c7fedaf1f268d2d7d06ff1a5df9e2af2306d))
|
||||
* add Calendar Component ([e0212d5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e0212d510928e5e95d3ba75e391c34714f1bb035))
|
||||
* add Calendar schedules component (clicking on storybook not working) ([d1a336e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1a336e903f09b04b89f11ba7ede2f7d26e0ac3c))
|
||||
* add CalendarHeader and its Storybook, need to resize ([23276e5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23276e5c7c907261b1d02e9006d8021d99b43984))
|
||||
* add check-path-alias custom ESLint rule ([#123](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/123)) ([208103d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/208103d7081abcf5b31bf36335320aaf7d213464))
|
||||
* add chrome.storage api mocks for storybook use ([#141](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/141)) ([3839bff](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3839bff29ef6f0ecfad1e975e685df9a64d96c92))
|
||||
* add CSS for calendarCell div ([6cdcf49](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6cdcf4930d9868c0ed45820f66102d89a644cfb6))
|
||||
* add CSS for hourLine div ([0ba6153](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ba61534cbfc83408cb64eb1145ecacef1ee8f04))
|
||||
* add CSS for timeLabelContainer div ([56f6456](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56f6456ce85f77edb9d6fa64ecb82a8388feec41))
|
||||
* add custom ESLint rule restrict-import-depth ([#110](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/110)) ([8c069b7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8c069b7ad339ed8db97bb5e3e6e88ab8d332489b))
|
||||
* add downloadBlob util ([2af351e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2af351efa85264da5abeee27fbd091d4ce637041))
|
||||
* add empty settings component - waiting on design ([9d0f210](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d0f2105481cc3d5affdb4bd69d428379ea92de3))
|
||||
* add ImportantLinks Component ([5dbee6f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5dbee6f0c39e620c3b65a5e0156fd59ec8217ca7))
|
||||
* add List component ([e6b4049](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e6b40494031ca88894b2f918bb18448b70124481))
|
||||
* add MIMEType ([0c76052](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c760524781556cf089f1885dc4ff3fd567bfc2b))
|
||||
* add new db powered by UT_Grade_Parser ([#163](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/163)) ([60d1f48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60d1f48bd95132f0517258f017a7644d8aff5101))
|
||||
* add react-loading-skeleton package ([#244](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/244)) ([b4dd91a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4dd91ad2595d9583a60530c2c2ff6d829d2d5e5))
|
||||
* add skeleton loader for course description + distribution ([#267](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/267)) ([c2cab40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2cab407f3a07c1d3073e936c9d23cb1cecc9cb9))
|
||||
* add story for CalendarGridCell ([fd91c3b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fd91c3b12ef5670563e689d190be75ef1f695d1c))
|
||||
* add Storybook story ([cb3cb5d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cb3cb5d5fc18a68ca5a825f97b808b535aa1fe29))
|
||||
* add tailwind version of Button component ([28d93b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28d93b3c25e1cbca3baea992a299d626ca823570))
|
||||
* add tickmarks to day div ([8b9cb06](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b9cb065c28b5dd38b7e1681839a81f55691a3c6))
|
||||
* add time column to Calendar Component ([9d68211](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d6821127e7ff9bf63cef659932ee7408de4c969))
|
||||
* add timeAndGrid div ([95e0544](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95e0544b7301d382439b74038fb1b3e25dfe6d30))
|
||||
* added flag ;-; ([#195](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/195)) ([9b4d61c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9b4d61c2b0d8806b5d4a10296c1cc1266ac4229f))
|
||||
* added scrapedAt property ([#149](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/149)) ([8e181b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e181b3010dfe25ea1e4b4ba181cbe9944d6e92e))
|
||||
* additional changes to [#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201) ([#224](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/224)) ([bc354f3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc354f3798a02e6ebc3c66a8b5eee553c25a19d4))
|
||||
* aesthetically pleasing squishier course blocks when compressed ([#232](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/232)) ([438c82b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/438c82bfb5db0f570b261d15368a05447939b0fb))
|
||||
* align day labels and add to grid ([1bb6191](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1bb6191244f40220a9af66cced4fe8f0c1e546a0))
|
||||
* alignment on calendar and header ([#109](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/109)) ([07ec5ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/07ec5abc3e1b40b801b7c977d21399b31222a4d3))
|
||||
* async course adding and async/other course block adjustments ([#273](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/273)) ([668c8d0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/668c8d00756a5e3e3daaade46380967c74eec1ae))
|
||||
* async text hiding on Calendar's Bottom Bar when there are no async courses ([#152](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/152)) ([0dff122](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0dff12232c29415fa7bc5ac3771393a406ab738d))
|
||||
* basic CalendarCourseMeeting component laid out - missing Text and Right Icon ([da9e7aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da9e7aac4135afa5184e4949c36a288ef6ab62a7))
|
||||
* Best Practices ([#102](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/102)) ([5eb7be2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5eb7be246cd2a1db27c7ca777d81074ae7bb3b82))
|
||||
* beta builds ([#187](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/187)) ([8a5e12e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8a5e12ec63539ae7199f0f1561f642cb9cf19302))
|
||||
* better discord icon ([#205](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/205)) ([a3f5e0f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a3f5e0f27ffdfcb4e3ddd47140979aca379f9f42))
|
||||
* bold red refresh error ([#220](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/220)) ([229a8a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/229a8a29e8d04dfbe15de200ceffc53b4f758413))
|
||||
* bottom bar for the calendar page ([#91](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/91)) ([0f730d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f730d6c50462c9f7d0428ebb379742305212ef6))
|
||||
* build without errors ([babc925](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/babc925967b01f1064b8d8e067e7bc792dd57b0a))
|
||||
* calendar components 3rd attempt at merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([4faca8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4faca8c43befe19c9b05ff4f3afba420e016bb59))
|
||||
* Calendar Components 3rd Attempt at Merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([ab2cd68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ab2cd688fae616742b39c0637291a65e508e23bd))
|
||||
* calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([00e0019](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/00e00197efb807d420196f2b030fc4dc71e9cd42))
|
||||
* calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([a41cb3e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a41cb3ed8711eff9a2fbbe435e867c073904f452))
|
||||
* calendar grid and grid cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([bfeb239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bfeb2398aacf9a1fba892737b6ef0286acbc326f))
|
||||
* Calendar Grid and Grid Cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([dd2f696](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dd2f696f8de2c0b291e917ef4d4cb2171b76712c))
|
||||
* calendar header formatting and data displaying ([#160](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/160)) ([5cce1c7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5cce1c79fc2b50843426ed290a1b53849375e4eb))
|
||||
* calendar matchings ([#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173)) ([791a42b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/791a42bcd49478024b6f1a237a2d2a9f6211749e))
|
||||
* Calendar Schedule component finished, fix: list didn't allow updates when adding a new schedule ([#115](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/115)) ([a99a557](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a99a55788a0b9791ff048c8bbbaad5bada47c41f))
|
||||
* calendar-course-cell-color-picker ([#157](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/157)) ([df18491](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df1849180de2c793c10e3a49d2c862d236456ec2))
|
||||
* can open tabs, updated injected popup heading. basically done ([35fab34](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35fab3444582b436f63c7b16a26ebd5989c4bf3e))
|
||||
* change Chip to tailwind css. Fixed eslint for ConflictsWithWarning ([3568b8e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3568b8eb5ee9ce3fe17f77f5641c0583bacc17a4))
|
||||
* check-path-alias autofix ([#124](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/124)) ([265652c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/265652c4200a56b1ae62e6e94e0609fb4604c188))
|
||||
* chrome extension works ([35f3c72](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35f3c7225049d760c6061ed827aa796514291e62))
|
||||
* color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([471e55d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/471e55dcea1ae439658d00ed41570e2f218f0c3d))
|
||||
* Conventional Commits ([#103](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/103)) ([fe599df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fe599dfe7514ead880596d3b75c8370bde796e09))
|
||||
* convert all LabelsAndDetails Components to Tailwind ([9e0f9df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9e0f9df9de1a5c99657ddcef3b2eb101dd825b84))
|
||||
* course color generation ([#179](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/179)) ([5ed81e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ed81e4be99a8b7f3c68a3ba70358e4cbe5cc613))
|
||||
* course colors ([#175](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/175)) ([dc77cc2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc77cc27da7ab521e290a8c9ba810573e677b6b8))
|
||||
* Course Flag Tooltips ([#178](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/178)) ([ba2bc60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ba2bc60add2b87ccd4e9894c454d7a8d8382f0dd))
|
||||
* course-catalog-injected-popup ([#98](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/98)) ([89d03f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/89d03f4244d324915cadadaf75a827221525d43f))
|
||||
* CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([58d7df4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58d7df499ca9a8dfd4dc3aa47bc9d76837f21bf7))
|
||||
* CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([fa1d737](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa1d7374bcafbe19673dc31f33b3f8075e45f37a))
|
||||
* create empty Popup story ([ad83ba4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad83ba4cdc67f86096d0cbc2cb6659aa9be98a0b))
|
||||
* Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([ccea0f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ccea0f4bd1e8d66dc0717d92c9e970040d9fbe9e))
|
||||
* Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([1b51d65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1b51d65c89a4b544f4f2a9c60106e14300f9a3b0))
|
||||
* Derek vinson/calendar header ([#94](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/94)) ([12d09b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12d09b54cbf840993d17323b96cf274ec24c67ce))
|
||||
* Derek/disable updating ([#239](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/239)) ([0ab83ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ab83efd47d75fb6c278994c7dc8a6d22b4b6b83))
|
||||
* Derek/export png ([#95](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/95)) ([58c2b46](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58c2b4634a9d065ca156d27c4af69a504b7c2d2d))
|
||||
* DialogProvider component ([#198](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/198)) ([d1b921a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1b921a5b000693d7f3dabaf84d8b9580c361941))
|
||||
* dividers in calendar bottom bar ([#120](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/120)) ([eba5d9f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eba5d9f508576d2648bd2501e5d5aaff32592566))
|
||||
* **docs:** add extra acknowledgements ([e2cbfa3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e2cbfa3f48cb0b10a43134cf9784a44b13aa542d))
|
||||
* drag only on vertical axis ([34a6449](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/34a644952995d4aedd18d11d327bd8589f5b2610))
|
||||
* early iteration of non-virtual list ([677aa62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/677aa624d7fb2bbb922aaf8806abe979c3399e4e))
|
||||
* enable TS strict mode ([#168](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/168)) ([efed1c0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/efed1c0edbf93987c551952a03c9c4b3c461d819))
|
||||
* experimental toggle for icons, left off for now ([#237](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/237)) ([f34dd95](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f34dd95d7765322b6cecb2e817a46e0549d929a5))
|
||||
* fall 2023 grades ([#226](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/226)) ([863d980](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863d980b2d1c706b1fc648f1a0de2a31515e339e))
|
||||
* finally fix grid JSX.Element generation ([e49fc29](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e49fc295ba40a37f9bf59686adbd8b4f523cd9c6))
|
||||
* finish ScheduleTotalHoursAndCourses ([12f680d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12f680d7e9aef826281c8f769825408dc6f9f9de))
|
||||
* fix icons on PopupMain and convert to tailwind ([#108](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/108)) ([87799d8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/87799d8f02aa5986025982f768639afdb1b0267a))
|
||||
* fix save as button dividers ([#153](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/153)) ([7986549](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7986549fdd40834a85bedbfd0862cdb21c9ae657))
|
||||
* grades by professor ([#225](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/225)) ([78d749a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78d749a8a96f63c32663b464e5b663f932c28ed0))
|
||||
* html2canvas -> htmlToImage and fix derick's bugs ([bda0282](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bda02826b14b96fd65a6f24218950e510c5aa3d8))
|
||||
* icon added successfully ([3b588c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3b588c20394523ddf90456e1ca58546e5b820c74))
|
||||
* implement Chip component ([23e881f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23e881f14cc80100d8f8deef6a25daaa72d83f07))
|
||||
* implement flatten course schedule helper function ([e54f488](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e54f488b170d5a9af646c1ac82e8b33579fef61d))
|
||||
* implemented ConflictsWithWarning ([93f3a30](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93f3a307b4acce6cc55fc411f1ea2d7576006b00))
|
||||
* implemented InfoCard ([21b6430](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/21b643000d884442e025534802be6bb1f6ba68e2))
|
||||
* Initial Splash Text Commit ([#208](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/208)) ([0534f60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0534f607a51f1dd0905f6f45f08519cba65ea05a))
|
||||
* limit schedules to 10 ([#272](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/272)) ([290b841](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/290b8415170bca631e5d71b08d88db80b02163f0))
|
||||
* link to your registered courses ([#228](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/228)) ([f83e012](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f83e012d62e268d95dce19a30e54e34f3779142b))
|
||||
* list reordering ([#154](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/154)) ([038ebaa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/038ebaa2689c14bc9906afb542ef62c21cb13177))
|
||||
* listed versioning for beta builds ([#192](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/192)) ([0c42979](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c429794230a91c4fd949715b7eea210ac18fee3))
|
||||
* lowercase instructor! ([#268](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/268)) ([9ec05ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ec05ef764b2451c05e2d084d92074fb1e984268))
|
||||
* made List more extensible ([cd34601](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd34601379d5cd2b53d967afbc954178834823b9))
|
||||
* match calendar designs & add functionality ([#176](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/176)) ([8027c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8027c3d1bf228053acbad3e232b030c9ddbaca6a))
|
||||
* migrate styles to TailwindCSS ([7e2f5ea](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7e2f5eaed7d782bc886545f7241e0891d55cfae0))
|
||||
* migration update showing ([#293](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/293)) ([aede681](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aede681d4bb5b01723eb9d68527f4e64991adfab))
|
||||
* missed one chip toggle there ([#245](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/245)) ([5ca24da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ca24dab82509d34cf43af4359940476159d052f))
|
||||
* newer grades and parameterized queries ([#238](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/238)) ([75ad416](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/75ad4167b6639bbcf58e2dc6dafc80ed4656a899))
|
||||
* one single exclamation mark did all that ([#235](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/235)) ([be87e41](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be87e4181430e0df41683be5c9d0a1ce992b2c61))
|
||||
* open an injected course page on course block click in popup main ([#146](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/146)) ([2709484](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27094846f70feb8d83c8d464ab0fa8dcd99b3e71))
|
||||
* pad unique ids to 5 digits ([#170](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/170)) ([b4ad687](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4ad6870bfc88f68bdd7f87fe1d94c23d0a02b95))
|
||||
* parallelize initializeDB.ts promises ([9f1dcc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9f1dcc667df9857e3d0469fe7112a9f985aad490))
|
||||
* popout icon for ccip in calendar ([#221](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/221)) ([6812d68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6812d685d08902f7b3d9d2e5293350c8170c6f06))
|
||||
* popup schedule select ([#126](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/126)) ([7f2a589](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7f2a5893d4dd82a0f077dca6dfd28e79f929766f))
|
||||
* PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([9accd17](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9accd17bd418f8c9334e80b0f7e38673092ba208))
|
||||
* PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([f045b40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f045b400a56569f7353eb00ecd0d081b68660fc5))
|
||||
* proper injected styles ([#164](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/164)) ([e919e96](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e919e96c53bc9bec7db3d09693d1ff0684b56e87))
|
||||
* readme animation ([#281](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/281)) ([da6d86c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da6d86c785f92f70f52ef0b4cab3dc14e0bd9790))
|
||||
* refactor all components in common ([e544312](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e5443122b422266a126de497b475020e298b2f1c))
|
||||
* refactor all components in injected ([0c44849](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c44849e15333c3a5cbdf8972eb31ada0e830b0a))
|
||||
* refactor calendar ([28f1924](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28f192472b7f244253b6a0b5339491b9740880f7))
|
||||
* Refactor database initialization code ([5e98f45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5e98f45210346f0e7bb69af5cf25e336c76416ca))
|
||||
* release notes ([#283](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/283)) ([bd17e33](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bd17e3353792df70ca2e33c8b7a32b5fb9acc7d2))
|
||||
* report issue popup ([#261](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/261)) ([65ff6bf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/65ff6bfbbfc6b696621628e448865155d0405f7f))
|
||||
* rerouted directory to syllabus when click on professor name ([#211](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/211)) ([8959e0d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8959e0d9f7fdd82125f391f1ec51aa390ba9450d))
|
||||
* sam's jokes ([#278](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/278)) ([895cd31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/895cd31d8eb40e7e99fc0969b543e95bd070f6b7))
|
||||
* save as PNG functionality ([ad18fbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad18fbd16235be0c75121b527867fac708670300))
|
||||
* schedule list item action menu ([#230](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/230)) ([15fc369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/15fc3699cfda3ad56e5a262bd37dca166e2685dd))
|
||||
* screenshot whole page, hide certain elements, screenshot fixed size ([#180](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/180)) ([7d4c5d7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7d4c5d7be8b266b5f3caf2135c4f3fecb96d75be))
|
||||
* settings page ([#260](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/260)) ([7a5c3a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a5c3a2e62c3a726735f9fe921f9e08d4092d0f9))
|
||||
* show async courses in the bottom bar ([#204](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/204)) ([227de53](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/227de53e8453804f0791f269dae64ec388136390))
|
||||
* some small changes for colors and font ([#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201)) ([bae1da4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bae1da43d3373e12d593682e9fb69e19557b5749))
|
||||
* splash text additions before v2 release ([#296](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/296)) ([e774f31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e774f316e3f92c03e79274a55f1f729178c9a14a))
|
||||
* splash text has arrived! ([#246](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/246)) ([9971435](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9971435716dec11e954dc26c14bf7d1505563d0d))
|
||||
* Storybook for Vite ([#52](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/52)) ([9cc299c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9cc299ced6132644a5c2375b95a8a16a3482601b))
|
||||
* swe title updates ([#310](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/310)) ([4629626](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4629626a31934c491758ddca874e5018d9c22e57))
|
||||
* switch button ([#229](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/229)) ([abae7a5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/abae7a5c22ab944262d66ae897298b008a03c5f1))
|
||||
* temporary removal of waitlist etc ([#236](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/236)) ([d424ccc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d424ccce49ba05305b24cb61aeb4ffeada5bab33))
|
||||
* UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([85c7f78](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/85c7f7817c58f13f6a4e8bec13a45f6412ad87db))
|
||||
* UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([6521a4b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6521a4b2a90af06e182c779f2fc7cb1a3b1e55c1))
|
||||
* unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([2d67b12](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d67b1218ff852c59901b77909615c5f54794a67))
|
||||
* unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([945e09b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/945e09b49e4ffa9bd4b02442f6567bb99831923e))
|
||||
* update admin titles ([4cf8c3f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4cf8c3f9645cd8fda07244413cdc406105b12fec))
|
||||
* update badge count when schedule changes ([#150](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/150)) ([a5e9e3c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e9e3c2145d61d8cc5788eb50fa19718e6d13bf))
|
||||
* update Button to v2 design ([863521f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863521fb3bb268131bd3f369064ae10a442b4fbc))
|
||||
* update dialog component to headlessui ([#159](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/159)) ([442be8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/442be8cbee06ec403467b100d8d5300dd4a7ea72))
|
||||
* update with TailwindCSS ([f3a8a7d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f3a8a7db560a6b28f96a2e976c8ed33af97fe77a))
|
||||
* updated calendar page and recruitment banner links ([#219](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/219)) ([a2303ee](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a2303ee35f10aba5fa7ff5e307d0092a39f18830))
|
||||
* updated divider component ([#99](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/99)) ([8ab60c9](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8ab60c9f018143df594e7bfd0d321666289cc28c))
|
||||
* updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([8b8433d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b8433deaf8fe66f917fd66fb56cb0a748bc6e6e))
|
||||
* updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([bb727f7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb727f70bea5a4c2ff5dba7e9b4428c0c84de7b2))
|
||||
* updating joke styling and updating jokes array ([#277](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/277)) ([0da27e2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0da27e2c46e9fc32efb80808715053c1f9f5165a))
|
||||
* use display: grid for calendarGrid ([b535a6e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b535a6eb32ac1091c8b5309ca3cfb6bab0b62526))
|
||||
* use downloadBlob util ([#186](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/186)) ([2dfb10e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2dfb10e57b51a08fcde2dc6638a81b5ec9bbc7ab))
|
||||
* use filter() instead of pop() ([063349d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/063349d96d0ad008fa0dc1f0a8c7a27cf3f108ce))
|
||||
* use React-icons ([8df9ea5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8df9ea55a9f0bcb04c90314cb311bba9d1ebf2e3))
|
||||
* UTRP v2 migration ([#292](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/292)) ([d22237d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d22237d561ddf6a2f8ed699ca4c11088a8b408e8))
|
||||
* working PNG and CAL downloads ([#119](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/119)) ([d9ee23c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d9ee23c5bbe27240a0e2849aae2eae81d7960bb5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- add margin-top: -10px to p ([18406b0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/18406b0c94604b1b524de03bf97e78cffe7a5bbf))
|
||||
- added room number to course popup ([#231](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/231)) ([9eaff24](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9eaff24cbb6d78d7f28521a07c32630a90a96f82))
|
||||
- align timeBlock div ([4dc8957](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4dc8957c459d0ee57e40c67fa61194ace832327e))
|
||||
- async course display size ([#181](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/181)) ([949bbb0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/949bbb0835bfb55a81f0800850aa084b4ed1bfc4))
|
||||
- broken close bracket ([b34aacb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b34aacb06772af6f83d1f7bafe828ba43a10db85))
|
||||
- broken file ([92462cf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/92462cf0dffa222d75965885ee0e63181bce9890))
|
||||
- bugs ([2a01506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a0150600f26af5b7394f878e13c4d19611f3f64))
|
||||
- build ([60ab140](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60ab140c556ec56eca78b1f4e280dfb6e9dbb538))
|
||||
- build errors and merge in Casey's branch (driodiwb) ([39947b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/39947b3694f42f9d5ad2f21d044585aa3d12c407))
|
||||
- build errors and restructure Calendar page ([c6a48dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6a48dd3f6025fe531c18e12b8730683d63f67ed))
|
||||
- calendar course cell colors ([74be880](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/74be880f9d2dc340ba48416429711fb28915baa2))
|
||||
- calendar storybook issue ([#125](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/125)) ([0c5bec8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c5bec8002022cb4702f3879f43fcd32b9fa6b5a))
|
||||
- Calendar View/Scaling Issues ([#144](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/144)) ([4c61ebd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4c61ebd3fc93240903f1224f9dd3057a23d30046))
|
||||
- CalendarCourseCell spacing ([13c69ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/13c69ef862f0214dfa6c9368fc3463519aa8f2f0))
|
||||
- change Chromatic action to build current branch, not base branch ([#100](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/100)) ([e73c9fe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e73c9fe417169e73c395cde1aeb841eee8add579))
|
||||
- change material icons to material symbols ([#71](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/71)) ([52e34cb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52e34cb830ff1f12659703776bd3d9a24815ee00))
|
||||
- chromatic build ([11303da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/11303daebcc1e4de340463e6266082dc0920582d))
|
||||
- chromatic builds on PRs ([#140](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/140)) ([78a6939](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78a69399292767a1f8eac66e4c86cbcb8aad019d))
|
||||
- chromatic storybook - CourseCatalogInjectedPopup ([#106](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/106)) ([ced2997](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ced29975b20a2a5beac51ea875627a2b1042e5c2))
|
||||
- clean up [#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173) ([#174](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/174)) ([afa634f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/afa634f0853dc16cf313c129434d49bf132388d0))
|
||||
- cleanup imports ([#112](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/112)) ([b17c3fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b17c3fae6d9a8fdb2f6de84dc28d00bc31e7bcc8))
|
||||
- conflict row bug ([#130](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/130)) ([a8ea3bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a8ea3bc683f88fc33191a8cacf649be83f6758f8))
|
||||
- ConflictsWithWarning ([1599e48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1599e48d75d4877b3515c943120d83b59d084a55))
|
||||
- correct parsing of noon ([#155](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/155)) ([91f62e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91f62e1943633eaef7dc8d437e6a7397456a9123))
|
||||
- db with proper insertion order ([8e79d6a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e79d6a6a87210e0a30584c0c9ceb60bd3a33665))
|
||||
- delete storybook timestamp file ([f93a98e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f93a98e46ae76e9b1474c8143bfc3f5076e8b91f))
|
||||
- dialog movement ([#227](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/227)) ([bc5d68c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc5d68ce18f818c285ef7f5eda03f499365ee2e8))
|
||||
- disabled [object Object] hover message on dialog popups ([#284](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/284)) ([dcc1d81](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dcc1d81a74922ba27ad2a6859f978f3f20136178))
|
||||
- divider usage in HeaderAndActions ([#113](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/113)) ([84e8320](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/84e8320e8fce5961877a5745e89419a722055ed5))
|
||||
- doesn't autoload on pages that don't have pages to load ([#270](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/270)) ([88eeb62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/88eeb620aec52d6e4172cc908843339412ade90b))
|
||||
- don't crash on cultural diversity flag ([#196](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/196)) ([5b1e451](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5b1e4513e29203a54ed9f4913c227d6c45d2e67a))
|
||||
- eslint and remove React-beautiful-dnd ([6af805b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6af805ba3a7b04b7e5705d3d597b5ace686d61e0))
|
||||
- extra space ([0f43796](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f43796cd864acd012fc1242cbdf34844df62406))
|
||||
- Fix popup drag hitbox ([#216](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/216)) ([7a40008](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a40008c1e3846f09ac4eeadc4a50f810ffc0d90))
|
||||
- fixed bug where activeSchedule doesn't update correctly ([#158](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/158)) ([a409090](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a409090b904686b76a5db52af980e81108b97082))
|
||||
- fixed bug with course cells after 12 PM extending past midnight ([#122](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/122)) ([f22a3cd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f22a3cd7c0df138ca6ecd4b4a4efaa7ce845c3dd))
|
||||
- fixed issues involving course meeting objects not being recognized as course meeting objects ([#132](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/132)) ([3406e9a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3406e9a0e2644218fc06cbd0b05046df5339264c))
|
||||
- Fixed typescript error ([#161](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/161)) ([df7a7c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df7a7c65d695cb5c5a825ac9f5ecc48438735b65))
|
||||
- grade dist when no instructor ([#269](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/269)) ([6a363ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6a363aeb5ccb1c11e15db317b34c4f04a3c9aafc))
|
||||
- grid JSX.Element generation ([b691bf3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b691bf3231d5002a631687f26c7409e311237662))
|
||||
- icon library resolution ([#74](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/74)) ([bb3b313](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb3b313fd272bba12f99270c912e046df5358fed))
|
||||
- idk why that comment was there ([#177](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/177)) ([c5fc621](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c5fc6219e1540e1fb889d8bedc7296190103a56b))
|
||||
- import error ([152bc45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/152bc4577685605ae95f39d9e670b5449e32e0e9))
|
||||
- improper list data propagation ([#240](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/240)) ([149fda3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/149fda3b721dcc3d8ffa6c2398c28e39dcb62aaa))
|
||||
- improve dialog handling and error management in list items ([#257](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/257)) ([1942508](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1942508d8d11f51b62806894ae13162b6404753b))
|
||||
- injection not working from som/elie commit ([#145](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/145)) ([591687e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/591687eee8731b3649a5f8c1357a416eb2992a93))
|
||||
- list component fixed ([#162](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/162)) ([5714ed1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5714ed16d72c5442f58366ac51f40cc32ea406ab))
|
||||
- made list draggable only by handle ([cbb190b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cbb190bf4b3ad694c87b650489e1fca5aa6b7826))
|
||||
- margins on list component ([cc71389](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cc7138949cf77d1bcf1520633d669e939540575e))
|
||||
- non-determinstic options page generation ([#137](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/137)) ([d700110](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d70011016a45f5de62b06839a31c634637024f4a))
|
||||
- non-virtual dnd ([837fddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/837fddf8048350b0b25a58bbd16c1957fbad6edb))
|
||||
- old icon removed in .tsx ([4d387e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4d387e8063314c7c6d7452b746728e2cf85a1787))
|
||||
- only show button hover effects when not disabled ([8e3aa7e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e3aa7ef3380836fd36a12698b1f6982e110c0f7))
|
||||
- openTabFromContentScript TS issue ([3a48859](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3a48859dddc0e85649ff6a949e9afd22c962825d))
|
||||
- options page ([#131](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/131)) ([dc100b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc100b5d3ac1db5f1dc011ea2536c286f56fa55b))
|
||||
- reactivity ([#188](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/188)) ([4f4f34e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f4f34e281e8aabcdbf8b06652d05bca3554b11f))
|
||||
- README.md ([a30fecf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a30fecf8ec76ecae03be9bb4d813803b9ffdb490))
|
||||
- README.md ([b27b21b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b27b21bbfcc8fbdc130c3fa85776479451745b7b))
|
||||
- refactor AST parsing for custom ESLint rule ([62f0851](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/62f0851406bf82d3d0481fed40462bdd30ffcf1b))
|
||||
- remote react-window fully (from List component) ([#114](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/114)) ([5f1c023](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5f1c0231e483bc571ef944bbc0b950ab20d31028))
|
||||
- remove course name from the syllabi lookup ([#200](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/200)) ([bcb5a8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bcb5a8c469c4b5c1909880ab6789d67d04487ed2))
|
||||
- remove extra spacing ([#121](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/121)) ([6ba8b68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6ba8b68654dc182bd2a084f93b0f4f7d5c132862))
|
||||
- remove white space after duplicate schedule regex matching ([#286](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/286)) ([d73615e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d73615e28129ee7d78604c6b295ec572b11be46e))
|
||||
- rename to course block and fix line height for styling ([b602b0b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b602b0b895416a26214e934f9650a8ec0a10711e))
|
||||
- revert "chore: add default story" ([aef8c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aef8c3d9873c6df79f6a54ab4c669ee1849b5ea5))
|
||||
- revert "rename to course block and fix line height for styling" ([0273a23](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0273a239139c0f3c0ad773ed8ab1cd4ad8d22fa3))
|
||||
- revert CalendarGrid and CalendarGridCell back to SCSS from Tailwind ([56306ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56306ab9440baf5ca1158f95d788de7ba42d73d8))
|
||||
- revert last commit ([27d945f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27d945f57c76a1c2f31fee9f98c324fab6183bb6))
|
||||
- Schedule Switching Bugs ([#138](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/138)) ([c51e688](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c51e6881d186e8bef056e483e2bca95585d5eac6))
|
||||
- support classes with no location ([#242](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/242)) ([3ff06e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3ff06e043b112bc232c9c173e72b2ea99609cf7a))
|
||||
- theme colors ([2f537b4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2f537b4f3e3946241f2e287d9ae075e5a2aa7087))
|
||||
- type issues by using correct import ([#111](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/111)) ([19fe070](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/19fe070491be9e2d40f12918561f6f6ac5921237))
|
||||
- **ui:** unhid settings button ([#288](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/288)) ([db1eac3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db1eac33a2786a3db87f0e6b3679233a85ab923f))
|
||||
- undefined color case ([9aa78a0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9aa78a02a5d4f68daa062e4892875cf5f568306c))
|
||||
- unocss theme color namings ([79d7832](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79d7832d0987b8a7c9650b984f72ffd702682423))
|
||||
- update alignment ([7eb3113](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7eb3113adaa0917c0275576c3366c387bfe77440))
|
||||
- update daysOfWeek with new DAY_MAP keys ([ecdaadb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ecdaadb83eb21b144d07d573613fd8971f0a5ce2))
|
||||
- visual overflow bug when editing schedule name ([#251](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/251)) ([e8d2c2e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e8d2c2e1429072fcc1173ee770f06b07e9ddda20))
|
||||
- vitest path alias bug ([ee37897](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee37897df4f65cd2d285e2ad628be43aebb21ea1))
|
||||
* add margin-top: -10px to p ([18406b0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/18406b0c94604b1b524de03bf97e78cffe7a5bbf))
|
||||
* added room number to course popup ([#231](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/231)) ([9eaff24](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9eaff24cbb6d78d7f28521a07c32630a90a96f82))
|
||||
* align timeBlock div ([4dc8957](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4dc8957c459d0ee57e40c67fa61194ace832327e))
|
||||
* async course display size ([#181](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/181)) ([949bbb0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/949bbb0835bfb55a81f0800850aa084b4ed1bfc4))
|
||||
* broken close bracket ([b34aacb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b34aacb06772af6f83d1f7bafe828ba43a10db85))
|
||||
* broken file ([92462cf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/92462cf0dffa222d75965885ee0e63181bce9890))
|
||||
* bugs ([2a01506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a0150600f26af5b7394f878e13c4d19611f3f64))
|
||||
* build ([60ab140](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60ab140c556ec56eca78b1f4e280dfb6e9dbb538))
|
||||
* build errors and merge in Casey's branch (driodiwb) ([39947b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/39947b3694f42f9d5ad2f21d044585aa3d12c407))
|
||||
* build errors and restructure Calendar page ([c6a48dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6a48dd3f6025fe531c18e12b8730683d63f67ed))
|
||||
* calendar course cell colors ([74be880](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/74be880f9d2dc340ba48416429711fb28915baa2))
|
||||
* calendar storybook issue ([#125](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/125)) ([0c5bec8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c5bec8002022cb4702f3879f43fcd32b9fa6b5a))
|
||||
* Calendar View/Scaling Issues ([#144](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/144)) ([4c61ebd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4c61ebd3fc93240903f1224f9dd3057a23d30046))
|
||||
* CalendarCourseCell spacing ([13c69ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/13c69ef862f0214dfa6c9368fc3463519aa8f2f0))
|
||||
* change Chromatic action to build current branch, not base branch ([#100](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/100)) ([e73c9fe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e73c9fe417169e73c395cde1aeb841eee8add579))
|
||||
* change material icons to material symbols ([#71](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/71)) ([52e34cb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52e34cb830ff1f12659703776bd3d9a24815ee00))
|
||||
* chromatic build ([11303da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/11303daebcc1e4de340463e6266082dc0920582d))
|
||||
* chromatic builds on PRs ([#140](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/140)) ([78a6939](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78a69399292767a1f8eac66e4c86cbcb8aad019d))
|
||||
* chromatic storybook - CourseCatalogInjectedPopup ([#106](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/106)) ([ced2997](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ced29975b20a2a5beac51ea875627a2b1042e5c2))
|
||||
* clean up [#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173) ([#174](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/174)) ([afa634f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/afa634f0853dc16cf313c129434d49bf132388d0))
|
||||
* cleanup imports ([#112](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/112)) ([b17c3fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b17c3fae6d9a8fdb2f6de84dc28d00bc31e7bcc8))
|
||||
* conflict row bug ([#130](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/130)) ([a8ea3bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a8ea3bc683f88fc33191a8cacf649be83f6758f8))
|
||||
* ConflictsWithWarning ([1599e48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1599e48d75d4877b3515c943120d83b59d084a55))
|
||||
* correct parsing of noon ([#155](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/155)) ([91f62e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91f62e1943633eaef7dc8d437e6a7397456a9123))
|
||||
* db with proper insertion order ([8e79d6a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e79d6a6a87210e0a30584c0c9ceb60bd3a33665))
|
||||
* delete storybook timestamp file ([f93a98e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f93a98e46ae76e9b1474c8143bfc3f5076e8b91f))
|
||||
* dialog movement ([#227](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/227)) ([bc5d68c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc5d68ce18f818c285ef7f5eda03f499365ee2e8))
|
||||
* disabled [object Object] hover message on dialog popups ([#284](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/284)) ([dcc1d81](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dcc1d81a74922ba27ad2a6859f978f3f20136178))
|
||||
* divider usage in HeaderAndActions ([#113](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/113)) ([84e8320](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/84e8320e8fce5961877a5745e89419a722055ed5))
|
||||
* doesn't autoload on pages that don't have pages to load ([#270](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/270)) ([88eeb62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/88eeb620aec52d6e4172cc908843339412ade90b))
|
||||
* don't crash on cultural diversity flag ([#196](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/196)) ([5b1e451](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5b1e4513e29203a54ed9f4913c227d6c45d2e67a))
|
||||
* eslint and remove React-beautiful-dnd ([6af805b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6af805ba3a7b04b7e5705d3d597b5ace686d61e0))
|
||||
* extra space ([0f43796](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f43796cd864acd012fc1242cbdf34844df62406))
|
||||
* Fix popup drag hitbox ([#216](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/216)) ([7a40008](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a40008c1e3846f09ac4eeadc4a50f810ffc0d90))
|
||||
* fixed bug where activeSchedule doesn't update correctly ([#158](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/158)) ([a409090](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a409090b904686b76a5db52af980e81108b97082))
|
||||
* fixed bug with course cells after 12 PM extending past midnight ([#122](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/122)) ([f22a3cd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f22a3cd7c0df138ca6ecd4b4a4efaa7ce845c3dd))
|
||||
* fixed issues involving course meeting objects not being recognized as course meeting objects ([#132](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/132)) ([3406e9a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3406e9a0e2644218fc06cbd0b05046df5339264c))
|
||||
* Fixed typescript error ([#161](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/161)) ([df7a7c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df7a7c65d695cb5c5a825ac9f5ecc48438735b65))
|
||||
* grade dist when no instructor ([#269](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/269)) ([6a363ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6a363aeb5ccb1c11e15db317b34c4f04a3c9aafc))
|
||||
* grid JSX.Element generation ([b691bf3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b691bf3231d5002a631687f26c7409e311237662))
|
||||
* icon library resolution ([#74](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/74)) ([bb3b313](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb3b313fd272bba12f99270c912e046df5358fed))
|
||||
* idk why that comment was there ([#177](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/177)) ([c5fc621](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c5fc6219e1540e1fb889d8bedc7296190103a56b))
|
||||
* import error ([152bc45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/152bc4577685605ae95f39d9e670b5449e32e0e9))
|
||||
* improper list data propagation ([#240](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/240)) ([149fda3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/149fda3b721dcc3d8ffa6c2398c28e39dcb62aaa))
|
||||
* improve dialog handling and error management in list items ([#257](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/257)) ([1942508](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1942508d8d11f51b62806894ae13162b6404753b))
|
||||
* injection not working from som/elie commit ([#145](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/145)) ([591687e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/591687eee8731b3649a5f8c1357a416eb2992a93))
|
||||
* list component fixed ([#162](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/162)) ([5714ed1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5714ed16d72c5442f58366ac51f40cc32ea406ab))
|
||||
* made list draggable only by handle ([cbb190b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cbb190bf4b3ad694c87b650489e1fca5aa6b7826))
|
||||
* margins on list component ([cc71389](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cc7138949cf77d1bcf1520633d669e939540575e))
|
||||
* non-determinstic options page generation ([#137](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/137)) ([d700110](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d70011016a45f5de62b06839a31c634637024f4a))
|
||||
* non-virtual dnd ([837fddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/837fddf8048350b0b25a58bbd16c1957fbad6edb))
|
||||
* old icon removed in .tsx ([4d387e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4d387e8063314c7c6d7452b746728e2cf85a1787))
|
||||
* only show button hover effects when not disabled ([8e3aa7e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e3aa7ef3380836fd36a12698b1f6982e110c0f7))
|
||||
* openTabFromContentScript TS issue ([3a48859](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3a48859dddc0e85649ff6a949e9afd22c962825d))
|
||||
* options page ([#131](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/131)) ([dc100b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc100b5d3ac1db5f1dc011ea2536c286f56fa55b))
|
||||
* reactivity ([#188](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/188)) ([4f4f34e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f4f34e281e8aabcdbf8b06652d05bca3554b11f))
|
||||
* README.md ([a30fecf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a30fecf8ec76ecae03be9bb4d813803b9ffdb490))
|
||||
* README.md ([b27b21b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b27b21bbfcc8fbdc130c3fa85776479451745b7b))
|
||||
* refactor AST parsing for custom ESLint rule ([62f0851](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/62f0851406bf82d3d0481fed40462bdd30ffcf1b))
|
||||
* remote react-window fully (from List component) ([#114](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/114)) ([5f1c023](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5f1c0231e483bc571ef944bbc0b950ab20d31028))
|
||||
* remove course name from the syllabi lookup ([#200](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/200)) ([bcb5a8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bcb5a8c469c4b5c1909880ab6789d67d04487ed2))
|
||||
* remove extra spacing ([#121](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/121)) ([6ba8b68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6ba8b68654dc182bd2a084f93b0f4f7d5c132862))
|
||||
* remove white space after duplicate schedule regex matching ([#286](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/286)) ([d73615e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d73615e28129ee7d78604c6b295ec572b11be46e))
|
||||
* rename to course block and fix line height for styling ([b602b0b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b602b0b895416a26214e934f9650a8ec0a10711e))
|
||||
* revert "chore: add default story" ([aef8c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aef8c3d9873c6df79f6a54ab4c669ee1849b5ea5))
|
||||
* revert "rename to course block and fix line height for styling" ([0273a23](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0273a239139c0f3c0ad773ed8ab1cd4ad8d22fa3))
|
||||
* revert CalendarGrid and CalendarGridCell back to SCSS from Tailwind ([56306ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56306ab9440baf5ca1158f95d788de7ba42d73d8))
|
||||
* revert last commit ([27d945f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27d945f57c76a1c2f31fee9f98c324fab6183bb6))
|
||||
* Schedule Switching Bugs ([#138](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/138)) ([c51e688](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c51e6881d186e8bef056e483e2bca95585d5eac6))
|
||||
* support classes with no location ([#242](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/242)) ([3ff06e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3ff06e043b112bc232c9c173e72b2ea99609cf7a))
|
||||
* theme colors ([2f537b4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2f537b4f3e3946241f2e287d9ae075e5a2aa7087))
|
||||
* type issues by using correct import ([#111](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/111)) ([19fe070](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/19fe070491be9e2d40f12918561f6f6ac5921237))
|
||||
* **ui:** unhid settings button ([#288](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/288)) ([db1eac3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db1eac33a2786a3db87f0e6b3679233a85ab923f))
|
||||
* undefined color case ([9aa78a0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9aa78a02a5d4f68daa062e4892875cf5f568306c))
|
||||
* unocss theme color namings ([79d7832](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79d7832d0987b8a7c9650b984f72ffd702682423))
|
||||
* update alignment ([7eb3113](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7eb3113adaa0917c0275576c3366c387bfe77440))
|
||||
* update daysOfWeek with new DAY_MAP keys ([ecdaadb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ecdaadb83eb21b144d07d573613fd8971f0a5ce2))
|
||||
* visual overflow bug when editing schedule name ([#251](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/251)) ([e8d2c2e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e8d2c2e1429072fcc1173ee770f06b07e9ddda20))
|
||||
* vitest path alias bug ([ee37897](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee37897df4f65cd2d285e2ad628be43aebb21ea1))
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "individual bug fix" ([b4e8c75](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4e8c7589e53f1064d70703459cc6d66fae1b04c))
|
||||
- color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([51bbd65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/51bbd6590bf284ce54644b014466c8b2c73b8925))
|
||||
* Revert "individual bug fix" ([b4e8c75](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4e8c7589e53f1064d70703459cc6d66fae1b04c))
|
||||
* color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([51bbd65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/51bbd6590bf284ce54644b014466c8b2c73b8925))
|
||||
|
||||
32
CODE_OF_CONDUCT.md
Normal file
32
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# UT Registration Plus Code of Conduct
|
||||
|
||||
Like the technical community as a whole, the UT Registration Plus team and community is made up of a mixture of professionals and volunteers from all over the world, working on every aspect of the mission - including mentorship, teaching, and connecting people.
|
||||
|
||||
Diversity is one of our huge strengths, but it can also lead to communication issues and unhappiness. To that end, we have a few ground rules that we ask people to adhere to. This code applies equally to founders, mentors and those seeking help and guidance.
|
||||
|
||||
This isn’t an exhaustive list of things that you can’t do. Rather, take it in the spirit in which it’s intended - a guide to make it easier to enrich all of us and the technical communities in which we participate.
|
||||
|
||||
This code of conduct applies to all spaces managed by the UT Registration Plus project or Longhorn Developers. This includes IRC, the mailing lists, the issue tracker, DSF events, and any other forums created by the project team which the community uses for communication. In addition, violations of this code outside these spaces may affect a person's ability to participate within them.
|
||||
|
||||
If you believe someone is violating the code of conduct, we ask that you report it by emailing [contact@longhorns.dev](mailto:contact@longhorns.dev). For more details please see our
|
||||
|
||||
- **Be friendly and patient.**
|
||||
- **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
|
||||
- **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
|
||||
- **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the UT Registration Plus community should be respectful when dealing with other members as well as with people outside the UT Registration Plus community.
|
||||
- **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
|
||||
- Violent threats or language directed against another person.
|
||||
- Discriminatory jokes and language.
|
||||
- Posting sexually explicit or violent material.
|
||||
- Posting (or threatening to post) other people's personally identifying information ("doxing").
|
||||
- Personal insults, especially those using racist or sexist terms.
|
||||
- Unwelcome sexual attention.
|
||||
- Advocating for, or encouraging, any of the above behavior.
|
||||
- Repeated harassment of others. In general, if someone asks you to stop, then stop.
|
||||
- **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time and UT Registration Plus is no exception. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of UT Registration Plus comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
|
||||
|
||||
Original text courtesy of the [Speak Up! project](http://web.archive.org/web/20141109123859/http://speakup.io/coc.html).
|
||||
|
||||
## Questions?
|
||||
|
||||
If you have questions, please see . If that doesn't answer your questions, feel free to [contact us](mailto:contact@longhorns.dev).
|
||||
10
README.md
10
README.md
@@ -26,8 +26,9 @@
|
||||
## Toolchain
|
||||
|
||||
- React v20.9.0 (LTS)
|
||||
- TypeScript
|
||||
- Vite 5
|
||||
- TypeScript v5.x
|
||||
- Vite v5.x
|
||||
- pnpm v10.x
|
||||
- UnoCSS
|
||||
- ESLint
|
||||
- Prettier
|
||||
@@ -184,8 +185,9 @@ We maintain a strict code of conduct. By contributing, you agree to adhere to th
|
||||
Special thanks to the developers and contributors behind these amazing tools and libraries:
|
||||
|
||||
- React v20.9.0 (LTS)
|
||||
- TypeScript
|
||||
- Vite 5
|
||||
- TypeScript v5.x
|
||||
- Vite v5.x
|
||||
- pnpm v10.x
|
||||
- UnoCSS
|
||||
- ESLint
|
||||
- Prettier
|
||||
|
||||
0
docs/WebSocket-Implementation-Tutorial.md
Normal file
0
docs/WebSocket-Implementation-Tutorial.md
Normal file
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1759831965,
|
||||
"narHash": "sha256-vgPm2xjOmKdZ0xKA6yLXPJpjOtQPHfaZDRtH+47XEBo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c9b6fb798541223bbb396d287d16f43520250518",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
43
flake.nix
Normal file
43
flake.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = (import nixpkgs { inherit system; });
|
||||
|
||||
commonPackages = with pkgs; [
|
||||
nodejs_20 # v20.19.5
|
||||
pnpm_10 # v10.18.0
|
||||
];
|
||||
|
||||
additionalPackages = with pkgs; [
|
||||
bun
|
||||
nodePackages.conventional-changelog-cli
|
||||
sentry-cli
|
||||
];
|
||||
in
|
||||
{
|
||||
formatter = pkgs.nixfmt-rfc-style;
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
name = "utrp-dev";
|
||||
buildInputs = commonPackages;
|
||||
};
|
||||
|
||||
devShells.full = pkgs.mkShell {
|
||||
name = "utrp-dev-full";
|
||||
buildInputs = commonPackages ++ additionalPackages;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -35,9 +35,13 @@ function removeExtraDatabaseDir(cb) {
|
||||
// Instrument with Sentry
|
||||
// Make sure sentry is configured https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/typescript/#2-configure-sentry-cli
|
||||
async function instrumentWithSentry(cb) {
|
||||
if (process.env.SENTRY_ENV && process.env.SENTRY_ENV !== 'development') {
|
||||
await exec(`sentry-cli sourcemaps inject ${DIST_DIR}`);
|
||||
await exec(`sentry-cli sourcemaps upload ${DIST_DIR}`);
|
||||
log('Sentry instrumentation completed.');
|
||||
} else {
|
||||
logWarn('Skipping uploading/creating Sentry source maps. (development build)');
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
|
||||
14
package.json
14
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ut-registration-plus",
|
||||
"displayName": "UT Registration Plus",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.2",
|
||||
"description": "UT Registration Plus is a Chrome extension that allows students to easily register for classes.",
|
||||
"private": true,
|
||||
"homepage": "https://github.com/Longhorn-Developers/UT-Registration-Plus",
|
||||
@@ -9,8 +9,10 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"build:dev": "tsc && NODE_ENV='development' vite build --mode development",
|
||||
"build:watch": "NODE_ENV='development' vite build --mode development -w",
|
||||
"zip": "PROD=true pnpm build && pnpm gulp zipProdBuild",
|
||||
"zip": "pnpm build && pnpm gulp zipProdBuild",
|
||||
"zip:to-publish": "SENTRY_ENV='production' pnpm zip",
|
||||
"prettier": "prettier src --check",
|
||||
"prettier:fix": "prettier src --write",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives",
|
||||
@@ -27,6 +29,7 @@
|
||||
"prepare": "husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"@date-fns/tz": "^1.2.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
@@ -35,11 +38,13 @@
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"@phosphor-icons/react": "^2.1.7",
|
||||
"@sentry/react": "^8.55.0",
|
||||
"@tanstack/react-query": "^5.69.0",
|
||||
"@unocss/vite": "^0.63.6",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"chrome-extension-toolkit": "^0.0.54",
|
||||
"clsx": "^2.1.1",
|
||||
"conventional-changelog": "^6.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"highcharts": "^11.4.8",
|
||||
"highcharts-react-official": "^3.2.1",
|
||||
"html-to-image": "^1.11.13",
|
||||
@@ -139,7 +144,7 @@
|
||||
"unocss": "^0.63.6",
|
||||
"unocss-preset-primitives": "0.0.2-beta.1",
|
||||
"unplugin-icons": "^0.19.3",
|
||||
"vite": "^5.4.14",
|
||||
"vite": "^5.4.20",
|
||||
"vite-plugin-inspect": "^0.8.9",
|
||||
"vitest": "^2.1.9"
|
||||
},
|
||||
@@ -157,6 +162,7 @@
|
||||
}
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.9.0"
|
||||
"node": "20.19.4",
|
||||
"pnpm": "10.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
969
pnpm-lock.yaml
generated
969
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
src/assets/LD-icon-new.png
Normal file
BIN
src/assets/LD-icon-new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
@@ -8,15 +8,27 @@ const splashText: string[] = [
|
||||
'The squirrels, they have mastered begging for food better than students. Impressive... but worrying.',
|
||||
"Do you study often? Ha! What am I saying? Of course you don't.",
|
||||
"Hey, you, you're finally awake. You were trying to skip class right?",
|
||||
'Mmm... Brutalist architecture...',
|
||||
'The course syllabus: more than meets the eye',
|
||||
'Pain is temporary, GPA is forever.',
|
||||
"You've Yee'd Your Last Haw.",
|
||||
'lol everything is already waitlisted.',
|
||||
'Could be worse. Could be A&M.',
|
||||
"Should you major in Compsci? well, here's a better question. do you wanna have a bad time?",
|
||||
'A pen and paper is old fashioned, but sometimes old ways are best',
|
||||
'A heart is like bedrock, destroyable only by cheating',
|
||||
'You may not rest now, there are Canvas assignments nearby',
|
||||
'You are filled with DETERMINATION',
|
||||
'60k+ users!',
|
||||
'Almost Turing complete',
|
||||
'#BF5700',
|
||||
'The waitlist is a lie!',
|
||||
'BEVO JOCKEY 🗣️🗣️🗣️',
|
||||
'RIP Domino, you beloved campus feline.',
|
||||
"The year is 2055 and Welch still isn't finished.",
|
||||
'Motivation dropping faster than ur GPA',
|
||||
'No Work Happens On PCL 5th Floor.',
|
||||
'I may be a sophomore in name, but my credit count screams freshman!',
|
||||
'Pain is temporary, GPA is forever.',
|
||||
"You've Yee'd Your Last Haw.",
|
||||
'lol everything is already waitlisted.',
|
||||
'Could be worse. Could be A&M.',
|
||||
// 'TeXAs iS BaCK GuYZ',
|
||||
'mAke iT yOuR tExAS',
|
||||
'change yOur slogan',
|
||||
@@ -24,7 +36,7 @@ const splashText: string[] = [
|
||||
'Does McCombs teach Parseltongue?',
|
||||
'No Cruce Enfrente Del Bus.',
|
||||
'Omae Wa Mou Shindeiru...',
|
||||
'Every day another brick disappears from Speedway',
|
||||
"They say each day, another brick disappears from Speedway. No one's sure where to.",
|
||||
'The GDC will annex the EER one day',
|
||||
'To hike to Kins or not to hike to Kins...',
|
||||
"C'mon you Longhorns! You want to study forever?",
|
||||
@@ -34,15 +46,11 @@ const splashText: string[] = [
|
||||
"The Block of Butter incident of '22",
|
||||
'Begun, the midterms have.',
|
||||
'You must construct additional schedules',
|
||||
"Arrows of Christ vs Church of Scientology was the crossover we didn't know we needed",
|
||||
'THE WALK SIGN IS ON TO CROSS GUADALUPE AND 21ST',
|
||||
'Pay attention. Might learn something.',
|
||||
'Long ago, apartment rates lived together in harmony. Then, everything changed when American Campus Communities Inc attacked.',
|
||||
'Roll for Initiative!',
|
||||
'The line at the on-campus Starbucks is longer than your course waitlist.',
|
||||
'The weather changes more often than your class schedule.',
|
||||
'Mmm... Brutalist architecture...',
|
||||
'The course syllabus: more than meets the eye',
|
||||
"'studying' often means refreshing Canvas every five minutes to see if the professor posted lecture slides.",
|
||||
"It's over Bevo! I have the high ground!",
|
||||
"I'll just skip this lecture and watch the recording later. What's the worst that could happen?",
|
||||
@@ -59,23 +67,15 @@ const splashText: string[] = [
|
||||
'follow @sghsri!',
|
||||
'Officially part of the SEC',
|
||||
'Planner is now acquired by Plus',
|
||||
'Longhorn-Developers is the best UT Student Org',
|
||||
'Longhorn Developers is the best UT Student Org',
|
||||
'The Eiffel Tower is the UT Tower of Paris',
|
||||
'A pen and paper is old fashioned, but sometimes old ways are best',
|
||||
'A heart is like bedrock, destroyable only by cheating',
|
||||
'You may not rest now, there are Canvas assignments nearby',
|
||||
'You are filled with DETERMINATION',
|
||||
'60k+ users!',
|
||||
'Almost Turing complete',
|
||||
'#BF5700',
|
||||
'The waitlist is a lie!',
|
||||
`He's a CS Major, but he showers regularly. 🧢`,
|
||||
"He's a CS Major, but he showers regularly. 🧢",
|
||||
'A CS major walks into a bar. The bar is empty because it is a CS major.',
|
||||
'UT Registration Plus - The only thing that can make registration worse is not having it',
|
||||
'UT Registration Plus - We make registration slightly less painful. Slightly.',
|
||||
'UT Registration Plus - Do you really want to figure out which professors will ruin your GPA by yourself?',
|
||||
'Ayo tf is a memory leak',
|
||||
"lowkey we never thought we'd get this far, how tf are 60k of you people using this",
|
||||
"Ayo what's is a memory leak",
|
||||
"lowkey we never thought we'd get this far, how are 60k of you people using this",
|
||||
"dang we're really out here making a splash",
|
||||
"We'd make a joke about A&M, but we're not sure they can read",
|
||||
"We've only caused one or two outages, we swear!",
|
||||
@@ -114,7 +114,6 @@ const splashText: string[] = [
|
||||
'Befriend the raccoons on campus',
|
||||
`It's ${new Date().toLocaleString('en-US', { month: 'long', day: 'numeric' })} and OU still sucks`,
|
||||
'As seen on TV!',
|
||||
"Should you major in Compsci? well, here's a better question. do you wanna have a bad time?",
|
||||
];
|
||||
|
||||
export default splashText;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { ExtensionStore } from '@shared/storage/ExtensionStore';
|
||||
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
|
||||
|
||||
import createSchedule from '../lib/createSchedule';
|
||||
|
||||
/**
|
||||
* Called when the extension is updated (or when the extension is reloaded in development mode)
|
||||
@@ -8,4 +11,11 @@ export default async function onUpdate() {
|
||||
version: chrome.runtime.getManifest().version,
|
||||
lastUpdate: Date.now(),
|
||||
});
|
||||
|
||||
const schedules = await UserScheduleStore.get('schedules');
|
||||
|
||||
// By invariant, there must always be at least one schedule
|
||||
if (schedules.length === 0) {
|
||||
createSchedule('Schedule 1');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,5 +36,14 @@ export default async function createSchedule(scheduleName: string) {
|
||||
schedules.push(newSchedule);
|
||||
|
||||
await UserScheduleStore.set('schedules', schedules);
|
||||
|
||||
// Automatically switch to the new schedule
|
||||
await UserScheduleStore.set('activeIndex', schedules.length - 1);
|
||||
|
||||
// If there is only one schedule, set the active index to the new schedule
|
||||
if (schedules.length <= 1) {
|
||||
await UserScheduleStore.set('activeIndex', 0);
|
||||
}
|
||||
|
||||
return newSchedule.id;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ export default async function deleteSchedule(scheduleId: string): Promise<string
|
||||
schedules.splice(scheduleIndex, 1);
|
||||
await UserScheduleStore.set('schedules', schedules);
|
||||
|
||||
// By invariant, there must always be at least one schedule
|
||||
if (schedules.length === 0) {
|
||||
createSchedule('Schedule 1');
|
||||
}
|
||||
|
||||
let newActiveIndex = activeIndex;
|
||||
if (scheduleIndex < activeIndex) {
|
||||
newActiveIndex = activeIndex - 1;
|
||||
|
||||
@@ -31,5 +31,9 @@ export default async function duplicateSchedule(scheduleId: string): Promise<str
|
||||
} satisfies typeof schedule);
|
||||
|
||||
await UserScheduleStore.set('schedules', schedules);
|
||||
|
||||
// Automatically switch to the duplicated schedule
|
||||
await UserScheduleStore.set('activeIndex', scheduleIndex + 1);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import Calendar from '@views/components/calendar/Calendar';
|
||||
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||
import { MigrationDialog } from '@views/components/common/MigrationDialog';
|
||||
import { WhatsNewDialog } from '@views/components/common/WhatsNewPopup';
|
||||
import SentryProvider from '@views/contexts/SentryContext';
|
||||
import { MessageListener } from 'chrome-extension-toolkit';
|
||||
import useKC_DABR_WASM from 'kc-dabr-wasm';
|
||||
@@ -34,6 +35,7 @@ export default function CalendarMain() {
|
||||
<ExtensionRoot className='h-full w-full'>
|
||||
<DialogProvider>
|
||||
<MigrationDialog />
|
||||
<WhatsNewDialog />
|
||||
<Calendar />
|
||||
</DialogProvider>
|
||||
</ExtensionRoot>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import CourseCatalogMain from '@views/components/CourseCatalogMain';
|
||||
import InjectedButton from '@views/components/injected/AddAllButton';
|
||||
import DaysCheckbox from '@views/components/injected/DaysCheckbox';
|
||||
import ShadedResults from '@views/components/injected/SearchResultShader';
|
||||
import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport';
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
@@ -25,3 +27,11 @@ if (support === SiteSupport.COURSE_CATALOG_DETAILS || support === SiteSupport.CO
|
||||
if (support === SiteSupport.MY_UT) {
|
||||
renderComponent(InjectedButton);
|
||||
}
|
||||
|
||||
if (support === SiteSupport.COURSE_CATALOG_SEARCH) {
|
||||
renderComponent(DaysCheckbox);
|
||||
}
|
||||
|
||||
if (support === SiteSupport.COURSE_CATALOG_KWS) {
|
||||
renderComponent(ShadedResults);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ interface IExtensionStore {
|
||||
version: string;
|
||||
/** When was the last update */
|
||||
lastUpdate: number;
|
||||
/** The last version of the "What's New" popup that was shown to the user */
|
||||
lastWhatsNewPopupVersion: number;
|
||||
}
|
||||
|
||||
export const ExtensionStore = createLocalStore<IExtensionStore>({
|
||||
version: chrome.runtime.getManifest().version,
|
||||
lastUpdate: Date.now(),
|
||||
lastWhatsNewPopupVersion: 0,
|
||||
});
|
||||
|
||||
debugStore({ ExtensionStore });
|
||||
|
||||
@@ -18,6 +18,14 @@ export interface IOptionsStore {
|
||||
|
||||
/** whether we should open the calendar in a new tab; default is to focus an existing calendar tab */
|
||||
alwaysOpenCalendarInNewTab: boolean;
|
||||
|
||||
/** whether the calendar sidebar should be shown when the calendar is opened */
|
||||
showCalendarSidebar: boolean;
|
||||
|
||||
/** whether the promo should be shown */
|
||||
showUTDiningPromo: boolean;
|
||||
/** whether users are allowed to bypass the 10 schedule limit */
|
||||
allowMoreSchedules: boolean;
|
||||
}
|
||||
|
||||
export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||
@@ -26,6 +34,9 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||
enableScrollToLoad: true,
|
||||
enableDataRefreshing: false,
|
||||
alwaysOpenCalendarInNewTab: false,
|
||||
showCalendarSidebar: true,
|
||||
showUTDiningPromo: true,
|
||||
allowMoreSchedules: false,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -40,6 +51,9 @@ export const initSettings = async () =>
|
||||
enableScrollToLoad: await OptionsStore.get('enableScrollToLoad'),
|
||||
enableDataRefreshing: await OptionsStore.get('enableDataRefreshing'),
|
||||
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
||||
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
||||
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
||||
allowMoreSchedules: await OptionsStore.get('allowMoreSchedules'),
|
||||
}) satisfies IOptionsStore;
|
||||
|
||||
// Clothing retailer right
|
||||
|
||||
@@ -44,7 +44,12 @@ export type Semester = {
|
||||
export class Course {
|
||||
/** Every course has a uniqueId within UT's registrar system corresponding to each course section */
|
||||
uniqueId!: number;
|
||||
/** This is the course number for a course, i.e CS 314 would be 314, MAL 306H would be 306H */
|
||||
/**
|
||||
* This is the course number for a course, i.e CS 314 would be 314, MAL 306H would be 306H.
|
||||
* UT prefixes summer courses with f, s, n, or w:
|
||||
* [f]irst term, [s]econd term, [n]ine week term, [w]hole term.
|
||||
* So, the first term of PSY 301 over the summer would be 'f301'
|
||||
*/
|
||||
number!: string;
|
||||
/** The full name of the course, i.e. CS 314 Data Structures and Algorithms */
|
||||
fullName!: string;
|
||||
@@ -91,6 +96,46 @@ export class Course {
|
||||
}
|
||||
this.colors = course.colors ? structuredClone(course.colors) : getCourseColors('emerald', 500);
|
||||
this.core = course.core ?? [];
|
||||
if (course.semester.season === 'Summer') {
|
||||
// A bug from and old version put the summer term in the course,
|
||||
// so we need to handle that case
|
||||
const { department, number } = Course.cleanSummerTerm(course.department, course.number);
|
||||
this.department = department;
|
||||
this.number = number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to a bug in an older version, the summer term was included in the course department code,
|
||||
* instead of the course number.
|
||||
* UT prefixes summer courses with f, s, n, or w:
|
||||
* [f]irst term, [s]econd term, [n]ine week term, [w]hole term
|
||||
*
|
||||
* @param department - The course department code, like 'C S'
|
||||
* @param number - The course number, like '314H'
|
||||
* @returns The properly formatted department and course number
|
||||
* @example
|
||||
* ```ts
|
||||
* cleanSummerTerm('C S', '314H') // { department: 'C S', number: '314H' }
|
||||
* cleanSummerTerm('P R', 'f378') // { department: 'P R', number: 'f378' }
|
||||
* cleanSummerTerm('P R f', '378') // { department: 'P R', number: 'f378' }
|
||||
* cleanSummerTerm('P S', 'n303') // { department: 'P S', number: 'n303' }
|
||||
* cleanSummerTerm('P S n', '303') // { department: 'P S', number: 'n303' }
|
||||
* ```
|
||||
*/
|
||||
static cleanSummerTerm(department: string, number: string): { department: string; number: string } {
|
||||
// UT prefixes summer courses with f, s, n, or w:
|
||||
// [f]irst term, [s]econd term, [n]ine week term, [w]hole term
|
||||
const summerTerm = department.match(/[fsnw]$/);
|
||||
|
||||
if (!summerTerm) {
|
||||
return { department, number };
|
||||
}
|
||||
|
||||
return {
|
||||
department: department.slice(0, -1).trim(),
|
||||
number: summerTerm[0] + number,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,6 +156,18 @@ export class Course {
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The course number without the summer term
|
||||
* @example
|
||||
* ```ts
|
||||
* const c = new Course({ number: 'f301', ... });
|
||||
* c.getNumberWithoutTerm() // '301'
|
||||
* ```
|
||||
*/
|
||||
getNumberWithoutTerm(): string {
|
||||
return this.number.replace(/^\D/, ''); // Remove nondigit at start, if it exists
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
57
src/shared/types/tests/Course.test.ts
Normal file
57
src/shared/types/tests/Course.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { Course } from '../Course';
|
||||
|
||||
describe('Course::cleanSummerTerm', () => {
|
||||
it("shouldn't affect already cleaned summer terms", () => {
|
||||
const inputs = [
|
||||
['C S', '314H'],
|
||||
['P R', 'f378'],
|
||||
['P S', 'f303'],
|
||||
['WGS', 's301'],
|
||||
['S W', 'n360K'],
|
||||
['GOV', 'w312L'],
|
||||
['J', 's311F'],
|
||||
['J S', '311F'],
|
||||
] as const;
|
||||
const expected = [
|
||||
{ department: 'C S', number: '314H' },
|
||||
{ department: 'P R', number: 'f378' },
|
||||
{ department: 'P S', number: 'f303' },
|
||||
{ department: 'WGS', number: 's301' },
|
||||
{ department: 'S W', number: 'n360K' },
|
||||
{ department: 'GOV', number: 'w312L' },
|
||||
{ department: 'J', number: 's311F' },
|
||||
{ department: 'J S', number: '311F' },
|
||||
];
|
||||
|
||||
const results = inputs.map(input => Course.cleanSummerTerm(input[0], input[1]));
|
||||
|
||||
expect(results).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should move summer term indicator to course number', () => {
|
||||
const inputs = [
|
||||
['P R f', '378'],
|
||||
['P S f', '303'],
|
||||
['WGS s', '301'],
|
||||
['S W n', '360K'],
|
||||
['GOV w', '312L'],
|
||||
['J s', '311F'],
|
||||
['J S', '311F'],
|
||||
] as const;
|
||||
const expected = [
|
||||
{ department: 'P R', number: 'f378' },
|
||||
{ department: 'P S', number: 'f303' },
|
||||
{ department: 'WGS', number: 's301' },
|
||||
{ department: 'S W', number: 'n360K' },
|
||||
{ department: 'GOV', number: 'w312L' },
|
||||
{ department: 'J', number: 's311F' },
|
||||
{ department: 'J S', number: '311F' },
|
||||
];
|
||||
|
||||
const results = inputs.map(input => Course.cleanSummerTerm(input[0], input[1]));
|
||||
|
||||
expect(results).toEqual(expected);
|
||||
});
|
||||
});
|
||||
19
src/shared/util/appUrls.ts
Normal file
19
src/shared/util/appUrls.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* This file contains URLs for external applications and resources.
|
||||
* Centralizing these URLs makes it easier to track, update, and manage them in a single place.
|
||||
*/
|
||||
|
||||
/**
|
||||
* URL to the UT Dining app on the App Store
|
||||
*/
|
||||
export const UT_DINING_APP_STORE_URL = new URL('https://apps.apple.com/us/app/ut-dining/id6743042002').toString();
|
||||
|
||||
/**
|
||||
* URL to the UT Dining app on the Google Play Store (currently not available)
|
||||
*/
|
||||
export const UT_DINING_GOOGLE_PLAY_URL = ''; // Placeholder for Google Play URL, Android app not available yet
|
||||
|
||||
/**
|
||||
* URL to the promo image
|
||||
*/
|
||||
export const UT_DINING_PROMO_IMAGE_URL = new URL('https://cdn.longhorns.dev/ut-dining-advert1.png').toString();
|
||||
@@ -48,3 +48,22 @@ export const ellipsify = (input: string, chars: number): string => {
|
||||
}
|
||||
return ellipisifed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies a list of items in English format.
|
||||
*
|
||||
* @param items - The list of items to stringify.
|
||||
* @returns A string representation of the list in English format.
|
||||
* @example
|
||||
* englishStringifyList([]) // ''
|
||||
* englishStringifyList(['Alice']) // 'Alice'
|
||||
* englishStringifyList(['Alice', 'Bob']) // 'Alice and Bob'
|
||||
* englishStringifyList(['Alice', 'Bob', 'Charlie']) // 'Alice, Bob, and Charlie'
|
||||
*/
|
||||
export const englishStringifyList = (items: readonly string[]): string => {
|
||||
if (items.length === 0) return '';
|
||||
if (items.length === 1) return items[0]!;
|
||||
if (items.length === 2) return `${items[0]} and ${items[1]}`;
|
||||
|
||||
return `${items.slice(0, -1).join(', ')}, and ${items.at(-1)}`;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { capitalize, capitalizeFirstLetter, ellipsify } from '@shared/util/string';
|
||||
import { capitalize, capitalizeFirstLetter, ellipsify, englishStringifyList } from '@shared/util/string';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
// TODO: Fix `string.ts` and `string.test.ts` to make the tests pass
|
||||
@@ -54,3 +54,49 @@ describe('ellipsify', () => {
|
||||
expect(ellipsify('', 5)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('englishStringifyList', () => {
|
||||
it('should handle an empty array', () => {
|
||||
const data = [] satisfies string[];
|
||||
const result = englishStringifyList(data);
|
||||
const expected = '';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle 1 element', () => {
|
||||
const data = ['Alice'] satisfies string[];
|
||||
const result = englishStringifyList(data);
|
||||
const expected = 'Alice';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle 2 elements', () => {
|
||||
const data = ['Alice', 'Bob'] satisfies string[];
|
||||
const result = englishStringifyList(data);
|
||||
const expected = 'Alice and Bob';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle 3 elements', () => {
|
||||
const data = ['Alice', 'Bob', 'Charlie'] satisfies string[];
|
||||
const result = englishStringifyList(data);
|
||||
const expected = 'Alice, Bob, and Charlie';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle n elements', () => {
|
||||
const testcases = [
|
||||
{ data: [], expected: '' },
|
||||
{ data: ['foo'], expected: 'foo' },
|
||||
{ data: ['foo', 'bar'], expected: 'foo and bar' },
|
||||
{ data: ['foo', 'bar', 'baz'], expected: 'foo, bar, and baz' },
|
||||
{ data: ['a', 'b', 'c', 'd'], expected: 'a, b, c, and d' },
|
||||
{ data: 'abcdefghijk'.split(''), expected: 'a, b, c, d, e, f, g, h, i, j, and k' },
|
||||
] satisfies { data: string[]; expected: string }[];
|
||||
|
||||
for (const { data, expected } of testcases) {
|
||||
const result = englishStringifyList(data);
|
||||
expect(result).toBe(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,11 +3,13 @@ import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('sleep', () => {
|
||||
it('should resolve after the specified number of milliseconds', async () => {
|
||||
const start = Date.now();
|
||||
const start = performance.now();
|
||||
const milliseconds = 1000;
|
||||
await sleep(milliseconds);
|
||||
const end = Date.now();
|
||||
const end = performance.now();
|
||||
const elapsed = end - start;
|
||||
expect(elapsed).toBeGreaterThanOrEqual(milliseconds);
|
||||
// Flaky test due to JS's lack of precision in setTimeout,
|
||||
// so we allow for a 1ms difference
|
||||
expect(elapsed).toBeGreaterThanOrEqual(milliseconds - 1);
|
||||
});
|
||||
});
|
||||
|
||||
14
src/stories/components/DiningAppPromo.stories.tsx
Normal file
14
src/stories/components/DiningAppPromo.stories.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import DiningAppPromo from '@views/components/calendar/DiningAppPromo';
|
||||
|
||||
export default {
|
||||
title: 'Components/Calendar/DiningAppPromo',
|
||||
component: DiningAppPromo,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
} satisfies Meta<typeof DiningAppPromo>;
|
||||
|
||||
type Story = StoryObj<typeof DiningAppPromo>;
|
||||
|
||||
export const Default: Story = {};
|
||||
@@ -73,7 +73,7 @@ const generateCourses = (count: number): Course[] => {
|
||||
|
||||
const exampleCourses = generateCourses(numberOfCourses);
|
||||
|
||||
type CourseWithId = Course & BaseItem;
|
||||
type CourseWithId = { course: Course } & BaseItem;
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Common/SortableList',
|
||||
@@ -91,11 +91,10 @@ export const Default: Story = {
|
||||
args: {
|
||||
draggables: exampleCourses.map(course => ({
|
||||
id: course.uniqueId,
|
||||
...course,
|
||||
getConflicts: course.getConflicts,
|
||||
course,
|
||||
})),
|
||||
onChange: () => {},
|
||||
renderItem: course => <PopupCourseBlock key={course.id} course={course} colors={course.colors} />,
|
||||
renderItem: ({ id, course }) => <PopupCourseBlock key={id} course={course} colors={course.colors} />,
|
||||
},
|
||||
render: args => (
|
||||
<div className='h-3xl w-3xl transform-none'>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import type { UpdateTextProps } from '@views/components/common/UpdateText';
|
||||
import UpdateText from '@views/components/common/UpdateText';
|
||||
import React from 'react';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Common/UpdateText',
|
||||
component: UpdateText,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
courses: { control: 'object' },
|
||||
},
|
||||
} satisfies Meta<typeof UpdateText>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const Template = (args: React.JSX.IntrinsicAttributes & UpdateTextProps) => <UpdateText {...args} />;
|
||||
|
||||
export const Default: Story = {
|
||||
render: Template,
|
||||
args: {
|
||||
courses: ['12345', '23456', '34567', '45678', '56789'],
|
||||
},
|
||||
};
|
||||
Default.args = {
|
||||
courses: ['12345', '23456', '34567', '45678', '56789'],
|
||||
};
|
||||
38
src/stories/components/WhatsNewPopup.stories.tsx
Normal file
38
src/stories/components/WhatsNewPopup.stories.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
||||
import WhatsNewPopup from '@views/components/common/WhatsNewPopup';
|
||||
import useWhatsNewPopUp from '@views/hooks/useWhatsNew';
|
||||
import React from 'react';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Common/WhatsNewPopup',
|
||||
component: WhatsNewPopup,
|
||||
parameters: {
|
||||
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
||||
layout: 'centered',
|
||||
},
|
||||
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof WhatsNewPopup>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Primary: Story = {
|
||||
render: () => (
|
||||
<DialogProvider>
|
||||
<InnerComponent />
|
||||
</DialogProvider>
|
||||
),
|
||||
};
|
||||
|
||||
const InnerComponent = () => {
|
||||
const handleOnClick = useWhatsNewPopUp();
|
||||
|
||||
return (
|
||||
<Button color='ut-burntorange' onClick={handleOnClick}>
|
||||
Open Dialog
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -174,3 +174,137 @@ export const mikeScottCS314Schedule: UserSchedule = new UserSchedule({
|
||||
hours: 3,
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
|
||||
export const multiMeetingMultiInstructorCourse: Course = new Course({
|
||||
colors: {
|
||||
primaryColor: '#ef4444',
|
||||
secondaryColor: '#991b1b',
|
||||
},
|
||||
core: [],
|
||||
courseName: '44-REPORTING TEXAS',
|
||||
creditHours: 3,
|
||||
department: 'J',
|
||||
description: [
|
||||
"Contemporary social, professional, and intellectual concerns with the practice of journalism. Students work as online reporters, photographers, and editors for the School of Journalism's Reporting Texas Web site.",
|
||||
'Prerequisite: Graduate standing; additional prerequisites vary with the topic.',
|
||||
'Designed to accommodate 35 or fewer students. Course number may be repeated for credit when the topics vary.',
|
||||
],
|
||||
flags: [],
|
||||
fullName: 'J 395 44-REPORTING TEXAS',
|
||||
instructionMode: 'In Person',
|
||||
instructors: [
|
||||
{
|
||||
firstName: 'JOHN',
|
||||
fullName: 'SCHWARTZ, JOHN R',
|
||||
lastName: 'SCHWARTZ',
|
||||
middleInitial: 'R',
|
||||
},
|
||||
{
|
||||
firstName: 'JOHN',
|
||||
fullName: 'BRIDGES, JOHN A III',
|
||||
lastName: 'BRIDGES',
|
||||
middleInitial: 'A',
|
||||
},
|
||||
],
|
||||
isReserved: true,
|
||||
number: '395',
|
||||
schedule: {
|
||||
meetings: [
|
||||
{
|
||||
days: ['Tuesday', 'Thursday'],
|
||||
endTime: 660,
|
||||
location: {
|
||||
building: 'CMA',
|
||||
room: '6.146',
|
||||
},
|
||||
startTime: 570,
|
||||
},
|
||||
{
|
||||
days: ['Friday'],
|
||||
endTime: 960,
|
||||
location: {
|
||||
building: 'DMC',
|
||||
room: '3.208',
|
||||
},
|
||||
startTime: 780,
|
||||
},
|
||||
],
|
||||
},
|
||||
scrapedAt: 1742491957535,
|
||||
semester: {
|
||||
code: '20259',
|
||||
season: 'Fall',
|
||||
year: 2025,
|
||||
},
|
||||
status: 'OPEN',
|
||||
uniqueId: 10335,
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/10335/',
|
||||
});
|
||||
|
||||
export const multiMeetingMultiInstructorSchedule: UserSchedule = new UserSchedule({
|
||||
courses: [multiMeetingMultiInstructorCourse],
|
||||
id: 'mmmis',
|
||||
name: 'Multi Meeting Multi Instructor Schedule',
|
||||
hours: 3,
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
|
||||
export const chatterjeeCS429Course: Course = new Course({
|
||||
colors: {
|
||||
primaryColor: '#0284c7',
|
||||
secondaryColor: '#0c4a6e',
|
||||
},
|
||||
core: [],
|
||||
courseName: 'COMP ORGANIZATN AND ARCH',
|
||||
creditHours: 4,
|
||||
department: 'C S',
|
||||
description: [
|
||||
'Restricted to computer science majors.',
|
||||
'An introduction to low-level computer design ranging from the basics of digital design to the hardware/software interface for application programs. Includes basic systems principles of pipelining and caching, and requires writing and understanding programs at multiple levels.',
|
||||
'Computer Science 429 and 429H may not both be counted.',
|
||||
'Prerequisite: The following courses with a grade of at least C-: Computer Science 311 or 311H; and Computer Science 314 or 314H.',
|
||||
],
|
||||
flags: [],
|
||||
fullName: 'C S 429 COMP ORGANIZATN AND ARCH',
|
||||
instructionMode: 'In Person',
|
||||
instructors: [
|
||||
{
|
||||
firstName: 'SIDDHARTHA',
|
||||
fullName: 'CHATTERJEE, SIDDHARTHA',
|
||||
lastName: 'CHATTERJEE',
|
||||
},
|
||||
],
|
||||
isReserved: true,
|
||||
number: '429',
|
||||
schedule: {
|
||||
meetings: [
|
||||
{
|
||||
days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday'],
|
||||
endTime: 1020,
|
||||
location: {
|
||||
building: 'UTC',
|
||||
room: '3.102',
|
||||
},
|
||||
startTime: 960,
|
||||
},
|
||||
{
|
||||
days: ['Friday'],
|
||||
endTime: 660,
|
||||
location: {
|
||||
building: 'GSB',
|
||||
room: '2.122',
|
||||
},
|
||||
startTime: 540,
|
||||
},
|
||||
],
|
||||
},
|
||||
scrapedAt: 1742496630445,
|
||||
semester: {
|
||||
code: '20259',
|
||||
season: 'Fall',
|
||||
year: 2025,
|
||||
},
|
||||
status: 'OPEN',
|
||||
uniqueId: 54795,
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/54795/',
|
||||
});
|
||||
|
||||
@@ -13,7 +13,9 @@ import { CourseCatalogScraper } from '@views/lib/CourseCatalogScraper';
|
||||
import getCourseTableRows from '@views/lib/getCourseTableRows';
|
||||
import type { SiteSupportType } from '@views/lib/getSiteSupport';
|
||||
import { populateSearchInputs } from '@views/lib/populateSearchInputs';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import DialogProvider from './common/DialogProvider/DialogProvider';
|
||||
|
||||
interface Props {
|
||||
support: Extract<SiteSupportType, 'COURSE_CATALOG_DETAILS' | 'COURSE_CATALOG_LIST'>;
|
||||
@@ -27,6 +29,8 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
|
||||
const [selectedCourse, setSelectedCourse] = useState<Course | null>(null);
|
||||
const [showPopup, setShowPopup] = useState(false);
|
||||
const [enableScrollToLoad, setEnableScrollToLoad] = useState<boolean>(false);
|
||||
const prevCourseTitleRef = useRef<string | null>(null);
|
||||
const tbody = document.querySelector('table tbody')!;
|
||||
|
||||
useEffect(() => {
|
||||
populateSearchInputs();
|
||||
@@ -43,6 +47,9 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
|
||||
const ccs = new CourseCatalogScraper(support);
|
||||
const scrapedRows = ccs.scrape(tableRows, true);
|
||||
setRows(scrapedRows);
|
||||
prevCourseTitleRef.current =
|
||||
scrapedRows.findLast(row => row.course === null)?.element.querySelector('.course_header')?.textContent ??
|
||||
null;
|
||||
}, [support]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -51,8 +58,17 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
|
||||
|
||||
const addRows = (newRows: ScrapedRow[]) => {
|
||||
newRows.forEach(row => {
|
||||
document.querySelector('table tbody')!.appendChild(row.element);
|
||||
const courseTitle = row.element.querySelector('.course_header')?.textContent ?? null;
|
||||
if (row.course === null) {
|
||||
if (courseTitle !== prevCourseTitleRef.current) {
|
||||
tbody.appendChild(row.element);
|
||||
prevCourseTitleRef.current = courseTitle;
|
||||
}
|
||||
} else {
|
||||
tbody.appendChild(row.element);
|
||||
}
|
||||
});
|
||||
|
||||
setRows([...rows, ...newRows]);
|
||||
};
|
||||
|
||||
@@ -68,6 +84,7 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
|
||||
|
||||
return (
|
||||
<ExtensionRoot>
|
||||
<DialogProvider>
|
||||
<NewSearchLink />
|
||||
<RecruitmentBanner />
|
||||
<TableHead>Plus</TableHead>
|
||||
@@ -90,6 +107,7 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
|
||||
afterLeave={() => setSelectedCourse(null)}
|
||||
/>
|
||||
{enableScrollToLoad && <AutoLoad addRows={addRows} />}
|
||||
</DialogProvider>
|
||||
</ExtensionRoot>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,11 +66,19 @@ export default function PopupMain(): JSX.Element {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const randomIndex = Math.floor(Math.random() * splashText.length);
|
||||
setFunny(
|
||||
splashText[randomIndex] ?? 'If you are seeing this, something has gone horribly wrong behind the scenes.'
|
||||
setFunny(prevFunny => {
|
||||
// Ensure that the next splash text is not the same as the previous one
|
||||
const splashTextWithoutCurrent = splashText.filter(text => text !== prevFunny);
|
||||
const randomIndex = Math.floor(Math.random() * splashTextWithoutCurrent.length);
|
||||
|
||||
return (
|
||||
splashTextWithoutCurrent[randomIndex] ??
|
||||
'If you are seeing this, something has gone horribly wrong behind the scenes.'
|
||||
);
|
||||
}, []);
|
||||
});
|
||||
|
||||
// Generate a new splash text every time the active schedule changes
|
||||
}, [activeSchedule.id]);
|
||||
|
||||
const handleOpenOptions = async () => {
|
||||
const url = chrome.runtime.getURL('/options.html');
|
||||
@@ -147,15 +155,14 @@ export default function PopupMain(): JSX.Element {
|
||||
<SortableList
|
||||
draggables={activeSchedule.courses.map(course => ({
|
||||
id: course.uniqueId,
|
||||
...course,
|
||||
getConflicts: course.getConflicts,
|
||||
course,
|
||||
}))}
|
||||
onChange={reordered => {
|
||||
activeSchedule.courses = reordered.map(({ id: _id, ...course }) => course);
|
||||
activeSchedule.courses = reordered.map(({ course }) => course);
|
||||
replaceSchedule(getActiveSchedule(), activeSchedule);
|
||||
}}
|
||||
renderItem={course => (
|
||||
<PopupCourseBlock key={course.id} course={course} colors={course.colors} />
|
||||
renderItem={({ id, course }) => (
|
||||
<PopupCourseBlock key={id} course={course} colors={course.colors} />
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Sidebar } from '@phosphor-icons/react';
|
||||
import type { CalendarTabMessages } from '@shared/messages/CalendarMessages';
|
||||
import { OptionsStore } from '@shared/storage/OptionsStore';
|
||||
import type { Course } from '@shared/types/Course';
|
||||
import { CRX_PAGES } from '@shared/types/CRXPages';
|
||||
import { openReportWindow } from '@shared/util/openReportWindow';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import CalendarBottomBar from '@views/components/calendar/CalendarBottomBar';
|
||||
import CalendarGrid from '@views/components/calendar/CalendarGrid';
|
||||
import CalendarHeader from '@views/components/calendar/CalendarHeader/CalendarHeader';
|
||||
@@ -13,8 +15,10 @@ import CourseCatalogInjectedPopup from '@views/components/injected/CourseCatalog
|
||||
import { CalendarContext } from '@views/contexts/CalendarContext';
|
||||
import useCourseFromUrl from '@views/hooks/useCourseFromUrl';
|
||||
import { useFlattenedCourseSchedule } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import useWhatsNewPopUp from '@views/hooks/useWhatsNew';
|
||||
import { MessageListener } from 'chrome-extension-toolkit';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import OutwardArrowIcon from '~icons/material-symbols/arrow-outward';
|
||||
@@ -23,17 +27,39 @@ import { Button } from '../common/Button';
|
||||
import { LargeLogo } from '../common/LogoIcon';
|
||||
import Text from '../common/Text/Text';
|
||||
import CalendarFooter from './CalendarFooter';
|
||||
import DiningAppPromo from './DiningAppPromo';
|
||||
|
||||
/**
|
||||
* Calendar page component
|
||||
*/
|
||||
export default function Calendar(): JSX.Element {
|
||||
export default function Calendar(): ReactNode {
|
||||
const { courseCells, activeSchedule } = useFlattenedCourseSchedule();
|
||||
const asyncCourseCells = courseCells.filter(block => block.async);
|
||||
const displayBottomBar = asyncCourseCells && asyncCourseCells.length > 0;
|
||||
|
||||
const [course, setCourse] = useState<Course | null>(useCourseFromUrl());
|
||||
|
||||
const [showPopup, setShowPopup] = useState<boolean>(course !== null);
|
||||
const [showSidebar, setShowSidebar] = useState<boolean>(true);
|
||||
const showWhatsNewDialog = useWhatsNewPopUp();
|
||||
|
||||
const [showUTDiningPromo, setShowUTDiningPromo] = useState<boolean>(false);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { data: showSidebar, isPending: isSidebarStatePending } = useQuery({
|
||||
queryKey: ['settings', 'showCalendarSidebar'],
|
||||
queryFn: () => OptionsStore.get('showCalendarSidebar'),
|
||||
staleTime: Infinity, // Prevent loading state on refocus
|
||||
});
|
||||
|
||||
const { mutate: setShowSidebar } = useMutation({
|
||||
mutationKey: ['settings', 'showCalendarSidebar'],
|
||||
mutationFn: async (showSidebar: boolean) => {
|
||||
OptionsStore.set('showCalendarSidebar', showSidebar);
|
||||
},
|
||||
onSuccess: (_, showSidebar) => {
|
||||
queryClient.setQueryData(['settings', 'showCalendarSidebar'], showSidebar);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = new MessageListener<CalendarTabMessages>({
|
||||
@@ -59,10 +85,19 @@ export default function Calendar(): JSX.Element {
|
||||
if (course) setShowPopup(true);
|
||||
}, [course]);
|
||||
|
||||
useEffect(() => {
|
||||
// Load the user's preference for the promo
|
||||
OptionsStore.get('showUTDiningPromo').then(show => {
|
||||
setShowUTDiningPromo(show);
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (isSidebarStatePending) return null;
|
||||
|
||||
return (
|
||||
<CalendarContext.Provider value>
|
||||
<div className='h-full w-full flex flex-col'>
|
||||
<div className='h-screen flex overflow-auto'>
|
||||
<div className='screenshot:calendar-target h-screen flex overflow-auto'>
|
||||
<div
|
||||
className={clsx(
|
||||
'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-ut-offwhite/50 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] motion-safe:duration-300 motion-safe:ease-out-expo motion-safe:transition-[max-width] screenshot:hidden',
|
||||
@@ -97,8 +132,17 @@ export default function Calendar(): JSX.Element {
|
||||
<CalendarSchedules />
|
||||
<Divider orientation='horizontal' size='100%' />
|
||||
<ResourceLinks />
|
||||
<Divider orientation='horizontal' size='100%' />
|
||||
{/* <TeamLinks /> */}
|
||||
<Divider orientation='horizontal' size='100%' />
|
||||
{showUTDiningPromo && (
|
||||
<DiningAppPromo
|
||||
onClose={() => {
|
||||
setShowUTDiningPromo(false);
|
||||
OptionsStore.set('showUTDiningPromo', false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className='flex flex-col gap-spacing-3'>
|
||||
<a
|
||||
href={CRX_PAGES.REPORT}
|
||||
className='flex items-center gap-spacing-2 text-ut-burntorange underline-offset-2 hover:underline'
|
||||
@@ -112,6 +156,20 @@ export default function Calendar(): JSX.Element {
|
||||
<Text variant='p'>Send us Feedback!</Text>
|
||||
<OutwardArrowIcon className='h-4 w-4' />
|
||||
</a>
|
||||
<a
|
||||
href=''
|
||||
className='flex items-center gap-spacing-2 text-ut-burntorange underline-offset-2 hover:underline'
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
onClick={event => {
|
||||
event.preventDefault();
|
||||
showWhatsNewDialog();
|
||||
}}
|
||||
>
|
||||
<Text variant='p'>What's New!</Text>
|
||||
<OutwardArrowIcon className='h-4 w-4' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CalendarFooter />
|
||||
@@ -123,7 +181,7 @@ export default function Calendar(): JSX.Element {
|
||||
// scrollbarGutter: 'stable',
|
||||
}
|
||||
}
|
||||
className='h-full flex flex-grow flex-col overflow-x-scroll px-spacing-5'
|
||||
className='z-1 h-full flex flex-grow flex-col overflow-x-scroll [&>*]:px-spacing-5'
|
||||
>
|
||||
<CalendarHeader
|
||||
sidebarOpen={showSidebar}
|
||||
@@ -131,7 +189,11 @@ export default function Calendar(): JSX.Element {
|
||||
setShowSidebar(!showSidebar);
|
||||
}}
|
||||
/>
|
||||
<div className='min-h-2xl min-w-5xl flex-grow overflow-auto pl-spacing-3 pt-spacing-3 screenshot:min-h-xl'>
|
||||
<div
|
||||
className={clsx('min-h-2xl min-w-5xl flex-grow gap-0 pl-spacing-3 screenshot:min-h-xl', {
|
||||
'screenshot:flex-grow-0': displayBottomBar, // html-to-image seems to have a bug with flex-grow
|
||||
})}
|
||||
>
|
||||
<CalendarGrid courseCells={courseCells} setCourse={setCourse} />
|
||||
</div>
|
||||
<CalendarBottomBar courseCells={courseCells} setCourse={setCourse} />
|
||||
|
||||
@@ -3,6 +3,7 @@ import Text from '@views/components/common/Text/Text';
|
||||
import { ColorPickerProvider } from '@views/contexts/ColorPickerContext';
|
||||
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import CalendarCourseBlock from './CalendarCourseCell';
|
||||
@@ -18,19 +19,15 @@ type CalendarBottomBarProps = {
|
||||
* @param courses - The list of courses to display in the calendar.
|
||||
* @returns The rendered bottom bar component.
|
||||
*/
|
||||
export default function CalendarBottomBar({ courseCells, setCourse }: CalendarBottomBarProps): JSX.Element {
|
||||
export default function CalendarBottomBar({ courseCells, setCourse }: CalendarBottomBarProps): ReactNode {
|
||||
const asyncCourseCells = courseCells?.filter(block => block.async);
|
||||
const displayCourses = asyncCourseCells && asyncCourseCells.length > 0;
|
||||
|
||||
if (!displayCourses) return null;
|
||||
|
||||
return (
|
||||
<div className='w-full flex pl-spacing-7 pr-spacing-3 pt-spacing-4'>
|
||||
<div
|
||||
className={clsx('flex flex-grow items-center gap-1 text-nowrap', {
|
||||
'py-7.5': !displayCourses,
|
||||
})}
|
||||
>
|
||||
{displayCourses && (
|
||||
<>
|
||||
<div className='flex flex-grow items-center gap-1 text-nowrap'>
|
||||
<Text variant='p' className='text-ut-black uppercase'>
|
||||
Async / Other
|
||||
</Text>
|
||||
@@ -54,8 +51,6 @@ export default function CalendarBottomBar({ courseCells, setCourse }: CalendarBo
|
||||
})}
|
||||
</ColorPickerProvider>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -27,12 +27,10 @@ export default function HexColorEditor({ hexCode, setHexCode }: HexColorEditorPr
|
||||
const tagColor = pickFontColor(previewColor.slice(1) as `#${string}`);
|
||||
|
||||
const [localHexCode, setLocalHexCode] = React.useState(hexCode);
|
||||
const debouncedSetHexCode = useDebounce((value: string) => setHexCode(value), 500);
|
||||
const debouncedSetHexCode = useDebounce(setHexCode, 500);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (hexCode !== localHexCode) {
|
||||
setLocalHexCode(hexCode);
|
||||
}
|
||||
}, [hexCode]);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
@@ -2,14 +2,18 @@ import type { Course } from '@shared/types/Course';
|
||||
import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import { ColorPickerProvider } from '@views/contexts/ColorPickerContext';
|
||||
import { useSentryScope } from '@views/contexts/SentryContext';
|
||||
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import CalendarCell from './CalendarGridCell';
|
||||
import { calculateCourseCellColumns } from './utils';
|
||||
|
||||
const daysOfWeek = ['MON', 'TUE', 'WED', 'THU', 'FRI'];
|
||||
const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8);
|
||||
|
||||
const IS_STORYBOOK = import.meta.env.STORYBOOK;
|
||||
|
||||
interface Props {
|
||||
courseCells?: CalendarGridCourse[];
|
||||
saturdayClass?: boolean;
|
||||
@@ -30,13 +34,13 @@ function makeGridRow(row: number, cols: number): JSX.Element {
|
||||
const hour = hoursOfDay[row]!;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Fragment key={row}>
|
||||
<CalendarHour hour={hour} />
|
||||
<div className='grid-row-span-2 w-4 border-b border-r border-gray-300' />
|
||||
{[...Array(cols).keys()].map(col => (
|
||||
<CalendarCell key={`${row}${col}`} row={row} col={col} />
|
||||
))}
|
||||
</>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,23 +60,40 @@ export default function CalendarGrid({
|
||||
setCourse,
|
||||
}: React.PropsWithChildren<Props>): JSX.Element {
|
||||
return (
|
||||
<div className='grid grid-cols-[auto_auto_repeat(5,1fr)] grid-rows-[auto_repeat(26,1fr)] h-full'>
|
||||
<div className='grid grid-cols-[auto_auto_repeat(5,1fr)] grid-rows-[auto_auto_repeat(27,1fr)] h-full'>
|
||||
{/* Cover top left corner of grid, so time gets cut off at the top of the partial border */}
|
||||
<div className='sticky top-[85px] z-10 col-span-2 h-3 bg-white' />
|
||||
{/* Displaying day labels */}
|
||||
<div />
|
||||
<div className='w-4 border-b border-r border-gray-300' />
|
||||
{daysOfWeek.map(day => (
|
||||
<div className='h-4 flex items-end justify-center border-b border-r border-gray-300 pb-1.5'>
|
||||
<Text key={day} variant='small' className='text-center text-ut-burntorange' as='div'>
|
||||
<div
|
||||
// Full height with background to prevent grid lines from showing behind
|
||||
className='sticky top-[85px] z-10 row-span-2 h-7 flex flex-col items-end self-start justify-end bg-white'
|
||||
key={day}
|
||||
>
|
||||
{/* Partial border height because that's what Isaiah wants */}
|
||||
<div className='h-4 w-full flex items-end border-b border-r border-gray-300'>
|
||||
{/* Alignment for text */}
|
||||
<div className='h-[calc(1.75rem_-_1px)] w-full flex items-center justify-center'>
|
||||
<Text variant='small' className='text-center text-ut-burntorange' as='div'>
|
||||
{day}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{/* empty slot, for alignment */}
|
||||
<div />
|
||||
{/* time tick for the first hour */}
|
||||
<div className='h-4 w-4 self-end border-b border-r border-gray-300' />
|
||||
{[...Array(13).keys()].map(i => makeGridRow(i, 5))}
|
||||
<CalendarHour hour={21} />
|
||||
{Array(6)
|
||||
.fill(1)
|
||||
.map(() => (
|
||||
<div className='h-4 flex items-end justify-center border-r border-gray-300' />
|
||||
.map((_, i) => (
|
||||
// Key suppresses warning about duplicate keys,
|
||||
// and index is fine because it doesn't change between renders
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div key={i} className='h-4 flex items-end justify-center border-r border-gray-300' />
|
||||
))}
|
||||
<ColorPickerProvider>
|
||||
{courseCells && <AccountForCourseConflicts courseCells={courseCells} setCourse={setCourse} />}
|
||||
@@ -89,6 +110,12 @@ interface AccountForCourseConflictsProps {
|
||||
// TODO: Possibly refactor to be more concise
|
||||
// TODO: Deal with react strict mode (wacky movements)
|
||||
function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseConflictsProps): JSX.Element[] {
|
||||
// Sentry is not defined in storybook.
|
||||
// This is a valid use case for a condition hook, since IS_STORYBOOK is determined at build time,
|
||||
// it doesn't change between renders.
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const [sentryScope] = IS_STORYBOOK ? [undefined] : useSentryScope();
|
||||
|
||||
// Groups by dayIndex to identify overlaps
|
||||
const days = courseCells.reduce(
|
||||
(acc, cell: CalendarGridCourse) => {
|
||||
@@ -103,31 +130,15 @@ function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseC
|
||||
);
|
||||
|
||||
// Check for overlaps within each day and adjust gridColumnIndex and totalColumns
|
||||
Object.values(days).forEach((dayCells: CalendarGridCourse[]) => {
|
||||
// Sort by start time to ensure proper columnIndex assignment
|
||||
dayCells.sort((a, b) => a.calendarGridPoint.startIndex - b.calendarGridPoint.startIndex);
|
||||
|
||||
dayCells.forEach((cell, _, arr) => {
|
||||
let columnIndex = 1;
|
||||
cell.totalColumns = 1;
|
||||
// Check for overlaps and adjust columnIndex as needed
|
||||
for (let otherCell of arr) {
|
||||
if (otherCell !== cell) {
|
||||
const isOverlapping =
|
||||
otherCell.calendarGridPoint.startIndex < cell.calendarGridPoint.endIndex &&
|
||||
otherCell.calendarGridPoint.endIndex > cell.calendarGridPoint.startIndex;
|
||||
if (isOverlapping) {
|
||||
// Adjust columnIndex to not overlap with the otherCell
|
||||
if (otherCell.gridColumnStart && otherCell.gridColumnStart >= columnIndex) {
|
||||
columnIndex = otherCell.gridColumnStart + 1;
|
||||
}
|
||||
cell.totalColumns += 1;
|
||||
Object.values(days).forEach((dayCells: CalendarGridCourse[], idx) => {
|
||||
try {
|
||||
calculateCourseCellColumns(dayCells);
|
||||
} catch (error) {
|
||||
console.error(`Error calculating course cell columns ${idx}`, error);
|
||||
if (sentryScope) {
|
||||
sentryScope.captureException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
cell.gridColumnStart = columnIndex;
|
||||
cell.gridColumnEnd = columnIndex + 1;
|
||||
});
|
||||
});
|
||||
|
||||
return courseCells
|
||||
|
||||
@@ -17,8 +17,8 @@ function CalendarCell({ row, col }: Props): JSX.Element {
|
||||
<div
|
||||
className='h-full w-full flex items-center border-b border-r border-gray-300'
|
||||
style={{
|
||||
gridColumn: col + 3,
|
||||
gridRow: `${2 * row + 2} / ${2 * row + 4}`,
|
||||
gridColumn: col + 3, // start in the 3rd 1-index column
|
||||
gridRow: `${2 * row + 3} / ${2 * row + 5}`, // Span 2 rows, skip 2 header rows
|
||||
}}
|
||||
>
|
||||
<div className='h-0 w-full border-t border-gray-300/25' />
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react';
|
||||
import { CalendarDots, Export, FilePng, Sidebar } from '@phosphor-icons/react';
|
||||
import { CalendarDots, Export, FileCode, FilePng, Sidebar } from '@phosphor-icons/react';
|
||||
import styles from '@views/components/calendar/CalendarHeader/CalendarHeader.module.scss';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
||||
import Divider from '@views/components/common/Divider';
|
||||
import { ExtensionRootWrapper, styleResetClass } from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||
import { LargeLogo } from '@views/components/common/LogoIcon';
|
||||
import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotalHoursAndCourses';
|
||||
import useSchedules from '@views/hooks/useSchedules';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import { saveAsCal, saveCalAsPng } from '../utils';
|
||||
import { handleExportJson, saveAsCal, saveCalAsPng } from '../utils';
|
||||
|
||||
interface CalendarHeaderProps {
|
||||
sidebarOpen?: boolean;
|
||||
@@ -27,7 +28,7 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
|
||||
return (
|
||||
<div
|
||||
style={{ scrollbarGutter: 'stable' }}
|
||||
className='sticky left-0 right-0 min-h-[85px] flex items-center gap-5 overflow-x-scroll overflow-y-hidden pl-spacing-7 pt-spacing-5'
|
||||
className='sticky left-0 right-0 top-0 z-10 min-h-[85px] flex items-center gap-5 overflow-x-scroll overflow-y-hidden bg-white pl-spacing-7 pt-spacing-5'
|
||||
>
|
||||
{!sidebarOpen && (
|
||||
<Button
|
||||
@@ -39,6 +40,9 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
|
||||
/>
|
||||
)}
|
||||
|
||||
<LargeLogo className='hidden! screenshot:flex!' />
|
||||
<Divider className='self-center hidden! screenshot:block!' size='2.5rem' orientation='vertical' />
|
||||
|
||||
<div className='min-w-[11.5rem] screenshot:transform-origin-left screenshot:scale-120'>
|
||||
<ScheduleTotalHoursAndCourses
|
||||
scheduleName={activeSchedule.name}
|
||||
@@ -62,7 +66,7 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
|
||||
className={clsx([
|
||||
styleResetClass,
|
||||
'mt-spacing-3',
|
||||
'min-w-max cursor-pointer origin-top-right rounded bg-white p-1 text-black shadow-lg transition border border-ut-offwhite/50 focus:outline-none',
|
||||
'min-w-max cursor-pointer origin-top-right rounded bg-white p-1 text-black shadow-lg transition border border-ut-offwhite/50 focus:outline-none z-20',
|
||||
'data-[closed]:(opacity-0 scale-95)',
|
||||
'data-[enter]:(ease-out-expo duration-150)',
|
||||
'data-[leave]:(ease-out duration-50)',
|
||||
@@ -94,6 +98,18 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
|
||||
Save as .cal
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<Button
|
||||
className='w-full flex justify-start'
|
||||
onClick={() => handleExportJson(activeSchedule.id)}
|
||||
color='ut-black'
|
||||
size='small'
|
||||
variant='minimal'
|
||||
icon={FileCode}
|
||||
>
|
||||
Save as .json
|
||||
</Button>
|
||||
</MenuItem>
|
||||
{/* <MenuItem>
|
||||
<Button color='ut-black' size='small' variant='minimal' icon={FileTxt}>
|
||||
Export Unique IDs
|
||||
|
||||
69
src/views/components/calendar/DiningAppPromo.tsx
Normal file
69
src/views/components/calendar/DiningAppPromo.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { AppStoreLogo, ForkKnife, X as CloseIcon } from '@phosphor-icons/react';
|
||||
import { UT_DINING_APP_STORE_URL } from '@shared/util/appUrls';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import React from 'react';
|
||||
|
||||
interface DiningAppPromoProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promotional component for the UT Dining app
|
||||
*/
|
||||
export default function DiningAppPromo({ onClose }: DiningAppPromoProps) {
|
||||
return (
|
||||
<div className='relative min-w-[16.25rem] w-full flex items-center gap-spacing-3 border border-ut-offwhite/50 rounded p-spacing-4'>
|
||||
<div className='flex items-center justify-center'>
|
||||
<ForkKnife className='h-6 w-6 text-ut-black' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-spacing-1'>
|
||||
<Text as='p' variant='small' className='whitespace-normal text-ut-black'>
|
||||
Download our new{' '}
|
||||
<a
|
||||
href={UT_DINING_APP_STORE_URL}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
aria-label='UT Dining app'
|
||||
className='text-ut-burntorange underline'
|
||||
>
|
||||
UT Dining app
|
||||
</a>{' '}
|
||||
to explore all dining options on campus!
|
||||
</Text>
|
||||
<div className='mt-spacing-2 flex items-center gap-spacing-2'>
|
||||
<Text variant='mini' className='text-ut-black'>
|
||||
Available on
|
||||
</Text>
|
||||
<a
|
||||
href={UT_DINING_APP_STORE_URL}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
aria-label='Download on App Store'
|
||||
className='text-theme-black transition-colors hover:text-ut-burntorange'
|
||||
>
|
||||
<AppStoreLogo className='h-4.5 w-4.5' />
|
||||
</a>
|
||||
{/* <a
|
||||
href={UT_DINING_GOOGLE_PLAY_URL}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
aria-label='Download on Google Play'
|
||||
className='text-theme-black hover:text-ut-burntorange transition-colors'
|
||||
>
|
||||
<GooglePlayLogo className='h-4.5 w-4.5' />
|
||||
</a> */}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant='minimal'
|
||||
color='theme-black'
|
||||
onClick={onClose}
|
||||
className='absolute right-1 top-1 h-5 w-5 p-0'
|
||||
icon={CloseIcon}
|
||||
aria-label='Close dining app promo'
|
||||
title='Close'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,10 +13,10 @@ interface LinkItem {
|
||||
}
|
||||
|
||||
const links: LinkItem[] = [
|
||||
{
|
||||
text: "Spring '25 Course Schedule",
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/',
|
||||
},
|
||||
// {
|
||||
// text: "Spring '25 Course Schedule",
|
||||
// url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/',
|
||||
// },
|
||||
{
|
||||
text: 'Course Schedule Archives',
|
||||
url: 'https://registrar.utexas.edu/schedules/archive',
|
||||
|
||||
@@ -14,30 +14,30 @@ interface LinkItem {
|
||||
}
|
||||
|
||||
const links: LinkItem[] = [
|
||||
// {
|
||||
// text: "Fall '25 Course Schedule",
|
||||
// url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/',
|
||||
// },
|
||||
// {
|
||||
// text: 'Course Schedule Archives',
|
||||
// url: 'https://registrar.utexas.edu/schedules/archive',
|
||||
// },
|
||||
{
|
||||
text: "Fall '25 Course Schedule",
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/',
|
||||
text: "Spring '26 Course Schedule",
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20262/',
|
||||
},
|
||||
{
|
||||
text: "Summer '25 Course Schedule",
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20256/',
|
||||
},
|
||||
{
|
||||
text: "Spring '25 Course Schedule",
|
||||
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/',
|
||||
},
|
||||
{
|
||||
text: 'Course Schedule Archives',
|
||||
url: 'https://registrar.utexas.edu/schedules/archive',
|
||||
text: 'Other Course Schedules',
|
||||
url: 'https://registrar.utexas.edu/schedules',
|
||||
},
|
||||
{
|
||||
text: 'My Degree Audit (IDA)',
|
||||
url: 'https://utdirect.utexas.edu/apps/degree/audits/',
|
||||
},
|
||||
// {
|
||||
// text: "'24-'25 Academic Calendar",
|
||||
// url: 'https://registrar.utexas.edu/calendars/24-25',
|
||||
// },
|
||||
{
|
||||
text: "'25-'26 Academic Calendar",
|
||||
url: 'https://registrar.utexas.edu/calendars/25-26',
|
||||
},
|
||||
{
|
||||
text: 'Registration Info Sheet (RIS)',
|
||||
url: 'https://utdirect.utexas.edu/registrar/ris.WBX',
|
||||
|
||||
200
src/views/components/calendar/academic-calendars.ts
Normal file
200
src/views/components/calendar/academic-calendars.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
||||
type Year = `20${Digit}${Digit}`;
|
||||
type Month = `0${Exclude<Digit, 0>}` | `1${'0' | '1' | '2'}`;
|
||||
type Day = `0${Exclude<Digit, 0>}` | `${1 | 2}${Digit}` | '30' | '31';
|
||||
type DateStr = `${Year}-${Month}-${Day}`;
|
||||
type SemesterDigit = 2 | 6 | 9;
|
||||
type SemesterIdentifier = `20${Digit}${Digit}${SemesterDigit}`;
|
||||
|
||||
type AcademicCalendarSemester = {
|
||||
year: number;
|
||||
semester: 'Fall' | 'Spring' | 'Summer';
|
||||
firstClassDate: DateStr;
|
||||
lastClassDate: DateStr;
|
||||
breakDates: (DateStr | [DateStr, DateStr])[];
|
||||
};
|
||||
|
||||
/**
|
||||
* UT Austin's academic calendars, split by semester.
|
||||
*
|
||||
* See https://registrar.utexas.edu/calendars for future years.
|
||||
*/
|
||||
export const academicCalendars = {
|
||||
'20229': {
|
||||
year: 2022,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2022-08-22',
|
||||
lastClassDate: '2022-12-05',
|
||||
breakDates: [
|
||||
'2022-09-05', // Labor Day holiday
|
||||
['2022-11-21', '2022-11-26'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20232': {
|
||||
year: 2023,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2023-01-09',
|
||||
lastClassDate: '2023-04-24',
|
||||
breakDates: [
|
||||
'2023-01-16', // Martin Luther King, Jr. Day
|
||||
['2023-03-13', '2023-03-18'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20236': {
|
||||
year: 2023,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2023-06-01',
|
||||
lastClassDate: '2023-08-11',
|
||||
breakDates: [
|
||||
'2023-06-19', // Juneteenth holiday
|
||||
'2023-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
'20239': {
|
||||
year: 2023,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2023-08-21',
|
||||
lastClassDate: '2023-12-04',
|
||||
breakDates: [
|
||||
'2023-09-04', // Labor Day holiday
|
||||
['2023-11-20', '2023-11-25'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20242': {
|
||||
year: 2024,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2024-01-16',
|
||||
lastClassDate: '2024-04-29',
|
||||
breakDates: [
|
||||
'2024-01-15', // Martin Luther King, Jr. Day
|
||||
['2024-03-11', '2024-03-16'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20246': {
|
||||
year: 2024,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2024-06-06',
|
||||
lastClassDate: '2024-08-16',
|
||||
breakDates: [
|
||||
'2024-06-19', // Juneteenth holiday
|
||||
'2024-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
'20249': {
|
||||
year: 2024,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2024-08-26',
|
||||
lastClassDate: '2024-12-09',
|
||||
breakDates: [
|
||||
'2024-09-02', // Labor Day holiday
|
||||
['2024-11-25', '2024-11-30'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20252': {
|
||||
year: 2025,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2025-01-13',
|
||||
lastClassDate: '2025-04-28',
|
||||
breakDates: [
|
||||
'2025-01-20', // Martin Luther King, Jr. Day
|
||||
['2025-03-17', '2025-03-22'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20256': {
|
||||
year: 2025,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2025-06-05',
|
||||
lastClassDate: '2025-08-15',
|
||||
breakDates: [
|
||||
'2025-06-19', // Juneteenth holiday
|
||||
'2025-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
'20259': {
|
||||
year: 2025,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2025-08-25',
|
||||
lastClassDate: '2025-12-08',
|
||||
breakDates: [
|
||||
'2025-09-01', // Labor Day holiday
|
||||
['2025-11-24', '2025-11-29'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20262': {
|
||||
year: 2026,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2026-01-12',
|
||||
lastClassDate: '2026-04-27',
|
||||
breakDates: [
|
||||
'2026-01-19', // Martin Luther King, Jr. Day
|
||||
['2026-03-16', '2026-03-21'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20266': {
|
||||
year: 2026,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2026-06-04',
|
||||
lastClassDate: '2026-08-14',
|
||||
breakDates: [
|
||||
'2026-06-19', // Juneteenth holiday
|
||||
'2026-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
'20269': {
|
||||
year: 2026,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2026-08-24',
|
||||
lastClassDate: '2026-12-07',
|
||||
breakDates: [
|
||||
'2026-09-07', // Labor Day holiday
|
||||
['2026-11-23', '2026-11-28'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20272': {
|
||||
year: 2027,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2027-01-11',
|
||||
lastClassDate: '2027-04-26',
|
||||
breakDates: [
|
||||
'2027-01-18', // Martin Luther King, Jr. Day
|
||||
['2027-03-15', '2027-03-20'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20276': {
|
||||
year: 2027,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2027-06-03',
|
||||
lastClassDate: '2027-08-13',
|
||||
breakDates: [
|
||||
'2027-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
'20279': {
|
||||
year: 2027,
|
||||
semester: 'Fall',
|
||||
firstClassDate: '2027-08-23',
|
||||
lastClassDate: '2027-12-06',
|
||||
breakDates: [
|
||||
'2027-09-06', // Labor Day holiday
|
||||
['2027-11-22', '2027-11-27'], // Fall break / Thanksgiving
|
||||
],
|
||||
},
|
||||
'20282': {
|
||||
year: 2028,
|
||||
semester: 'Spring',
|
||||
firstClassDate: '2028-01-18',
|
||||
lastClassDate: '2028-05-01',
|
||||
breakDates: [
|
||||
['2028-03-13', '2028-03-18'], // Spring Break
|
||||
],
|
||||
},
|
||||
'20286': {
|
||||
year: 2028,
|
||||
semester: 'Summer',
|
||||
firstClassDate: '2028-06-08',
|
||||
lastClassDate: '2028-08-18',
|
||||
breakDates: [
|
||||
'2028-07-04', // Independence Day holiday
|
||||
],
|
||||
},
|
||||
} as const satisfies Partial<Record<SemesterIdentifier, AcademicCalendarSemester>>;
|
||||
@@ -1,6 +1,40 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { tz } from '@date-fns/tz';
|
||||
import { Course } from '@shared/types/Course';
|
||||
import { UserSchedule } from '@shared/types/UserSchedule';
|
||||
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
import { format as formatDate, parseISO } from 'date-fns';
|
||||
import {
|
||||
chatterjeeCS429Course,
|
||||
multiMeetingMultiInstructorCourse,
|
||||
multiMeetingMultiInstructorSchedule,
|
||||
} from 'src/stories/injected/mocked';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { formatToHHMMSS } from './utils';
|
||||
import type { CalendarCourseCellProps } from './CalendarCourseCell';
|
||||
import {
|
||||
allDatesInRanges,
|
||||
calculateCourseCellColumns,
|
||||
formatToHHMMSS,
|
||||
meetingToIcsString,
|
||||
nextDayInclusive,
|
||||
scheduleToIcsString,
|
||||
} from './utils';
|
||||
|
||||
// Do all timezone calculations relative to UT's timezone
|
||||
const TIMEZONE = 'America/Chicago';
|
||||
const TZ = tz(TIMEZONE);
|
||||
|
||||
// Date and datetime formats used by iCal
|
||||
const ISO_DATE_FORMAT = 'yyyy-MM-dd';
|
||||
const ISO_BASIC_DATETIME_FORMAT = "yyyyMMdd'T'HHmmss";
|
||||
|
||||
/**
|
||||
* Simulate serialized class instance, without the class's methods
|
||||
*
|
||||
* serde <-- Serialize, Deserialize
|
||||
*/
|
||||
const serde = <T>(data: T) => JSON.parse(JSON.stringify(data)) as Serialized<T>;
|
||||
|
||||
describe('formatToHHMMSS', () => {
|
||||
it('should format minutes to HHMMSS format', () => {
|
||||
@@ -24,3 +58,624 @@ describe('formatToHHMMSS', () => {
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nextDayInclusive', () => {
|
||||
it('should return the same date if the given day is the same as the target day', () => {
|
||||
const date = parseISO('2024-01-01', { in: TZ }); // Monday
|
||||
const day = 1; // Monday
|
||||
const result = nextDayInclusive(date, day);
|
||||
expect(formatDate(result, ISO_DATE_FORMAT)).toBe('2024-01-01');
|
||||
});
|
||||
|
||||
it('should return the next day if the given day is not the same as the target day', () => {
|
||||
const date = parseISO('2024-07-18', { in: TZ }); // Thursday
|
||||
const day = 2; // Tuesday
|
||||
const result = nextDayInclusive(date, day);
|
||||
expect(formatDate(result, ISO_DATE_FORMAT)).toBe('2024-07-23');
|
||||
});
|
||||
|
||||
it('should wrap around years', () => {
|
||||
const date = parseISO('2025-12-28', { in: TZ }); // Sunday
|
||||
const day = 5; // Friday
|
||||
const result = nextDayInclusive(date, day);
|
||||
expect(formatDate(result, ISO_DATE_FORMAT)).toBe('2026-01-02');
|
||||
});
|
||||
|
||||
it('should handle leap day', () => {
|
||||
const date = parseISO('2024-02-27', { in: TZ }); // Tuesday
|
||||
const day = 4; // Thursday
|
||||
const result = nextDayInclusive(date, day);
|
||||
expect(formatDate(result, ISO_DATE_FORMAT)).toBe('2024-02-29');
|
||||
});
|
||||
|
||||
it('should handle an entire week of inputs', () => {
|
||||
const date = parseISO('2024-08-20', { in: TZ }); // Tuesday
|
||||
const days = [0, 1, 2, 3, 4, 5, 6] as const;
|
||||
const results = days.map(day => nextDayInclusive(date, day));
|
||||
const resultsFormatted = results.map(result => formatDate(result, ISO_DATE_FORMAT));
|
||||
const expectedResults = [
|
||||
'2024-08-25',
|
||||
'2024-08-26',
|
||||
'2024-08-20', // Same date
|
||||
'2024-08-21',
|
||||
'2024-08-22',
|
||||
'2024-08-23',
|
||||
'2024-08-24',
|
||||
];
|
||||
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
expect(resultsFormatted[i]).toBe(expectedResults[i]);
|
||||
}
|
||||
});
|
||||
|
||||
it('should maintain hours/minutes/seconds', () => {
|
||||
const date = parseISO('20250115T143021', { in: TZ }); // Wednesday
|
||||
const days = [0, 1, 2, 3, 4, 5, 6] as const;
|
||||
const results = days.map(day => nextDayInclusive(date, day));
|
||||
const resultsFormatted = results.map(result => formatDate(result, ISO_BASIC_DATETIME_FORMAT));
|
||||
const expectedResults = [
|
||||
'20250119T143021',
|
||||
'20250120T143021',
|
||||
'20250121T143021',
|
||||
'20250115T143021',
|
||||
'20250116T143021',
|
||||
'20250117T143021',
|
||||
'20250118T143021',
|
||||
];
|
||||
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
expect(resultsFormatted[i]).toBe(expectedResults[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('allDatesInRanges', () => {
|
||||
it('should handle empty array', () => {
|
||||
const dateRanges = [] satisfies string[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = [] satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle a single date', () => {
|
||||
const dateRanges = ['2025-03-14'] satisfies (string | [string, string])[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = ['2025-03-14'].map(dateStr => parseISO(dateStr, { in: TZ })) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle a single date', () => {
|
||||
const dateRanges = ['2025-03-14'] satisfies string[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = ['2025-03-14'].map(dateStr => parseISO(dateStr, { in: TZ })) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle a single date range', () => {
|
||||
const dateRanges = [['2025-03-14', '2025-03-19']] satisfies (string | [string, string])[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = ['2025-03-14', '2025-03-15', '2025-03-16', '2025-03-17', '2025-03-18', '2025-03-19'].map(
|
||||
dateStr => parseISO(dateStr, { in: TZ })
|
||||
) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle multiple dates/date ranges', () => {
|
||||
const dateRanges = [
|
||||
'2025-02-14',
|
||||
['2025-03-14', '2025-03-19'],
|
||||
'2026-12-01',
|
||||
['2026-12-03', '2026-12-05'],
|
||||
] satisfies (string | [string, string])[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = [
|
||||
'2025-02-14', // '2025-02-14'
|
||||
'2025-03-14', // ['2025-03-14', '2025-03-19']
|
||||
'2025-03-15',
|
||||
'2025-03-16',
|
||||
'2025-03-17',
|
||||
'2025-03-18',
|
||||
'2025-03-19',
|
||||
'2026-12-01', // '2026-12-01'
|
||||
'2026-12-03', // ['2026-12-03', '2026-12-05'
|
||||
'2026-12-04',
|
||||
'2026-12-05',
|
||||
].map(dateStr => parseISO(dateStr, { in: TZ })) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle month-/year-spanning ranges', () => {
|
||||
const dateRanges = [
|
||||
['2023-02-27', '2023-03-02'],
|
||||
['2023-12-27', '2024-01-03'],
|
||||
] satisfies (string | [string, string])[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = [
|
||||
'2023-02-27', // ['2023-02-27', '2023-03-2']
|
||||
'2023-02-28',
|
||||
'2023-03-01',
|
||||
'2023-03-02',
|
||||
'2023-12-27', // ['2023-12-27', '2024-01-3']
|
||||
'2023-12-28',
|
||||
'2023-12-29',
|
||||
'2023-12-30',
|
||||
'2023-12-31',
|
||||
'2024-01-01',
|
||||
'2024-01-02',
|
||||
'2024-01-03',
|
||||
].map(dateStr => parseISO(dateStr, { in: TZ })) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle leap years', () => {
|
||||
const dateRanges = [
|
||||
['2023-02-27', '2023-03-02'],
|
||||
['2024-02-27', '2024-03-02'],
|
||||
['2025-02-27', '2025-03-02'],
|
||||
] satisfies (string | [string, string])[];
|
||||
const result = allDatesInRanges(dateRanges);
|
||||
const expected = [
|
||||
'2023-02-27', // ['2023-02-27', '2023-03-2']
|
||||
'2023-02-28',
|
||||
'2023-03-01',
|
||||
'2023-03-02',
|
||||
'2024-02-27', // ['2024-02-27', '2024-03-2']
|
||||
'2024-02-28',
|
||||
'2024-02-29',
|
||||
'2024-03-01',
|
||||
'2024-03-02',
|
||||
'2025-02-27', // ['2025-02-27', '2025-03-2']
|
||||
'2025-02-28',
|
||||
'2025-03-01',
|
||||
'2025-03-02',
|
||||
].map(dateStr => parseISO(dateStr, { in: TZ })) satisfies Date[];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('meetingToIcsString', () => {
|
||||
it('should handle a one-day meeting with one instructor', () => {
|
||||
const course = serde(multiMeetingMultiInstructorCourse);
|
||||
course.instructors = course.instructors.slice(0, 1);
|
||||
const meeting = course.schedule.meetings[1]!;
|
||||
const result = meetingToIcsString(course, meeting);
|
||||
const expected = (
|
||||
`BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T130000
|
||||
DTEND;TZID=America/Chicago:20250829T160000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T130000
|
||||
` +
|
||||
// Only skips one Thanksgiving break day
|
||||
`SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:DMC 3.208
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz
|
||||
END:VEVENT`
|
||||
).replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle unique numbers below 5 digits', () => {
|
||||
const course = serde(multiMeetingMultiInstructorCourse);
|
||||
course.instructors = course.instructors.slice(0, 1);
|
||||
course.uniqueId = 4269;
|
||||
const meeting = course.schedule.meetings[1]!;
|
||||
const result = meetingToIcsString(course, meeting);
|
||||
const expected = `BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T130000
|
||||
DTEND;TZID=America/Chicago:20250829T160000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T130000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:DMC 3.208
|
||||
DESCRIPTION:Unique number: 04269\\nTaught by John Schwartz
|
||||
END:VEVENT`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle a one-day meeting with multiple instructors', () => {
|
||||
const course = serde(multiMeetingMultiInstructorCourse);
|
||||
const meeting = course.schedule.meetings[1]!;
|
||||
const result = meetingToIcsString(course, meeting);
|
||||
const expected = `BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T130000
|
||||
DTEND;TZID=America/Chicago:20250829T160000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T130000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:DMC 3.208
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should gracefully error on an out of range semester code', () => {
|
||||
const course = serde(multiMeetingMultiInstructorCourse);
|
||||
const meeting = course.schedule.meetings[0]!;
|
||||
vi.spyOn(console, 'error').mockReturnValue(undefined);
|
||||
course.semester = {
|
||||
season: 'Fall',
|
||||
year: 2010,
|
||||
code: '20109',
|
||||
};
|
||||
const result = meetingToIcsString(course, meeting);
|
||||
expect(result).toBeNull();
|
||||
expect(console.error).toBeCalledWith(
|
||||
`No academic calendar found for semester code: 20109; course uniqueId: ${course.uniqueId}`
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle a multi-day meeting with multiple instructors', () => {
|
||||
const course = serde(multiMeetingMultiInstructorCourse);
|
||||
const meeting = course.schedule.meetings[0]!;
|
||||
const result = meetingToIcsString(course, meeting);
|
||||
const expected = `BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250826T093000
|
||||
DTEND;TZID=America/Chicago:20250826T110000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251125T093000,20251127T093000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:CMA 6.146
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('scheduleToIcsString', () => {
|
||||
it('should handle an empty schedule', () => {
|
||||
const schedule = serde(
|
||||
new UserSchedule({
|
||||
courses: [],
|
||||
hours: 0,
|
||||
id: 'fajowe',
|
||||
name: 'fajowe',
|
||||
updatedAt: Date.now(),
|
||||
})
|
||||
);
|
||||
const result = scheduleToIcsString(schedule);
|
||||
const expected = `BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
X-WR-CALNAME:My Schedule
|
||||
END:VCALENDAR`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle a schedule with courses but no meetings', () => {
|
||||
const schedule = serde(
|
||||
new UserSchedule({
|
||||
courses: [
|
||||
new Course({
|
||||
...multiMeetingMultiInstructorCourse,
|
||||
schedule: {
|
||||
meetings: [],
|
||||
},
|
||||
}),
|
||||
],
|
||||
hours: 0,
|
||||
id: 'fajowe',
|
||||
name: 'fajowe',
|
||||
updatedAt: Date.now(),
|
||||
})
|
||||
);
|
||||
const result = scheduleToIcsString(schedule);
|
||||
const expected = `BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
X-WR-CALNAME:My Schedule
|
||||
END:VCALENDAR`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle a schedule with courses but out-of-range semester', () => {
|
||||
vi.spyOn(console, 'error').mockReturnValue(undefined);
|
||||
const schedule = serde(
|
||||
new UserSchedule({
|
||||
courses: [
|
||||
new Course({
|
||||
...multiMeetingMultiInstructorCourse,
|
||||
semester: {
|
||||
season: 'Fall',
|
||||
year: 2010,
|
||||
code: '20109',
|
||||
},
|
||||
}),
|
||||
],
|
||||
hours: 0,
|
||||
id: 'fajowe',
|
||||
name: 'fajowe',
|
||||
updatedAt: Date.now(),
|
||||
})
|
||||
);
|
||||
const result = scheduleToIcsString(schedule);
|
||||
const expected = `BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
X-WR-CALNAME:My Schedule
|
||||
END:VCALENDAR`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle a single course with multiple meetings', () => {
|
||||
const schedule = serde(multiMeetingMultiInstructorSchedule);
|
||||
const result = scheduleToIcsString(schedule);
|
||||
const expected = `BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
X-WR-CALNAME:My Schedule
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250826T093000
|
||||
DTEND;TZID=America/Chicago:20250826T110000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251125T093000,20251127T093000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:CMA 6.146
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T130000
|
||||
DTEND;TZID=America/Chicago:20250829T160000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T130000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:DMC 3.208
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT
|
||||
END:VCALENDAR`.replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle a complex schedule', () => {
|
||||
const schedule = serde(multiMeetingMultiInstructorSchedule);
|
||||
schedule.courses.push(chatterjeeCS429Course);
|
||||
const result = scheduleToIcsString(schedule);
|
||||
const expected = (
|
||||
`BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
X-WR-CALNAME:My Schedule
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250826T093000
|
||||
DTEND;TZID=America/Chicago:20250826T110000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251125T093000,20251127T093000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:CMA 6.146
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T130000
|
||||
DTEND;TZID=America/Chicago:20250829T160000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T130000
|
||||
SUMMARY:J 395 – 44-REPORTING TEXAS
|
||||
LOCATION:DMC 3.208
|
||||
DESCRIPTION:Unique number: 10335\\nTaught by John Schwartz and John Bridges
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250825T160000
|
||||
DTEND;TZID=America/Chicago:20250825T170000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH;UNTIL=20251209T060000Z
|
||||
` +
|
||||
// Skips Labor Day and only relevant days of Thanksgiving
|
||||
`EXDATE;TZID=America/Chicago:20250901T160000,20251124T160000,20251125T160000,20251126T160000,20251127T160000
|
||||
SUMMARY:C S 429 – COMP ORGANIZATN AND ARCH
|
||||
LOCATION:UTC 3.102
|
||||
DESCRIPTION:Unique number: 54795\\nTaught by Siddhartha Chatterjee
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=America/Chicago:20250829T090000
|
||||
DTEND;TZID=America/Chicago:20250829T110000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20251209T060000Z
|
||||
EXDATE;TZID=America/Chicago:20251128T090000
|
||||
SUMMARY:C S 429 – COMP ORGANIZATN AND ARCH
|
||||
LOCATION:GSB 2.122
|
||||
DESCRIPTION:Unique number: 54795\\nTaught by Siddhartha Chatterjee
|
||||
END:VEVENT
|
||||
END:VCALENDAR`
|
||||
).replaceAll(/^\s+/gm, '');
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateCourseCellColumns', () => {
|
||||
let testIdCounter = 0;
|
||||
|
||||
const makeCell = (startIndex: number, endIndex: number): CalendarGridCourse => {
|
||||
if (endIndex <= startIndex && !(startIndex === -1 && endIndex === -1)) {
|
||||
throw new Error('Test writer error: startIndex must be strictly less than endIndex');
|
||||
}
|
||||
|
||||
const cell = {
|
||||
calendarGridPoint: {
|
||||
dayIndex: 1,
|
||||
startIndex,
|
||||
endIndex,
|
||||
},
|
||||
componentProps: {} as unknown as CalendarCourseCellProps,
|
||||
course: {} as unknown as Course,
|
||||
async: false,
|
||||
} satisfies CalendarGridCourse;
|
||||
|
||||
/* eslint no-underscore-dangle: ["error", { "allow": ["__test_id"] }] */
|
||||
(cell as unknown as { __test_id: number }).__test_id = testIdCounter++;
|
||||
|
||||
return cell;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates test cases for calculateCourseCellColumns
|
||||
* @param cellConfigs - Array of [startIndex, endIndex, totalColumns, gridColumnStart, gridColumnEnd]
|
||||
* @returns Tuple of [cells, expectedCells]
|
||||
*/
|
||||
const makeCellsTest = (
|
||||
cellConfigs: Array<[number, number, number, number, number]>
|
||||
): [CalendarGridCourse[], CalendarGridCourse[]] => {
|
||||
// Create cells with only start/end indices
|
||||
const cells = cellConfigs.map(([startIndex, endIndex]) => makeCell(startIndex, endIndex));
|
||||
|
||||
// Create expected cells with all properties set
|
||||
const expectedCells = structuredClone<CalendarGridCourse[]>(cells);
|
||||
cellConfigs.forEach((config, index) => {
|
||||
const [, , totalColumns, gridColumnStart, gridColumnEnd] = config;
|
||||
expectedCells[index]!.totalColumns = totalColumns;
|
||||
expectedCells[index]!.gridColumnStart = gridColumnStart;
|
||||
expectedCells[index]!.gridColumnEnd = gridColumnEnd;
|
||||
});
|
||||
|
||||
return [cells, expectedCells];
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// Ensure independence between tests
|
||||
testIdCounter = 0;
|
||||
});
|
||||
|
||||
it('should do nothing to an empty array if no courses are present', () => {
|
||||
const cells: CalendarGridCourse[] = [];
|
||||
calculateCourseCellColumns(cells);
|
||||
expect(cells).toEqual([]);
|
||||
});
|
||||
|
||||
it('should set the right values for one course cell', () => {
|
||||
const [cells, expectedCells] = makeCellsTest([[13, 15, 1, 1, 2]]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle two separated courses', () => {
|
||||
// These two cells can share a column, because they aren't concurrent
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 15, 1, 1, 2],
|
||||
[16, 18, 1, 1, 2],
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle two back-to-back courses', () => {
|
||||
// These two cells can share a column, because they aren't concurrent
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 15, 1, 1, 2],
|
||||
[15, 17, 1, 1, 2],
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle two concurrent courses', () => {
|
||||
// These two cells must be in separate columns, because they are concurrent
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 15, 2, 1, 2],
|
||||
[14, 16, 2, 2, 3],
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle a simple grid', () => {
|
||||
// Two columns
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 15, 2, 1, 2], // start in left-most column
|
||||
[15, 17, 2, 1, 2], // compact into left column
|
||||
[13, 17, 2, 2, 3], // take up second column
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle a simple grid, flipped', () => {
|
||||
// Ensures `totalColumns` is calculated correctly
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 17, 2, 1, 2],
|
||||
[15, 17, 2, 2, 3],
|
||||
[13, 15, 2, 2, 3],
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle a weird grid', () => {
|
||||
// Three columns
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[13, 15, 3, 1, 2],
|
||||
[14, 18, 3, 2, 3],
|
||||
[14, 16, 3, 3, 4],
|
||||
[15, 17, 3, 1, 2], // compacted into left-most columns
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle many clean concurrent courses', () => {
|
||||
// All cells here are concurrent, 8 columns
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[10, 16, 8, 1, 2],
|
||||
[12, 16, 8, 2, 3],
|
||||
[13, 16, 8, 3, 4],
|
||||
[13, 16, 8, 4, 5],
|
||||
[13, 19, 8, 5, 6],
|
||||
[13, 19, 8, 6, 7],
|
||||
[14, 18, 8, 7, 8],
|
||||
[15, 19, 8, 8, 9],
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it('should handle many clean concurrent courses with one partially-concurrent', () => {
|
||||
// Despite adding another course, we don't need to increase
|
||||
// the number of columns, because we can compact
|
||||
const [cells, expectedCells] = makeCellsTest([
|
||||
[10, 16, 8, 1, 2],
|
||||
[11, 15, 8, 2, 3], // new course, only overlaps with some
|
||||
[12, 16, 8, 3, 4],
|
||||
[13, 16, 8, 4, 5],
|
||||
[13, 16, 8, 5, 6],
|
||||
[13, 19, 8, 6, 7],
|
||||
[13, 19, 8, 7, 8],
|
||||
[14, 18, 8, 8, 9],
|
||||
[15, 19, 8, 2, 3], // compacts to be under new course
|
||||
]);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
|
||||
it("shouldn't crash on courses without times", () => {
|
||||
const cells = [makeCell(-1, -1), makeCell(-1, -1)];
|
||||
cells[1]!.async = true; // see if we can ignore async and non-async courses without times
|
||||
|
||||
const expectedCells = structuredClone<CalendarGridCourse[]>(cells);
|
||||
|
||||
calculateCourseCellColumns(cells);
|
||||
|
||||
expect(cells).toEqual(expectedCells);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,38 @@
|
||||
import { tz, TZDate } from '@date-fns/tz';
|
||||
import exportSchedule from '@pages/background/lib/exportSchedule';
|
||||
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
|
||||
import type { Course } from '@shared/types/Course';
|
||||
import type { CourseMeeting } from '@shared/types/CourseMeeting';
|
||||
import Instructor from '@shared/types/Instructor';
|
||||
import type { UserSchedule } from '@shared/types/UserSchedule';
|
||||
import { downloadBlob } from '@shared/util/downloadBlob';
|
||||
import { englishStringifyList } from '@shared/util/string';
|
||||
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
import type { DateArg, Day } from 'date-fns';
|
||||
import {
|
||||
addDays,
|
||||
eachDayOfInterval,
|
||||
format as formatDate,
|
||||
formatISO,
|
||||
getDay,
|
||||
nextDay,
|
||||
parseISO,
|
||||
set as setMultiple,
|
||||
} from 'date-fns';
|
||||
import { toBlob } from 'html-to-image';
|
||||
|
||||
import { academicCalendars } from './academic-calendars';
|
||||
|
||||
// Do all timezone calculations relative to UT's timezone
|
||||
const TIMEZONE_ID = 'America/Chicago';
|
||||
const TZ = tz(TIMEZONE_ID);
|
||||
|
||||
// Datetime format used by iCal, not directly supported by date-fns
|
||||
// (date-fns adds the timezone to the end, but iCal doesn't want it)
|
||||
const ISO_BASIC_DATETIME_FORMAT = "yyyyMMdd'T'HHmmss";
|
||||
|
||||
// iCal uses two-letter codes for days of the week
|
||||
export const CAL_MAP = {
|
||||
Sunday: 'SU',
|
||||
Monday: 'MO',
|
||||
@@ -14,6 +43,17 @@ export const CAL_MAP = {
|
||||
Saturday: 'SA',
|
||||
} as const satisfies Record<string, string>;
|
||||
|
||||
// Date objects' day field goes by index like this
|
||||
const DAY_NAME_TO_NUMBER = {
|
||||
Sunday: 0,
|
||||
Monday: 1,
|
||||
Tuesday: 2,
|
||||
Wednesday: 3,
|
||||
Thursday: 4,
|
||||
Friday: 5,
|
||||
Saturday: 6,
|
||||
} as const satisfies Record<string, number>;
|
||||
|
||||
/**
|
||||
* Retrieves the schedule from the UserScheduleStore based on the active index.
|
||||
* @returns A promise that resolves to the retrieved schedule.
|
||||
@@ -38,85 +78,244 @@ export const formatToHHMMSS = (minutes: number) => {
|
||||
return `${hours}${mins}00`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a date in the format YYYYMMDD'T'HHmmss, which is the format used by iCal.
|
||||
*
|
||||
* @param date - The date to format.
|
||||
* @returns The formatted date string.
|
||||
*/
|
||||
const iCalDateFormat = <DateType extends Date>(date: DateArg<DateType>) =>
|
||||
formatDate(date, ISO_BASIC_DATETIME_FORMAT, { in: TZ });
|
||||
|
||||
/**
|
||||
* Returns the next day of the given date, inclusive of the given day.
|
||||
*
|
||||
* If the given date is the given day, the same date is returned.
|
||||
*
|
||||
* For example, a Monday targeting a Wednesday will return the next Wednesday,
|
||||
* but if it was targeting a Monday it would return the same date.
|
||||
*
|
||||
* @param date - The date to increment.
|
||||
* @param day - The day to increment to. (0 = Sunday, 1 = Monday, etc.)
|
||||
* @returns The next day of the given date, inclusive of the given day.
|
||||
*/
|
||||
export const nextDayInclusive = (date: Date, day: Day): TZDate => {
|
||||
if (getDay(date, { in: TZ }) === day) {
|
||||
return new TZDate(date, TIMEZONE_ID);
|
||||
}
|
||||
|
||||
return nextDay(date, day, { in: TZ });
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of all the dates (as Date objects) in the given date ranges.
|
||||
*
|
||||
* @param dateRanges - An array of date ranges.
|
||||
* Each date range can be a string (in which case it is interpreted as a single date)
|
||||
* or an array of two strings (in which case it is interpreted as a date range, inclusive).
|
||||
* @returns An array of all the dates (as Date objects) in the given date ranges.
|
||||
*
|
||||
* @example
|
||||
* allDatesInRanges(['2025-01-01', ['2025-03-14', '2025-03-16']]) // ['2025-01-01', '2025-03-14', '2025-03-15', '2025-03-16'] (as Date objects)
|
||||
*
|
||||
* @remarks Does not remove duplicate dates.
|
||||
*/
|
||||
export const allDatesInRanges = (dateRanges: readonly (string | [string, string])[]): Date[] =>
|
||||
dateRanges.flatMap(breakDate => {
|
||||
if (Array.isArray(breakDate)) {
|
||||
return eachDayOfInterval({
|
||||
start: parseISO(breakDate[0], { in: TZ }),
|
||||
end: parseISO(breakDate[1], { in: TZ }),
|
||||
});
|
||||
}
|
||||
|
||||
return parseISO(breakDate, { in: TZ });
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a VEVENT string for a meeting of a course.
|
||||
*
|
||||
* @param course - The course object
|
||||
* @param meeting - The meeting object
|
||||
* @returns A string representation of the meeting in the iCalendar format (ICS)
|
||||
*/
|
||||
export const meetingToIcsString = (course: Serialized<Course>, meeting: Serialized<CourseMeeting>): string | null => {
|
||||
const { startTime, endTime, days, location } = meeting;
|
||||
if (!course.semester.code) {
|
||||
console.error(`No semester found for course uniqueId: ${course.uniqueId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (days.length === 0) {
|
||||
console.error(`No days found for course uniqueId: ${course.uniqueId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(academicCalendars, course.semester.code)) {
|
||||
console.error(
|
||||
`No academic calendar found for semester code: ${course.semester.code}; course uniqueId: ${course.uniqueId}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const academicCalendar = academicCalendars[course.semester.code as keyof typeof academicCalendars];
|
||||
|
||||
const startDate = nextDayInclusive(
|
||||
parseISO(academicCalendar.firstClassDate, { in: TZ }),
|
||||
DAY_NAME_TO_NUMBER[days[0]!]
|
||||
);
|
||||
|
||||
const startTimeHours = Math.floor(startTime / 60);
|
||||
const startTimeMinutes = startTime % 60;
|
||||
const startTimeDate = setMultiple(startDate, { hours: startTimeHours, minutes: startTimeMinutes }, { in: TZ });
|
||||
|
||||
const endTimeHours = Math.floor(endTime / 60);
|
||||
const endTimeMinutes = endTime % 60;
|
||||
const endTimeDate = setMultiple(startDate, { hours: endTimeHours, minutes: endTimeMinutes }, { in: TZ });
|
||||
|
||||
const untilDate = addDays(parseISO(academicCalendar.lastClassDate, { in: TZ }), 1);
|
||||
|
||||
const daysNumSet = new Set(days.map(d => DAY_NAME_TO_NUMBER[d]));
|
||||
const excludedDates = allDatesInRanges(academicCalendar.breakDates)
|
||||
// Don't need to exclude Tues/Thurs if it's a MWF class, etc.
|
||||
.filter(date => daysNumSet.has(getDay(date, { in: TZ }) as Day))
|
||||
.map(date => setMultiple(date, { hours: startTimeHours, minutes: startTimeMinutes }, { in: TZ }));
|
||||
|
||||
const startDateFormatted = iCalDateFormat(startTimeDate);
|
||||
const endDateFormatted = iCalDateFormat(endTimeDate);
|
||||
// Convert days to ICS compatible format, e.g. MO,WE,FR
|
||||
const icsDays = days.map(day => CAL_MAP[day]).join(',');
|
||||
|
||||
// per spec, UNTIL must be in UTC
|
||||
const untilDateFormatted = formatISO(untilDate, { format: 'basic', in: tz('utc') });
|
||||
const excludedDatesFormatted = excludedDates.map(date => iCalDateFormat(date));
|
||||
|
||||
const uniqueNumberFormatted = course.uniqueId.toString().padStart(5, '0');
|
||||
|
||||
// The list part of "Taught by Michael Scott and Siddhartha Chatterjee Beasley"
|
||||
const instructorsFormatted = englishStringifyList(
|
||||
course.instructors
|
||||
.map(instructor => Instructor.prototype.toString.call(instructor, { format: 'first_last' }))
|
||||
.filter(name => name !== '')
|
||||
);
|
||||
|
||||
// Construct event string
|
||||
let icsString = 'BEGIN:VEVENT\n';
|
||||
icsString += `DTSTART;TZID=${TIMEZONE_ID}:${startDateFormatted}\n`;
|
||||
icsString += `DTEND;TZID=${TIMEZONE_ID}:${endDateFormatted}\n`;
|
||||
icsString += `RRULE:FREQ=WEEKLY;BYDAY=${icsDays};UNTIL=${untilDateFormatted}\n`;
|
||||
icsString += `EXDATE;TZID=${TIMEZONE_ID}:${excludedDatesFormatted.join(',')}\n`;
|
||||
icsString += `SUMMARY:${course.department} ${course.number} \u2013 ${course.courseName}\n`;
|
||||
|
||||
if (location?.building || location?.building) {
|
||||
const locationFormatted = `${location?.building ?? ''} ${location?.room ?? ''}`.trim();
|
||||
icsString += `LOCATION:${locationFormatted}\n`;
|
||||
}
|
||||
|
||||
icsString += `DESCRIPTION:Unique number: ${uniqueNumberFormatted}`;
|
||||
if (instructorsFormatted) {
|
||||
// Newlines need to be double-escaped
|
||||
icsString += `\\nTaught by ${instructorsFormatted}`;
|
||||
}
|
||||
icsString += '\n';
|
||||
|
||||
icsString += 'END:VEVENT';
|
||||
|
||||
return icsString;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a VCALENDAR string for a schedule of a user.
|
||||
* @param schedule - The schedule object
|
||||
* @returns A string representation of the schedule in the iCalendar format (ICS)
|
||||
*/
|
||||
export const scheduleToIcsString = (schedule: Serialized<UserSchedule>) => {
|
||||
let icsString = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nX-WR-CALNAME:My Schedule\n';
|
||||
|
||||
const vevents = schedule.courses
|
||||
.flatMap(course => course.schedule.meetings.map(meeting => meetingToIcsString(course, meeting)))
|
||||
.filter(event => event !== null)
|
||||
.join('\n');
|
||||
|
||||
if (vevents.length > 0) {
|
||||
icsString += `${vevents}\n`;
|
||||
}
|
||||
|
||||
icsString += 'END:VCALENDAR';
|
||||
|
||||
return icsString;
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the current schedule as a calendar file in the iCalendar format (ICS).
|
||||
* Fetches the current active schedule and converts it into an ICS string.
|
||||
* Downloads the ICS file to the user's device.
|
||||
*/
|
||||
export const saveAsCal = async () => {
|
||||
const schedule = await getSchedule(); // Assumes this fetches the current active schedule
|
||||
|
||||
let icsString = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nX-WR-CALNAME:My Schedule\n';
|
||||
const schedule = await getSchedule();
|
||||
|
||||
if (!schedule) {
|
||||
throw new Error('No schedule found');
|
||||
}
|
||||
|
||||
schedule.courses.forEach(course => {
|
||||
course.schedule.meetings.forEach(meeting => {
|
||||
const { startTime, endTime, days, location } = meeting;
|
||||
|
||||
// Format start and end times to HHMMSS
|
||||
const formattedStartTime = formatToHHMMSS(startTime);
|
||||
const formattedEndTime = formatToHHMMSS(endTime);
|
||||
|
||||
// Map days to ICS compatible format
|
||||
console.log(days);
|
||||
const icsDays = days.map(day => CAL_MAP[day]).join(',');
|
||||
console.log(icsDays);
|
||||
|
||||
// Assuming course has date started and ended, adapt as necessary
|
||||
// const year = new Date().getFullYear(); // Example year, adapt accordingly
|
||||
// Example event date, adapt startDate according to your needs
|
||||
const startDate = `20240101T${formattedStartTime}`;
|
||||
const endDate = `20240101T${formattedEndTime}`;
|
||||
|
||||
icsString += `BEGIN:VEVENT\n`;
|
||||
icsString += `DTSTART:${startDate}\n`;
|
||||
icsString += `DTEND:${endDate}\n`;
|
||||
icsString += `RRULE:FREQ=WEEKLY;BYDAY=${icsDays}\n`;
|
||||
icsString += `SUMMARY:${course.fullName}\n`;
|
||||
icsString += `LOCATION:${location?.building ?? ''} ${location?.room ?? ''}\n`;
|
||||
icsString += `END:VEVENT\n`;
|
||||
});
|
||||
});
|
||||
|
||||
icsString += 'END:VCALENDAR';
|
||||
const icsString = scheduleToIcsString(schedule);
|
||||
|
||||
downloadBlob(icsString, 'CALENDAR', 'schedule.ics');
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves current schedule to JSON that can be imported on other devices.
|
||||
* @param id - Provided schedule ID to download
|
||||
*/
|
||||
export const handleExportJson = async (id: string) => {
|
||||
const jsonString = await exportSchedule(id);
|
||||
if (jsonString) {
|
||||
const schedules = await UserScheduleStore.get('schedules');
|
||||
const schedule = schedules.find(s => s.id === id);
|
||||
const fileName = `${schedule?.name ?? `schedule_${id}`}_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
|
||||
await downloadBlob(jsonString, 'JSON', fileName);
|
||||
} else {
|
||||
console.error('Error exporting schedule: jsonString is undefined');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the calendar as a PNG image.
|
||||
*
|
||||
* @param calendarRef - The reference to the calendar component.
|
||||
*/
|
||||
export const saveCalAsPng = () => {
|
||||
const WIDTH_PX = 1165;
|
||||
const HEIGHT_PX = 754;
|
||||
const SCALE = 2;
|
||||
|
||||
const rootNode = document.createElement('div');
|
||||
rootNode.style.backgroundColor = 'white';
|
||||
rootNode.style.position = 'fixed';
|
||||
rootNode.style.zIndex = '1000';
|
||||
rootNode.style.top = '-10000px';
|
||||
rootNode.style.left = '-10000px';
|
||||
rootNode.style.width = '1165px';
|
||||
rootNode.style.height = '754px';
|
||||
rootNode.style.width = `${WIDTH_PX}px`;
|
||||
rootNode.style.height = `${HEIGHT_PX}px`;
|
||||
document.body.appendChild(rootNode);
|
||||
|
||||
const clonedNode = document.querySelector('#root')!.cloneNode(true) as HTMLDivElement;
|
||||
clonedNode.style.backgroundColor = 'white';
|
||||
(clonedNode.firstChild as HTMLDivElement).classList.add('screenshot-in-progress');
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
requestAnimationFrame(async () => {
|
||||
rootNode.appendChild(clonedNode);
|
||||
const calendarTarget = clonedNode.querySelector('.screenshot\\:calendar-target') as HTMLDivElement;
|
||||
calendarTarget.style.width = `${WIDTH_PX}px`;
|
||||
calendarTarget.style.height = `${HEIGHT_PX}px`;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
rootNode.appendChild(clonedNode);
|
||||
requestAnimationFrame(async () => {
|
||||
try {
|
||||
const screenshotBlob = await toBlob(clonedNode, {
|
||||
cacheBust: true,
|
||||
canvasWidth: 1165 * 2,
|
||||
canvasHeight: 754 * 2,
|
||||
canvasWidth: WIDTH_PX * SCALE,
|
||||
canvasHeight: HEIGHT_PX * SCALE,
|
||||
skipAutoScale: true,
|
||||
pixelRatio: 2,
|
||||
pixelRatio: SCALE,
|
||||
});
|
||||
|
||||
if (!screenshotBlob) {
|
||||
@@ -134,3 +333,136 @@ export const saveCalAsPng = () => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines all the connected components in the list of cells, where two cells
|
||||
* are "connected" if there is a path (potentially through other cells) where
|
||||
* each neighboring cells have overlapping start/end times
|
||||
*
|
||||
* @param cells - An array of cells to go on the calendar grid
|
||||
* @returns An array of connected components, where the inner array is a list of
|
||||
* all cells that there's a path to (potentially through other intervals)
|
||||
* without crossing a time gap
|
||||
*
|
||||
* @remarks The internal fields cell.concurrentCells and cell.hasParent are
|
||||
* modified by this function
|
||||
*
|
||||
* @example [[8am, 9am), [8:30am, 10am), [9:30am, 11am)] // is all one connected component
|
||||
* @example [[8am, 9am), [8:30am, 10am), [10am, 11am)] // has two connected components, [[8am, 9am), [8:30am, 10am)] and [[10am, 11am)]]
|
||||
*/
|
||||
const findConnectedComponents = (cells: CalendarGridCourse[]): CalendarGridCourse[][] => {
|
||||
const connectedComponents: CalendarGridCourse[][] = [];
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
const cell = cells[i]!;
|
||||
|
||||
if (!cell.concurrentCells || cell.concurrentCells.length === 0) {
|
||||
// If this cell isn't already part of an existing connected component,
|
||||
// then we need to make a new one.
|
||||
connectedComponents.push([]);
|
||||
}
|
||||
|
||||
connectedComponents.at(-1)!.push(cell);
|
||||
|
||||
for (let j = i + 1; j < cells.length; j++) {
|
||||
const otherCell = cells[j]!;
|
||||
if (otherCell.calendarGridPoint.startIndex >= cell.calendarGridPoint.endIndex) {
|
||||
break;
|
||||
}
|
||||
|
||||
// By ordering of cells array, we know cell.startTime <= other.startTime
|
||||
// By the if check above, we know cell.endTime > other.endTime
|
||||
// So, they're concurrent
|
||||
// Also, by initializing j to i + 1, we know we don't have duplicates
|
||||
cell.concurrentCells!.push(otherCell);
|
||||
otherCell.concurrentCells!.push(cell);
|
||||
}
|
||||
}
|
||||
|
||||
return connectedComponents;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assigns column positions to each cell in a set of calendar grid cells.
|
||||
* Ensures that overlapping cells are placed in different columns.
|
||||
*
|
||||
* Inspired by the Greedy Interval-Partitioning algorithm.
|
||||
*
|
||||
* @param cells - An array of calendar grid course cells to position, must be
|
||||
* sorted in increasing order of start time
|
||||
* @throws Error if there's no available column for a cell (should never happen if totalColumns is calculated correctly)
|
||||
* @remarks The number of columns created is strictly equal to the minimum needed by a perfectly optimal algorithm.
|
||||
* The minimum number of columns needed is the maximum number of events that happen concurrently.
|
||||
* Research Interval Graphs for more info https://en.wikipedia.org/wiki/Interval_graph
|
||||
*/
|
||||
const assignColumns = (cells: CalendarGridCourse[]) => {
|
||||
const availableColumns = [true];
|
||||
|
||||
for (const cell of cells) {
|
||||
availableColumns.fill(true);
|
||||
for (const otherCell of cell.concurrentCells!) {
|
||||
if (otherCell.gridColumnStart !== undefined) {
|
||||
availableColumns[otherCell.gridColumnStart - 1] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find an available column, or create one if all columns are full
|
||||
let column = availableColumns.indexOf(true);
|
||||
|
||||
if (column === -1) {
|
||||
column = availableColumns.length;
|
||||
availableColumns.push(true);
|
||||
}
|
||||
|
||||
// CSS Grid uses 1-based indexing
|
||||
cell.gridColumnStart = column + 1;
|
||||
cell.gridColumnEnd = column + 2;
|
||||
}
|
||||
|
||||
for (const cell of cells) {
|
||||
cell.totalColumns = availableColumns.length;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the column positions for course cells in a calendar grid.
|
||||
* This function handles the layout algorithm for displaying overlapping course meetings
|
||||
* in a calendar view. It identifies connected components of overlapping courses,
|
||||
* determines the number of columns needed for each component, and assigns appropriate
|
||||
* column positions to each cell.
|
||||
*
|
||||
* @param dayCells - An array of calendar grid course cells for a specific day
|
||||
*/
|
||||
export const calculateCourseCellColumns = (dayCells: CalendarGridCourse[]) => {
|
||||
// Sort by start time, increasing
|
||||
// This is necessary for the correctness of the column assignment
|
||||
const cells = dayCells
|
||||
.filter(
|
||||
cell =>
|
||||
!cell.async &&
|
||||
cell.calendarGridPoint &&
|
||||
typeof cell.calendarGridPoint.startIndex === 'number' &&
|
||||
cell.calendarGridPoint.startIndex >= 0
|
||||
)
|
||||
.toSorted((a, b) => a.calendarGridPoint.startIndex - b.calendarGridPoint.startIndex);
|
||||
|
||||
// Initialize metadata
|
||||
for (const cell of cells) {
|
||||
cell.concurrentCells = [];
|
||||
cell.gridColumnStart = undefined;
|
||||
cell.gridColumnEnd = undefined;
|
||||
}
|
||||
|
||||
// Construct connected components, set concurrent neighbors
|
||||
const connectedComponents = findConnectedComponents(cells);
|
||||
|
||||
// Assign columns for each connectedComponents
|
||||
for (const cc of connectedComponents) {
|
||||
assignColumns(cc);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for (const cell of cells) {
|
||||
delete cell.concurrentCells;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ export function usePrompt(): (info: PromptInfo, options?: DialogOptions) => void
|
||||
{info.description}
|
||||
</Text>
|
||||
),
|
||||
className: 'max-w-[400px] flex flex-col gap-2.5 p-6.25',
|
||||
className: 'max-w-[415px] flex flex-col gap-2.5 p-6.25 border border-ut-offwhite/50',
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
@apply font-sans;
|
||||
color: #303030;
|
||||
|
||||
// fix font-family on injected pages
|
||||
* {
|
||||
@apply font-sans;
|
||||
}
|
||||
|
||||
[data-rfd-drag-handle-context-id=':r1:'] {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// import '@unocss/reset/tailwind-compat.css';
|
||||
import 'uno.css';
|
||||
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import clsx from 'clsx';
|
||||
import React, { forwardRef } from 'react';
|
||||
|
||||
@@ -8,6 +9,8 @@ import styles from './ExtensionRoot.module.scss';
|
||||
|
||||
export const styleResetClass = styles.extensionRoot;
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
/**
|
||||
* A wrapper component for the extension elements that adds some basic styling to them
|
||||
*/
|
||||
@@ -16,7 +19,9 @@ export default function ExtensionRoot(props: React.HTMLProps<HTMLDivElement>): J
|
||||
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<div className={clsx(styleResetClass, 'h-full', className)} {...others} />
|
||||
</QueryClientProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { ThemeColor } from '@shared/types/ThemeColors';
|
||||
import { getThemeColorHexByName, getThemeColorRgbByName } from '@shared/util/themeColors';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@@ -21,9 +21,8 @@ interface Props {
|
||||
}
|
||||
|
||||
/**
|
||||
* A reusable input button component that follows the Button.tsx consistency
|
||||
*
|
||||
* @returns
|
||||
* A reusable input button component that follows Button.tsx consistency.
|
||||
* Now supports drag-and-drop file uploads (issue #446).
|
||||
*/
|
||||
export default function FileUpload({
|
||||
className,
|
||||
@@ -43,22 +42,74 @@ export default function FileUpload({
|
||||
const isIconOnly = !children && !!icon;
|
||||
const colorHex = getThemeColorHexByName(color);
|
||||
const colorRgb = getThemeColorRgbByName(color)?.join(' ');
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
// Convert accept to a comma-separated string if it's an array
|
||||
// Convert accept array to comma-separated list
|
||||
const acceptValue = Array.isArray(accept) ? accept.join(',') : accept;
|
||||
|
||||
// --- Prevent Chrome from opening the file on drop anywhere else ---
|
||||
useEffect(() => {
|
||||
const preventDefault = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
window.addEventListener('dragover', preventDefault);
|
||||
window.addEventListener('drop', preventDefault);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('dragover', preventDefault);
|
||||
window.removeEventListener('drop', preventDefault);
|
||||
};
|
||||
}, []);
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
// --- Local drag and drop handlers for this button only -------------
|
||||
const handleDrop = (event: React.DragEvent<HTMLLabelElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setIsDragging(false);
|
||||
if (disabled) return;
|
||||
|
||||
const file = event.dataTransfer.files?.[0];
|
||||
if (file && inputRef.current && onChange) {
|
||||
const dataTransfer = new DataTransfer();
|
||||
dataTransfer.items.add(file);
|
||||
inputRef.current.files = dataTransfer.files;
|
||||
|
||||
// Trigger change event manually
|
||||
onChange({ target: inputRef.current } as React.ChangeEvent<HTMLInputElement>);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (event: React.DragEvent<HTMLLabelElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (!disabled) setIsDragging(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (event: React.DragEvent<HTMLLabelElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setIsDragging(false);
|
||||
};
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
return (
|
||||
<label
|
||||
style={
|
||||
{
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
style={{
|
||||
...style,
|
||||
color: disabled ? 'ut-gray' : colorHex,
|
||||
backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity)`,
|
||||
} satisfies React.CSSProperties
|
||||
}
|
||||
backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity))`,
|
||||
}}
|
||||
className={clsx(
|
||||
'btn has-enabled:active:scale-96',
|
||||
'btn transition-colors select-none',
|
||||
{
|
||||
'ring-2 ring-offset-2 ring-blue-400': isDragging && !disabled,
|
||||
'text-white! bg-opacity-100 hover:enabled:shadow-md active:enabled:shadow-sm shadow-black/20':
|
||||
variant === 'filled',
|
||||
'bg-opacity-0 border-current hover:enabled:bg-opacity-8 border stroke-width-[1px]':
|
||||
@@ -70,6 +121,7 @@ export default function FileUpload({
|
||||
'h-[35px] w-[35px] p-spacing-2': size === 'small' && isIconOnly,
|
||||
'h-6 p-spacing-2': size === 'mini' && !isIconOnly,
|
||||
'h-6 w-6 p-0': size === 'mini' && isIconOnly,
|
||||
'opacity-60 cursor-not-allowed': disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
@@ -85,6 +137,7 @@ export default function FileUpload({
|
||||
</Text>
|
||||
)}
|
||||
<input
|
||||
ref={inputRef}
|
||||
type='file'
|
||||
{...(accept ? { accept: acceptValue } : {})}
|
||||
className='hidden'
|
||||
|
||||
@@ -102,7 +102,7 @@ export function useMigrationDialog() {
|
||||
{
|
||||
title: 'This extension has updated!',
|
||||
description:
|
||||
"You may have already began planning your Spring '25 schedule. Click the button below to transfer your saved schedules into a new schedule. (You may be required to login to the UT Registrar)",
|
||||
"You may have already began planning your Fall '25 schedule. Click the button below to transfer your saved schedules into a new schedule. (You may be required to login to the UT Registrar)",
|
||||
|
||||
buttons: close => <MigrationButtons close={close} />,
|
||||
},
|
||||
|
||||
@@ -19,13 +19,17 @@ export default function ScheduleDropdown({ defaultOpen, children }: ScheduleDrop
|
||||
const [activeSchedule] = useSchedules();
|
||||
|
||||
return (
|
||||
<div className='border border-ut-offwhite/50 rounded bg-white'>
|
||||
<div className='max-h-[200px] flex flex-col border border-ut-offwhite/50 rounded bg-white'>
|
||||
<Disclosure defaultOpen={defaultOpen}>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<DisclosureButton className='w-full flex items-center border-none bg-transparent px-3.5 py-2.5 text-left'>
|
||||
<div className='flex-1'>
|
||||
<Text as='div' variant='h3' className='w-100% text-ut-burntorange normal-case!'>
|
||||
<div className='min-w-0 flex-1 overflow-hidden'>
|
||||
<Text
|
||||
as='div'
|
||||
variant='h3'
|
||||
className='w-full truncate whitespace-nowrap text-ut-burntorange normal-case!'
|
||||
>
|
||||
{activeSchedule ? activeSchedule.name : 'Schedule'}
|
||||
</Text>
|
||||
<div className='flex gap-2.5 text-theme-black leading-[75%]!'>
|
||||
@@ -50,17 +54,17 @@ export default function ScheduleDropdown({ defaultOpen, children }: ScheduleDrop
|
||||
|
||||
<Transition
|
||||
as='div'
|
||||
className='overflow-hidden'
|
||||
className='flex flex-1 flex-col overflow-y-hidden'
|
||||
enter='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo'
|
||||
enterFrom='max-h-0 opacity-0 p-0.5'
|
||||
enterTo='max-h-[440px] opacity-100 p-0'
|
||||
enterTo='max-h-[200px] opacity-100 p-0'
|
||||
leave='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo'
|
||||
leaveFrom='max-h-[440px] opacity-100 p-0'
|
||||
leaveFrom='max-h-[200px] opacity-100 p-0'
|
||||
leaveTo='max-h-0 opacity-0 p-0.5'
|
||||
>
|
||||
<div className='px-3.5 pb-2.5 pt-2'>
|
||||
<DisclosurePanel>{children}</DisclosurePanel>
|
||||
</div>
|
||||
<DisclosurePanel className='mx-1.75 mb-2.5 mt-2 flex flex-1 flex-col overflow-y-auto'>
|
||||
<div className='mx-1.75'>{children}</div>
|
||||
</DisclosurePanel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -109,12 +109,14 @@ export default function ScheduleListItem({ schedule, onClick }: ScheduleListItem
|
||||
|
||||
const handleDelete = () => {
|
||||
showDialog({
|
||||
title: 'Are you sure?',
|
||||
title: 'Delete schedule?',
|
||||
description: (
|
||||
<>
|
||||
<Text>Deleting </Text>
|
||||
<Text className='text-ut-burntorange'>{schedule.name}</Text>
|
||||
<Text>is permanent and will remove all added courses from that schedule.</Text>
|
||||
<Text> is permanent and will remove all added courses from </Text>
|
||||
<Text className='text-ut-burntorange'>{schedule.name}</Text>
|
||||
<Text>.</Text>
|
||||
</>
|
||||
),
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
@@ -126,12 +128,13 @@ export default function ScheduleListItem({ schedule, onClick }: ScheduleListItem
|
||||
<Button
|
||||
variant='filled'
|
||||
color='theme-red'
|
||||
icon={Trash}
|
||||
onClick={() => {
|
||||
close();
|
||||
deleteSchedule(schedule.id);
|
||||
}}
|
||||
>
|
||||
Delete Permanently
|
||||
Delete permanently
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Props for the Update Text
|
||||
*/
|
||||
export type UpdateTextProps = {
|
||||
courses: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateText component displays a message indicating that the extension has been updated
|
||||
* and lists the unique course numbers from the old version.
|
||||
*
|
||||
* @param courses - An array of course unique numbers to be displayed.
|
||||
* @returns The rendered UpdateText component.
|
||||
*/
|
||||
export default function UpdateText({ courses }: UpdateTextProps): JSX.Element {
|
||||
return (
|
||||
<div className='max-w-64 flex flex-col justify-center gap-2'>
|
||||
<div className='flex flex-col gap-0 text-center'>
|
||||
<Text variant='h4' className='text-ut-burntorange'>
|
||||
This extension has updated!
|
||||
</Text>
|
||||
<Text variant='p' className='text-ut-black'>
|
||||
You may have already began planning your Spring 2025 schedule. Here are the Unique Numbers you had
|
||||
from the old version: (Please open each link and re-add course to your new schedule)
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-col gap-1 text-center'>
|
||||
{courses.map(course => (
|
||||
<Text key={course} variant='p' className='text-ut-orange underline'>
|
||||
{course}
|
||||
</Text>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
139
src/views/components/common/WhatsNewPopup.tsx
Normal file
139
src/views/components/common/WhatsNewPopup.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import type { IconProps } from '@phosphor-icons/react';
|
||||
import { CloudX, Coffee, ForkKnife, MapTrifold, Storefront } from '@phosphor-icons/react';
|
||||
import { ExtensionStore } from '@shared/storage/ExtensionStore';
|
||||
import { UT_DINING_PROMO_IMAGE_URL } from '@shared/util/appUrls';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import useWhatsNewPopUp from '@views/hooks/useWhatsNew';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* This is the version of the 'What's New' features popup.
|
||||
*
|
||||
* It is used to check if the popup has already been shown to the user or not
|
||||
*
|
||||
* It should be incremented every time the "What's New" popup is updated.
|
||||
*/
|
||||
const WHATSNEW_POPUP_VERSION = 2;
|
||||
|
||||
// const WHATSNEW_VIDEO_URL = 'https://cdn.longhorns.dev/whats-new-v2.1.2.mp4';
|
||||
|
||||
type Feature = {
|
||||
id: string;
|
||||
icon: React.ForwardRefExoticComponent<IconProps>;
|
||||
title: string | JSX.Element;
|
||||
description: string;
|
||||
};
|
||||
|
||||
const NEW_FEATURES = [
|
||||
{
|
||||
id: 'dining-halls-info',
|
||||
icon: ForkKnife,
|
||||
title: 'Dining Halls Info',
|
||||
description: 'See daily menus and nutritional deets for J2, JCL, and Kins',
|
||||
},
|
||||
{
|
||||
id: 'coffee-shops',
|
||||
icon: Coffee,
|
||||
title: 'Coffee Shops',
|
||||
description: 'Need a Coffee Fix? Check operating times for your favorite campus cafes.',
|
||||
},
|
||||
{
|
||||
id: 'convenience-stores',
|
||||
icon: Storefront,
|
||||
title: 'Convenience Stores',
|
||||
description: 'Find hours for quick snacks and essentials on campus.',
|
||||
},
|
||||
{
|
||||
id: 'microwave-map',
|
||||
icon: MapTrifold,
|
||||
title: 'Microwave Map',
|
||||
description: 'Need to heat up your lunch? Find microwaves across campus!',
|
||||
},
|
||||
] as const satisfies readonly Feature[];
|
||||
|
||||
/**
|
||||
* WhatsNewPopupContent component.
|
||||
*
|
||||
* This component displays the content of the WhatsNew dialog.
|
||||
* It shows the new features that have been added to the extension.
|
||||
*
|
||||
* @returns A JSX of WhatsNewPopupContent component.
|
||||
*/
|
||||
export default function WhatsNewPopupContent(): JSX.Element {
|
||||
const [videoError, _setVideoError] = useState(false);
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-row justify-between'>
|
||||
<div className='w-full flex flex-col-reverse items-center justify-between gap-spacing-7 md:flex-row'>
|
||||
<div className='grid grid-cols-1 w-fit items-center gap-spacing-6 sm:grid-cols-2 md:w-[277px] md:flex md:flex-col md:flex-nowrap'>
|
||||
{NEW_FEATURES.map(({ id, icon: Icon, title, description }) => (
|
||||
<div key={id} className='w-full flex items-center justify-between gap-spacing-5'>
|
||||
<Icon width='40' height='40' className='text-ut-burntorange' />
|
||||
<div className='w-full flex flex-col gap-spacing-1'>
|
||||
<Text variant='h4' className='text-ut-burntorange font-bold!'>
|
||||
{title}
|
||||
</Text>
|
||||
<Text variant='p' className='text-ut-black'>
|
||||
{description}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className='h-full max-w-[464px] w-full flex items-center justify-center'>
|
||||
{videoError ? (
|
||||
<div className='h-full w-full flex items-center justify-center border border-ut-offwhite/50 rounded'>
|
||||
<div className='flex flex-col items-center justify-center p-spacing-2'>
|
||||
<CloudX size={52} className='text-ut-black/50' />
|
||||
<Text variant='h4' className='text-center text-ut-black/50'>
|
||||
Failed to load video. Please try again later.
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<img
|
||||
className='h-full w-full border border-ut-offwhite/50 rounded object-cover'
|
||||
src={UT_DINING_PROMO_IMAGE_URL}
|
||||
alt='UT Dining Promo'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* WhatsNewDialog component.
|
||||
*
|
||||
* This component is responsible for checking if the extension has already been updated
|
||||
* and if so, it displays the WhatsNew dialog. Then it updates the state to show that the
|
||||
* dialog has been shown.
|
||||
*
|
||||
* @returns An empty fragment.
|
||||
*
|
||||
* @remarks
|
||||
* The component uses the `useWhatsNew` hook to show the WhatsNew dialog and the
|
||||
* `useEffect` hook to perform the check on component mount. It also uses the `ExtensionStore`
|
||||
* to view the state of the dialog.
|
||||
*/
|
||||
export function WhatsNewDialog(): null {
|
||||
const showPopUp = useWhatsNewPopUp();
|
||||
|
||||
useEffect(() => {
|
||||
const checkUpdate = async () => {
|
||||
const version = await ExtensionStore.get('lastWhatsNewPopupVersion');
|
||||
if (version !== WHATSNEW_POPUP_VERSION) {
|
||||
await ExtensionStore.set('lastWhatsNewPopupVersion', WHATSNEW_POPUP_VERSION);
|
||||
showPopUp();
|
||||
}
|
||||
};
|
||||
|
||||
checkUpdate();
|
||||
|
||||
// This is on purpose
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
||||
import { background } from '@shared/messages';
|
||||
import { validateLoginStatus } from '@shared/util/checkLoginStatus';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||
import useSchedules from '@views/hooks/useSchedules';
|
||||
@@ -43,6 +42,8 @@ export default function InjectedButton(): JSX.Element | null {
|
||||
await addCourseByURL(activeSchedule, a);
|
||||
}
|
||||
} else {
|
||||
// We'll allow the alert for this WIP feature
|
||||
// eslint-disable-next-line no-alert
|
||||
window.alert('Logged into UT Registrar.');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,7 +140,7 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
|
||||
tickWidth: 1,
|
||||
tickLength: 10,
|
||||
tickColor: '#9CADB7',
|
||||
crosshair: { color: extendedColors.theme.offwhite },
|
||||
crosshair: { color: `${extendedColors.theme.offwhite}50` },
|
||||
lineColor: '#9CADB7',
|
||||
},
|
||||
yAxis: {
|
||||
@@ -215,7 +215,7 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
|
||||
options={{
|
||||
...chartOptions,
|
||||
title: {
|
||||
text: `There is currently no grade distribution data for ${course.department} ${course.number}`,
|
||||
text: `There is currently no grade distribution data for ${course.department} ${course.getNumberWithoutTerm()}`,
|
||||
},
|
||||
tooltip: { enabled: false },
|
||||
}}
|
||||
@@ -228,7 +228,7 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
|
||||
<Text variant='small' className='text-ut-black'>
|
||||
Grade Distribution for{' '}
|
||||
<Text variant='small' className='font-extrabold!' as='strong'>
|
||||
{course.department} {course.number}
|
||||
{course.department} {course.getNumberWithoutTerm()}
|
||||
</Text>
|
||||
</Text>
|
||||
<select
|
||||
@@ -267,7 +267,8 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
|
||||
<div className='mt-3 flex flex-wrap content-center items-center self-stretch justify-center gap-3 text-center'>
|
||||
<Text variant='small' className='text-theme-red'>
|
||||
We couldn't find {semester !== 'Aggregate' && ` ${semester}`} grades for this
|
||||
instructor, so here are the grades for all {course.department} {course.number} sections.
|
||||
instructor, so here are the grades for all {course.department}{' '}
|
||||
{course.getNumberWithoutTerm()} sections.
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import createSchedule from '@pages/background/lib/createSchedule';
|
||||
import switchSchedule from '@pages/background/lib/switchSchedule';
|
||||
import {
|
||||
ArrowUpRight,
|
||||
CalendarDots,
|
||||
@@ -14,8 +16,10 @@ import { background } from '@shared/messages';
|
||||
import type { Course } from '@shared/types/Course';
|
||||
import type Instructor from '@shared/types/Instructor';
|
||||
import type { UserSchedule } from '@shared/types/UserSchedule';
|
||||
import { englishStringifyList } from '@shared/util/string';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import { Chip, coreMap, flagMap } from '@views/components/common/Chip';
|
||||
import { usePrompt } from '@views/components/common/DialogProvider/DialogProvider';
|
||||
import Divider from '@views/components/common/Divider';
|
||||
import Link from '@views/components/common/Link';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
@@ -60,7 +64,7 @@ export default function HeadingAndActions({ course, activeSchedule, onClose }: H
|
||||
|
||||
const [isCopied, setIsCopied] = useState<boolean>(false);
|
||||
const lastCopyTime = useRef<number>(0);
|
||||
|
||||
const showDialog = usePrompt();
|
||||
const getInstructorFullName = (instructor: Instructor) => instructor.toString({ format: 'first_last' });
|
||||
|
||||
const handleCopy = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
@@ -112,10 +116,78 @@ export default function HeadingAndActions({ course, activeSchedule, onClose }: H
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddToNewSchedule = async (close: () => void) => {
|
||||
const newScheduleId = await createSchedule(`${course.semester.season} ${course.semester.year}`);
|
||||
switchSchedule(newScheduleId);
|
||||
addCourse({ course, scheduleId: newScheduleId });
|
||||
close();
|
||||
};
|
||||
|
||||
const handleAddOrRemoveCourse = async () => {
|
||||
const uniqueSemesterCodes = [
|
||||
...new Set(
|
||||
activeSchedule.courses
|
||||
.map(course => course.semester.code)
|
||||
.filter((code): code is string => code !== undefined)
|
||||
),
|
||||
];
|
||||
uniqueSemesterCodes.sort();
|
||||
const codeToReadableMap: Record<string, string> = {};
|
||||
activeSchedule.courses.forEach(course => {
|
||||
const { code } = course.semester;
|
||||
if (code) {
|
||||
const readable = `${course.semester.season} ${course.semester.year}`;
|
||||
codeToReadableMap[code] = readable;
|
||||
}
|
||||
});
|
||||
const sortedSemesters = uniqueSemesterCodes
|
||||
.map(code => codeToReadableMap[code])
|
||||
.filter((value): value is string => value !== undefined);
|
||||
const activeSemesters = englishStringifyList(sortedSemesters);
|
||||
|
||||
if (!activeSchedule) return;
|
||||
if (!courseAdded) {
|
||||
const currentSemesterCode = course.semester.code;
|
||||
// Show warning if this course is for a different semester than the selected schedule
|
||||
if (
|
||||
activeSchedule.courses.length > 0 &&
|
||||
activeSchedule.courses.every(otherCourse => otherCourse.semester.code !== currentSemesterCode)
|
||||
) {
|
||||
const dialogButtons = (close: () => void) => (
|
||||
<>
|
||||
<Button variant='minimal' color='ut-black' onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant='filled'
|
||||
color='ut-burntorange'
|
||||
onClick={() => {
|
||||
handleAddToNewSchedule(close);
|
||||
}}
|
||||
>
|
||||
Start a new schedule
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
showDialog({
|
||||
title: 'This course section is from a different semester!',
|
||||
description: (
|
||||
<>
|
||||
The section you're adding is for{' '}
|
||||
<span className='whitespace-nowrap text-ut-burntorange'>
|
||||
{course.semester.season} {course.semester.year}
|
||||
</span>
|
||||
, but your current schedule contains sections in{' '}
|
||||
<span className='whitespace-nowrap text-ut-burntorange'>{activeSemesters}</span>. Mixing
|
||||
semesters in one schedule may cause confusion.
|
||||
</>
|
||||
),
|
||||
buttons: dialogButtons,
|
||||
});
|
||||
} else {
|
||||
addCourse({ course, scheduleId: activeSchedule.id });
|
||||
}
|
||||
} else {
|
||||
removeCourse({ course, scheduleId: activeSchedule.id });
|
||||
}
|
||||
|
||||
89
src/views/components/injected/DaysCheckbox.tsx
Normal file
89
src/views/components/injected/DaysCheckbox.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] as const;
|
||||
/**
|
||||
* Component that transforms the days dropdown into a series of checkboxes
|
||||
* on the course catalog search page
|
||||
*
|
||||
* @returns The rendered checkbox component or null if the container is not found.
|
||||
*/
|
||||
export default function DaysCheckbox(): JSX.Element | null {
|
||||
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
||||
const [daysValue, setDaysValue] = useState<number[]>([0, 0, 0, 0, 0, 0]);
|
||||
|
||||
useEffect(() => {
|
||||
const daysDropdown = document.getElementById('mtg_days_st') as HTMLSelectElement | null;
|
||||
if (!daysDropdown) {
|
||||
console.error('Days dropdown not found');
|
||||
return;
|
||||
}
|
||||
|
||||
const formElement = daysDropdown.closest('.form_element')!;
|
||||
const checkboxContainer = document.createElement('div');
|
||||
|
||||
// Create a hidden input to store the value
|
||||
const hiddenInput = document.createElement('input');
|
||||
hiddenInput.type = 'hidden';
|
||||
hiddenInput.name = 'mtg_days_st';
|
||||
hiddenInput.id = 'mtg_days_st_hidden';
|
||||
hiddenInput.value = daysDropdown.value;
|
||||
|
||||
// Remove old dropdown
|
||||
formElement.innerHTML = '';
|
||||
|
||||
// Add the label back
|
||||
const newLabel = document.createElement('label');
|
||||
newLabel.className = 'primary_label';
|
||||
newLabel.htmlFor = 'mtg_days_st_hidden';
|
||||
newLabel.textContent = 'AND days';
|
||||
|
||||
formElement.appendChild(newLabel);
|
||||
formElement.appendChild(hiddenInput);
|
||||
formElement.appendChild(checkboxContainer);
|
||||
setContainer(checkboxContainer);
|
||||
|
||||
return () => {
|
||||
checkboxContainer.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Update hidden input when daysValue changes
|
||||
const hiddenInput = document.getElementById('mtg_days_st_hidden') as HTMLInputElement | null;
|
||||
if (hiddenInput) {
|
||||
hiddenInput.value = daysValue.join('');
|
||||
}
|
||||
}, [daysValue]);
|
||||
|
||||
const handleDayChange = (position: number, checked: boolean) => {
|
||||
setDaysValue(prev => prev.with(position, checked ? 1 : 0));
|
||||
};
|
||||
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<ExtensionRoot>
|
||||
<ul className='text-black font-[Verdana,_"Helvetica_Neue",_Helvetica,_Arial,_sans-serif]'>
|
||||
{days.map((day, index) => (
|
||||
<li key={day}>
|
||||
<input
|
||||
type='checkbox'
|
||||
id={`day_${day}`}
|
||||
checked={daysValue[index] === 1}
|
||||
onChange={e => {
|
||||
handleDayChange(index, e.target.checked);
|
||||
}}
|
||||
className='form-checkbox m-[3px_3px_3px_4px]'
|
||||
/>{' '}
|
||||
<label htmlFor={`day_${day}`}>{day}</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</ExtensionRoot>,
|
||||
container
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,49 @@
|
||||
import Link from '@views/components/common/Link';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import styles from './RecruitmentBanner.module.scss';
|
||||
|
||||
const DISCORD_URL = 'https://discord.gg/7pQDBGdmb7';
|
||||
const GITHUB_URL = 'https://github.com/Longhorn-Developers/UT-Registration-Plus';
|
||||
const DESIGNER_APPLICATION_URL =
|
||||
'https://docs.google.com/forms/d/e/1FAIpQLSdX1Bb37tW6s1bkdIW3GJoTGcM_Uc-2DzFOFMXxGdn1jZ3K1A/viewform';
|
||||
|
||||
const RECRUIT_FROM_DEPARTMENTS = ['C S', 'ECE', 'MIS', 'CSE', 'EE', 'ITD', 'DES'];
|
||||
// The lists below _must_ be mutually exclusive
|
||||
const DEVELOPER_RECRUIT_FROM_DEPARTMENTS = new Set(['C S', 'ECE', 'MIS', 'CSE', 'EE', 'ITD']);
|
||||
const DESIGNER_RECRUIT_FROM_DEPARTMENTS = new Set(['I', 'DES', 'AET']);
|
||||
|
||||
type RecruitmentType = 'DEVELOPER' | 'DESIGNER' | 'NONE';
|
||||
|
||||
const DeveloperRecruitmentBanner = () => (
|
||||
<div className={styles.container}>
|
||||
<Text className='text-white'>
|
||||
Interested in helping us develop UT Registration Plus? Check out our{' '}
|
||||
<Link className='text-ut-orange!' href={DISCORD_URL}>
|
||||
Discord Server
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link className='text-ut-orange!' href={GITHUB_URL}>
|
||||
GitHub
|
||||
</Link>
|
||||
!
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
|
||||
const DesignerRecruitmentBanner = () => (
|
||||
<div className={styles.container}>
|
||||
<Text className='text-white'>
|
||||
Design for thousands of UT students through Longhorn Developers on real-world projects like UT Reg.
|
||||
Plus.—build your portfolio and collaborate in Figma. Apply{' '}
|
||||
<Link className='text-ut-orange!' href={DESIGNER_APPLICATION_URL}>
|
||||
here
|
||||
</Link>
|
||||
!
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* This adds a new column to the course catalog table header.
|
||||
@@ -17,47 +52,37 @@ const RECRUIT_FROM_DEPARTMENTS = ['C S', 'ECE', 'MIS', 'CSE', 'EE', 'ITD', 'DES'
|
||||
*/
|
||||
export default function RecruitmentBanner(): JSX.Element | null {
|
||||
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
||||
const recruitmentType = useMemo<RecruitmentType>(getRecruitmentType, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canRecruitFrom()) {
|
||||
if (recruitmentType === 'NONE') {
|
||||
return;
|
||||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.setAttribute('id', 'ut-registration-plus-table-head');
|
||||
|
||||
const table = document.querySelector('table');
|
||||
table!.before(container);
|
||||
setContainer(container);
|
||||
}, []);
|
||||
}, [recruitmentType]);
|
||||
|
||||
if (!container) {
|
||||
if (!container || recruitmentType === 'NONE') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
<div className={styles.container}>
|
||||
<Text color='white'>
|
||||
Interested in helping us develop UT Registration Plus? Check out our{' '}
|
||||
<Link color='white' href={DISCORD_URL}>
|
||||
Discord Server
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link color='white' href={GITHUB_URL}>
|
||||
GitHub
|
||||
</Link>
|
||||
!
|
||||
</Text>
|
||||
</div>,
|
||||
recruitmentType === 'DEVELOPER' ? <DeveloperRecruitmentBanner /> : <DesignerRecruitmentBanner />,
|
||||
container
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if recruitment can be done from the current department.
|
||||
* Determines what type of recruitment can be done from the current department.
|
||||
*
|
||||
* @returns True if recruitment can be done from the current department, false otherwise.
|
||||
* @returns 'DEVELOPER' or 'DESIGNER' if the current department recruits for that respective type, otherwise 'NONE'
|
||||
*/
|
||||
export const canRecruitFrom = (): boolean => {
|
||||
export const getRecruitmentType = (): RecruitmentType => {
|
||||
const params = ['fos_fl', 'fos_cn'];
|
||||
let department = '';
|
||||
params.forEach(p => {
|
||||
@@ -66,8 +91,18 @@ export const canRecruitFrom = (): boolean => {
|
||||
department = param;
|
||||
}
|
||||
});
|
||||
|
||||
if (!department) {
|
||||
return false;
|
||||
return 'NONE';
|
||||
}
|
||||
return RECRUIT_FROM_DEPARTMENTS.includes(department);
|
||||
|
||||
if (DEVELOPER_RECRUIT_FROM_DEPARTMENTS.has(department)) {
|
||||
return 'DEVELOPER';
|
||||
}
|
||||
|
||||
if (DESIGNER_RECRUIT_FROM_DEPARTMENTS.has(department)) {
|
||||
return 'DESIGNER';
|
||||
}
|
||||
|
||||
return 'NONE';
|
||||
};
|
||||
|
||||
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 { addCourseByURL } from '@pages/background/lib/addCourseByURL';
|
||||
import { deleteAllSchedules } from '@pages/background/lib/deleteSchedule';
|
||||
import exportSchedule from '@pages/background/lib/exportSchedule';
|
||||
import importSchedule from '@pages/background/lib/importSchedule';
|
||||
import { CalendarDots, Trash } from '@phosphor-icons/react';
|
||||
import { background } from '@shared/messages';
|
||||
import { DevStore } from '@shared/storage/DevStore';
|
||||
import { initSettings, OptionsStore } from '@shared/storage/OptionsStore';
|
||||
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
|
||||
import { CRX_PAGES } from '@shared/types/CRXPages';
|
||||
import MIMEType from '@shared/types/MIMEType';
|
||||
import { downloadBlob } from '@shared/util/downloadBlob';
|
||||
// import { addCourseByUrl } from '@shared/util/courseUtils';
|
||||
// import { getCourseColors } from '@shared/util/colors';
|
||||
// import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
|
||||
@@ -32,6 +29,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import IconoirGitFork from '~icons/iconoir/git-fork';
|
||||
|
||||
import { handleExportJson } from '../calendar/utils';
|
||||
// import { ExampleCourse } from 'src/stories/components/ConflictsWithWarning.stories';;
|
||||
import FileUpload from '../common/FileUpload';
|
||||
import { useMigrationDialog } from '../common/MigrationDialog';
|
||||
@@ -94,6 +92,7 @@ export default function Settings(): JSX.Element {
|
||||
const [loadAllCourses, setLoadAllCourses] = useState<boolean>(false);
|
||||
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);
|
||||
const [calendarNewTab, setCalendarNewTab] = useState<boolean>(false);
|
||||
const [increaseScheduleLimit, setIncreaseScheduleLimit] = useState<boolean>(false);
|
||||
|
||||
const showMigrationDialog = useMigrationDialog();
|
||||
|
||||
@@ -128,6 +127,7 @@ export default function Settings(): JSX.Element {
|
||||
enableScrollToLoad,
|
||||
enableDataRefreshing,
|
||||
alwaysOpenCalendarInNewTab,
|
||||
allowMoreSchedules,
|
||||
} = await initSettings();
|
||||
setEnableCourseStatusChips(enableCourseStatusChips);
|
||||
// setShowTimeLocation(enableTimeAndLocationInPopup);
|
||||
@@ -135,6 +135,7 @@ export default function Settings(): JSX.Element {
|
||||
setLoadAllCourses(enableScrollToLoad);
|
||||
setEnableDataRefreshing(enableDataRefreshing);
|
||||
setCalendarNewTab(alwaysOpenCalendarInNewTab);
|
||||
setIncreaseScheduleLimit(allowMoreSchedules);
|
||||
};
|
||||
|
||||
const initDS = async () => {
|
||||
@@ -189,6 +190,15 @@ export default function Settings(): JSX.Element {
|
||||
// console.log('alwaysOpenCalendarInNewTab', newValue);
|
||||
});
|
||||
|
||||
const l6 = OptionsStore.listen('alwaysOpenCalendarInNewTab', async ({ newValue }) => {
|
||||
setCalendarNewTab(newValue);
|
||||
// console.log('alwaysOpenCalendarInNewTab', newValue);
|
||||
});
|
||||
|
||||
const l7 = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
|
||||
setIncreaseScheduleLimit(newValue);
|
||||
});
|
||||
|
||||
// Remove listeners when the component is unmounted
|
||||
return () => {
|
||||
OptionsStore.removeListener(l1);
|
||||
@@ -196,6 +206,8 @@ export default function Settings(): JSX.Element {
|
||||
OptionsStore.removeListener(l3);
|
||||
OptionsStore.removeListener(l4);
|
||||
OptionsStore.removeListener(l5);
|
||||
OptionsStore.removeListener(l6);
|
||||
OptionsStore.removeListener(l7);
|
||||
|
||||
DevStore.removeListener(ds_l1);
|
||||
|
||||
@@ -232,35 +244,20 @@ export default function Settings(): JSX.Element {
|
||||
});
|
||||
};
|
||||
|
||||
const handleExportClick = async (id: string) => {
|
||||
const jsonString = await exportSchedule(id);
|
||||
if (jsonString) {
|
||||
const schedules = await UserScheduleStore.get('schedules');
|
||||
const schedule = schedules.find(s => s.id === id);
|
||||
const fileName = `${schedule?.name ?? `schedule_${id}`}_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
|
||||
await downloadBlob(jsonString, 'JSON', fileName);
|
||||
} else {
|
||||
console.error('Error exporting schedule: jsonString is undefined');
|
||||
}
|
||||
};
|
||||
|
||||
const handleImportClick = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async e => {
|
||||
try {
|
||||
const result = e.target?.result as string;
|
||||
const jsonObject = JSON.parse(result);
|
||||
await importSchedule(jsonObject);
|
||||
} catch (error) {
|
||||
console.error('Invalid import file!');
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
if (!file) return;
|
||||
|
||||
try {
|
||||
const text = await file.text();
|
||||
const data = JSON.parse(text);
|
||||
await importSchedule(data);
|
||||
alert('Schedule imported successfully.');
|
||||
} catch (error) {
|
||||
console.error('Error importing schedule:', error);
|
||||
alert('Failed to import schedule. Make sure the file is a valid .json format.');
|
||||
}
|
||||
};
|
||||
// const handleAddCourseByLink = async () => {
|
||||
// // todo: Use a proper modal instead of a prompt
|
||||
// const link: string | null = prompt('Enter course link');
|
||||
@@ -400,7 +397,7 @@ export default function Settings(): JSX.Element {
|
||||
<Button
|
||||
variant='outline'
|
||||
color='ut-burntorange'
|
||||
onClick={() => handleExportClick(activeSchedule.id)}
|
||||
onClick={() => handleExportJson(activeSchedule.id)}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
@@ -466,6 +463,25 @@ export default function Settings(): JSX.Element {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='max-w-xs'>
|
||||
<Text variant='h4' className='text-ut-burntorange font-semibold'>
|
||||
Allow more than 10 schedules
|
||||
</Text>
|
||||
<p className='text-sm text-gray-600'>
|
||||
Allow bypassing the 10-schedule limit. Intended for advisors or staff who
|
||||
need to create many schedules on behalf of students.
|
||||
</p>
|
||||
</div>
|
||||
<SwitchButton
|
||||
isChecked={increaseScheduleLimit}
|
||||
onChange={() => {
|
||||
setIncreaseScheduleLimit(!increaseScheduleLimit);
|
||||
OptionsStore.set('allowMoreSchedules', !increaseScheduleLimit);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider size='auto' orientation='horizontal' />
|
||||
|
||||
<div className='flex items-center justify-between'>
|
||||
@@ -595,7 +611,9 @@ export default function Settings(): JSX.Element {
|
||||
|
||||
<section className='my-8 lg:my-0 lg:ml-4 lg:w-1/2'>
|
||||
<section>
|
||||
<h2 className='mb-4 text-xl text-ut-black font-semibold'>LONGHORN DEVELOPERS ADMINS</h2>
|
||||
<h2 className='mb-4 text-xl text-ut-black font-semibold'>
|
||||
LONGHORN DEVELOPERS (LHD) EXECUTIVE BOARD
|
||||
</h2>
|
||||
<div className='grid grid-cols-2 gap-4 2xl:grid-cols-4 md:grid-cols-3'>
|
||||
{LONGHORN_DEVELOPERS_ADMINS.map(admin => (
|
||||
<div
|
||||
@@ -611,7 +629,11 @@ export default function Settings(): JSX.Element {
|
||||
>
|
||||
{admin.name}
|
||||
</Text>
|
||||
<p className='text-sm text-gray-600'>{admin.role}</p>
|
||||
{admin.role.map(role => (
|
||||
<p key={admin.githubUsername} className='text-sm text-gray-600'>
|
||||
{role}
|
||||
</p>
|
||||
))}
|
||||
{showGitHubStats && githubStats && (
|
||||
<div className='mt-2'>
|
||||
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
|
||||
@@ -657,7 +679,11 @@ export default function Settings(): JSX.Element {
|
||||
>
|
||||
{swe.name}
|
||||
</Text>
|
||||
<p className='text-sm text-gray-600'>{swe.role}</p>
|
||||
{swe.role.map(role => (
|
||||
<p key={swe.githubUsername} className='text-sm text-gray-600'>
|
||||
{role}
|
||||
</p>
|
||||
))}
|
||||
{showGitHubStats && githubStats && (
|
||||
<div className='mt-2'>
|
||||
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { convertMinutesToIndex } from '../useFlattenedCourseSchedule';
|
||||
describe('useFlattenedCourseSchedule', () => {
|
||||
it('should convert minutes to index correctly', () => {
|
||||
const minutes = 480; // 8:00 AM
|
||||
const expectedIndex = 2; // (480 - 420) / 30 = 2
|
||||
const expectedIndex = 3; // (480 - 480) / 30 + 2 + 1 = 3
|
||||
const result = convertMinutesToIndex(minutes);
|
||||
expect(result).toBe(expectedIndex);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { background } from '@shared/messages';
|
||||
import { OptionsStore } from '@shared/storage/OptionsStore';
|
||||
import { CRX_PAGES } from '@shared/types/CRXPages';
|
||||
import useSchedules from '@views/hooks/useSchedules';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '../components/common/Button';
|
||||
import { usePrompt } from '../components/common/DialogProvider/DialogProvider';
|
||||
@@ -17,29 +20,68 @@ const SCHEDULE_LIMIT = 10;
|
||||
export function useEnforceScheduleLimit(): () => boolean {
|
||||
const [, schedules] = useSchedules();
|
||||
const showDialog = usePrompt();
|
||||
const [allowMoreSchedules, setAllowMoreSchedules] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
(async () => {
|
||||
try {
|
||||
const val = await OptionsStore.get('allowMoreSchedules');
|
||||
if (mounted) setAllowMoreSchedules(val ?? false);
|
||||
} catch (err) {
|
||||
console.error('Failed to read allowMoreSchedules from OptionsStore:', err);
|
||||
}
|
||||
})();
|
||||
|
||||
const listener = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
|
||||
setAllowMoreSchedules(newValue);
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
OptionsStore.removeListener(listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return useCallback(() => {
|
||||
// If user has enabled bypass, allow creating more schedules
|
||||
if (allowMoreSchedules) return true;
|
||||
|
||||
if (schedules.length >= SCHEDULE_LIMIT) {
|
||||
showDialog({
|
||||
title: `You have ${SCHEDULE_LIMIT} active schedules!`,
|
||||
title: `You have too many schedules!`,
|
||||
|
||||
description: (
|
||||
<>
|
||||
To encourage organization,{' '}
|
||||
<span className='text-ut-burntorange'>please consider removing some unused schedules</span> you
|
||||
may have.
|
||||
<span className='text-ut-burntorange'>please consider deleting any unused schedules</span> you
|
||||
may have. You can increase the limit in the settings if it’s really necessary.
|
||||
</>
|
||||
),
|
||||
|
||||
buttons: close => (
|
||||
<Button variant='filled' color='ut-burntorange' onClick={close}>
|
||||
I Understand
|
||||
<>
|
||||
<Button
|
||||
variant='outline'
|
||||
color='ut-black'
|
||||
onClick={() => {
|
||||
close();
|
||||
// open options/settings page so user can enable bypass if they are advising staff
|
||||
const url = chrome.runtime.getURL(CRX_PAGES.OPTIONS);
|
||||
background.openNewTab({ url });
|
||||
}}
|
||||
>
|
||||
Open Settings
|
||||
</Button>
|
||||
<Button variant='filled' color='ut-burntorange' onClick={close}>
|
||||
I understand
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, [schedules, showDialog]);
|
||||
}, [schedules, showDialog, allowMoreSchedules]);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface CalendarGridCourse {
|
||||
gridColumnStart?: number;
|
||||
gridColumnEnd?: number;
|
||||
totalColumns?: number;
|
||||
concurrentCells?: CalendarGridCourse[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,9 @@ export interface FlattenedCourseSchedule {
|
||||
* @param minutes - The number of minutes.
|
||||
* @returns The index value.
|
||||
*/
|
||||
export const convertMinutesToIndex = (minutes: number): number => Math.floor((minutes - 420) / 30);
|
||||
export const convertMinutesToIndex = (minutes: number): number =>
|
||||
// 480 = 8 a.m., 30 = 30 minute slots, 2 header rows, and grid rows start at 1
|
||||
Math.floor((minutes - 480) / 30) + 2 + 1;
|
||||
|
||||
/**
|
||||
* Get the active schedule, and convert it to be render-able into a calendar.
|
||||
|
||||
54
src/views/hooks/useWhatsNew.tsx
Normal file
54
src/views/hooks/useWhatsNew.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { UT_DINING_APP_STORE_URL } from '@shared/util/appUrls';
|
||||
import { Button } from '@views/components/common/Button';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import WhatsNewPopupContent from '@views/components/common/WhatsNewPopup';
|
||||
import { useDialog } from '@views/contexts/DialogContext';
|
||||
import React from 'react';
|
||||
|
||||
// import useChangelog from './useChangelog';
|
||||
|
||||
const LDIconURL = new URL('/src/assets/LD-icon-new.png', import.meta.url).href;
|
||||
|
||||
/**
|
||||
* Custom hook that provides a function to display a what's new dialog.
|
||||
*
|
||||
* @returns A function that, when called, shows a dialog with the changelog.
|
||||
*/
|
||||
export default function useWhatsNewPopUp(): () => void {
|
||||
const showDialog = useDialog();
|
||||
// const showChangeLog = useChangelog();
|
||||
// const { version } = chrome.runtime.getManifest();
|
||||
|
||||
const showPopUp = () => {
|
||||
showDialog(close => ({
|
||||
className: 'w-[830px] flex flex-col items-center gap-spacing-7 p-spacing-8',
|
||||
title: (
|
||||
<div className='flex items-center justify-between gap-4'>
|
||||
<img src={LDIconURL} alt='LD Icon' className='h-12 w-12 rounded-lg' />
|
||||
<Text variant='h1' className='text-theme-black'>
|
||||
Download our new UT Dining app!
|
||||
</Text>
|
||||
</div>
|
||||
),
|
||||
description: <WhatsNewPopupContent />,
|
||||
buttons: (
|
||||
<div className='flex flex-row items-end gap-spacing-4'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.open(UT_DINING_APP_STORE_URL, '_blank');
|
||||
}}
|
||||
variant='minimal'
|
||||
color='ut-black'
|
||||
>
|
||||
Download UT Dining on iOS
|
||||
</Button>
|
||||
<Button onClick={close} color='ut-burntorange'>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
};
|
||||
|
||||
return showPopUp;
|
||||
}
|
||||
34
src/views/lib/CourseCatalogScraper.test.ts
Normal file
34
src/views/lib/CourseCatalogScraper.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { CourseCatalogScraper } from './CourseCatalogScraper';
|
||||
|
||||
describe('CourseCatalogScraper::separateCourseName', () => {
|
||||
it('should separate a simple course', () => {
|
||||
// UT Formats strings weird... lots of meaningless spaces
|
||||
const input = 'C S 314H DATA STRUCTURES: HONORS ';
|
||||
const expected = ['DATA STRUCTURES: HONORS', 'C S', '314H'];
|
||||
const result = CourseCatalogScraper.separateCourseName(input);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('separate summer courses ', () => {
|
||||
// UT Formats strings weird... lots of meaningless spaces
|
||||
const inputs = [
|
||||
'P R f378 PUBLIC RELATNS TECHNIQUES-IRL (First term) ',
|
||||
'CRP s396 INDEPENDENT RESEARCH IN CRP (Second term) ',
|
||||
'B A n284S 1-MANAGERIAL MICROECON-I-DAL (Nine week term) ',
|
||||
'J w379 JOURNALISM INDEPENDENT STUDY (Whole term) ',
|
||||
];
|
||||
|
||||
const expected = [
|
||||
['PUBLIC RELATNS TECHNIQUES-IRL (First term)', 'P R', 'f378'],
|
||||
['INDEPENDENT RESEARCH IN CRP (Second term)', 'CRP', 's396'],
|
||||
['1-MANAGERIAL MICROECON-I-DAL (Nine week term)', 'B A', 'n284S'],
|
||||
['JOURNALISM INDEPENDENT STUDY (Whole term)', 'J', 'w379'],
|
||||
];
|
||||
const results = inputs.map(input => CourseCatalogScraper.separateCourseName(input));
|
||||
|
||||
expect(results).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -75,7 +75,7 @@ export class CourseCatalogScraper {
|
||||
|
||||
fullName = fullName.replace(/\s\s+/g, ' ').trim();
|
||||
|
||||
const [courseName, department, number] = this.separateCourseName(fullName);
|
||||
const [courseName, department, number] = CourseCatalogScraper.separateCourseName(fullName);
|
||||
const [status, isReserved] = this.getStatus(row);
|
||||
|
||||
const newCourse = new Course({
|
||||
@@ -113,16 +113,31 @@ export class CourseCatalogScraper {
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* separateCourseName("CS 314H - Honors Discrete Structures") => ["Honors Discrete Structures", "CS", "314H"]
|
||||
* separateCourseName("C S 314H DATA STRUCTURES: HONORS") => ["DATA STRUCTURES: HONORS", "C S", "314H"]
|
||||
* ```
|
||||
* @param courseFullName - the full name of the course (e.g. "CS 314H - Honors Discrete Structures")
|
||||
* @param courseFullName - the full name of the course (e.g. "C S 314H DATA STRUCTURES: HONORS")
|
||||
* @returns an array of the course name, department, and number
|
||||
*/
|
||||
separateCourseName(courseFullName: string): [courseName: string, department: string, number: string] {
|
||||
let courseNumberIndex = courseFullName.search(/\d/);
|
||||
let department = courseFullName.substring(0, courseNumberIndex).trim();
|
||||
let number = courseFullName.substring(courseNumberIndex, courseFullName.indexOf(' ', courseNumberIndex)).trim();
|
||||
let courseName = courseFullName.substring(courseFullName.indexOf(' ', courseNumberIndex)).trim();
|
||||
static separateCourseName(courseFullName: string): [courseName: string, department: string, number: string] {
|
||||
// C S 314H DATA STRUCTURES: HONORS
|
||||
// ^ Here for normal courses
|
||||
// B A n284S 1-MANAGERIAL MICROECON-I-DAL (Nine week term)
|
||||
// ^ Also works for summer courses ([f]irst term, [s]econd term, [n]ine week term, [w]hole term)
|
||||
const courseNumberIndex = courseFullName.search(/\w?\d/);
|
||||
|
||||
if (courseNumberIndex === -1) {
|
||||
throw new Error("Course name doesn't have a course number");
|
||||
}
|
||||
|
||||
// Everything before the course number
|
||||
const department = courseFullName.substring(0, courseNumberIndex).trim();
|
||||
|
||||
const number = courseFullName
|
||||
.substring(courseNumberIndex, courseFullName.indexOf(' ', courseNumberIndex))
|
||||
.trim();
|
||||
|
||||
// Everything after the course number
|
||||
const courseName = courseFullName.substring(courseFullName.indexOf(' ', courseNumberIndex)).trim();
|
||||
|
||||
return [courseName, department, number];
|
||||
}
|
||||
|
||||
@@ -109,16 +109,22 @@ function generateQuery(
|
||||
includeInstructor: boolean
|
||||
): [string, GradeDistributionParams] {
|
||||
const query = `
|
||||
select * from grade_distributions
|
||||
where Department_Code = :department_code
|
||||
and Course_Number = :course_number
|
||||
${includeInstructor ? `and Instructor_Last = :instructor_last collate nocase` : ''}
|
||||
${semester ? `and Semester = :semester` : ''}
|
||||
SELECT * FROM grade_distributions
|
||||
WHERE Department_Code = :department_code
|
||||
AND Course_Number COLLATE NOCASE IN (
|
||||
:course_number,
|
||||
concat('F', :course_number), -- Check summer courses with prefix, too
|
||||
concat('S', :course_number),
|
||||
concat('N', :course_number),
|
||||
concat('W', :course_number)
|
||||
)
|
||||
${includeInstructor ? `AND Instructor_Last = :instructor_last COLLATE NOCASE` : ''}
|
||||
${semester ? `AND Semester = :semester` : ''}
|
||||
`;
|
||||
|
||||
const params: GradeDistributionParams = {
|
||||
':department_code': course.department,
|
||||
':course_number': course.number,
|
||||
':course_number': course.getNumberWithoutTerm(),
|
||||
};
|
||||
|
||||
if (includeInstructor) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { CachedData } from '@shared/types/CachedData';
|
||||
// Types
|
||||
type TeamMember = {
|
||||
name: string;
|
||||
role: string;
|
||||
role: string[];
|
||||
githubUsername: string;
|
||||
};
|
||||
|
||||
@@ -40,21 +40,38 @@ const REPO_NAME = 'UT-Registration-Plus';
|
||||
const CONTRIBUTORS_API_ROUTE = `/repos/${REPO_OWNER}/${REPO_NAME}/stats/contributors`;
|
||||
|
||||
export const LONGHORN_DEVELOPERS_ADMINS = [
|
||||
{ name: 'Sriram Hariharan', role: 'Founder', githubUsername: 'sghsri' },
|
||||
{ name: 'Elie Soloveichik', role: 'Staff Engineer', githubUsername: 'Razboy20' },
|
||||
{ name: 'Diego Perez', role: 'Staff Engineer', githubUsername: 'doprz' },
|
||||
{ name: 'Lukas Zenick', role: 'Senior Software Engineer', githubUsername: 'Lukas-Zenick' },
|
||||
{ name: 'Isaiah Rodriguez', role: 'Chief Operations and Design Officer', githubUsername: 'IsaDavRod' },
|
||||
{ name: 'Samuel Gunter', role: 'Senior Software Engineer', githubUsername: 'Samathingamajig' },
|
||||
{ name: 'Derek Chen', role: 'Senior Software Engineer', githubUsername: 'DereC4' },
|
||||
{ name: 'Sriram Hariharan', role: ['LHD Co-Founder', 'UTRP Founder'], githubUsername: 'sghsri' },
|
||||
{
|
||||
name: 'Elie Soloveichik',
|
||||
role: ['LHD Co-Founder', 'Learning and Development Director', 'UTRP Senior SWE'],
|
||||
githubUsername: 'Razboy20',
|
||||
},
|
||||
{
|
||||
name: 'Diego Perez',
|
||||
role: ['LHD Co-Founder', 'Software Engineering Director', 'UTRP Senior SWE'],
|
||||
githubUsername: 'doprz',
|
||||
},
|
||||
{ name: 'Isaiah Rodriguez', role: ['LHD Co-Founder', 'President and UI/UX Director'], githubUsername: 'IsaDavRod' },
|
||||
{
|
||||
name: 'Samuel Gunter',
|
||||
role: ['Administrative Director', 'UTRP Co-Lead', 'UTRP Senior SWE'],
|
||||
githubUsername: 'Samathingamajig',
|
||||
},
|
||||
{
|
||||
name: 'Derek Chen',
|
||||
role: ['Communications Director', 'UTRP Co-Lead', 'UTRP Senior SWE'],
|
||||
githubUsername: 'DereC4',
|
||||
},
|
||||
{ name: 'Kabir Ramzan', role: ['Events Director'], githubUsername: 'CMEONE' },
|
||||
] as const satisfies TeamMember[];
|
||||
|
||||
export const LONGHORN_DEVELOPERS_SWE = [
|
||||
{ name: 'Preston Cook', role: 'Software Engineer', githubUsername: 'Preston-Cook' },
|
||||
{ name: 'Ethan Lanting', role: 'Software Engineer', githubUsername: 'EthanL06' },
|
||||
{ name: 'Casey Charleston', role: 'Software Engineer', githubUsername: 'caseycharleston' },
|
||||
{ name: 'Vinson', role: 'Software Engineer', githubUsername: 'vinsonzheng499' },
|
||||
{ name: 'Vivek', role: 'Software Engineer', githubUsername: 'vivek12311' },
|
||||
{ name: 'Preston Cook', role: ['Software Engineer'], githubUsername: 'Preston-Cook' },
|
||||
{ name: 'Ethan Lanting', role: ['Software Engineer'], githubUsername: 'EthanL06' },
|
||||
{ name: 'Casey Charleston', role: ['Software Engineer'], githubUsername: 'caseycharleston' },
|
||||
{ name: 'Lukas Zenick', role: ['LHD Alumni', 'Senior Software Engineer'], githubUsername: 'Lukas-Zenick' },
|
||||
{ name: 'Vinson', role: ['LHD Alumni', 'Software Engineer'], githubUsername: 'vinsonzheng499' },
|
||||
{ name: 'Vivek', role: ['LHD Alumni', 'Software Engineer'], githubUsername: 'vivek12311' },
|
||||
] as const satisfies TeamMember[];
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,9 @@ export const SiteSupport = {
|
||||
MY_CALENDAR: 'MY_CALENDAR',
|
||||
REPORT_ISSUE: 'REPORT_ISSUE',
|
||||
MY_UT: 'MY_UT',
|
||||
COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH',
|
||||
CLASSLIST: 'CLASSLIST',
|
||||
COURSE_CATALOG_KWS: 'COURSE_CATALOG_KWS',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -39,12 +41,16 @@ export default function getSiteSupport(url: string): SiteSupportType | null {
|
||||
return SiteSupport.UT_PLANNER;
|
||||
}
|
||||
if (url.includes('utdirect.utexas.edu/apps/registrar/course_schedule')) {
|
||||
if (url.includes('kws_results')) {
|
||||
return SiteSupport.COURSE_CATALOG_KWS;
|
||||
}
|
||||
if (url.includes('results')) {
|
||||
return SiteSupport.COURSE_CATALOG_LIST;
|
||||
}
|
||||
if (document.querySelector('#details')) {
|
||||
return SiteSupport.COURSE_CATALOG_DETAILS;
|
||||
}
|
||||
return SiteSupport.COURSE_CATALOG_SEARCH;
|
||||
}
|
||||
if (url.includes('utdirect.utexas.edu') && (url.includes('waitlist') || url.includes('classlist'))) {
|
||||
return SiteSupport.WAITLIST;
|
||||
|
||||
@@ -26,7 +26,7 @@ export default defineConfig({
|
||||
],
|
||||
shortcuts: {
|
||||
focusable: 'outline-none ring-blue-500/50 dark:ring-blue-400/60 ring-0 focus-visible:ring-4',
|
||||
btn: 'h-10 w-auto flex cursor-pointer justify-center items-center gap-spacing-3 rounded-1 px-spacing-5 py-0 text-4.5 btn-transition disabled:(cursor-not-allowed opacity-50) active:enabled:scale-96 focusable',
|
||||
btn: 'h-10 w-auto flex cursor-pointer justify-center items-center gap-spacing-3 rounded-1 px-spacing-5 py-0 text-4.5 btn-transition disabled:(cursor-not-allowed opacity-50) active:enabled:scale-96 active:has-enabled:scale-96 focusable',
|
||||
link: 'text-ut-burntorange link:text-ut-burntorange underline underline-offset-2 hover:text-ut-orange focus-visible:text-ut-orange focusable btn-transition ease-out-expo',
|
||||
linkanimate:
|
||||
'relative cursor-pointer transition duration-100 ease-out after:(absolute left-0.4 right-0.4 h-2px scale-x-95 bg-ut-orange opacity-0 transition duration-250 ease-out-expo content-empty -bottom-0.75 -translate-y-0.5) active:scale-95 hover:text-ut-orange focus-visible:text-ut-orange hover:after:(opacity-100) !hover:after:translate-y-0 !hover:after:scale-x-100',
|
||||
|
||||
@@ -24,16 +24,14 @@ const pagesDir = resolve(root, 'pages');
|
||||
const assetsDir = resolve(root, 'assets');
|
||||
const publicDir = resolve(__dirname, 'public');
|
||||
|
||||
// Set default environment variables
|
||||
process.env.PROD = process.env.NODE_ENV === 'production' ? 'true' : 'false';
|
||||
|
||||
const isBeta = !!process.env.BETA;
|
||||
if (isBeta) {
|
||||
process.env.VITE_BETA_BUILD = 'true';
|
||||
}
|
||||
process.env.VITE_PACKAGE_VERSION = packageJson.version;
|
||||
// TODO: Debug this. If PROD is false, VITE_SENTRY_ENVIRONMENT is in production mode
|
||||
if (process.env.PROD) {
|
||||
|
||||
// special condition for production sentry instrumentation, as many of our devs like to use `pnpm build` directly. Production instrumentation is added and uploaded during `pnpm zip:to-publish`.
|
||||
if (process.env.SENTRY_ENV === 'production') {
|
||||
process.env.VITE_SENTRY_ENVIRONMENT = 'production';
|
||||
} else if (isBeta) {
|
||||
process.env.VITE_SENTRY_ENVIRONMENT = 'beta';
|
||||
|
||||
Reference in New Issue
Block a user